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
27 #include "wine/debug.h"
28 #include "wine/unicode.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
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-----"
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','-','-',
58 static const char b64[] =
59 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
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);
66 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
67 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
71 if (*pcchString < cbBinary)
74 *pcchString = cbBinary;
77 SetLastError(ERROR_INSUFFICIENT_BUFFER);
78 *pcchString = cbBinary;
85 memcpy(pszString, pbBinary, cbBinary);
86 *pcchString = cbBinary;
91 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
92 char* out_buf, DWORD *out_len)
95 const BYTE *d = in_buf;
96 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
100 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
101 needed = bytes + pad_bytes + 1;
102 needed += (needed / 64 + 1) * strlen(sep);
104 if (needed > *out_len)
107 return ERROR_INSUFFICIENT_BUFFER;
112 /* Three bytes of input give 4 chars of output */
119 if (i && i % 64 == 0)
124 /* first char is the first 6 bits of the first byte*/
125 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
126 /* second char is the last 2 bits of the first byte and the first 4
127 * bits of the second byte */
128 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
129 /* third char is the last 4 bits of the second byte and the first 2
130 * bits of the third byte */
131 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
132 /* fourth char is the remaining 6 bits of the third byte */
133 *ptr++ = b64[ d[2] & 0x3f];
142 /* first char is the first 6 bits of the first byte*/
143 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
144 /* second char is the last 2 bits of the first byte and the first 4
145 * bits of the second byte */
146 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
147 /* third char is the last 4 bits of the second byte padded with
149 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
150 /* fourth char is a = to indicate one byte of padding */
154 /* first char is the first 6 bits of the first byte*/
155 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
156 /* second char is the last 2 bits of the first byte padded with
158 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
159 /* third char is = to indicate padding */
161 /* fourth char is = to indicate padding */
167 return ERROR_SUCCESS;
170 static BOOL BinaryToBase64A(const BYTE *pbBinary,
171 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
173 static const char crlf[] = "\r\n", lf[] = "\n";
175 LPCSTR header = NULL, trailer = NULL, sep;
178 if (dwFlags & CRYPT_STRING_NOCR)
180 else if (dwFlags & CRYPT_STRING_NOCRLF)
184 switch (dwFlags & 0x0fffffff)
186 case CRYPT_STRING_BASE64:
187 /* no header or footer */
189 case CRYPT_STRING_BASE64HEADER:
190 header = CERT_HEADER;
191 trailer = CERT_TRAILER;
193 case CRYPT_STRING_BASE64REQUESTHEADER:
194 header = CERT_REQUEST_HEADER;
195 trailer = CERT_REQUEST_TRAILER;
197 case CRYPT_STRING_BASE64X509CRLHEADER:
198 header = X509_HEADER;
199 trailer = X509_TRAILER;
204 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
206 charsNeeded += strlen(header) + strlen(sep);
208 charsNeeded += strlen(trailer) + strlen(sep);
209 if (charsNeeded <= *pcchString)
211 LPSTR ptr = pszString;
212 DWORD size = charsNeeded;
221 encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
225 strcpy(ptr, trailer);
230 *pcchString = charsNeeded - 1;
234 *pcchString = charsNeeded;
235 SetLastError(ERROR_INSUFFICIENT_BUFFER);
239 *pcchString = charsNeeded;
243 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
244 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
246 BinaryToStringAFunc encoder = NULL;
248 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
253 SetLastError(ERROR_INVALID_PARAMETER);
258 SetLastError(ERROR_INVALID_PARAMETER);
262 switch (dwFlags & 0x0fffffff)
264 case CRYPT_STRING_BINARY:
265 encoder = EncodeBinaryToBinaryA;
267 case CRYPT_STRING_BASE64:
268 case CRYPT_STRING_BASE64HEADER:
269 case CRYPT_STRING_BASE64REQUESTHEADER:
270 case CRYPT_STRING_BASE64X509CRLHEADER:
271 encoder = BinaryToBase64A;
273 case CRYPT_STRING_HEX:
274 case CRYPT_STRING_HEXASCII:
275 case CRYPT_STRING_HEXADDR:
276 case CRYPT_STRING_HEXASCIIADDR:
277 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
280 SetLastError(ERROR_INVALID_PARAMETER);
283 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
286 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
287 WCHAR* out_buf, DWORD *out_len)
290 const BYTE *d = in_buf;
291 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
295 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
296 needed = bytes + pad_bytes + 1;
297 needed += (needed / 64 + 1) * strlenW(sep);
299 if (needed > *out_len)
302 return ERROR_INSUFFICIENT_BUFFER;
307 /* Three bytes of input give 4 chars of output */
314 if (i && i % 64 == 0)
319 /* first char is the first 6 bits of the first byte*/
320 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
321 /* second char is the last 2 bits of the first byte and the first 4
322 * bits of the second byte */
323 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
324 /* third char is the last 4 bits of the second byte and the first 2
325 * bits of the third byte */
326 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
327 /* fourth char is the remaining 6 bits of the third byte */
328 *ptr++ = b64[ d[2] & 0x3f];
337 /* first char is the first 6 bits of the first byte*/
338 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
339 /* second char is the last 2 bits of the first byte and the first 4
340 * bits of the second byte */
341 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
342 /* third char is the last 4 bits of the second byte padded with
344 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
345 /* fourth char is a = to indicate one byte of padding */
349 /* first char is the first 6 bits of the first byte*/
350 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
351 /* second char is the last 2 bits of the first byte padded with
353 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
354 /* third char is = to indicate padding */
356 /* fourth char is = to indicate padding */
362 return ERROR_SUCCESS;
365 static BOOL BinaryToBase64W(const BYTE *pbBinary,
366 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
368 static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 }, empty[] = {0};
370 LPCWSTR header = NULL, trailer = NULL, sep;
373 if (dwFlags & CRYPT_STRING_NOCR)
375 else if (dwFlags & CRYPT_STRING_NOCRLF)
379 switch (dwFlags & 0x0fffffff)
381 case CRYPT_STRING_BASE64:
382 /* no header or footer */
384 case CRYPT_STRING_BASE64HEADER:
385 header = CERT_HEADER_W;
386 trailer = CERT_TRAILER_W;
388 case CRYPT_STRING_BASE64REQUESTHEADER:
389 header = CERT_REQUEST_HEADER_W;
390 trailer = CERT_REQUEST_TRAILER_W;
392 case CRYPT_STRING_BASE64X509CRLHEADER:
393 header = X509_HEADER_W;
394 trailer = X509_TRAILER_W;
399 encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
401 charsNeeded += strlenW(header) + strlenW(sep);
403 charsNeeded += strlenW(trailer) + strlenW(sep);
404 if (charsNeeded <= *pcchString)
406 LPWSTR ptr = pszString;
407 DWORD size = charsNeeded;
411 strcpyW(ptr, header);
416 encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
420 strcpyW(ptr, trailer);
425 *pcchString = charsNeeded - 1;
429 *pcchString = charsNeeded;
430 SetLastError(ERROR_INSUFFICIENT_BUFFER);
434 *pcchString = charsNeeded;
438 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
439 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
441 BinaryToStringWFunc encoder = NULL;
443 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
448 SetLastError(ERROR_INVALID_PARAMETER);
453 SetLastError(ERROR_INVALID_PARAMETER);
457 switch (dwFlags & 0x0fffffff)
459 case CRYPT_STRING_BASE64:
460 case CRYPT_STRING_BASE64HEADER:
461 case CRYPT_STRING_BASE64REQUESTHEADER:
462 case CRYPT_STRING_BASE64X509CRLHEADER:
463 encoder = BinaryToBase64W;
465 case CRYPT_STRING_BINARY:
466 case CRYPT_STRING_HEX:
467 case CRYPT_STRING_HEXASCII:
468 case CRYPT_STRING_HEXADDR:
469 case CRYPT_STRING_HEXASCIIADDR:
470 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
473 SetLastError(ERROR_INVALID_PARAMETER);
476 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
479 static inline BYTE decodeBase64Byte(int c)
483 if (c >= 'A' && c <= 'Z')
485 else if (c >= 'a' && c <= 'z')
487 else if (c >= '0' && c <= '9')
498 static LONG decodeBase64Block(const char *in_buf, int in_len,
499 const char **nextBlock, PBYTE out_buf, DWORD *out_len)
502 const char *d = in_buf;
503 int ip0, ip1, ip2, ip3;
506 return ERROR_INVALID_DATA;
510 if ((ip0 = decodeBase64Byte(d[0])) > 63)
511 return ERROR_INVALID_DATA;
512 if ((ip1 = decodeBase64Byte(d[1])) > 63)
513 return ERROR_INVALID_DATA;
516 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
519 else if (d[3] == '=')
521 if ((ip0 = decodeBase64Byte(d[0])) > 63)
522 return ERROR_INVALID_DATA;
523 if ((ip1 = decodeBase64Byte(d[1])) > 63)
524 return ERROR_INVALID_DATA;
525 if ((ip2 = decodeBase64Byte(d[2])) > 63)
526 return ERROR_INVALID_DATA;
530 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
531 out_buf[1] = (ip1 << 4) | (ip2 >> 2);
537 if ((ip0 = decodeBase64Byte(d[0])) > 63)
538 return ERROR_INVALID_DATA;
539 if ((ip1 = decodeBase64Byte(d[1])) > 63)
540 return ERROR_INVALID_DATA;
541 if ((ip2 = decodeBase64Byte(d[2])) > 63)
542 return ERROR_INVALID_DATA;
543 if ((ip3 = decodeBase64Byte(d[3])) > 63)
544 return ERROR_INVALID_DATA;
548 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
549 out_buf[1] = (ip1 << 4) | (ip2 >> 2);
550 out_buf[2] = (ip2 << 6) | ip3;
554 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
556 else if (len >= 5 && d[4] == '\n')
558 else if (len >= 4 && d[4])
562 return ERROR_SUCCESS;
565 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
568 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
569 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
571 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
572 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
574 LONG ret = ERROR_SUCCESS;
575 const char *nextBlock;
578 nextBlock = pszString;
579 while (nextBlock && !ret)
583 ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
584 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
587 if (cchString - (nextBlock - pszString) <= 0)
596 *pdwFlags = CRYPT_STRING_BASE64;
598 else if (ret == ERROR_INSUFFICIENT_BUFFER)
606 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
607 DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
608 DWORD *pcbBinary, DWORD *pdwSkip)
613 if (cchString > strlen(header) + strlen(trailer)
614 && (ptr = strstr(pszString, header)) != NULL)
616 LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
618 if (pszString[cchString - 1] == '\n')
623 if (pszString[cchString - 1] == '\r')
628 if (!strncmp(trailerSpot, trailer, strlen(trailer)))
631 *pdwSkip = ptr - pszString;
632 ptr += strlen(header);
633 if (*ptr == '\r') ptr++;
634 if (*ptr == '\n') ptr++;
635 cchString -= ptr - pszString + strlen(trailer);
636 ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL,
640 ret = ERROR_INVALID_DATA;
643 ret = ERROR_INVALID_DATA;
647 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
648 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
650 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
651 CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
653 if (!ret && pdwFlags)
654 *pdwFlags = CRYPT_STRING_BASE64HEADER;
658 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
659 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
661 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
662 CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
664 if (!ret && pdwFlags)
665 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
669 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
670 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
672 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
673 X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
675 if (!ret && pdwFlags)
676 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
680 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
681 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
685 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
687 if (ret == ERROR_INVALID_DATA)
688 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
693 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
694 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
696 LONG ret = ERROR_SUCCESS;
698 if (*pcbBinary < cchString)
701 *pcbBinary = cchString;
704 ret = ERROR_INSUFFICIENT_BUFFER;
705 *pcbBinary = cchString;
711 memcpy(pbBinary, pszString, cchString);
712 *pcbBinary = cchString;
717 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
718 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
722 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
724 if (ret == ERROR_INVALID_DATA)
725 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
727 if (ret == ERROR_INVALID_DATA)
728 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
733 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
734 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
735 DWORD *pdwSkip, DWORD *pdwFlags)
737 StringToBinaryAFunc decoder;
740 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
741 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
745 SetLastError(ERROR_INVALID_PARAMETER);
748 /* Only the bottom byte contains valid types */
749 if (dwFlags & 0xfffffff0)
751 SetLastError(ERROR_INVALID_DATA);
756 case CRYPT_STRING_BASE64_ANY:
757 decoder = Base64AnyToBinaryA;
759 case CRYPT_STRING_BASE64:
760 decoder = Base64ToBinaryA;
762 case CRYPT_STRING_BASE64HEADER:
763 decoder = Base64HeaderToBinaryA;
765 case CRYPT_STRING_BASE64REQUESTHEADER:
766 decoder = Base64RequestHeaderToBinaryA;
768 case CRYPT_STRING_BASE64X509CRLHEADER:
769 decoder = Base64X509HeaderToBinaryA;
771 case CRYPT_STRING_BINARY:
772 decoder = DecodeBinaryToBinaryA;
774 case CRYPT_STRING_ANY:
775 decoder = DecodeAnyA;
777 case CRYPT_STRING_HEX:
778 case CRYPT_STRING_HEXASCII:
779 case CRYPT_STRING_HEXADDR:
780 case CRYPT_STRING_HEXASCIIADDR:
781 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
784 SetLastError(ERROR_INVALID_PARAMETER);
788 cchString = strlen(pszString);
789 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
792 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
795 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
796 const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
799 const WCHAR *d = in_buf;
800 int ip0, ip1, ip2, ip3;
803 return ERROR_INVALID_DATA;
808 if ((ip0 = decodeBase64Byte(d[0])) > 63)
809 return ERROR_INVALID_DATA;
810 if ((ip1 = decodeBase64Byte(d[1])) > 63)
811 return ERROR_INVALID_DATA;
814 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
817 else if (d[3] == '=')
819 if ((ip0 = decodeBase64Byte(d[0])) > 63)
820 return ERROR_INVALID_DATA;
821 if ((ip1 = decodeBase64Byte(d[1])) > 63)
822 return ERROR_INVALID_DATA;
823 if ((ip2 = decodeBase64Byte(d[2])) > 63)
824 return ERROR_INVALID_DATA;
828 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
829 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
835 if ((ip0 = decodeBase64Byte(d[0])) > 63)
836 return ERROR_INVALID_DATA;
837 if ((ip1 = decodeBase64Byte(d[1])) > 63)
838 return ERROR_INVALID_DATA;
839 if ((ip2 = decodeBase64Byte(d[2])) > 63)
840 return ERROR_INVALID_DATA;
841 if ((ip3 = decodeBase64Byte(d[3])) > 63)
842 return ERROR_INVALID_DATA;
846 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
847 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
848 out_buf[i + 2] = (ip2 << 6) | ip3;
852 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
854 else if (len >= 5 && d[4] == '\n')
856 else if (len >= 4 && d[4])
861 return ERROR_SUCCESS;
864 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
867 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
868 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
870 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
871 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
873 LONG ret = ERROR_SUCCESS;
874 const WCHAR *nextBlock;
877 nextBlock = pszString;
878 while (nextBlock && !ret)
882 ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
883 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
886 if (cchString - (nextBlock - pszString) <= 0)
895 *pdwFlags = CRYPT_STRING_BASE64;
897 else if (ret == ERROR_INSUFFICIENT_BUFFER)
905 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
906 DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
907 DWORD *pcbBinary, DWORD *pdwSkip)
912 if (cchString > strlenW(header) + strlenW(trailer)
913 && (ptr = strstrW(pszString, header)) != NULL)
915 LPCWSTR trailerSpot = pszString + cchString - strlenW(trailer);
917 if (pszString[cchString - 1] == '\n')
922 if (pszString[cchString - 1] == '\r')
927 if (!strncmpW(trailerSpot, trailer, strlenW(trailer)))
930 *pdwSkip = ptr - pszString;
931 ptr += strlenW(header);
932 if (*ptr == '\r') ptr++;
933 if (*ptr == '\n') ptr++;
934 cchString -= ptr - pszString + strlenW(trailer);
935 ret = Base64ToBinaryW(ptr, cchString, pbBinary, pcbBinary, NULL,
939 ret = ERROR_INVALID_DATA;
942 ret = ERROR_INVALID_DATA;
946 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
947 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
949 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
950 CERT_HEADER_W, CERT_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
952 if (!ret && pdwFlags)
953 *pdwFlags = CRYPT_STRING_BASE64HEADER;
957 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
958 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
960 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
961 CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
964 if (!ret && pdwFlags)
965 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
969 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
970 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
972 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
973 X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
975 if (!ret && pdwFlags)
976 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
980 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
981 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
985 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
987 if (ret == ERROR_INVALID_DATA)
988 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
993 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
994 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
996 LONG ret = ERROR_SUCCESS;
998 if (*pcbBinary < cchString)
1001 *pcbBinary = cchString;
1004 ret = ERROR_INSUFFICIENT_BUFFER;
1005 *pcbBinary = cchString;
1011 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1012 *pcbBinary = cchString * sizeof(WCHAR);
1017 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1018 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1022 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1024 if (ret == ERROR_INVALID_DATA)
1025 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1027 if (ret == ERROR_INVALID_DATA)
1028 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1033 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1034 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1035 DWORD *pdwSkip, DWORD *pdwFlags)
1037 StringToBinaryWFunc decoder;
1040 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
1041 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1045 SetLastError(ERROR_INVALID_PARAMETER);
1048 /* Only the bottom byte contains valid types */
1049 if (dwFlags & 0xfffffff0)
1051 SetLastError(ERROR_INVALID_DATA);
1056 case CRYPT_STRING_BASE64_ANY:
1057 decoder = Base64AnyToBinaryW;
1059 case CRYPT_STRING_BASE64:
1060 decoder = Base64ToBinaryW;
1062 case CRYPT_STRING_BASE64HEADER:
1063 decoder = Base64HeaderToBinaryW;
1065 case CRYPT_STRING_BASE64REQUESTHEADER:
1066 decoder = Base64RequestHeaderToBinaryW;
1068 case CRYPT_STRING_BASE64X509CRLHEADER:
1069 decoder = Base64X509HeaderToBinaryW;
1071 case CRYPT_STRING_BINARY:
1072 decoder = DecodeBinaryToBinaryW;
1074 case CRYPT_STRING_ANY:
1075 decoder = DecodeAnyW;
1077 case CRYPT_STRING_HEX:
1078 case CRYPT_STRING_HEXASCII:
1079 case CRYPT_STRING_HEXADDR:
1080 case CRYPT_STRING_HEXASCIIADDR:
1081 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1084 SetLastError(ERROR_INVALID_PARAMETER);
1088 cchString = strlenW(pszString);
1089 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1092 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;