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
22 #include "crypt32_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
26 #define CERT_HEADER "-----BEGIN CERTIFICATE-----"
27 #define CERT_HEADER_START "-----BEGIN "
28 #define CERT_DELIMITER "-----"
29 #define CERT_TRAILER "-----END CERTIFICATE-----"
30 #define CERT_TRAILER_START "-----END "
31 #define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
32 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
33 #define X509_HEADER "-----BEGIN X509 CRL-----"
34 #define X509_TRAILER "-----END X509 CRL-----"
36 static const WCHAR CERT_HEADER_W
[] = {
37 '-','-','-','-','-','B','E','G','I','N',' ','C','E','R','T','I','F','I','C',
38 'A','T','E','-','-','-','-','-',0 };
39 static const WCHAR CERT_HEADER_START_W
[] = {
40 '-','-','-','-','-','B','E','G','I','N',' ',0 };
41 static const WCHAR CERT_DELIMITER_W
[] = {
42 '-','-','-','-','-',0 };
43 static const WCHAR CERT_TRAILER_W
[] = {
44 '-','-','-','-','-','E','N','D',' ','C','E','R','T','I','F','I','C','A','T',
45 'E','-','-','-','-','-',0 };
46 static const WCHAR CERT_TRAILER_START_W
[] = {
47 '-','-','-','-','-','E','N','D',' ',0 };
48 static const WCHAR CERT_REQUEST_HEADER_W
[] = {
49 '-','-','-','-','-','B','E','G','I','N',' ','N','E','W',' ','C','E','R','T',
50 'I','F','I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
51 static const WCHAR CERT_REQUEST_TRAILER_W
[] = {
52 '-','-','-','-','-','E','N','D',' ','N','E','W',' ','C','E','R','T','I','F',
53 'I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
54 static const WCHAR X509_HEADER_W
[] = {
55 '-','-','-','-','-','B','E','G','I','N',' ','X','5','0','9',' ','C','R','L',
56 '-','-','-','-','-',0 };
57 static const WCHAR X509_TRAILER_W
[] = {
58 '-','-','-','-','-','E','N','D',' ','X','5','0','9',' ','C','R','L','-','-',
61 static const char b64
[] =
62 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
64 typedef BOOL (*BinaryToStringAFunc
)(const BYTE
*pbBinary
,
65 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
);
66 typedef BOOL (*BinaryToStringWFunc
)(const BYTE
*pbBinary
,
67 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
);
69 static BOOL
EncodeBinaryToBinaryA(const BYTE
*pbBinary
,
70 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
74 if (*pcchString
< cbBinary
)
77 *pcchString
= cbBinary
;
80 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
81 *pcchString
= cbBinary
;
88 memcpy(pszString
, pbBinary
, cbBinary
);
89 *pcchString
= cbBinary
;
94 static LONG
encodeBase64A(const BYTE
*in_buf
, int in_len
, LPCSTR sep
,
95 char* out_buf
, DWORD
*out_len
)
98 const BYTE
*d
= in_buf
;
99 int bytes
= (in_len
*8 + 5)/6, pad_bytes
= (bytes
% 4) ? 4 - (bytes
% 4) : 0;
103 TRACE("bytes is %d, pad bytes is %d\n", bytes
, pad_bytes
);
104 needed
= bytes
+ pad_bytes
+ 1;
105 needed
+= (needed
/ 64 + 1) * strlen(sep
);
107 if (needed
> *out_len
)
110 return ERROR_INSUFFICIENT_BUFFER
;
115 /* Three bytes of input give 4 chars of output */
122 if (i
&& i
% 64 == 0)
127 /* first char is the first 6 bits of the first byte*/
128 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
129 /* second char is the last 2 bits of the first byte and the first 4
130 * bits of the second byte */
131 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
132 /* third char is the last 4 bits of the second byte and the first 2
133 * bits of the third byte */
134 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) | (d
[2] >> 6 & 0x03)];
135 /* fourth char is the remaining 6 bits of the third byte */
136 *ptr
++ = b64
[ d
[2] & 0x3f];
145 /* first char is the first 6 bits of the first byte*/
146 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
147 /* second char is the last 2 bits of the first byte and the first 4
148 * bits of the second byte */
149 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
150 /* third char is the last 4 bits of the second byte padded with
152 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) ];
153 /* fourth char is a = to indicate one byte of padding */
157 /* first char is the first 6 bits of the first byte*/
158 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
159 /* second char is the last 2 bits of the first byte padded with
161 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30)];
162 /* third char is = to indicate padding */
164 /* fourth char is = to indicate padding */
170 return ERROR_SUCCESS
;
173 static BOOL
BinaryToBase64A(const BYTE
*pbBinary
,
174 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
176 static const char crlf
[] = "\r\n", lf
[] = "\n";
178 LPCSTR header
= NULL
, trailer
= NULL
, sep
;
181 if (dwFlags
& CRYPT_STRING_NOCR
)
183 else if (dwFlags
& CRYPT_STRING_NOCRLF
)
187 switch (dwFlags
& 0x0fffffff)
189 case CRYPT_STRING_BASE64
:
190 /* no header or footer */
192 case CRYPT_STRING_BASE64HEADER
:
193 header
= CERT_HEADER
;
194 trailer
= CERT_TRAILER
;
196 case CRYPT_STRING_BASE64REQUESTHEADER
:
197 header
= CERT_REQUEST_HEADER
;
198 trailer
= CERT_REQUEST_TRAILER
;
200 case CRYPT_STRING_BASE64X509CRLHEADER
:
201 header
= X509_HEADER
;
202 trailer
= X509_TRAILER
;
207 encodeBase64A(pbBinary
, cbBinary
, sep
, NULL
, &charsNeeded
);
209 charsNeeded
+= strlen(header
) + strlen(sep
);
211 charsNeeded
+= strlen(trailer
) + strlen(sep
);
212 if (charsNeeded
<= *pcchString
)
214 LPSTR ptr
= pszString
;
215 DWORD size
= charsNeeded
;
224 encodeBase64A(pbBinary
, cbBinary
, sep
, ptr
, &size
);
228 strcpy(ptr
, trailer
);
232 *pcchString
= charsNeeded
- 1;
236 *pcchString
= charsNeeded
;
237 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
241 *pcchString
= charsNeeded
;
245 BOOL WINAPI
CryptBinaryToStringA(const BYTE
*pbBinary
,
246 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
248 BinaryToStringAFunc encoder
= NULL
;
250 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
255 SetLastError(ERROR_INVALID_PARAMETER
);
260 SetLastError(ERROR_INVALID_PARAMETER
);
264 switch (dwFlags
& 0x0fffffff)
266 case CRYPT_STRING_BINARY
:
267 encoder
= EncodeBinaryToBinaryA
;
269 case CRYPT_STRING_BASE64
:
270 case CRYPT_STRING_BASE64HEADER
:
271 case CRYPT_STRING_BASE64REQUESTHEADER
:
272 case CRYPT_STRING_BASE64X509CRLHEADER
:
273 encoder
= BinaryToBase64A
;
275 case CRYPT_STRING_HEX
:
276 case CRYPT_STRING_HEXASCII
:
277 case CRYPT_STRING_HEXADDR
:
278 case CRYPT_STRING_HEXASCIIADDR
:
279 FIXME("Unimplemented type %d\n", dwFlags
& 0x0fffffff);
282 SetLastError(ERROR_INVALID_PARAMETER
);
285 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
288 static LONG
encodeBase64W(const BYTE
*in_buf
, int in_len
, LPCWSTR sep
,
289 WCHAR
* out_buf
, DWORD
*out_len
)
292 const BYTE
*d
= in_buf
;
293 int bytes
= (in_len
*8 + 5)/6, pad_bytes
= (bytes
% 4) ? 4 - (bytes
% 4) : 0;
297 TRACE("bytes is %d, pad bytes is %d\n", bytes
, pad_bytes
);
298 needed
= bytes
+ pad_bytes
+ 1;
299 needed
+= (needed
/ 64 + 1) * strlenW(sep
);
301 if (needed
> *out_len
)
304 return ERROR_INSUFFICIENT_BUFFER
;
309 /* Three bytes of input give 4 chars of output */
316 if (i
&& i
% 64 == 0)
321 /* first char is the first 6 bits of the first byte*/
322 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
323 /* second char is the last 2 bits of the first byte and the first 4
324 * bits of the second byte */
325 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
326 /* third char is the last 4 bits of the second byte and the first 2
327 * bits of the third byte */
328 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) | (d
[2] >> 6 & 0x03)];
329 /* fourth char is the remaining 6 bits of the third byte */
330 *ptr
++ = b64
[ d
[2] & 0x3f];
339 /* first char is the first 6 bits of the first byte*/
340 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
341 /* second char is the last 2 bits of the first byte and the first 4
342 * bits of the second byte */
343 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
344 /* third char is the last 4 bits of the second byte padded with
346 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) ];
347 /* fourth char is a = to indicate one byte of padding */
351 /* first char is the first 6 bits of the first byte*/
352 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
353 /* second char is the last 2 bits of the first byte padded with
355 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30)];
356 /* third char is = to indicate padding */
358 /* fourth char is = to indicate padding */
364 return ERROR_SUCCESS
;
367 static BOOL
BinaryToBase64W(const BYTE
*pbBinary
,
368 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
370 static const WCHAR crlf
[] = { '\r','\n',0 }, lf
[] = { '\n',0 }, empty
[] = {0};
372 LPCWSTR header
= NULL
, trailer
= NULL
, sep
;
375 if (dwFlags
& CRYPT_STRING_NOCR
)
377 else if (dwFlags
& CRYPT_STRING_NOCRLF
)
381 switch (dwFlags
& 0x0fffffff)
383 case CRYPT_STRING_BASE64
:
384 /* no header or footer */
386 case CRYPT_STRING_BASE64HEADER
:
387 header
= CERT_HEADER_W
;
388 trailer
= CERT_TRAILER_W
;
390 case CRYPT_STRING_BASE64REQUESTHEADER
:
391 header
= CERT_REQUEST_HEADER_W
;
392 trailer
= CERT_REQUEST_TRAILER_W
;
394 case CRYPT_STRING_BASE64X509CRLHEADER
:
395 header
= X509_HEADER_W
;
396 trailer
= X509_TRAILER_W
;
401 encodeBase64W(pbBinary
, cbBinary
, sep
, NULL
, &charsNeeded
);
403 charsNeeded
+= strlenW(header
) + strlenW(sep
);
405 charsNeeded
+= strlenW(trailer
) + strlenW(sep
);
406 if (charsNeeded
<= *pcchString
)
408 LPWSTR ptr
= pszString
;
409 DWORD size
= charsNeeded
;
413 strcpyW(ptr
, header
);
418 encodeBase64W(pbBinary
, cbBinary
, sep
, ptr
, &size
);
422 strcpyW(ptr
, trailer
);
426 *pcchString
= charsNeeded
- 1;
430 *pcchString
= charsNeeded
;
431 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
435 *pcchString
= charsNeeded
;
439 BOOL WINAPI
CryptBinaryToStringW(const BYTE
*pbBinary
,
440 DWORD cbBinary
, DWORD dwFlags
, LPWSTR pszString
, DWORD
*pcchString
)
442 BinaryToStringWFunc encoder
= NULL
;
444 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
449 SetLastError(ERROR_INVALID_PARAMETER
);
454 SetLastError(ERROR_INVALID_PARAMETER
);
458 switch (dwFlags
& 0x0fffffff)
460 case CRYPT_STRING_BASE64
:
461 case CRYPT_STRING_BASE64HEADER
:
462 case CRYPT_STRING_BASE64REQUESTHEADER
:
463 case CRYPT_STRING_BASE64X509CRLHEADER
:
464 encoder
= BinaryToBase64W
;
466 case CRYPT_STRING_BINARY
:
467 case CRYPT_STRING_HEX
:
468 case CRYPT_STRING_HEXASCII
:
469 case CRYPT_STRING_HEXADDR
:
470 case CRYPT_STRING_HEXASCIIADDR
:
471 FIXME("Unimplemented type %d\n", dwFlags
& 0x0fffffff);
474 SetLastError(ERROR_INVALID_PARAMETER
);
477 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
480 #define BASE64_DECODE_PADDING 0x100
481 #define BASE64_DECODE_WHITESPACE 0x200
482 #define BASE64_DECODE_INVALID 0x300
484 static inline int decodeBase64Byte(int c
)
486 int ret
= BASE64_DECODE_INVALID
;
488 if (c
>= 'A' && c
<= 'Z')
490 else if (c
>= 'a' && c
<= 'z')
492 else if (c
>= '0' && c
<= '9')
499 ret
= BASE64_DECODE_PADDING
;
500 else if (c
== ' ' || c
== '\t' || c
== '\r' || c
== '\n')
501 ret
= BASE64_DECODE_WHITESPACE
;
505 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
508 typedef LONG (*StringToBinaryAFunc
)(LPCSTR pszString
, DWORD cchString
,
509 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
511 static LONG
Base64ToBinary(const void* pszString
, BOOL wide
, DWORD cchString
,
512 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
514 DWORD cbIn
, cbValid
, cbOut
, hasPadding
;
516 for (cbIn
= cbValid
= cbOut
= hasPadding
= 0; cbIn
< cchString
; ++cbIn
)
518 int c
= wide
? (int)((WCHAR
*)pszString
)[cbIn
] : (int)((char*)pszString
)[cbIn
];
519 int d
= decodeBase64Byte(c
);
520 if (d
== BASE64_DECODE_INVALID
)
522 if (d
== BASE64_DECODE_WHITESPACE
)
525 /* When padding starts, data is not acceptable */
526 if (hasPadding
&& d
!= BASE64_DECODE_PADDING
)
529 /* Padding after a full block (like "VVVV=") is ok and stops decoding */
530 if (d
== BASE64_DECODE_PADDING
&& (cbValid
& 3) == 0)
535 if (d
== BASE64_DECODE_PADDING
)
538 /* When padding reaches a full block, stop decoding */
539 if ((cbValid
& 3) == 0)
544 /* cbOut is incremented in the 4-char block as follows: "1-23" */
545 if ((cbValid
& 3) != 2)
548 /* Fail if the block has bad padding; omitting padding is fine */
549 if ((cbValid
& 3) != 0 && hasPadding
)
551 /* Check available buffer size */
552 if (pbBinary
&& *pcbBinary
&& cbOut
> *pcbBinary
)
554 /* Convert the data; this step depends on the validity checks above! */
555 if (pbBinary
) for (cbIn
= cbValid
= cbOut
= 0; cbIn
< cchString
; ++cbIn
)
557 int c
= wide
? (int)((WCHAR
*)pszString
)[cbIn
] : (int)((char*)pszString
)[cbIn
];
558 int d
= decodeBase64Byte(c
);
559 if (d
== BASE64_DECODE_WHITESPACE
)
561 if (d
== BASE64_DECODE_PADDING
)
563 block
[cbValid
& 3] = d
;
565 switch (cbValid
& 3) {
567 pbBinary
[cbOut
++] = (block
[0] << 2);
570 pbBinary
[cbOut
-1] = (block
[0] << 2) | (block
[1] >> 4);
573 pbBinary
[cbOut
++] = (block
[1] << 4) | (block
[2] >> 2);
576 pbBinary
[cbOut
++] = (block
[2] << 6) | (block
[3] >> 0);
584 *pdwFlags
= CRYPT_STRING_BASE64
;
585 return ERROR_SUCCESS
;
587 return ERROR_INSUFFICIENT_BUFFER
;
590 return ERROR_INVALID_DATA
;
593 static LONG
Base64ToBinaryA(LPCSTR pszString
, DWORD cchString
,
594 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
596 return Base64ToBinary(pszString
, FALSE
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
599 static LONG
Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString
,
600 DWORD cchString
, BYTE
*pbBinary
,
601 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
604 LPCSTR header
= CERT_HEADER_START
;
605 LPCSTR trailer
= CERT_TRAILER_START
;
609 LPCSTR trailerBegins
;
612 if ((strlen(header
) + strlen(trailer
)) > cchString
)
614 return ERROR_INVALID_DATA
;
617 if (!(headerBegins
= strstr(pszString
, header
)))
619 TRACE("Can't find %s in %s.\n", header
, pszString
);
620 return ERROR_INVALID_DATA
;
623 dataBegins
= headerBegins
+ strlen(header
);
624 if (!(dataBegins
= strstr(dataBegins
, CERT_DELIMITER
)))
626 return ERROR_INVALID_DATA
;
628 dataBegins
+= strlen(CERT_DELIMITER
);
629 if (*dataBegins
== '\r') dataBegins
++;
630 if (*dataBegins
== '\n') dataBegins
++;
632 if (!(trailerBegins
= strstr(dataBegins
, trailer
)))
634 return ERROR_INVALID_DATA
;
636 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
637 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
640 *pdwSkip
= headerBegins
- pszString
;
642 dataLength
= trailerBegins
- dataBegins
;
644 ret
= Base64ToBinaryA(dataBegins
, dataLength
, pbBinary
, pcbBinary
, NULL
,
650 static LONG
Base64HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
651 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
653 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
654 pbBinary
, pcbBinary
, pdwSkip
);
656 if (!ret
&& pdwFlags
)
657 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
661 static LONG
Base64RequestHeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
662 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
664 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
665 pbBinary
, pcbBinary
, pdwSkip
);
667 if (!ret
&& pdwFlags
)
668 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
672 static LONG
Base64X509HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
673 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
675 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
676 pbBinary
, pcbBinary
, pdwSkip
);
678 if (!ret
&& pdwFlags
)
679 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
683 static LONG
Base64AnyToBinaryA(LPCSTR pszString
, DWORD cchString
,
684 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
688 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
690 if (ret
== ERROR_INVALID_DATA
)
691 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
696 static LONG
DecodeBinaryToBinaryA(LPCSTR pszString
, DWORD cchString
,
697 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
699 LONG ret
= ERROR_SUCCESS
;
701 if (*pcbBinary
< cchString
)
704 *pcbBinary
= cchString
;
707 ret
= ERROR_INSUFFICIENT_BUFFER
;
708 *pcbBinary
= cchString
;
714 memcpy(pbBinary
, pszString
, cchString
);
715 *pcbBinary
= cchString
;
720 static LONG
DecodeAnyA(LPCSTR pszString
, DWORD cchString
,
721 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
725 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
727 if (ret
== ERROR_INVALID_DATA
)
728 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
730 if (ret
== ERROR_INVALID_DATA
)
731 ret
= DecodeBinaryToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
736 BOOL WINAPI
CryptStringToBinaryA(LPCSTR pszString
,
737 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
738 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
740 StringToBinaryAFunc decoder
;
743 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString
),
744 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
748 SetLastError(ERROR_INVALID_PARAMETER
);
751 /* Only the bottom byte contains valid types */
752 if (dwFlags
& 0xfffffff0)
754 SetLastError(ERROR_INVALID_DATA
);
759 case CRYPT_STRING_BASE64_ANY
:
760 decoder
= Base64AnyToBinaryA
;
762 case CRYPT_STRING_BASE64
:
763 decoder
= Base64ToBinaryA
;
765 case CRYPT_STRING_BASE64HEADER
:
766 decoder
= Base64HeaderToBinaryA
;
768 case CRYPT_STRING_BASE64REQUESTHEADER
:
769 decoder
= Base64RequestHeaderToBinaryA
;
771 case CRYPT_STRING_BASE64X509CRLHEADER
:
772 decoder
= Base64X509HeaderToBinaryA
;
774 case CRYPT_STRING_BINARY
:
775 decoder
= DecodeBinaryToBinaryA
;
777 case CRYPT_STRING_ANY
:
778 decoder
= DecodeAnyA
;
780 case CRYPT_STRING_HEX
:
781 case CRYPT_STRING_HEXASCII
:
782 case CRYPT_STRING_HEXADDR
:
783 case CRYPT_STRING_HEXASCIIADDR
:
784 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
787 SetLastError(ERROR_INVALID_PARAMETER
);
791 cchString
= strlen(pszString
);
792 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
795 return ret
== ERROR_SUCCESS
;
798 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
801 typedef LONG (*StringToBinaryWFunc
)(LPCWSTR pszString
, DWORD cchString
,
802 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
804 static LONG
Base64ToBinaryW(LPCWSTR pszString
, DWORD cchString
,
805 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
807 return Base64ToBinary(pszString
, TRUE
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
810 static LONG
Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString
,
811 DWORD cchString
, BYTE
*pbBinary
,
812 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
815 LPCWSTR header
= CERT_HEADER_START_W
;
816 LPCWSTR trailer
= CERT_TRAILER_START_W
;
818 LPCWSTR headerBegins
;
820 LPCWSTR trailerBegins
;
823 if ((strlenW(header
) + strlenW(trailer
)) > cchString
)
825 return ERROR_INVALID_DATA
;
828 if (!(headerBegins
= strstrW(pszString
, header
)))
830 TRACE("Can't find %s in %s.\n", debugstr_w(header
), debugstr_w(pszString
));
831 return ERROR_INVALID_DATA
;
834 dataBegins
= headerBegins
+ strlenW(header
);
835 if (!(dataBegins
= strstrW(dataBegins
, CERT_DELIMITER_W
)))
837 return ERROR_INVALID_DATA
;
839 dataBegins
+= strlenW(CERT_DELIMITER_W
);
840 if (*dataBegins
== '\r') dataBegins
++;
841 if (*dataBegins
== '\n') dataBegins
++;
843 if (!(trailerBegins
= strstrW(dataBegins
, trailer
)))
845 return ERROR_INVALID_DATA
;
847 if (*(trailerBegins
-1) == '\n') trailerBegins
--;
848 if (*(trailerBegins
-1) == '\r') trailerBegins
--;
851 *pdwSkip
= headerBegins
- pszString
;
853 dataLength
= trailerBegins
- dataBegins
;
855 ret
= Base64ToBinaryW(dataBegins
, dataLength
, pbBinary
, pcbBinary
, NULL
,
861 static LONG
Base64HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
862 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
864 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
865 pbBinary
, pcbBinary
, pdwSkip
);
867 if (!ret
&& pdwFlags
)
868 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
872 static LONG
Base64RequestHeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
873 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
875 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
876 pbBinary
, pcbBinary
, pdwSkip
);
878 if (!ret
&& pdwFlags
)
879 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
883 static LONG
Base64X509HeaderToBinaryW(LPCWSTR pszString
, DWORD cchString
,
884 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
886 LONG ret
= Base64WithHeaderAndTrailerToBinaryW(pszString
, cchString
,
887 pbBinary
, pcbBinary
, pdwSkip
);
889 if (!ret
&& pdwFlags
)
890 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
894 static LONG
Base64AnyToBinaryW(LPCWSTR pszString
, DWORD cchString
,
895 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
899 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
901 if (ret
== ERROR_INVALID_DATA
)
902 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
907 static LONG
DecodeBinaryToBinaryW(LPCWSTR pszString
, DWORD cchString
,
908 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
910 LONG ret
= ERROR_SUCCESS
;
912 if (*pcbBinary
< cchString
)
915 *pcbBinary
= cchString
;
918 ret
= ERROR_INSUFFICIENT_BUFFER
;
919 *pcbBinary
= cchString
;
925 memcpy(pbBinary
, pszString
, cchString
* sizeof(WCHAR
));
926 *pcbBinary
= cchString
* sizeof(WCHAR
);
931 static LONG
DecodeAnyW(LPCWSTR pszString
, DWORD cchString
,
932 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
936 ret
= Base64HeaderToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
938 if (ret
== ERROR_INVALID_DATA
)
939 ret
= Base64ToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
941 if (ret
== ERROR_INVALID_DATA
)
942 ret
= DecodeBinaryToBinaryW(pszString
, cchString
, pbBinary
, pcbBinary
,
947 BOOL WINAPI
CryptStringToBinaryW(LPCWSTR pszString
,
948 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
949 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
951 StringToBinaryWFunc decoder
;
954 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString
),
955 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
959 SetLastError(ERROR_INVALID_PARAMETER
);
962 /* Only the bottom byte contains valid types */
963 if (dwFlags
& 0xfffffff0)
965 SetLastError(ERROR_INVALID_DATA
);
970 case CRYPT_STRING_BASE64_ANY
:
971 decoder
= Base64AnyToBinaryW
;
973 case CRYPT_STRING_BASE64
:
974 decoder
= Base64ToBinaryW
;
976 case CRYPT_STRING_BASE64HEADER
:
977 decoder
= Base64HeaderToBinaryW
;
979 case CRYPT_STRING_BASE64REQUESTHEADER
:
980 decoder
= Base64RequestHeaderToBinaryW
;
982 case CRYPT_STRING_BASE64X509CRLHEADER
:
983 decoder
= Base64X509HeaderToBinaryW
;
985 case CRYPT_STRING_BINARY
:
986 decoder
= DecodeBinaryToBinaryW
;
988 case CRYPT_STRING_ANY
:
989 decoder
= DecodeAnyW
;
991 case CRYPT_STRING_HEX
:
992 case CRYPT_STRING_HEXASCII
:
993 case CRYPT_STRING_HEXADDR
:
994 case CRYPT_STRING_HEXASCIIADDR
:
995 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
998 SetLastError(ERROR_INVALID_PARAMETER
);
1002 cchString
= strlenW(pszString
);
1003 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
1006 return ret
== ERROR_SUCCESS
;