ntdll: Add a helper for platform-specific threading initialization.
[wine.git] / dlls / crypt32 / base64.c
blob73619421ab031eb91ac18b24169cb66707ecf6d8
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"
28 #include "wine/unicode.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32 #define CERT_HEADER "-----BEGIN CERTIFICATE-----"
33 #define CERT_HEADER_START "-----BEGIN "
34 #define CERT_DELIMITER "-----"
35 #define CERT_TRAILER "-----END CERTIFICATE-----"
36 #define CERT_TRAILER_START "-----END "
37 #define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
38 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
39 #define X509_HEADER "-----BEGIN X509 CRL-----"
40 #define X509_TRAILER "-----END X509 CRL-----"
42 static const WCHAR CERT_HEADER_W[] = {
43 '-','-','-','-','-','B','E','G','I','N',' ','C','E','R','T','I','F','I','C',
44 'A','T','E','-','-','-','-','-',0 };
45 static const WCHAR CERT_HEADER_START_W[] = {
46 '-','-','-','-','-','B','E','G','I','N',' ',0 };
47 static const WCHAR CERT_DELIMITER_W[] = {
48 '-','-','-','-','-',0 };
49 static const WCHAR CERT_TRAILER_W[] = {
50 '-','-','-','-','-','E','N','D',' ','C','E','R','T','I','F','I','C','A','T',
51 'E','-','-','-','-','-',0 };
52 static const WCHAR CERT_TRAILER_START_W[] = {
53 '-','-','-','-','-','E','N','D',' ',0 };
54 static const WCHAR CERT_REQUEST_HEADER_W[] = {
55 '-','-','-','-','-','B','E','G','I','N',' ','N','E','W',' ','C','E','R','T',
56 'I','F','I','C','A','T','E',' ','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
57 static const WCHAR CERT_REQUEST_TRAILER_W[] = {
58 '-','-','-','-','-','E','N','D',' ','N','E','W',' ','C','E','R','T','I','F',
59 'I','C','A','T','E',' ','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
60 static const WCHAR X509_HEADER_W[] = {
61 '-','-','-','-','-','B','E','G','I','N',' ','X','5','0','9',' ','C','R','L',
62 '-','-','-','-','-',0 };
63 static const WCHAR X509_TRAILER_W[] = {
64 '-','-','-','-','-','E','N','D',' ','X','5','0','9',' ','C','R','L','-','-',
65 '-','-','-',0 };
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)
78 BOOL ret = TRUE;
80 if (pszString)
82 if (*pcchString < cbBinary)
84 SetLastError(ERROR_INSUFFICIENT_BUFFER);
85 ret = FALSE;
87 else if (cbBinary)
88 memcpy(pszString, pbBinary, cbBinary);
90 else
91 *pcchString = cbBinary;
93 return ret;
96 static DWORD stradd(LPSTR ptr, LPCSTR end, LPCSTR s, DWORD slen)
98 if (ptr + slen > end)
99 slen = end - ptr;
100 memcpy(ptr, s, slen);
101 return slen;
104 static DWORD encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
105 char* out_buf, DWORD *out_len)
107 int div, i;
108 const BYTE *d = in_buf;
109 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
110 LPSTR ptr;
111 LPCSTR end;
112 char chunk[4];
114 if (!out_buf)
116 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
117 *out_len = bytes + pad_bytes;
118 *out_len += (*out_len / 64 + (*out_len % 64 ? 1 : 0)) * strlen(sep) + 1;
119 return 0;
122 /* Three bytes of input give 4 chars of output */
123 div = in_len / 3;
125 ptr = out_buf;
126 end = ptr + *out_len;
127 i = 0;
128 while (div > 0 && ptr < end)
130 if (i && i % 64 == 0)
131 ptr += stradd(ptr, end, sep, strlen(sep));
132 /* first char is the first 6 bits of the first byte*/
133 chunk[0] = b64[ ( d[0] >> 2) & 0x3f ];
134 /* second char is the last 2 bits of the first byte and the first 4
135 * bits of the second byte */
136 chunk[1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
137 /* third char is the last 4 bits of the second byte and the first 2
138 * bits of the third byte */
139 chunk[2] = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
140 /* fourth char is the remaining 6 bits of the third byte */
141 chunk[3] = b64[ d[2] & 0x3f];
142 ptr += stradd(ptr, end, chunk, 4);
143 i += 4;
144 d += 3;
145 div--;
148 switch(pad_bytes)
150 case 1:
151 /* first char is the first 6 bits of the first byte*/
152 chunk[0] = b64[ ( d[0] >> 2) & 0x3f ];
153 /* second char is the last 2 bits of the first byte and the first 4
154 * bits of the second byte */
155 chunk[1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
156 /* third char is the last 4 bits of the second byte padded with
157 * two zeroes */
158 chunk[2] = b64[ ((d[1] << 2) & 0x3c) ];
159 /* fourth char is a = to indicate one byte of padding */
160 chunk[3] = '=';
161 ptr += stradd(ptr, end, chunk, 4);
162 break;
163 case 2:
164 /* first char is the first 6 bits of the first byte*/
165 chunk[0] = b64[ ( d[0] >> 2) & 0x3f ];
166 /* second char is the last 2 bits of the first byte padded with
167 * four zeroes*/
168 chunk[1] = b64[ ((d[0] << 4) & 0x30)];
169 /* third char is = to indicate padding */
170 chunk[2] = '=';
171 /* fourth char is = to indicate padding */
172 chunk[3] = '=';
173 ptr += stradd(ptr, end, chunk, 4);
174 break;
176 ptr += stradd(ptr, end, sep, strlen(sep));
178 return ptr - out_buf;
181 static BOOL BinaryToBase64A(const BYTE *pbBinary,
182 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
184 static const char crlf[] = "\r\n", lf[] = "\n";
185 BOOL ret = TRUE;
186 LPCSTR header = NULL, trailer = NULL, sep;
187 DWORD charsNeeded;
189 if (dwFlags & CRYPT_STRING_NOCR)
190 sep = lf;
191 else if (dwFlags & CRYPT_STRING_NOCRLF)
192 sep = "";
193 else
194 sep = crlf;
195 switch (dwFlags & 0x0fffffff)
197 case CRYPT_STRING_BASE64:
198 /* no header or footer */
199 break;
200 case CRYPT_STRING_BASE64HEADER:
201 header = CERT_HEADER;
202 trailer = CERT_TRAILER;
203 break;
204 case CRYPT_STRING_BASE64REQUESTHEADER:
205 header = CERT_REQUEST_HEADER;
206 trailer = CERT_REQUEST_TRAILER;
207 break;
208 case CRYPT_STRING_BASE64X509CRLHEADER:
209 header = X509_HEADER;
210 trailer = X509_TRAILER;
211 break;
214 charsNeeded = 0;
215 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
216 if (header)
217 charsNeeded += strlen(header) + strlen(sep);
218 if (trailer)
219 charsNeeded += strlen(trailer) + strlen(sep);
221 if (pszString)
223 LPSTR ptr = pszString;
224 DWORD size = *pcchString;
225 LPSTR end = ptr + size;
227 if (header)
229 ptr += stradd(ptr, end, header, strlen(header));
230 ptr += stradd(ptr, end, sep, strlen(sep));
231 size = end - ptr;
233 ptr += encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
234 if (trailer)
236 ptr += stradd(ptr, end, trailer, strlen(trailer));
237 ptr += stradd(ptr, end, sep, strlen(sep));
240 if (ptr < end)
241 *ptr = '\0';
243 if (charsNeeded <= *pcchString)
245 *pcchString = charsNeeded - 1;
247 else
249 *pcchString = charsNeeded;
250 SetLastError(ERROR_MORE_DATA);
251 ret = FALSE;
254 else
255 *pcchString = charsNeeded;
257 return ret;
260 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
261 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
263 BinaryToStringAFunc encoder = NULL;
265 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
266 pcchString);
268 if (!pbBinary)
270 SetLastError(ERROR_INVALID_PARAMETER);
271 return FALSE;
273 if (!pcchString)
275 SetLastError(ERROR_INVALID_PARAMETER);
276 return FALSE;
279 switch (dwFlags & 0x0fffffff)
281 case CRYPT_STRING_BINARY:
282 encoder = EncodeBinaryToBinaryA;
283 break;
284 case CRYPT_STRING_BASE64:
285 case CRYPT_STRING_BASE64HEADER:
286 case CRYPT_STRING_BASE64REQUESTHEADER:
287 case CRYPT_STRING_BASE64X509CRLHEADER:
288 encoder = BinaryToBase64A;
289 break;
290 case CRYPT_STRING_HEX:
291 case CRYPT_STRING_HEXASCII:
292 case CRYPT_STRING_HEXADDR:
293 case CRYPT_STRING_HEXASCIIADDR:
294 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
295 /* fall through */
296 default:
297 SetLastError(ERROR_INVALID_PARAMETER);
298 return FALSE;
300 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
303 static BOOL EncodeBinaryToBinaryW(const BYTE *in_buf, DWORD in_len, DWORD flags, WCHAR *out_buf, DWORD *out_len)
305 BOOL ret = TRUE;
307 if (out_buf)
309 if (*out_len < in_len)
311 SetLastError(ERROR_INSUFFICIENT_BUFFER);
312 ret = FALSE;
314 else if (in_len)
315 memcpy(out_buf, in_buf, in_len);
317 else
318 *out_len = in_len;
320 return ret;
323 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
324 WCHAR* out_buf, DWORD *out_len)
326 int div, i;
327 const BYTE *d = in_buf;
328 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
329 DWORD needed;
330 LPWSTR ptr;
332 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
333 needed = bytes + pad_bytes;
334 needed += (needed / 64 + (needed % 64 ? 1 : 0)) * strlenW(sep);
335 needed++;
337 if (needed > *out_len)
339 *out_len = needed;
340 return ERROR_INSUFFICIENT_BUFFER;
342 else
343 *out_len = needed;
345 /* Three bytes of input give 4 chars of output */
346 div = in_len / 3;
348 ptr = out_buf;
349 i = 0;
350 while (div > 0)
352 if (i && i % 64 == 0)
354 strcpyW(ptr, sep);
355 ptr += strlenW(sep);
357 /* first char is the first 6 bits of the first byte*/
358 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
359 /* second char is the last 2 bits of the first byte and the first 4
360 * bits of the second byte */
361 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
362 /* third char is the last 4 bits of the second byte and the first 2
363 * bits of the third byte */
364 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
365 /* fourth char is the remaining 6 bits of the third byte */
366 *ptr++ = b64[ d[2] & 0x3f];
367 i += 4;
368 d += 3;
369 div--;
372 switch(pad_bytes)
374 case 1:
375 /* first char is the first 6 bits of the first byte*/
376 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
377 /* second char is the last 2 bits of the first byte and the first 4
378 * bits of the second byte */
379 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
380 /* third char is the last 4 bits of the second byte padded with
381 * two zeroes */
382 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
383 /* fourth char is a = to indicate one byte of padding */
384 *ptr++ = '=';
385 break;
386 case 2:
387 /* first char is the first 6 bits of the first byte*/
388 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
389 /* second char is the last 2 bits of the first byte padded with
390 * four zeroes*/
391 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
392 /* third char is = to indicate padding */
393 *ptr++ = '=';
394 /* fourth char is = to indicate padding */
395 *ptr++ = '=';
396 break;
398 strcpyW(ptr, sep);
400 return ERROR_SUCCESS;
403 static BOOL BinaryToBase64W(const BYTE *pbBinary,
404 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
406 static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 }, empty[] = {0};
407 BOOL ret = TRUE;
408 LPCWSTR header = NULL, trailer = NULL, sep;
409 DWORD charsNeeded;
411 if (dwFlags & CRYPT_STRING_NOCR)
412 sep = lf;
413 else if (dwFlags & CRYPT_STRING_NOCRLF)
414 sep = empty;
415 else
416 sep = crlf;
417 switch (dwFlags & 0x0fffffff)
419 case CRYPT_STRING_BASE64:
420 /* no header or footer */
421 break;
422 case CRYPT_STRING_BASE64HEADER:
423 header = CERT_HEADER_W;
424 trailer = CERT_TRAILER_W;
425 break;
426 case CRYPT_STRING_BASE64REQUESTHEADER:
427 header = CERT_REQUEST_HEADER_W;
428 trailer = CERT_REQUEST_TRAILER_W;
429 break;
430 case CRYPT_STRING_BASE64X509CRLHEADER:
431 header = X509_HEADER_W;
432 trailer = X509_TRAILER_W;
433 break;
436 charsNeeded = 0;
437 encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
438 if (header)
439 charsNeeded += strlenW(header) + strlenW(sep);
440 if (trailer)
441 charsNeeded += strlenW(trailer) + strlenW(sep);
443 if (pszString)
445 if (charsNeeded <= *pcchString)
447 LPWSTR ptr = pszString;
448 DWORD size = charsNeeded;
450 if (header)
452 strcpyW(ptr, header);
453 ptr += strlenW(ptr);
454 strcpyW(ptr, sep);
455 ptr += strlenW(sep);
457 encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
458 ptr += size - 1;
459 if (trailer)
461 strcpyW(ptr, trailer);
462 ptr += strlenW(ptr);
463 strcpyW(ptr, sep);
465 *pcchString = charsNeeded - 1;
467 else
469 *pcchString = charsNeeded;
470 SetLastError(ERROR_MORE_DATA);
471 ret = FALSE;
474 else
475 *pcchString = charsNeeded;
477 return ret;
480 static BOOL BinaryToHexW(const BYTE *bin, DWORD nbin, DWORD flags, LPWSTR str, DWORD *nstr)
482 static const WCHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
483 DWORD needed;
485 if (flags & CRYPT_STRING_NOCRLF)
486 needed = 0;
487 else if (flags & CRYPT_STRING_NOCR)
488 needed = 1;
489 else
490 needed = 2;
492 needed += nbin * 2 + 1;
494 if (!str)
496 *nstr = needed;
497 return TRUE;
500 if (needed > *nstr)
502 SetLastError(ERROR_MORE_DATA);
503 return FALSE;
506 while (nbin--)
508 *str++ = hex[(*bin >> 4) & 0xf];
509 *str++ = hex[*bin & 0xf];
510 bin++;
513 if (flags & CRYPT_STRING_NOCR)
514 *str++ = '\n';
515 else if (!(flags & CRYPT_STRING_NOCRLF))
517 *str++ = '\r';
518 *str++ = '\n';
521 *str = 0;
522 *nstr = needed - 1;
523 return TRUE;
526 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
527 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
529 BinaryToStringWFunc encoder = NULL;
531 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
532 pcchString);
534 if (!pbBinary)
536 SetLastError(ERROR_INVALID_PARAMETER);
537 return FALSE;
539 if (!pcchString)
541 SetLastError(ERROR_INVALID_PARAMETER);
542 return FALSE;
545 switch (dwFlags & 0x0fffffff)
547 case CRYPT_STRING_BINARY:
548 encoder = EncodeBinaryToBinaryW;
549 break;
550 case CRYPT_STRING_BASE64:
551 case CRYPT_STRING_BASE64HEADER:
552 case CRYPT_STRING_BASE64REQUESTHEADER:
553 case CRYPT_STRING_BASE64X509CRLHEADER:
554 encoder = BinaryToBase64W;
555 break;
556 case CRYPT_STRING_HEXRAW:
557 encoder = BinaryToHexW;
558 break;
559 case CRYPT_STRING_HEX:
560 case CRYPT_STRING_HEXASCII:
561 case CRYPT_STRING_HEXADDR:
562 case CRYPT_STRING_HEXASCIIADDR:
563 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
564 /* fall through */
565 default:
566 SetLastError(ERROR_INVALID_PARAMETER);
567 return FALSE;
569 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
572 #define BASE64_DECODE_PADDING 0x100
573 #define BASE64_DECODE_WHITESPACE 0x200
574 #define BASE64_DECODE_INVALID 0x300
576 static inline int decodeBase64Byte(int c)
578 int ret = BASE64_DECODE_INVALID;
580 if (c >= 'A' && c <= 'Z')
581 ret = c - 'A';
582 else if (c >= 'a' && c <= 'z')
583 ret = c - 'a' + 26;
584 else if (c >= '0' && c <= '9')
585 ret = c - '0' + 52;
586 else if (c == '+')
587 ret = 62;
588 else if (c == '/')
589 ret = 63;
590 else if (c == '=')
591 ret = BASE64_DECODE_PADDING;
592 else if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
593 ret = BASE64_DECODE_WHITESPACE;
594 return ret;
597 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
598 * string to convert.
600 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
601 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
603 static LONG Base64ToBinary(const void* pszString, BOOL wide, DWORD cchString,
604 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
606 DWORD cbIn, cbValid, cbOut, hasPadding;
607 BYTE block[4];
608 for (cbIn = cbValid = cbOut = hasPadding = 0; cbIn < cchString; ++cbIn)
610 int c = wide ? (int)((WCHAR*)pszString)[cbIn] : (int)((char*)pszString)[cbIn];
611 int d = decodeBase64Byte(c);
612 if (d == BASE64_DECODE_INVALID)
613 goto invalid;
614 if (d == BASE64_DECODE_WHITESPACE)
615 continue;
617 /* When padding starts, data is not acceptable */
618 if (hasPadding && d != BASE64_DECODE_PADDING)
619 goto invalid;
621 /* Padding after a full block (like "VVVV=") is ok and stops decoding */
622 if (d == BASE64_DECODE_PADDING && (cbValid & 3) == 0)
623 break;
625 cbValid += 1;
627 if (d == BASE64_DECODE_PADDING)
629 hasPadding = 1;
630 /* When padding reaches a full block, stop decoding */
631 if ((cbValid & 3) == 0)
632 break;
633 continue;
636 /* cbOut is incremented in the 4-char block as follows: "1-23" */
637 if ((cbValid & 3) != 2)
638 cbOut += 1;
640 /* Fail if the block has bad padding; omitting padding is fine */
641 if ((cbValid & 3) != 0 && hasPadding)
642 goto invalid;
643 /* Check available buffer size */
644 if (pbBinary && *pcbBinary && cbOut > *pcbBinary)
645 goto overflow;
646 /* Convert the data; this step depends on the validity checks above! */
647 if (pbBinary) for (cbIn = cbValid = cbOut = 0; cbIn < cchString; ++cbIn)
649 int c = wide ? (int)((WCHAR*)pszString)[cbIn] : (int)((char*)pszString)[cbIn];
650 int d = decodeBase64Byte(c);
651 if (d == BASE64_DECODE_WHITESPACE)
652 continue;
653 if (d == BASE64_DECODE_PADDING)
654 break;
655 block[cbValid & 3] = d;
656 cbValid += 1;
657 switch (cbValid & 3) {
658 case 1:
659 pbBinary[cbOut++] = (block[0] << 2);
660 break;
661 case 2:
662 pbBinary[cbOut-1] = (block[0] << 2) | (block[1] >> 4);
663 break;
664 case 3:
665 pbBinary[cbOut++] = (block[1] << 4) | (block[2] >> 2);
666 break;
667 case 0:
668 pbBinary[cbOut++] = (block[2] << 6) | (block[3] >> 0);
669 break;
672 *pcbBinary = cbOut;
673 if (pdwSkip)
674 *pdwSkip = 0;
675 if (pdwFlags)
676 *pdwFlags = CRYPT_STRING_BASE64;
677 return ERROR_SUCCESS;
678 overflow:
679 return ERROR_INSUFFICIENT_BUFFER;
680 invalid:
681 *pcbBinary = cbOut;
682 return ERROR_INVALID_DATA;
685 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
686 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
688 return Base64ToBinary(pszString, FALSE, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
691 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
692 DWORD cchString, BYTE *pbBinary,
693 DWORD *pcbBinary, DWORD *pdwSkip)
695 LONG ret;
696 LPCSTR header = CERT_HEADER_START;
697 LPCSTR trailer = CERT_TRAILER_START;
699 LPCSTR headerBegins;
700 LPCSTR dataBegins;
701 LPCSTR trailerBegins;
702 size_t dataLength;
704 if ((strlen(header) + strlen(trailer)) > cchString)
706 return ERROR_INVALID_DATA;
709 if (!(headerBegins = strstr(pszString, header)))
711 TRACE("Can't find %s in %s.\n", header, debugstr_an(pszString, cchString));
712 return ERROR_INVALID_DATA;
715 dataBegins = headerBegins + strlen(header);
716 if (!(dataBegins = strstr(dataBegins, CERT_DELIMITER)))
718 return ERROR_INVALID_DATA;
720 dataBegins += strlen(CERT_DELIMITER);
721 if (*dataBegins == '\r') dataBegins++;
722 if (*dataBegins == '\n') dataBegins++;
724 if (!(trailerBegins = strstr(dataBegins, trailer)))
726 return ERROR_INVALID_DATA;
728 if (*(trailerBegins-1) == '\n') trailerBegins--;
729 if (*(trailerBegins-1) == '\r') trailerBegins--;
731 if (pdwSkip)
732 *pdwSkip = headerBegins - pszString;
734 dataLength = trailerBegins - dataBegins;
736 ret = Base64ToBinaryA(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
737 NULL);
739 return ret;
742 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
743 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
745 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
746 pbBinary, pcbBinary, pdwSkip);
748 if (!ret && pdwFlags)
749 *pdwFlags = CRYPT_STRING_BASE64HEADER;
750 return ret;
753 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
754 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
756 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
757 pbBinary, pcbBinary, pdwSkip);
759 if (!ret && pdwFlags)
760 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
761 return ret;
764 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
765 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
767 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
768 pbBinary, pcbBinary, pdwSkip);
770 if (!ret && pdwFlags)
771 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
772 return ret;
775 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
776 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
778 LONG ret;
780 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
781 pdwSkip, pdwFlags);
782 if (ret == ERROR_INVALID_DATA)
783 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
784 pdwSkip, pdwFlags);
785 return ret;
788 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
789 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
791 LONG ret = ERROR_SUCCESS;
793 if (*pcbBinary < cchString)
795 if (!pbBinary)
796 *pcbBinary = cchString;
797 else
799 ret = ERROR_INSUFFICIENT_BUFFER;
800 *pcbBinary = cchString;
803 else
805 if (cchString)
806 memcpy(pbBinary, pszString, cchString);
807 *pcbBinary = cchString;
809 return ret;
812 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
813 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
815 LONG ret;
817 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
818 pdwSkip, pdwFlags);
819 if (ret == ERROR_INVALID_DATA)
820 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
821 pdwSkip, pdwFlags);
822 if (ret == ERROR_INVALID_DATA)
823 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
824 pdwSkip, pdwFlags);
825 return ret;
828 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
829 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
830 DWORD *pdwSkip, DWORD *pdwFlags)
832 StringToBinaryAFunc decoder;
833 LONG ret;
835 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_an(pszString, cchString ? cchString : -1),
836 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
838 if (!pszString)
840 SetLastError(ERROR_INVALID_PARAMETER);
841 return FALSE;
843 /* Only the bottom byte contains valid types */
844 if (dwFlags & 0xfffffff0)
846 SetLastError(ERROR_INVALID_DATA);
847 return FALSE;
849 switch (dwFlags)
851 case CRYPT_STRING_BASE64_ANY:
852 decoder = Base64AnyToBinaryA;
853 break;
854 case CRYPT_STRING_BASE64:
855 decoder = Base64ToBinaryA;
856 break;
857 case CRYPT_STRING_BASE64HEADER:
858 decoder = Base64HeaderToBinaryA;
859 break;
860 case CRYPT_STRING_BASE64REQUESTHEADER:
861 decoder = Base64RequestHeaderToBinaryA;
862 break;
863 case CRYPT_STRING_BASE64X509CRLHEADER:
864 decoder = Base64X509HeaderToBinaryA;
865 break;
866 case CRYPT_STRING_BINARY:
867 decoder = DecodeBinaryToBinaryA;
868 break;
869 case CRYPT_STRING_ANY:
870 decoder = DecodeAnyA;
871 break;
872 case CRYPT_STRING_HEX:
873 case CRYPT_STRING_HEXASCII:
874 case CRYPT_STRING_HEXADDR:
875 case CRYPT_STRING_HEXASCIIADDR:
876 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
877 /* fall through */
878 default:
879 SetLastError(ERROR_INVALID_PARAMETER);
880 return FALSE;
882 if (!cchString)
883 cchString = strlen(pszString);
884 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
885 if (ret)
886 SetLastError(ret);
887 return ret == ERROR_SUCCESS;
890 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
891 * string to convert.
893 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
894 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
896 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
897 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
899 return Base64ToBinary(pszString, TRUE, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
902 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
903 DWORD cchString, BYTE *pbBinary,
904 DWORD *pcbBinary, DWORD *pdwSkip)
906 LONG ret;
907 LPCWSTR header = CERT_HEADER_START_W;
908 LPCWSTR trailer = CERT_TRAILER_START_W;
910 LPCWSTR headerBegins;
911 LPCWSTR dataBegins;
912 LPCWSTR trailerBegins;
913 size_t dataLength;
915 if ((strlenW(header) + strlenW(trailer)) > cchString)
917 return ERROR_INVALID_DATA;
920 if (!(headerBegins = strstrW(pszString, header)))
922 TRACE("Can't find %s in %s.\n", debugstr_w(header), debugstr_wn(pszString, cchString));
923 return ERROR_INVALID_DATA;
926 dataBegins = headerBegins + strlenW(header);
927 if (!(dataBegins = strstrW(dataBegins, CERT_DELIMITER_W)))
929 return ERROR_INVALID_DATA;
931 dataBegins += strlenW(CERT_DELIMITER_W);
932 if (*dataBegins == '\r') dataBegins++;
933 if (*dataBegins == '\n') dataBegins++;
935 if (!(trailerBegins = strstrW(dataBegins, trailer)))
937 return ERROR_INVALID_DATA;
939 if (*(trailerBegins-1) == '\n') trailerBegins--;
940 if (*(trailerBegins-1) == '\r') trailerBegins--;
942 if (pdwSkip)
943 *pdwSkip = headerBegins - pszString;
945 dataLength = trailerBegins - dataBegins;
947 ret = Base64ToBinaryW(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
948 NULL);
950 return ret;
953 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
954 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
956 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
957 pbBinary, pcbBinary, pdwSkip);
959 if (!ret && pdwFlags)
960 *pdwFlags = CRYPT_STRING_BASE64HEADER;
961 return ret;
964 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
965 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
967 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
968 pbBinary, pcbBinary, pdwSkip);
970 if (!ret && pdwFlags)
971 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
972 return ret;
975 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
976 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
978 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
979 pbBinary, pcbBinary, pdwSkip);
981 if (!ret && pdwFlags)
982 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
983 return ret;
986 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
987 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
989 LONG ret;
991 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
992 pdwSkip, pdwFlags);
993 if (ret == ERROR_INVALID_DATA)
994 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
995 pdwSkip, pdwFlags);
996 return ret;
999 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
1000 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1002 LONG ret = ERROR_SUCCESS;
1004 if (*pcbBinary < cchString)
1006 if (!pbBinary)
1007 *pcbBinary = cchString;
1008 else
1010 ret = ERROR_INSUFFICIENT_BUFFER;
1011 *pcbBinary = cchString;
1014 else
1016 if (cchString)
1017 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1018 *pcbBinary = cchString * sizeof(WCHAR);
1020 return ret;
1023 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1024 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1026 LONG ret;
1028 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1029 pdwSkip, pdwFlags);
1030 if (ret == ERROR_INVALID_DATA)
1031 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1032 pdwSkip, pdwFlags);
1033 if (ret == ERROR_INVALID_DATA)
1034 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1035 pdwSkip, pdwFlags);
1036 return ret;
1039 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1040 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1041 DWORD *pdwSkip, DWORD *pdwFlags)
1043 StringToBinaryWFunc decoder;
1044 LONG ret;
1046 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_wn(pszString, cchString ? cchString : -1),
1047 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1049 if (!pszString)
1051 SetLastError(ERROR_INVALID_PARAMETER);
1052 return FALSE;
1054 /* Only the bottom byte contains valid types */
1055 if (dwFlags & 0xfffffff0)
1057 SetLastError(ERROR_INVALID_DATA);
1058 return FALSE;
1060 switch (dwFlags)
1062 case CRYPT_STRING_BASE64_ANY:
1063 decoder = Base64AnyToBinaryW;
1064 break;
1065 case CRYPT_STRING_BASE64:
1066 decoder = Base64ToBinaryW;
1067 break;
1068 case CRYPT_STRING_BASE64HEADER:
1069 decoder = Base64HeaderToBinaryW;
1070 break;
1071 case CRYPT_STRING_BASE64REQUESTHEADER:
1072 decoder = Base64RequestHeaderToBinaryW;
1073 break;
1074 case CRYPT_STRING_BASE64X509CRLHEADER:
1075 decoder = Base64X509HeaderToBinaryW;
1076 break;
1077 case CRYPT_STRING_BINARY:
1078 decoder = DecodeBinaryToBinaryW;
1079 break;
1080 case CRYPT_STRING_ANY:
1081 decoder = DecodeAnyW;
1082 break;
1083 case CRYPT_STRING_HEX:
1084 case CRYPT_STRING_HEXASCII:
1085 case CRYPT_STRING_HEXADDR:
1086 case CRYPT_STRING_HEXASCIIADDR:
1087 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1088 /* fall through */
1089 default:
1090 SetLastError(ERROR_INVALID_PARAMETER);
1091 return FALSE;
1093 if (!cchString)
1094 cchString = strlenW(pszString);
1095 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1096 if (ret)
1097 SetLastError(ret);
1098 return ret == ERROR_SUCCESS;