winemac.drv: Don't filter non active displays out.
[wine/zf.git] / dlls / crypt32 / base64.c
blob0e8bd2227eb198693f48b64efaf4733e587678b9
1 /*
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 <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winerror.h"
26 #include "wincrypt.h"
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)
62 BOOL ret = TRUE;
64 if (pszString)
66 if (*pcchString < cbBinary)
68 SetLastError(ERROR_INSUFFICIENT_BUFFER);
69 ret = FALSE;
71 else if (cbBinary)
72 memcpy(pszString, pbBinary, cbBinary);
74 else
75 *pcchString = cbBinary;
77 return ret;
80 static DWORD stradd(LPSTR ptr, LPCSTR end, LPCSTR s, DWORD slen)
82 if (ptr + slen > end)
83 slen = end - ptr;
84 memcpy(ptr, s, slen);
85 return slen;
88 static DWORD encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
89 char* out_buf, DWORD *out_len)
91 int div, i;
92 const BYTE *d = in_buf;
93 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
94 LPSTR ptr;
95 LPCSTR end;
96 char chunk[4];
98 if (!out_buf)
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;
103 return 0;
106 /* Three bytes of input give 4 chars of output */
107 div = in_len / 3;
109 ptr = out_buf;
110 end = ptr + *out_len;
111 i = 0;
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);
127 i += 4;
128 d += 3;
129 div--;
132 switch(pad_bytes)
134 case 1:
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
141 * two zeroes */
142 chunk[2] = b64[ ((d[1] << 2) & 0x3c) ];
143 /* fourth char is a = to indicate one byte of padding */
144 chunk[3] = '=';
145 ptr += stradd(ptr, end, chunk, 4);
146 break;
147 case 2:
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
151 * four zeroes*/
152 chunk[1] = b64[ ((d[0] << 4) & 0x30)];
153 /* third char is = to indicate padding */
154 chunk[2] = '=';
155 /* fourth char is = to indicate padding */
156 chunk[3] = '=';
157 ptr += stradd(ptr, end, chunk, 4);
158 break;
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";
169 BOOL ret = TRUE;
170 LPCSTR header = NULL, trailer = NULL, sep;
171 DWORD charsNeeded;
173 if (dwFlags & CRYPT_STRING_NOCR)
174 sep = lf;
175 else if (dwFlags & CRYPT_STRING_NOCRLF)
176 sep = "";
177 else
178 sep = crlf;
179 switch (dwFlags & 0x0fffffff)
181 case CRYPT_STRING_BASE64:
182 /* no header or footer */
183 break;
184 case CRYPT_STRING_BASE64HEADER:
185 header = CERT_HEADER;
186 trailer = CERT_TRAILER;
187 break;
188 case CRYPT_STRING_BASE64REQUESTHEADER:
189 header = CERT_REQUEST_HEADER;
190 trailer = CERT_REQUEST_TRAILER;
191 break;
192 case CRYPT_STRING_BASE64X509CRLHEADER:
193 header = X509_HEADER;
194 trailer = X509_TRAILER;
195 break;
198 charsNeeded = 0;
199 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
200 if (header)
201 charsNeeded += strlen(header) + strlen(sep);
202 if (trailer)
203 charsNeeded += strlen(trailer) + strlen(sep);
205 if (pszString)
207 LPSTR ptr = pszString;
208 DWORD size = *pcchString;
209 LPSTR end = ptr + size;
211 if (header)
213 ptr += stradd(ptr, end, header, strlen(header));
214 ptr += stradd(ptr, end, sep, strlen(sep));
215 size = end - ptr;
217 ptr += encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
218 if (trailer)
220 ptr += stradd(ptr, end, trailer, strlen(trailer));
221 ptr += stradd(ptr, end, sep, strlen(sep));
224 if (ptr < end)
225 *ptr = '\0';
227 if (charsNeeded <= *pcchString)
229 *pcchString = charsNeeded - 1;
231 else
233 *pcchString = charsNeeded;
234 SetLastError(ERROR_MORE_DATA);
235 ret = FALSE;
238 else
239 *pcchString = charsNeeded;
241 return ret;
244 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
245 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
247 BinaryToStringAFunc encoder = NULL;
249 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
250 pcchString);
252 if (!pbBinary)
254 SetLastError(ERROR_INVALID_PARAMETER);
255 return FALSE;
257 if (!pcchString)
259 SetLastError(ERROR_INVALID_PARAMETER);
260 return FALSE;
263 switch (dwFlags & 0x0fffffff)
265 case CRYPT_STRING_BINARY:
266 encoder = EncodeBinaryToBinaryA;
267 break;
268 case CRYPT_STRING_BASE64:
269 case CRYPT_STRING_BASE64HEADER:
270 case CRYPT_STRING_BASE64REQUESTHEADER:
271 case CRYPT_STRING_BASE64X509CRLHEADER:
272 encoder = BinaryToBase64A;
273 break;
274 case CRYPT_STRING_HEX:
275 case CRYPT_STRING_HEXASCII:
276 case CRYPT_STRING_HEXADDR:
277 case CRYPT_STRING_HEXASCIIADDR:
278 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
279 /* fall through */
280 default:
281 SetLastError(ERROR_INVALID_PARAMETER);
282 return FALSE;
284 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
287 static BOOL EncodeBinaryToBinaryW(const BYTE *in_buf, DWORD in_len, DWORD flags, WCHAR *out_buf, DWORD *out_len)
289 BOOL ret = TRUE;
291 if (out_buf)
293 if (*out_len < in_len)
295 SetLastError(ERROR_INSUFFICIENT_BUFFER);
296 ret = FALSE;
298 else if (in_len)
299 memcpy(out_buf, in_buf, in_len);
301 else
302 *out_len = in_len;
304 return ret;
307 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
308 WCHAR* out_buf, DWORD *out_len)
310 int div, i;
311 const BYTE *d = in_buf;
312 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
313 DWORD needed;
314 LPWSTR ptr;
316 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
317 needed = bytes + pad_bytes;
318 needed += (needed / 64 + (needed % 64 ? 1 : 0)) * lstrlenW(sep);
319 needed++;
321 if (needed > *out_len)
323 *out_len = needed;
324 return ERROR_INSUFFICIENT_BUFFER;
326 else
327 *out_len = needed;
329 /* Three bytes of input give 4 chars of output */
330 div = in_len / 3;
332 ptr = out_buf;
333 i = 0;
334 while (div > 0)
336 if (i && i % 64 == 0)
338 lstrcpyW(ptr, sep);
339 ptr += lstrlenW(sep);
341 /* first char is the first 6 bits of the first byte*/
342 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
343 /* second char is the last 2 bits of the first byte and the first 4
344 * bits of the second byte */
345 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
346 /* third char is the last 4 bits of the second byte and the first 2
347 * bits of the third byte */
348 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
349 /* fourth char is the remaining 6 bits of the third byte */
350 *ptr++ = b64[ d[2] & 0x3f];
351 i += 4;
352 d += 3;
353 div--;
356 switch(pad_bytes)
358 case 1:
359 /* first char is the first 6 bits of the first byte*/
360 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
361 /* second char is the last 2 bits of the first byte and the first 4
362 * bits of the second byte */
363 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
364 /* third char is the last 4 bits of the second byte padded with
365 * two zeroes */
366 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
367 /* fourth char is a = to indicate one byte of padding */
368 *ptr++ = '=';
369 break;
370 case 2:
371 /* first char is the first 6 bits of the first byte*/
372 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
373 /* second char is the last 2 bits of the first byte padded with
374 * four zeroes*/
375 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
376 /* third char is = to indicate padding */
377 *ptr++ = '=';
378 /* fourth char is = to indicate padding */
379 *ptr++ = '=';
380 break;
382 lstrcpyW(ptr, sep);
384 return ERROR_SUCCESS;
387 static BOOL BinaryToBase64W(const BYTE *pbBinary,
388 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
390 BOOL ret = TRUE;
391 LPCWSTR header = NULL, trailer = NULL, sep;
392 DWORD charsNeeded;
394 if (dwFlags & CRYPT_STRING_NOCR)
395 sep = L"\n";
396 else if (dwFlags & CRYPT_STRING_NOCRLF)
397 sep = L"";
398 else
399 sep = L"\r\n";
400 switch (dwFlags & 0x0fffffff)
402 case CRYPT_STRING_BASE64:
403 /* no header or footer */
404 break;
405 case CRYPT_STRING_BASE64HEADER:
406 header = CERT_HEADER_W;
407 trailer = CERT_TRAILER_W;
408 break;
409 case CRYPT_STRING_BASE64REQUESTHEADER:
410 header = CERT_REQUEST_HEADER_W;
411 trailer = CERT_REQUEST_TRAILER_W;
412 break;
413 case CRYPT_STRING_BASE64X509CRLHEADER:
414 header = X509_HEADER_W;
415 trailer = X509_TRAILER_W;
416 break;
419 charsNeeded = 0;
420 encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
421 if (header)
422 charsNeeded += lstrlenW(header) + lstrlenW(sep);
423 if (trailer)
424 charsNeeded += lstrlenW(trailer) + lstrlenW(sep);
426 if (pszString)
428 if (charsNeeded <= *pcchString)
430 LPWSTR ptr = pszString;
431 DWORD size = charsNeeded;
433 if (header)
435 lstrcpyW(ptr, header);
436 ptr += lstrlenW(ptr);
437 lstrcpyW(ptr, sep);
438 ptr += lstrlenW(sep);
440 encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
441 ptr += size - 1;
442 if (trailer)
444 lstrcpyW(ptr, trailer);
445 ptr += lstrlenW(ptr);
446 lstrcpyW(ptr, sep);
448 *pcchString = charsNeeded - 1;
450 else
452 *pcchString = charsNeeded;
453 SetLastError(ERROR_MORE_DATA);
454 ret = FALSE;
457 else
458 *pcchString = charsNeeded;
460 return ret;
463 static BOOL BinaryToHexRawW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
465 static const WCHAR hex[] = L"0123456789abcdef";
466 DWORD needed;
468 if (flags & CRYPT_STRING_NOCRLF)
469 needed = 0;
470 else if (flags & CRYPT_STRING_NOCR)
471 needed = 1;
472 else
473 needed = 2;
475 needed += nbin * 2 + 1;
477 if (!str)
479 *nstr = needed;
480 return TRUE;
483 if (needed > *nstr)
485 SetLastError(ERROR_MORE_DATA);
486 return FALSE;
489 while (nbin--)
491 *str++ = hex[(*bin >> 4) & 0xf];
492 *str++ = hex[*bin & 0xf];
493 bin++;
496 if (flags & CRYPT_STRING_NOCR)
497 *str++ = '\n';
498 else if (!(flags & CRYPT_STRING_NOCRLF))
500 *str++ = '\r';
501 *str++ = '\n';
504 *str = 0;
505 *nstr = needed - 1;
506 return TRUE;
509 static BOOL binary_to_hexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
511 static const WCHAR hex[] = L"0123456789abcdef";
512 DWORD needed, i;
514 needed = nbin * 3; /* spaces + terminating \0 */
516 if (flags & CRYPT_STRING_NOCR)
518 needed += (nbin + 7) / 16; /* space every 16 characters */
519 needed += 1; /* terminating \n */
521 else if (!(flags & CRYPT_STRING_NOCRLF))
523 needed += (nbin + 7) / 16; /* space every 16 characters */
524 needed += nbin / 16 + 1; /* LF every 16 characters + terminating \r */
526 if (nbin % 16)
527 needed += 1; /* terminating \n */
530 if (!str)
532 *nstr = needed;
533 return TRUE;
536 if (needed > *nstr)
538 SetLastError(ERROR_MORE_DATA);
539 return FALSE;
542 for (i = 0; i < nbin; i++)
544 *str++ = hex[(bin[i] >> 4) & 0xf];
545 *str++ = hex[bin[i] & 0xf];
547 if (i >= nbin - 1) break;
549 if (i && !(flags & CRYPT_STRING_NOCRLF))
551 if (!((i + 1) % 16))
553 if (flags & CRYPT_STRING_NOCR)
554 *str++ = '\n';
555 else
557 *str++ = '\r';
558 *str++ = '\n';
560 continue;
562 else if (!((i + 1) % 8))
563 *str++ = ' ';
566 *str++ = ' ';
569 if (flags & CRYPT_STRING_NOCR)
570 *str++ = '\n';
571 else if (!(flags & CRYPT_STRING_NOCRLF))
573 *str++ = '\r';
574 *str++ = '\n';
577 *str = 0;
578 *nstr = needed - 1;
579 return TRUE;
582 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
583 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
585 BinaryToStringWFunc encoder = NULL;
587 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
588 pcchString);
590 if (!pbBinary)
592 SetLastError(ERROR_INVALID_PARAMETER);
593 return FALSE;
595 if (!pcchString)
597 SetLastError(ERROR_INVALID_PARAMETER);
598 return FALSE;
601 switch (dwFlags & 0x0fffffff)
603 case CRYPT_STRING_BINARY:
604 encoder = EncodeBinaryToBinaryW;
605 break;
606 case CRYPT_STRING_BASE64:
607 case CRYPT_STRING_BASE64HEADER:
608 case CRYPT_STRING_BASE64REQUESTHEADER:
609 case CRYPT_STRING_BASE64X509CRLHEADER:
610 encoder = BinaryToBase64W;
611 break;
612 case CRYPT_STRING_HEXRAW:
613 encoder = BinaryToHexRawW;
614 break;
615 case CRYPT_STRING_HEX:
616 encoder = binary_to_hexW;
617 break;
618 case CRYPT_STRING_HEXASCII:
619 case CRYPT_STRING_HEXADDR:
620 case CRYPT_STRING_HEXASCIIADDR:
621 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
622 /* fall through */
623 default:
624 SetLastError(ERROR_INVALID_PARAMETER);
625 return FALSE;
627 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
630 #define BASE64_DECODE_PADDING 0x100
631 #define BASE64_DECODE_WHITESPACE 0x200
632 #define BASE64_DECODE_INVALID 0x300
634 static inline int decodeBase64Byte(int c)
636 int ret = BASE64_DECODE_INVALID;
638 if (c >= 'A' && c <= 'Z')
639 ret = c - 'A';
640 else if (c >= 'a' && c <= 'z')
641 ret = c - 'a' + 26;
642 else if (c >= '0' && c <= '9')
643 ret = c - '0' + 52;
644 else if (c == '+')
645 ret = 62;
646 else if (c == '/')
647 ret = 63;
648 else if (c == '=')
649 ret = BASE64_DECODE_PADDING;
650 else if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
651 ret = BASE64_DECODE_WHITESPACE;
652 return ret;
655 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
656 * string to convert.
658 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
659 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
661 static LONG Base64ToBinary(const void* pszString, BOOL wide, DWORD cchString,
662 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
664 DWORD cbIn, cbValid, cbOut, hasPadding;
665 BYTE block[4];
666 for (cbIn = cbValid = cbOut = hasPadding = 0; cbIn < cchString; ++cbIn)
668 int c = wide ? (int)((WCHAR*)pszString)[cbIn] : (int)((char*)pszString)[cbIn];
669 int d = decodeBase64Byte(c);
670 if (d == BASE64_DECODE_INVALID)
671 goto invalid;
672 if (d == BASE64_DECODE_WHITESPACE)
673 continue;
675 /* When padding starts, data is not acceptable */
676 if (hasPadding && d != BASE64_DECODE_PADDING)
677 goto invalid;
679 /* Padding after a full block (like "VVVV=") is ok and stops decoding */
680 if (d == BASE64_DECODE_PADDING && (cbValid & 3) == 0)
681 break;
683 cbValid += 1;
685 if (d == BASE64_DECODE_PADDING)
687 hasPadding = 1;
688 /* When padding reaches a full block, stop decoding */
689 if ((cbValid & 3) == 0)
690 break;
691 continue;
694 /* cbOut is incremented in the 4-char block as follows: "1-23" */
695 if ((cbValid & 3) != 2)
696 cbOut += 1;
698 /* Fail if the block has bad padding; omitting padding is fine */
699 if ((cbValid & 3) != 0 && hasPadding)
700 goto invalid;
701 /* Check available buffer size */
702 if (pbBinary && *pcbBinary && cbOut > *pcbBinary)
703 goto overflow;
704 /* Convert the data; this step depends on the validity checks above! */
705 if (pbBinary) for (cbIn = cbValid = cbOut = 0; cbIn < cchString; ++cbIn)
707 int c = wide ? (int)((WCHAR*)pszString)[cbIn] : (int)((char*)pszString)[cbIn];
708 int d = decodeBase64Byte(c);
709 if (d == BASE64_DECODE_WHITESPACE)
710 continue;
711 if (d == BASE64_DECODE_PADDING)
712 break;
713 block[cbValid & 3] = d;
714 cbValid += 1;
715 switch (cbValid & 3) {
716 case 1:
717 pbBinary[cbOut++] = (block[0] << 2);
718 break;
719 case 2:
720 pbBinary[cbOut-1] = (block[0] << 2) | (block[1] >> 4);
721 break;
722 case 3:
723 pbBinary[cbOut++] = (block[1] << 4) | (block[2] >> 2);
724 break;
725 case 0:
726 pbBinary[cbOut++] = (block[2] << 6) | (block[3] >> 0);
727 break;
730 *pcbBinary = cbOut;
731 if (pdwSkip)
732 *pdwSkip = 0;
733 if (pdwFlags)
734 *pdwFlags = CRYPT_STRING_BASE64;
735 return ERROR_SUCCESS;
736 overflow:
737 return ERROR_INSUFFICIENT_BUFFER;
738 invalid:
739 *pcbBinary = cbOut;
740 return ERROR_INVALID_DATA;
743 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
744 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
746 return Base64ToBinary(pszString, FALSE, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
749 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
750 DWORD cchString, BYTE *pbBinary,
751 DWORD *pcbBinary, DWORD *pdwSkip)
753 LONG ret;
754 LPCSTR header = CERT_HEADER_START;
755 LPCSTR trailer = CERT_TRAILER_START;
757 LPCSTR headerBegins;
758 LPCSTR dataBegins;
759 LPCSTR trailerBegins;
760 size_t dataLength;
762 if ((strlen(header) + strlen(trailer)) > cchString)
764 return ERROR_INVALID_DATA;
767 if (!(headerBegins = strstr(pszString, header)))
769 TRACE("Can't find %s in %s.\n", header, debugstr_an(pszString, cchString));
770 return ERROR_INVALID_DATA;
773 dataBegins = headerBegins + strlen(header);
774 if (!(dataBegins = strstr(dataBegins, CERT_DELIMITER)))
776 return ERROR_INVALID_DATA;
778 dataBegins += strlen(CERT_DELIMITER);
779 if (*dataBegins == '\r') dataBegins++;
780 if (*dataBegins == '\n') dataBegins++;
782 if (!(trailerBegins = strstr(dataBegins, trailer)))
784 return ERROR_INVALID_DATA;
786 if (*(trailerBegins-1) == '\n') trailerBegins--;
787 if (*(trailerBegins-1) == '\r') trailerBegins--;
789 if (pdwSkip)
790 *pdwSkip = headerBegins - pszString;
792 dataLength = trailerBegins - dataBegins;
794 ret = Base64ToBinaryA(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
795 NULL);
797 return ret;
800 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
801 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
803 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
804 pbBinary, pcbBinary, pdwSkip);
806 if (!ret && pdwFlags)
807 *pdwFlags = CRYPT_STRING_BASE64HEADER;
808 return ret;
811 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
812 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
814 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
815 pbBinary, pcbBinary, pdwSkip);
817 if (!ret && pdwFlags)
818 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
819 return ret;
822 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
823 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
825 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
826 pbBinary, pcbBinary, pdwSkip);
828 if (!ret && pdwFlags)
829 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
830 return ret;
833 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
834 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
836 LONG ret;
838 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
839 pdwSkip, pdwFlags);
840 if (ret == ERROR_INVALID_DATA)
841 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
842 pdwSkip, pdwFlags);
843 return ret;
846 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
847 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
849 LONG ret = ERROR_SUCCESS;
851 if (*pcbBinary < cchString)
853 if (!pbBinary)
854 *pcbBinary = cchString;
855 else
857 ret = ERROR_INSUFFICIENT_BUFFER;
858 *pcbBinary = cchString;
861 else
863 if (cchString)
864 memcpy(pbBinary, pszString, cchString);
865 *pcbBinary = cchString;
867 return ret;
870 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
871 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
873 LONG ret;
875 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
876 pdwSkip, pdwFlags);
877 if (ret == ERROR_INVALID_DATA)
878 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
879 pdwSkip, pdwFlags);
880 if (ret == ERROR_INVALID_DATA)
881 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
882 pdwSkip, pdwFlags);
883 return ret;
886 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
887 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
888 DWORD *pdwSkip, DWORD *pdwFlags)
890 StringToBinaryAFunc decoder;
891 LONG ret;
893 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_an(pszString, cchString ? cchString : -1),
894 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
896 if (!pszString)
898 SetLastError(ERROR_INVALID_PARAMETER);
899 return FALSE;
901 /* Only the bottom byte contains valid types */
902 if (dwFlags & 0xfffffff0)
904 SetLastError(ERROR_INVALID_DATA);
905 return FALSE;
907 switch (dwFlags)
909 case CRYPT_STRING_BASE64_ANY:
910 decoder = Base64AnyToBinaryA;
911 break;
912 case CRYPT_STRING_BASE64:
913 decoder = Base64ToBinaryA;
914 break;
915 case CRYPT_STRING_BASE64HEADER:
916 decoder = Base64HeaderToBinaryA;
917 break;
918 case CRYPT_STRING_BASE64REQUESTHEADER:
919 decoder = Base64RequestHeaderToBinaryA;
920 break;
921 case CRYPT_STRING_BASE64X509CRLHEADER:
922 decoder = Base64X509HeaderToBinaryA;
923 break;
924 case CRYPT_STRING_BINARY:
925 decoder = DecodeBinaryToBinaryA;
926 break;
927 case CRYPT_STRING_ANY:
928 decoder = DecodeAnyA;
929 break;
930 case CRYPT_STRING_HEX:
931 case CRYPT_STRING_HEXASCII:
932 case CRYPT_STRING_HEXADDR:
933 case CRYPT_STRING_HEXASCIIADDR:
934 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
935 /* fall through */
936 default:
937 SetLastError(ERROR_INVALID_PARAMETER);
938 return FALSE;
940 if (!cchString)
941 cchString = strlen(pszString);
942 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
943 if (ret)
944 SetLastError(ret);
945 return ret == ERROR_SUCCESS;
948 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
949 * string to convert.
951 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
952 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
954 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
955 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
957 return Base64ToBinary(pszString, TRUE, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
960 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
961 DWORD cchString, BYTE *pbBinary,
962 DWORD *pcbBinary, DWORD *pdwSkip)
964 LONG ret;
965 LPCWSTR header = CERT_HEADER_START_W;
966 LPCWSTR trailer = CERT_TRAILER_START_W;
968 LPCWSTR headerBegins;
969 LPCWSTR dataBegins;
970 LPCWSTR trailerBegins;
971 size_t dataLength;
973 if ((lstrlenW(header) + lstrlenW(trailer)) > cchString)
975 return ERROR_INVALID_DATA;
978 if (!(headerBegins = wcsstr(pszString, header)))
980 TRACE("Can't find %s in %s.\n", debugstr_w(header), debugstr_wn(pszString, cchString));
981 return ERROR_INVALID_DATA;
984 dataBegins = headerBegins + lstrlenW(header);
985 if (!(dataBegins = wcsstr(dataBegins, CERT_DELIMITER_W)))
987 return ERROR_INVALID_DATA;
989 dataBegins += lstrlenW(CERT_DELIMITER_W);
990 if (*dataBegins == '\r') dataBegins++;
991 if (*dataBegins == '\n') dataBegins++;
993 if (!(trailerBegins = wcsstr(dataBegins, trailer)))
995 return ERROR_INVALID_DATA;
997 if (*(trailerBegins-1) == '\n') trailerBegins--;
998 if (*(trailerBegins-1) == '\r') trailerBegins--;
1000 if (pdwSkip)
1001 *pdwSkip = headerBegins - pszString;
1003 dataLength = trailerBegins - dataBegins;
1005 ret = Base64ToBinaryW(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
1006 NULL);
1008 return ret;
1011 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1012 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1014 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1015 pbBinary, pcbBinary, pdwSkip);
1017 if (!ret && pdwFlags)
1018 *pdwFlags = CRYPT_STRING_BASE64HEADER;
1019 return ret;
1022 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1023 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1025 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1026 pbBinary, pcbBinary, pdwSkip);
1028 if (!ret && pdwFlags)
1029 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
1030 return ret;
1033 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1034 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1036 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1037 pbBinary, pcbBinary, pdwSkip);
1039 if (!ret && pdwFlags)
1040 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
1041 return ret;
1044 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
1045 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1047 LONG ret;
1049 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1050 pdwSkip, pdwFlags);
1051 if (ret == ERROR_INVALID_DATA)
1052 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1053 pdwSkip, pdwFlags);
1054 return ret;
1057 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
1058 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1060 LONG ret = ERROR_SUCCESS;
1062 if (*pcbBinary < cchString)
1064 if (!pbBinary)
1065 *pcbBinary = cchString;
1066 else
1068 ret = ERROR_INSUFFICIENT_BUFFER;
1069 *pcbBinary = cchString;
1072 else
1074 if (cchString)
1075 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1076 *pcbBinary = cchString * sizeof(WCHAR);
1078 return ret;
1081 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1082 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1084 LONG ret;
1086 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1087 pdwSkip, pdwFlags);
1088 if (ret == ERROR_INVALID_DATA)
1089 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1090 pdwSkip, pdwFlags);
1091 if (ret == ERROR_INVALID_DATA)
1092 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1093 pdwSkip, pdwFlags);
1094 return ret;
1097 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1098 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1099 DWORD *pdwSkip, DWORD *pdwFlags)
1101 StringToBinaryWFunc decoder;
1102 LONG ret;
1104 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_wn(pszString, cchString ? cchString : -1),
1105 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1107 if (!pszString)
1109 SetLastError(ERROR_INVALID_PARAMETER);
1110 return FALSE;
1112 /* Only the bottom byte contains valid types */
1113 if (dwFlags & 0xfffffff0)
1115 SetLastError(ERROR_INVALID_DATA);
1116 return FALSE;
1118 switch (dwFlags)
1120 case CRYPT_STRING_BASE64_ANY:
1121 decoder = Base64AnyToBinaryW;
1122 break;
1123 case CRYPT_STRING_BASE64:
1124 decoder = Base64ToBinaryW;
1125 break;
1126 case CRYPT_STRING_BASE64HEADER:
1127 decoder = Base64HeaderToBinaryW;
1128 break;
1129 case CRYPT_STRING_BASE64REQUESTHEADER:
1130 decoder = Base64RequestHeaderToBinaryW;
1131 break;
1132 case CRYPT_STRING_BASE64X509CRLHEADER:
1133 decoder = Base64X509HeaderToBinaryW;
1134 break;
1135 case CRYPT_STRING_BINARY:
1136 decoder = DecodeBinaryToBinaryW;
1137 break;
1138 case CRYPT_STRING_ANY:
1139 decoder = DecodeAnyW;
1140 break;
1141 case CRYPT_STRING_HEX:
1142 case CRYPT_STRING_HEXASCII:
1143 case CRYPT_STRING_HEXADDR:
1144 case CRYPT_STRING_HEXASCIIADDR:
1145 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1146 /* fall through */
1147 default:
1148 SetLastError(ERROR_INVALID_PARAMETER);
1149 return FALSE;
1151 if (!cchString)
1152 cchString = lstrlenW(pszString);
1153 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1154 if (ret)
1155 SetLastError(ret);
1156 return ret == ERROR_SUCCESS;