wordpad: Update Portuguese translation.
[wine] / dlls / crypt32 / base64.c
1 /*
2  * base64 encoder/decoder
3  *
4  * Copyright 2005 by Kai Blin
5  * Copyright 2006 Juan Lang
6  *
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.
11  *
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.
16  *
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
20  */
21
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"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
31
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-----"
38
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 };
57
58 static const char b64[] =
59 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60
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);
65
66 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
67  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
68 {
69     BOOL ret = TRUE;
70
71     if (*pcchString < cbBinary)
72     {
73         if (!pszString)
74             *pcchString = cbBinary;
75         else
76         {
77             SetLastError(ERROR_INSUFFICIENT_BUFFER);
78             *pcchString = cbBinary;
79             ret = FALSE;
80         }
81     }
82     else
83     {
84         if (cbBinary)
85             memcpy(pszString, pbBinary, cbBinary);
86         *pcchString = cbBinary;
87     }
88     return ret;
89 }
90
91 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
92  char* out_buf, DWORD *out_len)
93 {
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;
99
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);
103
104     if (needed > *out_len)
105     {
106         *out_len = needed;
107         return ERROR_INSUFFICIENT_BUFFER;
108     }
109     else
110         *out_len = needed;
111
112     /* Three bytes of input give 4 chars of output */
113     div = in_len / 3;
114
115     ptr = out_buf;
116     i = 0;
117     while (div > 0)
118     {
119         if (i && i % 64 == 0)
120         {
121             strcpy(ptr, sep);
122             ptr += strlen(sep);
123         }
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--;
137     }
138
139     switch(pad_bytes)
140     {
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;
164     }
165     strcpy(ptr, sep);
166
167     return ERROR_SUCCESS;
168 }
169
170 static BOOL BinaryToBase64A(const BYTE *pbBinary,
171  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
172 {
173     static const char crlf[] = "\r\n", lf[] = "\n";
174     BOOL ret = TRUE;
175     LPCSTR header = NULL, trailer = NULL, sep;
176     DWORD charsNeeded;
177
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)
185     {
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;
201     }
202
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)
210     {
211         LPSTR ptr = pszString;
212         DWORD size = charsNeeded;
213
214         if (header)
215         {
216             strcpy(ptr, header);
217             ptr += strlen(ptr);
218             strcpy(ptr, sep);
219             ptr += strlen(sep);
220         }
221         encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
222         ptr += size - 1;
223         if (trailer)
224         {
225             strcpy(ptr, trailer);
226             ptr += strlen(ptr);
227             strcpy(ptr, sep);
228             ptr += strlen(sep);
229         }
230         *pcchString = charsNeeded - 1;
231     }
232     else if (pszString)
233     {
234         *pcchString = charsNeeded;
235         SetLastError(ERROR_INSUFFICIENT_BUFFER);
236         ret = FALSE;
237     }
238     else
239         *pcchString = charsNeeded;
240     return ret;
241 }
242
243 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
244  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
245 {
246     BinaryToStringAFunc encoder = NULL;
247
248     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
249      pcchString);
250
251     if (!pbBinary)
252     {
253         SetLastError(ERROR_INVALID_PARAMETER);
254         return FALSE;
255     }
256     if (!pcchString)
257     {
258         SetLastError(ERROR_INVALID_PARAMETER);
259         return FALSE;
260     }
261
262     switch (dwFlags & 0x0fffffff)
263     {
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;
282     }
283     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
284 }
285
286 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
287  WCHAR* out_buf, DWORD *out_len)
288 {
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;
294
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);
298
299     if (needed > *out_len)
300     {
301         *out_len = needed;
302         return ERROR_INSUFFICIENT_BUFFER;
303     }
304     else
305         *out_len = needed;
306
307     /* Three bytes of input give 4 chars of output */
308     div = in_len / 3;
309
310     ptr = out_buf;
311     i = 0;
312     while (div > 0)
313     {
314         if (i && i % 64 == 0)
315         {
316             strcpyW(ptr, sep);
317             ptr += strlenW(sep);
318         }
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--;
332     }
333
334     switch(pad_bytes)
335     {
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;
359     }
360     strcpyW(ptr, sep);
361
362     return ERROR_SUCCESS;
363 }
364
365 static BOOL BinaryToBase64W(const BYTE *pbBinary,
366  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
367 {
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;
372
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)
380     {
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;
396     }
397
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)
405     {
406         LPWSTR ptr = pszString;
407         DWORD size = charsNeeded;
408
409         if (header)
410         {
411             strcpyW(ptr, header);
412             ptr += strlenW(ptr);
413             strcpyW(ptr, sep);
414             ptr += strlenW(sep);
415         }
416         encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
417         ptr += size - 1;
418         if (trailer)
419         {
420             strcpyW(ptr, trailer);
421             ptr += strlenW(ptr);
422             strcpyW(ptr, sep);
423             ptr += strlenW(sep);
424         }
425         *pcchString = charsNeeded - 1;
426     }
427     else if (pszString)
428     {
429         *pcchString = charsNeeded;
430         SetLastError(ERROR_INSUFFICIENT_BUFFER);
431         ret = FALSE;
432     }
433     else
434         *pcchString = charsNeeded;
435     return ret;
436 }
437
438 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
439  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
440 {
441     BinaryToStringWFunc encoder = NULL;
442
443     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
444      pcchString);
445
446     if (!pbBinary)
447     {
448         SetLastError(ERROR_INVALID_PARAMETER);
449         return FALSE;
450     }
451     if (!pcchString)
452     {
453         SetLastError(ERROR_INVALID_PARAMETER);
454         return FALSE;
455     }
456
457     switch (dwFlags & 0x0fffffff)
458     {
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;
475     }
476     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
477 }
478
479 static inline BYTE decodeBase64Byte(int c)
480 {
481     BYTE ret;
482
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;
496 }
497
498 static LONG decodeBase64Block(const char *in_buf, int in_len,
499  const char **nextBlock, PBYTE out_buf, DWORD *out_len)
500 {
501     int len = in_len, i;
502     const char *d = in_buf;
503     int  ip0, ip1, ip2, ip3;
504
505     if (len < 4)
506         return ERROR_INVALID_DATA;
507
508     i = 0;
509     if (d[2] == '=')
510     {
511         if ((ip0 = decodeBase64Byte(d[0])) > 63)
512             return ERROR_INVALID_DATA;
513         if ((ip1 = decodeBase64Byte(d[1])) > 63)
514             return ERROR_INVALID_DATA;
515
516         if (out_buf)
517             out_buf[i] = (ip0 << 2) | (ip1 >> 4);
518         i++;
519     }
520     else if (d[3] == '=')
521     {
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;
528
529         if (out_buf)
530         {
531             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
532             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
533         }
534         i += 2;
535     }
536     else
537     {
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;
546
547         if (out_buf)
548         {
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;
552         }
553         i += 3;
554     }
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;
565 }
566
567 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
568  * string to convert.
569  */
570 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
571  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
572
573 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
574  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
575 {
576     LONG ret = ERROR_SUCCESS;
577     const char *nextBlock;
578     DWORD outLen = 0;
579
580     nextBlock = pszString;
581     while (nextBlock && !ret)
582     {
583         DWORD len = 0;
584
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;
591     }
592     *pcbBinary = outLen;
593     if (!ret)
594     {
595         if (pdwSkip)
596             *pdwSkip = 0;
597         if (pdwFlags)
598             *pdwFlags = CRYPT_STRING_BASE64;
599     }
600     else if (ret == ERROR_INSUFFICIENT_BUFFER)
601     {
602         if (!pbBinary)
603             ret = ERROR_SUCCESS;
604     }
605     return ret;
606 }
607
608 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
609  DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
610  DWORD *pcbBinary, DWORD *pdwSkip)
611 {
612     LONG ret;
613     LPCSTR ptr;
614
615     if (cchString > strlen(header) + strlen(trailer)
616      && (ptr = strstr(pszString, header)) != NULL)
617     {
618         LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
619
620         if (pszString[cchString - 1] == '\n')
621         {
622             cchString--;
623             trailerSpot--;
624         }
625         if (pszString[cchString - 1] == '\r')
626         {
627             cchString--;
628             trailerSpot--;
629         }
630         if (!strncmp(trailerSpot, trailer, strlen(trailer)))
631         {
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);
640         }
641         else
642             ret = ERROR_INVALID_DATA;
643     }
644     else
645         ret = ERROR_INVALID_DATA;
646     return ret;
647 }
648
649 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
650  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
651 {
652     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
653      CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
654
655     if (!ret && pdwFlags)
656         *pdwFlags = CRYPT_STRING_BASE64HEADER;
657     return ret;
658 }
659
660 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
661  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
662 {
663     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
664      CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
665
666     if (!ret && pdwFlags)
667         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
668     return ret;
669 }
670
671 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
672  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
673 {
674     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
675      X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
676
677     if (!ret && pdwFlags)
678         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
679     return ret;
680 }
681
682 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
683  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
684 {
685     LONG ret;
686
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;
693 }
694
695 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
696  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
697 {
698     LONG ret = ERROR_SUCCESS;
699
700     if (*pcbBinary < cchString)
701     {
702         if (!pbBinary)
703             *pcbBinary = cchString;
704         else
705         {
706             ret = ERROR_INSUFFICIENT_BUFFER;
707             *pcbBinary = cchString;
708         }
709     }
710     else
711     {
712         if (cchString)
713             memcpy(pbBinary, pszString, cchString);
714         *pcbBinary = cchString;
715     }
716     return ret;
717 }
718
719 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
720  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
721 {
722     LONG ret;
723
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;
733 }
734
735 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
736  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
737  DWORD *pdwSkip, DWORD *pdwFlags)
738 {
739     StringToBinaryAFunc decoder;
740     LONG ret;
741
742     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
743      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
744
745     if (!pszString)
746     {
747         SetLastError(ERROR_INVALID_PARAMETER);
748         return FALSE;
749     }
750     /* Only the bottom byte contains valid types */
751     if (dwFlags & 0xfffffff0)
752     {
753         SetLastError(ERROR_INVALID_DATA);
754         return FALSE;
755     }
756     switch (dwFlags)
757     {
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;
788     }
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;
795 }
796
797 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
798  const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
799 {
800     int len = in_len, i;
801     const WCHAR *d = in_buf;
802     int  ip0, ip1, ip2, ip3;
803
804     if (len < 4)
805         return ERROR_INVALID_DATA;
806
807     i = 0;
808     if (d[2] == '=')
809     {
810         if ((ip0 = decodeBase64Byte(d[0])) > 63)
811             return ERROR_INVALID_DATA;
812         if ((ip1 = decodeBase64Byte(d[1])) > 63)
813             return ERROR_INVALID_DATA;
814
815         if (out_buf)
816             out_buf[i] = (ip0 << 2) | (ip1 >> 4);
817         i++;
818     }
819     else if (d[3] == '=')
820     {
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;
827
828         if (out_buf)
829         {
830             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
831             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
832         }
833         i += 2;
834     }
835     else
836     {
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;
845
846         if (out_buf)
847         {
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;
851         }
852         i += 3;
853     }
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;
864 }
865
866 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
867  * string to convert.
868  */
869 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
870  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
871
872 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
873  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
874 {
875     LONG ret = ERROR_SUCCESS;
876     const WCHAR *nextBlock;
877     DWORD outLen = 0;
878
879     nextBlock = pszString;
880     while (nextBlock && !ret)
881     {
882         DWORD len = 0;
883
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;
890     }
891     *pcbBinary = outLen;
892     if (!ret)
893     {
894         if (pdwSkip)
895             *pdwSkip = 0;
896         if (pdwFlags)
897             *pdwFlags = CRYPT_STRING_BASE64;
898     }
899     else if (ret == ERROR_INSUFFICIENT_BUFFER)
900     {
901         if (!pbBinary)
902             ret = ERROR_SUCCESS;
903     }
904     return ret;
905 }
906
907 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
908  DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
909  DWORD *pcbBinary, DWORD *pdwSkip)
910 {
911     LONG ret;
912     LPCWSTR ptr;
913
914     if (cchString > strlenW(header) + strlenW(trailer)
915      && (ptr = strstrW(pszString, header)) != NULL)
916     {
917         LPCWSTR trailerSpot = pszString + cchString - strlenW(trailer);
918
919         if (pszString[cchString - 1] == '\n')
920         {
921             cchString--;
922             trailerSpot--;
923         }
924         if (pszString[cchString - 1] == '\r')
925         {
926             cchString--;
927             trailerSpot--;
928         }
929         if (!strncmpW(trailerSpot, trailer, strlenW(trailer)))
930         {
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);
939         }
940         else
941             ret = ERROR_INVALID_DATA;
942     }
943     else
944         ret = ERROR_INVALID_DATA;
945     return ret;
946 }
947
948 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
949  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
950 {
951     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
952      CERT_HEADER_W, CERT_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
953
954     if (!ret && pdwFlags)
955         *pdwFlags = CRYPT_STRING_BASE64HEADER;
956     return ret;
957 }
958
959 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
960  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
961 {
962     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
963      CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
964      pdwSkip);
965
966     if (!ret && pdwFlags)
967         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
968     return ret;
969 }
970
971 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
972  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
973 {
974     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
975      X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
976
977     if (!ret && pdwFlags)
978         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
979     return ret;
980 }
981
982 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
983  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
984 {
985     LONG ret;
986
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;
993 }
994
995 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
996  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
997 {
998     LONG ret = ERROR_SUCCESS;
999
1000     if (*pcbBinary < cchString)
1001     {
1002         if (!pbBinary)
1003             *pcbBinary = cchString;
1004         else
1005         {
1006             ret = ERROR_INSUFFICIENT_BUFFER;
1007             *pcbBinary = cchString;
1008         }
1009     }
1010     else
1011     {
1012         if (cchString)
1013             memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1014         *pcbBinary = cchString * sizeof(WCHAR);
1015     }
1016     return ret;
1017 }
1018
1019 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1020  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1021 {
1022     LONG ret;
1023
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;
1033 }
1034
1035 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1036  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1037  DWORD *pdwSkip, DWORD *pdwFlags)
1038 {
1039     StringToBinaryWFunc decoder;
1040     LONG ret;
1041
1042     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
1043      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1044
1045     if (!pszString)
1046     {
1047         SetLastError(ERROR_INVALID_PARAMETER);
1048         return FALSE;
1049     }
1050     /* Only the bottom byte contains valid types */
1051     if (dwFlags & 0xfffffff0)
1052     {
1053         SetLastError(ERROR_INVALID_DATA);
1054         return FALSE;
1055     }
1056     switch (dwFlags)
1057     {
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;
1088     }
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;
1095 }