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
;