xref: /reactos/dll/win32/crypt32/base64.c (revision 997d44c9)
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_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-----"
41 
42 static const WCHAR CERT_HEADER_W[] = {
43 '-','-','-','-','-','B','E','G','I','N',' ','C','E','R','T','I','F','I','C',
44 'A','T','E','-','-','-','-','-',0 };
45 static const WCHAR CERT_HEADER_START_W[] = {
46 '-','-','-','-','-','B','E','G','I','N',' ',0 };
47 static const WCHAR CERT_DELIMITER_W[] = {
48 '-','-','-','-','-',0 };
49 static const WCHAR CERT_TRAILER_W[] = {
50 '-','-','-','-','-','E','N','D',' ','C','E','R','T','I','F','I','C','A','T',
51 'E','-','-','-','-','-',0 };
52 static const WCHAR CERT_TRAILER_START_W[] = {
53 '-','-','-','-','-','E','N','D',' ',0 };
54 static const WCHAR CERT_REQUEST_HEADER_W[] = {
55 '-','-','-','-','-','B','E','G','I','N',' ','N','E','W',' ','C','E','R','T',
56 'I','F','I','C','A','T','E',' ','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
57 static const WCHAR CERT_REQUEST_TRAILER_W[] = {
58 '-','-','-','-','-','E','N','D',' ','N','E','W',' ','C','E','R','T','I','F',
59 'I','C','A','T','E',' ','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
60 static const WCHAR X509_HEADER_W[] = {
61 '-','-','-','-','-','B','E','G','I','N',' ','X','5','0','9',' ','C','R','L',
62 '-','-','-','-','-',0 };
63 static const WCHAR X509_TRAILER_W[] = {
64 '-','-','-','-','-','E','N','D',' ','X','5','0','9',' ','C','R','L','-','-',
65 '-','-','-',0 };
66 
67 static const char b64[] =
68 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
69 
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);
74 
EncodeBinaryToBinaryA(const BYTE * pbBinary,DWORD cbBinary,DWORD dwFlags,LPSTR pszString,DWORD * pcchString)75 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
76  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
77 {
78     BOOL ret = TRUE;
79 
80     if (pszString)
81     {
82         if (*pcchString < cbBinary)
83         {
84             SetLastError(ERROR_INSUFFICIENT_BUFFER);
85             ret = FALSE;
86         }
87         else if (cbBinary)
88             memcpy(pszString, pbBinary, cbBinary);
89     }
90     else
91         *pcchString = cbBinary;
92 
93     return ret;
94 }
95 
encodeBase64A(const BYTE * in_buf,int in_len,LPCSTR sep,char * out_buf,DWORD * out_len)96 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
97  char* out_buf, DWORD *out_len)
98 {
99     int div, i;
100     const BYTE *d = in_buf;
101     int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
102     DWORD needed;
103     LPSTR ptr;
104 
105     TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
106     needed = bytes + pad_bytes;
107     needed += (needed / 64 + (needed % 64 ? 1 : 0)) * strlen(sep);
108     needed++;
109 
110     if (needed > *out_len)
111     {
112         *out_len = needed;
113         return ERROR_INSUFFICIENT_BUFFER;
114     }
115     else
116         *out_len = needed;
117 
118     /* Three bytes of input give 4 chars of output */
119     div = in_len / 3;
120 
121     ptr = out_buf;
122     i = 0;
123     while (div > 0)
124     {
125         if (i && i % 64 == 0)
126         {
127             strcpy(ptr, sep);
128             ptr += strlen(sep);
129         }
130         /* first char is the first 6 bits of the first byte*/
131         *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
132         /* second char is the last 2 bits of the first byte and the first 4
133          * bits of the second byte */
134         *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
135         /* third char is the last 4 bits of the second byte and the first 2
136          * bits of the third byte */
137         *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
138         /* fourth char is the remaining 6 bits of the third byte */
139         *ptr++ = b64[   d[2]       & 0x3f];
140         i += 4;
141         d += 3;
142         div--;
143     }
144 
145     switch(pad_bytes)
146     {
147         case 1:
148             /* first char is the first 6 bits of the first byte*/
149             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
150             /* second char is the last 2 bits of the first byte and the first 4
151              * bits of the second byte */
152             *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
153             /* third char is the last 4 bits of the second byte padded with
154              * two zeroes */
155             *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
156             /* fourth char is a = to indicate one byte of padding */
157             *ptr++ = '=';
158             break;
159         case 2:
160             /* first char is the first 6 bits of the first byte*/
161             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
162             /* second char is the last 2 bits of the first byte padded with
163              * four zeroes*/
164             *ptr++ = b64[ ((d[0] << 4) & 0x30)];
165             /* third char is = to indicate padding */
166             *ptr++ = '=';
167             /* fourth char is = to indicate padding */
168             *ptr++ = '=';
169             break;
170     }
171     strcpy(ptr, sep);
172 
173     return ERROR_SUCCESS;
174 }
175 
BinaryToBase64A(const BYTE * pbBinary,DWORD cbBinary,DWORD dwFlags,LPSTR pszString,DWORD * pcchString)176 static BOOL BinaryToBase64A(const BYTE *pbBinary,
177  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
178 {
179     static const char crlf[] = "\r\n", lf[] = "\n";
180     BOOL ret = TRUE;
181     LPCSTR header = NULL, trailer = NULL, sep;
182     DWORD charsNeeded;
183 
184     if (dwFlags & CRYPT_STRING_NOCR)
185         sep = lf;
186     else if (dwFlags & CRYPT_STRING_NOCRLF)
187         sep = "";
188     else
189         sep = crlf;
190     switch (dwFlags & 0x0fffffff)
191     {
192     case CRYPT_STRING_BASE64:
193         /* no header or footer */
194         break;
195     case CRYPT_STRING_BASE64HEADER:
196         header = CERT_HEADER;
197         trailer = CERT_TRAILER;
198         break;
199     case CRYPT_STRING_BASE64REQUESTHEADER:
200         header = CERT_REQUEST_HEADER;
201         trailer = CERT_REQUEST_TRAILER;
202         break;
203     case CRYPT_STRING_BASE64X509CRLHEADER:
204         header = X509_HEADER;
205         trailer = X509_TRAILER;
206         break;
207     }
208 
209     charsNeeded = 0;
210     encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
211     if (header)
212         charsNeeded += strlen(header) + strlen(sep);
213     if (trailer)
214         charsNeeded += strlen(trailer) + strlen(sep);
215 
216     if (pszString)
217     {
218         if (charsNeeded <= *pcchString)
219         {
220             LPSTR ptr = pszString;
221             DWORD size = charsNeeded;
222 
223             if (header)
224             {
225                 strcpy(ptr, header);
226                 ptr += strlen(ptr);
227                 strcpy(ptr, sep);
228                 ptr += strlen(sep);
229             }
230             encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
231             ptr += size - 1;
232             if (trailer)
233             {
234                 strcpy(ptr, trailer);
235                 ptr += strlen(ptr);
236                strcpy(ptr, sep);
237             }
238             *pcchString = charsNeeded - 1;
239         }
240         else
241         {
242             *pcchString = charsNeeded;
243             SetLastError(ERROR_INSUFFICIENT_BUFFER);
244             ret = FALSE;
245         }
246     }
247     else
248         *pcchString = charsNeeded;
249 
250     return ret;
251 }
252 
CryptBinaryToStringA(const BYTE * pbBinary,DWORD cbBinary,DWORD dwFlags,LPSTR pszString,DWORD * pcchString)253 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
254  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
255 {
256     BinaryToStringAFunc encoder = NULL;
257 
258     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
259      pcchString);
260 
261     if (!pbBinary)
262     {
263         SetLastError(ERROR_INVALID_PARAMETER);
264         return FALSE;
265     }
266     if (!pcchString)
267     {
268         SetLastError(ERROR_INVALID_PARAMETER);
269         return FALSE;
270     }
271 
272     switch (dwFlags & 0x0fffffff)
273     {
274     case CRYPT_STRING_BINARY:
275         encoder = EncodeBinaryToBinaryA;
276         break;
277     case CRYPT_STRING_BASE64:
278     case CRYPT_STRING_BASE64HEADER:
279     case CRYPT_STRING_BASE64REQUESTHEADER:
280     case CRYPT_STRING_BASE64X509CRLHEADER:
281         encoder = BinaryToBase64A;
282         break;
283     case CRYPT_STRING_HEX:
284     case CRYPT_STRING_HEXASCII:
285     case CRYPT_STRING_HEXADDR:
286     case CRYPT_STRING_HEXASCIIADDR:
287         FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
288         /* fall through */
289     default:
290         SetLastError(ERROR_INVALID_PARAMETER);
291         return FALSE;
292     }
293     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
294 }
295 
EncodeBinaryToBinaryW(const BYTE * in_buf,DWORD in_len,DWORD flags,WCHAR * out_buf,DWORD * out_len)296 static BOOL EncodeBinaryToBinaryW(const BYTE *in_buf, DWORD in_len, DWORD flags, WCHAR *out_buf, DWORD *out_len)
297 {
298     BOOL ret = TRUE;
299 
300     if (out_buf)
301     {
302         if (*out_len < in_len)
303         {
304             SetLastError(ERROR_INSUFFICIENT_BUFFER);
305             ret = FALSE;
306         }
307         else if (in_len)
308             memcpy(out_buf, in_buf, in_len);
309     }
310     else
311         *out_len = in_len;
312 
313     return ret;
314 }
315 
encodeBase64W(const BYTE * in_buf,int in_len,LPCWSTR sep,WCHAR * out_buf,DWORD * out_len)316 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
317  WCHAR* out_buf, DWORD *out_len)
318 {
319     int div, i;
320     const BYTE *d = in_buf;
321     int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
322     DWORD needed;
323     LPWSTR ptr;
324 
325     TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
326     needed = bytes + pad_bytes;
327     needed += (needed / 64 + (needed % 64 ? 1 : 0)) * strlenW(sep);
328     needed++;
329 
330     if (needed > *out_len)
331     {
332         *out_len = needed;
333         return ERROR_INSUFFICIENT_BUFFER;
334     }
335     else
336         *out_len = needed;
337 
338     /* Three bytes of input give 4 chars of output */
339     div = in_len / 3;
340 
341     ptr = out_buf;
342     i = 0;
343     while (div > 0)
344     {
345         if (i && i % 64 == 0)
346         {
347             strcpyW(ptr, sep);
348             ptr += strlenW(sep);
349         }
350         /* first char is the first 6 bits of the first byte*/
351         *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
352         /* second char is the last 2 bits of the first byte and the first 4
353          * bits of the second byte */
354         *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
355         /* third char is the last 4 bits of the second byte and the first 2
356          * bits of the third byte */
357         *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
358         /* fourth char is the remaining 6 bits of the third byte */
359         *ptr++ = b64[   d[2]       & 0x3f];
360         i += 4;
361         d += 3;
362         div--;
363     }
364 
365     switch(pad_bytes)
366     {
367         case 1:
368             /* first char is the first 6 bits of the first byte*/
369             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
370             /* second char is the last 2 bits of the first byte and the first 4
371              * bits of the second byte */
372             *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
373             /* third char is the last 4 bits of the second byte padded with
374              * two zeroes */
375             *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
376             /* fourth char is a = to indicate one byte of padding */
377             *ptr++ = '=';
378             break;
379         case 2:
380             /* first char is the first 6 bits of the first byte*/
381             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
382             /* second char is the last 2 bits of the first byte padded with
383              * four zeroes*/
384             *ptr++ = b64[ ((d[0] << 4) & 0x30)];
385             /* third char is = to indicate padding */
386             *ptr++ = '=';
387             /* fourth char is = to indicate padding */
388             *ptr++ = '=';
389             break;
390     }
391     strcpyW(ptr, sep);
392 
393     return ERROR_SUCCESS;
394 }
395 
BinaryToBase64W(const BYTE * pbBinary,DWORD cbBinary,DWORD dwFlags,LPWSTR pszString,DWORD * pcchString)396 static BOOL BinaryToBase64W(const BYTE *pbBinary,
397  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
398 {
399     static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 }, empty[] = {0};
400     BOOL ret = TRUE;
401     LPCWSTR header = NULL, trailer = NULL, sep;
402     DWORD charsNeeded;
403 
404     if (dwFlags & CRYPT_STRING_NOCR)
405         sep = lf;
406     else if (dwFlags & CRYPT_STRING_NOCRLF)
407         sep = empty;
408     else
409         sep = crlf;
410     switch (dwFlags & 0x0fffffff)
411     {
412     case CRYPT_STRING_BASE64:
413         /* no header or footer */
414         break;
415     case CRYPT_STRING_BASE64HEADER:
416         header = CERT_HEADER_W;
417         trailer = CERT_TRAILER_W;
418         break;
419     case CRYPT_STRING_BASE64REQUESTHEADER:
420         header = CERT_REQUEST_HEADER_W;
421         trailer = CERT_REQUEST_TRAILER_W;
422         break;
423     case CRYPT_STRING_BASE64X509CRLHEADER:
424         header = X509_HEADER_W;
425         trailer = X509_TRAILER_W;
426         break;
427     }
428 
429     charsNeeded = 0;
430     encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
431     if (header)
432         charsNeeded += strlenW(header) + strlenW(sep);
433     if (trailer)
434         charsNeeded += strlenW(trailer) + strlenW(sep);
435 
436     if (pszString)
437     {
438         if (charsNeeded <= *pcchString)
439         {
440             LPWSTR ptr = pszString;
441             DWORD size = charsNeeded;
442 
443             if (header)
444             {
445                 strcpyW(ptr, header);
446                 ptr += strlenW(ptr);
447                 strcpyW(ptr, sep);
448                 ptr += strlenW(sep);
449             }
450             encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
451             ptr += size - 1;
452             if (trailer)
453             {
454                 strcpyW(ptr, trailer);
455                 ptr += strlenW(ptr);
456                 strcpyW(ptr, sep);
457             }
458             *pcchString = charsNeeded - 1;
459         }
460         else
461         {
462             *pcchString = charsNeeded;
463             SetLastError(ERROR_INSUFFICIENT_BUFFER);
464             ret = FALSE;
465         }
466     }
467     else
468         *pcchString = charsNeeded;
469 
470     return ret;
471 }
472 
CryptBinaryToStringW(const BYTE * pbBinary,DWORD cbBinary,DWORD dwFlags,LPWSTR pszString,DWORD * pcchString)473 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
474  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
475 {
476     BinaryToStringWFunc encoder = NULL;
477 
478     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
479      pcchString);
480 
481     if (!pbBinary)
482     {
483         SetLastError(ERROR_INVALID_PARAMETER);
484         return FALSE;
485     }
486     if (!pcchString)
487     {
488         SetLastError(ERROR_INVALID_PARAMETER);
489         return FALSE;
490     }
491 
492     switch (dwFlags & 0x0fffffff)
493     {
494     case CRYPT_STRING_BINARY:
495         encoder = EncodeBinaryToBinaryW;
496         break;
497     case CRYPT_STRING_BASE64:
498     case CRYPT_STRING_BASE64HEADER:
499     case CRYPT_STRING_BASE64REQUESTHEADER:
500     case CRYPT_STRING_BASE64X509CRLHEADER:
501         encoder = BinaryToBase64W;
502         break;
503     case CRYPT_STRING_HEX:
504     case CRYPT_STRING_HEXASCII:
505     case CRYPT_STRING_HEXADDR:
506     case CRYPT_STRING_HEXASCIIADDR:
507         FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
508         /* fall through */
509     default:
510         SetLastError(ERROR_INVALID_PARAMETER);
511         return FALSE;
512     }
513     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
514 }
515 
516 #define BASE64_DECODE_PADDING    0x100
517 #define BASE64_DECODE_WHITESPACE 0x200
518 #define BASE64_DECODE_INVALID    0x300
519 
decodeBase64Byte(int c)520 static inline int decodeBase64Byte(int c)
521 {
522     int ret = BASE64_DECODE_INVALID;
523 
524     if (c >= 'A' && c <= 'Z')
525         ret = c - 'A';
526     else if (c >= 'a' && c <= 'z')
527         ret = c - 'a' + 26;
528     else if (c >= '0' && c <= '9')
529         ret = c - '0' + 52;
530     else if (c == '+')
531         ret = 62;
532     else if (c == '/')
533         ret = 63;
534     else if (c == '=')
535         ret = BASE64_DECODE_PADDING;
536     else if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
537         ret = BASE64_DECODE_WHITESPACE;
538     return ret;
539 }
540 
541 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
542  * string to convert.
543  */
544 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
545  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
546 
Base64ToBinary(const void * pszString,BOOL wide,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)547 static LONG Base64ToBinary(const void* pszString, BOOL wide, DWORD cchString,
548  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
549 {
550     DWORD cbIn, cbValid, cbOut, hasPadding;
551     BYTE block[4];
552     for (cbIn = cbValid = cbOut = hasPadding = 0; cbIn < cchString; ++cbIn)
553     {
554         int c = wide ? (int)((WCHAR*)pszString)[cbIn] : (int)((char*)pszString)[cbIn];
555         int d = decodeBase64Byte(c);
556         if (d == BASE64_DECODE_INVALID)
557             goto invalid;
558         if (d == BASE64_DECODE_WHITESPACE)
559             continue;
560 
561         /* When padding starts, data is not acceptable */
562         if (hasPadding && d != BASE64_DECODE_PADDING)
563             goto invalid;
564 
565         /* Padding after a full block (like "VVVV=") is ok and stops decoding */
566         if (d == BASE64_DECODE_PADDING && (cbValid & 3) == 0)
567             break;
568 
569         cbValid += 1;
570 
571         if (d == BASE64_DECODE_PADDING)
572         {
573             hasPadding = 1;
574             /* When padding reaches a full block, stop decoding */
575             if ((cbValid & 3) == 0)
576                 break;
577             continue;
578         }
579 
580         /* cbOut is incremented in the 4-char block as follows: "1-23" */
581         if ((cbValid & 3) != 2)
582             cbOut += 1;
583     }
584     /* Fail if the block has bad padding; omitting padding is fine */
585     if ((cbValid & 3) != 0 && hasPadding)
586         goto invalid;
587     /* Check available buffer size */
588     if (pbBinary && *pcbBinary && cbOut > *pcbBinary)
589         goto overflow;
590     /* Convert the data; this step depends on the validity checks above! */
591     if (pbBinary) for (cbIn = cbValid = cbOut = 0; cbIn < cchString; ++cbIn)
592     {
593         int c = wide ? (int)((WCHAR*)pszString)[cbIn] : (int)((char*)pszString)[cbIn];
594         int d = decodeBase64Byte(c);
595         if (d == BASE64_DECODE_WHITESPACE)
596             continue;
597         if (d == BASE64_DECODE_PADDING)
598             break;
599         block[cbValid & 3] = d;
600         cbValid += 1;
601         switch (cbValid & 3) {
602         case 1:
603             pbBinary[cbOut++] = (block[0] << 2);
604             break;
605         case 2:
606             pbBinary[cbOut-1] = (block[0] << 2) | (block[1] >> 4);
607             break;
608         case 3:
609             pbBinary[cbOut++] = (block[1] << 4) | (block[2] >> 2);
610             break;
611         case 0:
612             pbBinary[cbOut++] = (block[2] << 6) | (block[3] >> 0);
613             break;
614         }
615     }
616     *pcbBinary = cbOut;
617     if (pdwSkip)
618         *pdwSkip = 0;
619     if (pdwFlags)
620         *pdwFlags = CRYPT_STRING_BASE64;
621     return ERROR_SUCCESS;
622 overflow:
623     return ERROR_INSUFFICIENT_BUFFER;
624 invalid:
625     *pcbBinary = cbOut;
626     return ERROR_INVALID_DATA;
627 }
628 
Base64ToBinaryA(LPCSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)629 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
630  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
631 {
632     return Base64ToBinary(pszString, FALSE, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
633 }
634 
Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip)635 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
636  DWORD cchString, BYTE *pbBinary,
637  DWORD *pcbBinary, DWORD *pdwSkip)
638 {
639     LONG ret;
640     LPCSTR header = CERT_HEADER_START;
641     LPCSTR trailer = CERT_TRAILER_START;
642 
643     LPCSTR headerBegins;
644     LPCSTR dataBegins;
645     LPCSTR trailerBegins;
646     size_t dataLength;
647 
648     if ((strlen(header) + strlen(trailer)) > cchString)
649     {
650         return ERROR_INVALID_DATA;
651     }
652 
653     if (!(headerBegins = strstr(pszString, header)))
654     {
655         TRACE("Can't find %s in %s.\n", header, debugstr_an(pszString, cchString));
656         return ERROR_INVALID_DATA;
657     }
658 
659     dataBegins = headerBegins + strlen(header);
660     if (!(dataBegins = strstr(dataBegins, CERT_DELIMITER)))
661     {
662         return ERROR_INVALID_DATA;
663     }
664     dataBegins += strlen(CERT_DELIMITER);
665     if (*dataBegins == '\r') dataBegins++;
666     if (*dataBegins == '\n') dataBegins++;
667 
668     if (!(trailerBegins = strstr(dataBegins, trailer)))
669     {
670         return ERROR_INVALID_DATA;
671     }
672     if (*(trailerBegins-1) == '\n') trailerBegins--;
673     if (*(trailerBegins-1) == '\r') trailerBegins--;
674 
675     if (pdwSkip)
676        *pdwSkip = headerBegins - pszString;
677 
678     dataLength = trailerBegins - dataBegins;
679 
680     ret = Base64ToBinaryA(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
681           NULL);
682 
683     return ret;
684 }
685 
Base64HeaderToBinaryA(LPCSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)686 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
687  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
688 {
689     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
690      pbBinary, pcbBinary, pdwSkip);
691 
692     if (!ret && pdwFlags)
693         *pdwFlags = CRYPT_STRING_BASE64HEADER;
694     return ret;
695 }
696 
Base64RequestHeaderToBinaryA(LPCSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)697 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
698  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
699 {
700     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
701      pbBinary, pcbBinary, pdwSkip);
702 
703     if (!ret && pdwFlags)
704         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
705     return ret;
706 }
707 
Base64X509HeaderToBinaryA(LPCSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)708 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
709  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
710 {
711     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
712      pbBinary, pcbBinary, pdwSkip);
713 
714     if (!ret && pdwFlags)
715         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
716     return ret;
717 }
718 
Base64AnyToBinaryA(LPCSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)719 static LONG Base64AnyToBinaryA(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     return ret;
730 }
731 
DecodeBinaryToBinaryA(LPCSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)732 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
733  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
734 {
735     LONG ret = ERROR_SUCCESS;
736 
737     if (*pcbBinary < cchString)
738     {
739         if (!pbBinary)
740             *pcbBinary = cchString;
741         else
742         {
743             ret = ERROR_INSUFFICIENT_BUFFER;
744             *pcbBinary = cchString;
745         }
746     }
747     else
748     {
749         if (cchString)
750             memcpy(pbBinary, pszString, cchString);
751         *pcbBinary = cchString;
752     }
753     return ret;
754 }
755 
DecodeAnyA(LPCSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)756 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
757  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
758 {
759     LONG ret;
760 
761     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
762      pdwSkip, pdwFlags);
763     if (ret == ERROR_INVALID_DATA)
764         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
765          pdwSkip, pdwFlags);
766     if (ret == ERROR_INVALID_DATA)
767         ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
768          pdwSkip, pdwFlags);
769     return ret;
770 }
771 
CryptStringToBinaryA(LPCSTR pszString,DWORD cchString,DWORD dwFlags,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)772 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
773  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
774  DWORD *pdwSkip, DWORD *pdwFlags)
775 {
776     StringToBinaryAFunc decoder;
777     LONG ret;
778 
779     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_an(pszString, cchString ? cchString : -1),
780      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
781 
782     if (!pszString)
783     {
784         SetLastError(ERROR_INVALID_PARAMETER);
785         return FALSE;
786     }
787     /* Only the bottom byte contains valid types */
788     if (dwFlags & 0xfffffff0)
789     {
790         SetLastError(ERROR_INVALID_DATA);
791         return FALSE;
792     }
793     switch (dwFlags)
794     {
795     case CRYPT_STRING_BASE64_ANY:
796         decoder = Base64AnyToBinaryA;
797         break;
798     case CRYPT_STRING_BASE64:
799         decoder = Base64ToBinaryA;
800         break;
801     case CRYPT_STRING_BASE64HEADER:
802         decoder = Base64HeaderToBinaryA;
803         break;
804     case CRYPT_STRING_BASE64REQUESTHEADER:
805         decoder = Base64RequestHeaderToBinaryA;
806         break;
807     case CRYPT_STRING_BASE64X509CRLHEADER:
808         decoder = Base64X509HeaderToBinaryA;
809         break;
810     case CRYPT_STRING_BINARY:
811         decoder = DecodeBinaryToBinaryA;
812         break;
813     case CRYPT_STRING_ANY:
814         decoder = DecodeAnyA;
815         break;
816     case CRYPT_STRING_HEX:
817     case CRYPT_STRING_HEXASCII:
818     case CRYPT_STRING_HEXADDR:
819     case CRYPT_STRING_HEXASCIIADDR:
820         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
821         /* fall through */
822     default:
823         SetLastError(ERROR_INVALID_PARAMETER);
824         return FALSE;
825     }
826     if (!cchString)
827         cchString = strlen(pszString);
828     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
829     if (ret)
830         SetLastError(ret);
831     return ret == ERROR_SUCCESS;
832 }
833 
834 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
835  * string to convert.
836  */
837 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
838  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
839 
Base64ToBinaryW(LPCWSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)840 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
841  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
842 {
843     return Base64ToBinary(pszString, TRUE, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
844 }
845 
Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip)846 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
847  DWORD cchString, BYTE *pbBinary,
848  DWORD *pcbBinary, DWORD *pdwSkip)
849 {
850     LONG ret;
851     LPCWSTR header = CERT_HEADER_START_W;
852     LPCWSTR trailer = CERT_TRAILER_START_W;
853 
854     LPCWSTR headerBegins;
855     LPCWSTR dataBegins;
856     LPCWSTR trailerBegins;
857     size_t dataLength;
858 
859     if ((strlenW(header) + strlenW(trailer)) > cchString)
860     {
861         return ERROR_INVALID_DATA;
862     }
863 
864     if (!(headerBegins = strstrW(pszString, header)))
865     {
866         TRACE("Can't find %s in %s.\n", debugstr_w(header), debugstr_wn(pszString, cchString));
867         return ERROR_INVALID_DATA;
868     }
869 
870     dataBegins = headerBegins + strlenW(header);
871     if (!(dataBegins = strstrW(dataBegins, CERT_DELIMITER_W)))
872     {
873         return ERROR_INVALID_DATA;
874     }
875     dataBegins += strlenW(CERT_DELIMITER_W);
876     if (*dataBegins == '\r') dataBegins++;
877     if (*dataBegins == '\n') dataBegins++;
878 
879     if (!(trailerBegins = strstrW(dataBegins, trailer)))
880     {
881         return ERROR_INVALID_DATA;
882     }
883     if (*(trailerBegins-1) == '\n') trailerBegins--;
884     if (*(trailerBegins-1) == '\r') trailerBegins--;
885 
886     if (pdwSkip)
887        *pdwSkip = headerBegins - pszString;
888 
889     dataLength = trailerBegins - dataBegins;
890 
891     ret = Base64ToBinaryW(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
892           NULL);
893 
894     return ret;
895 }
896 
Base64HeaderToBinaryW(LPCWSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)897 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
898  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
899 {
900     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
901      pbBinary, pcbBinary, pdwSkip);
902 
903     if (!ret && pdwFlags)
904         *pdwFlags = CRYPT_STRING_BASE64HEADER;
905     return ret;
906 }
907 
Base64RequestHeaderToBinaryW(LPCWSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)908 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
909  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
910 {
911     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
912      pbBinary, pcbBinary, pdwSkip);
913 
914     if (!ret && pdwFlags)
915         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
916     return ret;
917 }
918 
Base64X509HeaderToBinaryW(LPCWSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)919 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
920  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
921 {
922     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
923      pbBinary, pcbBinary, pdwSkip);
924 
925     if (!ret && pdwFlags)
926         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
927     return ret;
928 }
929 
Base64AnyToBinaryW(LPCWSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)930 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
931  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
932 {
933     LONG ret;
934 
935     ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
936      pdwSkip, pdwFlags);
937     if (ret == ERROR_INVALID_DATA)
938         ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
939          pdwSkip, pdwFlags);
940     return ret;
941 }
942 
DecodeBinaryToBinaryW(LPCWSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)943 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
944  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
945 {
946     LONG ret = ERROR_SUCCESS;
947 
948     if (*pcbBinary < cchString)
949     {
950         if (!pbBinary)
951             *pcbBinary = cchString;
952         else
953         {
954             ret = ERROR_INSUFFICIENT_BUFFER;
955             *pcbBinary = cchString;
956         }
957     }
958     else
959     {
960         if (cchString)
961             memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
962         *pcbBinary = cchString * sizeof(WCHAR);
963     }
964     return ret;
965 }
966 
DecodeAnyW(LPCWSTR pszString,DWORD cchString,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)967 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
968  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
969 {
970     LONG ret;
971 
972     ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
973      pdwSkip, pdwFlags);
974     if (ret == ERROR_INVALID_DATA)
975         ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
976          pdwSkip, pdwFlags);
977     if (ret == ERROR_INVALID_DATA)
978         ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
979          pdwSkip, pdwFlags);
980     return ret;
981 }
982 
CryptStringToBinaryW(LPCWSTR pszString,DWORD cchString,DWORD dwFlags,BYTE * pbBinary,DWORD * pcbBinary,DWORD * pdwSkip,DWORD * pdwFlags)983 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
984  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
985  DWORD *pdwSkip, DWORD *pdwFlags)
986 {
987     StringToBinaryWFunc decoder;
988     LONG ret;
989 
990     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_wn(pszString, cchString ? cchString : -1),
991      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
992 
993     if (!pszString)
994     {
995         SetLastError(ERROR_INVALID_PARAMETER);
996         return FALSE;
997     }
998     /* Only the bottom byte contains valid types */
999     if (dwFlags & 0xfffffff0)
1000     {
1001         SetLastError(ERROR_INVALID_DATA);
1002         return FALSE;
1003     }
1004     switch (dwFlags)
1005     {
1006     case CRYPT_STRING_BASE64_ANY:
1007         decoder = Base64AnyToBinaryW;
1008         break;
1009     case CRYPT_STRING_BASE64:
1010         decoder = Base64ToBinaryW;
1011         break;
1012     case CRYPT_STRING_BASE64HEADER:
1013         decoder = Base64HeaderToBinaryW;
1014         break;
1015     case CRYPT_STRING_BASE64REQUESTHEADER:
1016         decoder = Base64RequestHeaderToBinaryW;
1017         break;
1018     case CRYPT_STRING_BASE64X509CRLHEADER:
1019         decoder = Base64X509HeaderToBinaryW;
1020         break;
1021     case CRYPT_STRING_BINARY:
1022         decoder = DecodeBinaryToBinaryW;
1023         break;
1024     case CRYPT_STRING_ANY:
1025         decoder = DecodeAnyW;
1026         break;
1027     case CRYPT_STRING_HEX:
1028     case CRYPT_STRING_HEXASCII:
1029     case CRYPT_STRING_HEXADDR:
1030     case CRYPT_STRING_HEXASCIIADDR:
1031         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
1032         /* fall through */
1033     default:
1034         SetLastError(ERROR_INVALID_PARAMETER);
1035         return FALSE;
1036     }
1037     if (!cchString)
1038         cchString = strlenW(pszString);
1039     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
1040     if (ret)
1041         SetLastError(ret);
1042     return ret == ERROR_SUCCESS;
1043 }
1044