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_HEADER_START "-----BEGIN"
34 #define CERT_DELIMITER "-----"
35 #define CERT_TRAILER "-----END CERTIFICATE-----"
36 #define CERT_TRAILER_START "-----END"
37 #define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
38 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
39 #define X509_HEADER "-----BEGIN X509 CRL-----"
40 #define X509_TRAILER "-----END X509 CRL-----"
42 static const WCHAR CERT_HEADER_W[] = {
43 '-','-','-','-','-','B','E','G','I','N',' ','C','E','R','T','I','F','I','C',
44 'A','T','E','-','-','-','-','-',0 };
45 static const WCHAR CERT_HEADER_START_W[] = {
46 '-','-','-','-','-','B','E','G','I','N',0 };
47 static const WCHAR CERT_DELIMITER_W[] = {
48 '-','-','-','-','-',0 };
49 static const WCHAR CERT_TRAILER_W[] = {
50 '-','-','-','-','-','E','N','D',0 };
51 static const WCHAR CERT_TRAILER_START_W[] = {
52 '-','-','-','-','-','E','N','D',' ','C','E','R','T','I','F','I','C','A','T',
53 'E','-','-','-','-','-',0 };
54 static const WCHAR CERT_REQUEST_HEADER_W[] = {
55 '-','-','-','-','-','B','E','G','I','N',' ','N','E','W',' ','C','E','R','T',
56 'I','F','I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
57 static const WCHAR CERT_REQUEST_TRAILER_W[] = {
58 '-','-','-','-','-','E','N','D',' ','N','E','W',' ','C','E','R','T','I','F',
59 'I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
60 static const WCHAR X509_HEADER_W[] = {
61 '-','-','-','-','-','B','E','G','I','N',' ','X','5','0','9',' ','C','R','L',
62 '-','-','-','-','-',0 };
63 static const WCHAR X509_TRAILER_W[] = {
64 '-','-','-','-','-','E','N','D',' ','X','5','0','9',' ','C','R','L','-','-',
67 static const char b64[] =
68 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
70 typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary,
71 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString);
72 typedef BOOL (*BinaryToStringWFunc)(const BYTE *pbBinary,
73 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString);
75 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
76 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
80 if (*pcchString < cbBinary)
83 *pcchString = cbBinary;
86 SetLastError(ERROR_INSUFFICIENT_BUFFER);
87 *pcchString = cbBinary;
94 memcpy(pszString, pbBinary, cbBinary);
95 *pcchString = cbBinary;
100 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
101 char* out_buf, DWORD *out_len)
104 const BYTE *d = in_buf;
105 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
109 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
110 needed = bytes + pad_bytes + 1;
111 needed += (needed / 64 + 1) * strlen(sep);
113 if (needed > *out_len)
116 return ERROR_INSUFFICIENT_BUFFER;
121 /* Three bytes of input give 4 chars of output */
128 if (i && i % 64 == 0)
133 /* first char is the first 6 bits of the first byte*/
134 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
135 /* second char is the last 2 bits of the first byte and the first 4
136 * bits of the second byte */
137 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
138 /* third char is the last 4 bits of the second byte and the first 2
139 * bits of the third byte */
140 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
141 /* fourth char is the remaining 6 bits of the third byte */
142 *ptr++ = b64[ d[2] & 0x3f];
151 /* first char is the first 6 bits of the first byte*/
152 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
153 /* second char is the last 2 bits of the first byte and the first 4
154 * bits of the second byte */
155 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
156 /* third char is the last 4 bits of the second byte padded with
158 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
159 /* fourth char is a = to indicate one byte of padding */
163 /* first char is the first 6 bits of the first byte*/
164 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
165 /* second char is the last 2 bits of the first byte padded with
167 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
168 /* third char is = to indicate padding */
170 /* fourth char is = to indicate padding */
176 return ERROR_SUCCESS;
179 static BOOL BinaryToBase64A(const BYTE *pbBinary,
180 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
182 static const char crlf[] = "\r\n", lf[] = "\n";
184 LPCSTR header = NULL, trailer = NULL, sep;
187 if (dwFlags & CRYPT_STRING_NOCR)
189 else if (dwFlags & CRYPT_STRING_NOCRLF)
193 switch (dwFlags & 0x0fffffff)
195 case CRYPT_STRING_BASE64:
196 /* no header or footer */
198 case CRYPT_STRING_BASE64HEADER:
199 header = CERT_HEADER;
200 trailer = CERT_TRAILER;
202 case CRYPT_STRING_BASE64REQUESTHEADER:
203 header = CERT_REQUEST_HEADER;
204 trailer = CERT_REQUEST_TRAILER;
206 case CRYPT_STRING_BASE64X509CRLHEADER:
207 header = X509_HEADER;
208 trailer = X509_TRAILER;
213 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
215 charsNeeded += strlen(header) + strlen(sep);
217 charsNeeded += strlen(trailer) + strlen(sep);
218 if (charsNeeded <= *pcchString)
220 LPSTR ptr = pszString;
221 DWORD size = charsNeeded;
230 encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
234 strcpy(ptr, trailer);
239 *pcchString = charsNeeded - 1;
243 *pcchString = charsNeeded;
244 SetLastError(ERROR_INSUFFICIENT_BUFFER);
248 *pcchString = charsNeeded;
252 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
253 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
255 BinaryToStringAFunc encoder = NULL;
257 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
262 SetLastError(ERROR_INVALID_PARAMETER);
267 SetLastError(ERROR_INVALID_PARAMETER);
271 switch (dwFlags & 0x0fffffff)
273 case CRYPT_STRING_BINARY:
274 encoder = EncodeBinaryToBinaryA;
276 case CRYPT_STRING_BASE64:
277 case CRYPT_STRING_BASE64HEADER:
278 case CRYPT_STRING_BASE64REQUESTHEADER:
279 case CRYPT_STRING_BASE64X509CRLHEADER:
280 encoder = BinaryToBase64A;
282 case CRYPT_STRING_HEX:
283 case CRYPT_STRING_HEXASCII:
284 case CRYPT_STRING_HEXADDR:
285 case CRYPT_STRING_HEXASCIIADDR:
286 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
289 SetLastError(ERROR_INVALID_PARAMETER);
292 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
295 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
296 WCHAR* out_buf, DWORD *out_len)
299 const BYTE *d = in_buf;
300 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
304 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
305 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 (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 */
371 return ERROR_SUCCESS;
374 static BOOL BinaryToBase64W(const BYTE *pbBinary,
375 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
377 static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 }, empty[] = {0};
379 LPCWSTR header = NULL, trailer = NULL, sep;
382 if (dwFlags & CRYPT_STRING_NOCR)
384 else if (dwFlags & CRYPT_STRING_NOCRLF)
388 switch (dwFlags & 0x0fffffff)
390 case CRYPT_STRING_BASE64:
391 /* no header or footer */
393 case CRYPT_STRING_BASE64HEADER:
394 header = CERT_HEADER_W;
395 trailer = CERT_TRAILER_W;
397 case CRYPT_STRING_BASE64REQUESTHEADER:
398 header = CERT_REQUEST_HEADER_W;
399 trailer = CERT_REQUEST_TRAILER_W;
401 case CRYPT_STRING_BASE64X509CRLHEADER:
402 header = X509_HEADER_W;
403 trailer = X509_TRAILER_W;
408 encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
410 charsNeeded += strlenW(header) + strlenW(sep);
412 charsNeeded += strlenW(trailer) + strlenW(sep);
413 if (charsNeeded <= *pcchString)
415 LPWSTR ptr = pszString;
416 DWORD size = charsNeeded;
420 strcpyW(ptr, header);
425 encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
429 strcpyW(ptr, trailer);
434 *pcchString = charsNeeded - 1;
438 *pcchString = charsNeeded;
439 SetLastError(ERROR_INSUFFICIENT_BUFFER);
443 *pcchString = charsNeeded;
447 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
448 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
450 BinaryToStringWFunc encoder = NULL;
452 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
457 SetLastError(ERROR_INVALID_PARAMETER);
462 SetLastError(ERROR_INVALID_PARAMETER);
466 switch (dwFlags & 0x0fffffff)
468 case CRYPT_STRING_BASE64:
469 case CRYPT_STRING_BASE64HEADER:
470 case CRYPT_STRING_BASE64REQUESTHEADER:
471 case CRYPT_STRING_BASE64X509CRLHEADER:
472 encoder = BinaryToBase64W;
474 case CRYPT_STRING_BINARY:
475 case CRYPT_STRING_HEX:
476 case CRYPT_STRING_HEXASCII:
477 case CRYPT_STRING_HEXADDR:
478 case CRYPT_STRING_HEXASCIIADDR:
479 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
482 SetLastError(ERROR_INVALID_PARAMETER);
485 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
488 static inline BYTE decodeBase64Byte(int c)
492 if (c >= 'A' && c <= 'Z')
494 else if (c >= 'a' && c <= 'z')
496 else if (c >= '0' && c <= '9')
507 static LONG decodeBase64Block(const char *in_buf, int in_len,
508 const char **nextBlock, PBYTE out_buf, DWORD *out_len)
511 const char *d = in_buf;
512 int ip0, ip1, ip2, ip3;
515 return ERROR_INVALID_DATA;
519 if ((ip0 = decodeBase64Byte(d[0])) > 63)
520 return ERROR_INVALID_DATA;
521 if ((ip1 = decodeBase64Byte(d[1])) > 63)
522 return ERROR_INVALID_DATA;
525 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
528 else if (d[3] == '=')
530 if ((ip0 = decodeBase64Byte(d[0])) > 63)
531 return ERROR_INVALID_DATA;
532 if ((ip1 = decodeBase64Byte(d[1])) > 63)
533 return ERROR_INVALID_DATA;
534 if ((ip2 = decodeBase64Byte(d[2])) > 63)
535 return ERROR_INVALID_DATA;
539 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
540 out_buf[1] = (ip1 << 4) | (ip2 >> 2);
546 if ((ip0 = decodeBase64Byte(d[0])) > 63)
547 return ERROR_INVALID_DATA;
548 if ((ip1 = decodeBase64Byte(d[1])) > 63)
549 return ERROR_INVALID_DATA;
550 if ((ip2 = decodeBase64Byte(d[2])) > 63)
551 return ERROR_INVALID_DATA;
552 if ((ip3 = decodeBase64Byte(d[3])) > 63)
553 return ERROR_INVALID_DATA;
557 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
558 out_buf[1] = (ip1 << 4) | (ip2 >> 2);
559 out_buf[2] = (ip2 << 6) | ip3;
563 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
565 else if (len >= 5 && d[4] == '\n')
567 else if (len >= 4 && d[4])
571 return ERROR_SUCCESS;
574 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
577 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
578 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
580 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
581 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
583 LONG ret = ERROR_SUCCESS;
584 const char *nextBlock;
587 nextBlock = pszString;
588 while (nextBlock && !ret)
592 ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
593 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
596 if (cchString - (nextBlock - pszString) <= 0)
605 *pdwFlags = CRYPT_STRING_BASE64;
607 else if (ret == ERROR_INSUFFICIENT_BUFFER)
615 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
616 DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
617 DWORD *pcbBinary, DWORD *pdwSkip, BOOL exactHeaderAndTrailerMatch)
623 LPCSTR trailerBegins;
626 if ((strlen(header) + strlen(trailer)) > cchString)
628 return ERROR_INVALID_DATA;
631 if (!(headerBegins = strstr(pszString, header)))
633 TRACE("Can't find %s in %s.\n", header, pszString);
634 return ERROR_INVALID_DATA;
637 dataBegins = headerBegins + strlen(header);
638 if (!exactHeaderAndTrailerMatch)
640 if ((dataBegins = strstr(dataBegins, CERT_DELIMITER)))
642 dataBegins += strlen(CERT_DELIMITER);
646 return ERROR_INVALID_DATA;
649 if (*dataBegins == '\r') dataBegins++;
650 if (*dataBegins == '\n') dataBegins++;
652 if (exactHeaderAndTrailerMatch)
654 trailerBegins = pszString + cchString - strlen(trailer);
655 if (pszString[cchString - 1] == '\n') trailerBegins--;
656 if (pszString[cchString - 2] == '\r') trailerBegins--;
658 if (*(trailerBegins-1) == '\n') trailerBegins--;
659 if (*(trailerBegins-1) == '\r') trailerBegins--;
661 if (!strncmp(trailerBegins, trailer, strlen(trailer)))
663 return ERROR_INVALID_DATA;
668 if (!(trailerBegins = strstr(dataBegins, trailer)))
670 return ERROR_INVALID_DATA;
672 if (*(trailerBegins-1) == '\n') trailerBegins--;
673 if (*(trailerBegins-1) == '\r') trailerBegins--;
677 *pdwSkip = headerBegins - pszString;
679 dataLength = trailerBegins - dataBegins;
681 ret = Base64ToBinaryA(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
687 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
688 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
690 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
691 CERT_HEADER_START, CERT_TRAILER_START, pbBinary, pcbBinary, pdwSkip, FALSE);
693 if (!ret && pdwFlags)
694 *pdwFlags = CRYPT_STRING_BASE64HEADER;
698 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
699 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
701 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
702 CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip, TRUE);
704 if (!ret && pdwFlags)
705 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
709 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
710 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
712 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
713 X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip, TRUE);
715 if (!ret && pdwFlags)
716 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
720 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
721 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
725 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
727 if (ret == ERROR_INVALID_DATA)
728 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
733 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
734 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
736 LONG ret = ERROR_SUCCESS;
738 if (*pcbBinary < cchString)
741 *pcbBinary = cchString;
744 ret = ERROR_INSUFFICIENT_BUFFER;
745 *pcbBinary = cchString;
751 memcpy(pbBinary, pszString, cchString);
752 *pcbBinary = cchString;
757 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
758 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
762 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
764 if (ret == ERROR_INVALID_DATA)
765 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
767 if (ret == ERROR_INVALID_DATA)
768 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
773 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
774 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
775 DWORD *pdwSkip, DWORD *pdwFlags)
777 StringToBinaryAFunc decoder;
780 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
781 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
785 SetLastError(ERROR_INVALID_PARAMETER);
788 /* Only the bottom byte contains valid types */
789 if (dwFlags & 0xfffffff0)
791 SetLastError(ERROR_INVALID_DATA);
796 case CRYPT_STRING_BASE64_ANY:
797 decoder = Base64AnyToBinaryA;
799 case CRYPT_STRING_BASE64:
800 decoder = Base64ToBinaryA;
802 case CRYPT_STRING_BASE64HEADER:
803 decoder = Base64HeaderToBinaryA;
805 case CRYPT_STRING_BASE64REQUESTHEADER:
806 decoder = Base64RequestHeaderToBinaryA;
808 case CRYPT_STRING_BASE64X509CRLHEADER:
809 decoder = Base64X509HeaderToBinaryA;
811 case CRYPT_STRING_BINARY:
812 decoder = DecodeBinaryToBinaryA;
814 case CRYPT_STRING_ANY:
815 decoder = DecodeAnyA;
817 case CRYPT_STRING_HEX:
818 case CRYPT_STRING_HEXASCII:
819 case CRYPT_STRING_HEXADDR:
820 case CRYPT_STRING_HEXASCIIADDR:
821 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
824 SetLastError(ERROR_INVALID_PARAMETER);
828 cchString = strlen(pszString);
829 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
832 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
835 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
836 const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
839 const WCHAR *d = in_buf;
840 int ip0, ip1, ip2, ip3;
843 return ERROR_INVALID_DATA;
848 if ((ip0 = decodeBase64Byte(d[0])) > 63)
849 return ERROR_INVALID_DATA;
850 if ((ip1 = decodeBase64Byte(d[1])) > 63)
851 return ERROR_INVALID_DATA;
854 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
857 else if (d[3] == '=')
859 if ((ip0 = decodeBase64Byte(d[0])) > 63)
860 return ERROR_INVALID_DATA;
861 if ((ip1 = decodeBase64Byte(d[1])) > 63)
862 return ERROR_INVALID_DATA;
863 if ((ip2 = decodeBase64Byte(d[2])) > 63)
864 return ERROR_INVALID_DATA;
868 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
869 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
875 if ((ip0 = decodeBase64Byte(d[0])) > 63)
876 return ERROR_INVALID_DATA;
877 if ((ip1 = decodeBase64Byte(d[1])) > 63)
878 return ERROR_INVALID_DATA;
879 if ((ip2 = decodeBase64Byte(d[2])) > 63)
880 return ERROR_INVALID_DATA;
881 if ((ip3 = decodeBase64Byte(d[3])) > 63)
882 return ERROR_INVALID_DATA;
886 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
887 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
888 out_buf[i + 2] = (ip2 << 6) | ip3;
892 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
894 else if (len >= 5 && d[4] == '\n')
896 else if (len >= 4 && d[4])
901 return ERROR_SUCCESS;
904 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
907 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
908 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
910 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
911 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
913 LONG ret = ERROR_SUCCESS;
914 const WCHAR *nextBlock;
917 nextBlock = pszString;
918 while (nextBlock && !ret)
922 ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
923 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
926 if (cchString - (nextBlock - pszString) <= 0)
935 *pdwFlags = CRYPT_STRING_BASE64;
937 else if (ret == ERROR_INSUFFICIENT_BUFFER)
945 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
946 DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
947 DWORD *pcbBinary, DWORD *pdwSkip, BOOL exactHeaderAndTrailerMatch)
951 LPCWSTR headerBegins;
953 LPCWSTR trailerBegins;
956 if ((strlenW(header) + strlenW(trailer)) > cchString)
958 return ERROR_INVALID_DATA;
961 if (!(headerBegins = strstrW(pszString, header)))
963 TRACE("Can't find %s in %s.\n", debugstr_w(header), debugstr_w(pszString));
964 return ERROR_INVALID_DATA;
967 dataBegins = headerBegins + strlenW(header);
968 if (!exactHeaderAndTrailerMatch)
970 if ((dataBegins = strstrW(dataBegins, CERT_DELIMITER_W)))
972 dataBegins += strlenW(CERT_DELIMITER_W);
976 return ERROR_INVALID_DATA;
979 if (*dataBegins == '\r') dataBegins++;
980 if (*dataBegins == '\n') dataBegins++;
982 if (exactHeaderAndTrailerMatch)
984 trailerBegins = pszString + cchString - strlenW(trailer);
985 if (pszString[cchString - 1] == '\n') trailerBegins--;
986 if (pszString[cchString - 2] == '\r') trailerBegins--;
988 if (*(trailerBegins-1) == '\n') trailerBegins--;
989 if (*(trailerBegins-1) == '\r') trailerBegins--;
991 if (!strncmpW(trailerBegins, trailer, strlenW(trailer)))
993 return ERROR_INVALID_DATA;
998 if (!(trailerBegins = strstrW(dataBegins, trailer)))
1000 return ERROR_INVALID_DATA;
1002 if (*(trailerBegins-1) == '\n') trailerBegins--;
1003 if (*(trailerBegins-1) == '\r') trailerBegins--;
1007 *pdwSkip = headerBegins - pszString;
1009 dataLength = trailerBegins - dataBegins;
1011 ret = Base64ToBinaryW(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
1017 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1018 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1020 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1021 CERT_HEADER_START_W, CERT_TRAILER_START_W, pbBinary, pcbBinary,
1024 if (!ret && pdwFlags)
1025 *pdwFlags = CRYPT_STRING_BASE64HEADER;
1029 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1030 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1032 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1033 CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
1036 if (!ret && pdwFlags)
1037 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
1041 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1042 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1044 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1045 X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip, TRUE);
1047 if (!ret && pdwFlags)
1048 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
1052 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
1053 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1057 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1059 if (ret == ERROR_INVALID_DATA)
1060 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1065 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
1066 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1068 LONG ret = ERROR_SUCCESS;
1070 if (*pcbBinary < cchString)
1073 *pcbBinary = cchString;
1076 ret = ERROR_INSUFFICIENT_BUFFER;
1077 *pcbBinary = cchString;
1083 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1084 *pcbBinary = cchString * sizeof(WCHAR);
1089 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1090 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1094 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1096 if (ret == ERROR_INVALID_DATA)
1097 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1099 if (ret == ERROR_INVALID_DATA)
1100 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1105 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1106 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1107 DWORD *pdwSkip, DWORD *pdwFlags)
1109 StringToBinaryWFunc decoder;
1112 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
1113 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1117 SetLastError(ERROR_INVALID_PARAMETER);
1120 /* Only the bottom byte contains valid types */
1121 if (dwFlags & 0xfffffff0)
1123 SetLastError(ERROR_INVALID_DATA);
1128 case CRYPT_STRING_BASE64_ANY:
1129 decoder = Base64AnyToBinaryW;
1131 case CRYPT_STRING_BASE64:
1132 decoder = Base64ToBinaryW;
1134 case CRYPT_STRING_BASE64HEADER:
1135 decoder = Base64HeaderToBinaryW;
1137 case CRYPT_STRING_BASE64REQUESTHEADER:
1138 decoder = Base64RequestHeaderToBinaryW;
1140 case CRYPT_STRING_BASE64X509CRLHEADER:
1141 decoder = Base64X509HeaderToBinaryW;
1143 case CRYPT_STRING_BINARY:
1144 decoder = DecodeBinaryToBinaryW;
1146 case CRYPT_STRING_ANY:
1147 decoder = DecodeAnyW;
1149 case CRYPT_STRING_HEX:
1150 case CRYPT_STRING_HEXASCII:
1151 case CRYPT_STRING_HEXADDR:
1152 case CRYPT_STRING_HEXASCIIADDR:
1153 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1156 SetLastError(ERROR_INVALID_PARAMETER);
1160 cchString = strlenW(pszString);
1161 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1164 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;