1 /* $NetBSD: base32_code.c,v 1.1.1.1 2013/01/02 18:59:11 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* base32_code 3 6 /* SUMMARY 7 /* encode/decode data, base 32 style 8 /* SYNOPSIS 9 /* #include <base32_code.h> 10 /* 11 /* VSTRING *base32_encode(result, in, len) 12 /* VSTRING *result; 13 /* const char *in; 14 /* ssize_t len; 15 /* 16 /* VSTRING *base32_decode(result, in, len) 17 /* VSTRING *result; 18 /* const char *in; 19 /* ssize_t len; 20 /* DESCRIPTION 21 /* base32_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 /* base32_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 /* base32_decode() returns a null pointer when the input contains 29 /* characters not in the base 32 alphabet. 30 /* SEE ALSO 31 /* RFC 4648; padding is strictly enforced 32 /* LICENSE 33 /* .ad 34 /* .fi 35 /* The Secure Mailer license must be distributed with this software. 36 /* AUTHOR(S) 37 /* Wietse Venema 38 /* IBM T.J. Watson Research 39 /* P.O. Box 704 40 /* Yorktown Heights, NY 10598, USA 41 /*--*/ 42 43 /* System library. */ 44 45 #include "sys_defs.h" 46 #include <ctype.h> 47 #include <string.h> 48 #include <limits.h> 49 50 #ifndef UCHAR_MAX 51 #define UCHAR_MAX 0xff 52 #endif 53 54 /* Utility library. */ 55 56 #include <msg.h> 57 #include <mymalloc.h> 58 #include <vstring.h> 59 #include <base32_code.h> 60 61 /* Application-specific. */ 62 63 static unsigned char to_b32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; 64 65 #define UNSIG_CHAR_PTR(x) ((unsigned char *)(x)) 66 67 /* base32_encode - raw data to encoded */ 68 69 VSTRING *base32_encode(VSTRING *result, const char *in, ssize_t len) 70 { 71 const unsigned char *cp; 72 ssize_t count; 73 static int pad_count[] = {0, 6, 4, 3, 1}; 74 75 /* 76 * Encode 5 -> 8. 77 */ 78 VSTRING_RESET(result); 79 for (cp = UNSIG_CHAR_PTR(in), count = len; count > 0; count -= 5, cp += 5) { 80 VSTRING_ADDCH(result, to_b32[cp[0] >> 3]); 81 if (count < 2) { 82 VSTRING_ADDCH(result, to_b32[(cp[0] & 0x7) << 2]); 83 break; 84 } 85 VSTRING_ADDCH(result, to_b32[(cp[0] & 0x7) << 2 | cp[1] >> 6]); 86 VSTRING_ADDCH(result, to_b32[(cp[1] & 0x3f) >> 1]); 87 if (count < 3) { 88 VSTRING_ADDCH(result, to_b32[(cp[1] & 0x1) << 4]); 89 break; 90 } 91 VSTRING_ADDCH(result, to_b32[(cp[1] & 0x1) << 4 | cp[2] >> 4]); 92 if (count < 4) { 93 VSTRING_ADDCH(result, to_b32[(cp[2] & 0xf) << 1]); 94 break; 95 } 96 VSTRING_ADDCH(result, to_b32[(cp[2] & 0xf) << 1 | cp[3] >> 7]); 97 VSTRING_ADDCH(result, to_b32[(cp[3] & 0x7f) >> 2]); 98 if (count < 5) { 99 VSTRING_ADDCH(result, to_b32[(cp[3] & 0x3) << 3]); 100 break; 101 } 102 VSTRING_ADDCH(result, to_b32[(cp[3] & 0x3) << 3 | cp[4] >> 5]); 103 VSTRING_ADDCH(result, to_b32[cp[4] & 0x1f]); 104 } 105 if (count > 0) 106 vstring_strncat(result, "======", pad_count[count]); 107 VSTRING_TERMINATE(result); 108 return (result); 109 } 110 111 /* base32_decode - encoded data to raw */ 112 113 VSTRING *base32_decode(VSTRING *result, const char *in, ssize_t len) 114 { 115 static unsigned char *un_b32 = 0; 116 const unsigned char *cp; 117 ssize_t count; 118 unsigned int ch0; 119 unsigned int ch1; 120 unsigned int ch2; 121 unsigned int ch3; 122 unsigned int ch4; 123 unsigned int ch5; 124 unsigned int ch6; 125 unsigned int ch7; 126 127 #define CHARS_PER_BYTE (UCHAR_MAX + 1) 128 #define INVALID 0xff 129 #if 1 130 #define ENFORCE_LENGTH(x) (x) 131 #define ENFORCE_PADDING(x) (x) 132 #define ENFORCE_NULL_BITS(x) (x) 133 #else 134 #define ENFORCE_LENGTH(x) (1) 135 #define ENFORCE_PADDING(x) (1) 136 #define ENFORCE_NULL_BITS(x) (1) 137 #endif 138 139 /* 140 * Sanity check. 141 */ 142 if (ENFORCE_LENGTH(len % 8)) 143 return (0); 144 145 /* 146 * Once: initialize the decoding lookup table on the fly. 147 */ 148 if (un_b32 == 0) { 149 un_b32 = (unsigned char *) mymalloc(CHARS_PER_BYTE); 150 memset(un_b32, INVALID, CHARS_PER_BYTE); 151 for (cp = to_b32; cp < to_b32 + sizeof(to_b32); cp++) 152 un_b32[*cp] = cp - to_b32; 153 } 154 155 /* 156 * Decode 8 -> 5. 157 */ 158 VSTRING_RESET(result); 159 for (cp = UNSIG_CHAR_PTR(in), count = 0; count < len; count += 8) { 160 if ((ch0 = un_b32[*cp++]) == INVALID 161 || (ch1 = un_b32[*cp++]) == INVALID) 162 return (0); 163 VSTRING_ADDCH(result, ch0 << 3 | ch1 >> 2); 164 if ((ch2 = *cp++) == '=' 165 && ENFORCE_PADDING(strcmp((char *) cp, "=====") == 0) 166 && ENFORCE_NULL_BITS((ch1 & 0x3) == 0)) 167 break; 168 if ((ch2 = un_b32[ch2]) == INVALID) 169 return (0); 170 if ((ch3 = un_b32[*cp++]) == INVALID) 171 return (0); 172 VSTRING_ADDCH(result, ch1 << 6 | ch2 << 1 | ch3 >> 4); 173 if ((ch4 = *cp++) == '=' 174 && ENFORCE_PADDING(strcmp((char *) cp, "===") == 0) 175 && ENFORCE_NULL_BITS((ch3 & 0xf) == 0)) 176 break; 177 if ((ch4 = un_b32[ch4]) == INVALID) 178 return (0); 179 VSTRING_ADDCH(result, ch3 << 4 | ch4 >> 1); 180 if ((ch5 = *cp++) == '=' 181 && ENFORCE_PADDING(strcmp((char *) cp, "==") == 0) 182 && ENFORCE_NULL_BITS((ch4 & 0x1) == 0)) 183 break; 184 if ((ch5 = un_b32[ch5]) == INVALID) 185 return (0); 186 if ((ch6 = un_b32[*cp++]) == INVALID) 187 return (0); 188 VSTRING_ADDCH(result, ch4 << 7 | ch5 << 2 | ch6 >> 3); 189 if ((ch7 = *cp++) == '=' 190 && ENFORCE_NULL_BITS((ch6 & 0x7) == 0)) 191 break; 192 if ((ch7 = un_b32[ch7]) == INVALID) 193 return (0); 194 VSTRING_ADDCH(result, ch6 << 5 | ch7); 195 } 196 VSTRING_TERMINATE(result); 197 return (result); 198 } 199 200 #ifdef TEST 201 202 /* 203 * Proof-of-concept test program: convert to base 32 and back. 204 */ 205 206 #define STR(x) vstring_str(x) 207 #define LEN(x) VSTRING_LEN(x) 208 209 int main(int unused_argc, char **unused_argv) 210 { 211 VSTRING *b1 = vstring_alloc(1); 212 VSTRING *b2 = vstring_alloc(1); 213 VSTRING *test = vstring_alloc(1); 214 int i, j; 215 216 /* 217 * Test all byte values (except null) on all byte positions. 218 */ 219 for (j = 0; j < 256; j++) 220 for (i = 1; i < 256; i++) 221 VSTRING_ADDCH(test, i); 222 VSTRING_TERMINATE(test); 223 224 #define DECODE(b,x,l) { \ 225 if (base32_decode((b),(x),(l)) == 0) \ 226 msg_panic("bad base32: %s", (x)); \ 227 } 228 #define VERIFY(b,t,l) { \ 229 if (memcmp((b), (t), (l)) != 0) \ 230 msg_panic("bad test: %s", (b)); \ 231 } 232 233 /* 234 * Test all padding variants. 235 */ 236 for (i = 1; i <= 8; i++) { 237 base32_encode(b1, STR(test), LEN(test)); 238 DECODE(b2, STR(b1), LEN(b1)); 239 VERIFY(STR(b2), STR(test), LEN(test)); 240 241 base32_encode(b1, STR(test), LEN(test)); 242 base32_encode(b2, STR(b1), LEN(b1)); 243 base32_encode(b1, STR(b2), LEN(b2)); 244 DECODE(b2, STR(b1), LEN(b1)); 245 DECODE(b1, STR(b2), LEN(b2)); 246 DECODE(b2, STR(b1), LEN(b1)); 247 VERIFY(STR(b2), STR(test), LEN(test)); 248 249 base32_encode(b1, STR(test), LEN(test)); 250 base32_encode(b2, STR(b1), LEN(b1)); 251 base32_encode(b1, STR(b2), LEN(b2)); 252 base32_encode(b2, STR(b1), LEN(b1)); 253 base32_encode(b1, STR(b2), LEN(b2)); 254 DECODE(b2, STR(b1), LEN(b1)); 255 DECODE(b1, STR(b2), LEN(b2)); 256 DECODE(b2, STR(b1), LEN(b1)); 257 DECODE(b1, STR(b2), LEN(b2)); 258 DECODE(b2, STR(b1), LEN(b1)); 259 VERIFY(STR(b2), STR(test), LEN(test)); 260 vstring_truncate(test, LEN(test) - 1); 261 } 262 vstring_free(test); 263 vstring_free(b1); 264 vstring_free(b2); 265 return (0); 266 } 267 268 #endif 269