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(sep
);
210 charsNeeded
+= strlen(header
) + strlen(sep
);
212 charsNeeded
+= strlen(trailer
) + strlen(sep
);
213 if (charsNeeded
<= *pcchString
)
215 LPSTR ptr
= pszString
;
216 DWORD size
= charsNeeded
;
228 encodeBase64A(pbBinary
, cbBinary
, sep
, ptr
, &size
);
232 strcpy(ptr
, trailer
);
240 *pcchString
= charsNeeded
- 1;
244 *pcchString
= charsNeeded
;
245 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
249 *pcchString
= charsNeeded
;
253 BOOL WINAPI
CryptBinaryToStringA(const BYTE
*pbBinary
,
254 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
256 BinaryToStringAFunc encoder
= NULL
;
258 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
263 SetLastError(ERROR_INVALID_PARAMETER
);
268 SetLastError(ERROR_INVALID_PARAMETER
);
272 switch (dwFlags
& 0x0fffffff)
274 case CRYPT_STRING_BINARY
:
275 encoder
= EncodeBinaryToBinaryA
;
277 case CRYPT_STRING_BASE64
:
278 case CRYPT_STRING_BASE64HEADER
:
279 case CRYPT_STRING_BASE64REQUESTHEADER
:
280 case CRYPT_STRING_BASE64X509CRLHEADER
:
281 encoder
= BinaryToBase64A
;
283 case CRYPT_STRING_HEX
:
284 case CRYPT_STRING_HEXASCII
:
285 case CRYPT_STRING_HEXADDR
:
286 case CRYPT_STRING_HEXASCIIADDR
:
287 FIXME("Unimplemented type %d\n", dwFlags
& 0x0fffffff);
290 SetLastError(ERROR_INVALID_PARAMETER
);
293 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
296 static LONG
encodeBase64W(const BYTE
*in_buf
, int in_len
, LPCWSTR sep
,
297 WCHAR
* out_buf
, DWORD
*out_len
)
300 const BYTE
*d
= in_buf
;
301 int bytes
= (in_len
*8 + 5)/6, pad_bytes
= (bytes
% 4) ? 4 - (bytes
% 4) : 0;
305 TRACE("bytes is %d, pad bytes is %d\n", bytes
, pad_bytes
);
306 needed
= bytes
+ pad_bytes
+ 1;
308 needed
+= (needed
/ 64 + 1) * strlenW(sep
);
310 if (needed
> *out_len
)
313 return ERROR_INSUFFICIENT_BUFFER
;
318 /* Three bytes of input give 4 chars of output */
325 if (sep
&& i
&& i
% 64 == 0)
330 /* first char is the first 6 bits of the first byte*/
331 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
332 /* second char is the last 2 bits of the first byte and the first 4
333 * bits of the second byte */
334 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
335 /* third char is the last 4 bits of the second byte and the first 2
336 * bits of the third byte */
337 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) | (d
[2] >> 6 & 0x03)];
338 /* fourth char is the remaining 6 bits of the third byte */
339 *ptr
++ = b64
[ d
[2] & 0x3f];
348 /* first char is the first 6 bits of the first byte*/
349 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
350 /* second char is the last 2 bits of the first byte and the first 4
351 * bits of the second byte */
352 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
353 /* third char is the last 4 bits of the second byte padded with
355 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) ];
356 /* fourth char is a = to indicate one byte of padding */
360 /* first char is the first 6 bits of the first byte*/
361 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
362 /* second char is the last 2 bits of the first byte padded with
364 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30)];
365 /* third char is = to indicate padding */
367 /* fourth char is = to indicate padding */
374 return ERROR_SUCCESS
;
377 static BOOL
BinaryToBase64W(const BYTE
*pbBinary
,
378 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
380 static const WCHAR crlf
[] = { '\r','\n',0 }, lf
[] = { '\n',0 };
382 LPCWSTR header
= NULL
, trailer
= NULL
, sep
;
385 if (dwFlags
& CRYPT_STRING_NOCR
)
387 else if (dwFlags
& CRYPT_STRING_NOCRLF
)
391 switch (dwFlags
& 0x0fffffff)
393 case CRYPT_STRING_BASE64
:
394 /* no header or footer */
396 case CRYPT_STRING_BASE64HEADER
:
397 header
= CERT_HEADER_W
;
398 trailer
= CERT_TRAILER_W
;
400 case CRYPT_STRING_BASE64REQUESTHEADER
:
401 header
= CERT_REQUEST_HEADER_W
;
402 trailer
= CERT_REQUEST_TRAILER_W
;
404 case CRYPT_STRING_BASE64X509CRLHEADER
:
405 header
= X509_HEADER_W
;
406 trailer
= X509_TRAILER_W
;
411 encodeBase64W(pbBinary
, cbBinary
, sep
, NULL
, &charsNeeded
);
413 charsNeeded
+= strlenW(sep
);
415 charsNeeded
+= strlenW(header
) + strlenW(sep
);
417 charsNeeded
+= strlenW(trailer
) + strlenW(sep
);
418 if (charsNeeded
<= *pcchString
)
420 LPWSTR ptr
= pszString
;
421 DWORD size
= charsNeeded
;
425 strcpyW(ptr
, header
);
433 encodeBase64W(pbBinary
, cbBinary
, sep
, ptr
, &size
);
437 strcpyW(ptr
, trailer
);
445 *pcchString
= charsNeeded
- 1;
449 *pcchString
= charsNeeded
;
450 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
454 *pcchString
= charsNeeded
;
458 BOOL WINAPI
CryptBinaryToStringW(const BYTE
*pbBinary
,
459 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
461 BinaryToStringWFunc encoder
= NULL
;
463 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
468 SetLastError(ERROR_INVALID_PARAMETER
);
473 SetLastError(ERROR_INVALID_PARAMETER
);
477 switch (dwFlags
& 0x0fffffff)
479 case CRYPT_STRING_BASE64
:
480 case CRYPT_STRING_BASE64HEADER
:
481 case CRYPT_STRING_BASE64REQUESTHEADER
:
482 case CRYPT_STRING_BASE64X509CRLHEADER
:
483 encoder
= BinaryToBase64W
;
485 case CRYPT_STRING_BINARY
:
486 case CRYPT_STRING_HEX
:
487 case CRYPT_STRING_HEXASCII
:
488 case CRYPT_STRING_HEXADDR
:
489 case CRYPT_STRING_HEXASCIIADDR
:
490 FIXME("Unimplemented type %d\n", dwFlags
& 0x0fffffff);
493 SetLastError(ERROR_INVALID_PARAMETER
);
496 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
499 static inline BYTE
decodeBase64Byte(int c
)
503 if (c
>= 'A' && c
<= 'Z')
505 else if (c
>= 'a' && c
<= 'z')
507 else if (c
>= '0' && c
<= '9')
518 static LONG
decodeBase64Block(const char *in_buf
, int in_len
,
519 const char **nextBlock
, PBYTE out_buf
, DWORD
*out_len
)
522 const char *d
= in_buf
;
523 int ip0
, ip1
, ip2
, ip3
;
526 return ERROR_INVALID_DATA
;
531 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
532 return ERROR_INVALID_DATA
;
533 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
534 return ERROR_INVALID_DATA
;
537 out_buf
[i
] = (ip0
<< 2) | (ip1
>> 4);
540 else if (d
[3] == '=')
542 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
543 return ERROR_INVALID_DATA
;
544 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
545 return ERROR_INVALID_DATA
;
546 if ((ip2
= decodeBase64Byte(d
[2])) > 63)
547 return ERROR_INVALID_DATA
;
551 out_buf
[i
+ 0] = (ip0
<< 2) | (ip1
>> 4);
552 out_buf
[i
+ 1] = (ip1
<< 4) | (ip2
>> 2);
558 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
559 return ERROR_INVALID_DATA
;
560 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
561 return ERROR_INVALID_DATA
;
562 if ((ip2
= decodeBase64Byte(d
[2])) > 63)
563 return ERROR_INVALID_DATA
;
564 if ((ip3
= decodeBase64Byte(d
[3])) > 63)
565 return ERROR_INVALID_DATA
;
569 out_buf
[i
+ 0] = (ip0
<< 2) | (ip1
>> 4);
570 out_buf
[i
+ 1] = (ip1
<< 4) | (ip2
>> 2);
571 out_buf
[i
+ 2] = (ip2
<< 6) | ip3
;
575 if (len
>= 6 && d
[4] == '\r' && d
[5] == '\n')
577 else if (len
>= 5 && d
[4] == '\n')
579 else if (len
>= 4 && d
[4])
584 return ERROR_SUCCESS
;
587 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
590 typedef LONG (*StringToBinaryAFunc
)(LPCSTR pszString
, DWORD cchString
,
591 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
593 static LONG
Base64ToBinaryA(LPCSTR pszString
, DWORD cchString
,
594 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
596 LONG ret
= ERROR_SUCCESS
;
597 const char *nextBlock
;
600 nextBlock
= pszString
;
601 while (nextBlock
&& !ret
)
605 ret
= decodeBase64Block(nextBlock
, cchString
- (nextBlock
- pszString
),
606 &nextBlock
, pbBinary
? pbBinary
+ outLen
: NULL
, &len
);
609 if (cchString
- (nextBlock
- pszString
) <= 0)
618 *pdwFlags
= CRYPT_STRING_BASE64
;
620 else if (ret
== ERROR_INSUFFICIENT_BUFFER
)
628 static LONG
Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString
,
629 DWORD cchString
, LPCSTR header
, LPCSTR trailer
, BYTE
*pbBinary
,
630 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
635 if (cchString
> strlen(header
) + strlen(trailer
)
636 && (ptr
= strstr(pszString
, header
)) != NULL
)
638 LPCSTR trailerSpot
= pszString
+ cchString
- strlen(trailer
);
640 if (pszString
[cchString
- 1] == '\n')
645 if (pszString
[cchString
- 1] == '\r')
650 if (!strncmp(trailerSpot
, trailer
, strlen(trailer
)))
653 *pdwSkip
= ptr
- pszString
;
654 ptr
+= strlen(header
);
655 if (*ptr
== '\r') ptr
++;
656 if (*ptr
== '\n') ptr
++;
657 cchString
-= ptr
- pszString
+ strlen(trailer
);
658 ret
= Base64ToBinaryA(ptr
, cchString
, pbBinary
, pcbBinary
, NULL
,
662 ret
= ERROR_INVALID_DATA
;
665 ret
= ERROR_INVALID_DATA
;
669 static LONG
Base64HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
670 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
672 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
673 CERT_HEADER
, CERT_TRAILER
, pbBinary
, pcbBinary
, pdwSkip
);
675 if (!ret
&& pdwFlags
)
676 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
680 static LONG
Base64RequestHeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
681 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
683 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
684 CERT_REQUEST_HEADER
, CERT_REQUEST_TRAILER
, pbBinary
, pcbBinary
, pdwSkip
);
686 if (!ret
&& pdwFlags
)
687 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
691 static LONG
Base64X509HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
692 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
694 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
695 X509_HEADER
, X509_TRAILER
, pbBinary
, pcbBinary
, pdwSkip
);
697 if (!ret
&& pdwFlags
)
698 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
702 static LONG
Base64AnyToBinaryA(LPCSTR pszString
, DWORD cchString
,
703 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
707 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
709 if (ret
== ERROR_INVALID_DATA
)
710 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
715 static LONG
DecodeBinaryToBinaryA(LPCSTR pszString
, DWORD cchString
,
716 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
718 LONG ret
= ERROR_SUCCESS
;
720 if (*pcbBinary
< cchString
)
723 *pcbBinary
= cchString
;
726 ret
= ERROR_INSUFFICIENT_BUFFER
;
727 *pcbBinary
= cchString
;
733 memcpy(pbBinary
, pszString
, cchString
);
734 *pcbBinary
= cchString
;
739 static LONG
DecodeAnyA(LPCSTR pszString
, DWORD cchString
,
740 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
744 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
746 if (ret
== ERROR_INVALID_DATA
)
747 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
749 if (ret
== ERROR_INVALID_DATA
)
750 ret
= DecodeBinaryToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
755 BOOL WINAPI
CryptStringToBinaryA(LPCSTR pszString
,
756 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
757 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
759 StringToBinaryAFunc decoder
;
762 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString
),
763 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
767 SetLastError(ERROR_INVALID_PARAMETER
);
770 /* Only the bottom byte contains valid types */
771 if (dwFlags
& 0xfffffff0)
773 SetLastError(ERROR_INVALID_DATA
);
778 case CRYPT_STRING_BASE64_ANY
:
779 decoder
= Base64AnyToBinaryA
;
781 case CRYPT_STRING_BASE64
:
782 decoder
= Base64ToBinaryA
;
784 case CRYPT_STRING_BASE64HEADER
:
785 decoder
= Base64HeaderToBinaryA
;
787 case CRYPT_STRING_BASE64REQUESTHEADER
:
788 decoder
= Base64RequestHeaderToBinaryA
;
790 case CRYPT_STRING_BASE64X509CRLHEADER
:
791 decoder
= Base64X509HeaderToBinaryA
;
793 case CRYPT_STRING_BINARY
:
794 decoder
= DecodeBinaryToBinaryA
;
796 case CRYPT_STRING_ANY
:
797 decoder
= DecodeAnyA
;
799 case CRYPT_STRING_HEX
:
800 case CRYPT_STRING_HEXASCII
:
801 case CRYPT_STRING_HEXADDR
:
802 case CRYPT_STRING_HEXASCIIADDR
:
803 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
806 SetLastError(ERROR_INVALID_PARAMETER
);
810 cchString
= strlen(pszString
);
811 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
814 return (ret
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
817 static LONG
decodeBase64BlockW(const WCHAR
*in_buf
, int in_len
,
818 const WCHAR
**nextBlock
, PBYTE out_buf
, DWORD
*out_len
)
821 const WCHAR
*d
= in_buf
;
822 int ip0
, ip1
, ip2
, ip3
;
825 return ERROR_INVALID_DATA
;
830 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
831 return ERROR_INVALID_DATA
;
832 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
833 return ERROR_INVALID_DATA
;
836 out_buf
[i
] = (ip0
<< 2) | (ip1
>> 4);
839 else if (d
[3] == '=')
841 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
842 return ERROR_INVALID_DATA
;
843 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
844 return ERROR_INVALID_DATA
;
845 if ((ip2
= decodeBase64Byte(d
[2])) > 63)
846 return ERROR_INVALID_DATA
;
850 out_buf
[i
+ 0] = (ip0
<< 2) | (ip1
>> 4);
851 out_buf
[i
+ 1] = (ip1
<< 4) | (ip2
>> 2);
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
;
863 if ((ip3
= decodeBase64Byte(d
[3])) > 63)
864 return ERROR_INVALID_DATA
;
868 out_buf
[i
+ 0] = (ip0
<< 2) | (ip1
>> 4);
869 out_buf
[i
+ 1] = (ip1
<< 4) | (ip2
>> 2);
870 out_buf
[i
+ 2] = (ip2
<< 6) | ip3
;
874 if (len
>= 6 && d
[4] == '\r' && d
[5] == '\n')
876 else if (len
>= 5 && d
[4] == '\n')
878 else if (len
>= 4 && d
[4])
883 return ERROR_SUCCESS
;
886 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
889 typedef LONG (*StringToBinaryWFunc
)(LPCWSTR pszString
, DWORD cchString
,
890 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
892 static LONG
Base64ToBinaryW(LPCWSTR pszString
, DWORD cchString
,
893 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
895 LONG ret
= ERROR_SUCCESS
;
896 const WCHAR
*nextBlock
;
899 nextBlock
= pszString
;
900 while (nextBlock
&& !ret
)
904 ret
= decodeBase64BlockW(nextBlock
, cchString
- (nextBlock
- pszString
),
905 &nextBlock
, pbBinary
? pbBinary
+ outLen
: NULL
, &len
);
908 if (cchString
- (nextBlock
- pszString
) <= 0)
917 *pdwFlags
= CRYPT_STRING_BASE64
;
919 else if (ret
== ERROR_INSUFFICIENT_BUFFER
)
927 static LONG
Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString
,
928 DWORD cchString
, LPCWSTR header
, LPCWSTR trailer
, BYTE
*pbBinary
,
929 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
934 if (cchString
> strlenW(header
) + strlenW(trailer
)
935 && (ptr
= strstrW(pszString
, header
)) != NULL
)
937 LPCWSTR trailerSpot
= pszString
+ cchString
- strlenW(trailer
);
939 if (pszString
[cchString
- 1] == '\n')
944 if (pszString
[cchString
- 1] == '\r')
949 if (!strncmpW(trailerSpot
, trailer
, strlenW(trailer
)))
952 *pdwSkip
= ptr
- pszString
;
953 ptr
+= strlenW(header
);
954 if (*ptr
== '\r') ptr
++;
955 if (*ptr
== '\n') ptr
++;
956 cchString
-= ptr
- pszString
+ strlenW(trailer
);
957 ret
= Base64ToBinaryW(ptr
, cchString
, pbBinary
, pcbBinary
, NULL
,
961 ret
= ERROR_INVALID_DATA
;
964 ret
= ERROR_INVALID_DATA
;
968 static LONG
Base64HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
969 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
971 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
972 CERT_HEADER_W
, CERT_TRAILER_W
, pbBinary
, pcbBinary
, pdwSkip
);
974 if (!ret
&& pdwFlags
)
975 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
979 static LONG
Base64RequestHeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
980 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
982 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
983 CERT_REQUEST_HEADER_W
, CERT_REQUEST_TRAILER_W
, pbBinary
, pcbBinary
,
986 if (!ret
&& pdwFlags
)
987 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
991 static LONG
Base64X509HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
992 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
994 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
995 X509_HEADER_W
, X509_TRAILER_W
, pbBinary
, pcbBinary
, pdwSkip
);
997 if (!ret
&& pdwFlags
)
998 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
1002 static LONG
Base64AnyToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1003 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1007 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1009 if (ret
== ERROR_INVALID_DATA
)
1010 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1015 static LONG
DecodeBinaryToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1016 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1018 LONG ret
= ERROR_SUCCESS
;
1020 if (*pcbBinary
< cchString
)
1023 *pcbBinary
= cchString
;
1026 ret
= ERROR_INSUFFICIENT_BUFFER
;
1027 *pcbBinary
= cchString
;
1033 memcpy(pbBinary
, pszString
, cchString
* sizeof(WCHAR
));
1034 *pcbBinary
= cchString
* sizeof(WCHAR
);
1039 static LONG
DecodeAnyW(LPCWSTR pszString
, DWORD cchString
,
1040 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1044 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1046 if (ret
== ERROR_INVALID_DATA
)
1047 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1049 if (ret
== ERROR_INVALID_DATA
)
1050 ret
= DecodeBinaryToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1055 BOOL WINAPI
CryptStringToBinaryW(LPCWSTR pszString
,
1056 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
1057 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1059 StringToBinaryWFunc decoder
;
1062 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString
),
1063 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1067 SetLastError(ERROR_INVALID_PARAMETER
);
1070 /* Only the bottom byte contains valid types */
1071 if (dwFlags
& 0xfffffff0)
1073 SetLastError(ERROR_INVALID_DATA
);
1078 case CRYPT_STRING_BASE64_ANY
:
1079 decoder
= Base64AnyToBinaryW
;
1081 case CRYPT_STRING_BASE64
:
1082 decoder
= Base64ToBinaryW
;
1084 case CRYPT_STRING_BASE64HEADER
:
1085 decoder
= Base64HeaderToBinaryW
;
1087 case CRYPT_STRING_BASE64REQUESTHEADER
:
1088 decoder
= Base64RequestHeaderToBinaryW
;
1090 case CRYPT_STRING_BASE64X509CRLHEADER
:
1091 decoder
= Base64X509HeaderToBinaryW
;
1093 case CRYPT_STRING_BINARY
:
1094 decoder
= DecodeBinaryToBinaryW
;
1096 case CRYPT_STRING_ANY
:
1097 decoder
= DecodeAnyW
;
1099 case CRYPT_STRING_HEX
:
1100 case CRYPT_STRING_HEXASCII
:
1101 case CRYPT_STRING_HEXADDR
:
1102 case CRYPT_STRING_HEXASCIIADDR
:
1103 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
1106 SetLastError(ERROR_INVALID_PARAMETER
);
1110 cchString
= strlenW(pszString
);
1111 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1114 return (ret
== ERROR_SUCCESS
) ? TRUE
: FALSE
;