shell32: Add IFolderView::Item implementation.
[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     if (sep)
103         needed += (needed / 64 + 1) * strlen(sep);
104
105     if (needed > *out_len)
106     {
107         *out_len = needed;
108         return ERROR_INSUFFICIENT_BUFFER;
109     }
110     else
111         *out_len = needed;
112
113     /* Three bytes of input give 4 chars of output */
114     div = in_len / 3;
115
116     ptr = out_buf;
117     i = 0;
118     while (div > 0)
119     {
120         if (sep && i && i % 64 == 0)
121         {
122             strcpy(ptr, sep);
123             ptr += strlen(sep);
124         }
125         /* first char is the first 6 bits of the first byte*/
126         *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
127         /* second char is the last 2 bits of the first byte and the first 4
128          * bits of the second byte */
129         *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
130         /* third char is the last 4 bits of the second byte and the first 2
131          * bits of the third byte */
132         *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
133         /* fourth char is the remaining 6 bits of the third byte */
134         *ptr++ = b64[   d[2]       & 0x3f];
135         i += 4;
136         d += 3;
137         div--;
138     }
139
140     switch(pad_bytes)
141     {
142         case 1:
143             /* first char is the first 6 bits of the first byte*/
144             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
145             /* second char is the last 2 bits of the first byte and the first 4
146              * bits of the second byte */
147             *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
148             /* third char is the last 4 bits of the second byte padded with
149              * two zeroes */
150             *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
151             /* fourth char is a = to indicate one byte of padding */
152             *ptr++ = '=';
153             break;
154         case 2:
155             /* first char is the first 6 bits of the first byte*/
156             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
157             /* second char is the last 2 bits of the first byte padded with
158              * four zeroes*/
159             *ptr++ = b64[ ((d[0] << 4) & 0x30)];
160             /* third char is = to indicate padding */
161             *ptr++ = '=';
162             /* fourth char is = to indicate padding */
163             *ptr++ = '=';
164             break;
165     }
166     if (sep)
167         strcpy(ptr, sep);
168
169     return ERROR_SUCCESS;
170 }
171
172 static BOOL BinaryToBase64A(const BYTE *pbBinary,
173  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
174 {
175     static const char crlf[] = "\r\n", lf[] = "\n";
176     BOOL ret = TRUE;
177     LPCSTR header = NULL, trailer = NULL, sep;
178     DWORD charsNeeded;
179
180     if (dwFlags & CRYPT_STRING_NOCR)
181         sep = lf;
182     else if (dwFlags & CRYPT_STRING_NOCRLF)
183         sep = NULL;
184     else
185         sep = crlf;
186     switch (dwFlags & 0x0fffffff)
187     {
188     case CRYPT_STRING_BASE64:
189         /* no header or footer */
190         break;
191     case CRYPT_STRING_BASE64HEADER:
192         header = CERT_HEADER;
193         trailer = CERT_TRAILER;
194         break;
195     case CRYPT_STRING_BASE64REQUESTHEADER:
196         header = CERT_REQUEST_HEADER;
197         trailer = CERT_REQUEST_TRAILER;
198         break;
199     case CRYPT_STRING_BASE64X509CRLHEADER:
200         header = X509_HEADER;
201         trailer = X509_TRAILER;
202         break;
203     }
204
205     charsNeeded = 0;
206     encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
207     if (header)
208         charsNeeded += strlen(header) + strlen(sep);
209     if (trailer)
210         charsNeeded += strlen(trailer) + strlen(sep);
211     if (charsNeeded <= *pcchString)
212     {
213         LPSTR ptr = pszString;
214         DWORD size = charsNeeded;
215
216         if (header)
217         {
218             strcpy(ptr, header);
219             ptr += strlen(ptr);
220             if (sep)
221             {
222                 strcpy(ptr, sep);
223                 ptr += strlen(sep);
224             }
225         }
226         encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
227         ptr += size - 1;
228         if (trailer)
229         {
230             strcpy(ptr, trailer);
231             ptr += strlen(ptr);
232             if (sep)
233             {
234                 strcpy(ptr, sep);
235                 ptr += strlen(sep);
236             }
237         }
238         *pcchString = charsNeeded - 1;
239     }
240     else if (pszString)
241     {
242         *pcchString = charsNeeded;
243         SetLastError(ERROR_INSUFFICIENT_BUFFER);
244         ret = FALSE;
245     }
246     else
247         *pcchString = charsNeeded;
248     return ret;
249 }
250
251 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
252  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
253 {
254     BinaryToStringAFunc encoder = NULL;
255
256     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
257      pcchString);
258
259     if (!pbBinary)
260     {
261         SetLastError(ERROR_INVALID_PARAMETER);
262         return FALSE;
263     }
264     if (!pcchString)
265     {
266         SetLastError(ERROR_INVALID_PARAMETER);
267         return FALSE;
268     }
269
270     switch (dwFlags & 0x0fffffff)
271     {
272     case CRYPT_STRING_BINARY:
273         encoder = EncodeBinaryToBinaryA;
274         break;
275     case CRYPT_STRING_BASE64:
276     case CRYPT_STRING_BASE64HEADER:
277     case CRYPT_STRING_BASE64REQUESTHEADER:
278     case CRYPT_STRING_BASE64X509CRLHEADER:
279         encoder = BinaryToBase64A;
280         break;
281     case CRYPT_STRING_HEX:
282     case CRYPT_STRING_HEXASCII:
283     case CRYPT_STRING_HEXADDR:
284     case CRYPT_STRING_HEXASCIIADDR:
285         FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
286         /* fall through */
287     default:
288         SetLastError(ERROR_INVALID_PARAMETER);
289         return FALSE;
290     }
291     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
292 }
293
294 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
295  WCHAR* out_buf, DWORD *out_len)
296 {
297     int div, i;
298     const BYTE *d = in_buf;
299     int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
300     DWORD needed;
301     LPWSTR ptr;
302
303     TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
304     needed = bytes + pad_bytes + 1;
305     if (sep)
306         needed += (needed / 64 + 1) * strlenW(sep);
307
308     if (needed > *out_len)
309     {
310         *out_len = needed;
311         return ERROR_INSUFFICIENT_BUFFER;
312     }
313     else
314         *out_len = needed;
315
316     /* Three bytes of input give 4 chars of output */
317     div = in_len / 3;
318
319     ptr = out_buf;
320     i = 0;
321     while (div > 0)
322     {
323         if (sep && i && i % 64 == 0)
324         {
325             strcpyW(ptr, sep);
326             ptr += strlenW(sep);
327         }
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--;
341     }
342
343     switch(pad_bytes)
344     {
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;
368     }
369     if (sep)
370         strcpyW(ptr, sep);
371
372     return ERROR_SUCCESS;
373 }
374
375 static BOOL BinaryToBase64W(const BYTE *pbBinary,
376  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
377 {
378     static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 };
379     BOOL ret = TRUE;
380     LPCWSTR header = NULL, trailer = NULL, sep;
381     DWORD charsNeeded;
382
383     if (dwFlags & CRYPT_STRING_NOCR)
384         sep = lf;
385     else if (dwFlags & CRYPT_STRING_NOCRLF)
386         sep = NULL;
387     else
388         sep = crlf;
389     switch (dwFlags & 0x0fffffff)
390     {
391     case CRYPT_STRING_BASE64:
392         /* no header or footer */
393         break;
394     case CRYPT_STRING_BASE64HEADER:
395         header = CERT_HEADER_W;
396         trailer = CERT_TRAILER_W;
397         break;
398     case CRYPT_STRING_BASE64REQUESTHEADER:
399         header = CERT_REQUEST_HEADER_W;
400         trailer = CERT_REQUEST_TRAILER_W;
401         break;
402     case CRYPT_STRING_BASE64X509CRLHEADER:
403         header = X509_HEADER_W;
404         trailer = X509_TRAILER_W;
405         break;
406     }
407
408     charsNeeded = 0;
409     encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
410     if (header)
411         charsNeeded += strlenW(header) + strlenW(sep);
412     if (trailer)
413         charsNeeded += strlenW(trailer) + strlenW(sep);
414     if (charsNeeded <= *pcchString)
415     {
416         LPWSTR ptr = pszString;
417         DWORD size = charsNeeded;
418
419         if (header)
420         {
421             strcpyW(ptr, header);
422             ptr += strlenW(ptr);
423             if (sep)
424             {
425                 strcpyW(ptr, sep);
426                 ptr += strlenW(sep);
427             }
428         }
429         encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
430         ptr += size - 1;
431         if (trailer)
432         {
433             strcpyW(ptr, trailer);
434             ptr += strlenW(ptr);
435             if (sep)
436             {
437                 strcpyW(ptr, sep);
438                 ptr += strlenW(sep);
439             }
440         }
441         *pcchString = charsNeeded - 1;
442     }
443     else if (pszString)
444     {
445         *pcchString = charsNeeded;
446         SetLastError(ERROR_INSUFFICIENT_BUFFER);
447         ret = FALSE;
448     }
449     else
450         *pcchString = charsNeeded;
451     return ret;
452 }
453
454 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
455  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
456 {
457     BinaryToStringWFunc encoder = NULL;
458
459     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
460      pcchString);
461
462     if (!pbBinary)
463     {
464         SetLastError(ERROR_INVALID_PARAMETER);
465         return FALSE;
466     }
467     if (!pcchString)
468     {
469         SetLastError(ERROR_INVALID_PARAMETER);
470         return FALSE;
471     }
472
473     switch (dwFlags & 0x0fffffff)
474     {
475     case CRYPT_STRING_BASE64:
476     case CRYPT_STRING_BASE64HEADER:
477     case CRYPT_STRING_BASE64REQUESTHEADER:
478     case CRYPT_STRING_BASE64X509CRLHEADER:
479         encoder = BinaryToBase64W;
480         break;
481     case CRYPT_STRING_BINARY:
482     case CRYPT_STRING_HEX:
483     case CRYPT_STRING_HEXASCII:
484     case CRYPT_STRING_HEXADDR:
485     case CRYPT_STRING_HEXASCIIADDR:
486         FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
487         /* fall through */
488     default:
489         SetLastError(ERROR_INVALID_PARAMETER);
490         return FALSE;
491     }
492     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
493 }
494
495 static inline BYTE decodeBase64Byte(int c)
496 {
497     BYTE ret;
498
499     if (c >= 'A' && c <= 'Z')
500         ret = c - 'A';
501     else if (c >= 'a' && c <= 'z')
502         ret = c - 'a' + 26;
503     else if (c >= '0' && c <= '9')
504         ret = c - '0' + 52;
505     else if (c == '+')
506         ret = 62;
507     else if (c == '/')
508         ret = 63;
509     else
510         ret = 64;
511     return ret;
512 }
513
514 static LONG decodeBase64Block(const char *in_buf, int in_len,
515  const char **nextBlock, PBYTE out_buf, DWORD *out_len)
516 {
517     int len = in_len, i;
518     const char *d = in_buf;
519     int  ip0, ip1, ip2, ip3;
520
521     if (len < 4)
522         return ERROR_INVALID_DATA;
523
524     i = 0;
525     if (d[2] == '=')
526     {
527         if ((ip0 = decodeBase64Byte(d[0])) > 63)
528             return ERROR_INVALID_DATA;
529         if ((ip1 = decodeBase64Byte(d[1])) > 63)
530             return ERROR_INVALID_DATA;
531
532         if (out_buf)
533             out_buf[i] = (ip0 << 2) | (ip1 >> 4);
534         i++;
535     }
536     else if (d[3] == '=')
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
545         if (out_buf)
546         {
547             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
548             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
549         }
550         i += 2;
551     }
552     else
553     {
554         if ((ip0 = decodeBase64Byte(d[0])) > 63)
555             return ERROR_INVALID_DATA;
556         if ((ip1 = decodeBase64Byte(d[1])) > 63)
557             return ERROR_INVALID_DATA;
558         if ((ip2 = decodeBase64Byte(d[2])) > 63)
559             return ERROR_INVALID_DATA;
560         if ((ip3 = decodeBase64Byte(d[3])) > 63)
561             return ERROR_INVALID_DATA;
562
563         if (out_buf)
564         {
565             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
566             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
567             out_buf[i + 2] = (ip2 << 6) |  ip3;
568         }
569         i += 3;
570     }
571     if (len >= 6 && d[4] == '\r' && d[5] == '\n')
572         *nextBlock = d + 6;
573     else if (len >= 5 && d[4] == '\n')
574         *nextBlock = d + 5;
575     else if (len >= 4 && d[4])
576         *nextBlock = d + 4;
577     else
578         *nextBlock = NULL;
579     *out_len = i;
580     return ERROR_SUCCESS;
581 }
582
583 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
584  * string to convert.
585  */
586 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
587  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
588
589 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
590  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
591 {
592     LONG ret = ERROR_SUCCESS;
593     const char *nextBlock;
594     DWORD outLen = 0;
595
596     nextBlock = pszString;
597     while (nextBlock && !ret)
598     {
599         DWORD len = 0;
600
601         ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
602          &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
603         if (!ret)
604             outLen += len;
605         if (cchString - (nextBlock - pszString) <= 0)
606             nextBlock = NULL;
607     }
608     *pcbBinary = outLen;
609     if (!ret)
610     {
611         if (pdwSkip)
612             *pdwSkip = 0;
613         if (pdwFlags)
614             *pdwFlags = CRYPT_STRING_BASE64;
615     }
616     else if (ret == ERROR_INSUFFICIENT_BUFFER)
617     {
618         if (!pbBinary)
619             ret = ERROR_SUCCESS;
620     }
621     return ret;
622 }
623
624 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
625  DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
626  DWORD *pcbBinary, DWORD *pdwSkip)
627 {
628     LONG ret;
629     LPCSTR ptr;
630
631     if (cchString > strlen(header) + strlen(trailer)
632      && (ptr = strstr(pszString, header)) != NULL)
633     {
634         LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
635
636         if (pszString[cchString - 1] == '\n')
637         {
638             cchString--;
639             trailerSpot--;
640         }
641         if (pszString[cchString - 1] == '\r')
642         {
643             cchString--;
644             trailerSpot--;
645         }
646         if (!strncmp(trailerSpot, trailer, strlen(trailer)))
647         {
648             if (pdwSkip)
649                 *pdwSkip = ptr - pszString;
650             ptr += strlen(header);
651             if (*ptr == '\r') ptr++;
652             if (*ptr == '\n') ptr++;
653             cchString -= ptr - pszString + strlen(trailer);
654             ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL,
655              NULL);
656         }
657         else
658             ret = ERROR_INVALID_DATA;
659     }
660     else
661         ret = ERROR_INVALID_DATA;
662     return ret;
663 }
664
665 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
666  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
667 {
668     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
669      CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
670
671     if (!ret && pdwFlags)
672         *pdwFlags = CRYPT_STRING_BASE64HEADER;
673     return ret;
674 }
675
676 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
677  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
678 {
679     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
680      CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
681
682     if (!ret && pdwFlags)
683         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
684     return ret;
685 }
686
687 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
688  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
689 {
690     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
691      X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
692
693     if (!ret && pdwFlags)
694         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
695     return ret;
696 }
697
698 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
699  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
700 {
701     LONG ret;
702
703     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
704      pdwSkip, pdwFlags);
705     if (ret == ERROR_INVALID_DATA)
706         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
707          pdwSkip, pdwFlags);
708     return ret;
709 }
710
711 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
712  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
713 {
714     LONG ret = ERROR_SUCCESS;
715
716     if (*pcbBinary < cchString)
717     {
718         if (!pbBinary)
719             *pcbBinary = cchString;
720         else
721         {
722             ret = ERROR_INSUFFICIENT_BUFFER;
723             *pcbBinary = cchString;
724         }
725     }
726     else
727     {
728         if (cchString)
729             memcpy(pbBinary, pszString, cchString);
730         *pcbBinary = cchString;
731     }
732     return ret;
733 }
734
735 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
736  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
737 {
738     LONG ret;
739
740     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
741      pdwSkip, pdwFlags);
742     if (ret == ERROR_INVALID_DATA)
743         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
744          pdwSkip, pdwFlags);
745     if (ret == ERROR_INVALID_DATA)
746         ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
747          pdwSkip, pdwFlags);
748     return ret;
749 }
750
751 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
752  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
753  DWORD *pdwSkip, DWORD *pdwFlags)
754 {
755     StringToBinaryAFunc decoder;
756     LONG ret;
757
758     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
759      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
760
761     if (!pszString)
762     {
763         SetLastError(ERROR_INVALID_PARAMETER);
764         return FALSE;
765     }
766     /* Only the bottom byte contains valid types */
767     if (dwFlags & 0xfffffff0)
768     {
769         SetLastError(ERROR_INVALID_DATA);
770         return FALSE;
771     }
772     switch (dwFlags)
773     {
774     case CRYPT_STRING_BASE64_ANY:
775         decoder = Base64AnyToBinaryA;
776         break;
777     case CRYPT_STRING_BASE64:
778         decoder = Base64ToBinaryA;
779         break;
780     case CRYPT_STRING_BASE64HEADER:
781         decoder = Base64HeaderToBinaryA;
782         break;
783     case CRYPT_STRING_BASE64REQUESTHEADER:
784         decoder = Base64RequestHeaderToBinaryA;
785         break;
786     case CRYPT_STRING_BASE64X509CRLHEADER:
787         decoder = Base64X509HeaderToBinaryA;
788         break;
789     case CRYPT_STRING_BINARY:
790         decoder = DecodeBinaryToBinaryA;
791         break;
792     case CRYPT_STRING_ANY:
793         decoder = DecodeAnyA;
794         break;
795     case CRYPT_STRING_HEX:
796     case CRYPT_STRING_HEXASCII:
797     case CRYPT_STRING_HEXADDR:
798     case CRYPT_STRING_HEXASCIIADDR:
799         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
800         /* fall through */
801     default:
802         SetLastError(ERROR_INVALID_PARAMETER);
803         return FALSE;
804     }
805     if (!cchString)
806         cchString = strlen(pszString);
807     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
808     if (ret)
809         SetLastError(ret);
810     return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
811 }
812
813 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
814  const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
815 {
816     int len = in_len, i;
817     const WCHAR *d = in_buf;
818     int  ip0, ip1, ip2, ip3;
819
820     if (len < 4)
821         return ERROR_INVALID_DATA;
822
823     i = 0;
824     if (d[2] == '=')
825     {
826         if ((ip0 = decodeBase64Byte(d[0])) > 63)
827             return ERROR_INVALID_DATA;
828         if ((ip1 = decodeBase64Byte(d[1])) > 63)
829             return ERROR_INVALID_DATA;
830
831         if (out_buf)
832             out_buf[i] = (ip0 << 2) | (ip1 >> 4);
833         i++;
834     }
835     else if (d[3] == '=')
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
844         if (out_buf)
845         {
846             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
847             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
848         }
849         i += 2;
850     }
851     else
852     {
853         if ((ip0 = decodeBase64Byte(d[0])) > 63)
854             return ERROR_INVALID_DATA;
855         if ((ip1 = decodeBase64Byte(d[1])) > 63)
856             return ERROR_INVALID_DATA;
857         if ((ip2 = decodeBase64Byte(d[2])) > 63)
858             return ERROR_INVALID_DATA;
859         if ((ip3 = decodeBase64Byte(d[3])) > 63)
860             return ERROR_INVALID_DATA;
861
862         if (out_buf)
863         {
864             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
865             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
866             out_buf[i + 2] = (ip2 << 6) |  ip3;
867         }
868         i += 3;
869     }
870     if (len >= 6 && d[4] == '\r' && d[5] == '\n')
871         *nextBlock = d + 6;
872     else if (len >= 5 && d[4] == '\n')
873         *nextBlock = d + 5;
874     else if (len >= 4 && d[4])
875         *nextBlock = d + 4;
876     else
877         *nextBlock = NULL;
878     *out_len = i;
879     return ERROR_SUCCESS;
880 }
881
882 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
883  * string to convert.
884  */
885 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
886  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
887
888 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
889  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
890 {
891     LONG ret = ERROR_SUCCESS;
892     const WCHAR *nextBlock;
893     DWORD outLen = 0;
894
895     nextBlock = pszString;
896     while (nextBlock && !ret)
897     {
898         DWORD len = 0;
899
900         ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
901          &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
902         if (!ret)
903             outLen += len;
904         if (cchString - (nextBlock - pszString) <= 0)
905             nextBlock = NULL;
906     }
907     *pcbBinary = outLen;
908     if (!ret)
909     {
910         if (pdwSkip)
911             *pdwSkip = 0;
912         if (pdwFlags)
913             *pdwFlags = CRYPT_STRING_BASE64;
914     }
915     else if (ret == ERROR_INSUFFICIENT_BUFFER)
916     {
917         if (!pbBinary)
918             ret = ERROR_SUCCESS;
919     }
920     return ret;
921 }
922
923 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
924  DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
925  DWORD *pcbBinary, DWORD *pdwSkip)
926 {
927     LONG ret;
928     LPCWSTR ptr;
929
930     if (cchString > strlenW(header) + strlenW(trailer)
931      && (ptr = strstrW(pszString, header)) != NULL)
932     {
933         LPCWSTR trailerSpot = pszString + cchString - strlenW(trailer);
934
935         if (pszString[cchString - 1] == '\n')
936         {
937             cchString--;
938             trailerSpot--;
939         }
940         if (pszString[cchString - 1] == '\r')
941         {
942             cchString--;
943             trailerSpot--;
944         }
945         if (!strncmpW(trailerSpot, trailer, strlenW(trailer)))
946         {
947             if (pdwSkip)
948                 *pdwSkip = ptr - pszString;
949             ptr += strlenW(header);
950             if (*ptr == '\r') ptr++;
951             if (*ptr == '\n') ptr++;
952             cchString -= ptr - pszString + strlenW(trailer);
953             ret = Base64ToBinaryW(ptr, cchString, pbBinary, pcbBinary, NULL,
954              NULL);
955         }
956         else
957             ret = ERROR_INVALID_DATA;
958     }
959     else
960         ret = ERROR_INVALID_DATA;
961     return ret;
962 }
963
964 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
965  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
966 {
967     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
968      CERT_HEADER_W, CERT_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
969
970     if (!ret && pdwFlags)
971         *pdwFlags = CRYPT_STRING_BASE64HEADER;
972     return ret;
973 }
974
975 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
976  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
977 {
978     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
979      CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
980      pdwSkip);
981
982     if (!ret && pdwFlags)
983         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
984     return ret;
985 }
986
987 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
988  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
989 {
990     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
991      X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip);
992
993     if (!ret && pdwFlags)
994         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
995     return ret;
996 }
997
998 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
999  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1000 {
1001     LONG ret;
1002
1003     ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1004      pdwSkip, pdwFlags);
1005     if (ret == ERROR_INVALID_DATA)
1006         ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1007          pdwSkip, pdwFlags);
1008     return ret;
1009 }
1010
1011 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
1012  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1013 {
1014     LONG ret = ERROR_SUCCESS;
1015
1016     if (*pcbBinary < cchString)
1017     {
1018         if (!pbBinary)
1019             *pcbBinary = cchString;
1020         else
1021         {
1022             ret = ERROR_INSUFFICIENT_BUFFER;
1023             *pcbBinary = cchString;
1024         }
1025     }
1026     else
1027     {
1028         if (cchString)
1029             memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
1030         *pcbBinary = cchString * sizeof(WCHAR);
1031     }
1032     return ret;
1033 }
1034
1035 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
1036  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
1037 {
1038     LONG ret;
1039
1040     ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1041      pdwSkip, pdwFlags);
1042     if (ret == ERROR_INVALID_DATA)
1043         ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1044          pdwSkip, pdwFlags);
1045     if (ret == ERROR_INVALID_DATA)
1046         ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
1047          pdwSkip, pdwFlags);
1048     return ret;
1049 }
1050
1051 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
1052  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
1053  DWORD *pdwSkip, DWORD *pdwFlags)
1054 {
1055     StringToBinaryWFunc decoder;
1056     LONG ret;
1057
1058     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
1059      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1060
1061     if (!pszString)
1062     {
1063         SetLastError(ERROR_INVALID_PARAMETER);
1064         return FALSE;
1065     }
1066     /* Only the bottom byte contains valid types */
1067     if (dwFlags & 0xfffffff0)
1068     {
1069         SetLastError(ERROR_INVALID_DATA);
1070         return FALSE;
1071     }
1072     switch (dwFlags)
1073     {
1074     case CRYPT_STRING_BASE64_ANY:
1075         decoder = Base64AnyToBinaryW;
1076         break;
1077     case CRYPT_STRING_BASE64:
1078         decoder = Base64ToBinaryW;
1079         break;
1080     case CRYPT_STRING_BASE64HEADER:
1081         decoder = Base64HeaderToBinaryW;
1082         break;
1083     case CRYPT_STRING_BASE64REQUESTHEADER:
1084         decoder = Base64RequestHeaderToBinaryW;
1085         break;
1086     case CRYPT_STRING_BASE64X509CRLHEADER:
1087         decoder = Base64X509HeaderToBinaryW;
1088         break;
1089     case CRYPT_STRING_BINARY:
1090         decoder = DecodeBinaryToBinaryW;
1091         break;
1092     case CRYPT_STRING_ANY:
1093         decoder = DecodeAnyW;
1094         break;
1095     case CRYPT_STRING_HEX:
1096     case CRYPT_STRING_HEXASCII:
1097     case CRYPT_STRING_HEXADDR:
1098     case CRYPT_STRING_HEXASCIIADDR:
1099         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1100         /* fall through */
1101     default:
1102         SetLastError(ERROR_INVALID_PARAMETER);
1103         return FALSE;
1104     }
1105     if (!cchString)
1106         cchString = strlenW(pszString);
1107     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1108     if (ret)
1109         SetLastError(ret);
1110     return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
1111 }