1 /* $NetBSD: base64_code.c,v 1.1.1.1 2009/06/23 10:08:59 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 /* DESCRIPTION 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. 23 /* 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. 27 /* DIAGNOSTICS 28 /* base64_decode () returns a null pointer when the input contains 29 /* characters not in the base 64 alphabet. 30 /* LICENSE 31 /* .ad 32 /* .fi 33 /* The Secure Mailer license must be distributed with this software. 34 /* AUTHOR(S) 35 /* Wietse Venema 36 /* IBM T.J. Watson Research 37 /* P.O. Box 704 38 /* Yorktown Heights, NY 10598, USA 39 /*--*/ 40 41 /* System library. */ 42 43 #include "sys_defs.h" 44 #include <ctype.h> 45 #include <string.h> 46 #include <limits.h> 47 48 #ifndef UCHAR_MAX 49 #define UCHAR_MAX 0xff 50 #endif 51 52 /* Utility library. */ 53 54 #include <msg.h> 55 #include <mymalloc.h> 56 #include <vstring.h> 57 #include <base64_code.h> 58 59 /* Application-specific. */ 60 61 static unsigned char to_b64[] = 62 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 63 64 #define UNSIG_CHAR_PTR(x) ((unsigned char *)(x)) 65 66 /* base64_encode - raw data to encoded */ 67 68 VSTRING *base64_encode(VSTRING *result, const char *in, ssize_t len) 69 { 70 const unsigned char *cp; 71 ssize_t count; 72 73 /* 74 * Encode 3 -> 4. 75 */ 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]); 79 if (count > 1) { 80 VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4 | cp[1] >> 4]); 81 if (count > 2) { 82 VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2 | cp[2] >> 6]); 83 VSTRING_ADDCH(result, to_b64[cp[2] & 0x3f]); 84 } else { 85 VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2]); 86 VSTRING_ADDCH(result, '='); 87 break; 88 } 89 } else { 90 VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4]); 91 VSTRING_ADDCH(result, '='); 92 VSTRING_ADDCH(result, '='); 93 break; 94 } 95 } 96 VSTRING_TERMINATE(result); 97 return (result); 98 } 99 100 /* base64_decode - encoded data to raw */ 101 102 VSTRING *base64_decode(VSTRING *result, const char *in, ssize_t len) 103 { 104 static unsigned char *un_b64 = 0; 105 const unsigned char *cp; 106 ssize_t count; 107 unsigned int ch0; 108 unsigned int ch1; 109 unsigned int ch2; 110 unsigned int ch3; 111 112 #define CHARS_PER_BYTE (UCHAR_MAX + 1) 113 #define INVALID 0xff 114 115 /* 116 * Sanity check. 117 */ 118 if (len % 4) 119 return (0); 120 121 /* 122 * Once: initialize the decoding lookup table on the fly. 123 */ 124 if (un_b64 == 0) { 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; 129 } 130 131 /* 132 * Decode 4 -> 3. 133 */ 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) 138 return (0); 139 VSTRING_ADDCH(result, ch0 << 2 | ch1 >> 4); 140 if ((ch2 = *cp++) == '=') 141 break; 142 if ((ch2 = un_b64[ch2]) == INVALID) 143 return (0); 144 VSTRING_ADDCH(result, ch1 << 4 | ch2 >> 2); 145 if ((ch3 = *cp++) == '=') 146 break; 147 if ((ch3 = un_b64[ch3]) == INVALID) 148 return (0); 149 VSTRING_ADDCH(result, ch2 << 6 | ch3); 150 } 151 VSTRING_TERMINATE(result); 152 return (result); 153 } 154 155 #ifdef TEST 156 157 /* 158 * Proof-of-concept test program: convert to base 64 and back. 159 */ 160 161 #define STR(x) vstring_str(x) 162 #define LEN(x) VSTRING_LEN(x) 163 164 int main(int unused_argc, char **unused_argv) 165 { 166 VSTRING *b1 = vstring_alloc(1); 167 VSTRING *b2 = vstring_alloc(1); 168 char *test = "this is a test"; 169 170 #define DECODE(b,x,l) { \ 171 if (base64_decode((b),(x),(l)) == 0) \ 172 msg_panic("bad base64: %s", (x)); \ 173 } 174 #define VERIFY(b,t) { \ 175 if (strcmp((b), (t)) != 0) \ 176 msg_panic("bad test: %s", (b)); \ 177 } 178 179 base64_encode(b1, test, strlen(test)); 180 DECODE(b2, STR(b1), LEN(b1)); 181 VERIFY(STR(b2), test); 182 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); 190 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); 202 203 vstring_free(b1); 204 vstring_free(b2); 205 return (0); 206 } 207 208 #endif 209