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
;
511 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
512 return ERROR_INVALID_DATA
;
513 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
514 return ERROR_INVALID_DATA
;
517 out_buf
[i
] = (ip0
<< 2) | (ip1
>> 4);
520 else if (d
[3] == '=')
522 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
523 return ERROR_INVALID_DATA
;
524 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
525 return ERROR_INVALID_DATA
;
526 if ((ip2
= decodeBase64Byte(d
[2])) > 63)
527 return ERROR_INVALID_DATA
;
531 out_buf
[i
+ 0] = (ip0
<< 2) | (ip1
>> 4);
532 out_buf
[i
+ 1] = (ip1
<< 4) | (ip2
>> 2);
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
;
544 if ((ip3
= decodeBase64Byte(d
[3])) > 63)
545 return ERROR_INVALID_DATA
;
549 out_buf
[i
+ 0] = (ip0
<< 2) | (ip1
>> 4);
550 out_buf
[i
+ 1] = (ip1
<< 4) | (ip2
>> 2);
551 out_buf
[i
+ 2] = (ip2
<< 6) | ip3
;
555 if (len
>= 6 && d
[4] == '\r' && d
[5] == '\n')
557 else if (len
>= 5 && d
[4] == '\n')
559 else if (len
>= 4 && d
[4])
564 return ERROR_SUCCESS
;
567 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
570 typedef LONG (*StringToBinaryAFunc
)(LPCSTR pszString
, DWORD cchString
,
571 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
573 static LONG
Base64ToBinaryA(LPCSTR pszString
, DWORD cchString
,
574 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
576 LONG ret
= ERROR_SUCCESS
;
577 const char *nextBlock
;
580 nextBlock
= pszString
;
581 while (nextBlock
&& !ret
)
585 ret
= decodeBase64Block(nextBlock
, cchString
- (nextBlock
- pszString
),
586 &nextBlock
, pbBinary
? pbBinary
+ outLen
: NULL
, &len
);
589 if (cchString
- (nextBlock
- pszString
) <= 0)
598 *pdwFlags
= CRYPT_STRING_BASE64
;
600 else if (ret
== ERROR_INSUFFICIENT_BUFFER
)
608 static LONG
Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString
,
609 DWORD cchString
, LPCSTR header
, LPCSTR trailer
, BYTE
*pbBinary
,
610 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
615 if (cchString
> strlen(header
) + strlen(trailer
)
616 && (ptr
= strstr(pszString
, header
)) != NULL
)
618 LPCSTR trailerSpot
= pszString
+ cchString
- strlen(trailer
);
620 if (pszString
[cchString
- 1] == '\n')
625 if (pszString
[cchString
- 1] == '\r')
630 if (!strncmp(trailerSpot
, trailer
, strlen(trailer
)))
633 *pdwSkip
= ptr
- pszString
;
634 ptr
+= strlen(header
);
635 if (*ptr
== '\r') ptr
++;
636 if (*ptr
== '\n') ptr
++;
637 cchString
-= ptr
- pszString
+ strlen(trailer
);
638 ret
= Base64ToBinaryA(ptr
, cchString
, pbBinary
, pcbBinary
, NULL
,
642 ret
= ERROR_INVALID_DATA
;
645 ret
= ERROR_INVALID_DATA
;
649 static LONG
Base64HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
650 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
652 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
653 CERT_HEADER
, CERT_TRAILER
, pbBinary
, pcbBinary
, pdwSkip
);
655 if (!ret
&& pdwFlags
)
656 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
660 static LONG
Base64RequestHeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
661 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
663 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
664 CERT_REQUEST_HEADER
, CERT_REQUEST_TRAILER
, pbBinary
, pcbBinary
, pdwSkip
);
666 if (!ret
&& pdwFlags
)
667 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
671 static LONG
Base64X509HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
672 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
674 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
675 X509_HEADER
, X509_TRAILER
, pbBinary
, pcbBinary
, pdwSkip
);
677 if (!ret
&& pdwFlags
)
678 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
682 static LONG
Base64AnyToBinaryA(LPCSTR pszString
, DWORD cchString
,
683 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
687 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
689 if (ret
== ERROR_INVALID_DATA
)
690 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
695 static LONG
DecodeBinaryToBinaryA(LPCSTR pszString
, DWORD cchString
,
696 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
698 LONG ret
= ERROR_SUCCESS
;
700 if (*pcbBinary
< cchString
)
703 *pcbBinary
= cchString
;
706 ret
= ERROR_INSUFFICIENT_BUFFER
;
707 *pcbBinary
= cchString
;
713 memcpy(pbBinary
, pszString
, cchString
);
714 *pcbBinary
= cchString
;
719 static LONG
DecodeAnyA(LPCSTR pszString
, DWORD cchString
,
720 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
724 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
726 if (ret
== ERROR_INVALID_DATA
)
727 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
729 if (ret
== ERROR_INVALID_DATA
)
730 ret
= DecodeBinaryToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
735 BOOL WINAPI
CryptStringToBinaryA(LPCSTR pszString
,
736 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
737 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
739 StringToBinaryAFunc decoder
;
742 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString
),
743 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
747 SetLastError(ERROR_INVALID_PARAMETER
);
750 /* Only the bottom byte contains valid types */
751 if (dwFlags
& 0xfffffff0)
753 SetLastError(ERROR_INVALID_DATA
);
758 case CRYPT_STRING_BASE64_ANY
:
759 decoder
= Base64AnyToBinaryA
;
761 case CRYPT_STRING_BASE64
:
762 decoder
= Base64ToBinaryA
;
764 case CRYPT_STRING_BASE64HEADER
:
765 decoder
= Base64HeaderToBinaryA
;
767 case CRYPT_STRING_BASE64REQUESTHEADER
:
768 decoder
= Base64RequestHeaderToBinaryA
;
770 case CRYPT_STRING_BASE64X509CRLHEADER
:
771 decoder
= Base64X509HeaderToBinaryA
;
773 case CRYPT_STRING_BINARY
:
774 decoder
= DecodeBinaryToBinaryA
;
776 case CRYPT_STRING_ANY
:
777 decoder
= DecodeAnyA
;
779 case CRYPT_STRING_HEX
:
780 case CRYPT_STRING_HEXASCII
:
781 case CRYPT_STRING_HEXADDR
:
782 case CRYPT_STRING_HEXASCIIADDR
:
783 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
786 SetLastError(ERROR_INVALID_PARAMETER
);
790 cchString
= strlen(pszString
);
791 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
794 return (ret
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
797 static LONG
decodeBase64BlockW(const WCHAR
*in_buf
, int in_len
,
798 const WCHAR
**nextBlock
, PBYTE out_buf
, DWORD
*out_len
)
801 const WCHAR
*d
= in_buf
;
802 int ip0
, ip1
, ip2
, ip3
;
805 return ERROR_INVALID_DATA
;
810 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
811 return ERROR_INVALID_DATA
;
812 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
813 return ERROR_INVALID_DATA
;
816 out_buf
[i
] = (ip0
<< 2) | (ip1
>> 4);
819 else if (d
[3] == '=')
821 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
822 return ERROR_INVALID_DATA
;
823 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
824 return ERROR_INVALID_DATA
;
825 if ((ip2
= decodeBase64Byte(d
[2])) > 63)
826 return ERROR_INVALID_DATA
;
830 out_buf
[i
+ 0] = (ip0
<< 2) | (ip1
>> 4);
831 out_buf
[i
+ 1] = (ip1
<< 4) | (ip2
>> 2);
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
;
843 if ((ip3
= decodeBase64Byte(d
[3])) > 63)
844 return ERROR_INVALID_DATA
;
848 out_buf
[i
+ 0] = (ip0
<< 2) | (ip1
>> 4);
849 out_buf
[i
+ 1] = (ip1
<< 4) | (ip2
>> 2);
850 out_buf
[i
+ 2] = (ip2
<< 6) | ip3
;
854 if (len
>= 6 && d
[4] == '\r' && d
[5] == '\n')
856 else if (len
>= 5 && d
[4] == '\n')
858 else if (len
>= 4 && d
[4])
863 return ERROR_SUCCESS
;
866 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
869 typedef LONG (*StringToBinaryWFunc
)(LPCWSTR pszString
, DWORD cchString
,
870 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
872 static LONG
Base64ToBinaryW(LPCWSTR pszString
, DWORD cchString
,
873 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
875 LONG ret
= ERROR_SUCCESS
;
876 const WCHAR
*nextBlock
;
879 nextBlock
= pszString
;
880 while (nextBlock
&& !ret
)
884 ret
= decodeBase64BlockW(nextBlock
, cchString
- (nextBlock
- pszString
),
885 &nextBlock
, pbBinary
? pbBinary
+ outLen
: NULL
, &len
);
888 if (cchString
- (nextBlock
- pszString
) <= 0)
897 *pdwFlags
= CRYPT_STRING_BASE64
;
899 else if (ret
== ERROR_INSUFFICIENT_BUFFER
)
907 static LONG
Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString
,
908 DWORD cchString
, LPCWSTR header
, LPCWSTR trailer
, BYTE
*pbBinary
,
909 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
914 if (cchString
> strlenW(header
) + strlenW(trailer
)
915 && (ptr
= strstrW(pszString
, header
)) != NULL
)
917 LPCWSTR trailerSpot
= pszString
+ cchString
- strlenW(trailer
);
919 if (pszString
[cchString
- 1] == '\n')
924 if (pszString
[cchString
- 1] == '\r')
929 if (!strncmpW(trailerSpot
, trailer
, strlenW(trailer
)))
932 *pdwSkip
= ptr
- pszString
;
933 ptr
+= strlenW(header
);
934 if (*ptr
== '\r') ptr
++;
935 if (*ptr
== '\n') ptr
++;
936 cchString
-= ptr
- pszString
+ strlenW(trailer
);
937 ret
= Base64ToBinaryW(ptr
, cchString
, pbBinary
, pcbBinary
, NULL
,
941 ret
= ERROR_INVALID_DATA
;
944 ret
= ERROR_INVALID_DATA
;
948 static LONG
Base64HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
949 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
951 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
952 CERT_HEADER_W
, CERT_TRAILER_W
, pbBinary
, pcbBinary
, pdwSkip
);
954 if (!ret
&& pdwFlags
)
955 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
959 static LONG
Base64RequestHeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
960 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
962 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
963 CERT_REQUEST_HEADER_W
, CERT_REQUEST_TRAILER_W
, pbBinary
, pcbBinary
,
966 if (!ret
&& pdwFlags
)
967 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
971 static LONG
Base64X509HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
972 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
974 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
975 X509_HEADER_W
, X509_TRAILER_W
, pbBinary
, pcbBinary
, pdwSkip
);
977 if (!ret
&& pdwFlags
)
978 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
982 static LONG
Base64AnyToBinaryW(LPCWSTR pszString
, DWORD cchString
,
983 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
987 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
989 if (ret
== ERROR_INVALID_DATA
)
990 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
995 static LONG
DecodeBinaryToBinaryW(LPCWSTR pszString
, DWORD cchString
,
996 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
998 LONG ret
= ERROR_SUCCESS
;
1000 if (*pcbBinary
< cchString
)
1003 *pcbBinary
= cchString
;
1006 ret
= ERROR_INSUFFICIENT_BUFFER
;
1007 *pcbBinary
= cchString
;
1013 memcpy(pbBinary
, pszString
, cchString
* sizeof(WCHAR
));
1014 *pcbBinary
= cchString
* sizeof(WCHAR
);
1019 static LONG
DecodeAnyW(LPCWSTR pszString
, DWORD cchString
,
1020 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1024 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1026 if (ret
== ERROR_INVALID_DATA
)
1027 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1029 if (ret
== ERROR_INVALID_DATA
)
1030 ret
= DecodeBinaryToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1035 BOOL WINAPI
CryptStringToBinaryW(LPCWSTR pszString
,
1036 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
1037 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1039 StringToBinaryWFunc decoder
;
1042 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString
),
1043 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1047 SetLastError(ERROR_INVALID_PARAMETER
);
1050 /* Only the bottom byte contains valid types */
1051 if (dwFlags
& 0xfffffff0)
1053 SetLastError(ERROR_INVALID_DATA
);
1058 case CRYPT_STRING_BASE64_ANY
:
1059 decoder
= Base64AnyToBinaryW
;
1061 case CRYPT_STRING_BASE64
:
1062 decoder
= Base64ToBinaryW
;
1064 case CRYPT_STRING_BASE64HEADER
:
1065 decoder
= Base64HeaderToBinaryW
;
1067 case CRYPT_STRING_BASE64REQUESTHEADER
:
1068 decoder
= Base64RequestHeaderToBinaryW
;
1070 case CRYPT_STRING_BASE64X509CRLHEADER
:
1071 decoder
= Base64X509HeaderToBinaryW
;
1073 case CRYPT_STRING_BINARY
:
1074 decoder
= DecodeBinaryToBinaryW
;
1076 case CRYPT_STRING_ANY
:
1077 decoder
= DecodeAnyW
;
1079 case CRYPT_STRING_HEX
:
1080 case CRYPT_STRING_HEXASCII
:
1081 case CRYPT_STRING_HEXADDR
:
1082 case CRYPT_STRING_HEXASCIIADDR
:
1083 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
1086 SetLastError(ERROR_INVALID_PARAMETER
);
1090 cchString
= strlenW(pszString
);
1091 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1094 return (ret
== ERROR_SUCCESS
) ? TRUE
: FALSE
;