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"
29 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
31 #define CERT_HEADER "-----BEGIN CERTIFICATE-----"
32 #define CERT_HEADER_START "-----BEGIN "
33 #define CERT_DELIMITER "-----"
34 #define CERT_TRAILER "-----END CERTIFICATE-----"
35 #define CERT_TRAILER_START "-----END "
36 #define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
37 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
38 #define X509_HEADER "-----BEGIN X509 CRL-----"
39 #define X509_TRAILER "-----END X509 CRL-----"
41 static const WCHAR CERT_HEADER_W
[] = L
"-----BEGIN CERTIFICATE-----";
42 static const WCHAR CERT_HEADER_START_W
[] = L
"-----BEGIN ";
43 static const WCHAR CERT_DELIMITER_W
[] = L
"-----";
44 static const WCHAR CERT_TRAILER_W
[] = L
"-----END CERTIFICATE-----";
45 static const WCHAR CERT_TRAILER_START_W
[] = L
"-----END ";
46 static const WCHAR CERT_REQUEST_HEADER_W
[] = L
"-----BEGIN NEW CERTIFICATE REQUEST-----";
47 static const WCHAR CERT_REQUEST_TRAILER_W
[] = L
"-----END NEW CERTIFICATE REQUEST-----";
48 static const WCHAR X509_HEADER_W
[] = L
"-----BEGIN X509 CRL-----";
49 static const WCHAR X509_TRAILER_W
[] = L
"-----END X509 CRL-----";
51 static const char b64
[] =
52 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
54 typedef BOOL (*BinaryToStringAFunc
)(const BYTE
*pbBinary
,
55 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
);
56 typedef BOOL (*BinaryToStringWFunc
)(const BYTE
*pbBinary
,
57 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
);
59 static BOOL
EncodeBinaryToBinaryA(const BYTE
*pbBinary
,
60 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
66 if (*pcchString
< cbBinary
)
68 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
72 memcpy(pszString
, pbBinary
, cbBinary
);
75 *pcchString
= cbBinary
;
80 static DWORD
stradd(LPSTR ptr
, LPCSTR end
, LPCSTR s
, DWORD slen
)
88 static DWORD
encodeBase64A(const BYTE
*in_buf
, int in_len
, LPCSTR sep
,
89 char* out_buf
, DWORD
*out_len
)
92 const BYTE
*d
= in_buf
;
93 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 *out_len
= bytes
+ pad_bytes
;
102 *out_len
+= (*out_len
/ 64 + (*out_len
% 64 ? 1 : 0)) * strlen(sep
) + 1;
106 /* Three bytes of input give 4 chars of output */
110 end
= ptr
+ *out_len
;
112 while (div
> 0 && ptr
< end
)
114 if (i
&& i
% 64 == 0)
115 ptr
+= stradd(ptr
, end
, sep
, strlen(sep
));
116 /* first char is the first 6 bits of the first byte*/
117 chunk
[0] = b64
[ ( d
[0] >> 2) & 0x3f ];
118 /* second char is the last 2 bits of the first byte and the first 4
119 * bits of the second byte */
120 chunk
[1] = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
121 /* third char is the last 4 bits of the second byte and the first 2
122 * bits of the third byte */
123 chunk
[2] = b64
[ ((d
[1] << 2) & 0x3c) | (d
[2] >> 6 & 0x03)];
124 /* fourth char is the remaining 6 bits of the third byte */
125 chunk
[3] = b64
[ d
[2] & 0x3f];
126 ptr
+= stradd(ptr
, end
, chunk
, 4);
135 /* first char is the first 6 bits of the first byte*/
136 chunk
[0] = b64
[ ( d
[0] >> 2) & 0x3f ];
137 /* second char is the last 2 bits of the first byte and the first 4
138 * bits of the second byte */
139 chunk
[1] = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
140 /* third char is the last 4 bits of the second byte padded with
142 chunk
[2] = b64
[ ((d
[1] << 2) & 0x3c) ];
143 /* fourth char is a = to indicate one byte of padding */
145 ptr
+= stradd(ptr
, end
, chunk
, 4);
148 /* first char is the first 6 bits of the first byte*/
149 chunk
[0] = b64
[ ( d
[0] >> 2) & 0x3f ];
150 /* second char is the last 2 bits of the first byte padded with
152 chunk
[1] = b64
[ ((d
[0] << 4) & 0x30)];
153 /* third char is = to indicate padding */
155 /* fourth char is = to indicate padding */
157 ptr
+= stradd(ptr
, end
, chunk
, 4);
160 ptr
+= stradd(ptr
, end
, sep
, strlen(sep
));
162 return ptr
- out_buf
;
165 static BOOL
BinaryToBase64A(const BYTE
*pbBinary
,
166 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
168 static const char crlf
[] = "\r\n", lf
[] = "\n";
170 LPCSTR header
= NULL
, trailer
= NULL
, sep
;
173 if (dwFlags
& CRYPT_STRING_NOCR
)
175 else if (dwFlags
& CRYPT_STRING_NOCRLF
)
179 switch (dwFlags
& 0x0fffffff)
181 case CRYPT_STRING_BASE64
:
182 /* no header or footer */
184 case CRYPT_STRING_BASE64HEADER
:
185 header
= CERT_HEADER
;
186 trailer
= CERT_TRAILER
;
188 case CRYPT_STRING_BASE64REQUESTHEADER
:
189 header
= CERT_REQUEST_HEADER
;
190 trailer
= CERT_REQUEST_TRAILER
;
192 case CRYPT_STRING_BASE64X509CRLHEADER
:
193 header
= X509_HEADER
;
194 trailer
= X509_TRAILER
;
199 encodeBase64A(pbBinary
, cbBinary
, sep
, NULL
, &charsNeeded
);
201 charsNeeded
+= strlen(header
) + strlen(sep
);
203 charsNeeded
+= strlen(trailer
) + strlen(sep
);
207 LPSTR ptr
= pszString
;
208 DWORD size
= *pcchString
;
209 LPSTR end
= ptr
+ size
;
213 ptr
+= stradd(ptr
, end
, header
, strlen(header
));
214 ptr
+= stradd(ptr
, end
, sep
, strlen(sep
));
217 ptr
+= encodeBase64A(pbBinary
, cbBinary
, sep
, ptr
, &size
);
220 ptr
+= stradd(ptr
, end
, trailer
, strlen(trailer
));
221 ptr
+= stradd(ptr
, end
, sep
, strlen(sep
));
227 if (charsNeeded
<= *pcchString
)
229 *pcchString
= charsNeeded
- 1;
233 *pcchString
= charsNeeded
;
234 SetLastError(ERROR_MORE_DATA
);
239 *pcchString
= charsNeeded
;
244 BOOL WINAPI
CryptBinaryToStringA(const BYTE
*pbBinary
,
245 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
247 BinaryToStringAFunc encoder
= NULL
;
249 TRACE("(%p, %ld, %08lx, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
254 SetLastError(ERROR_INVALID_PARAMETER
);
259 SetLastError(ERROR_INVALID_PARAMETER
);
263 switch (dwFlags
& 0x0fffffff)
265 case CRYPT_STRING_BINARY
:
266 encoder
= EncodeBinaryToBinaryA
;
268 case CRYPT_STRING_BASE64
:
269 case CRYPT_STRING_BASE64HEADER
:
270 case CRYPT_STRING_BASE64REQUESTHEADER
:
271 case CRYPT_STRING_BASE64X509CRLHEADER
:
272 encoder
= BinaryToBase64A
;
274 case CRYPT_STRING_HEX
:
275 case CRYPT_STRING_HEXASCII
:
276 case CRYPT_STRING_HEXADDR
:
277 case CRYPT_STRING_HEXASCIIADDR
:
278 FIXME("Unimplemented type %ld\n", dwFlags
& 0x0fffffff);
281 SetLastError(ERROR_INVALID_PARAMETER
);
284 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
287 static BOOL
EncodeBinaryToBinaryW(const BYTE
*in_buf
, DWORD in_len
, DWORD flags
, WCHAR
*out_buf
, DWORD
*out_len
)
293 if (*out_len
< in_len
)
295 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
299 memcpy(out_buf
, in_buf
, in_len
);
307 static LONG
encodeBase64W(const BYTE
*in_buf
, int in_len
, LPCWSTR sep
,
308 WCHAR
* out_buf
, DWORD
*out_len
)
311 const BYTE
*d
= in_buf
;
312 int bytes
= (in_len
*8 + 5)/6, pad_bytes
= (bytes
% 4) ? 4 - (bytes
% 4) : 0;
316 TRACE("bytes is %d, pad bytes is %d\n", bytes
, pad_bytes
);
317 needed
= bytes
+ pad_bytes
;
318 needed
+= (needed
/ 64 + (needed
% 64 ? 1 : 0)) * lstrlenW(sep
);
321 if (needed
> *out_len
)
324 return ERROR_INSUFFICIENT_BUFFER
;
329 /* Three bytes of input give 4 chars of output */
336 if (i
&& i
% 64 == 0)
339 ptr
+= lstrlenW(sep
);
341 /* first char is the first 6 bits of the first byte*/
342 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
343 /* second char is the last 2 bits of the first byte and the first 4
344 * bits of the second byte */
345 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
346 /* third char is the last 4 bits of the second byte and the first 2
347 * bits of the third byte */
348 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) | (d
[2] >> 6 & 0x03)];
349 /* fourth char is the remaining 6 bits of the third byte */
350 *ptr
++ = b64
[ d
[2] & 0x3f];
359 /* first char is the first 6 bits of the first byte*/
360 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
361 /* second char is the last 2 bits of the first byte and the first 4
362 * bits of the second byte */
363 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
364 /* third char is the last 4 bits of the second byte padded with
366 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) ];
367 /* fourth char is a = to indicate one byte of padding */
371 /* first char is the first 6 bits of the first byte*/
372 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
373 /* second char is the last 2 bits of the first byte padded with
375 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30)];
376 /* third char is = to indicate padding */
378 /* fourth char is = to indicate padding */
384 return ERROR_SUCCESS
;
387 static BOOL
BinaryToBase64W(const BYTE
*pbBinary
,
388 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
391 LPCWSTR header
= NULL
, trailer
= NULL
, sep
;
394 if (dwFlags
& CRYPT_STRING_NOCR
)
396 else if (dwFlags
& CRYPT_STRING_NOCRLF
)
400 switch (dwFlags
& 0x0fffffff)
402 case CRYPT_STRING_BASE64
:
403 /* no header or footer */
405 case CRYPT_STRING_BASE64HEADER
:
406 header
= CERT_HEADER_W
;
407 trailer
= CERT_TRAILER_W
;
409 case CRYPT_STRING_BASE64REQUESTHEADER
:
410 header
= CERT_REQUEST_HEADER_W
;
411 trailer
= CERT_REQUEST_TRAILER_W
;
413 case CRYPT_STRING_BASE64X509CRLHEADER
:
414 header
= X509_HEADER_W
;
415 trailer
= X509_TRAILER_W
;
420 encodeBase64W(pbBinary
, cbBinary
, sep
, NULL
, &charsNeeded
);
422 charsNeeded
+= lstrlenW(header
) + lstrlenW(sep
);
424 charsNeeded
+= lstrlenW(trailer
) + lstrlenW(sep
);
428 if (charsNeeded
<= *pcchString
)
430 LPWSTR ptr
= pszString
;
431 DWORD size
= charsNeeded
;
435 lstrcpyW(ptr
, header
);
436 ptr
+= lstrlenW(ptr
);
438 ptr
+= lstrlenW(sep
);
440 encodeBase64W(pbBinary
, cbBinary
, sep
, ptr
, &size
);
444 lstrcpyW(ptr
, trailer
);
445 ptr
+= lstrlenW(ptr
);
448 *pcchString
= charsNeeded
- 1;
452 *pcchString
= charsNeeded
;
453 SetLastError(ERROR_MORE_DATA
);
458 *pcchString
= charsNeeded
;
463 static BOOL
BinaryToHexRawW(const BYTE
*bin
, DWORD nbin
, DWORD flags
, LPWSTR str
, DWORD
*nstr
)
465 static const WCHAR hex
[] = L
"0123456789abcdef";
468 if (flags
& CRYPT_STRING_NOCRLF
)
470 else if (flags
& CRYPT_STRING_NOCR
)
475 needed
+= nbin
* 2 + 1;
485 SetLastError(ERROR_MORE_DATA
);
491 *str
++ = hex
[(*bin
>> 4) & 0xf];
492 *str
++ = hex
[*bin
& 0xf];
496 if (flags
& CRYPT_STRING_NOCR
)
498 else if (!(flags
& CRYPT_STRING_NOCRLF
))
509 static BOOL
binary_to_hexW(const BYTE
*bin
, DWORD nbin
, DWORD flags
, LPWSTR str
, DWORD
*nstr
)
511 static const WCHAR hex
[] = L
"0123456789abcdef";
514 needed
= nbin
* 3; /* spaces + terminating \0 */
516 if (flags
& CRYPT_STRING_NOCR
)
518 needed
+= (nbin
+ 7) / 16; /* space every 16 characters */
519 needed
+= 1; /* terminating \n */
521 else if (!(flags
& CRYPT_STRING_NOCRLF
))
523 needed
+= (nbin
+ 7) / 16; /* space every 16 characters */
524 needed
+= nbin
/ 16 + 1; /* LF every 16 characters + terminating \r */
527 needed
+= 1; /* terminating \n */
538 SetLastError(ERROR_MORE_DATA
);
542 for (i
= 0; i
< nbin
; i
++)
544 *str
++ = hex
[(bin
[i
] >> 4) & 0xf];
545 *str
++ = hex
[bin
[i
] & 0xf];
547 if (i
>= nbin
- 1) break;
549 if (i
&& !(flags
& CRYPT_STRING_NOCRLF
))
553 if (flags
& CRYPT_STRING_NOCR
)
562 else if (!((i
+ 1) % 8))
569 if (flags
& CRYPT_STRING_NOCR
)
571 else if (!(flags
& CRYPT_STRING_NOCRLF
))
582 BOOL WINAPI
CryptBinaryToStringW(const BYTE
*pbBinary
,
583 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
585 BinaryToStringWFunc encoder
= NULL
;
587 TRACE("(%p, %ld, %08lx, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
592 SetLastError(ERROR_INVALID_PARAMETER
);
597 SetLastError(ERROR_INVALID_PARAMETER
);
601 switch (dwFlags
& 0x0fffffff)
603 case CRYPT_STRING_BINARY
:
604 encoder
= EncodeBinaryToBinaryW
;
606 case CRYPT_STRING_BASE64
:
607 case CRYPT_STRING_BASE64HEADER
:
608 case CRYPT_STRING_BASE64REQUESTHEADER
:
609 case CRYPT_STRING_BASE64X509CRLHEADER
:
610 encoder
= BinaryToBase64W
;
612 case CRYPT_STRING_HEXRAW
:
613 encoder
= BinaryToHexRawW
;
615 case CRYPT_STRING_HEX
:
616 encoder
= binary_to_hexW
;
618 case CRYPT_STRING_HEXASCII
:
619 case CRYPT_STRING_HEXADDR
:
620 case CRYPT_STRING_HEXASCIIADDR
:
621 FIXME("Unimplemented type %ld\n", dwFlags
& 0x0fffffff);
624 SetLastError(ERROR_INVALID_PARAMETER
);
627 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
630 #define BASE64_DECODE_PADDING 0x100
631 #define BASE64_DECODE_WHITESPACE 0x200
632 #define BASE64_DECODE_INVALID 0x300
634 static inline int decodeBase64Byte(int c
)
636 int ret
= BASE64_DECODE_INVALID
;
638 if (c
>= 'A' && c
<= 'Z')
640 else if (c
>= 'a' && c
<= 'z')
642 else if (c
>= '0' && c
<= '9')
649 ret
= BASE64_DECODE_PADDING
;
650 else if (c
== ' ' || c
== '\t' || c
== '\r' || c
== '\n')
651 ret
= BASE64_DECODE_WHITESPACE
;
655 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
658 typedef LONG (*StringToBinaryAFunc
)(LPCSTR pszString
, DWORD cchString
,
659 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
661 static LONG
Base64ToBinary(const void* pszString
, BOOL wide
, DWORD cchString
,
662 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
664 DWORD cbIn
, cbValid
, cbOut
, hasPadding
;
666 for (cbIn
= cbValid
= cbOut
= hasPadding
= 0; cbIn
< cchString
; ++cbIn
)
668 int c
= wide
? (int)((WCHAR
*)pszString
)[cbIn
] : (int)((char*)pszString
)[cbIn
];
669 int d
= decodeBase64Byte(c
);
670 if (d
== BASE64_DECODE_INVALID
)
672 if (d
== BASE64_DECODE_WHITESPACE
)
675 /* When padding starts, data is not acceptable */
676 if (hasPadding
&& d
!= BASE64_DECODE_PADDING
)
679 /* Padding after a full block (like "VVVV=") is ok and stops decoding */
680 if (d
== BASE64_DECODE_PADDING
&& (cbValid
& 3) == 0)
685 if (d
== BASE64_DECODE_PADDING
)
688 /* When padding reaches a full block, stop decoding */
689 if ((cbValid
& 3) == 0)
694 /* cbOut is incremented in the 4-char block as follows: "1-23" */
695 if ((cbValid
& 3) != 2)
698 /* Fail if the block has bad padding; omitting padding is fine */
699 if ((cbValid
& 3) != 0 && hasPadding
)
701 /* Check available buffer size */
702 if (pbBinary
&& *pcbBinary
&& cbOut
> *pcbBinary
)
704 /* Convert the data; this step depends on the validity checks above! */
705 if (pbBinary
) for (cbIn
= cbValid
= cbOut
= 0; cbIn
< cchString
; ++cbIn
)
707 int c
= wide
? (int)((WCHAR
*)pszString
)[cbIn
] : (int)((char*)pszString
)[cbIn
];
708 int d
= decodeBase64Byte(c
);
709 if (d
== BASE64_DECODE_WHITESPACE
)
711 if (d
== BASE64_DECODE_PADDING
)
713 block
[cbValid
& 3] = d
;
715 switch (cbValid
& 3) {
717 pbBinary
[cbOut
++] = (block
[0] << 2);
720 pbBinary
[cbOut
-1] = (block
[0] << 2) | (block
[1] >> 4);
723 pbBinary
[cbOut
++] = (block
[1] << 4) | (block
[2] >> 2);
726 pbBinary
[cbOut
++] = (block
[2] << 6) | (block
[3] >> 0);
734 *pdwFlags
= CRYPT_STRING_BASE64
;
735 return ERROR_SUCCESS
;
737 return ERROR_INSUFFICIENT_BUFFER
;
740 return ERROR_INVALID_DATA
;
743 static LONG
Base64ToBinaryA(LPCSTR pszString
, DWORD cchString
,
744 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
746 return Base64ToBinary(pszString
, FALSE
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
749 static LONG
Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString
,
750 DWORD cchString
, BYTE
*pbBinary
,
751 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
754 LPCSTR header
= CERT_HEADER_START
;
755 LPCSTR trailer
= CERT_TRAILER_START
;
759 LPCSTR trailerBegins
;
762 if ((strlen(header
) + strlen(trailer
)) > cchString
)
764 return ERROR_INVALID_DATA
;
767 if (!(headerBegins
= strstr(pszString
, header
)))
769 TRACE("Can't find %s in %s.\n", header
, debugstr_an(pszString
, cchString
));
770 return ERROR_INVALID_DATA
;
773 dataBegins
= headerBegins
+ strlen(header
);
774 if (!(dataBegins
= strstr(dataBegins
, CERT_DELIMITER
)))
776 return ERROR_INVALID_DATA
;
778 dataBegins
+= strlen(CERT_DELIMITER
);
779 if (*dataBegins
== '\r') dataBegins
++;
780 if (*dataBegins
== '\n') dataBegins
++;
782 if (!(trailerBegins
= strstr(dataBegins
, trailer
)))
784 return ERROR_INVALID_DATA
;
786 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
787 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
790 *pdwSkip
= headerBegins
- pszString
;
792 dataLength
= trailerBegins
- dataBegins
;
794 ret
= Base64ToBinaryA(dataBegins
, dataLength
, pbBinary
, pcbBinary
, NULL
,
800 static LONG
Base64HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
801 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
803 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
804 pbBinary
, pcbBinary
, pdwSkip
);
806 if (!ret
&& pdwFlags
)
807 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
811 static LONG
Base64RequestHeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
812 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
814 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
815 pbBinary
, pcbBinary
, pdwSkip
);
817 if (!ret
&& pdwFlags
)
818 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
822 static LONG
Base64X509HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
823 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
825 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
826 pbBinary
, pcbBinary
, pdwSkip
);
828 if (!ret
&& pdwFlags
)
829 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
833 static LONG
Base64AnyToBinaryA(LPCSTR pszString
, DWORD cchString
,
834 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
838 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
840 if (ret
== ERROR_INVALID_DATA
)
841 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
846 static LONG
DecodeBinaryToBinaryA(LPCSTR pszString
, DWORD cchString
,
847 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
849 LONG ret
= ERROR_SUCCESS
;
851 if (*pcbBinary
< cchString
)
854 *pcbBinary
= cchString
;
857 ret
= ERROR_INSUFFICIENT_BUFFER
;
858 *pcbBinary
= cchString
;
864 memcpy(pbBinary
, pszString
, cchString
);
865 *pcbBinary
= cchString
;
870 static LONG
DecodeAnyA(LPCSTR pszString
, DWORD cchString
,
871 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
875 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
877 if (ret
== ERROR_INVALID_DATA
)
878 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
880 if (ret
== ERROR_INVALID_DATA
)
881 ret
= DecodeBinaryToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
886 BOOL WINAPI
CryptStringToBinaryA(LPCSTR pszString
,
887 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
888 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
890 StringToBinaryAFunc decoder
;
893 TRACE("(%s, %ld, %08lx, %p, %p, %p, %p)\n", debugstr_an(pszString
, cchString
? cchString
: -1),
894 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
898 SetLastError(ERROR_INVALID_PARAMETER
);
901 /* Only the bottom byte contains valid types */
902 if (dwFlags
& 0xfffffff0)
904 SetLastError(ERROR_INVALID_DATA
);
909 case CRYPT_STRING_BASE64_ANY
:
910 decoder
= Base64AnyToBinaryA
;
912 case CRYPT_STRING_BASE64
:
913 decoder
= Base64ToBinaryA
;
915 case CRYPT_STRING_BASE64HEADER
:
916 decoder
= Base64HeaderToBinaryA
;
918 case CRYPT_STRING_BASE64REQUESTHEADER
:
919 decoder
= Base64RequestHeaderToBinaryA
;
921 case CRYPT_STRING_BASE64X509CRLHEADER
:
922 decoder
= Base64X509HeaderToBinaryA
;
924 case CRYPT_STRING_BINARY
:
925 decoder
= DecodeBinaryToBinaryA
;
927 case CRYPT_STRING_ANY
:
928 decoder
= DecodeAnyA
;
930 case CRYPT_STRING_HEX
:
931 case CRYPT_STRING_HEXASCII
:
932 case CRYPT_STRING_HEXADDR
:
933 case CRYPT_STRING_HEXASCIIADDR
:
934 FIXME("Unimplemented type %ld\n", dwFlags
& 0x7fffffff);
937 SetLastError(ERROR_INVALID_PARAMETER
);
941 cchString
= strlen(pszString
);
942 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
945 return ret
== ERROR_SUCCESS
;
948 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
951 typedef LONG (*StringToBinaryWFunc
)(LPCWSTR pszString
, DWORD cchString
,
952 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
954 static LONG
Base64ToBinaryW(LPCWSTR pszString
, DWORD cchString
,
955 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
957 return Base64ToBinary(pszString
, TRUE
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
960 static LONG
Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString
,
961 DWORD cchString
, BYTE
*pbBinary
,
962 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
965 LPCWSTR header
= CERT_HEADER_START_W
;
966 LPCWSTR trailer
= CERT_TRAILER_START_W
;
968 LPCWSTR headerBegins
;
970 LPCWSTR trailerBegins
;
973 if ((lstrlenW(header
) + lstrlenW(trailer
)) > cchString
)
975 return ERROR_INVALID_DATA
;
978 if (!(headerBegins
= wcsstr(pszString
, header
)))
980 TRACE("Can't find %s in %s.\n", debugstr_w(header
), debugstr_wn(pszString
, cchString
));
981 return ERROR_INVALID_DATA
;
984 dataBegins
= headerBegins
+ lstrlenW(header
);
985 if (!(dataBegins
= wcsstr(dataBegins
, CERT_DELIMITER_W
)))
987 return ERROR_INVALID_DATA
;
989 dataBegins
+= lstrlenW(CERT_DELIMITER_W
);
990 if (*dataBegins
== '\r') dataBegins
++;
991 if (*dataBegins
== '\n') dataBegins
++;
993 if (!(trailerBegins
= wcsstr(dataBegins
, trailer
)))
995 return ERROR_INVALID_DATA
;
997 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
998 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
1001 *pdwSkip
= headerBegins
- pszString
;
1003 dataLength
= trailerBegins
- dataBegins
;
1005 ret
= Base64ToBinaryW(dataBegins
, dataLength
, pbBinary
, pcbBinary
, NULL
,
1011 static LONG
Base64HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1012 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1014 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
1015 pbBinary
, pcbBinary
, pdwSkip
);
1017 if (!ret
&& pdwFlags
)
1018 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
1022 static LONG
Base64RequestHeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1023 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1025 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
1026 pbBinary
, pcbBinary
, pdwSkip
);
1028 if (!ret
&& pdwFlags
)
1029 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
1033 static LONG
Base64X509HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1034 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1036 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
1037 pbBinary
, pcbBinary
, pdwSkip
);
1039 if (!ret
&& pdwFlags
)
1040 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
1044 static LONG
Base64AnyToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1045 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1049 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1051 if (ret
== ERROR_INVALID_DATA
)
1052 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1057 static LONG
DecodeBinaryToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1058 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1060 LONG ret
= ERROR_SUCCESS
;
1062 if (*pcbBinary
< cchString
)
1065 *pcbBinary
= cchString
;
1068 ret
= ERROR_INSUFFICIENT_BUFFER
;
1069 *pcbBinary
= cchString
;
1075 memcpy(pbBinary
, pszString
, cchString
* sizeof(WCHAR
));
1076 *pcbBinary
= cchString
* sizeof(WCHAR
);
1081 static LONG
DecodeAnyW(LPCWSTR pszString
, DWORD cchString
,
1082 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1086 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1088 if (ret
== ERROR_INVALID_DATA
)
1089 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1091 if (ret
== ERROR_INVALID_DATA
)
1092 ret
= DecodeBinaryToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1097 BOOL WINAPI
CryptStringToBinaryW(LPCWSTR pszString
,
1098 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
1099 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1101 StringToBinaryWFunc decoder
;
1104 TRACE("(%s, %ld, %08lx, %p, %p, %p, %p)\n", debugstr_wn(pszString
, cchString
? cchString
: -1),
1105 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1109 SetLastError(ERROR_INVALID_PARAMETER
);
1112 /* Only the bottom byte contains valid types */
1113 if (dwFlags
& 0xfffffff0)
1115 SetLastError(ERROR_INVALID_DATA
);
1120 case CRYPT_STRING_BASE64_ANY
:
1121 decoder
= Base64AnyToBinaryW
;
1123 case CRYPT_STRING_BASE64
:
1124 decoder
= Base64ToBinaryW
;
1126 case CRYPT_STRING_BASE64HEADER
:
1127 decoder
= Base64HeaderToBinaryW
;
1129 case CRYPT_STRING_BASE64REQUESTHEADER
:
1130 decoder
= Base64RequestHeaderToBinaryW
;
1132 case CRYPT_STRING_BASE64X509CRLHEADER
:
1133 decoder
= Base64X509HeaderToBinaryW
;
1135 case CRYPT_STRING_BINARY
:
1136 decoder
= DecodeBinaryToBinaryW
;
1138 case CRYPT_STRING_ANY
:
1139 decoder
= DecodeAnyW
;
1141 case CRYPT_STRING_HEX
:
1142 case CRYPT_STRING_HEXASCII
:
1143 case CRYPT_STRING_HEXADDR
:
1144 case CRYPT_STRING_HEXASCIIADDR
:
1145 FIXME("Unimplemented type %ld\n", dwFlags
& 0x7fffffff);
1148 SetLastError(ERROR_INVALID_PARAMETER
);
1152 cchString
= lstrlenW(pszString
);
1153 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1156 return ret
== ERROR_SUCCESS
;