]>
git.saurik.com Git - apple/security.git/blob - CdsaUtils/cuEnc64.c
2 * Copyright (c) 1998-2003 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please
7 * obtain a copy of the License at http://www.apple.com/publicsource and
8 * read it before using this file.
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
15 * Please see the License for the specific language governing rights and
16 * limitations under the License.
18 * cuEnc64.c - encode/decode in 64-char IA5 format, per RFC 1421
25 #define NULL ((void *)0)
29 * map a 6-bit binary value to a printable character.
32 unsigned char bintoasc
[] =
33 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
36 * Map an 7-bit printable character to its corresponding binary value.
37 * Any illegal characters return high bit set.
40 unsigned char asctobin
[] =
42 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
43 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
44 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
45 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
46 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
47 0x80, 0x80, 0x80, 0x3e, 0x80, 0x80, 0x80, 0x3f,
48 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
49 0x3c, 0x3d, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
50 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
51 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
52 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
53 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,
54 0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
55 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
56 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
57 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80
61 * map 6 bits to a printing char
63 #define ENC(c) (bintoasc[((c) & 0x3f)])
68 * map one group of up to 3 bytes at inp to 4 bytes at outp.
69 * Count is number of valid bytes in *inp; if less than 3, the
70 * 1 or two extras must be zeros.
72 static void encChunk(const unsigned char *inp
,
76 unsigned char c1
, c2
, c3
, c4
;
79 c2
= ((inp
[0] << 4) & 0x30) | ((inp
[1] >> 4) & 0xf);
80 c3
= ((inp
[1] << 2) & 0x3c) | ((inp
[2] >> 6) & 0x3);
99 * Given input buffer inbuf, length inlen, encode to 64-char IA5 format.
100 * Result is fmalloc'd and returned; it is terminated by Microsoft-style
101 * newline and NULL. Its length (including the trailing newline and NULL)
102 * is returned in *outlen.
105 unsigned char *cuEnc64(const unsigned char *inbuf
,
107 unsigned *outlen
) // RETURNED
109 return cuEnc64WithLines(inbuf
, inlen
, 0, outlen
);
112 unsigned char *cuEnc64WithLines(const unsigned char *inbuf
,
118 unsigned len
; // to malloc, liberal
119 unsigned olen
= 0; // actual output size
120 unsigned char *outbuf
;
121 unsigned char endbuf
[3];
127 outTextLen
= ((inlen
+ 2) / 3) * 4;
130 * linelen must be 0 mod 4 for this to work; round up...
132 if((linelen
& 0x03) != 0) {
133 linelen
= (linelen
+ 3) & 0xfffffffc;
135 numLines
= (outTextLen
+ linelen
- 1)/ linelen
;
142 * Total output size = encoded text size plus one newline per
143 * line of output, plus trailing NULL. We always generate newlines
144 * as \n; when decoding, we tolerate \r\n (Microsoft) or \n.
146 len
= outTextLen
+ (2 * numLines
) + 1;
147 outbuf
= (unsigned char*)malloc(len
);
155 endbuf
[i
] = inbuf
[i
];
161 encChunk(endbuf
, outp
, inlen
);
165 encChunk(inbuf
, outp
, 3);
172 if((linelen
!= 0) && (thisLine
>= linelen
) && inlen
) {
174 * last trailing newline added below
175 * Note we don't split 4-byte output chunks over newlines
189 static inline int isWhite(unsigned char c
)
204 * Strip off all whitespace from a (supposedly) enc64-format string.
205 * Returns a malloc'd string.
207 static unsigned char *stringCleanse(const unsigned char *inbuf
,
211 unsigned char *news
; // cleansed inbuf
212 unsigned newsDex
; // index into news
215 news
= (unsigned char*)malloc(inlen
);
217 for(i
=0; i
<inlen
; i
++) {
218 if(!isWhite(inbuf
[i
])) {
219 news
[newsDex
++] = inbuf
[i
];
227 * Given input buffer inbuf, length inlen, decode from 64-char IA5 format to
228 * binary. Result is malloced and returned; its length is returned in *outlen.
229 * NULL return indicates corrupted input.
231 * All whitespace in input is ignored.
233 unsigned char *cuDec64(const unsigned char *inbuf
,
237 unsigned char *outbuf
;
238 unsigned char *outp
; // malloc'd outbuf size
240 const unsigned char *bp
;
241 unsigned olen
= 0; // actual output size
242 unsigned char c1
, c2
, c3
, c4
;
245 unsigned char *news
; // cleansed inbuf
249 * Strip out all whitespace; remainder must be multiple of four
252 news
= stringCleanse(inbuf
, inlen
, &newsLen
);
253 if((newsLen
& 0x03) != 0) {
255 return (unsigned char*) NULL
;
260 obuflen
= (inlen
/ 4) * 3;
261 outbuf
= (unsigned char*)malloc(obuflen
);
266 * Note inlen is always a multiple of four here
268 if (*bp
& 0x80 || (c1
= asctobin
[*bp
]) & 0x80) {
273 if (*bp
& 0x80 || (c2
= asctobin
[*bp
]) & 0x80){
280 * two input bytes, one output byte
299 } else if (*bp
& 0x80 || (c3
= asctobin
[*bp
]) & 0x80) {
306 * Three input bytes, two output
313 } else if (*bp
& 0x80 || (c4
= asctobin
[*bp
]) & 0x80) {
317 * Normal non-pad case
324 j
= (c1
<< 2) | (c2
>> 4);
327 j
= (c2
<< 4) | (c3
>> 2);
338 return outbuf
; /* normal return */
343 return (unsigned char*) NULL
;
347 * Determine if specified input data is valid enc64 format. Returns 1
348 * if valid, 0 if not.
349 * This doesn't do a full enc64 parse job; it scans for legal characters
350 * and proper sync when a possible pad is found.
352 int cuIsValidEnc64(const unsigned char *inbuf
,
355 int padChars
= 0; // running count of PAD chars
356 int validEncChars
= 0;
362 * -- count valid chars
363 * -- ensure not more than 2 PAD chars, only at end
364 * -- ensure valid chars mod 4 == 0
375 return 0; // max of 2 PAD chars at end
378 else if(padChars
> 0) {
379 return 0; // no normal chars after seeing PAD
381 else if((c
& 0x80) || ((asctobin
[c
]) & 0x80)) {
382 return 0; // invalid encoded char
386 if((validEncChars
& 0x03) != 0) {