]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/enc64.c
Security-58286.60.28.tar.gz
[apple/security.git] / OSX / libsecurity_cryptkit / lib / enc64.c
1 /* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved.
2 *
3 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
4 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
5 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
7 * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
8 * EXPOSE YOU TO LIABILITY.
9 ***************************************************************************
10 *
11 * enc64.c - encode/decode in 64-char IA5 format, per RFC 1421
12 *
13 * Revision History
14 * ----------------
15 * 11/27/98 dmitch
16 * Added ECDSA_VERIFY_ONLY dependencies.
17 * 10/06/98 ap
18 * Changed to compile with C++.
19 * 12 Dec 96 at NeXT
20 * Newlines optional in dec64() and isValidEnc64().
21 * 9 Oct 96 at NeXT
22 * Created.
23 */
24
25 #include "enc64.h"
26 #include "falloc.h"
27
28 /*
29 * 11/27/98 dmitch: The ECDSA_VERIFY_ONLY symbol, when #defined, disables all
30 * of the code in this module except that which is necessary for ECDSA
31 * siggnature verification.
32 */
33
34 #ifndef NULL
35 #define NULL ((void *)0)
36 #endif /* NULL */
37
38 /*
39 * map a 6-bit binary value to a printable character.
40 */
41 static const
42 unsigned char bintoasc[] =
43 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
44
45 /*
46 * Map an 7-bit printable character to its corresponding binary value.
47 * Any illegal characters return high bit set.
48 */
49 static const
50 unsigned char asctobin[] =
51 {
52 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
53 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
54 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
55 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
56 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
57 0x80, 0x80, 0x80, 0x3e, 0x80, 0x80, 0x80, 0x3f,
58 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
59 0x3c, 0x3d, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
60 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
61 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
62 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
63 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,
64 0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
65 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
66 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
67 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80
68 };
69
70 /*
71 * map 6 bits to a printing char
72 */
73 #define ENC(c) (bintoasc[((c) & 0x3f)])
74
75 #define PAD '='
76 //#define ENC_LINE_LEN 64
77
78 #ifndef ECDSA_VERIFY_ONLY
79
80 /*
81 * map one group of up to 3 bytes at inp to 4 bytes at outp.
82 * Count is number of valid bytes in *inp; if less than 3, the
83 * 1 or two extras must be zeros.
84 */
85 static void encChunk(const unsigned char *inp,
86 unsigned char *outp,
87 int count)
88 {
89 unsigned char c1, c2, c3, c4;
90
91 c1 = *inp >> 2;
92 c2 = ((inp[0] << 4) & 0x30) | ((inp[1] >> 4) & 0xf);
93 c3 = ((inp[1] << 2) & 0x3c) | ((inp[2] >> 6) & 0x3);
94 c4 = inp[2] & 0x3f;
95 *outp++ = ENC(c1);
96 *outp++ = ENC(c2);
97 if (count == 1) {
98 *outp++ = PAD;
99 *outp = PAD;
100 } else {
101 *outp++ = ENC(c3);
102 if (count == 2) {
103 *outp = PAD;
104 }
105 else {
106 *outp = ENC(c4);
107 }
108 }
109 }
110
111 /*
112 * Given input buffer inbuf, length inlen, encode to 64-char IA5 format.
113 * Result is fmalloc'd and returned; it is terminated by Microsoft-style
114 * newline and NULL. Its length (including the trailing newline and NULL)
115 * is returned in *outlen.
116 */
117
118 unsigned char *enc64(const unsigned char *inbuf,
119 unsigned inlen,
120 unsigned *outlen) // RETURNED
121 {
122 return enc64WithLines(inbuf, inlen, 0, outlen);
123 }
124
125 unsigned char *enc64WithLines(const unsigned char *inbuf,
126 unsigned inlen,
127 unsigned linelen,
128 unsigned *outlen)
129 {
130 unsigned outTextLen;
131 unsigned len; // to malloc, liberal
132 unsigned olen = 0; // actual output size
133 unsigned char *outbuf;
134 unsigned char endbuf[3];
135 unsigned i;
136 unsigned char *outp;
137 unsigned numLines;
138 unsigned thisLine;
139
140 outTextLen = ((inlen + 2) / 3) * 4;
141 if(linelen) {
142 /*
143 * linelen must be 0 mod 4 for this to work; round up...
144 */
145 if((linelen & 0x03) != 0) {
146 linelen = (linelen + 3) & 0xfffffffc;
147 }
148 numLines = (outTextLen + linelen - 1)/ linelen;
149 }
150 else {
151 numLines = 1;
152 }
153
154 /*
155 * Total output size = encoded text size plus one newline per
156 * line of output, plus trailing NULL. For Microsoft compatibility,
157 * we always generate newlines as \r\n; when decoding, we tolerate
158 * \r\n or \n.
159 */
160 len = outTextLen + (2 * numLines) + 1;
161 outbuf = (unsigned char*) fmalloc(len);
162 outp = outbuf;
163 thisLine = 0;
164
165 while(inlen) {
166 if(inlen < 3) {
167 for(i=0; i<3; i++) {
168 if(i < inlen) {
169 endbuf[i] = inbuf[i];
170 }
171 else {
172 endbuf[i] = 0;
173 }
174 }
175 encChunk(endbuf, outp, inlen);
176 inlen = 0;
177 }
178 else {
179 encChunk(inbuf, outp, 3);
180 inlen -= 3;
181 inbuf += 3;
182 }
183 outp += 4;
184 thisLine += 4;
185 olen += 4;
186 if((linelen != 0) && (thisLine >= linelen) && inlen) {
187 /*
188 * last trailing newline added below
189 * Note we don't split 4-byte output chunks over newlines
190 */
191 *outp++ = '\r';
192 *outp++ = '\n';
193 olen += 2;
194 thisLine = 0;
195 }
196 }
197 *outp++ = '\r';
198 *outp++ = '\n';
199 *outp = '\0';
200 olen += 3;
201 *outlen = olen;
202 return outbuf;
203 }
204
205 #endif /* ECDSA_VERIFY_ONLY */
206
207 static inline int isWhite(unsigned char c)
208 {
209 switch(c) {
210 case '\n':
211
212 case '\r':
213
214 case ' ':
215
216 case '\t':
217
218 case '\0':
219 return 1;
220
221 default:
222
223 return 0;
224
225 }
226 }
227
228 /*
229 * Strip off all whitespace from a (supposedly) enc64-format string.
230 * Returns a malloc'd string.
231 */
232 static unsigned char *stringCleanse(const unsigned char *inbuf,
233 unsigned inlen,
234 unsigned *outlen)
235 {
236 unsigned char *news; // cleansed inbuf
237 unsigned newsDex; // index into news
238 unsigned i;
239
240 news = (unsigned char*) fmalloc(inlen);
241 newsDex = 0;
242 for(i=0; i<inlen; i++) {
243 if(!isWhite(inbuf[i])) {
244 news[newsDex++] = inbuf[i];
245 }
246 }
247 *outlen = newsDex;
248 return news;
249 }
250
251 /*
252 * Given input buffer inbuf, length inlen, decode from 64-char IA5 format to
253 * binary. Result is fmalloced and returned; its length is returned in *outlen.
254 * NULL return indicates corrupted input.
255 *
256 * All whitespace in input is ignored.
257 */
258 unsigned char *dec64(const unsigned char *inbuf,
259 unsigned inlen,
260 unsigned *outlen)
261 {
262 unsigned char *outbuf;
263 unsigned char *outp; // malloc'd outbuf size
264 unsigned obuflen;
265 const unsigned char *bp;
266 unsigned olen = 0; // actual output size
267 unsigned char c1, c2, c3, c4;
268 unsigned char j;
269 unsigned thisOlen;
270 unsigned char *news; // cleansed inbuf
271 unsigned newsLen;
272
273 /*
274 * Strip out all whitespace; remainder must be multiple of four
275 * characters
276 */
277 news = stringCleanse(inbuf, inlen, &newsLen);
278 if((newsLen & 0x03) != 0) {
279 ffree(news);
280 return (unsigned char*) NULL;
281 }
282 inlen = newsLen;
283 bp = news;
284
285 obuflen = (inlen / 4) * 3;
286 outbuf = (unsigned char*) fmalloc(obuflen);
287 outp = outbuf;
288
289 while (inlen) {
290 /*
291 * Note inlen is always a multiple of four here
292 */
293 if (*bp & 0x80 || (c1 = asctobin[*bp]) & 0x80) {
294 goto errorOut;
295 }
296 inlen--;
297 bp++;
298 if (*bp & 0x80 || (c2 = asctobin[*bp]) & 0x80){
299 goto errorOut;
300 }
301 inlen--;
302 bp++;
303 if (*bp == PAD) {
304 /*
305 * two input bytes, one output byte
306 */
307 c3 = c4 = 0;
308 thisOlen = 1;
309 if (c2 & 0xf) {
310 goto errorOut;
311 }
312 bp++;
313 inlen--;
314 if (*bp == PAD) {
315 bp++;
316 inlen--;
317 if(inlen > 0) {
318 goto errorOut;
319 }
320 }
321 else {
322 goto errorOut;
323 }
324 } else if (*bp & 0x80 || (c3 = asctobin[*bp]) & 0x80) {
325 goto errorOut;
326 } else {
327 bp++;
328 inlen--;
329 if (*bp == PAD) {
330 /*
331 * Three input bytes, two output
332 */
333 c4 = 0;
334 thisOlen = 2;
335 if (c3 & 3) {
336 goto errorOut;
337 }
338 } else if (*bp & 0x80 || (c4 = asctobin[*bp]) & 0x80) {
339 goto errorOut;
340 } else {
341 /*
342 * Normal non-pad case
343 */
344 thisOlen = 3;
345 }
346 bp++;
347 inlen--;
348 }
349 j = (c1 << 2) | (c2 >> 4);
350 *outp++ = j;
351 if(thisOlen > 1) {
352 j = (c2 << 4) | (c3 >> 2);
353 *outp++ = j;
354 if(thisOlen == 3) {
355 j = (c3 << 6) | c4;
356 *outp++ = j;
357 }
358 }
359 olen += thisOlen;
360 }
361 ffree(news);
362 *outlen = olen;
363 return outbuf; /* normal return */
364
365 errorOut:
366 ffree(news);
367 ffree(outbuf);
368 return (unsigned char*) NULL;
369 }
370
371 /*
372 * Determine if specified input data is valid enc64 format. Returns 1
373 * if valid, 0 if not.
374 * This doesn't do a full enc64 parse job; it scans for legal characters
375 * and proper sync when a possible pad is found.
376 */
377 int isValidEnc64(const unsigned char *inbuf,
378 unsigned inlen)
379 {
380 int padChars = 0; // running count of PAD chars
381 int validEncChars = 0;
382 unsigned char c;
383
384 /*
385 * -- scan inbuf
386 * -- skip whitespace
387 * -- count valid chars
388 * -- ensure not more than 2 PAD chars, only at end
389 * -- ensure valid chars mod 4 == 0
390 */
391
392 while(inlen) {
393 c = *inbuf++;
394 inlen--;
395 if(isWhite(c)) {
396 continue;
397 }
398 if(c == PAD) {
399 if(++padChars > 2) {
400 return 0; // max of 2 PAD chars at end
401 }
402 }
403 else if(padChars > 0) {
404 return 0; // no normal chars after seeing PAD
405 }
406 else if((c & 0x80) || ((asctobin[c]) & 0x80)) {
407 return 0; // invalid encoded char
408 }
409 validEncChars++;
410 }
411 if((validEncChars & 0x03) != 0) {
412 return 0;
413 }
414 else {
415 return 1;
416 }
417 }