ntdll: Implement RtlIsEcCode().
[wine.git] / dlls / crypt32 / base64.c
blobb61ed7ff8cc49fc28e6805ef2425becea8e9ee9d
1 /*
2 * base64 encoder/decoder
4 * Copyright 2005 by Kai Blin
5 * Copyright 2006 Juan Lang
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.
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.
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
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"
29 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
31 #define CERT_HEADER "-----BEGIN CERTIFICATE-----"
32 #define CERT_HEADER_START "-----BEGIN "
33 #define CERT_DELIMITER "-----"
34 #define CERT_TRAILER "-----END CERTIFICATE-----"
35 #define CERT_TRAILER_START "-----END "
36 #define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
37 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
38 #define X509_HEADER "-----BEGIN X509 CRL-----"
39 #define X509_TRAILER "-----END X509 CRL-----"
41 static const WCHAR CERT_HEADER_W[] = L"-----BEGIN CERTIFICATE-----";
42 static const WCHAR CERT_HEADER_START_W[] = L"-----BEGIN ";
43 static const WCHAR CERT_DELIMITER_W[] = L"-----";
44 static const WCHAR CERT_TRAILER_W[] = L"-----END CERTIFICATE-----";
45 static const WCHAR CERT_TRAILER_START_W[] = L"-----END ";
46 static const WCHAR CERT_REQUEST_HEADER_W[] = L"-----BEGIN NEW CERTIFICATE REQUEST-----";
47 static const WCHAR CERT_REQUEST_TRAILER_W[] = L"-----END NEW CERTIFICATE REQUEST-----";
48 static const WCHAR X509_HEADER_W[] = L"-----BEGIN X509 CRL-----";
49 static const WCHAR X509_TRAILER_W[] = L"-----END X509 CRL-----";
51 static const char b64[] =
52 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
54 typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary,
55 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString);
56 typedef BOOL (*BinaryToStringWFunc)(const BYTE *pbBinary,
57 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString);
59 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
60 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
62 BOOL ret = TRUE;
64 if (pszString)
66 if (*pcchString < cbBinary)
68 SetLastError(ERROR_INSUFFICIENT_BUFFER);
69 ret = FALSE;
71 else if (cbBinary)
72 memcpy(pszString, pbBinary, cbBinary);
74 else
75 *pcchString = cbBinary;
77 return ret;
80 static DWORD stradd(LPSTR ptr, LPCSTR end, LPCSTR s, DWORD slen)
82 if (ptr + slen > end)
83 slen = end - ptr;
84 memcpy(ptr, s, slen);
85 return slen;
88 static DWORD encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
89 char* out_buf, DWORD *out_len)
91 int div, i;
92 const BYTE *d = in_buf;
93 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
94 LPSTR ptr;
95 LPCSTR end;
96 char chunk[4];
98 if (!out_buf)
100 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
101 *out_len = bytes + pad_bytes;
102 *out_len += (*out_len / 64 + (*out_len % 64 ? 1 : 0)) * strlen(sep) + 1;
103 return 0;
106 /* Three bytes of input give 4 chars of output */
107 div = in_len / 3;
109 ptr = out_buf;
110 end = ptr + *out_len;
111 i = 0;
112 while (div > 0 && ptr < end)
114 if (i && i % 64 == 0)
115 ptr += stradd(ptr, end, sep, strlen(sep));
116 /* first char is the first 6 bits of the first byte*/
117 chunk[0] = b64[ ( d[0] >> 2) & 0x3f ];
118 /* second char is the last 2 bits of the first byte and the first 4
119 * bits of the second byte */
120 chunk[1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
121 /* third char is the last 4 bits of the second byte and the first 2
122 * bits of the third byte */
123 chunk[2] = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
124 /* fourth char is the remaining 6 bits of the third byte */
125 chunk[3] = b64[ d[2] & 0x3f];
126 ptr += stradd(ptr, end, chunk, 4);
127 i += 4;
128 d += 3;
129 div--;
132 switch(pad_bytes)
134 case 1:
135 /* first char is the first 6 bits of the first byte*/
136 chunk[0] = b64[ ( d[0] >> 2) & 0x3f ];
137 /* second char is the last 2 bits of the first byte and the first 4
138 * bits of the second byte */
139 chunk[1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
140 /* third char is the last 4 bits of the second byte padded with
141 * two zeroes */
142 chunk[2] = b64[ ((d[1] << 2) & 0x3c) ];
143 /* fourth char is a = to indicate one byte of padding */
144 chunk[3] = '=';
145 ptr += stradd(ptr, end, chunk, 4);
146 break;
147 case 2:
148 /* first char is the first 6 bits of the first byte*/
149 chunk[0] = b64[ ( d[0] >> 2) & 0x3f ];
150 /* second char is the last 2 bits of the first byte padded with
151 * four zeroes*/
152 chunk[1] = b64[ ((d[0] << 4) & 0x30)];
153 /* third char is = to indicate padding */
154 chunk[2] = '=';
155 /* fourth char is = to indicate padding */
156 chunk[3] = '=';
157 ptr += stradd(ptr, end, chunk, 4);
158 break;
160 ptr += stradd(ptr, end, sep, strlen(sep));
162 return ptr - out_buf;
165 static BOOL BinaryToBase64A(const BYTE *pbBinary,
166 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
168 static const char crlf[] = "\r\n", lf[] = "\n";
169 BOOL ret = TRUE;
170 LPCSTR header = NULL, trailer = NULL, sep;
171 DWORD charsNeeded;
173 if (dwFlags & CRYPT_STRING_NOCR)
174 sep = lf;
175 else if (dwFlags & CRYPT_STRING_NOCRLF)
176 sep = "";
177 else
178 sep = crlf;
179 switch (dwFlags & 0x0fffffff)
181 case CRYPT_STRING_BASE64:
182 /* no header or footer */
183 break;
184 case CRYPT_STRING_BASE64HEADER:
185 header = CERT_HEADER;
186 trailer = CERT_TRAILER;
187 break;
188 case CRYPT_STRING_BASE64REQUESTHEADER:
189 header = CERT_REQUEST_HEADER;
190 trailer = CERT_REQUEST_TRAILER;
191 break;
192 case CRYPT_STRING_BASE64X509CRLHEADER:
193 header = X509_HEADER;
194 trailer = X509_TRAILER;
195 break;
198 charsNeeded = 0;
199 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
200 if (header)
201 charsNeeded += strlen(header) + strlen(sep);
202 if (trailer)
203 charsNeeded += strlen(trailer) + strlen(sep);
205 if (pszString)
207 LPSTR ptr = pszString;
208 DWORD size = *pcchString;
209 LPSTR end = ptr + size;
211 if (header)
213 ptr += stradd(ptr, end, header, strlen(header));
214 ptr += stradd(ptr, end, sep, strlen(sep));
215 size = end - ptr;
217 ptr += encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
218 if (trailer)
220 ptr += stradd(ptr, end, trailer, strlen(trailer));
221 ptr += stradd(ptr, end, sep, strlen(sep));
224 if (ptr < end)
225 *ptr = '\0';
227 if (charsNeeded <= *pcchString)
229 *pcchString = charsNeeded - 1;
231 else
233 *pcchString = charsNeeded;
234 SetLastError(ERROR_MORE_DATA);
235 ret = FALSE;
238 else
239 *pcchString = charsNeeded;
241 return ret;
244 static BOOL BinaryToHexRawA(const BYTE *bin, DWORD nbin, DWORD flags, char *str, DWORD *nstr)
246 static const char hex[] = "0123456789abcdef";
247 DWORD needed;
249 if (flags & CRYPT_STRING_NOCRLF)
250 needed = 0;
251 else if (flags & CRYPT_STRING_NOCR)
252 needed = 1;
253 else
254 needed = 2;
256 needed += nbin * 2 + 1;
258 if (!str)
260 *nstr = needed;
261 return TRUE;
264 if (needed > *nstr && *nstr < 3)
266 SetLastError(ERROR_MORE_DATA);
267 return FALSE;
270 nbin = min(nbin, (*nstr - 1) / 2);
272 while (nbin--)
274 *str++ = hex[(*bin >> 4) & 0xf];
275 *str++ = hex[*bin & 0xf];
276 bin++;
279 if (needed > *nstr)
281 *str = 0;
282 SetLastError(ERROR_MORE_DATA);
283 return FALSE;
286 if (flags & CRYPT_STRING_NOCR)
288 *str++ = '\n';
290 else if (!(flags & CRYPT_STRING_NOCRLF))
292 *str++ = '\r';
293 *str++ = '\n';
296 *str = 0;
297 *nstr = needed - 1;
298 return TRUE;
301 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
302 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
304 BinaryToStringAFunc encoder = NULL;
306 TRACE("(%p, %ld, %08lx, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
307 pcchString);
309 if (!pbBinary)
311 SetLastError(ERROR_INVALID_PARAMETER);
312 return FALSE;
314 if (!pcchString)
316 SetLastError(ERROR_INVALID_PARAMETER);
317 return FALSE;
320 switch (dwFlags & 0x0fffffff)
322 case CRYPT_STRING_BINARY:
323 encoder = EncodeBinaryToBinaryA;
324 break;
325 case CRYPT_STRING_BASE64:
326 case CRYPT_STRING_BASE64HEADER:
327 case CRYPT_STRING_BASE64REQUESTHEADER:
328 case CRYPT_STRING_BASE64X509CRLHEADER:
329 encoder = BinaryToBase64A;
330 break;
331 case CRYPT_STRING_HEXRAW:
332 encoder = BinaryToHexRawA;
333 break;
334 case CRYPT_STRING_HEX:
335 case CRYPT_STRING_HEXASCII:
336 case CRYPT_STRING_HEXADDR:
337 case CRYPT_STRING_HEXASCIIADDR:
338 FIXME("Unimplemented type %ld\n", dwFlags & 0x0fffffff);
339 /* fall through */
340 default:
341 SetLastError(ERROR_INVALID_PARAMETER);
342 return FALSE;
344 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
347 static BOOL EncodeBinaryToBinaryW(const BYTE *in_buf, DWORD in_len, DWORD flags, WCHAR *out_buf, DWORD *out_len)
349 BOOL ret = TRUE;
351 if (out_buf)
353 if (*out_len < in_len)
355 SetLastError(ERROR_INSUFFICIENT_BUFFER);
356 ret = FALSE;
358 else if (in_len)
359 memcpy(out_buf, in_buf, in_len);
361 else
362 *out_len = in_len;
364 return ret;
367 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
368 WCHAR* out_buf, DWORD *out_len)
370 int div, i;
371 const BYTE *d = in_buf;
372 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
373 DWORD needed;
374 LPWSTR ptr;
376 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
377 needed = bytes + pad_bytes;
378 needed += (needed / 64 + (needed % 64 ? 1 : 0)) * lstrlenW(sep);
379 needed++;
381 if (needed > *out_len)
383 *out_len = needed;
384 return ERROR_INSUFFICIENT_BUFFER;
386 else
387 *out_len = needed;
389 /* Three bytes of input give 4 chars of output */
390 div = in_len / 3;
392 ptr = out_buf;
393 i = 0;
394 while (div > 0)
396 if (i && i % 64 == 0)
398 lstrcpyW(ptr, sep);
399 ptr += lstrlenW(sep);
401 /* first char is the first 6 bits of the first byte*/
402 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
403 /* second char is the last 2 bits of the first byte and the first 4
404 * bits of the second byte */
405 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
406 /* third char is the last 4 bits of the second byte and the first 2
407 * bits of the third byte */
408 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
409 /* fourth char is the remaining 6 bits of the third byte */
410 *ptr++ = b64[ d[2] & 0x3f];
411 i += 4;
412 d += 3;
413 div--;
416 switch(pad_bytes)
418 case 1:
419 /* first char is the first 6 bits of the first byte*/
420 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
421 /* second char is the last 2 bits of the first byte and the first 4
422 * bits of the second byte */
423 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
424 /* third char is the last 4 bits of the second byte padded with
425 * two zeroes */
426 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
427 /* fourth char is a = to indicate one byte of padding */
428 *ptr++ = '=';
429 break;
430 case 2:
431 /* first char is the first 6 bits of the first byte*/
432 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
433 /* second char is the last 2 bits of the first byte padded with
434 * four zeroes*/
435 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
436 /* third char is = to indicate padding */
437 *ptr++ = '=';
438 /* fourth char is = to indicate padding */
439 *ptr++ = '=';
440 break;
442 lstrcpyW(ptr, sep);
444 return ERROR_SUCCESS;
447 static BOOL BinaryToBase64W(const BYTE *pbBinary,
448 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
450 BOOL ret = TRUE;
451 LPCWSTR header = NULL, trailer = NULL, sep;
452 DWORD charsNeeded;
454 if (dwFlags & CRYPT_STRING_NOCR)
455 sep = L"\n";
456 else if (dwFlags & CRYPT_STRING_NOCRLF)
457 sep = L"";
458 else
459 sep = L"\r\n";
460 switch (dwFlags & 0x0fffffff)
462 case CRYPT_STRING_BASE64:
463 /* no header or footer */
464 break;
465 case CRYPT_STRING_BASE64HEADER:
466 header = CERT_HEADER_W;
467 trailer = CERT_TRAILER_W;
468 break;
469 case CRYPT_STRING_BASE64REQUESTHEADER:
470 header = CERT_REQUEST_HEADER_W;
471 trailer = CERT_REQUEST_TRAILER_W;
472 break;
473 case CRYPT_STRING_BASE64X509CRLHEADER:
474 header = X509_HEADER_W;
475 trailer = X509_TRAILER_W;
476 break;
479 charsNeeded = 0;
480 encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
481 if (header)
482 charsNeeded += lstrlenW(header) + lstrlenW(sep);
483 if (trailer)
484 charsNeeded += lstrlenW(trailer) + lstrlenW(sep);
486 if (pszString)
488 if (charsNeeded <= *pcchString)
490 LPWSTR ptr = pszString;
491 DWORD size = charsNeeded;
493 if (header)
495 lstrcpyW(ptr, header);
496 ptr += lstrlenW(ptr);
497 lstrcpyW(ptr, sep);
498 ptr += lstrlenW(sep);
500 encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
501 ptr += size - 1;
502 if (trailer)
504 lstrcpyW(ptr, trailer);
505 ptr += lstrlenW(ptr);
506 lstrcpyW(ptr, sep);
508 *pcchString = charsNeeded - 1;
510 else
512 *pcchString = charsNeeded;
513 SetLastError(ERROR_MORE_DATA);
514 ret = FALSE;
517 else
518 *pcchString = charsNeeded;
520 return ret;
523 static BOOL BinaryToHexRawW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
525 static const WCHAR hex[] = L"0123456789abcdef";
526 DWORD needed;
528 if (flags & CRYPT_STRING_NOCRLF)
529 needed = 0;
530 else if (flags & CRYPT_STRING_NOCR)
531 needed = 1;
532 else
533 needed = 2;
535 needed += nbin * 2 + 1;
537 if (!str)
539 *nstr = needed;
540 return TRUE;
543 if (needed > *nstr)
545 SetLastError(ERROR_MORE_DATA);
546 return FALSE;
549 while (nbin--)
551 *str++ = hex[(*bin >> 4) & 0xf];
552 *str++ = hex[*bin & 0xf];
553 bin++;
556 if (flags & CRYPT_STRING_NOCR)
557 *str++ = '\n';
558 else if (!(flags & CRYPT_STRING_NOCRLF))
560 *str++ = '\r';
561 *str++ = '\n';
564 *str = 0;
565 *nstr = needed - 1;
566 return TRUE;
569 static BOOL binary_to_hexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
571 static const WCHAR hex[] = L"0123456789abcdef";
572 DWORD needed, i;
574 needed = nbin * 3; /* spaces + terminating \0 */
576 if (flags & CRYPT_STRING_NOCR)
578 needed += (nbin + 7) / 16; /* space every 16 characters */
579 needed += 1; /* terminating \n */
581 else if (!(flags & CRYPT_STRING_NOCRLF))
583 needed += (nbin + 7) / 16; /* space every 16 characters */
584 needed += nbin / 16 + 1; /* LF every 16 characters + terminating \r */
586 if (nbin % 16)
587 needed += 1; /* terminating \n */
590 if (!str)
592 *nstr = needed;
593 return TRUE;
596 if (needed > *nstr)
598 SetLastError(ERROR_MORE_DATA);
599 return FALSE;
602 for (i = 0; i < nbin; i++)
604 *str++ = hex[(bin[i] >> 4) & 0xf];
605 *str++ = hex[bin[i] & 0xf];
607 if (i >= nbin - 1) break;
609 if (i && !(flags & CRYPT_STRING_NOCRLF))
611 if (!((i + 1) % 16))
613 if (flags & CRYPT_STRING_NOCR)
614 *str++ = '\n';
615 else
617 *str++ = '\r';
618 *str++ = '\n';
620 continue;
622 else if (!((i + 1) % 8))
623 *str++ = ' ';
626 *str++ = ' ';
629 if (flags & CRYPT_STRING_NOCR)
630 *str++ = '\n';
631 else if (!(flags & CRYPT_STRING_NOCRLF))
633 *str++ = '\r';
634 *str++ = '\n';
637 *str = 0;
638 *nstr = needed - 1;
639 return TRUE;
642 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
643 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
645 BinaryToStringWFunc encoder = NULL;
647 TRACE("(%p, %ld, %08lx, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
648 pcchString);
650 if (!pbBinary)
652 SetLastError(ERROR_INVALID_PARAMETER);
653 return FALSE;
655 if (!pcchString)
657 SetLastError(ERROR_INVALID_PARAMETER);
658 return FALSE;
661 switch (dwFlags & 0x0fffffff)
663 case CRYPT_STRING_BINARY:
664 encoder = EncodeBinaryToBinaryW;
665 break;
666 case CRYPT_STRING_BASE64:
667 case CRYPT_STRING_BASE64HEADER:
668 case CRYPT_STRING_BASE64REQUESTHEADER:
669 case CRYPT_STRING_BASE64X509CRLHEADER:
670 encoder = BinaryToBase64W;
671 break;
672 case CRYPT_STRING_HEXRAW:
673 encoder = BinaryToHexRawW;
674 break;
675 case CRYPT_STRING_HEX:
676 encoder = binary_to_hexW;
677 break;
678 case CRYPT_STRING_HEXASCII:
679 case CRYPT_STRING_HEXADDR:
680 case CRYPT_STRING_HEXASCIIADDR:
681 FIXME("Unimplemented type %ld\n", dwFlags & 0x0fffffff);
682 /* fall through */
683 default:
684 SetLastError(ERROR_INVALID_PARAMETER);
685 return FALSE;
687 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
690 #define BASE64_DECODE_PADDING 0x100
691 #define BASE64_DECODE_WHITESPACE 0x200
692 #define BASE64_DECODE_INVALID 0x300
694 static inline int decodeBase64Byte(int c)
696 int ret = BASE64_DECODE_INVALID;
698 if (c >= 'A' && c <= 'Z')
699 ret = c - 'A';
700 else if (c >= 'a' && c <= 'z')
701 ret = c - 'a' + 26;
702 else if (c >= '0' && c <= '9')
703 ret = c - '0' + 52;
704 else if (c == '+')
705 ret = 62;
706 else if (c == '/')
707 ret = 63;
708 else if (c == '=')
709 ret = BASE64_DECODE_PADDING;
710 else if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
711 ret = BASE64_DECODE_WHITESPACE;
712 return ret;
715 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
716 * string to convert.
718 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
719 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
721 static LONG Base64ToBinary(const void* pszString, BOOL wide, DWORD cchString,
722 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
724 DWORD cbIn, cbValid, cbOut, hasPadding;
725 BYTE block[4];
726 for (cbIn = cbValid = cbOut = hasPadding = 0; cbIn < cchString; ++cbIn)
728 int c = wide ? (int)((WCHAR*)pszString)[cbIn] : (int)((char*)pszString)[cbIn];
729 int d = decodeBase64Byte(c);
730 if (d == BASE64_DECODE_INVALID)
731 goto invalid;
732 if (d == BASE64_DECODE_WHITESPACE)
733 continue;
735 /* When padding starts, data is not acceptable */
736 if (hasPadding && d != BASE64_DECODE_PADDING)
737 goto invalid;
739 /* Padding after a full block (like "VVVV=") is ok and stops decoding */
740 if (d == BASE64_DECODE_PADDING && (cbValid & 3) == 0)
741 break;
743 cbValid += 1;
745 if (d == BASE64_DECODE_PADDING)
747 hasPadding = 1;
748 /* When padding reaches a full block, stop decoding */
749 if ((cbValid & 3) == 0)
750 break;
751 continue;
754 /* cbOut is incremented in the 4-char block as follows: "1-23" */
755 if ((cbValid & 3) != 2)
756 cbOut += 1;
758 /* Fail if the block has bad padding; omitting padding is fine */
759 if ((cbValid & 3) != 0 && hasPadding)
760 goto invalid;
761 /* Check available buffer size */
762 if (pbBinary && *pcbBinary && cbOut > *pcbBinary)
763 goto overflow;
764 /* Convert the data; this step depends on the validity checks above! */
765 if (pbBinary) for (cbIn = cbValid = cbOut = 0; cbIn < cchString; ++cbIn)
767 int c = wide ? (int)((WCHAR*)pszString)[cbIn] : (int)((char*)pszString)[cbIn];
768 int d = decodeBase64Byte(c);
769 if (d == BASE64_DECODE_WHITESPACE)
770 continue;
771 if (d == BASE64_DECODE_PADDING)
772 break;
773 block[cbValid & 3] = d;
774 cbValid += 1;
775 switch (cbValid & 3) {
776 case 1:
777 pbBinary[cbOut++] = (block[0] << 2);
778 break;
779 case 2:
780 pbBinary[cbOut-1] = (block[0] << 2) | (block[1] >> 4);
781 break;
782 case 3:
783 pbBinary[cbOut++] = (block[1] << 4) | (block[2] >> 2);
784 break;
785 case 0:
786 pbBinary[cbOut++] = (block[2] << 6) | (block[3] >> 0);
787 break;
790 *pcbBinary = cbOut;
791 if (pdwSkip)
792 *pdwSkip = 0;
793 if (pdwFlags)
794 *pdwFlags = CRYPT_STRING_BASE64;
795 return ERROR_SUCCESS;
796 overflow:
797 return ERROR_INSUFFICIENT_BUFFER;
798 invalid:
799 *pcbBinary = cbOut;
800 return ERROR_INVALID_DATA;
803 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
804 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
806 return Base64ToBinary(pszString, FALSE, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
809 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
810 DWORD cchString, BYTE *pbBinary,
811 DWORD *pcbBinary, DWORD *pdwSkip)
813 LONG ret;
814 LPCSTR header = CERT_HEADER_START;
815 LPCSTR trailer = CERT_TRAILER_START;
817 LPCSTR headerBegins;
818 LPCSTR dataBegins;
819 LPCSTR trailerBegins;
820 size_t dataLength;
822 if ((strlen(header) + strlen(trailer)) > cchString)
824 return ERROR_INVALID_DATA;
827 if (!(headerBegins = strstr(pszString, header)))
829 TRACE("Can't find %s in %s.\n", header, debugstr_an(pszString, cchString));
830 return ERROR_INVALID_DATA;
833 dataBegins = headerBegins + strlen(header);
834 if (!(dataBegins = strstr(dataBegins, CERT_DELIMITER)))
836 return ERROR_INVALID_DATA;
838 dataBegins += strlen(CERT_DELIMITER);
839 if (*dataBegins == '\r') dataBegins++;
840 if (*dataBegins == '\n') dataBegins++;
842 if (!(trailerBegins = strstr(dataBegins, trailer)))
844 return ERROR_INVALID_DATA;
846 if (*(trailerBegins-1) == '\n') trailerBegins--;
847 if (*(trailerBegins-1) == '\r') trailerBegins--;
849 if (pdwSkip)
850 *pdwSkip = headerBegins - pszString;
852 dataLength = trailerBegins - dataBegins;
854 ret = Base64ToBinaryA(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
855 NULL);
857 return ret;
860 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
861 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
863 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
864 pbBinary, pcbBinary, pdwSkip);
866 if (!ret && pdwFlags)
867 *pdwFlags = CRYPT_STRING_BASE64HEADER;
868 return ret;
871 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
872 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
874 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
875 pbBinary, pcbBinary, pdwSkip);
877 if (!ret && pdwFlags)
878 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
879 return ret;
882 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
883 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
885 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
886 pbBinary, pcbBinary, pdwSkip);
888 if (!ret && pdwFlags)
889 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
890 return ret;
893 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
894 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
896 LONG ret;
898 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
899 pdwSkip, pdwFlags);
900 if (ret == ERROR_INVALID_DATA)
901 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
902 pdwSkip, pdwFlags);
903 return ret;
906 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
907 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
909 LONG ret = ERROR_SUCCESS;
911 if (*pcbBinary < cchString)
913 if (!pbBinary)
914 *pcbBinary = cchString;
915 else
917 ret = ERROR_INSUFFICIENT_BUFFER;
918 *pcbBinary = cchString;
921 else
923 if (cchString)
924 memcpy(pbBinary, pszString, cchString);
925 *pcbBinary = cchString;
927 return ret;
930 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
931 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
933 LONG ret;
935 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
936 pdwSkip, pdwFlags);
937 if (ret == ERROR_INVALID_DATA)
938 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
939 pdwSkip, pdwFlags);
940 if (ret == ERROR_INVALID_DATA)
941 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
942 pdwSkip, pdwFlags);
943 return ret;
946 static BOOL is_hex_string_special_char(WCHAR c)
948 switch (c)
950 case '-':
951 case ',':
952 case ' ':
953 case '\t':
954 case '\r':
955 case '\n':
956 return TRUE;
958 default:
959 return FALSE;
963 static WCHAR wchar_from_str(BOOL wide, const void **str, DWORD *len)
965 WCHAR c;
967 if (!*len)
968 return 0;
970 --*len;
971 if (wide)
972 c = *(*(const WCHAR **)str)++;
973 else
974 c = *(*(const char **)str)++;
976 return c ? c : 0xffff;
979 static BYTE digit_from_char(WCHAR c)
981 if (c >= '0' && c <= '9')
982 return c - '0';
983 c = towlower(c);
984 if (c >= 'a' && c <= 'f')
985 return c - 'a' + 0xa;
986 return 0xff;
989 static LONG string_to_hex(const void* str, BOOL wide, DWORD len, BYTE *hex, DWORD *hex_len,
990 DWORD *skipped, DWORD *ret_flags)
992 unsigned int byte_idx = 0;
993 BYTE d1, d2;
994 WCHAR c;
996 if (!str || !hex_len)
997 return ERROR_INVALID_PARAMETER;
999 if (!len)
1000 len = wide ? wcslen(str) : strlen(str);
1002 if (wide && !len)
1003 return ERROR_INVALID_PARAMETER;
1005 if (skipped)
1006 *skipped = 0;
1007 if (ret_flags)
1008 *ret_flags = 0;
1010 while ((c = wchar_from_str(wide, &str, &len)) && is_hex_string_special_char(c))
1013 while ((d1 = digit_from_char(c)) != 0xff)
1015 if ((d2 = digit_from_char(wchar_from_str(wide, &str, &len))) == 0xff)
1017 if (!hex)
1018 *hex_len = 0;
1019 return ERROR_INVALID_DATA;
1022 if (hex && byte_idx < *hex_len)
1023 hex[byte_idx] = (d1 << 4) | d2;
1025 ++byte_idx;
1029 c = wchar_from_str(wide, &str, &len);
1030 } while (c == '-' || c == ',');
1033 while (c)
1035 if (!is_hex_string_special_char(c))
1037 if (!hex)
1038 *hex_len = 0;
1039 return ERROR_INVALID_DATA;
1041 c = wchar_from_str(wide, &str, &len);
1044 if (hex && byte_idx > *hex_len)
1045 return ERROR_MORE_DATA;
1047 if (ret_flags)
1048 *ret_flags = CRYPT_STRING_HEX;
1050 *hex_len = byte_idx;
1052 return ERROR_SUCCESS;
1055 static LONG string_to_hexA(const char *str, DWORD len, BYTE *hex, DWORD *hex_len, DWORD *skipped, DWORD *ret_flags)
1057 return string_to_hex(str, FALSE, len, hex, hex_len, skipped, ret_flags);
1060 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
1061 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1062 DWORD *pdwSkip, DWORD *pdwFlags)
1064 StringToBinaryAFunc decoder;
1065 LONG ret;
1067 TRACE("(%s, %ld, %08lx, %p, %p, %p, %p)\n", debugstr_an(pszString, cchString ? cchString : -1),
1068 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1070 if (!pszString)
1072 SetLastError(ERROR_INVALID_PARAMETER);
1073 return FALSE;
1075 /* Only the bottom byte contains valid types */
1076 if (dwFlags & 0xfffffff0)
1078 SetLastError(ERROR_INVALID_DATA);
1079 return FALSE;
1081 switch (dwFlags)
1083 case CRYPT_STRING_BASE64_ANY:
1084 decoder = Base64AnyToBinaryA;
1085 break;
1086 case CRYPT_STRING_BASE64:
1087 decoder = Base64ToBinaryA;
1088 break;
1089 case CRYPT_STRING_BASE64HEADER:
1090 decoder = Base64HeaderToBinaryA;
1091 break;
1092 case CRYPT_STRING_BASE64REQUESTHEADER:
1093 decoder = Base64RequestHeaderToBinaryA;
1094 break;
1095 case CRYPT_STRING_BASE64X509CRLHEADER:
1096 decoder = Base64X509HeaderToBinaryA;
1097 break;
1098 case CRYPT_STRING_BINARY:
1099 decoder = DecodeBinaryToBinaryA;
1100 break;
1101 case CRYPT_STRING_ANY:
1102 decoder = DecodeAnyA;
1103 break;
1104 case CRYPT_STRING_HEX:
1105 decoder = string_to_hexA;
1106 break;
1107 case CRYPT_STRING_HEXASCII:
1108 case CRYPT_STRING_HEXADDR:
1109 case CRYPT_STRING_HEXASCIIADDR:
1110 FIXME("Unimplemented type %ld\n", dwFlags & 0x7fffffff);
1111 /* fall through */
1112 default:
1113 SetLastError(ERROR_INVALID_PARAMETER);
1114 return FALSE;
1116 if (!cchString)
1117 cchString = strlen(pszString);
1118 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1119 if (ret)
1120 SetLastError(ret);
1121 return ret == ERROR_SUCCESS;
1124 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
1125 * string to convert.
1127 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
1128 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
1130 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
1131 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1133 return Base64ToBinary(pszString, TRUE, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1136 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
1137 DWORD cchString, BYTE *pbBinary,
1138 DWORD *pcbBinary, DWORD *pdwSkip)
1140 LONG ret;
1141 LPCWSTR header = CERT_HEADER_START_W;
1142 LPCWSTR trailer = CERT_TRAILER_START_W;
1144 LPCWSTR headerBegins;
1145 LPCWSTR dataBegins;
1146 LPCWSTR trailerBegins;
1147 size_t dataLength;
1149 if ((lstrlenW(header) + lstrlenW(trailer)) > cchString)
1151 return ERROR_INVALID_DATA;
1154 if (!(headerBegins = wcsstr(pszString, header)))
1156 TRACE("Can't find %s in %s.\n", debugstr_w(header), debugstr_wn(pszString, cchString));
1157 return ERROR_INVALID_DATA;
1160 dataBegins = headerBegins + lstrlenW(header);
1161 if (!(dataBegins = wcsstr(dataBegins, CERT_DELIMITER_W)))
1163 return ERROR_INVALID_DATA;
1165 dataBegins += lstrlenW(CERT_DELIMITER_W);
1166 if (*dataBegins == '\r') dataBegins++;
1167 if (*dataBegins == '\n') dataBegins++;
1169 if (!(trailerBegins = wcsstr(dataBegins, trailer)))
1171 return ERROR_INVALID_DATA;
1173 if (*(trailerBegins-1) == '\n') trailerBegins--;
1174 if (*(trailerBegins-1) == '\r') trailerBegins--;
1176 if (pdwSkip)
1177 *pdwSkip = headerBegins - pszString;
1179 dataLength = trailerBegins - dataBegins;
1181 ret = Base64ToBinaryW(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
1182 NULL);
1184 return ret;
1187 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1188 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1190 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1191 pbBinary, pcbBinary, pdwSkip);
1193 if (!ret && pdwFlags)
1194 *pdwFlags = CRYPT_STRING_BASE64HEADER;
1195 return ret;
1198 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1199 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1201 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1202 pbBinary, pcbBinary, pdwSkip);
1204 if (!ret && pdwFlags)
1205 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
1206 return ret;
1209 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1210 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1212 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1213 pbBinary, pcbBinary, pdwSkip);
1215 if (!ret && pdwFlags)
1216 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
1217 return ret;
1220 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
1221 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1223 LONG ret;
1225 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1226 pdwSkip, pdwFlags);
1227 if (ret == ERROR_INVALID_DATA)
1228 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1229 pdwSkip, pdwFlags);
1230 return ret;
1233 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
1234 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1236 LONG ret = ERROR_SUCCESS;
1238 if (*pcbBinary < cchString)
1240 if (!pbBinary)
1241 *pcbBinary = cchString;
1242 else
1244 ret = ERROR_INSUFFICIENT_BUFFER;
1245 *pcbBinary = cchString;
1248 else
1250 if (cchString)
1251 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1252 *pcbBinary = cchString * sizeof(WCHAR);
1254 return ret;
1257 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1258 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1260 LONG ret;
1262 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1263 pdwSkip, pdwFlags);
1264 if (ret == ERROR_INVALID_DATA)
1265 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1266 pdwSkip, pdwFlags);
1267 if (ret == ERROR_INVALID_DATA)
1268 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1269 pdwSkip, pdwFlags);
1270 return ret;
1273 static LONG string_to_hexW(const WCHAR *str, DWORD len, BYTE *hex, DWORD *hex_len, DWORD *skipped, DWORD *ret_flags)
1275 return string_to_hex(str, TRUE, len, hex, hex_len, skipped, ret_flags);
1278 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1279 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1280 DWORD *pdwSkip, DWORD *pdwFlags)
1282 StringToBinaryWFunc decoder;
1283 LONG ret;
1285 TRACE("(%s, %ld, %08lx, %p, %p, %p, %p)\n", debugstr_wn(pszString, cchString ? cchString : -1),
1286 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1288 if (!pszString)
1290 SetLastError(ERROR_INVALID_PARAMETER);
1291 return FALSE;
1293 /* Only the bottom byte contains valid types */
1294 if (dwFlags & 0xfffffff0)
1296 SetLastError(ERROR_INVALID_DATA);
1297 return FALSE;
1299 switch (dwFlags)
1301 case CRYPT_STRING_BASE64_ANY:
1302 decoder = Base64AnyToBinaryW;
1303 break;
1304 case CRYPT_STRING_BASE64:
1305 decoder = Base64ToBinaryW;
1306 break;
1307 case CRYPT_STRING_BASE64HEADER:
1308 decoder = Base64HeaderToBinaryW;
1309 break;
1310 case CRYPT_STRING_BASE64REQUESTHEADER:
1311 decoder = Base64RequestHeaderToBinaryW;
1312 break;
1313 case CRYPT_STRING_BASE64X509CRLHEADER:
1314 decoder = Base64X509HeaderToBinaryW;
1315 break;
1316 case CRYPT_STRING_BINARY:
1317 decoder = DecodeBinaryToBinaryW;
1318 break;
1319 case CRYPT_STRING_ANY:
1320 decoder = DecodeAnyW;
1321 break;
1322 case CRYPT_STRING_HEX:
1323 decoder = string_to_hexW;
1324 break;
1325 case CRYPT_STRING_HEXASCII:
1326 case CRYPT_STRING_HEXADDR:
1327 case CRYPT_STRING_HEXASCIIADDR:
1328 FIXME("Unimplemented type %ld\n", dwFlags & 0x7fffffff);
1329 /* fall through */
1330 default:
1331 SetLastError(ERROR_INVALID_PARAMETER);
1332 return FALSE;
1334 if (!cchString)
1335 cchString = lstrlenW(pszString);
1336 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1337 if (ret)
1338 SetLastError(ret);
1339 return ret == ERROR_SUCCESS;