1 /* $NetBSD: base64_code.c,v 1.1.1.2 2014/07/06 19:27:57 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* base64_code 3 6 /* SUMMARY 7 /* encode/decode data, base 64 style 8 /* SYNOPSIS 9 /* #include <base64_code.h> 10 /* 11 /* VSTRING *base64_encode(result, in, len) 12 /* VSTRING *result; 13 /* const char *in; 14 /* ssize_t len; 15 /* 16 /* VSTRING *base64_decode(result, in, len) 17 /* VSTRING *result; 18 /* const char *in; 19 /* ssize_t len; 20 /* 21 /* VSTRING *base64_encode_opt(result, in, len, flags) 22 /* VSTRING *result; 23 /* const char *in; 24 /* ssize_t len; 25 /* int flags; 26 /* 27 /* VSTRING *base64_decode_opt(result, in, len, flags) 28 /* VSTRING *result; 29 /* const char *in; 30 /* ssize_t len; 31 /* int flags; 32 /* DESCRIPTION 33 /* base64_encode() takes a block of len bytes and encodes it as one 34 /* null-terminated string. The result value is the result argument. 35 /* 36 /* base64_decode() performs the opposite transformation. The result 37 /* value is the result argument. The result is null terminated, whether 38 /* or not that makes sense. 39 /* 40 /* base64_encode_opt() and base64_decode_opt() provide extended 41 /* interfaces. In both cases the flags arguments is the bit-wise 42 /* OR of zero or more the following: 43 /* .IP BASE64_FLAG_APPEND 44 /* Append the result, instead of overwriting the result buffer. 45 /* .PP 46 /* For convenience, BASE64_FLAG_NONE specifies none of the above. 47 /* DIAGNOSTICS 48 /* base64_decode () returns a null pointer when the input contains 49 /* characters not in the base 64 alphabet. 50 /* LICENSE 51 /* .ad 52 /* .fi 53 /* The Secure Mailer license must be distributed with this software. 54 /* AUTHOR(S) 55 /* Wietse Venema 56 /* IBM T.J. Watson Research 57 /* P.O. Box 704 58 /* Yorktown Heights, NY 10598, USA 59 /*--*/ 60 61 /* System library. */ 62 63 #include "sys_defs.h" 64 #include <ctype.h> 65 #include <string.h> 66 #include <limits.h> 67 68 #ifndef UCHAR_MAX 69 #define UCHAR_MAX 0xff 70 #endif 71 72 /* Utility library. */ 73 74 #include <msg.h> 75 #include <mymalloc.h> 76 #include <vstring.h> 77 #include <base64_code.h> 78 79 /* Application-specific. */ 80 81 static unsigned char to_b64[] = 82 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 83 84 #define UNSIG_CHAR_PTR(x) ((unsigned char *)(x)) 85 86 /* base64_encode - raw data to encoded */ 87 88 #undef base64_encode 89 90 extern VSTRING *base64_encode(VSTRING *, const char *, ssize_t); 91 92 VSTRING *base64_encode(VSTRING *result, const char *in, ssize_t len) 93 { 94 return (base64_encode_opt(result, in, len, BASE64_FLAG_NONE)); 95 } 96 97 VSTRING *base64_encode_opt(VSTRING *result, const char *in, ssize_t len, 98 int flags) 99 { 100 const unsigned char *cp; 101 ssize_t count; 102 103 /* 104 * Encode 3 -> 4. 105 */ 106 if ((flags & BASE64_FLAG_APPEND) == 0) 107 VSTRING_RESET(result); 108 for (cp = UNSIG_CHAR_PTR(in), count = len; count > 0; count -= 3, cp += 3) { 109 VSTRING_ADDCH(result, to_b64[cp[0] >> 2]); 110 if (count > 1) { 111 VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4 | cp[1] >> 4]); 112 if (count > 2) { 113 VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2 | cp[2] >> 6]); 114 VSTRING_ADDCH(result, to_b64[cp[2] & 0x3f]); 115 } else { 116 VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2]); 117 VSTRING_ADDCH(result, '='); 118 break; 119 } 120 } else { 121 VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4]); 122 VSTRING_ADDCH(result, '='); 123 VSTRING_ADDCH(result, '='); 124 break; 125 } 126 } 127 VSTRING_TERMINATE(result); 128 return (result); 129 } 130 131 /* base64_decode - encoded data to raw */ 132 133 #undef base64_decode 134 135 extern VSTRING *base64_decode(VSTRING *, const char *, ssize_t); 136 137 VSTRING *base64_decode(VSTRING *result, const char *in, ssize_t len) 138 { 139 return (base64_decode_opt(result, in, len, BASE64_FLAG_NONE)); 140 } 141 142 VSTRING *base64_decode_opt(VSTRING *result, const char *in, ssize_t len, 143 int flags) 144 { 145 static unsigned char *un_b64 = 0; 146 const unsigned char *cp; 147 ssize_t count; 148 unsigned int ch0; 149 unsigned int ch1; 150 unsigned int ch2; 151 unsigned int ch3; 152 153 #define CHARS_PER_BYTE (UCHAR_MAX + 1) 154 #define INVALID 0xff 155 156 /* 157 * Sanity check. 158 */ 159 if (len % 4) 160 return (0); 161 162 /* 163 * Once: initialize the decoding lookup table on the fly. 164 */ 165 if (un_b64 == 0) { 166 un_b64 = (unsigned char *) mymalloc(CHARS_PER_BYTE); 167 memset(un_b64, INVALID, CHARS_PER_BYTE); 168 for (cp = to_b64; cp < to_b64 + sizeof(to_b64); cp++) 169 un_b64[*cp] = cp - to_b64; 170 } 171 172 /* 173 * Decode 4 -> 3. 174 */ 175 if ((flags & BASE64_FLAG_APPEND) == 0) 176 VSTRING_RESET(result); 177 for (cp = UNSIG_CHAR_PTR(in), count = 0; count < len; count += 4) { 178 if ((ch0 = un_b64[*cp++]) == INVALID 179 || (ch1 = un_b64[*cp++]) == INVALID) 180 return (0); 181 VSTRING_ADDCH(result, ch0 << 2 | ch1 >> 4); 182 if ((ch2 = *cp++) == '=') 183 break; 184 if ((ch2 = un_b64[ch2]) == INVALID) 185 return (0); 186 VSTRING_ADDCH(result, ch1 << 4 | ch2 >> 2); 187 if ((ch3 = *cp++) == '=') 188 break; 189 if ((ch3 = un_b64[ch3]) == INVALID) 190 return (0); 191 VSTRING_ADDCH(result, ch2 << 6 | ch3); 192 } 193 VSTRING_TERMINATE(result); 194 return (result); 195 } 196 197 #ifdef TEST 198 199 /* 200 * Proof-of-concept test program: convert to base 64 and back. 201 */ 202 203 #define STR(x) vstring_str(x) 204 #define LEN(x) VSTRING_LEN(x) 205 206 #define TESXT "this is a test!" 207 208 int main(int unused_argc, char **unused_argv) 209 { 210 VSTRING *b1 = vstring_alloc(1); 211 VSTRING *b2 = vstring_alloc(1); 212 char *test = TESXT; 213 char *test2 = TESXT TESXT; 214 215 #define DECODE(b,x,l) { \ 216 if (base64_decode((b),(x),(l)) == 0) \ 217 msg_panic("bad base64: %s", (x)); \ 218 } 219 #define VERIFY(b,t) { \ 220 if (strcmp((b), (t)) != 0) \ 221 msg_panic("bad test: %s", (b)); \ 222 } 223 224 base64_encode(b1, test, strlen(test)); 225 DECODE(b2, STR(b1), LEN(b1)); 226 VERIFY(STR(b2), test); 227 228 base64_encode(b1, test, strlen(test)); 229 base64_encode(b2, STR(b1), LEN(b1)); 230 base64_encode(b1, STR(b2), LEN(b2)); 231 DECODE(b2, STR(b1), LEN(b1)); 232 DECODE(b1, STR(b2), LEN(b2)); 233 DECODE(b2, STR(b1), LEN(b1)); 234 VERIFY(STR(b2), test); 235 236 base64_encode(b1, test, strlen(test)); 237 base64_encode(b2, STR(b1), LEN(b1)); 238 base64_encode(b1, STR(b2), LEN(b2)); 239 base64_encode(b2, STR(b1), LEN(b1)); 240 base64_encode(b1, STR(b2), LEN(b2)); 241 DECODE(b2, STR(b1), LEN(b1)); 242 DECODE(b1, STR(b2), LEN(b2)); 243 DECODE(b2, STR(b1), LEN(b1)); 244 DECODE(b1, STR(b2), LEN(b2)); 245 DECODE(b2, STR(b1), LEN(b1)); 246 VERIFY(STR(b2), test); 247 248 base64_encode(b1, test, strlen(test)); 249 base64_encode_opt(b1, test, strlen(test), BASE64_FLAG_APPEND); 250 DECODE(b2, STR(b1), LEN(b1)); 251 VERIFY(STR(b2), test2); 252 253 vstring_free(b1); 254 vstring_free(b2); 255 return (0); 256 } 257 258 #endif 259