1 |
dpavlin |
1 |
/* |
2 |
|
|
* base64.c -- base-64 conversion routines. |
3 |
|
|
* Copyright (C)2002 by Eric S. Raymond. |
4 |
|
|
* |
5 |
|
|
* For license terms, see the file COPYING in this directory. |
6 |
|
|
* |
7 |
|
|
* This base 64 encoding is defined in RFC2045 section 6.8, |
8 |
|
|
* "Base64 Content-Transfer-Encoding", but lines must not be broken in the |
9 |
|
|
* scheme used here. |
10 |
|
|
*/ |
11 |
|
|
|
12 |
|
|
#include <ctype.h> |
13 |
|
|
|
14 |
|
|
static const char base64digits[] = |
15 |
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
16 |
|
|
|
17 |
|
|
#define BAD -1 |
18 |
|
|
|
19 |
|
|
static const char base64val[] = { |
20 |
|
|
BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, |
21 |
|
|
BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, |
22 |
|
|
BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63, |
23 |
|
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,BAD,BAD, BAD,BAD,BAD,BAD, |
24 |
|
|
BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
25 |
|
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,BAD, BAD,BAD,BAD,BAD, |
26 |
|
|
BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
27 |
|
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,BAD, BAD,BAD,BAD,BAD |
28 |
|
|
}; |
29 |
|
|
|
30 |
|
|
#define DECODE64(c) (isascii(c) ? base64val[c] : BAD) |
31 |
|
|
|
32 |
|
|
/* Encode into base64 */ |
33 |
|
|
void base64_encode(unsigned char *out,const unsigned char *in,int inlen) |
34 |
|
|
{ |
35 |
|
|
/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */ |
36 |
|
|
for (; inlen >= 3; inlen -= 3) { |
37 |
|
|
*out++ = base64digits[in[0] >> 2]; |
38 |
|
|
*out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)]; |
39 |
|
|
*out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; |
40 |
|
|
*out++ = base64digits[in[2] & 0x3f]; |
41 |
|
|
in += 3; |
42 |
|
|
} |
43 |
|
|
|
44 |
|
|
if (inlen > 0) { |
45 |
|
|
unsigned char fragment; |
46 |
|
|
|
47 |
|
|
*out++ = base64digits[in[0] >> 2]; |
48 |
|
|
fragment = (in[0] << 4) & 0x30; |
49 |
|
|
if (inlen > 1) |
50 |
|
|
fragment |= in[1] >> 4; |
51 |
|
|
*out++ = base64digits[fragment]; |
52 |
|
|
*out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c]; |
53 |
|
|
*out++ = '='; |
54 |
|
|
} |
55 |
|
|
*out = '\0'; |
56 |
|
|
} |
57 |
|
|
|
58 |
|
|
/* |
59 |
|
|
* Decode from base64. |
60 |
|
|
* |
61 |
|
|
* base 64 to raw bytes in quasi-big-endian order, returning count of bytes |
62 |
|
|
* maxlen limits output buffer size, set to zero to ignore. |
63 |
|
|
*/ |
64 |
|
|
int base64_decode(unsigned char *out,const unsigned char *in,int maxlen) |
65 |
|
|
{ |
66 |
|
|
register unsigned char digit1, digit2, digit3, digit4; |
67 |
|
|
int len = 0; |
68 |
|
|
|
69 |
|
|
if (in[0] == '+' && in[1] == ' ') |
70 |
|
|
in += 2; |
71 |
|
|
if (*in == '\r') |
72 |
|
|
return(0); |
73 |
|
|
|
74 |
|
|
do { |
75 |
|
|
digit1 = in[0]; |
76 |
|
|
if (DECODE64(digit1) == BAD) |
77 |
|
|
return(-1); |
78 |
|
|
digit2 = in[1]; |
79 |
|
|
if (DECODE64(digit2) == BAD) |
80 |
|
|
return(-1); |
81 |
|
|
digit3 = in[2]; |
82 |
|
|
if (digit3 != '=' && DECODE64(digit3) == BAD) |
83 |
|
|
return(-1); |
84 |
|
|
digit4 = in[3]; |
85 |
|
|
if (digit4 != '=' && DECODE64(digit4) == BAD) |
86 |
|
|
return(-1); |
87 |
|
|
in += 4; |
88 |
|
|
++len; |
89 |
|
|
|
90 |
|
|
if (maxlen && len > maxlen) |
91 |
|
|
return(-1); |
92 |
|
|
|
93 |
|
|
*out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4); |
94 |
|
|
if (digit3 != '=') |
95 |
|
|
{ |
96 |
|
|
++len; |
97 |
|
|
if (maxlen && (len > maxlen)) |
98 |
|
|
return(-1); |
99 |
|
|
|
100 |
|
|
*out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2); |
101 |
|
|
if (digit4 != '=') { |
102 |
|
|
++len; |
103 |
|
|
if (maxlen && (len > maxlen)) |
104 |
|
|
return(-1); |
105 |
|
|
*out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4); |
106 |
|
|
} |
107 |
|
|
} |
108 |
|
|
} while(*in && (*in != '\r') && (digit4 != '=')); |
109 |
|
|
|
110 |
|
|
return(len); |
111 |
|
|
} |