Sync to trunk (r44371)
[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.1 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 #include "wine/unicode.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
31
32 #define CERT_HEADER "-----BEGIN CERTIFICATE-----"
33 #define CERT_TRAILER "-----END CERTIFICATE-----"
34 #define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
35 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
36 #define X509_HEADER "-----BEGIN X509 CRL-----"
37 #define X509_TRAILER "-----END X509 CRL-----"
38
39 static const WCHAR CERT_HEADER_W[] = {
40 '-','-','-','-','-','B','E','G','I','N',' ','C','E','R','T','I','F','I','C',
41 'A','T','E','-','-','-','-','-',0 };
42 static const WCHAR CERT_TRAILER_W[] = {
43 '-','-','-','-','-','E','N','D',' ','C','E','R','T','I','F','I','C','A','T',
44 'E','-','-','-','-','-',0 };
45 static const WCHAR CERT_REQUEST_HEADER_W[] = {
46 '-','-','-','-','-','B','E','G','I','N',' ','N','E','W',' ','C','E','R','T',
47 'I','F','I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
48 static const WCHAR CERT_REQUEST_TRAILER_W[] = {
49 '-','-','-','-','-','E','N','D',' ','N','E','W',' ','C','E','R','T','I','F',
50 'I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
51 static const WCHAR X509_HEADER_W[] = {
52 '-','-','-','-','-','B','E','G','I','N',' ','X','5','0','9',' ','C','R','L',
53 '-','-','-','-','-',0 };
54 static const WCHAR X509_TRAILER_W[] = {
55 '-','-','-','-','-','E','N','D',' ','X','5','0','9',' ','C','R','L','-','-',
56 '-','-','-',0 };
57
58 static const char b64[] =
59 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60
61 typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary,
62 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString);
63 typedef BOOL (*BinaryToStringWFunc)(const BYTE *pbBinary,
64 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString);
65
66 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
67 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
68 {
69 BOOL ret = TRUE;
70
71 if (*pcchString < cbBinary)
72 {
73 if (!pszString)
74 *pcchString = cbBinary;
75 else
76 {
77 SetLastError(ERROR_INSUFFICIENT_BUFFER);
78 *pcchString = cbBinary;
79 ret = FALSE;
80 }
81 }
82 else
83 {
84 if (cbBinary)
85 memcpy(pszString, pbBinary, cbBinary);
86 *pcchString = cbBinary;
87 }
88 return ret;
89 }
90
91 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
92 char* out_buf, DWORD *out_len)
93 {
94 int div, i;
95 const BYTE *d = in_buf;
96 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
97 DWORD needed;
98 LPSTR ptr;
99
100 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
101 needed = bytes + pad_bytes + 1;
102 if (sep)
103 needed += (needed / 64 + 1) * strlen(sep);
104
105 if (needed > *out_len)
106 {
107 *out_len = needed;
108 return ERROR_INSUFFICIENT_BUFFER;
109 }
110 else
111 *out_len = needed;
112
113 /* Three bytes of input give 4 chars of output */
114 div = in_len / 3;
115
116 ptr = out_buf;
117 i = 0;
118 while (div > 0)
119 {
120 if (sep && i && i % 64 == 0)
121 {
122 strcpy(ptr, sep);
123 ptr += strlen(sep);
124 }
125 /* first char is the first 6 bits of the first byte*/
126 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
127 /* second char is the last 2 bits of the first byte and the first 4
128 * bits of the second byte */
129 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
130 /* third char is the last 4 bits of the second byte and the first 2
131 * bits of the third byte */
132 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
133 /* fourth char is the remaining 6 bits of the third byte */
134 *ptr++ = b64[ d[2] & 0x3f];
135 i += 4;
136 d += 3;
137 div--;
138 }
139
140 switch(pad_bytes)
141 {
142 case 1:
143 /* first char is the first 6 bits of the first byte*/
144 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
145 /* second char is the last 2 bits of the first byte and the first 4
146 * bits of the second byte */
147 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
148 /* third char is the last 4 bits of the second byte padded with
149 * two zeroes */
150 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
151 /* fourth char is a = to indicate one byte of padding */
152 *ptr++ = '=';
153 break;
154 case 2:
155 /* first char is the first 6 bits of the first byte*/
156 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
157 /* second char is the last 2 bits of the first byte padded with
158 * four zeroes*/
159 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
160 /* third char is = to indicate padding */
161 *ptr++ = '=';
162 /* fourth char is = to indicate padding */
163 *ptr++ = '=';
164 break;
165 }
166 if (sep)
167 strcpy(ptr, sep);
168
169 return ERROR_SUCCESS;
170 }
171
172 static BOOL BinaryToBase64A(const BYTE *pbBinary,
173 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
174 {
175 static const char crlf[] = "\r\n", lf[] = "\n";
176 BOOL ret = TRUE;
177 LPCSTR header = NULL, trailer = NULL, sep;
178 DWORD charsNeeded;
179
180 if (dwFlags & CRYPT_STRING_NOCR)
181 sep = lf;
182 else if (dwFlags & CRYPT_STRING_NOCRLF)
183 sep = NULL;
184 else
185 sep = crlf;
186 switch (dwFlags & 0x0fffffff)
187 {
188 case CRYPT_STRING_BASE64:
189 /* no header or footer */
190 break;
191 case CRYPT_STRING_BASE64HEADER:
192 header = CERT_HEADER;
193 trailer = CERT_TRAILER;
194 break;
195 case CRYPT_STRING_BASE64REQUESTHEADER:
196 header = CERT_REQUEST_HEADER;
197 trailer = CERT_REQUEST_TRAILER;
198 break;
199 case CRYPT_STRING_BASE64X509CRLHEADER:
200 header = X509_HEADER;
201 trailer = X509_TRAILER;
202 break;
203 }
204
205 charsNeeded = 0;
206 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
207 if (sep)
208 charsNeeded += strlen(sep);
209 if (header)
210 charsNeeded += strlen(header) + strlen(sep);
211 if (trailer)
212 charsNeeded += strlen(trailer) + strlen(sep);
213 if (charsNeeded <= *pcchString)
214 {
215 LPSTR ptr = pszString;
216 DWORD size = charsNeeded;
217
218 if (header)
219 {
220 strcpy(ptr, header);
221 ptr += strlen(ptr);
222 if (sep)
223 {
224 strcpy(ptr, sep);
225 ptr += strlen(sep);
226 }
227 }
228 encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
229 ptr += size - 1;
230 if (trailer)
231 {
232 strcpy(ptr, trailer);
233 ptr += strlen(ptr);
234 if (sep)
235 {
236 strcpy(ptr, sep);
237 ptr += strlen(sep);
238 }
239 }
240 *pcchString = charsNeeded - 1;
241 }
242 else if (pszString)
243 {
244 *pcchString = charsNeeded;
245 SetLastError(ERROR_INSUFFICIENT_BUFFER);
246 ret = FALSE;
247 }
248 else
249 *pcchString = charsNeeded;
250 return ret;
251 }
252
253 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
254 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
255 {
256 BinaryToStringAFunc encoder = NULL;
257
258 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
259 pcchString);
260
261 if (!pbBinary)
262 {
263 SetLastError(ERROR_INVALID_PARAMETER);
264 return FALSE;
265 }
266 if (!pcchString)
267 {
268 SetLastError(ERROR_INVALID_PARAMETER);
269 return FALSE;
270 }
271
272 switch (dwFlags & 0x0fffffff)
273 {
274 case CRYPT_STRING_BINARY:
275 encoder = EncodeBinaryToBinaryA;
276 break;
277 case CRYPT_STRING_BASE64:
278 case CRYPT_STRING_BASE64HEADER:
279 case CRYPT_STRING_BASE64REQUESTHEADER:
280 case CRYPT_STRING_BASE64X509CRLHEADER:
281 encoder = BinaryToBase64A;
282 break;
283 case CRYPT_STRING_HEX:
284 case CRYPT_STRING_HEXASCII:
285 case CRYPT_STRING_HEXADDR:
286 case CRYPT_STRING_HEXASCIIADDR:
287 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
288 /* fall through */
289 default:
290 SetLastError(ERROR_INVALID_PARAMETER);
291 return FALSE;
292 }
293 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
294 }
295
296 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
297 WCHAR* out_buf, DWORD *out_len)
298 {
299 int div, i;
300 const BYTE *d = in_buf;
301 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
302 DWORD needed;
303 LPWSTR ptr;
304
305 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
306 needed = bytes + pad_bytes + 1;
307 if (sep)
308 needed += (needed / 64 + 1) * strlenW(sep);
309
310 if (needed > *out_len)
311 {
312 *out_len = needed;
313 return ERROR_INSUFFICIENT_BUFFER;
314 }
315 else
316 *out_len = needed;
317
318 /* Three bytes of input give 4 chars of output */
319 div = in_len / 3;
320
321 ptr = out_buf;
322 i = 0;
323 while (div > 0)
324 {
325 if (sep && i && i % 64 == 0)
326 {
327 strcpyW(ptr, sep);
328 ptr += strlenW(sep);
329 }
330 /* first char is the first 6 bits of the first byte*/
331 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
332 /* second char is the last 2 bits of the first byte and the first 4
333 * bits of the second byte */
334 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
335 /* third char is the last 4 bits of the second byte and the first 2
336 * bits of the third byte */
337 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
338 /* fourth char is the remaining 6 bits of the third byte */
339 *ptr++ = b64[ d[2] & 0x3f];
340 i += 4;
341 d += 3;
342 div--;
343 }
344
345 switch(pad_bytes)
346 {
347 case 1:
348 /* first char is the first 6 bits of the first byte*/
349 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
350 /* second char is the last 2 bits of the first byte and the first 4
351 * bits of the second byte */
352 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
353 /* third char is the last 4 bits of the second byte padded with
354 * two zeroes */
355 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
356 /* fourth char is a = to indicate one byte of padding */
357 *ptr++ = '=';
358 break;
359 case 2:
360 /* first char is the first 6 bits of the first byte*/
361 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
362 /* second char is the last 2 bits of the first byte padded with
363 * four zeroes*/
364 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
365 /* third char is = to indicate padding */
366 *ptr++ = '=';
367 /* fourth char is = to indicate padding */
368 *ptr++ = '=';
369 break;
370 }
371 if (sep)
372 strcpyW(ptr, sep);
373
374 return ERROR_SUCCESS;
375 }
376
377 static BOOL BinaryToBase64W(const BYTE *pbBinary,
378 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
379 {
380 static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 };
381 BOOL ret = TRUE;
382 LPCWSTR header = NULL, trailer = NULL, sep;
383 DWORD charsNeeded;
384
385 if (dwFlags & CRYPT_STRING_NOCR)
386 sep = lf;
387 else if (dwFlags & CRYPT_STRING_NOCRLF)
388 sep = NULL;
389 else
390 sep = crlf;
391 switch (dwFlags & 0x0fffffff)
392 {
393 case CRYPT_STRING_BASE64:
394 /* no header or footer */
395 break;
396 case CRYPT_STRING_BASE64HEADER:
397 header = CERT_HEADER_W;
398 trailer = CERT_TRAILER_W;
399 break;
400 case CRYPT_STRING_BASE64REQUESTHEADER:
401 header = CERT_REQUEST_HEADER_W;
402 trailer = CERT_REQUEST_TRAILER_W;
403 break;
404 case CRYPT_STRING_BASE64X509CRLHEADER:
405 header = X509_HEADER_W;
406 trailer = X509_TRAILER_W;
407 break;
408 }
409
410 charsNeeded = 0;
411 encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
412 if (sep)
413 charsNeeded += strlenW(sep);
414 if (header)
415 charsNeeded += strlenW(header) + strlenW(sep);
416 if (trailer)
417 charsNeeded += strlenW(trailer) + strlenW(sep);
418 if (charsNeeded <= *pcchString)
419 {
420 LPWSTR ptr = pszString;
421 DWORD size = charsNeeded;
422
423 if (header)
424 {
425 strcpyW(ptr, header);
426 ptr += strlenW(ptr);
427 if (sep)
428 {
429 strcpyW(ptr, sep);
430 ptr += strlenW(sep);
431 }
432 }
433 encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
434 ptr += size - 1;
435 if (trailer)
436 {
437 strcpyW(ptr, trailer);
438 ptr += strlenW(ptr);
439 if (sep)
440 {
441 strcpyW(ptr, sep);
442 ptr += strlenW(sep);
443 }
444 }
445 *pcchString = charsNeeded - 1;
446 }
447 else if (pszString)
448 {
449 *pcchString = charsNeeded;
450 SetLastError(ERROR_INSUFFICIENT_BUFFER);
451 ret = FALSE;
452 }
453 else
454 *pcchString = charsNeeded;
455 return ret;
456 }
457
458 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
459 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
460 {
461 BinaryToStringWFunc encoder = NULL;
462
463 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
464 pcchString);
465
466 if (!pbBinary)
467 {
468 SetLastError(ERROR_INVALID_PARAMETER);
469 return FALSE;
470 }
471 if (!pcchString)
472 {
473 SetLastError(ERROR_INVALID_PARAMETER);
474 return FALSE;
475 }
476
477 switch (dwFlags & 0x0fffffff)
478 {
479 case CRYPT_STRING_BASE64:
480 case CRYPT_STRING_BASE64HEADER:
481 case CRYPT_STRING_BASE64REQUESTHEADER:
482 case CRYPT_STRING_BASE64X509CRLHEADER:
483 encoder = BinaryToBase64W;
484 break;
485 case CRYPT_STRING_BINARY:
486 case CRYPT_STRING_HEX:
487 case CRYPT_STRING_HEXASCII:
488 case CRYPT_STRING_HEXADDR:
489 case CRYPT_STRING_HEXASCIIADDR:
490 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
491 /* fall through */
492 default:
493 SetLastError(ERROR_INVALID_PARAMETER);
494 return FALSE;
495 }
496 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
497 }
498
499 static inline BYTE decodeBase64Byte(int c)
500 {
501 BYTE ret;
502
503 if (c >= 'A' && c <= 'Z')
504 ret = c - 'A';
505 else if (c >= 'a' && c <= 'z')
506 ret = c - 'a' + 26;
507 else if (c >= '0' && c <= '9')
508 ret = c - '0' + 52;
509 else if (c == '+')
510 ret = 62;
511 else if (c == '/')
512 ret = 63;
513 else
514 ret = 64;
515 return ret;
516 }
517
518 static LONG decodeBase64Block(const char *in_buf, int in_len,
519 const char **nextBlock, PBYTE out_buf, DWORD *out_len)
520 {
521 int len = in_len, i;
522 const char *d = in_buf;
523 int ip0, ip1, ip2, ip3;
524
525 if (len < 4)
526 return ERROR_INVALID_DATA;
527
528 i = 0;
529 if (d[2] == '=')
530 {
531 if ((ip0 = decodeBase64Byte(d[0])) > 63)
532 return ERROR_INVALID_DATA;
533 if ((ip1 = decodeBase64Byte(d[1])) > 63)
534 return ERROR_INVALID_DATA;
535
536 if (out_buf)
537 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
538 i++;
539 }
540 else if (d[3] == '=')
541 {
542 if ((ip0 = decodeBase64Byte(d[0])) > 63)
543 return ERROR_INVALID_DATA;
544 if ((ip1 = decodeBase64Byte(d[1])) > 63)
545 return ERROR_INVALID_DATA;
546 if ((ip2 = decodeBase64Byte(d[2])) > 63)
547 return ERROR_INVALID_DATA;
548
549 if (out_buf)
550 {
551 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
552 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
553 }
554 i += 2;
555 }
556 else
557 {
558 if ((ip0 = decodeBase64Byte(d[0])) > 63)
559 return ERROR_INVALID_DATA;
560 if ((ip1 = decodeBase64Byte(d[1])) > 63)
561 return ERROR_INVALID_DATA;
562 if ((ip2 = decodeBase64Byte(d[2])) > 63)
563 return ERROR_INVALID_DATA;
564 if ((ip3 = decodeBase64Byte(d[3])) > 63)
565 return ERROR_INVALID_DATA;
566
567 if (out_buf)
568 {
569 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
570 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
571 out_buf[i + 2] = (ip2 << 6) | ip3;
572 }
573 i += 3;
574 }
575 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
576 *nextBlock = d + 6;
577 else if (len >= 5 && d[4] == '\n')
578 *nextBlock = d + 5;
579 else if (len >= 4 && d[4])
580 *nextBlock = d + 4;
581 else
582 *nextBlock = NULL;
583 *out_len = i;
584 return ERROR_SUCCESS;
585 }
586
587 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
588 * string to convert.
589 */
590 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
591 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
592
593 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
594 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
595 {
596 LONG ret = ERROR_SUCCESS;
597 const char *nextBlock;
598 DWORD outLen = 0;
599
600 nextBlock = pszString;
601 while (nextBlock && !ret)
602 {
603 DWORD len = 0;
604
605 ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
606 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
607 if (!ret)
608 outLen += len;
609 if (cchString - (nextBlock - pszString) <= 0)
610 nextBlock = NULL;
611 }
612 *pcbBinary = outLen;
613 if (!ret)
614 {
615 if (pdwSkip)
616 *pdwSkip = 0;
617 if (pdwFlags)
618 *pdwFlags = CRYPT_STRING_BASE64;
619 }
620 else if (ret == ERROR_INSUFFICIENT_BUFFER)
621 {
622 if (!pbBinary)
623 ret = ERROR_SUCCESS;
624 }
625 return ret;
626 }
627
628 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
629 DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
630 DWORD *pcbBinary, DWORD *pdwSkip)
631 {
632 LONG ret;
633 LPCSTR ptr;
634
635 if (cchString > strlen(header) + strlen(trailer)
636 && (ptr = strstr(pszString, header)) != NULL)
637 {
638 LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
639
640 if (pszString[cchString - 1] == '\n')
641 {
642 cchString--;
643 trailerSpot--;
644 }
645 if (pszString[cchString - 1] == '\r')
646 {
647 cchString--;
648 trailerSpot--;
649 }
650 if (!strncmp(trailerSpot, trailer, strlen(trailer)))
651 {
652 if (pdwSkip)
653 *pdwSkip = ptr - pszString;
654 ptr += strlen(header);
655 if (*ptr == '\r') ptr++;
656 if (*ptr == '\n') ptr++;
657 cchString -= ptr - pszString + strlen(trailer);
658 ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL,
659 NULL);
660 }
661 else
662 ret = ERROR_INVALID_DATA;
663 }
664 else
665 ret = ERROR_INVALID_DATA;
666 return ret;
667 }
668
669 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
670 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
671 {
672 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
673 CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
674
675 if (!ret && pdwFlags)
676 *pdwFlags = CRYPT_STRING_BASE64HEADER;
677 return ret;
678 }
679
680 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
681 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
682 {
683 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
684 CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
685
686 if (!ret && pdwFlags)
687 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
688 return ret;
689 }
690
691 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
692 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
693 {
694 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
695 X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
696
697 if (!ret && pdwFlags)
698 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
699 return ret;
700 }
701
702 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
703 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
704 {
705 LONG ret;
706
707 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
708 pdwSkip, pdwFlags);
709 if (ret == ERROR_INVALID_DATA)
710 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
711 pdwSkip, pdwFlags);
712 return ret;
713 }
714
715 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
716 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
717 {
718 LONG ret = ERROR_SUCCESS;
719
720 if (*pcbBinary < cchString)
721 {
722 if (!pbBinary)
723 *pcbBinary = cchString;
724 else
725 {
726 ret = ERROR_INSUFFICIENT_BUFFER;
727 *pcbBinary = cchString;
728 }
729 }
730 else
731 {
732 if (cchString)
733 memcpy(pbBinary, pszString, cchString);
734 *pcbBinary = cchString;
735 }
736 return ret;
737 }
738
739 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
740 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
741 {
742 LONG ret;
743
744 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
745 pdwSkip, pdwFlags);
746 if (ret == ERROR_INVALID_DATA)
747 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
748 pdwSkip, pdwFlags);
749 if (ret == ERROR_INVALID_DATA)
750 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
751 pdwSkip, pdwFlags);
752 return ret;
753 }
754
755 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
756 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
757 DWORD *pdwSkip, DWORD *pdwFlags)
758 {
759 StringToBinaryAFunc decoder;
760 LONG ret;
761
762 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
763 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
764
765 if (!pszString)
766 {
767 SetLastError(ERROR_INVALID_PARAMETER);
768 return FALSE;
769 }
770 /* Only the bottom byte contains valid types */
771 if (dwFlags & 0xfffffff0)
772 {
773 SetLastError(ERROR_INVALID_DATA);
774 return FALSE;
775 }
776 switch (dwFlags)
777 {
778 case CRYPT_STRING_BASE64_ANY:
779 decoder = Base64AnyToBinaryA;
780 break;
781 case CRYPT_STRING_BASE64:
782 decoder = Base64ToBinaryA;
783 break;
784 case CRYPT_STRING_BASE64HEADER:
785 decoder = Base64HeaderToBinaryA;
786 break;
787 case CRYPT_STRING_BASE64REQUESTHEADER:
788 decoder = Base64RequestHeaderToBinaryA;
789 break;
790 case CRYPT_STRING_BASE64X509CRLHEADER:
791 decoder = Base64X509HeaderToBinaryA;
792 break;
793 case CRYPT_STRING_BINARY:
794 decoder = DecodeBinaryToBinaryA;
795 break;
796 case CRYPT_STRING_ANY:
797 decoder = DecodeAnyA;
798 break;
799 case CRYPT_STRING_HEX:
800 case CRYPT_STRING_HEXASCII:
801 case CRYPT_STRING_HEXADDR:
802 case CRYPT_STRING_HEXASCIIADDR:
803 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
804 /* fall through */
805 default:
806 SetLastError(ERROR_INVALID_PARAMETER);
807 return FALSE;
808 }
809 if (!cchString)
810 cchString = strlen(pszString);
811 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
812 if (ret)
813 SetLastError(ret);
814 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
815 }
816
817 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
818 const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
819 {
820 int len = in_len, i;
821 const WCHAR *d = in_buf;
822 int ip0, ip1, ip2, ip3;
823
824 if (len < 4)
825 return ERROR_INVALID_DATA;
826
827 i = 0;
828 if (d[2] == '=')
829 {
830 if ((ip0 = decodeBase64Byte(d[0])) > 63)
831 return ERROR_INVALID_DATA;
832 if ((ip1 = decodeBase64Byte(d[1])) > 63)
833 return ERROR_INVALID_DATA;
834
835 if (out_buf)
836 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
837 i++;
838 }
839 else if (d[3] == '=')
840 {
841 if ((ip0 = decodeBase64Byte(d[0])) > 63)
842 return ERROR_INVALID_DATA;
843 if ((ip1 = decodeBase64Byte(d[1])) > 63)
844 return ERROR_INVALID_DATA;
845 if ((ip2 = decodeBase64Byte(d[2])) > 63)
846 return ERROR_INVALID_DATA;
847
848 if (out_buf)
849 {
850 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
851 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
852 }
853 i += 2;
854 }
855 else
856 {
857 if ((ip0 = decodeBase64Byte(d[0])) > 63)
858 return ERROR_INVALID_DATA;
859 if ((ip1 = decodeBase64Byte(d[1])) > 63)
860 return ERROR_INVALID_DATA;
861 if ((ip2 = decodeBase64Byte(d[2])) > 63)
862 return ERROR_INVALID_DATA;
863 if ((ip3 = decodeBase64Byte(d[3])) > 63)
864 return ERROR_INVALID_DATA;
865
866 if (out_buf)
867 {
868 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
869 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
870 out_buf[i + 2] = (ip2 << 6) | ip3;
871 }
872 i += 3;
873 }
874 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
875 *nextBlock = d + 6;
876 else if (len >= 5 && d[4] == '\n')
877 *nextBlock = d + 5;
878 else if (len >= 4 && d[4])
879 *nextBlock = d + 4;
880 else
881 *nextBlock = NULL;
882 *out_len = i;
883 return ERROR_SUCCESS;
884 }
885
886 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
887 * string to convert.
888 */
889 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
890 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
891
892 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
893 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
894 {
895 LONG ret = ERROR_SUCCESS;
896 const WCHAR *nextBlock;
897 DWORD outLen = 0;
898
899 nextBlock = pszString;
900 while (nextBlock && !ret)
901 {
902 DWORD len = 0;
903
904 ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
905 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
906 if (!ret)
907 outLen += len;
908 if (cchString - (nextBlock - pszString) <= 0)
909 nextBlock = NULL;
910 }
911 *pcbBinary = outLen;
912 if (!ret)
913 {
914 if (pdwSkip)
915 *pdwSkip = 0;
916 if (pdwFlags)
917 *pdwFlags = CRYPT_STRING_BASE64;
918 }
919 else if (ret == ERROR_INSUFFICIENT_BUFFER)
920 {
921 if (!pbBinary)
922 ret = ERROR_SUCCESS;
923 }
924 return ret;
925 }
926
927 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
928 DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
929 DWORD *pcbBinary, DWORD *pdwSkip)
930 {
931 LONG ret;
932 LPCWSTR ptr;
933
934 if (cchString > strlenW(header) + strlenW(trailer)
935 && (ptr = strstrW(pszString, header)) != NULL)
936 {
937 LPCWSTR trailerSpot = pszString + cchString - strlenW(trailer);
938
939 if (pszString[cchString - 1] == '\n')
940 {
941 cchString--;
942 trailerSpot--;
943 }
944 if (pszString[cchString - 1] == '\r')
945 {
946 cchString--;
947 trailerSpot--;
948 }
949 if (!strncmpW(trailerSpot, trailer, strlenW(trailer)))
950 {
951 if (pdwSkip)
952 *pdwSkip = ptr - pszString;
953 ptr += strlenW(header);
954 if (*ptr == '\r') ptr++;
955 if (*ptr == '\n') ptr++;
956 cchString -= ptr - pszString + strlenW(trailer);
957 ret = Base64ToBinaryW(ptr, cchString, pbBinary, pcbBinary, NULL,
958 NULL);
959 }
960 else
961 ret = ERROR_INVALID_DATA;
962 }
963 else
964 ret = ERROR_INVALID_DATA;
965 return ret;
966 }
967
968 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
969 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
970 {
971 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
972 CERT_HEADER_W, CERT_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
973
974 if (!ret && pdwFlags)
975 *pdwFlags = CRYPT_STRING_BASE64HEADER;
976 return ret;
977 }
978
979 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
980 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
981 {
982 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
983 CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
984 pdwSkip);
985
986 if (!ret && pdwFlags)
987 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
988 return ret;
989 }
990
991 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
992 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
993 {
994 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
995 X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
996
997 if (!ret && pdwFlags)
998 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
999 return ret;
1000 }
1001
1002 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
1003 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1004 {
1005 LONG ret;
1006
1007 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1008 pdwSkip, pdwFlags);
1009 if (ret == ERROR_INVALID_DATA)
1010 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1011 pdwSkip, pdwFlags);
1012 return ret;
1013 }
1014
1015 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
1016 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1017 {
1018 LONG ret = ERROR_SUCCESS;
1019
1020 if (*pcbBinary < cchString)
1021 {
1022 if (!pbBinary)
1023 *pcbBinary = cchString;
1024 else
1025 {
1026 ret = ERROR_INSUFFICIENT_BUFFER;
1027 *pcbBinary = cchString;
1028 }
1029 }
1030 else
1031 {
1032 if (cchString)
1033 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1034 *pcbBinary = cchString * sizeof(WCHAR);
1035 }
1036 return ret;
1037 }
1038
1039 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1040 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1041 {
1042 LONG ret;
1043
1044 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1045 pdwSkip, pdwFlags);
1046 if (ret == ERROR_INVALID_DATA)
1047 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1048 pdwSkip, pdwFlags);
1049 if (ret == ERROR_INVALID_DATA)
1050 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1051 pdwSkip, pdwFlags);
1052 return ret;
1053 }
1054
1055 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1056 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1057 DWORD *pdwSkip, DWORD *pdwFlags)
1058 {
1059 StringToBinaryWFunc decoder;
1060 LONG ret;
1061
1062 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
1063 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1064
1065 if (!pszString)
1066 {
1067 SetLastError(ERROR_INVALID_PARAMETER);
1068 return FALSE;
1069 }
1070 /* Only the bottom byte contains valid types */
1071 if (dwFlags & 0xfffffff0)
1072 {
1073 SetLastError(ERROR_INVALID_DATA);
1074 return FALSE;
1075 }
1076 switch (dwFlags)
1077 {
1078 case CRYPT_STRING_BASE64_ANY:
1079 decoder = Base64AnyToBinaryW;
1080 break;
1081 case CRYPT_STRING_BASE64:
1082 decoder = Base64ToBinaryW;
1083 break;
1084 case CRYPT_STRING_BASE64HEADER:
1085 decoder = Base64HeaderToBinaryW;
1086 break;
1087 case CRYPT_STRING_BASE64REQUESTHEADER:
1088 decoder = Base64RequestHeaderToBinaryW;
1089 break;
1090 case CRYPT_STRING_BASE64X509CRLHEADER:
1091 decoder = Base64X509HeaderToBinaryW;
1092 break;
1093 case CRYPT_STRING_BINARY:
1094 decoder = DecodeBinaryToBinaryW;
1095 break;
1096 case CRYPT_STRING_ANY:
1097 decoder = DecodeAnyW;
1098 break;
1099 case CRYPT_STRING_HEX:
1100 case CRYPT_STRING_HEXASCII:
1101 case CRYPT_STRING_HEXADDR:
1102 case CRYPT_STRING_HEXASCIIADDR:
1103 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1104 /* fall through */
1105 default:
1106 SetLastError(ERROR_INVALID_PARAMETER);
1107 return FALSE;
1108 }
1109 if (!cchString)
1110 cchString = strlenW(pszString);
1111 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1112 if (ret)
1113 SetLastError(ret);
1114 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
1115 }