wined3d: Prevent some console spamming.
[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 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
29 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
30
31 #define CERT_HEADER          "-----BEGIN CERTIFICATE-----"
32 #define CERT_TRAILER         "-----END CERTIFICATE-----"
33 #define CERT_REQUEST_HEADER  "-----BEGIN NEW CERTIFICATE REQUEST-----"
34 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
35 #define X509_HEADER          "-----BEGIN X509 CRL-----"
36 #define X509_TRAILER         "-----END X509 CRL-----"
37
38 static const char b64[] =
39 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
40
41 typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary,
42  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString);
43
44 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
45  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
46 {
47     BOOL ret = TRUE;
48
49     if (*pcchString < cbBinary)
50     {
51         if (!pszString)
52             *pcchString = cbBinary;
53         else
54         {
55             SetLastError(ERROR_INSUFFICIENT_BUFFER);
56             *pcchString = cbBinary;
57             ret = FALSE;
58         }
59     }
60     else
61     {
62         if (cbBinary)
63             memcpy(pszString, pbBinary, cbBinary);
64         *pcchString = cbBinary;
65     }
66     return ret;
67 }
68
69 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
70  char* out_buf, DWORD *out_len)
71 {
72     int div, i;
73     const BYTE *d = in_buf;
74     int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
75     DWORD needed;
76     LPSTR ptr;
77
78     TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
79     needed = bytes + pad_bytes + 1;
80     needed += (needed / 64 + 1) * strlen(sep);
81
82     if (needed > *out_len)
83     {
84         *out_len = needed;
85         return ERROR_INSUFFICIENT_BUFFER;
86     }
87     else
88         *out_len = needed;
89
90     /* Three bytes of input give 4 chars of output */
91     div = in_len / 3;
92
93     ptr = out_buf;
94     i = 0;
95     while (div > 0)
96     {
97         if (i && i % 64 == 0)
98         {
99             strcpy(ptr, sep);
100             ptr += strlen(sep);
101         }
102         /* first char is the first 6 bits of the first byte*/
103         *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
104         /* second char is the last 2 bits of the first byte and the first 4
105          * bits of the second byte */
106         *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
107         /* third char is the last 4 bits of the second byte and the first 2
108          * bits of the third byte */
109         *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
110         /* fourth char is the remaining 6 bits of the third byte */
111         *ptr++ = b64[   d[2]       & 0x3f];
112         i += 4;
113         d += 3;
114         div--;
115     }
116
117     switch(pad_bytes)
118     {
119         case 1:
120             /* first char is the first 6 bits of the first byte*/
121             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
122             /* second char is the last 2 bits of the first byte and the first 4
123              * bits of the second byte */
124             *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
125             /* third char is the last 4 bits of the second byte padded with
126              * two zeroes */
127             *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
128             /* fourth char is a = to indicate one byte of padding */
129             *ptr++ = '=';
130             break;
131         case 2:
132             /* first char is the first 6 bits of the first byte*/
133             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
134             /* second char is the last 2 bits of the first byte padded with
135              * four zeroes*/
136             *ptr++ = b64[ ((d[0] << 4) & 0x30)];
137             /* third char is = to indicate padding */
138             *ptr++ = '=';
139             /* fourth char is = to indicate padding */
140             *ptr++ = '=';
141             break;
142     }
143     strcpy(ptr, sep);
144
145     return ERROR_SUCCESS;
146 }
147
148 static BOOL BinaryToBase64A(const BYTE *pbBinary,
149  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
150 {
151     static const char crlf[] = "\r\n", lf[] = "\n";
152     BOOL ret = TRUE;
153     LPCSTR header = NULL, trailer = NULL, sep = NULL;
154     DWORD charsNeeded;
155
156     if (dwFlags & CRYPT_STRING_NOCR)
157         sep = lf;
158     else
159         sep = crlf;
160     switch (dwFlags & 0x7fffffff)
161     {
162     case CRYPT_STRING_BASE64:
163         /* no header or footer */
164         break;
165     case CRYPT_STRING_BASE64HEADER:
166         header = CERT_HEADER;
167         trailer = CERT_TRAILER;
168         break;
169     case CRYPT_STRING_BASE64REQUESTHEADER:
170         header = CERT_REQUEST_HEADER;
171         trailer = CERT_REQUEST_TRAILER;
172         break;
173     case CRYPT_STRING_BASE64X509CRLHEADER:
174         header = X509_HEADER;
175         trailer = X509_TRAILER;
176         break;
177     }
178
179     charsNeeded = 0;
180     encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
181     charsNeeded += strlen(sep);
182     if (header)
183         charsNeeded += strlen(header) + strlen(sep);
184     if (trailer)
185         charsNeeded += strlen(trailer) + strlen(sep);
186     if (charsNeeded <= *pcchString)
187     {
188         LPSTR ptr = pszString;
189         DWORD size = charsNeeded;
190
191         if (header)
192         {
193             strcpy(ptr, header);
194             ptr += strlen(ptr);
195             strcpy(ptr, sep);
196             ptr += strlen(sep);
197         }
198         encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
199         ptr += size - 1;
200         if (trailer)
201         {
202             strcpy(ptr, trailer);
203             ptr += strlen(ptr);
204             strcpy(ptr, sep);
205             ptr += strlen(sep);
206         }
207         *pcchString = charsNeeded - 1;
208     }
209     else if (pszString)
210     {
211         *pcchString = charsNeeded;
212         SetLastError(ERROR_INSUFFICIENT_BUFFER);
213         ret = FALSE;
214     }
215     else
216         *pcchString = charsNeeded;
217     return ret;
218 }
219
220 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
221  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
222 {
223     BinaryToStringAFunc encoder = NULL;
224
225     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
226      pcchString);
227
228     if (!pbBinary)
229     {
230         SetLastError(ERROR_INVALID_PARAMETER);
231         return FALSE;
232     }
233     if (!pcchString)
234     {
235         SetLastError(ERROR_INVALID_PARAMETER);
236         return FALSE;
237     }
238
239     switch (dwFlags & 0x7fffffff)
240     {
241     case CRYPT_STRING_BINARY:
242         encoder = EncodeBinaryToBinaryA;
243         break;
244     case CRYPT_STRING_BASE64:
245     case CRYPT_STRING_BASE64HEADER:
246     case CRYPT_STRING_BASE64REQUESTHEADER:
247     case CRYPT_STRING_BASE64X509CRLHEADER:
248         encoder = BinaryToBase64A;
249         break;
250     case CRYPT_STRING_HEX:
251     case CRYPT_STRING_HEXASCII:
252     case CRYPT_STRING_HEXADDR:
253     case CRYPT_STRING_HEXASCIIADDR:
254         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
255         /* fall through */
256     default:
257         SetLastError(ERROR_INVALID_PARAMETER);
258         return FALSE;
259     }
260     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
261 }
262
263 static inline BYTE decodeBase64Byte(char c)
264 {
265     BYTE ret;
266
267     if (c >= 'A' && c <= 'Z')
268         ret = c - 'A';
269     else if (c >= 'a' && c <= 'z')
270         ret = c - 'a' + 26;
271     else if (c >= '0' && c <= '9')
272         ret = c - '0' + 52;
273     else if (c == '+')
274         ret = 62;
275     else if (c == '/')
276         ret = 63;
277     else
278         ret = 64;
279     return ret;
280 }
281
282 static LONG decodeBase64Block(const char *in_buf, int in_len,
283  const char **nextBlock, PBYTE out_buf, DWORD *out_len)
284 {
285     int len = in_len, i;
286     const char *d = in_buf;
287     int  ip0, ip1, ip2, ip3;
288
289     if (len < 4)
290         return ERROR_INVALID_DATA;
291
292     i = 0;
293     if (d[2] == '=')
294     {
295         if ((ip0 = decodeBase64Byte(d[0])) > 63)
296             return ERROR_INVALID_DATA;
297         if ((ip1 = decodeBase64Byte(d[1])) > 63)
298             return ERROR_INVALID_DATA;
299
300         if (out_buf)
301             out_buf[i] = (ip0 << 2) | (ip1 >> 4);
302         i++;
303     }
304     else if (d[3] == '=')
305     {
306         if ((ip0 = decodeBase64Byte(d[0])) > 63)
307             return ERROR_INVALID_DATA;
308         if ((ip1 = decodeBase64Byte(d[1])) > 63)
309             return ERROR_INVALID_DATA;
310         if ((ip2 = decodeBase64Byte(d[2])) > 63)
311             return ERROR_INVALID_DATA;
312
313         if (out_buf)
314         {
315             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
316             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
317         }
318         i += 2;
319     }
320     else
321     {
322         if ((ip0 = decodeBase64Byte(d[0])) > 63)
323             return ERROR_INVALID_DATA;
324         if ((ip1 = decodeBase64Byte(d[1])) > 63)
325             return ERROR_INVALID_DATA;
326         if ((ip2 = decodeBase64Byte(d[2])) > 63)
327             return ERROR_INVALID_DATA;
328         if ((ip3 = decodeBase64Byte(d[3])) > 63)
329             return ERROR_INVALID_DATA;
330
331         if (out_buf)
332         {
333             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
334             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
335             out_buf[i + 2] = (ip2 << 6) |  ip3;
336         }
337         i += 3;
338     }
339     if (len >= 6 && d[4] == '\r' && d[5] == '\n')
340         *nextBlock = d + 6;
341     else if (len >= 5 && d[4] == '\n')
342         *nextBlock = d + 5;
343     else if (len >= 4 && d[4])
344         *nextBlock = d + 4;
345     else
346         *nextBlock = NULL;
347     *out_len = i;
348     return ERROR_SUCCESS;
349 }
350
351 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
352  * string to convert.
353  */
354 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
355  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
356
357 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
358  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
359 {
360     LONG ret = ERROR_SUCCESS;
361     const char *nextBlock;
362     DWORD outLen = 0;
363
364     nextBlock = pszString;
365     while (nextBlock && !ret)
366     {
367         DWORD len = 0;
368
369         ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
370          &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
371         if (!ret)
372             outLen += len;
373         if (cchString - (nextBlock - pszString) <= 0)
374             nextBlock = NULL;
375     }
376     *pcbBinary = outLen;
377     if (!ret)
378     {
379         if (pdwSkip)
380             *pdwSkip = 0;
381         if (pdwFlags)
382             *pdwFlags = CRYPT_STRING_BASE64;
383     }
384     else if (ret == ERROR_INSUFFICIENT_BUFFER)
385     {
386         if (!pbBinary)
387             ret = ERROR_SUCCESS;
388     }
389     return ret;
390 }
391
392 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
393  DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
394  DWORD *pcbBinary, DWORD *pdwSkip)
395 {
396     LONG ret;
397     LPCSTR ptr;
398
399     if (cchString > strlen(header) + strlen(trailer)
400      && (ptr = strstr(pszString, header)) != NULL)
401     {
402         LPCSTR trailerSpot = pszString + cchString - strlen(trailer);
403
404         if (pszString[cchString - 1] == '\n')
405         {
406             cchString--;
407             trailerSpot--;
408         }
409         if (pszString[cchString - 1] == '\r')
410         {
411             cchString--;
412             trailerSpot--;
413         }
414         if (!strncmp(trailerSpot, trailer, strlen(trailer)))
415         {
416             if (pdwSkip)
417                 *pdwSkip = ptr - pszString;
418             ptr += strlen(header);
419             if (*ptr == '\r') ptr++;
420             if (*ptr == '\n') ptr++;
421             cchString -= ptr - pszString + strlen(trailer);
422             ret = Base64ToBinaryA(ptr, cchString, pbBinary, pcbBinary, NULL,
423              NULL);
424         }
425         else
426             ret = ERROR_INVALID_DATA;
427     }
428     else
429         ret = ERROR_INVALID_DATA;
430     return ret;
431 }
432
433 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
434  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
435 {
436     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
437      CERT_HEADER, CERT_TRAILER, pbBinary, pcbBinary, pdwSkip);
438
439     if (!ret && pdwFlags)
440         *pdwFlags = CRYPT_STRING_BASE64HEADER;
441     return ret;
442 }
443
444 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
445  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
446 {
447     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
448      CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip);
449
450     if (!ret && pdwFlags)
451         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
452     return ret;
453 }
454
455 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
456  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
457 {
458     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
459      X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip);
460
461     if (!ret && pdwFlags)
462         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
463     return ret;
464 }
465
466 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
467  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
468 {
469     LONG ret;
470
471     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
472      pdwSkip, pdwFlags);
473     if (ret == ERROR_INVALID_DATA)
474         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
475          pdwSkip, pdwFlags);
476     return ret;
477 }
478
479 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
480  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
481 {
482     LONG ret = ERROR_SUCCESS;
483
484     if (*pcbBinary < cchString)
485     {
486         if (!pbBinary)
487             *pcbBinary = cchString;
488         else
489         {
490             ret = ERROR_INSUFFICIENT_BUFFER;
491             *pcbBinary = cchString;
492         }
493     }
494     else
495     {
496         if (cchString)
497             memcpy(pbBinary, pszString, cchString);
498         *pcbBinary = cchString;
499     }
500     return ret;
501 }
502
503 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
504  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
505 {
506     LONG ret;
507
508     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
509      pdwSkip, pdwFlags);
510     if (ret == ERROR_INVALID_DATA)
511         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
512          pdwSkip, pdwFlags);
513     if (ret == ERROR_INVALID_DATA)
514         ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
515          pdwSkip, pdwFlags);
516     return ret;
517 }
518
519 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
520  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
521  DWORD *pdwSkip, DWORD *pdwFlags)
522 {
523     StringToBinaryAFunc decoder;
524     LONG ret;
525
526     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
527      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
528
529     if (!pszString)
530     {
531         SetLastError(ERROR_INVALID_PARAMETER);
532         return FALSE;
533     }
534     /* Only the bottom byte contains valid types */
535     if (dwFlags & 0xfffffff0)
536     {
537         SetLastError(ERROR_INVALID_DATA);
538         return FALSE;
539     }
540     switch (dwFlags)
541     {
542     case CRYPT_STRING_BASE64_ANY:
543         decoder = Base64AnyToBinaryA;
544         break;
545     case CRYPT_STRING_BASE64:
546         decoder = Base64ToBinaryA;
547         break;
548     case CRYPT_STRING_BASE64HEADER:
549         decoder = Base64HeaderToBinaryA;
550         break;
551     case CRYPT_STRING_BASE64REQUESTHEADER:
552         decoder = Base64RequestHeaderToBinaryA;
553         break;
554     case CRYPT_STRING_BASE64X509CRLHEADER:
555         decoder = Base64X509HeaderToBinaryA;
556         break;
557     case CRYPT_STRING_BINARY:
558         decoder = DecodeBinaryToBinaryA;
559         break;
560     case CRYPT_STRING_ANY:
561         decoder = DecodeAnyA;
562         break;
563     case CRYPT_STRING_HEX:
564     case CRYPT_STRING_HEXASCII:
565     case CRYPT_STRING_HEXADDR:
566     case CRYPT_STRING_HEXASCIIADDR:
567         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
568         /* fall through */
569     default:
570         SetLastError(ERROR_INVALID_PARAMETER);
571         return FALSE;
572     }
573     if (!cchString)
574         cchString = strlen(pszString);
575     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
576     if (ret)
577         SetLastError(ret);
578     return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
579 }