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;
103 needed += (needed / 64 + 1) * strlen(sep);
105 if (needed > *out_len)
108 return ERROR_INSUFFICIENT_BUFFER;
113 /* Three bytes of input give 4 chars of output */
120 if (sep && i && i % 64 == 0)
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];
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
150 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
151 /* fourth char is a = to indicate one byte of padding */
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
159 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
160 /* third char is = to indicate padding */
162 /* fourth char is = to indicate padding */
169 return ERROR_SUCCESS;
172 static BOOL BinaryToBase64A(const BYTE *pbBinary,
173 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
175 static const char crlf[] = "\r\n", lf[] = "\n";
177 LPCSTR header = NULL, trailer = NULL, sep;
180 if (dwFlags & CRYPT_STRING_NOCR)
182 else if (dwFlags & CRYPT_STRING_NOCRLF)
186 switch (dwFlags & 0x0fffffff)
188 case CRYPT_STRING_BASE64:
189 /* no header or footer */
191 case CRYPT_STRING_BASE64HEADER:
192 header = CERT_HEADER;
193 trailer = CERT_TRAILER;
195 case CRYPT_STRING_BASE64REQUESTHEADER:
196 header = CERT_REQUEST_HEADER;
197 trailer = CERT_REQUEST_TRAILER;
199 case CRYPT_STRING_BASE64X509CRLHEADER:
200 header = X509_HEADER;
201 trailer = X509_TRAILER;
206 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
208 charsNeeded += strlen(header) + strlen(sep);
210 charsNeeded += strlen(trailer) + strlen(sep);
211 if (charsNeeded <= *pcchString)
213 LPSTR ptr = pszString;
214 DWORD size = charsNeeded;
226 encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
230 strcpy(ptr, trailer);
238 *pcchString = charsNeeded - 1;
242 *pcchString = charsNeeded;
243 SetLastError(ERROR_INSUFFICIENT_BUFFER);
247 *pcchString = charsNeeded;
251 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
252 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
254 BinaryToStringAFunc encoder = NULL;
256 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
261 SetLastError(ERROR_INVALID_PARAMETER);
266 SetLastError(ERROR_INVALID_PARAMETER);
270 switch (dwFlags & 0x0fffffff)
272 case CRYPT_STRING_BINARY:
273 encoder = EncodeBinaryToBinaryA;
275 case CRYPT_STRING_BASE64:
276 case CRYPT_STRING_BASE64HEADER:
277 case CRYPT_STRING_BASE64REQUESTHEADER:
278 case CRYPT_STRING_BASE64X509CRLHEADER:
279 encoder = BinaryToBase64A;
281 case CRYPT_STRING_HEX:
282 case CRYPT_STRING_HEXASCII:
283 case CRYPT_STRING_HEXADDR:
284 case CRYPT_STRING_HEXASCIIADDR:
285 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
288 SetLastError(ERROR_INVALID_PARAMETER);
291 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
294 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
295 WCHAR* out_buf, DWORD *out_len)
298 const BYTE *d = in_buf;
299 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
303 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
304 needed = bytes + pad_bytes + 1;
306 needed += (needed / 64 + 1) * strlenW(sep);
308 if (needed > *out_len)
311 return ERROR_INSUFFICIENT_BUFFER;
316 /* Three bytes of input give 4 chars of output */
323 if (sep && i && i % 64 == 0)
328 /* first char is the first 6 bits of the first byte*/
329 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
330 /* second char is the last 2 bits of the first byte and the first 4
331 * bits of the second byte */
332 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
333 /* third char is the last 4 bits of the second byte and the first 2
334 * bits of the third byte */
335 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
336 /* fourth char is the remaining 6 bits of the third byte */
337 *ptr++ = b64[ d[2] & 0x3f];
346 /* first char is the first 6 bits of the first byte*/
347 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
348 /* second char is the last 2 bits of the first byte and the first 4
349 * bits of the second byte */
350 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
351 /* third char is the last 4 bits of the second byte padded with
353 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
354 /* fourth char is a = to indicate one byte of padding */
358 /* first char is the first 6 bits of the first byte*/
359 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
360 /* second char is the last 2 bits of the first byte padded with
362 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
363 /* third char is = to indicate padding */
365 /* fourth char is = to indicate padding */
372 return ERROR_SUCCESS;
375 static BOOL BinaryToBase64W(const BYTE *pbBinary,
376 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
378 static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 };
380 LPCWSTR header = NULL, trailer = NULL, sep;
383 if (dwFlags & CRYPT_STRING_NOCR)
385 else if (dwFlags & CRYPT_STRING_NOCRLF)
389 switch (dwFlags & 0x0fffffff)
391 case CRYPT_STRING_BASE64:
392 /* no header or footer */
394 case CRYPT_STRING_BASE64HEADER:
395 header = CERT_HEADER_W;
396 trailer = CERT_TRAILER_W;
398 case CRYPT_STRING_BASE64REQUESTHEADER:
399 header = CERT_REQUEST_HEADER_W;
400 trailer = CERT_REQUEST_TRAILER_W;
402 case CRYPT_STRING_BASE64X509CRLHEADER:
403 header = X509_HEADER_W;
404 trailer = X509_TRAILER_W;
409 encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
411 charsNeeded += strlenW(header) + strlenW(sep);
413 charsNeeded += strlenW(trailer) + strlenW(sep);
414 if (charsNeeded <= *pcchString)
416 LPWSTR ptr = pszString;
417 DWORD size = charsNeeded;
421 strcpyW(ptr, header);
429 encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
433 strcpyW(ptr, trailer);
441 *pcchString = charsNeeded - 1;
445 *pcchString = charsNeeded;
446 SetLastError(ERROR_INSUFFICIENT_BUFFER);
450 *pcchString = charsNeeded;
454 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
455 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
457 BinaryToStringWFunc encoder = NULL;
459 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
464 SetLastError(ERROR_INVALID_PARAMETER);
469 SetLastError(ERROR_INVALID_PARAMETER);
473 switch (dwFlags & 0x0fffffff)
475 case CRYPT_STRING_BASE64:
476 case CRYPT_STRING_BASE64HEADER:
477 case CRYPT_STRING_BASE64REQUESTHEADER:
478 case CRYPT_STRING_BASE64X509CRLHEADER:
479 encoder = BinaryToBase64W;
481 case CRYPT_STRING_BINARY:
482 case CRYPT_STRING_HEX:
483 case CRYPT_STRING_HEXASCII:
484 case CRYPT_STRING_HEXADDR:
485 case CRYPT_STRING_HEXASCIIADDR:
486 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
489 SetLastError(ERROR_INVALID_PARAMETER);
492 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
495 static inline BYTE decodeBase64Byte(int c)
499 if (c >= 'A' && c <= 'Z')
501 else if (c >= 'a' && c <= 'z')
503 else if (c >= '0' && c <= '9')
514 static LONG decodeBase64Block(const char *in_buf, int in_len,
515 const char **nextBlock, PBYTE out_buf, DWORD *out_len)
518 const char *d = in_buf;
519 int ip0, ip1, ip2, ip3;
522 return ERROR_INVALID_DATA;
527 if ((ip0 = decodeBase64Byte(d[0])) > 63)
528 return ERROR_INVALID_DATA;
529 if ((ip1 = decodeBase64Byte(d[1])) > 63)
530 return ERROR_INVALID_DATA;
533 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
536 else if (d[3] == '=')
538 if ((ip0 = decodeBase64Byte(d[0])) > 63)
539 return ERROR_INVALID_DATA;
540 if ((ip1 = decodeBase64Byte(d[1])) > 63)
541 return ERROR_INVALID_DATA;
542 if ((ip2 = decodeBase64Byte(d[2])) > 63)
543 return ERROR_INVALID_DATA;
547 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
548 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
554 if ((ip0 = decodeBase64Byte(d[0])) > 63)
555 return ERROR_INVALID_DATA;
556 if ((ip1 = decodeBase64Byte(d[1])) > 63)
557 return ERROR_INVALID_DATA;
558 if ((ip2 = decodeBase64Byte(d[2])) > 63)
559 return ERROR_INVALID_DATA;
560 if ((ip3 = decodeBase64Byte(d[3])) > 63)
561 return ERROR_INVALID_DATA;
565 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
566 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
567 out_buf[i + 2] = (ip2 << 6) | ip3;
571 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
573 else if (len >= 5 && d[4] == '\n')
575 else if (len >= 4 && d[4])
580 return ERROR_SUCCESS;
583 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
586 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
587 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
589 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
590 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
592 LONG ret = ERROR_SUCCESS;
593 const char *nextBlock;
596 nextBlock = pszString;
597 while (nextBlock && !ret)
601 ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
602 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
605 if (cchString - (nextBlock - pszString) <= 0)
614 *pdwFlags = CRYPT_STRING_BASE64;
616 else if (ret == ERROR_INSUFFICIENT_BUFFER)
624 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
625 DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
626 DWORD *pcbBinary, DWORD *pdwSkip)
631 if (cchString > strlen(header) + strlen(trailer)
632 && (ptr = strstr(pszString, header)) != NULL)
634 LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
636 if (pszString[cchString - 1] == '\n')
641 if (pszString[cchString - 1] == '\r')
646 if (!strncmp(trailerSpot, trailer, strlen(trailer)))
649 *pdwSkip = ptr - pszString;
650 ptr += strlen(header);
651 if (*ptr == '\r') ptr++;
652 if (*ptr == '\n') ptr++;
653 cchString -= ptr - pszString + strlen(trailer);
654 ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL,
658 ret = ERROR_INVALID_DATA;
661 ret = ERROR_INVALID_DATA;
665 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
666 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
668 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
669 CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
671 if (!ret && pdwFlags)
672 *pdwFlags = CRYPT_STRING_BASE64HEADER;
676 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
677 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
679 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
680 CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
682 if (!ret && pdwFlags)
683 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
687 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
688 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
690 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
691 X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
693 if (!ret && pdwFlags)
694 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
698 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
699 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
703 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
705 if (ret == ERROR_INVALID_DATA)
706 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
711 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
712 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
714 LONG ret = ERROR_SUCCESS;
716 if (*pcbBinary < cchString)
719 *pcbBinary = cchString;
722 ret = ERROR_INSUFFICIENT_BUFFER;
723 *pcbBinary = cchString;
729 memcpy(pbBinary, pszString, cchString);
730 *pcbBinary = cchString;
735 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
736 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
740 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
742 if (ret == ERROR_INVALID_DATA)
743 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
745 if (ret == ERROR_INVALID_DATA)
746 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
751 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
752 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
753 DWORD *pdwSkip, DWORD *pdwFlags)
755 StringToBinaryAFunc decoder;
758 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
759 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
763 SetLastError(ERROR_INVALID_PARAMETER);
766 /* Only the bottom byte contains valid types */
767 if (dwFlags & 0xfffffff0)
769 SetLastError(ERROR_INVALID_DATA);
774 case CRYPT_STRING_BASE64_ANY:
775 decoder = Base64AnyToBinaryA;
777 case CRYPT_STRING_BASE64:
778 decoder = Base64ToBinaryA;
780 case CRYPT_STRING_BASE64HEADER:
781 decoder = Base64HeaderToBinaryA;
783 case CRYPT_STRING_BASE64REQUESTHEADER:
784 decoder = Base64RequestHeaderToBinaryA;
786 case CRYPT_STRING_BASE64X509CRLHEADER:
787 decoder = Base64X509HeaderToBinaryA;
789 case CRYPT_STRING_BINARY:
790 decoder = DecodeBinaryToBinaryA;
792 case CRYPT_STRING_ANY:
793 decoder = DecodeAnyA;
795 case CRYPT_STRING_HEX:
796 case CRYPT_STRING_HEXASCII:
797 case CRYPT_STRING_HEXADDR:
798 case CRYPT_STRING_HEXASCIIADDR:
799 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
802 SetLastError(ERROR_INVALID_PARAMETER);
806 cchString = strlen(pszString);
807 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
810 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
813 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
814 const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
817 const WCHAR *d = in_buf;
818 int ip0, ip1, ip2, ip3;
821 return ERROR_INVALID_DATA;
826 if ((ip0 = decodeBase64Byte(d[0])) > 63)
827 return ERROR_INVALID_DATA;
828 if ((ip1 = decodeBase64Byte(d[1])) > 63)
829 return ERROR_INVALID_DATA;
832 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
835 else if (d[3] == '=')
837 if ((ip0 = decodeBase64Byte(d[0])) > 63)
838 return ERROR_INVALID_DATA;
839 if ((ip1 = decodeBase64Byte(d[1])) > 63)
840 return ERROR_INVALID_DATA;
841 if ((ip2 = decodeBase64Byte(d[2])) > 63)
842 return ERROR_INVALID_DATA;
846 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
847 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
853 if ((ip0 = decodeBase64Byte(d[0])) > 63)
854 return ERROR_INVALID_DATA;
855 if ((ip1 = decodeBase64Byte(d[1])) > 63)
856 return ERROR_INVALID_DATA;
857 if ((ip2 = decodeBase64Byte(d[2])) > 63)
858 return ERROR_INVALID_DATA;
859 if ((ip3 = decodeBase64Byte(d[3])) > 63)
860 return ERROR_INVALID_DATA;
864 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
865 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
866 out_buf[i + 2] = (ip2 << 6) | ip3;
870 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
872 else if (len >= 5 && d[4] == '\n')
874 else if (len >= 4 && d[4])
879 return ERROR_SUCCESS;
882 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
885 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
886 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
888 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
889 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
891 LONG ret = ERROR_SUCCESS;
892 const WCHAR *nextBlock;
895 nextBlock = pszString;
896 while (nextBlock && !ret)
900 ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
901 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
904 if (cchString - (nextBlock - pszString) <= 0)
913 *pdwFlags = CRYPT_STRING_BASE64;
915 else if (ret == ERROR_INSUFFICIENT_BUFFER)
923 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
924 DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
925 DWORD *pcbBinary, DWORD *pdwSkip)
930 if (cchString > strlenW(header) + strlenW(trailer)
931 && (ptr = strstrW(pszString, header)) != NULL)
933 LPCWSTR trailerSpot = pszString + cchString - strlenW(trailer);
935 if (pszString[cchString - 1] == '\n')
940 if (pszString[cchString - 1] == '\r')
945 if (!strncmpW(trailerSpot, trailer, strlenW(trailer)))
948 *pdwSkip = ptr - pszString;
949 ptr += strlenW(header);
950 if (*ptr == '\r') ptr++;
951 if (*ptr == '\n') ptr++;
952 cchString -= ptr - pszString + strlenW(trailer);
953 ret = Base64ToBinaryW(ptr, cchString, pbBinary, pcbBinary, NULL,
957 ret = ERROR_INVALID_DATA;
960 ret = ERROR_INVALID_DATA;
964 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
965 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
967 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
968 CERT_HEADER_W, CERT_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
970 if (!ret && pdwFlags)
971 *pdwFlags = CRYPT_STRING_BASE64HEADER;
975 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
976 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
978 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
979 CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
982 if (!ret && pdwFlags)
983 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
987 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
988 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
990 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
991 X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
993 if (!ret && pdwFlags)
994 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
998 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
999 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1003 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1005 if (ret == ERROR_INVALID_DATA)
1006 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1011 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
1012 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1014 LONG ret = ERROR_SUCCESS;
1016 if (*pcbBinary < cchString)
1019 *pcbBinary = cchString;
1022 ret = ERROR_INSUFFICIENT_BUFFER;
1023 *pcbBinary = cchString;
1029 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1030 *pcbBinary = cchString * sizeof(WCHAR);
1035 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1036 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1040 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1042 if (ret == ERROR_INVALID_DATA)
1043 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1045 if (ret == ERROR_INVALID_DATA)
1046 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1051 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1052 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1053 DWORD *pdwSkip, DWORD *pdwFlags)
1055 StringToBinaryWFunc decoder;
1058 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
1059 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1063 SetLastError(ERROR_INVALID_PARAMETER);
1066 /* Only the bottom byte contains valid types */
1067 if (dwFlags & 0xfffffff0)
1069 SetLastError(ERROR_INVALID_DATA);
1074 case CRYPT_STRING_BASE64_ANY:
1075 decoder = Base64AnyToBinaryW;
1077 case CRYPT_STRING_BASE64:
1078 decoder = Base64ToBinaryW;
1080 case CRYPT_STRING_BASE64HEADER:
1081 decoder = Base64HeaderToBinaryW;
1083 case CRYPT_STRING_BASE64REQUESTHEADER:
1084 decoder = Base64RequestHeaderToBinaryW;
1086 case CRYPT_STRING_BASE64X509CRLHEADER:
1087 decoder = Base64X509HeaderToBinaryW;
1089 case CRYPT_STRING_BINARY:
1090 decoder = DecodeBinaryToBinaryW;
1092 case CRYPT_STRING_ANY:
1093 decoder = DecodeAnyW;
1095 case CRYPT_STRING_HEX:
1096 case CRYPT_STRING_HEXASCII:
1097 case CRYPT_STRING_HEXADDR:
1098 case CRYPT_STRING_HEXASCIIADDR:
1099 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1102 SetLastError(ERROR_INVALID_PARAMETER);
1106 cchString = strlenW(pszString);
1107 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1110 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;