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
);
238 *pcchString
= charsNeeded
- 1;
242 *pcchString
= charsNeeded
;
243 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
247 *pcchString
= charsNeeded
;
251 BOOL WINAPI
CryptBinaryToStringA(const BYTE
*pbBinary
,
252 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
254 BinaryToStringAFunc encoder
= NULL
;
256 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
261 SetLastError(ERROR_INVALID_PARAMETER
);
266 SetLastError(ERROR_INVALID_PARAMETER
);
270 switch (dwFlags
& 0x0fffffff)
272 case CRYPT_STRING_BINARY
:
273 encoder
= EncodeBinaryToBinaryA
;
275 case CRYPT_STRING_BASE64
:
276 case CRYPT_STRING_BASE64HEADER
:
277 case CRYPT_STRING_BASE64REQUESTHEADER
:
278 case CRYPT_STRING_BASE64X509CRLHEADER
:
279 encoder
= BinaryToBase64A
;
281 case CRYPT_STRING_HEX
:
282 case CRYPT_STRING_HEXASCII
:
283 case CRYPT_STRING_HEXADDR
:
284 case CRYPT_STRING_HEXASCIIADDR
:
285 FIXME("Unimplemented type %d\n", dwFlags
& 0x0fffffff);
288 SetLastError(ERROR_INVALID_PARAMETER
);
291 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
294 static LONG
encodeBase64W(const BYTE
*in_buf
, int in_len
, LPCWSTR sep
,
295 WCHAR
* out_buf
, DWORD
*out_len
)
298 const BYTE
*d
= in_buf
;
299 int bytes
= (in_len
*8 + 5)/6, pad_bytes
= (bytes
% 4) ? 4 - (bytes
% 4) : 0;
303 TRACE("bytes is %d, pad bytes is %d\n", bytes
, pad_bytes
);
304 needed
= bytes
+ pad_bytes
+ 1;
305 needed
+= (needed
/ 64 + 1) * strlenW(sep
);
307 if (needed
> *out_len
)
310 return ERROR_INSUFFICIENT_BUFFER
;
315 /* Three bytes of input give 4 chars of output */
322 if (i
&& i
% 64 == 0)
327 /* first char is the first 6 bits of the first byte*/
328 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
329 /* second char is the last 2 bits of the first byte and the first 4
330 * bits of the second byte */
331 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
332 /* third char is the last 4 bits of the second byte and the first 2
333 * bits of the third byte */
334 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) | (d
[2] >> 6 & 0x03)];
335 /* fourth char is the remaining 6 bits of the third byte */
336 *ptr
++ = b64
[ d
[2] & 0x3f];
345 /* first char is the first 6 bits of the first byte*/
346 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
347 /* second char is the last 2 bits of the first byte and the first 4
348 * bits of the second byte */
349 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
350 /* third char is the last 4 bits of the second byte padded with
352 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) ];
353 /* fourth char is a = to indicate one byte of padding */
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 padded with
361 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30)];
362 /* third char is = to indicate padding */
364 /* fourth char is = to indicate padding */
370 return ERROR_SUCCESS
;
373 static BOOL
BinaryToBase64W(const BYTE
*pbBinary
,
374 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
376 static const WCHAR crlf
[] = { '\r','\n',0 }, lf
[] = { '\n',0 }, empty
[] = {0};
378 LPCWSTR header
= NULL
, trailer
= NULL
, sep
;
381 if (dwFlags
& CRYPT_STRING_NOCR
)
383 else if (dwFlags
& CRYPT_STRING_NOCRLF
)
387 switch (dwFlags
& 0x0fffffff)
389 case CRYPT_STRING_BASE64
:
390 /* no header or footer */
392 case CRYPT_STRING_BASE64HEADER
:
393 header
= CERT_HEADER_W
;
394 trailer
= CERT_TRAILER_W
;
396 case CRYPT_STRING_BASE64REQUESTHEADER
:
397 header
= CERT_REQUEST_HEADER_W
;
398 trailer
= CERT_REQUEST_TRAILER_W
;
400 case CRYPT_STRING_BASE64X509CRLHEADER
:
401 header
= X509_HEADER_W
;
402 trailer
= X509_TRAILER_W
;
407 encodeBase64W(pbBinary
, cbBinary
, sep
, NULL
, &charsNeeded
);
409 charsNeeded
+= strlenW(header
) + strlenW(sep
);
411 charsNeeded
+= strlenW(trailer
) + strlenW(sep
);
412 if (charsNeeded
<= *pcchString
)
414 LPWSTR ptr
= pszString
;
415 DWORD size
= charsNeeded
;
419 strcpyW(ptr
, header
);
424 encodeBase64W(pbBinary
, cbBinary
, sep
, ptr
, &size
);
428 strcpyW(ptr
, trailer
);
432 *pcchString
= charsNeeded
- 1;
436 *pcchString
= charsNeeded
;
437 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
441 *pcchString
= charsNeeded
;
445 BOOL WINAPI
CryptBinaryToStringW(const BYTE
*pbBinary
,
446 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
448 BinaryToStringWFunc encoder
= NULL
;
450 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
455 SetLastError(ERROR_INVALID_PARAMETER
);
460 SetLastError(ERROR_INVALID_PARAMETER
);
464 switch (dwFlags
& 0x0fffffff)
466 case CRYPT_STRING_BASE64
:
467 case CRYPT_STRING_BASE64HEADER
:
468 case CRYPT_STRING_BASE64REQUESTHEADER
:
469 case CRYPT_STRING_BASE64X509CRLHEADER
:
470 encoder
= BinaryToBase64W
;
472 case CRYPT_STRING_BINARY
:
473 case CRYPT_STRING_HEX
:
474 case CRYPT_STRING_HEXASCII
:
475 case CRYPT_STRING_HEXADDR
:
476 case CRYPT_STRING_HEXASCIIADDR
:
477 FIXME("Unimplemented type %d\n", dwFlags
& 0x0fffffff);
480 SetLastError(ERROR_INVALID_PARAMETER
);
483 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
486 #define BASE64_DECODE_PADDING 0x100
487 #define BASE64_DECODE_WHITESPACE 0x200
488 #define BASE64_DECODE_INVALID 0x300
490 static inline int decodeBase64Byte(int c
)
492 int ret
= BASE64_DECODE_INVALID
;
494 if (c
>= 'A' && c
<= 'Z')
496 else if (c
>= 'a' && c
<= 'z')
498 else if (c
>= '0' && c
<= '9')
505 ret
= BASE64_DECODE_PADDING
;
506 else if (c
== ' ' || c
== '\t' || c
== '\r' || c
== '\n')
507 ret
= BASE64_DECODE_WHITESPACE
;
511 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
514 typedef LONG (*StringToBinaryAFunc
)(LPCSTR pszString
, DWORD cchString
,
515 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
517 static LONG
Base64ToBinary(const void* pszString
, BOOL wide
, DWORD cchString
,
518 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
520 DWORD cbIn
, cbValid
, cbOut
, hasPadding
;
522 for (cbIn
= cbValid
= cbOut
= hasPadding
= 0; cbIn
< cchString
; ++cbIn
)
524 int c
= wide
? (int)((WCHAR
*)pszString
)[cbIn
] : (int)((char*)pszString
)[cbIn
];
525 int d
= decodeBase64Byte(c
);
526 if (d
== BASE64_DECODE_INVALID
)
528 if (d
== BASE64_DECODE_WHITESPACE
)
531 /* When padding starts, data is not acceptable */
532 if (hasPadding
&& d
!= BASE64_DECODE_PADDING
)
535 /* Padding after a full block (like "VVVV=") is ok and stops decoding */
536 if (d
== BASE64_DECODE_PADDING
&& (cbValid
& 3) == 0)
541 if (d
== BASE64_DECODE_PADDING
)
544 /* When padding reaches a full block, stop decoding */
545 if ((cbValid
& 3) == 0)
550 /* cbOut is incremented in the 4-char block as follows: "1-23" */
551 if ((cbValid
& 3) != 2)
554 /* Fail if the block has bad padding; omitting padding is fine */
555 if ((cbValid
& 3) != 0 && hasPadding
)
557 /* Check available buffer size */
558 if (pbBinary
&& *pcbBinary
&& cbOut
> *pcbBinary
)
560 /* Convert the data; this step depends on the validity checks above! */
561 if (pbBinary
) for (cbIn
= cbValid
= cbOut
= 0; cbIn
< cchString
; ++cbIn
)
563 int c
= wide
? (int)((WCHAR
*)pszString
)[cbIn
] : (int)((char*)pszString
)[cbIn
];
564 int d
= decodeBase64Byte(c
);
565 if (d
== BASE64_DECODE_WHITESPACE
)
567 if (d
== BASE64_DECODE_PADDING
)
569 block
[cbValid
& 3] = d
;
571 switch (cbValid
& 3) {
573 pbBinary
[cbOut
++] = (block
[0] << 2);
576 pbBinary
[cbOut
-1] = (block
[0] << 2) | (block
[1] >> 4);
579 pbBinary
[cbOut
++] = (block
[1] << 4) | (block
[2] >> 2);
582 pbBinary
[cbOut
++] = (block
[2] << 6) | (block
[3] >> 0);
590 *pdwFlags
= CRYPT_STRING_BASE64
;
591 return ERROR_SUCCESS
;
593 return ERROR_INSUFFICIENT_BUFFER
;
596 return ERROR_INVALID_DATA
;
599 static LONG
Base64ToBinaryA(LPCSTR pszString
, DWORD cchString
,
600 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
602 return Base64ToBinary(pszString
, FALSE
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
605 static LONG
Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString
,
606 DWORD cchString
, BYTE
*pbBinary
,
607 DWORD
*pcbBinary
, DWORD
*pdwSkip
, BOOL exactHeaderAndTrailerMatch
)
610 LPCSTR header
= CERT_HEADER_START
;
611 LPCSTR trailer
= CERT_TRAILER_START
;
615 LPCSTR trailerBegins
;
618 if ((strlen(header
) + strlen(trailer
)) > cchString
)
620 return ERROR_INVALID_DATA
;
623 if (!(headerBegins
= strstr(pszString
, header
)))
625 TRACE("Can't find %s in %s.\n", header
, pszString
);
626 return ERROR_INVALID_DATA
;
629 dataBegins
= headerBegins
+ strlen(header
);
630 if (!exactHeaderAndTrailerMatch
)
632 if ((dataBegins
= strstr(dataBegins
, CERT_DELIMITER
)))
634 dataBegins
+= strlen(CERT_DELIMITER
);
638 return ERROR_INVALID_DATA
;
641 if (*dataBegins
== '\r') dataBegins
++;
642 if (*dataBegins
== '\n') dataBegins
++;
644 if (exactHeaderAndTrailerMatch
)
646 trailerBegins
= pszString
+ cchString
- strlen(trailer
);
647 if (pszString
[cchString
- 1] == '\n') trailerBegins
--;
648 if (pszString
[cchString
- 2] == '\r') trailerBegins
--;
650 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
651 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
653 if (!strncmp(trailerBegins
, trailer
, strlen(trailer
)))
655 return ERROR_INVALID_DATA
;
660 if (!(trailerBegins
= strstr(dataBegins
, trailer
)))
662 return ERROR_INVALID_DATA
;
664 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
665 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
669 *pdwSkip
= headerBegins
- pszString
;
671 dataLength
= trailerBegins
- dataBegins
;
673 ret
= Base64ToBinaryA(dataBegins
, dataLength
, pbBinary
, pcbBinary
, NULL
,
679 static LONG
Base64HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
680 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
682 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
683 pbBinary
, pcbBinary
, pdwSkip
, FALSE
);
685 if (!ret
&& pdwFlags
)
686 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
690 static LONG
Base64RequestHeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
691 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
693 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
694 pbBinary
, pcbBinary
, pdwSkip
, FALSE
);
696 if (!ret
&& pdwFlags
)
697 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
701 static LONG
Base64X509HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
702 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
704 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
705 pbBinary
, pcbBinary
, pdwSkip
, FALSE
);
707 if (!ret
&& pdwFlags
)
708 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
712 static LONG
Base64AnyToBinaryA(LPCSTR pszString
, DWORD cchString
,
713 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
717 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
719 if (ret
== ERROR_INVALID_DATA
)
720 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
725 static LONG
DecodeBinaryToBinaryA(LPCSTR pszString
, DWORD cchString
,
726 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
728 LONG ret
= ERROR_SUCCESS
;
730 if (*pcbBinary
< cchString
)
733 *pcbBinary
= cchString
;
736 ret
= ERROR_INSUFFICIENT_BUFFER
;
737 *pcbBinary
= cchString
;
743 memcpy(pbBinary
, pszString
, cchString
);
744 *pcbBinary
= cchString
;
749 static LONG
DecodeAnyA(LPCSTR pszString
, DWORD cchString
,
750 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
754 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
756 if (ret
== ERROR_INVALID_DATA
)
757 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
759 if (ret
== ERROR_INVALID_DATA
)
760 ret
= DecodeBinaryToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
765 BOOL WINAPI
CryptStringToBinaryA(LPCSTR pszString
,
766 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
767 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
769 StringToBinaryAFunc decoder
;
772 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString
),
773 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
777 SetLastError(ERROR_INVALID_PARAMETER
);
780 /* Only the bottom byte contains valid types */
781 if (dwFlags
& 0xfffffff0)
783 SetLastError(ERROR_INVALID_DATA
);
788 case CRYPT_STRING_BASE64_ANY
:
789 decoder
= Base64AnyToBinaryA
;
791 case CRYPT_STRING_BASE64
:
792 decoder
= Base64ToBinaryA
;
794 case CRYPT_STRING_BASE64HEADER
:
795 decoder
= Base64HeaderToBinaryA
;
797 case CRYPT_STRING_BASE64REQUESTHEADER
:
798 decoder
= Base64RequestHeaderToBinaryA
;
800 case CRYPT_STRING_BASE64X509CRLHEADER
:
801 decoder
= Base64X509HeaderToBinaryA
;
803 case CRYPT_STRING_BINARY
:
804 decoder
= DecodeBinaryToBinaryA
;
806 case CRYPT_STRING_ANY
:
807 decoder
= DecodeAnyA
;
809 case CRYPT_STRING_HEX
:
810 case CRYPT_STRING_HEXASCII
:
811 case CRYPT_STRING_HEXADDR
:
812 case CRYPT_STRING_HEXASCIIADDR
:
813 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
816 SetLastError(ERROR_INVALID_PARAMETER
);
820 cchString
= strlen(pszString
);
821 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
824 return ret
== ERROR_SUCCESS
;
827 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
830 typedef LONG (*StringToBinaryWFunc
)(LPCWSTR pszString
, DWORD cchString
,
831 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
833 static LONG
Base64ToBinaryW(LPCWSTR pszString
, DWORD cchString
,
834 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
836 return Base64ToBinary(pszString
, TRUE
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
839 static LONG
Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString
,
840 DWORD cchString
, BYTE
*pbBinary
,
841 DWORD
*pcbBinary
, DWORD
*pdwSkip
, BOOL exactHeaderAndTrailerMatch
)
844 LPCWSTR header
= CERT_HEADER_START_W
;
845 LPCWSTR trailer
= CERT_TRAILER_START_W
;
847 LPCWSTR headerBegins
;
849 LPCWSTR trailerBegins
;
852 if ((strlenW(header
) + strlenW(trailer
)) > cchString
)
854 return ERROR_INVALID_DATA
;
857 if (!(headerBegins
= strstrW(pszString
, header
)))
859 TRACE("Can't find %s in %s.\n", debugstr_w(header
), debugstr_w(pszString
));
860 return ERROR_INVALID_DATA
;
863 dataBegins
= headerBegins
+ strlenW(header
);
864 if (!exactHeaderAndTrailerMatch
)
866 if ((dataBegins
= strstrW(dataBegins
, CERT_DELIMITER_W
)))
868 dataBegins
+= strlenW(CERT_DELIMITER_W
);
872 return ERROR_INVALID_DATA
;
875 if (*dataBegins
== '\r') dataBegins
++;
876 if (*dataBegins
== '\n') dataBegins
++;
878 if (exactHeaderAndTrailerMatch
)
880 trailerBegins
= pszString
+ cchString
- strlenW(trailer
);
881 if (pszString
[cchString
- 1] == '\n') trailerBegins
--;
882 if (pszString
[cchString
- 2] == '\r') trailerBegins
--;
884 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
885 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
887 if (!strncmpW(trailerBegins
, trailer
, strlenW(trailer
)))
889 return ERROR_INVALID_DATA
;
894 if (!(trailerBegins
= strstrW(dataBegins
, trailer
)))
896 return ERROR_INVALID_DATA
;
898 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
899 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
903 *pdwSkip
= headerBegins
- pszString
;
905 dataLength
= trailerBegins
- dataBegins
;
907 ret
= Base64ToBinaryW(dataBegins
, dataLength
, pbBinary
, pcbBinary
, NULL
,
913 static LONG
Base64HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
914 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
916 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
917 pbBinary
, pcbBinary
, pdwSkip
, FALSE
);
919 if (!ret
&& pdwFlags
)
920 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
924 static LONG
Base64RequestHeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
925 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
927 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
928 pbBinary
, pcbBinary
, pdwSkip
, FALSE
);
930 if (!ret
&& pdwFlags
)
931 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
935 static LONG
Base64X509HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
936 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
938 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
939 pbBinary
, pcbBinary
, pdwSkip
, FALSE
);
941 if (!ret
&& pdwFlags
)
942 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
946 static LONG
Base64AnyToBinaryW(LPCWSTR pszString
, DWORD cchString
,
947 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
951 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
953 if (ret
== ERROR_INVALID_DATA
)
954 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
959 static LONG
DecodeBinaryToBinaryW(LPCWSTR pszString
, DWORD cchString
,
960 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
962 LONG ret
= ERROR_SUCCESS
;
964 if (*pcbBinary
< cchString
)
967 *pcbBinary
= cchString
;
970 ret
= ERROR_INSUFFICIENT_BUFFER
;
971 *pcbBinary
= cchString
;
977 memcpy(pbBinary
, pszString
, cchString
* sizeof(WCHAR
));
978 *pcbBinary
= cchString
* sizeof(WCHAR
);
983 static LONG
DecodeAnyW(LPCWSTR pszString
, DWORD cchString
,
984 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
988 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
990 if (ret
== ERROR_INVALID_DATA
)
991 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
993 if (ret
== ERROR_INVALID_DATA
)
994 ret
= DecodeBinaryToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
999 BOOL WINAPI
CryptStringToBinaryW(LPCWSTR pszString
,
1000 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
1001 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
1003 StringToBinaryWFunc decoder
;
1006 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString
),
1007 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1011 SetLastError(ERROR_INVALID_PARAMETER
);
1014 /* Only the bottom byte contains valid types */
1015 if (dwFlags
& 0xfffffff0)
1017 SetLastError(ERROR_INVALID_DATA
);
1022 case CRYPT_STRING_BASE64_ANY
:
1023 decoder
= Base64AnyToBinaryW
;
1025 case CRYPT_STRING_BASE64
:
1026 decoder
= Base64ToBinaryW
;
1028 case CRYPT_STRING_BASE64HEADER
:
1029 decoder
= Base64HeaderToBinaryW
;
1031 case CRYPT_STRING_BASE64REQUESTHEADER
:
1032 decoder
= Base64RequestHeaderToBinaryW
;
1034 case CRYPT_STRING_BASE64X509CRLHEADER
:
1035 decoder
= Base64X509HeaderToBinaryW
;
1037 case CRYPT_STRING_BINARY
:
1038 decoder
= DecodeBinaryToBinaryW
;
1040 case CRYPT_STRING_ANY
:
1041 decoder
= DecodeAnyW
;
1043 case CRYPT_STRING_HEX
:
1044 case CRYPT_STRING_HEXASCII
:
1045 case CRYPT_STRING_HEXADDR
:
1046 case CRYPT_STRING_HEXASCIIADDR
:
1047 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
1050 SetLastError(ERROR_INVALID_PARAMETER
);
1054 cchString
= strlenW(pszString
);
1055 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1058 return ret
== ERROR_SUCCESS
;