ddraw: Hack to draw to the desktop window.
[wine/hacks.git] / dlls / crypt32 / base64.c
blob7a23dd9a11183393cc0cef24bcdeff86a18e7517
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_TRAILER "-----END CERTIFICATE-----"
34 #define CERT_REQUEST_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
35 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
36 #define X509_HEADER "-----BEGIN X509 CRL-----"
37 #define X509_TRAILER "-----END X509 CRL-----"
39 static const WCHAR CERT_HEADER_W[] = {
40 '-','-','-','-','-','B','E','G','I','N',' ','C','E','R','T','I','F','I','C',
41 'A','T','E','-','-','-','-','-',0 };
42 static const WCHAR CERT_TRAILER_W[] = {
43 '-','-','-','-','-','E','N','D',' ','C','E','R','T','I','F','I','C','A','T',
44 'E','-','-','-','-','-',0 };
45 static const WCHAR CERT_REQUEST_HEADER_W[] = {
46 '-','-','-','-','-','B','E','G','I','N',' ','N','E','W',' ','C','E','R','T',
47 'I','F','I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
48 static const WCHAR CERT_REQUEST_TRAILER_W[] = {
49 '-','-','-','-','-','E','N','D',' ','N','E','W',' ','C','E','R','T','I','F',
50 'I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
51 static const WCHAR X509_HEADER_W[] = {
52 '-','-','-','-','-','B','E','G','I','N',' ','X','5','0','9',' ','C','R','L',
53 '-','-','-','-','-',0 };
54 static const WCHAR X509_TRAILER_W[] = {
55 '-','-','-','-','-','E','N','D',' ','X','5','0','9',' ','C','R','L','-','-',
56 '-','-','-',0 };
58 static const char b64[] =
59 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
61 typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary,
62 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString);
63 typedef BOOL (*BinaryToStringWFunc)(const BYTE *pbBinary,
64 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString);
66 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
67 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
69 BOOL ret = TRUE;
71 if (*pcchString < cbBinary)
73 if (!pszString)
74 *pcchString = cbBinary;
75 else
77 SetLastError(ERROR_INSUFFICIENT_BUFFER);
78 *pcchString = cbBinary;
79 ret = FALSE;
82 else
84 if (cbBinary)
85 memcpy(pszString, pbBinary, cbBinary);
86 *pcchString = cbBinary;
88 return ret;
91 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
92 char* out_buf, DWORD *out_len)
94 int div, i;
95 const BYTE *d = in_buf;
96 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
97 DWORD needed;
98 LPSTR ptr;
100 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
101 needed = bytes + pad_bytes + 1;
102 needed += (needed / 64 + 1) * strlen(sep);
104 if (needed > *out_len)
106 *out_len = needed;
107 return ERROR_INSUFFICIENT_BUFFER;
109 else
110 *out_len = needed;
112 /* Three bytes of input give 4 chars of output */
113 div = in_len / 3;
115 ptr = out_buf;
116 i = 0;
117 while (div > 0)
119 if (i && i % 64 == 0)
121 strcpy(ptr, sep);
122 ptr += strlen(sep);
124 /* first char is the first 6 bits of the first byte*/
125 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
126 /* second char is the last 2 bits of the first byte and the first 4
127 * bits of the second byte */
128 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
129 /* third char is the last 4 bits of the second byte and the first 2
130 * bits of the third byte */
131 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
132 /* fourth char is the remaining 6 bits of the third byte */
133 *ptr++ = b64[ d[2] & 0x3f];
134 i += 4;
135 d += 3;
136 div--;
139 switch(pad_bytes)
141 case 1:
142 /* first char is the first 6 bits of the first byte*/
143 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
144 /* second char is the last 2 bits of the first byte and the first 4
145 * bits of the second byte */
146 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
147 /* third char is the last 4 bits of the second byte padded with
148 * two zeroes */
149 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
150 /* fourth char is a = to indicate one byte of padding */
151 *ptr++ = '=';
152 break;
153 case 2:
154 /* first char is the first 6 bits of the first byte*/
155 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
156 /* second char is the last 2 bits of the first byte padded with
157 * four zeroes*/
158 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
159 /* third char is = to indicate padding */
160 *ptr++ = '=';
161 /* fourth char is = to indicate padding */
162 *ptr++ = '=';
163 break;
165 strcpy(ptr, sep);
167 return ERROR_SUCCESS;
170 static BOOL BinaryToBase64A(const BYTE *pbBinary,
171 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
173 static const char crlf[] = "\r\n", lf[] = "\n";
174 BOOL ret = TRUE;
175 LPCSTR header = NULL, trailer = NULL, sep;
176 DWORD charsNeeded;
178 if (dwFlags & CRYPT_STRING_NOCR)
179 sep = lf;
180 else if (dwFlags & CRYPT_STRING_NOCRLF)
181 sep = "";
182 else
183 sep = crlf;
184 switch (dwFlags & 0x0fffffff)
186 case CRYPT_STRING_BASE64:
187 /* no header or footer */
188 break;
189 case CRYPT_STRING_BASE64HEADER:
190 header = CERT_HEADER;
191 trailer = CERT_TRAILER;
192 break;
193 case CRYPT_STRING_BASE64REQUESTHEADER:
194 header = CERT_REQUEST_HEADER;
195 trailer = CERT_REQUEST_TRAILER;
196 break;
197 case CRYPT_STRING_BASE64X509CRLHEADER:
198 header = X509_HEADER;
199 trailer = X509_TRAILER;
200 break;
203 charsNeeded = 0;
204 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
205 if (header)
206 charsNeeded += strlen(header) + strlen(sep);
207 if (trailer)
208 charsNeeded += strlen(trailer) + strlen(sep);
209 if (charsNeeded <= *pcchString)
211 LPSTR ptr = pszString;
212 DWORD size = charsNeeded;
214 if (header)
216 strcpy(ptr, header);
217 ptr += strlen(ptr);
218 strcpy(ptr, sep);
219 ptr += strlen(sep);
221 encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
222 ptr += size - 1;
223 if (trailer)
225 strcpy(ptr, trailer);
226 ptr += strlen(ptr);
227 strcpy(ptr, sep);
228 ptr += strlen(sep);
230 *pcchString = charsNeeded - 1;
232 else if (pszString)
234 *pcchString = charsNeeded;
235 SetLastError(ERROR_INSUFFICIENT_BUFFER);
236 ret = FALSE;
238 else
239 *pcchString = charsNeeded;
240 return ret;
243 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
244 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
246 BinaryToStringAFunc encoder = NULL;
248 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
249 pcchString);
251 if (!pbBinary)
253 SetLastError(ERROR_INVALID_PARAMETER);
254 return FALSE;
256 if (!pcchString)
258 SetLastError(ERROR_INVALID_PARAMETER);
259 return FALSE;
262 switch (dwFlags & 0x0fffffff)
264 case CRYPT_STRING_BINARY:
265 encoder = EncodeBinaryToBinaryA;
266 break;
267 case CRYPT_STRING_BASE64:
268 case CRYPT_STRING_BASE64HEADER:
269 case CRYPT_STRING_BASE64REQUESTHEADER:
270 case CRYPT_STRING_BASE64X509CRLHEADER:
271 encoder = BinaryToBase64A;
272 break;
273 case CRYPT_STRING_HEX:
274 case CRYPT_STRING_HEXASCII:
275 case CRYPT_STRING_HEXADDR:
276 case CRYPT_STRING_HEXASCIIADDR:
277 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
278 /* fall through */
279 default:
280 SetLastError(ERROR_INVALID_PARAMETER);
281 return FALSE;
283 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
286 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
287 WCHAR* out_buf, DWORD *out_len)
289 int div, i;
290 const BYTE *d = in_buf;
291 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
292 DWORD needed;
293 LPWSTR ptr;
295 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
296 needed = bytes + pad_bytes + 1;
297 needed += (needed / 64 + 1) * strlenW(sep);
299 if (needed > *out_len)
301 *out_len = needed;
302 return ERROR_INSUFFICIENT_BUFFER;
304 else
305 *out_len = needed;
307 /* Three bytes of input give 4 chars of output */
308 div = in_len / 3;
310 ptr = out_buf;
311 i = 0;
312 while (div > 0)
314 if (i && i % 64 == 0)
316 strcpyW(ptr, sep);
317 ptr += strlenW(sep);
319 /* first char is the first 6 bits of the first byte*/
320 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
321 /* second char is the last 2 bits of the first byte and the first 4
322 * bits of the second byte */
323 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
324 /* third char is the last 4 bits of the second byte and the first 2
325 * bits of the third byte */
326 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
327 /* fourth char is the remaining 6 bits of the third byte */
328 *ptr++ = b64[ d[2] & 0x3f];
329 i += 4;
330 d += 3;
331 div--;
334 switch(pad_bytes)
336 case 1:
337 /* first char is the first 6 bits of the first byte*/
338 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
339 /* second char is the last 2 bits of the first byte and the first 4
340 * bits of the second byte */
341 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
342 /* third char is the last 4 bits of the second byte padded with
343 * two zeroes */
344 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
345 /* fourth char is a = to indicate one byte of padding */
346 *ptr++ = '=';
347 break;
348 case 2:
349 /* first char is the first 6 bits of the first byte*/
350 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
351 /* second char is the last 2 bits of the first byte padded with
352 * four zeroes*/
353 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
354 /* third char is = to indicate padding */
355 *ptr++ = '=';
356 /* fourth char is = to indicate padding */
357 *ptr++ = '=';
358 break;
360 strcpyW(ptr, sep);
362 return ERROR_SUCCESS;
365 static BOOL BinaryToBase64W(const BYTE *pbBinary,
366 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
368 static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 }, empty[] = {0};
369 BOOL ret = TRUE;
370 LPCWSTR header = NULL, trailer = NULL, sep;
371 DWORD charsNeeded;
373 if (dwFlags & CRYPT_STRING_NOCR)
374 sep = lf;
375 else if (dwFlags & CRYPT_STRING_NOCRLF)
376 sep = empty;
377 else
378 sep = crlf;
379 switch (dwFlags & 0x0fffffff)
381 case CRYPT_STRING_BASE64:
382 /* no header or footer */
383 break;
384 case CRYPT_STRING_BASE64HEADER:
385 header = CERT_HEADER_W;
386 trailer = CERT_TRAILER_W;
387 break;
388 case CRYPT_STRING_BASE64REQUESTHEADER:
389 header = CERT_REQUEST_HEADER_W;
390 trailer = CERT_REQUEST_TRAILER_W;
391 break;
392 case CRYPT_STRING_BASE64X509CRLHEADER:
393 header = X509_HEADER_W;
394 trailer = X509_TRAILER_W;
395 break;
398 charsNeeded = 0;
399 encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
400 if (header)
401 charsNeeded += strlenW(header) + strlenW(sep);
402 if (trailer)
403 charsNeeded += strlenW(trailer) + strlenW(sep);
404 if (charsNeeded <= *pcchString)
406 LPWSTR ptr = pszString;
407 DWORD size = charsNeeded;
409 if (header)
411 strcpyW(ptr, header);
412 ptr += strlenW(ptr);
413 strcpyW(ptr, sep);
414 ptr += strlenW(sep);
416 encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
417 ptr += size - 1;
418 if (trailer)
420 strcpyW(ptr, trailer);
421 ptr += strlenW(ptr);
422 strcpyW(ptr, sep);
423 ptr += strlenW(sep);
425 *pcchString = charsNeeded - 1;
427 else if (pszString)
429 *pcchString = charsNeeded;
430 SetLastError(ERROR_INSUFFICIENT_BUFFER);
431 ret = FALSE;
433 else
434 *pcchString = charsNeeded;
435 return ret;
438 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
439 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
441 BinaryToStringWFunc encoder = NULL;
443 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
444 pcchString);
446 if (!pbBinary)
448 SetLastError(ERROR_INVALID_PARAMETER);
449 return FALSE;
451 if (!pcchString)
453 SetLastError(ERROR_INVALID_PARAMETER);
454 return FALSE;
457 switch (dwFlags & 0x0fffffff)
459 case CRYPT_STRING_BASE64:
460 case CRYPT_STRING_BASE64HEADER:
461 case CRYPT_STRING_BASE64REQUESTHEADER:
462 case CRYPT_STRING_BASE64X509CRLHEADER:
463 encoder = BinaryToBase64W;
464 break;
465 case CRYPT_STRING_BINARY:
466 case CRYPT_STRING_HEX:
467 case CRYPT_STRING_HEXASCII:
468 case CRYPT_STRING_HEXADDR:
469 case CRYPT_STRING_HEXASCIIADDR:
470 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
471 /* fall through */
472 default:
473 SetLastError(ERROR_INVALID_PARAMETER);
474 return FALSE;
476 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
479 static inline BYTE decodeBase64Byte(int c)
481 BYTE ret;
483 if (c >= 'A' && c <= 'Z')
484 ret = c - 'A';
485 else if (c >= 'a' && c <= 'z')
486 ret = c - 'a' + 26;
487 else if (c >= '0' && c <= '9')
488 ret = c - '0' + 52;
489 else if (c == '+')
490 ret = 62;
491 else if (c == '/')
492 ret = 63;
493 else
494 ret = 64;
495 return ret;
498 static LONG decodeBase64Block(const char *in_buf, int in_len,
499 const char **nextBlock, PBYTE out_buf, DWORD *out_len)
501 int len = in_len, i;
502 const char *d = in_buf;
503 int ip0, ip1, ip2, ip3;
505 if (len < 4)
506 return ERROR_INVALID_DATA;
508 i = 0;
509 if (d[2] == '=')
511 if ((ip0 = decodeBase64Byte(d[0])) > 63)
512 return ERROR_INVALID_DATA;
513 if ((ip1 = decodeBase64Byte(d[1])) > 63)
514 return ERROR_INVALID_DATA;
516 if (out_buf)
517 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
518 i++;
520 else if (d[3] == '=')
522 if ((ip0 = decodeBase64Byte(d[0])) > 63)
523 return ERROR_INVALID_DATA;
524 if ((ip1 = decodeBase64Byte(d[1])) > 63)
525 return ERROR_INVALID_DATA;
526 if ((ip2 = decodeBase64Byte(d[2])) > 63)
527 return ERROR_INVALID_DATA;
529 if (out_buf)
531 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
532 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
534 i += 2;
536 else
538 if ((ip0 = decodeBase64Byte(d[0])) > 63)
539 return ERROR_INVALID_DATA;
540 if ((ip1 = decodeBase64Byte(d[1])) > 63)
541 return ERROR_INVALID_DATA;
542 if ((ip2 = decodeBase64Byte(d[2])) > 63)
543 return ERROR_INVALID_DATA;
544 if ((ip3 = decodeBase64Byte(d[3])) > 63)
545 return ERROR_INVALID_DATA;
547 if (out_buf)
549 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
550 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
551 out_buf[i + 2] = (ip2 << 6) | ip3;
553 i += 3;
555 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
556 *nextBlock = d + 6;
557 else if (len >= 5 && d[4] == '\n')
558 *nextBlock = d + 5;
559 else if (len >= 4 && d[4])
560 *nextBlock = d + 4;
561 else
562 *nextBlock = NULL;
563 *out_len = i;
564 return ERROR_SUCCESS;
567 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
568 * string to convert.
570 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
571 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
573 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
574 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
576 LONG ret = ERROR_SUCCESS;
577 const char *nextBlock;
578 DWORD outLen = 0;
580 nextBlock = pszString;
581 while (nextBlock && !ret)
583 DWORD len = 0;
585 ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
586 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
587 if (!ret)
588 outLen += len;
589 if (cchString - (nextBlock - pszString) <= 0)
590 nextBlock = NULL;
592 *pcbBinary = outLen;
593 if (!ret)
595 if (pdwSkip)
596 *pdwSkip = 0;
597 if (pdwFlags)
598 *pdwFlags = CRYPT_STRING_BASE64;
600 else if (ret == ERROR_INSUFFICIENT_BUFFER)
602 if (!pbBinary)
603 ret = ERROR_SUCCESS;
605 return ret;
608 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
609 DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
610 DWORD *pcbBinary, DWORD *pdwSkip)
612 LONG ret;
613 LPCSTR ptr;
615 if (cchString > strlen(header) + strlen(trailer)
616 && (ptr = strstr(pszString, header)) != NULL)
618 LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
620 if (pszString[cchString - 1] == '\n')
622 cchString--;
623 trailerSpot--;
625 if (pszString[cchString - 1] == '\r')
627 cchString--;
628 trailerSpot--;
630 if (!strncmp(trailerSpot, trailer, strlen(trailer)))
632 if (pdwSkip)
633 *pdwSkip = ptr - pszString;
634 ptr += strlen(header);
635 if (*ptr == '\r') ptr++;
636 if (*ptr == '\n') ptr++;
637 cchString -= ptr - pszString + strlen(trailer);
638 ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL,
639 NULL);
641 else
642 ret = ERROR_INVALID_DATA;
644 else
645 ret = ERROR_INVALID_DATA;
646 return ret;
649 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
650 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
652 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
653 CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
655 if (!ret && pdwFlags)
656 *pdwFlags = CRYPT_STRING_BASE64HEADER;
657 return ret;
660 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
661 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
663 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
664 CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
666 if (!ret && pdwFlags)
667 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
668 return ret;
671 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
672 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
674 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
675 X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
677 if (!ret && pdwFlags)
678 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
679 return ret;
682 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
683 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
685 LONG ret;
687 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
688 pdwSkip, pdwFlags);
689 if (ret == ERROR_INVALID_DATA)
690 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
691 pdwSkip, pdwFlags);
692 return ret;
695 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
696 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
698 LONG ret = ERROR_SUCCESS;
700 if (*pcbBinary < cchString)
702 if (!pbBinary)
703 *pcbBinary = cchString;
704 else
706 ret = ERROR_INSUFFICIENT_BUFFER;
707 *pcbBinary = cchString;
710 else
712 if (cchString)
713 memcpy(pbBinary, pszString, cchString);
714 *pcbBinary = cchString;
716 return ret;
719 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
720 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
722 LONG ret;
724 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
725 pdwSkip, pdwFlags);
726 if (ret == ERROR_INVALID_DATA)
727 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
728 pdwSkip, pdwFlags);
729 if (ret == ERROR_INVALID_DATA)
730 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
731 pdwSkip, pdwFlags);
732 return ret;
735 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
736 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
737 DWORD *pdwSkip, DWORD *pdwFlags)
739 StringToBinaryAFunc decoder;
740 LONG ret;
742 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
743 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
745 if (!pszString)
747 SetLastError(ERROR_INVALID_PARAMETER);
748 return FALSE;
750 /* Only the bottom byte contains valid types */
751 if (dwFlags & 0xfffffff0)
753 SetLastError(ERROR_INVALID_DATA);
754 return FALSE;
756 switch (dwFlags)
758 case CRYPT_STRING_BASE64_ANY:
759 decoder = Base64AnyToBinaryA;
760 break;
761 case CRYPT_STRING_BASE64:
762 decoder = Base64ToBinaryA;
763 break;
764 case CRYPT_STRING_BASE64HEADER:
765 decoder = Base64HeaderToBinaryA;
766 break;
767 case CRYPT_STRING_BASE64REQUESTHEADER:
768 decoder = Base64RequestHeaderToBinaryA;
769 break;
770 case CRYPT_STRING_BASE64X509CRLHEADER:
771 decoder = Base64X509HeaderToBinaryA;
772 break;
773 case CRYPT_STRING_BINARY:
774 decoder = DecodeBinaryToBinaryA;
775 break;
776 case CRYPT_STRING_ANY:
777 decoder = DecodeAnyA;
778 break;
779 case CRYPT_STRING_HEX:
780 case CRYPT_STRING_HEXASCII:
781 case CRYPT_STRING_HEXADDR:
782 case CRYPT_STRING_HEXASCIIADDR:
783 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
784 /* fall through */
785 default:
786 SetLastError(ERROR_INVALID_PARAMETER);
787 return FALSE;
789 if (!cchString)
790 cchString = strlen(pszString);
791 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
792 if (ret)
793 SetLastError(ret);
794 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
797 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
798 const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
800 int len = in_len, i;
801 const WCHAR *d = in_buf;
802 int ip0, ip1, ip2, ip3;
804 if (len < 4)
805 return ERROR_INVALID_DATA;
807 i = 0;
808 if (d[2] == '=')
810 if ((ip0 = decodeBase64Byte(d[0])) > 63)
811 return ERROR_INVALID_DATA;
812 if ((ip1 = decodeBase64Byte(d[1])) > 63)
813 return ERROR_INVALID_DATA;
815 if (out_buf)
816 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
817 i++;
819 else if (d[3] == '=')
821 if ((ip0 = decodeBase64Byte(d[0])) > 63)
822 return ERROR_INVALID_DATA;
823 if ((ip1 = decodeBase64Byte(d[1])) > 63)
824 return ERROR_INVALID_DATA;
825 if ((ip2 = decodeBase64Byte(d[2])) > 63)
826 return ERROR_INVALID_DATA;
828 if (out_buf)
830 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
831 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
833 i += 2;
835 else
837 if ((ip0 = decodeBase64Byte(d[0])) > 63)
838 return ERROR_INVALID_DATA;
839 if ((ip1 = decodeBase64Byte(d[1])) > 63)
840 return ERROR_INVALID_DATA;
841 if ((ip2 = decodeBase64Byte(d[2])) > 63)
842 return ERROR_INVALID_DATA;
843 if ((ip3 = decodeBase64Byte(d[3])) > 63)
844 return ERROR_INVALID_DATA;
846 if (out_buf)
848 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
849 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
850 out_buf[i + 2] = (ip2 << 6) | ip3;
852 i += 3;
854 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
855 *nextBlock = d + 6;
856 else if (len >= 5 && d[4] == '\n')
857 *nextBlock = d + 5;
858 else if (len >= 4 && d[4])
859 *nextBlock = d + 4;
860 else
861 *nextBlock = NULL;
862 *out_len = i;
863 return ERROR_SUCCESS;
866 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
867 * string to convert.
869 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
870 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
872 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
873 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
875 LONG ret = ERROR_SUCCESS;
876 const WCHAR *nextBlock;
877 DWORD outLen = 0;
879 nextBlock = pszString;
880 while (nextBlock && !ret)
882 DWORD len = 0;
884 ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
885 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
886 if (!ret)
887 outLen += len;
888 if (cchString - (nextBlock - pszString) <= 0)
889 nextBlock = NULL;
891 *pcbBinary = outLen;
892 if (!ret)
894 if (pdwSkip)
895 *pdwSkip = 0;
896 if (pdwFlags)
897 *pdwFlags = CRYPT_STRING_BASE64;
899 else if (ret == ERROR_INSUFFICIENT_BUFFER)
901 if (!pbBinary)
902 ret = ERROR_SUCCESS;
904 return ret;
907 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
908 DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
909 DWORD *pcbBinary, DWORD *pdwSkip)
911 LONG ret;
912 LPCWSTR ptr;
914 if (cchString > strlenW(header) + strlenW(trailer)
915 && (ptr = strstrW(pszString, header)) != NULL)
917 LPCWSTR trailerSpot = pszString + cchString - strlenW(trailer);
919 if (pszString[cchString - 1] == '\n')
921 cchString--;
922 trailerSpot--;
924 if (pszString[cchString - 1] == '\r')
926 cchString--;
927 trailerSpot--;
929 if (!strncmpW(trailerSpot, trailer, strlenW(trailer)))
931 if (pdwSkip)
932 *pdwSkip = ptr - pszString;
933 ptr += strlenW(header);
934 if (*ptr == '\r') ptr++;
935 if (*ptr == '\n') ptr++;
936 cchString -= ptr - pszString + strlenW(trailer);
937 ret = Base64ToBinaryW(ptr, cchString, pbBinary, pcbBinary, NULL,
938 NULL);
940 else
941 ret = ERROR_INVALID_DATA;
943 else
944 ret = ERROR_INVALID_DATA;
945 return ret;
948 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
949 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
951 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
952 CERT_HEADER_W, CERT_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
954 if (!ret && pdwFlags)
955 *pdwFlags = CRYPT_STRING_BASE64HEADER;
956 return ret;
959 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
960 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
962 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
963 CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
964 pdwSkip);
966 if (!ret && pdwFlags)
967 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
968 return ret;
971 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
972 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
974 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
975 X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
977 if (!ret && pdwFlags)
978 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
979 return ret;
982 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
983 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
985 LONG ret;
987 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
988 pdwSkip, pdwFlags);
989 if (ret == ERROR_INVALID_DATA)
990 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
991 pdwSkip, pdwFlags);
992 return ret;
995 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
996 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
998 LONG ret = ERROR_SUCCESS;
1000 if (*pcbBinary < cchString)
1002 if (!pbBinary)
1003 *pcbBinary = cchString;
1004 else
1006 ret = ERROR_INSUFFICIENT_BUFFER;
1007 *pcbBinary = cchString;
1010 else
1012 if (cchString)
1013 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1014 *pcbBinary = cchString * sizeof(WCHAR);
1016 return ret;
1019 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1020 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1022 LONG ret;
1024 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1025 pdwSkip, pdwFlags);
1026 if (ret == ERROR_INVALID_DATA)
1027 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1028 pdwSkip, pdwFlags);
1029 if (ret == ERROR_INVALID_DATA)
1030 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1031 pdwSkip, pdwFlags);
1032 return ret;
1035 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1036 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1037 DWORD *pdwSkip, DWORD *pdwFlags)
1039 StringToBinaryWFunc decoder;
1040 LONG ret;
1042 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
1043 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1045 if (!pszString)
1047 SetLastError(ERROR_INVALID_PARAMETER);
1048 return FALSE;
1050 /* Only the bottom byte contains valid types */
1051 if (dwFlags & 0xfffffff0)
1053 SetLastError(ERROR_INVALID_DATA);
1054 return FALSE;
1056 switch (dwFlags)
1058 case CRYPT_STRING_BASE64_ANY:
1059 decoder = Base64AnyToBinaryW;
1060 break;
1061 case CRYPT_STRING_BASE64:
1062 decoder = Base64ToBinaryW;
1063 break;
1064 case CRYPT_STRING_BASE64HEADER:
1065 decoder = Base64HeaderToBinaryW;
1066 break;
1067 case CRYPT_STRING_BASE64REQUESTHEADER:
1068 decoder = Base64RequestHeaderToBinaryW;
1069 break;
1070 case CRYPT_STRING_BASE64X509CRLHEADER:
1071 decoder = Base64X509HeaderToBinaryW;
1072 break;
1073 case CRYPT_STRING_BINARY:
1074 decoder = DecodeBinaryToBinaryW;
1075 break;
1076 case CRYPT_STRING_ANY:
1077 decoder = DecodeAnyW;
1078 break;
1079 case CRYPT_STRING_HEX:
1080 case CRYPT_STRING_HEXASCII:
1081 case CRYPT_STRING_HEXADDR:
1082 case CRYPT_STRING_HEXASCIIADDR:
1083 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1084 /* fall through */
1085 default:
1086 SetLastError(ERROR_INVALID_PARAMETER);
1087 return FALSE;
1089 if (!cchString)
1090 cchString = strlenW(pszString);
1091 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1092 if (ret)
1093 SetLastError(ret);
1094 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;