source: trunk/src/crypt32/base64.c@ 21354

Last change on this file since 21354 was 21354, checked in by rlwalsh, 16 years ago

eliminate VACPP warning & info msgs - see Ticket #1

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