Autosyncing with Wine HEAD
[reactos.git] / reactos / dll / win32 / crypt32 / base64.c
1 /*
2 * base64 encoder/decoder
3 *
4 * Copyright 2005 by Kai Blin
5 * Copyright 2006 Juan Lang
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winerror.h"
26 #include "wincrypt.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
30
31 #define CERT_HEADER "-----BEGIN CERTIFICATE-----"
32 #define CERT_TRAILER "-----END CERTIFICATE-----"
33 #define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
34 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
35 #define X509_HEADER "-----BEGIN X509 CRL-----"
36 #define X509_TRAILER "-----END X509 CRL-----"
37
38 static const char b64[] =
39 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
40
41 typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary,
42 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString);
43
44 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
45 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
46 {
47 BOOL ret = TRUE;
48
49 if (*pcchString < cbBinary)
50 {
51 if (!pszString)
52 *pcchString = cbBinary;
53 else
54 {
55 SetLastError(ERROR_INSUFFICIENT_BUFFER);
56 *pcchString = cbBinary;
57 ret = FALSE;
58 }
59 }
60 else
61 {
62 if (cbBinary)
63 memcpy(pszString, pbBinary, cbBinary);
64 *pcchString = cbBinary;
65 }
66 return ret;
67 }
68
69 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
70 char* out_buf, DWORD *out_len)
71 {
72 int div, i;
73 const BYTE *d = in_buf;
74 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
75 DWORD needed;
76 LPSTR ptr;
77
78 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
79 needed = bytes + pad_bytes + 1;
80 needed += (needed / 64 + 1) * strlen(sep);
81
82 if (needed > *out_len)
83 {
84 *out_len = needed;
85 return ERROR_INSUFFICIENT_BUFFER;
86 }
87 else
88 *out_len = needed;
89
90 /* Three bytes of input give 4 chars of output */
91 div = in_len / 3;
92
93 ptr = out_buf;
94 i = 0;
95 while (div > 0)
96 {
97 if (i && i % 64 == 0)
98 {
99 strcpy(ptr, sep);
100 ptr += strlen(sep);
101 }
102 /* first char is the first 6 bits of the first byte*/
103 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
104 /* second char is the last 2 bits of the first byte and the first 4
105 * bits of the second byte */
106 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
107 /* third char is the last 4 bits of the second byte and the first 2
108 * bits of the third byte */
109 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
110 /* fourth char is the remaining 6 bits of the third byte */
111 *ptr++ = b64[ d[2] & 0x3f];
112 i += 4;
113 d += 3;
114 div--;
115 }
116
117 switch(pad_bytes)
118 {
119 case 1:
120 /* first char is the first 6 bits of the first byte*/
121 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
122 /* second char is the last 2 bits of the first byte and the first 4
123 * bits of the second byte */
124 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
125 /* third char is the last 4 bits of the second byte padded with
126 * two zeroes */
127 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
128 /* fourth char is a = to indicate one byte of padding */
129 *ptr++ = '=';
130 break;
131 case 2:
132 /* first char is the first 6 bits of the first byte*/
133 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
134 /* second char is the last 2 bits of the first byte padded with
135 * four zeroes*/
136 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
137 /* third char is = to indicate padding */
138 *ptr++ = '=';
139 /* fourth char is = to indicate padding */
140 *ptr++ = '=';
141 break;
142 }
143 strcpy(ptr, sep);
144
145 return ERROR_SUCCESS;
146 }
147
148 static BOOL BinaryToBase64A(const BYTE *pbBinary,
149 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
150 {
151 static const char crlf[] = "\r\n", lf[] = "\n";
152 BOOL ret = TRUE;
153 LPCSTR header = NULL, trailer = NULL, sep = NULL;
154 DWORD charsNeeded;
155
156 if (dwFlags & CRYPT_STRING_NOCR)
157 sep = lf;
158 else
159 sep = crlf;
160 switch (dwFlags & 0x7fffffff)
161 {
162 case CRYPT_STRING_BASE64:
163 /* no header or footer */
164 break;
165 case CRYPT_STRING_BASE64HEADER:
166 header = CERT_HEADER;
167 trailer = CERT_TRAILER;
168 break;
169 case CRYPT_STRING_BASE64REQUESTHEADER:
170 header = CERT_REQUEST_HEADER;
171 trailer = CERT_REQUEST_TRAILER;
172 break;
173 case CRYPT_STRING_BASE64X509CRLHEADER:
174 header = X509_HEADER;
175 trailer = X509_TRAILER;
176 break;
177 }
178
179 charsNeeded = 0;
180 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
181 charsNeeded += strlen(sep);
182 if (header)
183 charsNeeded += strlen(header) + strlen(sep);
184 if (trailer)
185 charsNeeded += strlen(trailer) + strlen(sep);
186 if (charsNeeded <= *pcchString)
187 {
188 LPSTR ptr = pszString;
189 DWORD size = charsNeeded;
190
191 if (header)
192 {
193 strcpy(ptr, header);
194 ptr += strlen(ptr);
195 strcpy(ptr, sep);
196 ptr += strlen(sep);
197 }
198 encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
199 ptr += size - 1;
200 if (trailer)
201 {
202 strcpy(ptr, trailer);
203 ptr += strlen(ptr);
204 strcpy(ptr, sep);
205 ptr += strlen(sep);
206 }
207 *pcchString = charsNeeded - 1;
208 }
209 else if (pszString)
210 {
211 *pcchString = charsNeeded;
212 SetLastError(ERROR_INSUFFICIENT_BUFFER);
213 ret = FALSE;
214 }
215 else
216 *pcchString = charsNeeded;
217 return ret;
218 }
219
220 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
221 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
222 {
223 BinaryToStringAFunc encoder = NULL;
224
225 TRACE("(%p, %ld, %08lx, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
226 pcchString);
227
228 if (!pbBinary)
229 {
230 SetLastError(ERROR_INVALID_PARAMETER);
231 return FALSE;
232 }
233 if (!pcchString)
234 {
235 SetLastError(ERROR_INVALID_PARAMETER);
236 return FALSE;
237 }
238
239 switch (dwFlags & 0x7fffffff)
240 {
241 case CRYPT_STRING_BINARY:
242 encoder = EncodeBinaryToBinaryA;
243 break;
244 case CRYPT_STRING_BASE64:
245 case CRYPT_STRING_BASE64HEADER:
246 case CRYPT_STRING_BASE64REQUESTHEADER:
247 case CRYPT_STRING_BASE64X509CRLHEADER:
248 encoder = BinaryToBase64A;
249 break;
250 case CRYPT_STRING_HEX:
251 case CRYPT_STRING_HEXASCII:
252 case CRYPT_STRING_HEXADDR:
253 case CRYPT_STRING_HEXASCIIADDR:
254 FIXME("Unimplemented type %ld\n", dwFlags & 0x7fffffff);
255 /* fall through */
256 default:
257 SetLastError(ERROR_INVALID_PARAMETER);
258 return FALSE;
259 }
260 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
261 }
262
263 static inline BYTE decodeBase64Byte(char c)
264 {
265 BYTE ret;
266
267 if (c >= 'A' && c <= 'Z')
268 ret = c - 'A';
269 else if (c >= 'a' && c <= 'z')
270 ret = c - 'a' + 26;
271 else if (c >= '0' && c <= '9')
272 ret = c - '0' + 52;
273 else if (c == '+')
274 ret = 62;
275 else if (c == '/')
276 ret = 63;
277 else
278 ret = 64;
279 return ret;
280 }
281
282 static LONG decodeBase64Block(const char *in_buf, int in_len,
283 const char **nextBlock, PBYTE out_buf, DWORD *out_len)
284 {
285 int len = in_len, i;
286 const char *d = in_buf;
287 int ip0, ip1, ip2, ip3;
288
289 if (len < 4)
290 return ERROR_INVALID_DATA;
291
292 i = 0;
293 if (d[2] == '=')
294 {
295 if ((ip0 = decodeBase64Byte(d[0])) > 63)
296 return ERROR_INVALID_DATA;
297 if ((ip1 = decodeBase64Byte(d[1])) > 63)
298 return ERROR_INVALID_DATA;
299
300 if (out_buf)
301 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
302 i++;
303 }
304 else if (d[3] == '=')
305 {
306 if ((ip0 = decodeBase64Byte(d[0])) > 63)
307 return ERROR_INVALID_DATA;
308 if ((ip1 = decodeBase64Byte(d[1])) > 63)
309 return ERROR_INVALID_DATA;
310 if ((ip2 = decodeBase64Byte(d[2])) > 63)
311 return ERROR_INVALID_DATA;
312
313 if (out_buf)
314 {
315 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
316 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
317 }
318 i += 2;
319 }
320 else
321 {
322 if ((ip0 = decodeBase64Byte(d[0])) > 63)
323 return ERROR_INVALID_DATA;
324 if ((ip1 = decodeBase64Byte(d[1])) > 63)
325 return ERROR_INVALID_DATA;
326 if ((ip2 = decodeBase64Byte(d[2])) > 63)
327 return ERROR_INVALID_DATA;
328 if ((ip3 = decodeBase64Byte(d[3])) > 63)
329 return ERROR_INVALID_DATA;
330
331 if (out_buf)
332 {
333 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
334 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
335 out_buf[i + 2] = (ip2 << 6) | ip3;
336 }
337 i += 3;
338 }
339 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
340 *nextBlock = d + 6;
341 else if (len >= 5 && d[4] == '\n')
342 *nextBlock = d + 5;
343 else if (len >= 4 && d[4])
344 *nextBlock = d + 4;
345 else
346 *nextBlock = NULL;
347 *out_len = i;
348 return ERROR_SUCCESS;
349 }
350
351 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
352 * string to convert.
353 */
354 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
355 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
356
357 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
358 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
359 {
360 LONG ret = ERROR_SUCCESS;
361 const char *nextBlock;
362 DWORD outLen = 0;
363
364 nextBlock = pszString;
365 while (nextBlock && !ret)
366 {
367 DWORD len = 0;
368
369 ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
370 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
371 if (!ret)
372 outLen += len;
373 if (cchString - (nextBlock - pszString) <= 0)
374 nextBlock = NULL;
375 }
376 *pcbBinary = outLen;
377 if (!ret)
378 {
379 if (pdwSkip)
380 *pdwSkip = 0;
381 if (pdwFlags)
382 *pdwFlags = CRYPT_STRING_BASE64;
383 }
384 else if (ret == ERROR_INSUFFICIENT_BUFFER)
385 {
386 if (!pbBinary)
387 ret = ERROR_SUCCESS;
388 }
389 return ret;
390 }
391
392 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
393 DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
394 DWORD *pcbBinary, DWORD *pdwSkip)
395 {
396 LONG ret;
397 LPCSTR ptr;
398
399 if (cchString > strlen(header) + strlen(trailer)
400 && (ptr = strstr(pszString, header)) != NULL)
401 {
402 LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
403
404 if (pszString[cchString - 1] == '\n')
405 {
406 cchString--;
407 trailerSpot--;
408 }
409 if (pszString[cchString - 1] == '\r')
410 {
411 cchString--;
412 trailerSpot--;
413 }
414 if (!strncmp(trailerSpot, trailer, strlen(trailer)))
415 {
416 if (pdwSkip)
417 *pdwSkip = ptr - pszString;
418 ptr += strlen(header);
419 if (*ptr == '\r') ptr++;
420 if (*ptr == '\n') ptr++;
421 cchString -= ptr - pszString + strlen(trailer);
422 ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL,
423 NULL);
424 }
425 else
426 ret = ERROR_INVALID_DATA;
427 }
428 else
429 ret = ERROR_INVALID_DATA;
430 return ret;
431 }
432
433 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
434 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
435 {
436 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
437 CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
438
439 if (!ret && pdwFlags)
440 *pdwFlags = CRYPT_STRING_BASE64HEADER;
441 return ret;
442 }
443
444 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
445 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
446 {
447 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
448 CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
449
450 if (!ret && pdwFlags)
451 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
452 return ret;
453 }
454
455 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
456 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
457 {
458 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
459 X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
460
461 if (!ret && pdwFlags)
462 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
463 return ret;
464 }
465
466 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
467 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
468 {
469 LONG ret;
470
471 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
472 pdwSkip, pdwFlags);
473 if (ret == ERROR_INVALID_DATA)
474 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
475 pdwSkip, pdwFlags);
476 return ret;
477 }
478
479 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
480 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
481 {
482 LONG ret = ERROR_SUCCESS;
483
484 if (*pcbBinary < cchString)
485 {
486 if (!pbBinary)
487 *pcbBinary = cchString;
488 else
489 {
490 ret = ERROR_INSUFFICIENT_BUFFER;
491 *pcbBinary = cchString;
492 }
493 }
494 else
495 {
496 if (cchString)
497 memcpy(pbBinary, pszString, cchString);
498 *pcbBinary = cchString;
499 }
500 return ret;
501 }
502
503 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
504 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
505 {
506 LONG ret;
507
508 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
509 pdwSkip, pdwFlags);
510 if (ret == ERROR_INVALID_DATA)
511 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
512 pdwSkip, pdwFlags);
513 if (ret == ERROR_INVALID_DATA)
514 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
515 pdwSkip, pdwFlags);
516 return ret;
517 }
518
519 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
520 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
521 DWORD *pdwSkip, DWORD *pdwFlags)
522 {
523 StringToBinaryAFunc decoder;
524 LONG ret;
525
526 TRACE("(%s, %ld, %08lx, %p, %p, %p, %p)\n", debugstr_a(pszString),
527 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
528
529 if (!pszString)
530 {
531 SetLastError(ERROR_INVALID_PARAMETER);
532 return FALSE;
533 }
534 /* Only the bottom byte contains valid types */
535 if (dwFlags & 0xfffffff0)
536 {
537 SetLastError(ERROR_INVALID_DATA);
538 return FALSE;
539 }
540 switch (dwFlags)
541 {
542 case CRYPT_STRING_BASE64_ANY:
543 decoder = Base64AnyToBinaryA;
544 break;
545 case CRYPT_STRING_BASE64:
546 decoder = Base64ToBinaryA;
547 break;
548 case CRYPT_STRING_BASE64HEADER:
549 decoder = Base64HeaderToBinaryA;
550 break;
551 case CRYPT_STRING_BASE64REQUESTHEADER:
552 decoder = Base64RequestHeaderToBinaryA;
553 break;
554 case CRYPT_STRING_BASE64X509CRLHEADER:
555 decoder = Base64X509HeaderToBinaryA;
556 break;
557 case CRYPT_STRING_BINARY:
558 decoder = DecodeBinaryToBinaryA;
559 break;
560 case CRYPT_STRING_ANY:
561 decoder = DecodeAnyA;
562 break;
563 case CRYPT_STRING_HEX:
564 case CRYPT_STRING_HEXASCII:
565 case CRYPT_STRING_HEXADDR:
566 case CRYPT_STRING_HEXASCIIADDR:
567 FIXME("Unimplemented type %ld\n", dwFlags & 0x7fffffff);
568 /* fall through */
569 default:
570 SetLastError(ERROR_INVALID_PARAMETER);
571 return FALSE;
572 }
573 if (!cchString)
574 cchString = strlen(pszString);
575 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
576 if (ret)
577 SetLastError(ret);
578 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
579 }