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 static BOOL
BinaryToHexRawA(const BYTE
*bin
, DWORD nbin
, DWORD flags
, char *str
, DWORD
*nstr
)
246 static const char hex
[] = "0123456789abcdef";
249 if (flags
& CRYPT_STRING_NOCRLF
)
251 else if (flags
& CRYPT_STRING_NOCR
)
256 needed
+= nbin
* 2 + 1;
264 if (needed
> *nstr
&& *nstr
< 3)
266 SetLastError(ERROR_MORE_DATA
);
270 nbin
= min(nbin
, (*nstr
- 1) / 2);
274 *str
++ = hex
[(*bin
>> 4) & 0xf];
275 *str
++ = hex
[*bin
& 0xf];
282 SetLastError(ERROR_MORE_DATA
);
286 if (flags
& CRYPT_STRING_NOCR
)
290 else if (!(flags
& CRYPT_STRING_NOCRLF
))
301 BOOL WINAPI
CryptBinaryToStringA(const BYTE
*pbBinary
,
302 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
304 BinaryToStringAFunc encoder
= NULL
;
306 TRACE("(%p, %ld, %08lx, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
311 SetLastError(ERROR_INVALID_PARAMETER
);
316 SetLastError(ERROR_INVALID_PARAMETER
);
320 switch (dwFlags
& 0x0fffffff)
322 case CRYPT_STRING_BINARY
:
323 encoder
= EncodeBinaryToBinaryA
;
325 case CRYPT_STRING_BASE64
:
326 case CRYPT_STRING_BASE64HEADER
:
327 case CRYPT_STRING_BASE64REQUESTHEADER
:
328 case CRYPT_STRING_BASE64X509CRLHEADER
:
329 encoder
= BinaryToBase64A
;
331 case CRYPT_STRING_HEXRAW
:
332 encoder
= BinaryToHexRawA
;
334 case CRYPT_STRING_HEX
:
335 case CRYPT_STRING_HEXASCII
:
336 case CRYPT_STRING_HEXADDR
:
337 case CRYPT_STRING_HEXASCIIADDR
:
338 FIXME("Unimplemented type %ld\n", dwFlags
& 0x0fffffff);
341 SetLastError(ERROR_INVALID_PARAMETER
);
344 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
347 static BOOL
EncodeBinaryToBinaryW(const BYTE
*in_buf
, DWORD in_len
, DWORD flags
, WCHAR
*out_buf
, DWORD
*out_len
)
353 if (*out_len
< in_len
)
355 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
359 memcpy(out_buf
, in_buf
, in_len
);
367 static LONG
encodeBase64W(const BYTE
*in_buf
, int in_len
, LPCWSTR sep
,
368 WCHAR
* out_buf
, DWORD
*out_len
)
371 const BYTE
*d
= in_buf
;
372 int bytes
= (in_len
*8 + 5)/6, pad_bytes
= (bytes
% 4) ? 4 - (bytes
% 4) : 0;
376 TRACE("bytes is %d, pad bytes is %d\n", bytes
, pad_bytes
);
377 needed
= bytes
+ pad_bytes
;
378 needed
+= (needed
/ 64 + (needed
% 64 ? 1 : 0)) * lstrlenW(sep
);
381 if (needed
> *out_len
)
384 return ERROR_INSUFFICIENT_BUFFER
;
389 /* Three bytes of input give 4 chars of output */
396 if (i
&& i
% 64 == 0)
399 ptr
+= lstrlenW(sep
);
401 /* first char is the first 6 bits of the first byte*/
402 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
403 /* second char is the last 2 bits of the first byte and the first 4
404 * bits of the second byte */
405 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
406 /* third char is the last 4 bits of the second byte and the first 2
407 * bits of the third byte */
408 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) | (d
[2] >> 6 & 0x03)];
409 /* fourth char is the remaining 6 bits of the third byte */
410 *ptr
++ = b64
[ d
[2] & 0x3f];
419 /* first char is the first 6 bits of the first byte*/
420 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
421 /* second char is the last 2 bits of the first byte and the first 4
422 * bits of the second byte */
423 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
424 /* third char is the last 4 bits of the second byte padded with
426 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) ];
427 /* fourth char is a = to indicate one byte of padding */
431 /* first char is the first 6 bits of the first byte*/
432 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
433 /* second char is the last 2 bits of the first byte padded with
435 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30)];
436 /* third char is = to indicate padding */
438 /* fourth char is = to indicate padding */
444 return ERROR_SUCCESS
;
447 static BOOL
BinaryToBase64W(const BYTE
*pbBinary
,
448 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
451 LPCWSTR header
= NULL
, trailer
= NULL
, sep
;
454 if (dwFlags
& CRYPT_STRING_NOCR
)
456 else if (dwFlags
& CRYPT_STRING_NOCRLF
)
460 switch (dwFlags
& 0x0fffffff)
462 case CRYPT_STRING_BASE64
:
463 /* no header or footer */
465 case CRYPT_STRING_BASE64HEADER
:
466 header
= CERT_HEADER_W
;
467 trailer
= CERT_TRAILER_W
;
469 case CRYPT_STRING_BASE64REQUESTHEADER
:
470 header
= CERT_REQUEST_HEADER_W
;
471 trailer
= CERT_REQUEST_TRAILER_W
;
473 case CRYPT_STRING_BASE64X509CRLHEADER
:
474 header
= X509_HEADER_W
;
475 trailer
= X509_TRAILER_W
;
480 encodeBase64W(pbBinary
, cbBinary
, sep
, NULL
, &charsNeeded
);
482 charsNeeded
+= lstrlenW(header
) + lstrlenW(sep
);
484 charsNeeded
+= lstrlenW(trailer
) + lstrlenW(sep
);
488 if (charsNeeded
<= *pcchString
)
490 LPWSTR ptr
= pszString
;
491 DWORD size
= charsNeeded
;
495 lstrcpyW(ptr
, header
);
496 ptr
+= lstrlenW(ptr
);
498 ptr
+= lstrlenW(sep
);
500 encodeBase64W(pbBinary
, cbBinary
, sep
, ptr
, &size
);
504 lstrcpyW(ptr
, trailer
);
505 ptr
+= lstrlenW(ptr
);
508 *pcchString
= charsNeeded
- 1;
512 *pcchString
= charsNeeded
;
513 SetLastError(ERROR_MORE_DATA
);
518 *pcchString
= charsNeeded
;
523 static BOOL
BinaryToHexRawW(const BYTE
*bin
, DWORD nbin
, DWORD flags
, LPWSTR str
, DWORD
*nstr
)
525 static const WCHAR hex
[] = L
"0123456789abcdef";
528 if (flags
& CRYPT_STRING_NOCRLF
)
530 else if (flags
& CRYPT_STRING_NOCR
)
535 needed
+= nbin
* 2 + 1;
545 SetLastError(ERROR_MORE_DATA
);
551 *str
++ = hex
[(*bin
>> 4) & 0xf];
552 *str
++ = hex
[*bin
& 0xf];
556 if (flags
& CRYPT_STRING_NOCR
)
558 else if (!(flags
& CRYPT_STRING_NOCRLF
))
569 static BOOL
binary_to_hexW(const BYTE
*bin
, DWORD nbin
, DWORD flags
, LPWSTR str
, DWORD
*nstr
)
571 static const WCHAR hex
[] = L
"0123456789abcdef";
574 needed
= nbin
* 3; /* spaces + terminating \0 */
576 if (flags
& CRYPT_STRING_NOCR
)
578 needed
+= (nbin
+ 7) / 16; /* space every 16 characters */
579 needed
+= 1; /* terminating \n */
581 else if (!(flags
& CRYPT_STRING_NOCRLF
))
583 needed
+= (nbin
+ 7) / 16; /* space every 16 characters */
584 needed
+= nbin
/ 16 + 1; /* LF every 16 characters + terminating \r */
587 needed
+= 1; /* terminating \n */
598 SetLastError(ERROR_MORE_DATA
);
602 for (i
= 0; i
< nbin
; i
++)
604 *str
++ = hex
[(bin
[i
] >> 4) & 0xf];
605 *str
++ = hex
[bin
[i
] & 0xf];
607 if (i
>= nbin
- 1) break;
609 if (i
&& !(flags
& CRYPT_STRING_NOCRLF
))
613 if (flags
& CRYPT_STRING_NOCR
)
622 else if (!((i
+ 1) % 8))
629 if (flags
& CRYPT_STRING_NOCR
)
631 else if (!(flags
& CRYPT_STRING_NOCRLF
))
642 BOOL WINAPI
CryptBinaryToStringW(const BYTE
*pbBinary
,
643 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
645 BinaryToStringWFunc encoder
= NULL
;
647 TRACE("(%p, %ld, %08lx, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
652 SetLastError(ERROR_INVALID_PARAMETER
);
657 SetLastError(ERROR_INVALID_PARAMETER
);
661 switch (dwFlags
& 0x0fffffff)
663 case CRYPT_STRING_BINARY
:
664 encoder
= EncodeBinaryToBinaryW
;
666 case CRYPT_STRING_BASE64
:
667 case CRYPT_STRING_BASE64HEADER
:
668 case CRYPT_STRING_BASE64REQUESTHEADER
:
669 case CRYPT_STRING_BASE64X509CRLHEADER
:
670 encoder
= BinaryToBase64W
;
672 case CRYPT_STRING_HEXRAW
:
673 encoder
= BinaryToHexRawW
;
675 case CRYPT_STRING_HEX
:
676 encoder
= binary_to_hexW
;
678 case CRYPT_STRING_HEXASCII
:
679 case CRYPT_STRING_HEXADDR
:
680 case CRYPT_STRING_HEXASCIIADDR
:
681 FIXME("Unimplemented type %ld\n", dwFlags
& 0x0fffffff);
684 SetLastError(ERROR_INVALID_PARAMETER
);
687 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
690 #define BASE64_DECODE_PADDING 0x100
691 #define BASE64_DECODE_WHITESPACE 0x200
692 #define BASE64_DECODE_INVALID 0x300
694 static inline int decodeBase64Byte(int c
)
696 int ret
= BASE64_DECODE_INVALID
;
698 if (c
>= 'A' && c
<= 'Z')
700 else if (c
>= 'a' && c
<= 'z')
702 else if (c
>= '0' && c
<= '9')
709 ret
= BASE64_DECODE_PADDING
;
710 else if (c
== ' ' || c
== '\t' || c
== '\r' || c
== '\n')
711 ret
= BASE64_DECODE_WHITESPACE
;
715 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
718 typedef LONG (*StringToBinaryAFunc
)(LPCSTR pszString
, DWORD cchString
,
719 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
721 static LONG
Base64ToBinary(const void* pszString
, BOOL wide
, DWORD cchString
,
722 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
724 DWORD cbIn
, cbValid
, cbOut
, hasPadding
;
726 for (cbIn
= cbValid
= cbOut
= hasPadding
= 0; cbIn
< cchString
; ++cbIn
)
728 int c
= wide
? (int)((WCHAR
*)pszString
)[cbIn
] : (int)((char*)pszString
)[cbIn
];
729 int d
= decodeBase64Byte(c
);
730 if (d
== BASE64_DECODE_INVALID
)
732 if (d
== BASE64_DECODE_WHITESPACE
)
735 /* When padding starts, data is not acceptable */
736 if (hasPadding
&& d
!= BASE64_DECODE_PADDING
)
739 /* Padding after a full block (like "VVVV=") is ok and stops decoding */
740 if (d
== BASE64_DECODE_PADDING
&& (cbValid
& 3) == 0)
745 if (d
== BASE64_DECODE_PADDING
)
748 /* When padding reaches a full block, stop decoding */
749 if ((cbValid
& 3) == 0)
754 /* cbOut is incremented in the 4-char block as follows: "1-23" */
755 if ((cbValid
& 3) != 2)
758 /* Fail if the block has bad padding; omitting padding is fine */
759 if ((cbValid
& 3) != 0 && hasPadding
)
761 /* Check available buffer size */
762 if (pbBinary
&& *pcbBinary
&& cbOut
> *pcbBinary
)
764 /* Convert the data; this step depends on the validity checks above! */
765 if (pbBinary
) for (cbIn
= cbValid
= cbOut
= 0; cbIn
< cchString
; ++cbIn
)
767 int c
= wide
? (int)((WCHAR
*)pszString
)[cbIn
] : (int)((char*)pszString
)[cbIn
];
768 int d
= decodeBase64Byte(c
);
769 if (d
== BASE64_DECODE_WHITESPACE
)
771 if (d
== BASE64_DECODE_PADDING
)
773 block
[cbValid
& 3] = d
;
775 switch (cbValid
& 3) {
777 pbBinary
[cbOut
++] = (block
[0] << 2);
780 pbBinary
[cbOut
-1] = (block
[0] << 2) | (block
[1] >> 4);
783 pbBinary
[cbOut
++] = (block
[1] << 4) | (block
[2] >> 2);
786 pbBinary
[cbOut
++] = (block
[2] << 6) | (block
[3] >> 0);
794 *pdwFlags
= CRYPT_STRING_BASE64
;
795 return ERROR_SUCCESS
;
797 return ERROR_INSUFFICIENT_BUFFER
;
800 return ERROR_INVALID_DATA
;
803 static LONG
Base64ToBinaryA(LPCSTR pszString
, DWORD cchString
,
804 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
806 return Base64ToBinary(pszString
, FALSE
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
809 static LONG
Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString
,
810 DWORD cchString
, BYTE
*pbBinary
,
811 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
814 LPCSTR header
= CERT_HEADER_START
;
815 LPCSTR trailer
= CERT_TRAILER_START
;
819 LPCSTR trailerBegins
;
822 if ((strlen(header
) + strlen(trailer
)) > cchString
)
824 return ERROR_INVALID_DATA
;
827 if (!(headerBegins
= strstr(pszString
, header
)))
829 TRACE("Can't find %s in %s.\n", header
, debugstr_an(pszString
, cchString
));
830 return ERROR_INVALID_DATA
;
833 dataBegins
= headerBegins
+ strlen(header
);
834 if (!(dataBegins
= strstr(dataBegins
, CERT_DELIMITER
)))
836 return ERROR_INVALID_DATA
;
838 dataBegins
+= strlen(CERT_DELIMITER
);
839 if (*dataBegins
== '\r') dataBegins
++;
840 if (*dataBegins
== '\n') dataBegins
++;
842 if (!(trailerBegins
= strstr(dataBegins
, trailer
)))
844 return ERROR_INVALID_DATA
;
846 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
847 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
850 *pdwSkip
= headerBegins
- pszString
;
852 dataLength
= trailerBegins
- dataBegins
;
854 ret
= Base64ToBinaryA(dataBegins
, dataLength
, pbBinary
, pcbBinary
, NULL
,
860 static LONG
Base64HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
861 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
863 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
864 pbBinary
, pcbBinary
, pdwSkip
);
866 if (!ret
&& pdwFlags
)
867 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
871 static LONG
Base64RequestHeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
872 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
874 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
875 pbBinary
, pcbBinary
, pdwSkip
);
877 if (!ret
&& pdwFlags
)
878 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
882 static LONG
Base64X509HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
883 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
885 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
886 pbBinary
, pcbBinary
, pdwSkip
);
888 if (!ret
&& pdwFlags
)
889 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
893 static LONG
Base64AnyToBinaryA(LPCSTR pszString
, DWORD cchString
,
894 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
898 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
900 if (ret
== ERROR_INVALID_DATA
)
901 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
906 static LONG
DecodeBinaryToBinaryA(LPCSTR pszString
, DWORD cchString
,
907 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
909 LONG ret
= ERROR_SUCCESS
;
911 if (*pcbBinary
< cchString
)
914 *pcbBinary
= cchString
;
917 ret
= ERROR_INSUFFICIENT_BUFFER
;
918 *pcbBinary
= cchString
;
924 memcpy(pbBinary
, pszString
, cchString
);
925 *pcbBinary
= cchString
;
930 static LONG
DecodeAnyA(LPCSTR pszString
, DWORD cchString
,
931 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
935 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
937 if (ret
== ERROR_INVALID_DATA
)
938 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
940 if (ret
== ERROR_INVALID_DATA
)
941 ret
= DecodeBinaryToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
946 static BOOL
is_hex_string_special_char(WCHAR c
)
963 static WCHAR
wchar_from_str(BOOL wide
, const void **str
, DWORD
*len
)
972 c
= *(*(const WCHAR
**)str
)++;
974 c
= *(*(const char **)str
)++;
976 return c
? c
: 0xffff;
979 static BYTE
digit_from_char(WCHAR c
)
981 if (c
>= '0' && c
<= '9')
984 if (c
>= 'a' && c
<= 'f')
985 return c
- 'a' + 0xa;
989 static LONG
string_to_hex(const void* str
, BOOL wide
, DWORD len
, BYTE
*hex
, DWORD
*hex_len
,
990 DWORD
*skipped
, DWORD
*ret_flags
)
992 unsigned int byte_idx
= 0;
996 if (!str
|| !hex_len
)
997 return ERROR_INVALID_PARAMETER
;
1000 len
= wide
? wcslen(str
) : strlen(str
);
1003 return ERROR_INVALID_PARAMETER
;
1010 while ((c
= wchar_from_str(wide
, &str
, &len
)) && is_hex_string_special_char(c
))
1013 while ((d1
= digit_from_char(c
)) != 0xff)
1015 if ((d2
= digit_from_char(wchar_from_str(wide
, &str
, &len
))) == 0xff)
1019 return ERROR_INVALID_DATA
;
1022 if (hex
&& byte_idx
< *hex_len
)
1023 hex
[byte_idx
] = (d1
<< 4) | d2
;
1029 c
= wchar_from_str(wide
, &str
, &len
);
1030 } while (c
== '-' || c
== ',');
1035 if (!is_hex_string_special_char(c
))
1039 return ERROR_INVALID_DATA
;
1041 c
= wchar_from_str(wide
, &str
, &len
);
1044 if (hex
&& byte_idx
> *hex_len
)
1045 return ERROR_MORE_DATA
;
1048 *ret_flags
= CRYPT_STRING_HEX
;
1050 *hex_len
= byte_idx
;
1052 return ERROR_SUCCESS
;
1055 static LONG
string_to_hexA(const char *str
, DWORD len
, BYTE
*hex
, DWORD
*hex_len
, DWORD
*skipped
, DWORD
*ret_flags
)
1057 return string_to_hex(str
, FALSE
, len
, hex
, hex_len
, skipped
, ret_flags
);
1060 BOOL WINAPI
CryptStringToBinaryA(LPCSTR pszString
,
1061 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
1062 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1064 StringToBinaryAFunc decoder
;
1067 TRACE("(%s, %ld, %08lx, %p, %p, %p, %p)\n", debugstr_an(pszString
, cchString
? cchString
: -1),
1068 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1072 SetLastError(ERROR_INVALID_PARAMETER
);
1075 /* Only the bottom byte contains valid types */
1076 if (dwFlags
& 0xfffffff0)
1078 SetLastError(ERROR_INVALID_DATA
);
1083 case CRYPT_STRING_BASE64_ANY
:
1084 decoder
= Base64AnyToBinaryA
;
1086 case CRYPT_STRING_BASE64
:
1087 decoder
= Base64ToBinaryA
;
1089 case CRYPT_STRING_BASE64HEADER
:
1090 decoder
= Base64HeaderToBinaryA
;
1092 case CRYPT_STRING_BASE64REQUESTHEADER
:
1093 decoder
= Base64RequestHeaderToBinaryA
;
1095 case CRYPT_STRING_BASE64X509CRLHEADER
:
1096 decoder
= Base64X509HeaderToBinaryA
;
1098 case CRYPT_STRING_BINARY
:
1099 decoder
= DecodeBinaryToBinaryA
;
1101 case CRYPT_STRING_ANY
:
1102 decoder
= DecodeAnyA
;
1104 case CRYPT_STRING_HEX
:
1105 decoder
= string_to_hexA
;
1107 case CRYPT_STRING_HEXASCII
:
1108 case CRYPT_STRING_HEXADDR
:
1109 case CRYPT_STRING_HEXASCIIADDR
:
1110 FIXME("Unimplemented type %ld\n", dwFlags
& 0x7fffffff);
1113 SetLastError(ERROR_INVALID_PARAMETER
);
1117 cchString
= strlen(pszString
);
1118 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1121 return ret
== ERROR_SUCCESS
;
1124 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
1125 * string to convert.
1127 typedef LONG (*StringToBinaryWFunc
)(LPCWSTR pszString
, DWORD cchString
,
1128 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
1130 static LONG
Base64ToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1131 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1133 return Base64ToBinary(pszString
, TRUE
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1136 static LONG
Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString
,
1137 DWORD cchString
, BYTE
*pbBinary
,
1138 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
1141 LPCWSTR header
= CERT_HEADER_START_W
;
1142 LPCWSTR trailer
= CERT_TRAILER_START_W
;
1144 LPCWSTR headerBegins
;
1146 LPCWSTR trailerBegins
;
1149 if ((lstrlenW(header
) + lstrlenW(trailer
)) > cchString
)
1151 return ERROR_INVALID_DATA
;
1154 if (!(headerBegins
= wcsstr(pszString
, header
)))
1156 TRACE("Can't find %s in %s.\n", debugstr_w(header
), debugstr_wn(pszString
, cchString
));
1157 return ERROR_INVALID_DATA
;
1160 dataBegins
= headerBegins
+ lstrlenW(header
);
1161 if (!(dataBegins
= wcsstr(dataBegins
, CERT_DELIMITER_W
)))
1163 return ERROR_INVALID_DATA
;
1165 dataBegins
+= lstrlenW(CERT_DELIMITER_W
);
1166 if (*dataBegins
== '\r') dataBegins
++;
1167 if (*dataBegins
== '\n') dataBegins
++;
1169 if (!(trailerBegins
= wcsstr(dataBegins
, trailer
)))
1171 return ERROR_INVALID_DATA
;
1173 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
1174 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
1177 *pdwSkip
= headerBegins
- pszString
;
1179 dataLength
= trailerBegins
- dataBegins
;
1181 ret
= Base64ToBinaryW(dataBegins
, dataLength
, pbBinary
, pcbBinary
, NULL
,
1187 static LONG
Base64HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1188 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1190 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
1191 pbBinary
, pcbBinary
, pdwSkip
);
1193 if (!ret
&& pdwFlags
)
1194 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
1198 static LONG
Base64RequestHeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1199 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1201 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
1202 pbBinary
, pcbBinary
, pdwSkip
);
1204 if (!ret
&& pdwFlags
)
1205 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
1209 static LONG
Base64X509HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1210 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1212 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
1213 pbBinary
, pcbBinary
, pdwSkip
);
1215 if (!ret
&& pdwFlags
)
1216 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
1220 static LONG
Base64AnyToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1221 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1225 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1227 if (ret
== ERROR_INVALID_DATA
)
1228 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1233 static LONG
DecodeBinaryToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1234 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1236 LONG ret
= ERROR_SUCCESS
;
1238 if (*pcbBinary
< cchString
)
1241 *pcbBinary
= cchString
;
1244 ret
= ERROR_INSUFFICIENT_BUFFER
;
1245 *pcbBinary
= cchString
;
1251 memcpy(pbBinary
, pszString
, cchString
* sizeof(WCHAR
));
1252 *pcbBinary
= cchString
* sizeof(WCHAR
);
1257 static LONG
DecodeAnyW(LPCWSTR pszString
, DWORD cchString
,
1258 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1262 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1264 if (ret
== ERROR_INVALID_DATA
)
1265 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1267 if (ret
== ERROR_INVALID_DATA
)
1268 ret
= DecodeBinaryToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1273 static LONG
string_to_hexW(const WCHAR
*str
, DWORD len
, BYTE
*hex
, DWORD
*hex_len
, DWORD
*skipped
, DWORD
*ret_flags
)
1275 return string_to_hex(str
, TRUE
, len
, hex
, hex_len
, skipped
, ret_flags
);
1278 BOOL WINAPI
CryptStringToBinaryW(LPCWSTR pszString
,
1279 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
1280 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1282 StringToBinaryWFunc decoder
;
1285 TRACE("(%s, %ld, %08lx, %p, %p, %p, %p)\n", debugstr_wn(pszString
, cchString
? cchString
: -1),
1286 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1290 SetLastError(ERROR_INVALID_PARAMETER
);
1293 /* Only the bottom byte contains valid types */
1294 if (dwFlags
& 0xfffffff0)
1296 SetLastError(ERROR_INVALID_DATA
);
1301 case CRYPT_STRING_BASE64_ANY
:
1302 decoder
= Base64AnyToBinaryW
;
1304 case CRYPT_STRING_BASE64
:
1305 decoder
= Base64ToBinaryW
;
1307 case CRYPT_STRING_BASE64HEADER
:
1308 decoder
= Base64HeaderToBinaryW
;
1310 case CRYPT_STRING_BASE64REQUESTHEADER
:
1311 decoder
= Base64RequestHeaderToBinaryW
;
1313 case CRYPT_STRING_BASE64X509CRLHEADER
:
1314 decoder
= Base64X509HeaderToBinaryW
;
1316 case CRYPT_STRING_BINARY
:
1317 decoder
= DecodeBinaryToBinaryW
;
1319 case CRYPT_STRING_ANY
:
1320 decoder
= DecodeAnyW
;
1322 case CRYPT_STRING_HEX
:
1323 decoder
= string_to_hexW
;
1325 case CRYPT_STRING_HEXASCII
:
1326 case CRYPT_STRING_HEXADDR
:
1327 case CRYPT_STRING_HEXASCIIADDR
:
1328 FIXME("Unimplemented type %ld\n", dwFlags
& 0x7fffffff);
1331 SetLastError(ERROR_INVALID_PARAMETER
);
1335 cchString
= lstrlenW(pszString
);
1336 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1339 return ret
== ERROR_SUCCESS
;