msvcrt: Add support for template operators in symbol demangling.
[wine/testsucceed.git] / dlls / crypt32 / base64.c
blob9a3079a81f3191c6e6fe2ff4f7e1c3b07bb35951
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',0 };
51 static const WCHAR CERT_TRAILER_START_W[] = {
52 '-','-','-','-','-','E','N','D',' ','C','E','R','T','I','F','I','C','A','T',
53 'E','-','-','-','-','-',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 (*pcchString < cbBinary)
82 if (!pszString)
83 *pcchString = cbBinary;
84 else
86 SetLastError(ERROR_INSUFFICIENT_BUFFER);
87 *pcchString = cbBinary;
88 ret = FALSE;
91 else
93 if (cbBinary)
94 memcpy(pszString, pbBinary, cbBinary);
95 *pcchString = cbBinary;
97 return ret;
100 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
101 char* out_buf, DWORD *out_len)
103 int div, i;
104 const BYTE *d = in_buf;
105 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
106 DWORD needed;
107 LPSTR ptr;
109 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
110 needed = bytes + pad_bytes + 1;
111 needed += (needed / 64 + 1) * strlen(sep);
113 if (needed > *out_len)
115 *out_len = needed;
116 return ERROR_INSUFFICIENT_BUFFER;
118 else
119 *out_len = needed;
121 /* Three bytes of input give 4 chars of output */
122 div = in_len / 3;
124 ptr = out_buf;
125 i = 0;
126 while (div > 0)
128 if (i && i % 64 == 0)
130 strcpy(ptr, sep);
131 ptr += strlen(sep);
133 /* first char is the first 6 bits of the first byte*/
134 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
135 /* second char is the last 2 bits of the first byte and the first 4
136 * bits of the second byte */
137 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
138 /* third char is the last 4 bits of the second byte and the first 2
139 * bits of the third byte */
140 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
141 /* fourth char is the remaining 6 bits of the third byte */
142 *ptr++ = b64[ d[2] & 0x3f];
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 *ptr++ = 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 *ptr++ = 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 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
159 /* fourth char is a = to indicate one byte of padding */
160 *ptr++ = '=';
161 break;
162 case 2:
163 /* first char is the first 6 bits of the first byte*/
164 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
165 /* second char is the last 2 bits of the first byte padded with
166 * four zeroes*/
167 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
168 /* third char is = to indicate padding */
169 *ptr++ = '=';
170 /* fourth char is = to indicate padding */
171 *ptr++ = '=';
172 break;
174 strcpy(ptr, sep);
176 return ERROR_SUCCESS;
179 static BOOL BinaryToBase64A(const BYTE *pbBinary,
180 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
182 static const char crlf[] = "\r\n", lf[] = "\n";
183 BOOL ret = TRUE;
184 LPCSTR header = NULL, trailer = NULL, sep;
185 DWORD charsNeeded;
187 if (dwFlags & CRYPT_STRING_NOCR)
188 sep = lf;
189 else if (dwFlags & CRYPT_STRING_NOCRLF)
190 sep = "";
191 else
192 sep = crlf;
193 switch (dwFlags & 0x0fffffff)
195 case CRYPT_STRING_BASE64:
196 /* no header or footer */
197 break;
198 case CRYPT_STRING_BASE64HEADER:
199 header = CERT_HEADER;
200 trailer = CERT_TRAILER;
201 break;
202 case CRYPT_STRING_BASE64REQUESTHEADER:
203 header = CERT_REQUEST_HEADER;
204 trailer = CERT_REQUEST_TRAILER;
205 break;
206 case CRYPT_STRING_BASE64X509CRLHEADER:
207 header = X509_HEADER;
208 trailer = X509_TRAILER;
209 break;
212 charsNeeded = 0;
213 encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
214 if (header)
215 charsNeeded += strlen(header) + strlen(sep);
216 if (trailer)
217 charsNeeded += strlen(trailer) + strlen(sep);
218 if (charsNeeded <= *pcchString)
220 LPSTR ptr = pszString;
221 DWORD size = charsNeeded;
223 if (header)
225 strcpy(ptr, header);
226 ptr += strlen(ptr);
227 strcpy(ptr, sep);
228 ptr += strlen(sep);
230 encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
231 ptr += size - 1;
232 if (trailer)
234 strcpy(ptr, trailer);
235 ptr += strlen(ptr);
236 strcpy(ptr, sep);
237 ptr += strlen(sep);
239 *pcchString = charsNeeded - 1;
241 else if (pszString)
243 *pcchString = charsNeeded;
244 SetLastError(ERROR_INSUFFICIENT_BUFFER);
245 ret = FALSE;
247 else
248 *pcchString = charsNeeded;
249 return ret;
252 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
253 DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
255 BinaryToStringAFunc encoder = NULL;
257 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
258 pcchString);
260 if (!pbBinary)
262 SetLastError(ERROR_INVALID_PARAMETER);
263 return FALSE;
265 if (!pcchString)
267 SetLastError(ERROR_INVALID_PARAMETER);
268 return FALSE;
271 switch (dwFlags & 0x0fffffff)
273 case CRYPT_STRING_BINARY:
274 encoder = EncodeBinaryToBinaryA;
275 break;
276 case CRYPT_STRING_BASE64:
277 case CRYPT_STRING_BASE64HEADER:
278 case CRYPT_STRING_BASE64REQUESTHEADER:
279 case CRYPT_STRING_BASE64X509CRLHEADER:
280 encoder = BinaryToBase64A;
281 break;
282 case CRYPT_STRING_HEX:
283 case CRYPT_STRING_HEXASCII:
284 case CRYPT_STRING_HEXADDR:
285 case CRYPT_STRING_HEXASCIIADDR:
286 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
287 /* fall through */
288 default:
289 SetLastError(ERROR_INVALID_PARAMETER);
290 return FALSE;
292 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
295 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
296 WCHAR* out_buf, DWORD *out_len)
298 int div, i;
299 const BYTE *d = in_buf;
300 int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
301 DWORD needed;
302 LPWSTR ptr;
304 TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
305 needed = bytes + pad_bytes + 1;
306 needed += (needed / 64 + 1) * strlenW(sep);
308 if (needed > *out_len)
310 *out_len = needed;
311 return ERROR_INSUFFICIENT_BUFFER;
313 else
314 *out_len = needed;
316 /* Three bytes of input give 4 chars of output */
317 div = in_len / 3;
319 ptr = out_buf;
320 i = 0;
321 while (div > 0)
323 if (i && i % 64 == 0)
325 strcpyW(ptr, sep);
326 ptr += strlenW(sep);
328 /* first char is the first 6 bits of the first byte*/
329 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
330 /* second char is the last 2 bits of the first byte and the first 4
331 * bits of the second byte */
332 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
333 /* third char is the last 4 bits of the second byte and the first 2
334 * bits of the third byte */
335 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
336 /* fourth char is the remaining 6 bits of the third byte */
337 *ptr++ = b64[ d[2] & 0x3f];
338 i += 4;
339 d += 3;
340 div--;
343 switch(pad_bytes)
345 case 1:
346 /* first char is the first 6 bits of the first byte*/
347 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
348 /* second char is the last 2 bits of the first byte and the first 4
349 * bits of the second byte */
350 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
351 /* third char is the last 4 bits of the second byte padded with
352 * two zeroes */
353 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
354 /* fourth char is a = to indicate one byte of padding */
355 *ptr++ = '=';
356 break;
357 case 2:
358 /* first char is the first 6 bits of the first byte*/
359 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
360 /* second char is the last 2 bits of the first byte padded with
361 * four zeroes*/
362 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
363 /* third char is = to indicate padding */
364 *ptr++ = '=';
365 /* fourth char is = to indicate padding */
366 *ptr++ = '=';
367 break;
369 strcpyW(ptr, sep);
371 return ERROR_SUCCESS;
374 static BOOL BinaryToBase64W(const BYTE *pbBinary,
375 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
377 static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 }, empty[] = {0};
378 BOOL ret = TRUE;
379 LPCWSTR header = NULL, trailer = NULL, sep;
380 DWORD charsNeeded;
382 if (dwFlags & CRYPT_STRING_NOCR)
383 sep = lf;
384 else if (dwFlags & CRYPT_STRING_NOCRLF)
385 sep = empty;
386 else
387 sep = crlf;
388 switch (dwFlags & 0x0fffffff)
390 case CRYPT_STRING_BASE64:
391 /* no header or footer */
392 break;
393 case CRYPT_STRING_BASE64HEADER:
394 header = CERT_HEADER_W;
395 trailer = CERT_TRAILER_W;
396 break;
397 case CRYPT_STRING_BASE64REQUESTHEADER:
398 header = CERT_REQUEST_HEADER_W;
399 trailer = CERT_REQUEST_TRAILER_W;
400 break;
401 case CRYPT_STRING_BASE64X509CRLHEADER:
402 header = X509_HEADER_W;
403 trailer = X509_TRAILER_W;
404 break;
407 charsNeeded = 0;
408 encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
409 if (header)
410 charsNeeded += strlenW(header) + strlenW(sep);
411 if (trailer)
412 charsNeeded += strlenW(trailer) + strlenW(sep);
413 if (charsNeeded <= *pcchString)
415 LPWSTR ptr = pszString;
416 DWORD size = charsNeeded;
418 if (header)
420 strcpyW(ptr, header);
421 ptr += strlenW(ptr);
422 strcpyW(ptr, sep);
423 ptr += strlenW(sep);
425 encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
426 ptr += size - 1;
427 if (trailer)
429 strcpyW(ptr, trailer);
430 ptr += strlenW(ptr);
431 strcpyW(ptr, sep);
432 ptr += strlenW(sep);
434 *pcchString = charsNeeded - 1;
436 else if (pszString)
438 *pcchString = charsNeeded;
439 SetLastError(ERROR_INSUFFICIENT_BUFFER);
440 ret = FALSE;
442 else
443 *pcchString = charsNeeded;
444 return ret;
447 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
448 DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
450 BinaryToStringWFunc encoder = NULL;
452 TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
453 pcchString);
455 if (!pbBinary)
457 SetLastError(ERROR_INVALID_PARAMETER);
458 return FALSE;
460 if (!pcchString)
462 SetLastError(ERROR_INVALID_PARAMETER);
463 return FALSE;
466 switch (dwFlags & 0x0fffffff)
468 case CRYPT_STRING_BASE64:
469 case CRYPT_STRING_BASE64HEADER:
470 case CRYPT_STRING_BASE64REQUESTHEADER:
471 case CRYPT_STRING_BASE64X509CRLHEADER:
472 encoder = BinaryToBase64W;
473 break;
474 case CRYPT_STRING_BINARY:
475 case CRYPT_STRING_HEX:
476 case CRYPT_STRING_HEXASCII:
477 case CRYPT_STRING_HEXADDR:
478 case CRYPT_STRING_HEXASCIIADDR:
479 FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
480 /* fall through */
481 default:
482 SetLastError(ERROR_INVALID_PARAMETER);
483 return FALSE;
485 return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
488 static inline BYTE decodeBase64Byte(int c)
490 BYTE ret;
492 if (c >= 'A' && c <= 'Z')
493 ret = c - 'A';
494 else if (c >= 'a' && c <= 'z')
495 ret = c - 'a' + 26;
496 else if (c >= '0' && c <= '9')
497 ret = c - '0' + 52;
498 else if (c == '+')
499 ret = 62;
500 else if (c == '/')
501 ret = 63;
502 else
503 ret = 64;
504 return ret;
507 static LONG decodeBase64Block(const char *in_buf, int in_len,
508 const char **nextBlock, PBYTE out_buf, DWORD *out_len)
510 int len = in_len;
511 const char *d = in_buf;
512 int ip0, ip1, ip2, ip3;
514 if (len < 4)
515 return ERROR_INVALID_DATA;
517 if (d[2] == '=')
519 if ((ip0 = decodeBase64Byte(d[0])) > 63)
520 return ERROR_INVALID_DATA;
521 if ((ip1 = decodeBase64Byte(d[1])) > 63)
522 return ERROR_INVALID_DATA;
524 if (out_buf)
525 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
526 *out_len = 1;
528 else if (d[3] == '=')
530 if ((ip0 = decodeBase64Byte(d[0])) > 63)
531 return ERROR_INVALID_DATA;
532 if ((ip1 = decodeBase64Byte(d[1])) > 63)
533 return ERROR_INVALID_DATA;
534 if ((ip2 = decodeBase64Byte(d[2])) > 63)
535 return ERROR_INVALID_DATA;
537 if (out_buf)
539 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
540 out_buf[1] = (ip1 << 4) | (ip2 >> 2);
542 *out_len = 2;
544 else
546 if ((ip0 = decodeBase64Byte(d[0])) > 63)
547 return ERROR_INVALID_DATA;
548 if ((ip1 = decodeBase64Byte(d[1])) > 63)
549 return ERROR_INVALID_DATA;
550 if ((ip2 = decodeBase64Byte(d[2])) > 63)
551 return ERROR_INVALID_DATA;
552 if ((ip3 = decodeBase64Byte(d[3])) > 63)
553 return ERROR_INVALID_DATA;
555 if (out_buf)
557 out_buf[0] = (ip0 << 2) | (ip1 >> 4);
558 out_buf[1] = (ip1 << 4) | (ip2 >> 2);
559 out_buf[2] = (ip2 << 6) | ip3;
561 *out_len = 3;
563 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
564 *nextBlock = d + 6;
565 else if (len >= 5 && d[4] == '\n')
566 *nextBlock = d + 5;
567 else if (len >= 4 && d[4])
568 *nextBlock = d + 4;
569 else
570 *nextBlock = NULL;
571 return ERROR_SUCCESS;
574 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
575 * string to convert.
577 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
578 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
580 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
581 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
583 LONG ret = ERROR_SUCCESS;
584 const char *nextBlock;
585 DWORD outLen = 0;
587 nextBlock = pszString;
588 while (nextBlock && !ret)
590 DWORD len = 0;
592 ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
593 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
594 if (!ret)
595 outLen += len;
596 if (cchString - (nextBlock - pszString) <= 0)
597 nextBlock = NULL;
599 *pcbBinary = outLen;
600 if (!ret)
602 if (pdwSkip)
603 *pdwSkip = 0;
604 if (pdwFlags)
605 *pdwFlags = CRYPT_STRING_BASE64;
607 else if (ret == ERROR_INSUFFICIENT_BUFFER)
609 if (!pbBinary)
610 ret = ERROR_SUCCESS;
612 return ret;
615 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
616 DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
617 DWORD *pcbBinary, DWORD *pdwSkip, BOOL exactHeaderAndTrailerMatch)
619 LONG ret;
621 LPCSTR headerBegins;
622 LPCSTR dataBegins;
623 LPCSTR trailerBegins;
624 size_t dataLength;
626 if ((strlen(header) + strlen(trailer)) > cchString)
628 return ERROR_INVALID_DATA;
631 if (!(headerBegins = strstr(pszString, header)))
633 TRACE("Can't find %s in %s.\n", header, pszString);
634 return ERROR_INVALID_DATA;
637 dataBegins = headerBegins + strlen(header);
638 if (!exactHeaderAndTrailerMatch)
640 if ((dataBegins = strstr(dataBegins, CERT_DELIMITER)))
642 dataBegins += strlen(CERT_DELIMITER);
644 else
646 return ERROR_INVALID_DATA;
649 if (*dataBegins == '\r') dataBegins++;
650 if (*dataBegins == '\n') dataBegins++;
652 if (exactHeaderAndTrailerMatch)
654 trailerBegins = pszString + cchString - strlen(trailer);
655 if (pszString[cchString - 1] == '\n') trailerBegins--;
656 if (pszString[cchString - 2] == '\r') trailerBegins--;
658 if (*(trailerBegins-1) == '\n') trailerBegins--;
659 if (*(trailerBegins-1) == '\r') trailerBegins--;
661 if (!strncmp(trailerBegins, trailer, strlen(trailer)))
663 return ERROR_INVALID_DATA;
666 else
668 if (!(trailerBegins = strstr(dataBegins, trailer)))
670 return ERROR_INVALID_DATA;
672 if (*(trailerBegins-1) == '\n') trailerBegins--;
673 if (*(trailerBegins-1) == '\r') trailerBegins--;
676 if (pdwSkip)
677 *pdwSkip = headerBegins - pszString;
679 dataLength = trailerBegins - dataBegins;
681 ret = Base64ToBinaryA(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
682 NULL);
684 return ret;
687 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
688 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
690 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
691 CERT_HEADER_START, CERT_TRAILER_START, pbBinary, pcbBinary, pdwSkip, FALSE);
693 if (!ret && pdwFlags)
694 *pdwFlags = CRYPT_STRING_BASE64HEADER;
695 return ret;
698 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
699 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
701 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
702 CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip, TRUE);
704 if (!ret && pdwFlags)
705 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
706 return ret;
709 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
710 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
712 LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
713 X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip, TRUE);
715 if (!ret && pdwFlags)
716 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
717 return ret;
720 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
721 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
723 LONG ret;
725 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
726 pdwSkip, pdwFlags);
727 if (ret == ERROR_INVALID_DATA)
728 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
729 pdwSkip, pdwFlags);
730 return ret;
733 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
734 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
736 LONG ret = ERROR_SUCCESS;
738 if (*pcbBinary < cchString)
740 if (!pbBinary)
741 *pcbBinary = cchString;
742 else
744 ret = ERROR_INSUFFICIENT_BUFFER;
745 *pcbBinary = cchString;
748 else
750 if (cchString)
751 memcpy(pbBinary, pszString, cchString);
752 *pcbBinary = cchString;
754 return ret;
757 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
758 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
760 LONG ret;
762 ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
763 pdwSkip, pdwFlags);
764 if (ret == ERROR_INVALID_DATA)
765 ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
766 pdwSkip, pdwFlags);
767 if (ret == ERROR_INVALID_DATA)
768 ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
769 pdwSkip, pdwFlags);
770 return ret;
773 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
774 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
775 DWORD *pdwSkip, DWORD *pdwFlags)
777 StringToBinaryAFunc decoder;
778 LONG ret;
780 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
781 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
783 if (!pszString)
785 SetLastError(ERROR_INVALID_PARAMETER);
786 return FALSE;
788 /* Only the bottom byte contains valid types */
789 if (dwFlags & 0xfffffff0)
791 SetLastError(ERROR_INVALID_DATA);
792 return FALSE;
794 switch (dwFlags)
796 case CRYPT_STRING_BASE64_ANY:
797 decoder = Base64AnyToBinaryA;
798 break;
799 case CRYPT_STRING_BASE64:
800 decoder = Base64ToBinaryA;
801 break;
802 case CRYPT_STRING_BASE64HEADER:
803 decoder = Base64HeaderToBinaryA;
804 break;
805 case CRYPT_STRING_BASE64REQUESTHEADER:
806 decoder = Base64RequestHeaderToBinaryA;
807 break;
808 case CRYPT_STRING_BASE64X509CRLHEADER:
809 decoder = Base64X509HeaderToBinaryA;
810 break;
811 case CRYPT_STRING_BINARY:
812 decoder = DecodeBinaryToBinaryA;
813 break;
814 case CRYPT_STRING_ANY:
815 decoder = DecodeAnyA;
816 break;
817 case CRYPT_STRING_HEX:
818 case CRYPT_STRING_HEXASCII:
819 case CRYPT_STRING_HEXADDR:
820 case CRYPT_STRING_HEXASCIIADDR:
821 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
822 /* fall through */
823 default:
824 SetLastError(ERROR_INVALID_PARAMETER);
825 return FALSE;
827 if (!cchString)
828 cchString = strlen(pszString);
829 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
830 if (ret)
831 SetLastError(ret);
832 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
835 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
836 const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
838 int len = in_len, i;
839 const WCHAR *d = in_buf;
840 int ip0, ip1, ip2, ip3;
842 if (len < 4)
843 return ERROR_INVALID_DATA;
845 i = 0;
846 if (d[2] == '=')
848 if ((ip0 = decodeBase64Byte(d[0])) > 63)
849 return ERROR_INVALID_DATA;
850 if ((ip1 = decodeBase64Byte(d[1])) > 63)
851 return ERROR_INVALID_DATA;
853 if (out_buf)
854 out_buf[i] = (ip0 << 2) | (ip1 >> 4);
855 i++;
857 else if (d[3] == '=')
859 if ((ip0 = decodeBase64Byte(d[0])) > 63)
860 return ERROR_INVALID_DATA;
861 if ((ip1 = decodeBase64Byte(d[1])) > 63)
862 return ERROR_INVALID_DATA;
863 if ((ip2 = decodeBase64Byte(d[2])) > 63)
864 return ERROR_INVALID_DATA;
866 if (out_buf)
868 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
869 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
871 i += 2;
873 else
875 if ((ip0 = decodeBase64Byte(d[0])) > 63)
876 return ERROR_INVALID_DATA;
877 if ((ip1 = decodeBase64Byte(d[1])) > 63)
878 return ERROR_INVALID_DATA;
879 if ((ip2 = decodeBase64Byte(d[2])) > 63)
880 return ERROR_INVALID_DATA;
881 if ((ip3 = decodeBase64Byte(d[3])) > 63)
882 return ERROR_INVALID_DATA;
884 if (out_buf)
886 out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
887 out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
888 out_buf[i + 2] = (ip2 << 6) | ip3;
890 i += 3;
892 if (len >= 6 && d[4] == '\r' && d[5] == '\n')
893 *nextBlock = d + 6;
894 else if (len >= 5 && d[4] == '\n')
895 *nextBlock = d + 5;
896 else if (len >= 4 && d[4])
897 *nextBlock = d + 4;
898 else
899 *nextBlock = NULL;
900 *out_len = i;
901 return ERROR_SUCCESS;
904 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
905 * string to convert.
907 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
908 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
910 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
911 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
913 LONG ret = ERROR_SUCCESS;
914 const WCHAR *nextBlock;
915 DWORD outLen = 0;
917 nextBlock = pszString;
918 while (nextBlock && !ret)
920 DWORD len = 0;
922 ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
923 &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
924 if (!ret)
925 outLen += len;
926 if (cchString - (nextBlock - pszString) <= 0)
927 nextBlock = NULL;
929 *pcbBinary = outLen;
930 if (!ret)
932 if (pdwSkip)
933 *pdwSkip = 0;
934 if (pdwFlags)
935 *pdwFlags = CRYPT_STRING_BASE64;
937 else if (ret == ERROR_INSUFFICIENT_BUFFER)
939 if (!pbBinary)
940 ret = ERROR_SUCCESS;
942 return ret;
945 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
946 DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
947 DWORD *pcbBinary, DWORD *pdwSkip, BOOL exactHeaderAndTrailerMatch)
949 LONG ret;
951 LPCWSTR headerBegins;
952 LPCWSTR dataBegins;
953 LPCWSTR trailerBegins;
954 size_t dataLength;
956 if ((strlenW(header) + strlenW(trailer)) > cchString)
958 return ERROR_INVALID_DATA;
961 if (!(headerBegins = strstrW(pszString, header)))
963 TRACE("Can't find %s in %s.\n", debugstr_w(header), debugstr_w(pszString));
964 return ERROR_INVALID_DATA;
967 dataBegins = headerBegins + strlenW(header);
968 if (!exactHeaderAndTrailerMatch)
970 if ((dataBegins = strstrW(dataBegins, CERT_DELIMITER_W)))
972 dataBegins += strlenW(CERT_DELIMITER_W);
974 else
976 return ERROR_INVALID_DATA;
979 if (*dataBegins == '\r') dataBegins++;
980 if (*dataBegins == '\n') dataBegins++;
982 if (exactHeaderAndTrailerMatch)
984 trailerBegins = pszString + cchString - strlenW(trailer);
985 if (pszString[cchString - 1] == '\n') trailerBegins--;
986 if (pszString[cchString - 2] == '\r') trailerBegins--;
988 if (*(trailerBegins-1) == '\n') trailerBegins--;
989 if (*(trailerBegins-1) == '\r') trailerBegins--;
991 if (!strncmpW(trailerBegins, trailer, strlenW(trailer)))
993 return ERROR_INVALID_DATA;
996 else
998 if (!(trailerBegins = strstrW(dataBegins, trailer)))
1000 return ERROR_INVALID_DATA;
1002 if (*(trailerBegins-1) == '\n') trailerBegins--;
1003 if (*(trailerBegins-1) == '\r') trailerBegins--;
1006 if (pdwSkip)
1007 *pdwSkip = headerBegins - pszString;
1009 dataLength = trailerBegins - dataBegins;
1011 ret = Base64ToBinaryW(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
1012 NULL);
1014 return ret;
1017 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1018 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1020 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1021 CERT_HEADER_START_W, CERT_TRAILER_START_W, pbBinary, pcbBinary,
1022 pdwSkip, FALSE);
1024 if (!ret && pdwFlags)
1025 *pdwFlags = CRYPT_STRING_BASE64HEADER;
1026 return ret;
1029 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1030 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1032 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1033 CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
1034 pdwSkip, TRUE);
1036 if (!ret && pdwFlags)
1037 *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
1038 return ret;
1041 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
1042 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1044 LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
1045 X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip, TRUE);
1047 if (!ret && pdwFlags)
1048 *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
1049 return ret;
1052 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
1053 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1055 LONG ret;
1057 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1058 pdwSkip, pdwFlags);
1059 if (ret == ERROR_INVALID_DATA)
1060 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1061 pdwSkip, pdwFlags);
1062 return ret;
1065 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
1066 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1068 LONG ret = ERROR_SUCCESS;
1070 if (*pcbBinary < cchString)
1072 if (!pbBinary)
1073 *pcbBinary = cchString;
1074 else
1076 ret = ERROR_INSUFFICIENT_BUFFER;
1077 *pcbBinary = cchString;
1080 else
1082 if (cchString)
1083 memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1084 *pcbBinary = cchString * sizeof(WCHAR);
1086 return ret;
1089 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1090 BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1092 LONG ret;
1094 ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1095 pdwSkip, pdwFlags);
1096 if (ret == ERROR_INVALID_DATA)
1097 ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1098 pdwSkip, pdwFlags);
1099 if (ret == ERROR_INVALID_DATA)
1100 ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1101 pdwSkip, pdwFlags);
1102 return ret;
1105 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1106 DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1107 DWORD *pdwSkip, DWORD *pdwFlags)
1109 StringToBinaryWFunc decoder;
1110 LONG ret;
1112 TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
1113 cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1115 if (!pszString)
1117 SetLastError(ERROR_INVALID_PARAMETER);
1118 return FALSE;
1120 /* Only the bottom byte contains valid types */
1121 if (dwFlags & 0xfffffff0)
1123 SetLastError(ERROR_INVALID_DATA);
1124 return FALSE;
1126 switch (dwFlags)
1128 case CRYPT_STRING_BASE64_ANY:
1129 decoder = Base64AnyToBinaryW;
1130 break;
1131 case CRYPT_STRING_BASE64:
1132 decoder = Base64ToBinaryW;
1133 break;
1134 case CRYPT_STRING_BASE64HEADER:
1135 decoder = Base64HeaderToBinaryW;
1136 break;
1137 case CRYPT_STRING_BASE64REQUESTHEADER:
1138 decoder = Base64RequestHeaderToBinaryW;
1139 break;
1140 case CRYPT_STRING_BASE64X509CRLHEADER:
1141 decoder = Base64X509HeaderToBinaryW;
1142 break;
1143 case CRYPT_STRING_BINARY:
1144 decoder = DecodeBinaryToBinaryW;
1145 break;
1146 case CRYPT_STRING_ANY:
1147 decoder = DecodeAnyW;
1148 break;
1149 case CRYPT_STRING_HEX:
1150 case CRYPT_STRING_HEXASCII:
1151 case CRYPT_STRING_HEXADDR:
1152 case CRYPT_STRING_HEXASCIIADDR:
1153 FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1154 /* fall through */
1155 default:
1156 SetLastError(ERROR_INVALID_PARAMETER);
1157 return FALSE;
1159 if (!cchString)
1160 cchString = strlenW(pszString);
1161 ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1162 if (ret)
1163 SetLastError(ret);
1164 return (ret == ERROR_SUCCESS) ? TRUE : FALSE;