7 /* encode/decode data, base 64 style
9 /* #include <base64_code.h>
11 /* VSTRING *base64_encode(result, in, len)
16 /* VSTRING *base64_decode(result, in, len)
21 /* base64_encode() takes a block of len bytes and encodes it as one
22 /* null-terminated string. The result value is the result argument.
24 /* base64_decode() performs the opposite transformation. The result
25 /* value is the result argument. The result is null terminated, whether
26 /* or not that makes sense.
28 /* base64_decode () returns a null pointer when the input contains
29 /* characters not in the base 64 alphabet.
33 /* The Secure Mailer license must be distributed with this software.
36 /* IBM T.J. Watson Research
38 /* Yorktown Heights, NY 10598, USA
49 #define UCHAR_MAX 0xff
52 /* Utility library. */
57 #include <base64_code.h>
59 /* Application-specific. */
61 static unsigned char to_b64
[] =
62 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
64 #define UNSIG_CHAR_PTR(x) ((unsigned char *)(x))
66 /* base64_encode - raw data to encoded */
68 VSTRING
*base64_encode(VSTRING
*result
, const char *in
, ssize_t len
)
70 const unsigned char *cp
;
76 VSTRING_RESET(result
);
77 for (cp
= UNSIG_CHAR_PTR(in
), count
= len
; count
> 0; count
-= 3, cp
+= 3) {
78 VSTRING_ADDCH(result
, to_b64
[cp
[0] >> 2]);
80 VSTRING_ADDCH(result
, to_b64
[(cp
[0] & 0x3) << 4 | cp
[1] >> 4]);
82 VSTRING_ADDCH(result
, to_b64
[(cp
[1] & 0xf) << 2 | cp
[2] >> 6]);
83 VSTRING_ADDCH(result
, to_b64
[cp
[2] & 0x3f]);
85 VSTRING_ADDCH(result
, to_b64
[(cp
[1] & 0xf) << 2]);
86 VSTRING_ADDCH(result
, '=');
90 VSTRING_ADDCH(result
, to_b64
[(cp
[0] & 0x3) << 4]);
91 VSTRING_ADDCH(result
, '=');
92 VSTRING_ADDCH(result
, '=');
96 VSTRING_TERMINATE(result
);
100 /* base64_decode - encoded data to raw */
102 VSTRING
*base64_decode(VSTRING
*result
, const char *in
, ssize_t len
)
104 static unsigned char *un_b64
= 0;
105 const unsigned char *cp
;
112 #define CHARS_PER_BYTE (UCHAR_MAX + 1)
122 * Once: initialize the decoding lookup table on the fly.
125 un_b64
= (unsigned char *) mymalloc(CHARS_PER_BYTE
);
126 memset(un_b64
, INVALID
, CHARS_PER_BYTE
);
127 for (cp
= to_b64
; cp
< to_b64
+ sizeof(to_b64
); cp
++)
128 un_b64
[*cp
] = cp
- to_b64
;
134 VSTRING_RESET(result
);
135 for (cp
= UNSIG_CHAR_PTR(in
), count
= 0; count
< len
; count
+= 4) {
136 if ((ch0
= un_b64
[*cp
++]) == INVALID
137 || (ch1
= un_b64
[*cp
++]) == INVALID
)
139 VSTRING_ADDCH(result
, ch0
<< 2 | ch1
>> 4);
140 if ((ch2
= *cp
++) == '=')
142 if ((ch2
= un_b64
[ch2
]) == INVALID
)
144 VSTRING_ADDCH(result
, ch1
<< 4 | ch2
>> 2);
145 if ((ch3
= *cp
++) == '=')
147 if ((ch3
= un_b64
[ch3
]) == INVALID
)
149 VSTRING_ADDCH(result
, ch2
<< 6 | ch3
);
151 VSTRING_TERMINATE(result
);
158 * Proof-of-concept test program: convert to base 64 and back.
161 #define STR(x) vstring_str(x)
162 #define LEN(x) VSTRING_LEN(x)
164 int main(int unused_argc
, char **unused_argv
)
166 VSTRING
*b1
= vstring_alloc(1);
167 VSTRING
*b2
= vstring_alloc(1);
168 char *test
= "this is a test";
170 #define DECODE(b,x,l) { \
171 if (base64_decode((b),(x),(l)) == 0) \
172 msg_panic("bad base64: %s", (x)); \
174 #define VERIFY(b,t) { \
175 if (strcmp((b), (t)) != 0) \
176 msg_panic("bad test: %s", (b)); \
179 base64_encode(b1
, test
, strlen(test
));
180 DECODE(b2
, STR(b1
), LEN(b1
));
181 VERIFY(STR(b2
), test
);
183 base64_encode(b1
, test
, strlen(test
));
184 base64_encode(b2
, STR(b1
), LEN(b1
));
185 base64_encode(b1
, STR(b2
), LEN(b2
));
186 DECODE(b2
, STR(b1
), LEN(b1
));
187 DECODE(b1
, STR(b2
), LEN(b2
));
188 DECODE(b2
, STR(b1
), LEN(b1
));
189 VERIFY(STR(b2
), test
);
191 base64_encode(b1
, test
, strlen(test
));
192 base64_encode(b2
, STR(b1
), LEN(b1
));
193 base64_encode(b1
, STR(b2
), LEN(b2
));
194 base64_encode(b2
, STR(b1
), LEN(b1
));
195 base64_encode(b1
, STR(b2
), LEN(b2
));
196 DECODE(b2
, STR(b1
), LEN(b1
));
197 DECODE(b1
, STR(b2
), LEN(b2
));
198 DECODE(b2
, STR(b1
), LEN(b1
));
199 DECODE(b1
, STR(b2
), LEN(b2
));
200 DECODE(b2
, STR(b1
), LEN(b1
));
201 VERIFY(STR(b2
), test
);