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',' ','C','E','R','T','I','F','I','C','A','T',
51 'E','-','-','-','-','-',0 };
52 static const WCHAR CERT_TRAILER_START_W
[] = {
53 '-','-','-','-','-','E','N','D',' ',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
)
82 if (*pcchString
< cbBinary
)
84 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
88 memcpy(pszString
, pbBinary
, cbBinary
);
91 *pcchString
= cbBinary
;
96 static DWORD
stradd(LPSTR ptr
, LPCSTR end
, LPCSTR s
, DWORD slen
)
100 memcpy(ptr
, s
, slen
);
104 static DWORD
encodeBase64A(const BYTE
*in_buf
, int in_len
, LPCSTR sep
,
105 char* out_buf
, DWORD
*out_len
)
108 const BYTE
*d
= in_buf
;
109 int bytes
= (in_len
*8 + 5)/6, pad_bytes
= (bytes
% 4) ? 4 - (bytes
% 4) : 0;
116 TRACE("bytes is %d, pad bytes is %d\n", bytes
, pad_bytes
);
117 *out_len
= bytes
+ pad_bytes
;
118 *out_len
+= (*out_len
/ 64 + (*out_len
% 64 ? 1 : 0)) * strlen(sep
) + 1;
122 /* Three bytes of input give 4 chars of output */
126 end
= ptr
+ *out_len
;
128 while (div
> 0 && ptr
< end
)
130 if (i
&& i
% 64 == 0)
131 ptr
+= stradd(ptr
, end
, sep
, strlen(sep
));
132 /* first char is the first 6 bits of the first byte*/
133 chunk
[0] = b64
[ ( d
[0] >> 2) & 0x3f ];
134 /* second char is the last 2 bits of the first byte and the first 4
135 * bits of the second byte */
136 chunk
[1] = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
137 /* third char is the last 4 bits of the second byte and the first 2
138 * bits of the third byte */
139 chunk
[2] = b64
[ ((d
[1] << 2) & 0x3c) | (d
[2] >> 6 & 0x03)];
140 /* fourth char is the remaining 6 bits of the third byte */
141 chunk
[3] = b64
[ d
[2] & 0x3f];
142 ptr
+= stradd(ptr
, end
, chunk
, 4);
151 /* first char is the first 6 bits of the first byte*/
152 chunk
[0] = 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 chunk
[1] = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
156 /* third char is the last 4 bits of the second byte padded with
158 chunk
[2] = b64
[ ((d
[1] << 2) & 0x3c) ];
159 /* fourth char is a = to indicate one byte of padding */
161 ptr
+= stradd(ptr
, end
, chunk
, 4);
164 /* first char is the first 6 bits of the first byte*/
165 chunk
[0] = b64
[ ( d
[0] >> 2) & 0x3f ];
166 /* second char is the last 2 bits of the first byte padded with
168 chunk
[1] = b64
[ ((d
[0] << 4) & 0x30)];
169 /* third char is = to indicate padding */
171 /* fourth char is = to indicate padding */
173 ptr
+= stradd(ptr
, end
, chunk
, 4);
176 ptr
+= stradd(ptr
, end
, sep
, strlen(sep
));
178 return ptr
- out_buf
;
181 static BOOL
BinaryToBase64A(const BYTE
*pbBinary
,
182 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
184 static const char crlf
[] = "\r\n", lf
[] = "\n";
186 LPCSTR header
= NULL
, trailer
= NULL
, sep
;
189 if (dwFlags
& CRYPT_STRING_NOCR
)
191 else if (dwFlags
& CRYPT_STRING_NOCRLF
)
195 switch (dwFlags
& 0x0fffffff)
197 case CRYPT_STRING_BASE64
:
198 /* no header or footer */
200 case CRYPT_STRING_BASE64HEADER
:
201 header
= CERT_HEADER
;
202 trailer
= CERT_TRAILER
;
204 case CRYPT_STRING_BASE64REQUESTHEADER
:
205 header
= CERT_REQUEST_HEADER
;
206 trailer
= CERT_REQUEST_TRAILER
;
208 case CRYPT_STRING_BASE64X509CRLHEADER
:
209 header
= X509_HEADER
;
210 trailer
= X509_TRAILER
;
215 encodeBase64A(pbBinary
, cbBinary
, sep
, NULL
, &charsNeeded
);
217 charsNeeded
+= strlen(header
) + strlen(sep
);
219 charsNeeded
+= strlen(trailer
) + strlen(sep
);
223 LPSTR ptr
= pszString
;
224 DWORD size
= *pcchString
;
225 LPSTR end
= ptr
+ size
;
229 ptr
+= stradd(ptr
, end
, header
, strlen(header
));
230 ptr
+= stradd(ptr
, end
, sep
, strlen(sep
));
233 ptr
+= encodeBase64A(pbBinary
, cbBinary
, sep
, ptr
, &size
);
236 ptr
+= stradd(ptr
, end
, trailer
, strlen(trailer
));
237 ptr
+= stradd(ptr
, end
, sep
, strlen(sep
));
243 if (charsNeeded
<= *pcchString
)
245 *pcchString
= charsNeeded
- 1;
249 *pcchString
= charsNeeded
;
250 SetLastError(ERROR_MORE_DATA
);
255 *pcchString
= charsNeeded
;
260 BOOL WINAPI
CryptBinaryToStringA(const BYTE
*pbBinary
,
261 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
263 BinaryToStringAFunc encoder
= NULL
;
265 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
270 SetLastError(ERROR_INVALID_PARAMETER
);
275 SetLastError(ERROR_INVALID_PARAMETER
);
279 switch (dwFlags
& 0x0fffffff)
281 case CRYPT_STRING_BINARY
:
282 encoder
= EncodeBinaryToBinaryA
;
284 case CRYPT_STRING_BASE64
:
285 case CRYPT_STRING_BASE64HEADER
:
286 case CRYPT_STRING_BASE64REQUESTHEADER
:
287 case CRYPT_STRING_BASE64X509CRLHEADER
:
288 encoder
= BinaryToBase64A
;
290 case CRYPT_STRING_HEX
:
291 case CRYPT_STRING_HEXASCII
:
292 case CRYPT_STRING_HEXADDR
:
293 case CRYPT_STRING_HEXASCIIADDR
:
294 FIXME("Unimplemented type %d\n", dwFlags
& 0x0fffffff);
297 SetLastError(ERROR_INVALID_PARAMETER
);
300 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
303 static BOOL
EncodeBinaryToBinaryW(const BYTE
*in_buf
, DWORD in_len
, DWORD flags
, WCHAR
*out_buf
, DWORD
*out_len
)
309 if (*out_len
< in_len
)
311 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
315 memcpy(out_buf
, in_buf
, in_len
);
323 static LONG
encodeBase64W(const BYTE
*in_buf
, int in_len
, LPCWSTR sep
,
324 WCHAR
* out_buf
, DWORD
*out_len
)
327 const BYTE
*d
= in_buf
;
328 int bytes
= (in_len
*8 + 5)/6, pad_bytes
= (bytes
% 4) ? 4 - (bytes
% 4) : 0;
332 TRACE("bytes is %d, pad bytes is %d\n", bytes
, pad_bytes
);
333 needed
= bytes
+ pad_bytes
;
334 needed
+= (needed
/ 64 + (needed
% 64 ? 1 : 0)) * strlenW(sep
);
337 if (needed
> *out_len
)
340 return ERROR_INSUFFICIENT_BUFFER
;
345 /* Three bytes of input give 4 chars of output */
352 if (i
&& i
% 64 == 0)
357 /* first char is the first 6 bits of the first byte*/
358 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
359 /* second char is the last 2 bits of the first byte and the first 4
360 * bits of the second byte */
361 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
362 /* third char is the last 4 bits of the second byte and the first 2
363 * bits of the third byte */
364 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) | (d
[2] >> 6 & 0x03)];
365 /* fourth char is the remaining 6 bits of the third byte */
366 *ptr
++ = b64
[ d
[2] & 0x3f];
375 /* first char is the first 6 bits of the first byte*/
376 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
377 /* second char is the last 2 bits of the first byte and the first 4
378 * bits of the second byte */
379 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
380 /* third char is the last 4 bits of the second byte padded with
382 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) ];
383 /* fourth char is a = to indicate one byte of padding */
387 /* first char is the first 6 bits of the first byte*/
388 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
389 /* second char is the last 2 bits of the first byte padded with
391 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30)];
392 /* third char is = to indicate padding */
394 /* fourth char is = to indicate padding */
400 return ERROR_SUCCESS
;
403 static BOOL
BinaryToBase64W(const BYTE
*pbBinary
,
404 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
406 static const WCHAR crlf
[] = { '\r','\n',0 }, lf
[] = { '\n',0 }, empty
[] = {0};
408 LPCWSTR header
= NULL
, trailer
= NULL
, sep
;
411 if (dwFlags
& CRYPT_STRING_NOCR
)
413 else if (dwFlags
& CRYPT_STRING_NOCRLF
)
417 switch (dwFlags
& 0x0fffffff)
419 case CRYPT_STRING_BASE64
:
420 /* no header or footer */
422 case CRYPT_STRING_BASE64HEADER
:
423 header
= CERT_HEADER_W
;
424 trailer
= CERT_TRAILER_W
;
426 case CRYPT_STRING_BASE64REQUESTHEADER
:
427 header
= CERT_REQUEST_HEADER_W
;
428 trailer
= CERT_REQUEST_TRAILER_W
;
430 case CRYPT_STRING_BASE64X509CRLHEADER
:
431 header
= X509_HEADER_W
;
432 trailer
= X509_TRAILER_W
;
437 encodeBase64W(pbBinary
, cbBinary
, sep
, NULL
, &charsNeeded
);
439 charsNeeded
+= strlenW(header
) + strlenW(sep
);
441 charsNeeded
+= strlenW(trailer
) + strlenW(sep
);
445 if (charsNeeded
<= *pcchString
)
447 LPWSTR ptr
= pszString
;
448 DWORD size
= charsNeeded
;
452 strcpyW(ptr
, header
);
457 encodeBase64W(pbBinary
, cbBinary
, sep
, ptr
, &size
);
461 strcpyW(ptr
, trailer
);
465 *pcchString
= charsNeeded
- 1;
469 *pcchString
= charsNeeded
;
470 SetLastError(ERROR_MORE_DATA
);
475 *pcchString
= charsNeeded
;
480 static BOOL
BinaryToHexW(const BYTE
*bin
, DWORD nbin
, DWORD flags
, LPWSTR str
, DWORD
*nstr
)
482 static const WCHAR hex
[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
485 if (flags
& CRYPT_STRING_NOCRLF
)
487 else if (flags
& CRYPT_STRING_NOCR
)
492 needed
+= nbin
* 2 + 1;
502 SetLastError(ERROR_MORE_DATA
);
508 *str
++ = hex
[(*bin
>> 4) & 0xf];
509 *str
++ = hex
[*bin
& 0xf];
513 if (flags
& CRYPT_STRING_NOCR
)
515 else if (!(flags
& CRYPT_STRING_NOCRLF
))
526 BOOL WINAPI
CryptBinaryToStringW(const BYTE
*pbBinary
,
527 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
529 BinaryToStringWFunc encoder
= NULL
;
531 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
536 SetLastError(ERROR_INVALID_PARAMETER
);
541 SetLastError(ERROR_INVALID_PARAMETER
);
545 switch (dwFlags
& 0x0fffffff)
547 case CRYPT_STRING_BINARY
:
548 encoder
= EncodeBinaryToBinaryW
;
550 case CRYPT_STRING_BASE64
:
551 case CRYPT_STRING_BASE64HEADER
:
552 case CRYPT_STRING_BASE64REQUESTHEADER
:
553 case CRYPT_STRING_BASE64X509CRLHEADER
:
554 encoder
= BinaryToBase64W
;
556 case CRYPT_STRING_HEXRAW
:
557 encoder
= BinaryToHexW
;
559 case CRYPT_STRING_HEX
:
560 case CRYPT_STRING_HEXASCII
:
561 case CRYPT_STRING_HEXADDR
:
562 case CRYPT_STRING_HEXASCIIADDR
:
563 FIXME("Unimplemented type %d\n", dwFlags
& 0x0fffffff);
566 SetLastError(ERROR_INVALID_PARAMETER
);
569 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
572 #define BASE64_DECODE_PADDING 0x100
573 #define BASE64_DECODE_WHITESPACE 0x200
574 #define BASE64_DECODE_INVALID 0x300
576 static inline int decodeBase64Byte(int c
)
578 int ret
= BASE64_DECODE_INVALID
;
580 if (c
>= 'A' && c
<= 'Z')
582 else if (c
>= 'a' && c
<= 'z')
584 else if (c
>= '0' && c
<= '9')
591 ret
= BASE64_DECODE_PADDING
;
592 else if (c
== ' ' || c
== '\t' || c
== '\r' || c
== '\n')
593 ret
= BASE64_DECODE_WHITESPACE
;
597 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
600 typedef LONG (*StringToBinaryAFunc
)(LPCSTR pszString
, DWORD cchString
,
601 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
603 static LONG
Base64ToBinary(const void* pszString
, BOOL wide
, DWORD cchString
,
604 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
606 DWORD cbIn
, cbValid
, cbOut
, hasPadding
;
608 for (cbIn
= cbValid
= cbOut
= hasPadding
= 0; cbIn
< cchString
; ++cbIn
)
610 int c
= wide
? (int)((WCHAR
*)pszString
)[cbIn
] : (int)((char*)pszString
)[cbIn
];
611 int d
= decodeBase64Byte(c
);
612 if (d
== BASE64_DECODE_INVALID
)
614 if (d
== BASE64_DECODE_WHITESPACE
)
617 /* When padding starts, data is not acceptable */
618 if (hasPadding
&& d
!= BASE64_DECODE_PADDING
)
621 /* Padding after a full block (like "VVVV=") is ok and stops decoding */
622 if (d
== BASE64_DECODE_PADDING
&& (cbValid
& 3) == 0)
627 if (d
== BASE64_DECODE_PADDING
)
630 /* When padding reaches a full block, stop decoding */
631 if ((cbValid
& 3) == 0)
636 /* cbOut is incremented in the 4-char block as follows: "1-23" */
637 if ((cbValid
& 3) != 2)
640 /* Fail if the block has bad padding; omitting padding is fine */
641 if ((cbValid
& 3) != 0 && hasPadding
)
643 /* Check available buffer size */
644 if (pbBinary
&& *pcbBinary
&& cbOut
> *pcbBinary
)
646 /* Convert the data; this step depends on the validity checks above! */
647 if (pbBinary
) for (cbIn
= cbValid
= cbOut
= 0; cbIn
< cchString
; ++cbIn
)
649 int c
= wide
? (int)((WCHAR
*)pszString
)[cbIn
] : (int)((char*)pszString
)[cbIn
];
650 int d
= decodeBase64Byte(c
);
651 if (d
== BASE64_DECODE_WHITESPACE
)
653 if (d
== BASE64_DECODE_PADDING
)
655 block
[cbValid
& 3] = d
;
657 switch (cbValid
& 3) {
659 pbBinary
[cbOut
++] = (block
[0] << 2);
662 pbBinary
[cbOut
-1] = (block
[0] << 2) | (block
[1] >> 4);
665 pbBinary
[cbOut
++] = (block
[1] << 4) | (block
[2] >> 2);
668 pbBinary
[cbOut
++] = (block
[2] << 6) | (block
[3] >> 0);
676 *pdwFlags
= CRYPT_STRING_BASE64
;
677 return ERROR_SUCCESS
;
679 return ERROR_INSUFFICIENT_BUFFER
;
682 return ERROR_INVALID_DATA
;
685 static LONG
Base64ToBinaryA(LPCSTR pszString
, DWORD cchString
,
686 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
688 return Base64ToBinary(pszString
, FALSE
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
691 static LONG
Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString
,
692 DWORD cchString
, BYTE
*pbBinary
,
693 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
696 LPCSTR header
= CERT_HEADER_START
;
697 LPCSTR trailer
= CERT_TRAILER_START
;
701 LPCSTR trailerBegins
;
704 if ((strlen(header
) + strlen(trailer
)) > cchString
)
706 return ERROR_INVALID_DATA
;
709 if (!(headerBegins
= strstr(pszString
, header
)))
711 TRACE("Can't find %s in %s.\n", header
, debugstr_an(pszString
, cchString
));
712 return ERROR_INVALID_DATA
;
715 dataBegins
= headerBegins
+ strlen(header
);
716 if (!(dataBegins
= strstr(dataBegins
, CERT_DELIMITER
)))
718 return ERROR_INVALID_DATA
;
720 dataBegins
+= strlen(CERT_DELIMITER
);
721 if (*dataBegins
== '\r') dataBegins
++;
722 if (*dataBegins
== '\n') dataBegins
++;
724 if (!(trailerBegins
= strstr(dataBegins
, trailer
)))
726 return ERROR_INVALID_DATA
;
728 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
729 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
732 *pdwSkip
= headerBegins
- pszString
;
734 dataLength
= trailerBegins
- dataBegins
;
736 ret
= Base64ToBinaryA(dataBegins
, dataLength
, pbBinary
, pcbBinary
, NULL
,
742 static LONG
Base64HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
743 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
745 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
746 pbBinary
, pcbBinary
, pdwSkip
);
748 if (!ret
&& pdwFlags
)
749 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
753 static LONG
Base64RequestHeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
754 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
756 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
757 pbBinary
, pcbBinary
, pdwSkip
);
759 if (!ret
&& pdwFlags
)
760 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
764 static LONG
Base64X509HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
765 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
767 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
768 pbBinary
, pcbBinary
, pdwSkip
);
770 if (!ret
&& pdwFlags
)
771 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
775 static LONG
Base64AnyToBinaryA(LPCSTR pszString
, DWORD cchString
,
776 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
780 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
782 if (ret
== ERROR_INVALID_DATA
)
783 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
788 static LONG
DecodeBinaryToBinaryA(LPCSTR pszString
, DWORD cchString
,
789 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
791 LONG ret
= ERROR_SUCCESS
;
793 if (*pcbBinary
< cchString
)
796 *pcbBinary
= cchString
;
799 ret
= ERROR_INSUFFICIENT_BUFFER
;
800 *pcbBinary
= cchString
;
806 memcpy(pbBinary
, pszString
, cchString
);
807 *pcbBinary
= cchString
;
812 static LONG
DecodeAnyA(LPCSTR pszString
, DWORD cchString
,
813 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
817 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
819 if (ret
== ERROR_INVALID_DATA
)
820 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
822 if (ret
== ERROR_INVALID_DATA
)
823 ret
= DecodeBinaryToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
828 BOOL WINAPI
CryptStringToBinaryA(LPCSTR pszString
,
829 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
830 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
832 StringToBinaryAFunc decoder
;
835 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_an(pszString
, cchString
? cchString
: -1),
836 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
840 SetLastError(ERROR_INVALID_PARAMETER
);
843 /* Only the bottom byte contains valid types */
844 if (dwFlags
& 0xfffffff0)
846 SetLastError(ERROR_INVALID_DATA
);
851 case CRYPT_STRING_BASE64_ANY
:
852 decoder
= Base64AnyToBinaryA
;
854 case CRYPT_STRING_BASE64
:
855 decoder
= Base64ToBinaryA
;
857 case CRYPT_STRING_BASE64HEADER
:
858 decoder
= Base64HeaderToBinaryA
;
860 case CRYPT_STRING_BASE64REQUESTHEADER
:
861 decoder
= Base64RequestHeaderToBinaryA
;
863 case CRYPT_STRING_BASE64X509CRLHEADER
:
864 decoder
= Base64X509HeaderToBinaryA
;
866 case CRYPT_STRING_BINARY
:
867 decoder
= DecodeBinaryToBinaryA
;
869 case CRYPT_STRING_ANY
:
870 decoder
= DecodeAnyA
;
872 case CRYPT_STRING_HEX
:
873 case CRYPT_STRING_HEXASCII
:
874 case CRYPT_STRING_HEXADDR
:
875 case CRYPT_STRING_HEXASCIIADDR
:
876 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
879 SetLastError(ERROR_INVALID_PARAMETER
);
883 cchString
= strlen(pszString
);
884 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
887 return ret
== ERROR_SUCCESS
;
890 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
893 typedef LONG (*StringToBinaryWFunc
)(LPCWSTR pszString
, DWORD cchString
,
894 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
896 static LONG
Base64ToBinaryW(LPCWSTR pszString
, DWORD cchString
,
897 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
899 return Base64ToBinary(pszString
, TRUE
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
902 static LONG
Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString
,
903 DWORD cchString
, BYTE
*pbBinary
,
904 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
907 LPCWSTR header
= CERT_HEADER_START_W
;
908 LPCWSTR trailer
= CERT_TRAILER_START_W
;
910 LPCWSTR headerBegins
;
912 LPCWSTR trailerBegins
;
915 if ((strlenW(header
) + strlenW(trailer
)) > cchString
)
917 return ERROR_INVALID_DATA
;
920 if (!(headerBegins
= strstrW(pszString
, header
)))
922 TRACE("Can't find %s in %s.\n", debugstr_w(header
), debugstr_wn(pszString
, cchString
));
923 return ERROR_INVALID_DATA
;
926 dataBegins
= headerBegins
+ strlenW(header
);
927 if (!(dataBegins
= strstrW(dataBegins
, CERT_DELIMITER_W
)))
929 return ERROR_INVALID_DATA
;
931 dataBegins
+= strlenW(CERT_DELIMITER_W
);
932 if (*dataBegins
== '\r') dataBegins
++;
933 if (*dataBegins
== '\n') dataBegins
++;
935 if (!(trailerBegins
= strstrW(dataBegins
, trailer
)))
937 return ERROR_INVALID_DATA
;
939 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
940 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
943 *pdwSkip
= headerBegins
- pszString
;
945 dataLength
= trailerBegins
- dataBegins
;
947 ret
= Base64ToBinaryW(dataBegins
, dataLength
, pbBinary
, pcbBinary
, NULL
,
953 static LONG
Base64HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
954 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
956 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
957 pbBinary
, pcbBinary
, pdwSkip
);
959 if (!ret
&& pdwFlags
)
960 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
964 static LONG
Base64RequestHeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
965 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
967 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
968 pbBinary
, pcbBinary
, pdwSkip
);
970 if (!ret
&& pdwFlags
)
971 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
975 static LONG
Base64X509HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
976 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
978 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
979 pbBinary
, pcbBinary
, pdwSkip
);
981 if (!ret
&& pdwFlags
)
982 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
986 static LONG
Base64AnyToBinaryW(LPCWSTR pszString
, DWORD cchString
,
987 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
991 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
993 if (ret
== ERROR_INVALID_DATA
)
994 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
999 static LONG
DecodeBinaryToBinaryW(LPCWSTR pszString
, DWORD cchString
,
1000 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1002 LONG ret
= ERROR_SUCCESS
;
1004 if (*pcbBinary
< cchString
)
1007 *pcbBinary
= cchString
;
1010 ret
= ERROR_INSUFFICIENT_BUFFER
;
1011 *pcbBinary
= cchString
;
1017 memcpy(pbBinary
, pszString
, cchString
* sizeof(WCHAR
));
1018 *pcbBinary
= cchString
* sizeof(WCHAR
);
1023 static LONG
DecodeAnyW(LPCWSTR pszString
, DWORD cchString
,
1024 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1028 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1030 if (ret
== ERROR_INVALID_DATA
)
1031 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1033 if (ret
== ERROR_INVALID_DATA
)
1034 ret
= DecodeBinaryToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
1039 BOOL WINAPI
CryptStringToBinaryW(LPCWSTR pszString
,
1040 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
1041 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1043 StringToBinaryWFunc decoder
;
1046 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_wn(pszString
, cchString
? cchString
: -1),
1047 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1051 SetLastError(ERROR_INVALID_PARAMETER
);
1054 /* Only the bottom byte contains valid types */
1055 if (dwFlags
& 0xfffffff0)
1057 SetLastError(ERROR_INVALID_DATA
);
1062 case CRYPT_STRING_BASE64_ANY
:
1063 decoder
= Base64AnyToBinaryW
;
1065 case CRYPT_STRING_BASE64
:
1066 decoder
= Base64ToBinaryW
;
1068 case CRYPT_STRING_BASE64HEADER
:
1069 decoder
= Base64HeaderToBinaryW
;
1071 case CRYPT_STRING_BASE64REQUESTHEADER
:
1072 decoder
= Base64RequestHeaderToBinaryW
;
1074 case CRYPT_STRING_BASE64X509CRLHEADER
:
1075 decoder
= Base64X509HeaderToBinaryW
;
1077 case CRYPT_STRING_BINARY
:
1078 decoder
= DecodeBinaryToBinaryW
;
1080 case CRYPT_STRING_ANY
:
1081 decoder
= DecodeAnyW
;
1083 case CRYPT_STRING_HEX
:
1084 case CRYPT_STRING_HEXASCII
:
1085 case CRYPT_STRING_HEXADDR
:
1086 case CRYPT_STRING_HEXASCIIADDR
:
1087 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
1090 SetLastError(ERROR_INVALID_PARAMETER
);
1094 cchString
= strlenW(pszString
);
1095 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1098 return ret
== ERROR_SUCCESS
;