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);
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;
305 needed += (needed / 64 + 1) * strlenW(sep);
307 if (needed > *out_len)
310 return ERROR_INSUFFICIENT_BUFFER;
315 /* Three bytes of input give 4 chars of output */
322 if (i && i % 64 == 0)
327 /* first char is the first 6 bits of the first byte*/
328 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
329 /* second char is the last 2 bits of the first byte and the first 4
330 * bits of the second byte */
331 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
332 /* third char is the last 4 bits of the second byte and the first 2
333 * bits of the third byte */
334 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
335 /* fourth char is the remaining 6 bits of the third byte */
336 *ptr++ = b64[ d[2] & 0x3f];
345 /* first char is the first 6 bits of the first byte*/
346 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
347 /* second char is the last 2 bits of the first byte and the first 4
348 * bits of the second byte */
349 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
350 /* third char is the last 4 bits of the second byte padded with
352 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
353 /* fourth char is a = to indicate one byte of padding */
357 /* first char is the first 6 bits of the first byte*/
358 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
359 /* second char is the last 2 bits of the first byte padded with
361 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
362 /* third char is = to indicate padding */
364 /* fourth char is = to indicate padding */
370 return ERROR_SUCCESS;
373 static BOOL BinaryToBase64W(const BYTE *pbBinary,
374 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
376 static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 }, empty[] = {0};
378 LPCWSTR header = NULL, trailer = NULL, sep;
381 if (dwFlags & CRYPT_STRING_NOCR)
383 else if (dwFlags & CRYPT_STRING_NOCRLF)
387 switch (dwFlags & 0x0fffffff)
389 case CRYPT_STRING_BASE64:
390 /* no header or footer */
392 case CRYPT_STRING_BASE64HEADER:
393 header = CERT_HEADER_W;
394 trailer = CERT_TRAILER_W;
396 case CRYPT_STRING_BASE64REQUESTHEADER:
397 header = CERT_REQUEST_HEADER_W;
398 trailer = CERT_REQUEST_TRAILER_W;
400 case CRYPT_STRING_BASE64X509CRLHEADER:
401 header = X509_HEADER_W;
402 trailer = X509_TRAILER_W;
407 encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
409 charsNeeded += strlenW(header) + strlenW(sep);
411 charsNeeded += strlenW(trailer) + strlenW(sep);
412 if (charsNeeded <= *pcchString)
414 LPWSTR ptr = pszString;
415 DWORD size = charsNeeded;
419 strcpyW(ptr, header);
424 encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
428 strcpyW(ptr, trailer);
432 *pcchString = charsNeeded - 1;
436 *pcchString = charsNeeded;
437 SetLastError(ERROR_INSUFFICIENT_BUFFER);
441 *pcchString = charsNeeded;
445 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
446 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
448 BinaryToStringWFunc encoder = NULL;
450 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
455 SetLastError(ERROR_INVALID_PARAMETER);
460 SetLastError(ERROR_INVALID_PARAMETER);
464 switch (dwFlags & 0x0fffffff)
466 case CRYPT_STRING_BASE64:
467 case CRYPT_STRING_BASE64HEADER:
468 case CRYPT_STRING_BASE64REQUESTHEADER:
469 case CRYPT_STRING_BASE64X509CRLHEADER:
470 encoder = BinaryToBase64W;
472 case CRYPT_STRING_BINARY:
473 case CRYPT_STRING_HEX:
474 case CRYPT_STRING_HEXASCII:
475 case CRYPT_STRING_HEXADDR:
476 case CRYPT_STRING_HEXASCIIADDR:
477 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
480 SetLastError(ERROR_INVALID_PARAMETER);
483 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
486 static inline BYTE decodeBase64Byte(int c)
490 if (c >= 'A' && c <= 'Z')
492 else if (c >= 'a' && c <= 'z')
494 else if (c >= '0' && c <= '9')
505 static LONG decodeBase64Block(const char *in_buf, int in_len,
506 const char **nextBlock, PBYTE out_buf, DWORD *out_len)
509 const char *d = in_buf;
510 int ip0, ip1, ip2, ip3;
513 return ERROR_INVALID_DATA;
517 if ((ip0 = decodeBase64Byte(d[0])) > 63)
518 return ERROR_INVALID_DATA;
519 if ((ip1 = decodeBase64Byte(d[1])) > 63)
520 return ERROR_INVALID_DATA;
523 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
526 else if (d[3] == '=')
528 if ((ip0 = decodeBase64Byte(d[0])) > 63)
529 return ERROR_INVALID_DATA;
530 if ((ip1 = decodeBase64Byte(d[1])) > 63)
531 return ERROR_INVALID_DATA;
532 if ((ip2 = decodeBase64Byte(d[2])) > 63)
533 return ERROR_INVALID_DATA;
537 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
538 out_buf[1] = (ip1 << 4) | (ip2 >> 2);
544 if ((ip0 = decodeBase64Byte(d[0])) > 63)
545 return ERROR_INVALID_DATA;
546 if ((ip1 = decodeBase64Byte(d[1])) > 63)
547 return ERROR_INVALID_DATA;
548 if ((ip2 = decodeBase64Byte(d[2])) > 63)
549 return ERROR_INVALID_DATA;
550 if ((ip3 = decodeBase64Byte(d[3])) > 63)
551 return ERROR_INVALID_DATA;
555 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
556 out_buf[1] = (ip1 << 4) | (ip2 >> 2);
557 out_buf[2] = (ip2 << 6) | ip3;
561 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
563 else if (len >= 5 && d[4] == '\n')
565 else if (len >= 4 && d[4])
569 return ERROR_SUCCESS;
572 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
575 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
576 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
578 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
579 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
581 LONG ret = ERROR_SUCCESS;
582 const char *nextBlock;
585 nextBlock = pszString;
586 while (nextBlock && !ret)
590 ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
591 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
594 if (cchString - (nextBlock - pszString) <= 0)
603 *pdwFlags = CRYPT_STRING_BASE64;
605 else if (ret == ERROR_INSUFFICIENT_BUFFER)
613 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
614 DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
615 DWORD *pcbBinary, DWORD *pdwSkip, BOOL exactHeaderAndTrailerMatch)
621 LPCSTR trailerBegins;
624 if ((strlen(header) + strlen(trailer)) > cchString)
626 return ERROR_INVALID_DATA;
629 if (!(headerBegins = strstr(pszString, header)))
631 TRACE("Can't find %s in %s.\n", header, pszString);
632 return ERROR_INVALID_DATA;
635 dataBegins = headerBegins + strlen(header);
636 if (!exactHeaderAndTrailerMatch)
638 if ((dataBegins = strstr(dataBegins, CERT_DELIMITER)))
640 dataBegins += strlen(CERT_DELIMITER);
644 return ERROR_INVALID_DATA;
647 if (*dataBegins == '\r') dataBegins++;
648 if (*dataBegins == '\n') dataBegins++;
650 if (exactHeaderAndTrailerMatch)
652 trailerBegins = pszString + cchString - strlen(trailer);
653 if (pszString[cchString - 1] == '\n') trailerBegins--;
654 if (pszString[cchString - 2] == '\r') trailerBegins--;
656 if (*(trailerBegins-1) == '\n') trailerBegins--;
657 if (*(trailerBegins-1) == '\r') trailerBegins--;
659 if (!strncmp(trailerBegins, trailer, strlen(trailer)))
661 return ERROR_INVALID_DATA;
666 if (!(trailerBegins = strstr(dataBegins, trailer)))
668 return ERROR_INVALID_DATA;
670 if (*(trailerBegins-1) == '\n') trailerBegins--;
671 if (*(trailerBegins-1) == '\r') trailerBegins--;
675 *pdwSkip = headerBegins - pszString;
677 dataLength = trailerBegins - dataBegins;
679 ret = Base64ToBinaryA(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
685 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
686 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
688 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
689 CERT_HEADER_START, CERT_TRAILER_START, pbBinary, pcbBinary, pdwSkip, FALSE);
691 if (!ret && pdwFlags)
692 *pdwFlags = CRYPT_STRING_BASE64HEADER;
696 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
697 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
699 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
700 CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip, TRUE);
702 if (!ret && pdwFlags)
703 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
707 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
708 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
710 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
711 X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip, TRUE);
713 if (!ret && pdwFlags)
714 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
718 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
719 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
723 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
725 if (ret == ERROR_INVALID_DATA)
726 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
731 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
732 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
734 LONG ret = ERROR_SUCCESS;
736 if (*pcbBinary < cchString)
739 *pcbBinary = cchString;
742 ret = ERROR_INSUFFICIENT_BUFFER;
743 *pcbBinary = cchString;
749 memcpy(pbBinary, pszString, cchString);
750 *pcbBinary = cchString;
755 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
756 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
760 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
762 if (ret == ERROR_INVALID_DATA)
763 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
765 if (ret == ERROR_INVALID_DATA)
766 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
771 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
772 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
773 DWORD *pdwSkip, DWORD *pdwFlags)
775 StringToBinaryAFunc decoder;
778 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
779 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
783 SetLastError(ERROR_INVALID_PARAMETER);
786 /* Only the bottom byte contains valid types */
787 if (dwFlags & 0xfffffff0)
789 SetLastError(ERROR_INVALID_DATA);
794 case CRYPT_STRING_BASE64_ANY:
795 decoder = Base64AnyToBinaryA;
797 case CRYPT_STRING_BASE64:
798 decoder = Base64ToBinaryA;
800 case CRYPT_STRING_BASE64HEADER:
801 decoder = Base64HeaderToBinaryA;
803 case CRYPT_STRING_BASE64REQUESTHEADER:
804 decoder = Base64RequestHeaderToBinaryA;
806 case CRYPT_STRING_BASE64X509CRLHEADER:
807 decoder = Base64X509HeaderToBinaryA;
809 case CRYPT_STRING_BINARY:
810 decoder = DecodeBinaryToBinaryA;
812 case CRYPT_STRING_ANY:
813 decoder = DecodeAnyA;
815 case CRYPT_STRING_HEX:
816 case CRYPT_STRING_HEXASCII:
817 case CRYPT_STRING_HEXADDR:
818 case CRYPT_STRING_HEXASCIIADDR:
819 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
822 SetLastError(ERROR_INVALID_PARAMETER);
826 cchString = strlen(pszString);
827 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
830 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
833 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
834 const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
837 const WCHAR *d = in_buf;
838 int ip0, ip1, ip2, ip3;
841 return ERROR_INVALID_DATA;
846 if ((ip0 = decodeBase64Byte(d[0])) > 63)
847 return ERROR_INVALID_DATA;
848 if ((ip1 = decodeBase64Byte(d[1])) > 63)
849 return ERROR_INVALID_DATA;
852 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
855 else if (d[3] == '=')
857 if ((ip0 = decodeBase64Byte(d[0])) > 63)
858 return ERROR_INVALID_DATA;
859 if ((ip1 = decodeBase64Byte(d[1])) > 63)
860 return ERROR_INVALID_DATA;
861 if ((ip2 = decodeBase64Byte(d[2])) > 63)
862 return ERROR_INVALID_DATA;
866 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
867 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
873 if ((ip0 = decodeBase64Byte(d[0])) > 63)
874 return ERROR_INVALID_DATA;
875 if ((ip1 = decodeBase64Byte(d[1])) > 63)
876 return ERROR_INVALID_DATA;
877 if ((ip2 = decodeBase64Byte(d[2])) > 63)
878 return ERROR_INVALID_DATA;
879 if ((ip3 = decodeBase64Byte(d[3])) > 63)
880 return ERROR_INVALID_DATA;
884 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
885 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
886 out_buf[i + 2] = (ip2 << 6) | ip3;
890 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
892 else if (len >= 5 && d[4] == '\n')
894 else if (len >= 4 && d[4])
899 return ERROR_SUCCESS;
902 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
905 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
906 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
908 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
909 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
911 LONG ret = ERROR_SUCCESS;
912 const WCHAR *nextBlock;
915 nextBlock = pszString;
916 while (nextBlock && !ret)
920 ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
921 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
924 if (cchString - (nextBlock - pszString) <= 0)
933 *pdwFlags = CRYPT_STRING_BASE64;
935 else if (ret == ERROR_INSUFFICIENT_BUFFER)
943 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
944 DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
945 DWORD *pcbBinary, DWORD *pdwSkip, BOOL exactHeaderAndTrailerMatch)
949 LPCWSTR headerBegins;
951 LPCWSTR trailerBegins;
954 if ((strlenW(header) + strlenW(trailer)) > cchString)
956 return ERROR_INVALID_DATA;
959 if (!(headerBegins = strstrW(pszString, header)))
961 TRACE("Can't find %s in %s.\n", debugstr_w(header), debugstr_w(pszString));
962 return ERROR_INVALID_DATA;
965 dataBegins = headerBegins + strlenW(header);
966 if (!exactHeaderAndTrailerMatch)
968 if ((dataBegins = strstrW(dataBegins, CERT_DELIMITER_W)))
970 dataBegins += strlenW(CERT_DELIMITER_W);
974 return ERROR_INVALID_DATA;
977 if (*dataBegins == '\r') dataBegins++;
978 if (*dataBegins == '\n') dataBegins++;
980 if (exactHeaderAndTrailerMatch)
982 trailerBegins = pszString + cchString - strlenW(trailer);
983 if (pszString[cchString - 1] == '\n') trailerBegins--;
984 if (pszString[cchString - 2] == '\r') trailerBegins--;
986 if (*(trailerBegins-1) == '\n') trailerBegins--;
987 if (*(trailerBegins-1) == '\r') trailerBegins--;
989 if (!strncmpW(trailerBegins, trailer, strlenW(trailer)))
991 return ERROR_INVALID_DATA;
996 if (!(trailerBegins = strstrW(dataBegins, trailer)))
998 return ERROR_INVALID_DATA;
1000 if (*(trailerBegins-1) == '\n') trailerBegins--;
1001 if (*(trailerBegins-1) == '\r') trailerBegins--;
1005 *pdwSkip = headerBegins - pszString;
1007 dataLength = trailerBegins - dataBegins;
1009 ret = Base64ToBinaryW(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
1015 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1016 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1018 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1019 CERT_HEADER_START_W, CERT_TRAILER_START_W, pbBinary, pcbBinary,
1022 if (!ret && pdwFlags)
1023 *pdwFlags = CRYPT_STRING_BASE64HEADER;
1027 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1028 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1030 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1031 CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
1034 if (!ret && pdwFlags)
1035 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
1039 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1040 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1042 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1043 X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip, TRUE);
1045 if (!ret && pdwFlags)
1046 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
1050 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
1051 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1055 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1057 if (ret == ERROR_INVALID_DATA)
1058 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1063 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
1064 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1066 LONG ret = ERROR_SUCCESS;
1068 if (*pcbBinary < cchString)
1071 *pcbBinary = cchString;
1074 ret = ERROR_INSUFFICIENT_BUFFER;
1075 *pcbBinary = cchString;
1081 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1082 *pcbBinary = cchString * sizeof(WCHAR);
1087 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1088 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1092 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1094 if (ret == ERROR_INVALID_DATA)
1095 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1097 if (ret == ERROR_INVALID_DATA)
1098 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1103 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1104 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1105 DWORD *pdwSkip, DWORD *pdwFlags)
1107 StringToBinaryWFunc decoder;
1110 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
1111 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1115 SetLastError(ERROR_INVALID_PARAMETER);
1118 /* Only the bottom byte contains valid types */
1119 if (dwFlags & 0xfffffff0)
1121 SetLastError(ERROR_INVALID_DATA);
1126 case CRYPT_STRING_BASE64_ANY:
1127 decoder = Base64AnyToBinaryW;
1129 case CRYPT_STRING_BASE64:
1130 decoder = Base64ToBinaryW;
1132 case CRYPT_STRING_BASE64HEADER:
1133 decoder = Base64HeaderToBinaryW;
1135 case CRYPT_STRING_BASE64REQUESTHEADER:
1136 decoder = Base64RequestHeaderToBinaryW;
1138 case CRYPT_STRING_BASE64X509CRLHEADER:
1139 decoder = Base64X509HeaderToBinaryW;
1141 case CRYPT_STRING_BINARY:
1142 decoder = DecodeBinaryToBinaryW;
1144 case CRYPT_STRING_ANY:
1145 decoder = DecodeAnyW;
1147 case CRYPT_STRING_HEX:
1148 case CRYPT_STRING_HEXASCII:
1149 case CRYPT_STRING_HEXADDR:
1150 case CRYPT_STRING_HEXASCIIADDR:
1151 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1154 SetLastError(ERROR_INVALID_PARAMETER);
1158 cchString = strlenW(pszString);
1159 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1162 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;