Merge HAL changes 34743, 34812, 34839, 34917, 35515, 35771, 35902, 35904,
[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
64 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
65 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
66 {
67 BOOL ret = TRUE;
68
69 if (*pcchString < cbBinary)
70 {
71 if (!pszString)
72 *pcchString = cbBinary;
73 else
74 {
75 SetLastError(ERROR_INSUFFICIENT_BUFFER);
76 *pcchString = cbBinary;
77 ret = FALSE;
78 }
79 }
80 else
81 {
82 if (cbBinary)
83 memcpy(pszString, pbBinary, cbBinary);
84 *pcchString = cbBinary;
85 }
86 return ret;
87 }
88
89 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
90 char* out_buf, DWORD *out_len)
91 {
92 int div, i;
93 const BYTE *d = in_buf;
94 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
95 DWORD needed;
96 LPSTR ptr;
97
98 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
99 needed = bytes + pad_bytes + 1;
100 needed += (needed / 64 + 1) * strlen(sep);
101
102 if (needed > *out_len)
103 {
104 *out_len = needed;
105 return ERROR_INSUFFICIENT_BUFFER;
106 }
107 else
108 *out_len = needed;
109
110 /* Three bytes of input give 4 chars of output */
111 div = in_len / 3;
112
113 ptr = out_buf;
114 i = 0;
115 while (div > 0)
116 {
117 if (i && i % 64 == 0)
118 {
119 strcpy(ptr, sep);
120 ptr += strlen(sep);
121 }
122 /* first char is the first 6 bits of the first byte*/
123 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
124 /* second char is the last 2 bits of the first byte and the first 4
125 * bits of the second byte */
126 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
127 /* third char is the last 4 bits of the second byte and the first 2
128 * bits of the third byte */
129 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
130 /* fourth char is the remaining 6 bits of the third byte */
131 *ptr++ = b64[ d[2] & 0x3f];
132 i += 4;
133 d += 3;
134 div--;
135 }
136
137 switch(pad_bytes)
138 {
139 case 1:
140 /* first char is the first 6 bits of the first byte*/
141 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
142 /* second char is the last 2 bits of the first byte and the first 4
143 * bits of the second byte */
144 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
145 /* third char is the last 4 bits of the second byte padded with
146 * two zeroes */
147 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
148 /* fourth char is a = to indicate one byte of padding */
149 *ptr++ = '=';
150 break;
151 case 2:
152 /* first char is the first 6 bits of the first byte*/
153 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
154 /* second char is the last 2 bits of the first byte padded with
155 * four zeroes*/
156 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
157 /* third char is = to indicate padding */
158 *ptr++ = '=';
159 /* fourth char is = to indicate padding */
160 *ptr++ = '=';
161 break;
162 }
163 strcpy(ptr, sep);
164
165 return ERROR_SUCCESS;
166 }
167
168 static BOOL BinaryToBase64A(const BYTE *pbBinary,
169 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
170 {
171 static const char crlf[] = "\r\n", lf[] = "\n";
172 BOOL ret = TRUE;
173 LPCSTR header = NULL, trailer = NULL, sep = NULL;
174 DWORD charsNeeded;
175
176 if (dwFlags & CRYPT_STRING_NOCR)
177 sep = lf;
178 else
179 sep = crlf;
180 switch (dwFlags & 0x7fffffff)
181 {
182 case CRYPT_STRING_BASE64:
183 /* no header or footer */
184 break;
185 case CRYPT_STRING_BASE64HEADER:
186 header = CERT_HEADER;
187 trailer = CERT_TRAILER;
188 break;
189 case CRYPT_STRING_BASE64REQUESTHEADER:
190 header = CERT_REQUEST_HEADER;
191 trailer = CERT_REQUEST_TRAILER;
192 break;
193 case CRYPT_STRING_BASE64X509CRLHEADER:
194 header = X509_HEADER;
195 trailer = X509_TRAILER;
196 break;
197 }
198
199 charsNeeded = 0;
200 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
201 charsNeeded += strlen(sep);
202 if (header)
203 charsNeeded += strlen(header) + strlen(sep);
204 if (trailer)
205 charsNeeded += strlen(trailer) + strlen(sep);
206 if (charsNeeded <= *pcchString)
207 {
208 LPSTR ptr = pszString;
209 DWORD size = charsNeeded;
210
211 if (header)
212 {
213 strcpy(ptr, header);
214 ptr += strlen(ptr);
215 strcpy(ptr, sep);
216 ptr += strlen(sep);
217 }
218 encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
219 ptr += size - 1;
220 if (trailer)
221 {
222 strcpy(ptr, trailer);
223 ptr += strlen(ptr);
224 strcpy(ptr, sep);
225 ptr += strlen(sep);
226 }
227 *pcchString = charsNeeded - 1;
228 }
229 else if (pszString)
230 {
231 *pcchString = charsNeeded;
232 SetLastError(ERROR_INSUFFICIENT_BUFFER);
233 ret = FALSE;
234 }
235 else
236 *pcchString = charsNeeded;
237 return ret;
238 }
239
240 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
241 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
242 {
243 BinaryToStringAFunc encoder = NULL;
244
245 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
246 pcchString);
247
248 if (!pbBinary)
249 {
250 SetLastError(ERROR_INVALID_PARAMETER);
251 return FALSE;
252 }
253 if (!pcchString)
254 {
255 SetLastError(ERROR_INVALID_PARAMETER);
256 return FALSE;
257 }
258
259 switch (dwFlags & 0x7fffffff)
260 {
261 case CRYPT_STRING_BINARY:
262 encoder = EncodeBinaryToBinaryA;
263 break;
264 case CRYPT_STRING_BASE64:
265 case CRYPT_STRING_BASE64HEADER:
266 case CRYPT_STRING_BASE64REQUESTHEADER:
267 case CRYPT_STRING_BASE64X509CRLHEADER:
268 encoder = BinaryToBase64A;
269 break;
270 case CRYPT_STRING_HEX:
271 case CRYPT_STRING_HEXASCII:
272 case CRYPT_STRING_HEXADDR:
273 case CRYPT_STRING_HEXASCIIADDR:
274 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
275 /* fall through */
276 default:
277 SetLastError(ERROR_INVALID_PARAMETER);
278 return FALSE;
279 }
280 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
281 }
282
283 static inline BYTE decodeBase64Byte(int c)
284 {
285 BYTE ret;
286
287 if (c >= 'A' && c <= 'Z')
288 ret = c - 'A';
289 else if (c >= 'a' && c <= 'z')
290 ret = c - 'a' + 26;
291 else if (c >= '0' && c <= '9')
292 ret = c - '0' + 52;
293 else if (c == '+')
294 ret = 62;
295 else if (c == '/')
296 ret = 63;
297 else
298 ret = 64;
299 return ret;
300 }
301
302 static LONG decodeBase64Block(const char *in_buf, int in_len,
303 const char **nextBlock, PBYTE out_buf, DWORD *out_len)
304 {
305 int len = in_len, i;
306 const char *d = in_buf;
307 int ip0, ip1, ip2, ip3;
308
309 if (len < 4)
310 return ERROR_INVALID_DATA;
311
312 i = 0;
313 if (d[2] == '=')
314 {
315 if ((ip0 = decodeBase64Byte(d[0])) > 63)
316 return ERROR_INVALID_DATA;
317 if ((ip1 = decodeBase64Byte(d[1])) > 63)
318 return ERROR_INVALID_DATA;
319
320 if (out_buf)
321 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
322 i++;
323 }
324 else if (d[3] == '=')
325 {
326 if ((ip0 = decodeBase64Byte(d[0])) > 63)
327 return ERROR_INVALID_DATA;
328 if ((ip1 = decodeBase64Byte(d[1])) > 63)
329 return ERROR_INVALID_DATA;
330 if ((ip2 = decodeBase64Byte(d[2])) > 63)
331 return ERROR_INVALID_DATA;
332
333 if (out_buf)
334 {
335 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
336 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
337 }
338 i += 2;
339 }
340 else
341 {
342 if ((ip0 = decodeBase64Byte(d[0])) > 63)
343 return ERROR_INVALID_DATA;
344 if ((ip1 = decodeBase64Byte(d[1])) > 63)
345 return ERROR_INVALID_DATA;
346 if ((ip2 = decodeBase64Byte(d[2])) > 63)
347 return ERROR_INVALID_DATA;
348 if ((ip3 = decodeBase64Byte(d[3])) > 63)
349 return ERROR_INVALID_DATA;
350
351 if (out_buf)
352 {
353 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
354 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
355 out_buf[i + 2] = (ip2 << 6) | ip3;
356 }
357 i += 3;
358 }
359 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
360 *nextBlock = d + 6;
361 else if (len >= 5 && d[4] == '\n')
362 *nextBlock = d + 5;
363 else if (len >= 4 && d[4])
364 *nextBlock = d + 4;
365 else
366 *nextBlock = NULL;
367 *out_len = i;
368 return ERROR_SUCCESS;
369 }
370
371 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
372 * string to convert.
373 */
374 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
375 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
376
377 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
378 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
379 {
380 LONG ret = ERROR_SUCCESS;
381 const char *nextBlock;
382 DWORD outLen = 0;
383
384 nextBlock = pszString;
385 while (nextBlock && !ret)
386 {
387 DWORD len = 0;
388
389 ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
390 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
391 if (!ret)
392 outLen += len;
393 if (cchString - (nextBlock - pszString) <= 0)
394 nextBlock = NULL;
395 }
396 *pcbBinary = outLen;
397 if (!ret)
398 {
399 if (pdwSkip)
400 *pdwSkip = 0;
401 if (pdwFlags)
402 *pdwFlags = CRYPT_STRING_BASE64;
403 }
404 else if (ret == ERROR_INSUFFICIENT_BUFFER)
405 {
406 if (!pbBinary)
407 ret = ERROR_SUCCESS;
408 }
409 return ret;
410 }
411
412 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
413 DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
414 DWORD *pcbBinary, DWORD *pdwSkip)
415 {
416 LONG ret;
417 LPCSTR ptr;
418
419 if (cchString > strlen(header) + strlen(trailer)
420 && (ptr = strstr(pszString, header)) != NULL)
421 {
422 LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
423
424 if (pszString[cchString - 1] == '\n')
425 {
426 cchString--;
427 trailerSpot--;
428 }
429 if (pszString[cchString - 1] == '\r')
430 {
431 cchString--;
432 trailerSpot--;
433 }
434 if (!strncmp(trailerSpot, trailer, strlen(trailer)))
435 {
436 if (pdwSkip)
437 *pdwSkip = ptr - pszString;
438 ptr += strlen(header);
439 if (*ptr == '\r') ptr++;
440 if (*ptr == '\n') ptr++;
441 cchString -= ptr - pszString + strlen(trailer);
442 ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL,
443 NULL);
444 }
445 else
446 ret = ERROR_INVALID_DATA;
447 }
448 else
449 ret = ERROR_INVALID_DATA;
450 return ret;
451 }
452
453 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
454 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
455 {
456 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
457 CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
458
459 if (!ret && pdwFlags)
460 *pdwFlags = CRYPT_STRING_BASE64HEADER;
461 return ret;
462 }
463
464 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
465 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
466 {
467 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
468 CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
469
470 if (!ret && pdwFlags)
471 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
472 return ret;
473 }
474
475 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
476 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
477 {
478 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
479 X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
480
481 if (!ret && pdwFlags)
482 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
483 return ret;
484 }
485
486 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
487 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
488 {
489 LONG ret;
490
491 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
492 pdwSkip, pdwFlags);
493 if (ret == ERROR_INVALID_DATA)
494 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
495 pdwSkip, pdwFlags);
496 return ret;
497 }
498
499 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
500 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
501 {
502 LONG ret = ERROR_SUCCESS;
503
504 if (*pcbBinary < cchString)
505 {
506 if (!pbBinary)
507 *pcbBinary = cchString;
508 else
509 {
510 ret = ERROR_INSUFFICIENT_BUFFER;
511 *pcbBinary = cchString;
512 }
513 }
514 else
515 {
516 if (cchString)
517 memcpy(pbBinary, pszString, cchString);
518 *pcbBinary = cchString;
519 }
520 return ret;
521 }
522
523 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
524 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
525 {
526 LONG ret;
527
528 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
529 pdwSkip, pdwFlags);
530 if (ret == ERROR_INVALID_DATA)
531 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
532 pdwSkip, pdwFlags);
533 if (ret == ERROR_INVALID_DATA)
534 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
535 pdwSkip, pdwFlags);
536 return ret;
537 }
538
539 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
540 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
541 DWORD *pdwSkip, DWORD *pdwFlags)
542 {
543 StringToBinaryAFunc decoder;
544 LONG ret;
545
546 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
547 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
548
549 if (!pszString)
550 {
551 SetLastError(ERROR_INVALID_PARAMETER);
552 return FALSE;
553 }
554 /* Only the bottom byte contains valid types */
555 if (dwFlags & 0xfffffff0)
556 {
557 SetLastError(ERROR_INVALID_DATA);
558 return FALSE;
559 }
560 switch (dwFlags)
561 {
562 case CRYPT_STRING_BASE64_ANY:
563 decoder = Base64AnyToBinaryA;
564 break;
565 case CRYPT_STRING_BASE64:
566 decoder = Base64ToBinaryA;
567 break;
568 case CRYPT_STRING_BASE64HEADER:
569 decoder = Base64HeaderToBinaryA;
570 break;
571 case CRYPT_STRING_BASE64REQUESTHEADER:
572 decoder = Base64RequestHeaderToBinaryA;
573 break;
574 case CRYPT_STRING_BASE64X509CRLHEADER:
575 decoder = Base64X509HeaderToBinaryA;
576 break;
577 case CRYPT_STRING_BINARY:
578 decoder = DecodeBinaryToBinaryA;
579 break;
580 case CRYPT_STRING_ANY:
581 decoder = DecodeAnyA;
582 break;
583 case CRYPT_STRING_HEX:
584 case CRYPT_STRING_HEXASCII:
585 case CRYPT_STRING_HEXADDR:
586 case CRYPT_STRING_HEXASCIIADDR:
587 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
588 /* fall through */
589 default:
590 SetLastError(ERROR_INVALID_PARAMETER);
591 return FALSE;
592 }
593 if (!cchString)
594 cchString = strlen(pszString);
595 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
596 if (ret)
597 SetLastError(ret);
598 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
599 }
600
601 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
602 const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
603 {
604 int len = in_len, i;
605 const WCHAR *d = in_buf;
606 int ip0, ip1, ip2, ip3;
607
608 if (len < 4)
609 return ERROR_INVALID_DATA;
610
611 i = 0;
612 if (d[2] == '=')
613 {
614 if ((ip0 = decodeBase64Byte(d[0])) > 63)
615 return ERROR_INVALID_DATA;
616 if ((ip1 = decodeBase64Byte(d[1])) > 63)
617 return ERROR_INVALID_DATA;
618
619 if (out_buf)
620 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
621 i++;
622 }
623 else if (d[3] == '=')
624 {
625 if ((ip0 = decodeBase64Byte(d[0])) > 63)
626 return ERROR_INVALID_DATA;
627 if ((ip1 = decodeBase64Byte(d[1])) > 63)
628 return ERROR_INVALID_DATA;
629 if ((ip2 = decodeBase64Byte(d[2])) > 63)
630 return ERROR_INVALID_DATA;
631
632 if (out_buf)
633 {
634 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
635 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
636 }
637 i += 2;
638 }
639 else
640 {
641 if ((ip0 = decodeBase64Byte(d[0])) > 63)
642 return ERROR_INVALID_DATA;
643 if ((ip1 = decodeBase64Byte(d[1])) > 63)
644 return ERROR_INVALID_DATA;
645 if ((ip2 = decodeBase64Byte(d[2])) > 63)
646 return ERROR_INVALID_DATA;
647 if ((ip3 = decodeBase64Byte(d[3])) > 63)
648 return ERROR_INVALID_DATA;
649
650 if (out_buf)
651 {
652 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
653 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
654 out_buf[i + 2] = (ip2 << 6) | ip3;
655 }
656 i += 3;
657 }
658 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
659 *nextBlock = d + 6;
660 else if (len >= 5 && d[4] == '\n')
661 *nextBlock = d + 5;
662 else if (len >= 4 && d[4])
663 *nextBlock = d + 4;
664 else
665 *nextBlock = NULL;
666 *out_len = i;
667 return ERROR_SUCCESS;
668 }
669
670 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
671 * string to convert.
672 */
673 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
674 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
675
676 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
677 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
678 {
679 LONG ret = ERROR_SUCCESS;
680 const WCHAR *nextBlock;
681 DWORD outLen = 0;
682
683 nextBlock = pszString;
684 while (nextBlock && !ret)
685 {
686 DWORD len = 0;
687
688 ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
689 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
690 if (!ret)
691 outLen += len;
692 if (cchString - (nextBlock - pszString) <= 0)
693 nextBlock = NULL;
694 }
695 *pcbBinary = outLen;
696 if (!ret)
697 {
698 if (pdwSkip)
699 *pdwSkip = 0;
700 if (pdwFlags)
701 *pdwFlags = CRYPT_STRING_BASE64;
702 }
703 else if (ret == ERROR_INSUFFICIENT_BUFFER)
704 {
705 if (!pbBinary)
706 ret = ERROR_SUCCESS;
707 }
708 return ret;
709 }
710
711 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
712 DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
713 DWORD *pcbBinary, DWORD *pdwSkip)
714 {
715 LONG ret;
716 LPCWSTR ptr;
717
718 if (cchString > strlenW(header) + strlenW(trailer)
719 && (ptr = strstrW(pszString, header)) != NULL)
720 {
721 LPCWSTR trailerSpot = pszString + cchString - strlenW(trailer);
722
723 if (pszString[cchString - 1] == '\n')
724 {
725 cchString--;
726 trailerSpot--;
727 }
728 if (pszString[cchString - 1] == '\r')
729 {
730 cchString--;
731 trailerSpot--;
732 }
733 if (!strncmpW(trailerSpot, trailer, strlenW(trailer)))
734 {
735 if (pdwSkip)
736 *pdwSkip = ptr - pszString;
737 ptr += strlenW(header);
738 if (*ptr == '\r') ptr++;
739 if (*ptr == '\n') ptr++;
740 cchString -= ptr - pszString + strlenW(trailer);
741 ret = Base64ToBinaryW(ptr, cchString, pbBinary, pcbBinary, NULL,
742 NULL);
743 }
744 else
745 ret = ERROR_INVALID_DATA;
746 }
747 else
748 ret = ERROR_INVALID_DATA;
749 return ret;
750 }
751
752 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
753 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
754 {
755 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
756 CERT_HEADER_W, CERT_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
757
758 if (!ret && pdwFlags)
759 *pdwFlags = CRYPT_STRING_BASE64HEADER;
760 return ret;
761 }
762
763 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
764 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
765 {
766 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
767 CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
768 pdwSkip);
769
770 if (!ret && pdwFlags)
771 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
772 return ret;
773 }
774
775 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
776 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
777 {
778 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
779 X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
780
781 if (!ret && pdwFlags)
782 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
783 return ret;
784 }
785
786 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
787 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
788 {
789 LONG ret;
790
791 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
792 pdwSkip, pdwFlags);
793 if (ret == ERROR_INVALID_DATA)
794 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
795 pdwSkip, pdwFlags);
796 return ret;
797 }
798
799 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
800 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
801 {
802 LONG ret = ERROR_SUCCESS;
803
804 if (*pcbBinary < cchString)
805 {
806 if (!pbBinary)
807 *pcbBinary = cchString;
808 else
809 {
810 ret = ERROR_INSUFFICIENT_BUFFER;
811 *pcbBinary = cchString;
812 }
813 }
814 else
815 {
816 if (cchString)
817 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
818 *pcbBinary = cchString * sizeof(WCHAR);
819 }
820 return ret;
821 }
822
823 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
824 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
825 {
826 LONG ret;
827
828 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
829 pdwSkip, pdwFlags);
830 if (ret == ERROR_INVALID_DATA)
831 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
832 pdwSkip, pdwFlags);
833 if (ret == ERROR_INVALID_DATA)
834 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
835 pdwSkip, pdwFlags);
836 return ret;
837 }
838
839 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
840 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
841 DWORD *pdwSkip, DWORD *pdwFlags)
842 {
843 StringToBinaryWFunc decoder;
844 LONG ret;
845
846 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
847 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
848
849 if (!pszString)
850 {
851 SetLastError(ERROR_INVALID_PARAMETER);
852 return FALSE;
853 }
854 /* Only the bottom byte contains valid types */
855 if (dwFlags & 0xfffffff0)
856 {
857 SetLastError(ERROR_INVALID_DATA);
858 return FALSE;
859 }
860 switch (dwFlags)
861 {
862 case CRYPT_STRING_BASE64_ANY:
863 decoder = Base64AnyToBinaryW;
864 break;
865 case CRYPT_STRING_BASE64:
866 decoder = Base64ToBinaryW;
867 break;
868 case CRYPT_STRING_BASE64HEADER:
869 decoder = Base64HeaderToBinaryW;
870 break;
871 case CRYPT_STRING_BASE64REQUESTHEADER:
872 decoder = Base64RequestHeaderToBinaryW;
873 break;
874 case CRYPT_STRING_BASE64X509CRLHEADER:
875 decoder = Base64X509HeaderToBinaryW;
876 break;
877 case CRYPT_STRING_BINARY:
878 decoder = DecodeBinaryToBinaryW;
879 break;
880 case CRYPT_STRING_ANY:
881 decoder = DecodeAnyW;
882 break;
883 case CRYPT_STRING_HEX:
884 case CRYPT_STRING_HEXASCII:
885 case CRYPT_STRING_HEXADDR:
886 case CRYPT_STRING_HEXASCIIADDR:
887 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
888 /* fall through */
889 default:
890 SetLastError(ERROR_INVALID_PARAMETER);
891 return FALSE;
892 }
893 if (!cchString)
894 cchString = strlenW(pszString);
895 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
896 if (ret)
897 SetLastError(ret);
898 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
899 }