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 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_TRAILER "-----END CERTIFICATE-----"
33 #define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
34 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
35 #define X509_HEADER "-----BEGIN X509 CRL-----"
36 #define X509_TRAILER "-----END X509 CRL-----"
38 static const char b64
[] =
39 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
41 typedef BOOL (*BinaryToStringAFunc
)(const BYTE
*pbBinary
,
42 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
);
44 static BOOL
EncodeBinaryToBinaryA(const BYTE
*pbBinary
,
45 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
49 if (*pcchString
< cbBinary
)
52 *pcchString
= cbBinary
;
55 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
56 *pcchString
= cbBinary
;
63 memcpy(pszString
, pbBinary
, cbBinary
);
64 *pcchString
= cbBinary
;
69 static LONG
encodeBase64A(const BYTE
*in_buf
, int in_len
, LPCSTR sep
,
70 char* out_buf
, DWORD
*out_len
)
73 const BYTE
*d
= in_buf
;
74 int bytes
= (in_len
*8 + 5)/6, pad_bytes
= (bytes
% 4) ? 4 - (bytes
% 4) : 0;
78 TRACE("bytes is %d, pad bytes is %d\n", bytes
, pad_bytes
);
79 needed
= bytes
+ pad_bytes
+ 1;
80 needed
+= (needed
/ 64 + 1) * strlen(sep
);
82 if (needed
> *out_len
)
85 return ERROR_INSUFFICIENT_BUFFER
;
90 /* Three bytes of input give 4 chars of output */
102 /* first char is the first 6 bits of the first byte*/
103 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
104 /* second char is the last 2 bits of the first byte and the first 4
105 * bits of the second byte */
106 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
107 /* third char is the last 4 bits of the second byte and the first 2
108 * bits of the third byte */
109 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) | (d
[2] >> 6 & 0x03)];
110 /* fourth char is the remaining 6 bits of the third byte */
111 *ptr
++ = b64
[ d
[2] & 0x3f];
120 /* first char is the first 6 bits of the first byte*/
121 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
122 /* second char is the last 2 bits of the first byte and the first 4
123 * bits of the second byte */
124 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30) | (d
[1] >> 4 & 0x0f)];
125 /* third char is the last 4 bits of the second byte padded with
127 *ptr
++ = b64
[ ((d
[1] << 2) & 0x3c) ];
128 /* fourth char is a = to indicate one byte of padding */
132 /* first char is the first 6 bits of the first byte*/
133 *ptr
++ = b64
[ ( d
[0] >> 2) & 0x3f ];
134 /* second char is the last 2 bits of the first byte padded with
136 *ptr
++ = b64
[ ((d
[0] << 4) & 0x30)];
137 /* third char is = to indicate padding */
139 /* fourth char is = to indicate padding */
145 return ERROR_SUCCESS
;
148 static BOOL
BinaryToBase64A(const BYTE
*pbBinary
,
149 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
151 static const char crlf
[] = "\r\n", lf
[] = "\n";
153 LPCSTR header
= NULL
, trailer
= NULL
, sep
= NULL
;
156 if (dwFlags
& CRYPT_STRING_NOCR
)
160 switch (dwFlags
& 0x7fffffff)
162 case CRYPT_STRING_BASE64
:
163 /* no header or footer */
165 case CRYPT_STRING_BASE64HEADER
:
166 header
= CERT_HEADER
;
167 trailer
= CERT_TRAILER
;
169 case CRYPT_STRING_BASE64REQUESTHEADER
:
170 header
= CERT_REQUEST_HEADER
;
171 trailer
= CERT_REQUEST_TRAILER
;
173 case CRYPT_STRING_BASE64X509CRLHEADER
:
174 header
= X509_HEADER
;
175 trailer
= X509_TRAILER
;
180 encodeBase64A(pbBinary
, cbBinary
, sep
, NULL
, &charsNeeded
);
181 charsNeeded
+= strlen(sep
);
183 charsNeeded
+= strlen(header
) + strlen(sep
);
185 charsNeeded
+= strlen(trailer
) + strlen(sep
);
186 if (charsNeeded
<= *pcchString
)
188 LPSTR ptr
= pszString
;
189 DWORD size
= charsNeeded
;
198 encodeBase64A(pbBinary
, cbBinary
, sep
, ptr
, &size
);
202 strcpy(ptr
, trailer
);
207 *pcchString
= charsNeeded
- 1;
211 *pcchString
= charsNeeded
;
212 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
216 *pcchString
= charsNeeded
;
220 BOOL WINAPI
CryptBinaryToStringA(const BYTE
*pbBinary
,
221 DWORD cbBinary
, DWORD dwFlags
, LPSTR pszString
, DWORD
*pcchString
)
223 BinaryToStringAFunc encoder
= NULL
;
225 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary
, cbBinary
, dwFlags
, pszString
,
230 SetLastError(ERROR_INVALID_PARAMETER
);
235 SetLastError(ERROR_INVALID_PARAMETER
);
239 switch (dwFlags
& 0x7fffffff)
241 case CRYPT_STRING_BINARY
:
242 encoder
= EncodeBinaryToBinaryA
;
244 case CRYPT_STRING_BASE64
:
245 case CRYPT_STRING_BASE64HEADER
:
246 case CRYPT_STRING_BASE64REQUESTHEADER
:
247 case CRYPT_STRING_BASE64X509CRLHEADER
:
248 encoder
= BinaryToBase64A
;
250 case CRYPT_STRING_HEX
:
251 case CRYPT_STRING_HEXASCII
:
252 case CRYPT_STRING_HEXADDR
:
253 case CRYPT_STRING_HEXASCIIADDR
:
254 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
257 SetLastError(ERROR_INVALID_PARAMETER
);
260 return encoder(pbBinary
, cbBinary
, dwFlags
, pszString
, pcchString
);
263 static inline BYTE
decodeBase64Byte(char c
)
267 if (c
>= 'A' && c
<= 'Z')
269 else if (c
>= 'a' && c
<= 'z')
271 else if (c
>= '0' && c
<= '9')
282 static LONG
decodeBase64Block(const char *in_buf
, int in_len
,
283 const char **nextBlock
, PBYTE out_buf
, DWORD
*out_len
)
286 const char *d
= in_buf
;
287 int ip0
, ip1
, ip2
, ip3
;
290 return ERROR_INVALID_DATA
;
295 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
296 return ERROR_INVALID_DATA
;
297 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
298 return ERROR_INVALID_DATA
;
301 out_buf
[i
] = (ip0
<< 2) | (ip1
>> 4);
304 else if (d
[3] == '=')
306 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
307 return ERROR_INVALID_DATA
;
308 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
309 return ERROR_INVALID_DATA
;
310 if ((ip2
= decodeBase64Byte(d
[2])) > 63)
311 return ERROR_INVALID_DATA
;
315 out_buf
[i
+ 0] = (ip0
<< 2) | (ip1
>> 4);
316 out_buf
[i
+ 1] = (ip1
<< 4) | (ip2
>> 2);
322 if ((ip0
= decodeBase64Byte(d
[0])) > 63)
323 return ERROR_INVALID_DATA
;
324 if ((ip1
= decodeBase64Byte(d
[1])) > 63)
325 return ERROR_INVALID_DATA
;
326 if ((ip2
= decodeBase64Byte(d
[2])) > 63)
327 return ERROR_INVALID_DATA
;
328 if ((ip3
= decodeBase64Byte(d
[3])) > 63)
329 return ERROR_INVALID_DATA
;
333 out_buf
[i
+ 0] = (ip0
<< 2) | (ip1
>> 4);
334 out_buf
[i
+ 1] = (ip1
<< 4) | (ip2
>> 2);
335 out_buf
[i
+ 2] = (ip2
<< 6) | ip3
;
339 if (len
>= 6 && d
[4] == '\r' && d
[5] == '\n')
341 else if (len
>= 5 && d
[4] == '\n')
343 else if (len
>= 4 && d
[4])
348 return ERROR_SUCCESS
;
351 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
354 typedef LONG (*StringToBinaryAFunc
)(LPCSTR pszString
, DWORD cchString
,
355 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
);
357 static LONG
Base64ToBinaryA(LPCSTR pszString
, DWORD cchString
,
358 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
360 LONG ret
= ERROR_SUCCESS
;
361 const char *nextBlock
;
364 nextBlock
= pszString
;
365 while (nextBlock
&& !ret
)
369 ret
= decodeBase64Block(nextBlock
, cchString
- (nextBlock
- pszString
),
370 &nextBlock
, pbBinary
? pbBinary
+ outLen
: NULL
, &len
);
373 if (cchString
- (nextBlock
- pszString
) <= 0)
382 *pdwFlags
= CRYPT_STRING_BASE64
;
384 else if (ret
== ERROR_INSUFFICIENT_BUFFER
)
392 static LONG
Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString
,
393 DWORD cchString
, LPCSTR header
, LPCSTR trailer
, BYTE
*pbBinary
,
394 DWORD
*pcbBinary
, DWORD
*pdwSkip
)
399 if (cchString
> strlen(header
) + strlen(trailer
)
400 && (ptr
= strstr(pszString
, header
)) != NULL
)
402 LPCSTR trailerSpot
= pszString
+ cchString
- strlen(trailer
);
404 if (pszString
[cchString
- 1] == '\n')
409 if (pszString
[cchString
- 1] == '\r')
414 if (!strncmp(trailerSpot
, trailer
, strlen(trailer
)))
417 *pdwSkip
= ptr
- pszString
;
418 ptr
+= strlen(header
);
419 if (*ptr
== '\r') ptr
++;
420 if (*ptr
== '\n') ptr
++;
421 cchString
-= ptr
- pszString
+ strlen(trailer
);
422 ret
= Base64ToBinaryA(ptr
, cchString
, pbBinary
, pcbBinary
, NULL
,
426 ret
= ERROR_INVALID_DATA
;
429 ret
= ERROR_INVALID_DATA
;
433 static LONG
Base64HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
434 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
436 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
437 CERT_HEADER
, CERT_TRAILER
, pbBinary
, pcbBinary
, pdwSkip
);
439 if (!ret
&& pdwFlags
)
440 *pdwFlags
= CRYPT_STRING_BASE64HEADER
;
444 static LONG
Base64RequestHeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
445 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
447 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
448 CERT_REQUEST_HEADER
, CERT_REQUEST_TRAILER
, pbBinary
, pcbBinary
, pdwSkip
);
450 if (!ret
&& pdwFlags
)
451 *pdwFlags
= CRYPT_STRING_BASE64REQUESTHEADER
;
455 static LONG
Base64X509HeaderToBinaryA(LPCSTR pszString
, DWORD cchString
,
456 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
458 LONG ret
= Base64WithHeaderAndTrailerToBinaryA(pszString
, cchString
,
459 X509_HEADER
, X509_TRAILER
, pbBinary
, pcbBinary
, pdwSkip
);
461 if (!ret
&& pdwFlags
)
462 *pdwFlags
= CRYPT_STRING_BASE64X509CRLHEADER
;
466 static LONG
Base64AnyToBinaryA(LPCSTR pszString
, DWORD cchString
,
467 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
471 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
473 if (ret
== ERROR_INVALID_DATA
)
474 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
479 static LONG
DecodeBinaryToBinaryA(LPCSTR pszString
, DWORD cchString
,
480 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
482 LONG ret
= ERROR_SUCCESS
;
484 if (*pcbBinary
< cchString
)
487 *pcbBinary
= cchString
;
490 ret
= ERROR_INSUFFICIENT_BUFFER
;
491 *pcbBinary
= cchString
;
497 memcpy(pbBinary
, pszString
, cchString
);
498 *pcbBinary
= cchString
;
503 static LONG
DecodeAnyA(LPCSTR pszString
, DWORD cchString
,
504 BYTE
*pbBinary
, DWORD
*pcbBinary
, DWORD
*pdwSkip
, DWORD
*pdwFlags
)
508 ret
= Base64HeaderToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
510 if (ret
== ERROR_INVALID_DATA
)
511 ret
= Base64ToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
513 if (ret
== ERROR_INVALID_DATA
)
514 ret
= DecodeBinaryToBinaryA(pszString
, cchString
, pbBinary
, pcbBinary
,
519 BOOL WINAPI
CryptStringToBinaryA(LPCSTR pszString
,
520 DWORD cchString
, DWORD dwFlags
, BYTE
*pbBinary
, DWORD
*pcbBinary
,
521 DWORD
*pdwSkip
, DWORD
*pdwFlags
)
523 StringToBinaryAFunc decoder
;
526 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString
),
527 cchString
, dwFlags
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
531 SetLastError(ERROR_INVALID_PARAMETER
);
534 /* Only the bottom byte contains valid types */
535 if (dwFlags
& 0xfffffff0)
537 SetLastError(ERROR_INVALID_DATA
);
542 case CRYPT_STRING_BASE64_ANY
:
543 decoder
= Base64AnyToBinaryA
;
545 case CRYPT_STRING_BASE64
:
546 decoder
= Base64ToBinaryA
;
548 case CRYPT_STRING_BASE64HEADER
:
549 decoder
= Base64HeaderToBinaryA
;
551 case CRYPT_STRING_BASE64REQUESTHEADER
:
552 decoder
= Base64RequestHeaderToBinaryA
;
554 case CRYPT_STRING_BASE64X509CRLHEADER
:
555 decoder
= Base64X509HeaderToBinaryA
;
557 case CRYPT_STRING_BINARY
:
558 decoder
= DecodeBinaryToBinaryA
;
560 case CRYPT_STRING_ANY
:
561 decoder
= DecodeAnyA
;
563 case CRYPT_STRING_HEX
:
564 case CRYPT_STRING_HEXASCII
:
565 case CRYPT_STRING_HEXADDR
:
566 case CRYPT_STRING_HEXASCIIADDR
:
567 FIXME("Unimplemented type %d\n", dwFlags
& 0x7fffffff);
570 SetLastError(ERROR_INVALID_PARAMETER
);
574 cchString
= strlen(pszString
);
575 ret
= decoder(pszString
, cchString
, pbBinary
, pcbBinary
, pdwSkip
, pdwFlags
);
578 return (ret
== ERROR_SUCCESS
) ? TRUE
: FALSE
;