Return to base32.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc |
1.1 ! misho 1: /* ! 2: * Copyright (C) 2008, 2009 Internet Systems Consortium, Inc. ("ISC") ! 3: * ! 4: * Permission to use, copy, modify, and/or distribute this software for any ! 5: * purpose with or without fee is hereby granted, provided that the above ! 6: * copyright notice and this permission notice appear in all copies. ! 7: * ! 8: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ! 9: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ! 10: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ! 11: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ! 12: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ! 13: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ! 14: * PERFORMANCE OF THIS SOFTWARE. ! 15: */ ! 16: ! 17: /* $Id: base32.c,v 1.3.116.2 2009/01/18 23:47:41 tbox Exp $ */ ! 18: ! 19: /*! \file */ ! 20: ! 21: #include <config.h> ! 22: ! 23: #include <isc/base32.h> ! 24: #include <isc/buffer.h> ! 25: #include <isc/lex.h> ! 26: #include <isc/region.h> ! 27: #include <isc/string.h> ! 28: #include <isc/util.h> ! 29: ! 30: #define RETERR(x) do { \ ! 31: isc_result_t _r = (x); \ ! 32: if (_r != ISC_R_SUCCESS) \ ! 33: return (_r); \ ! 34: } while (0) ! 35: ! 36: ! 37: /*@{*/ ! 38: /*! ! 39: * These static functions are also present in lib/dns/rdata.c. I'm not ! 40: * sure where they should go. -- bwelling ! 41: */ ! 42: static isc_result_t ! 43: str_totext(const char *source, isc_buffer_t *target); ! 44: ! 45: static isc_result_t ! 46: mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); ! 47: ! 48: /*@}*/ ! 49: ! 50: static const char base32[] = ! 51: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=abcdefghijklmnopqrstuvwxyz234567"; ! 52: static const char base32hex[] = ! 53: "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv"; ! 54: ! 55: static isc_result_t ! 56: base32_totext(isc_region_t *source, int wordlength, const char *wordbreak, ! 57: isc_buffer_t *target, const char base[]) ! 58: { ! 59: char buf[9]; ! 60: unsigned int loops = 0; ! 61: ! 62: if (wordlength >= 0 && wordlength < 8) ! 63: wordlength = 8; ! 64: ! 65: memset(buf, 0, sizeof(buf)); ! 66: while (source->length > 0) { ! 67: buf[0] = base[((source->base[0]>>3)&0x1f)]; /* 5 + */ ! 68: if (source->length == 1) { ! 69: buf[1] = base[(source->base[0]<<2)&0x1c]; ! 70: buf[2] = buf[3] = buf[4] = '='; ! 71: buf[5] = buf[6] = buf[7] = '='; ! 72: RETERR(str_totext(buf, target)); ! 73: break; ! 74: } ! 75: buf[1] = base[((source->base[0]<<2)&0x1c)| /* 3 = 8 */ ! 76: ((source->base[1]>>6)&0x03)]; /* 2 + */ ! 77: buf[2] = base[((source->base[1]>>1)&0x1f)]; /* 5 + */ ! 78: if (source->length == 2) { ! 79: buf[3] = base[(source->base[1]<<4)&0x10]; ! 80: buf[4] = buf[5] = buf[6] = buf[7] = '='; ! 81: RETERR(str_totext(buf, target)); ! 82: break; ! 83: } ! 84: buf[3] = base[((source->base[1]<<4)&0x10)| /* 1 = 8 */ ! 85: ((source->base[2]>>4)&0x0f)]; /* 4 + */ ! 86: if (source->length == 3) { ! 87: buf[4] = base[(source->base[2]<<1)&0x1e]; ! 88: buf[5] = buf[6] = buf[7] = '='; ! 89: RETERR(str_totext(buf, target)); ! 90: break; ! 91: } ! 92: buf[4] = base[((source->base[2]<<1)&0x1e)| /* 4 = 8 */ ! 93: ((source->base[3]>>7)&0x01)]; /* 1 + */ ! 94: buf[5] = base[((source->base[3]>>2)&0x1f)]; /* 5 + */ ! 95: if (source->length == 4) { ! 96: buf[6] = base[(source->base[3]<<3)&0x18]; ! 97: buf[7] = '='; ! 98: RETERR(str_totext(buf, target)); ! 99: break; ! 100: } ! 101: buf[6] = base[((source->base[3]<<3)&0x18)| /* 2 = 8 */ ! 102: ((source->base[4]>>5)&0x07)]; /* 3 + */ ! 103: buf[7] = base[source->base[4]&0x1f]; /* 5 = 8 */ ! 104: RETERR(str_totext(buf, target)); ! 105: isc_region_consume(source, 5); ! 106: ! 107: loops++; ! 108: if (source->length != 0 && wordlength >= 0 && ! 109: (int)((loops + 1) * 8) >= wordlength) ! 110: { ! 111: loops = 0; ! 112: RETERR(str_totext(wordbreak, target)); ! 113: } ! 114: } ! 115: return (ISC_R_SUCCESS); ! 116: } ! 117: ! 118: isc_result_t ! 119: isc_base32_totext(isc_region_t *source, int wordlength, ! 120: const char *wordbreak, isc_buffer_t *target) ! 121: { ! 122: return (base32_totext(source, wordlength, wordbreak, target, base32)); ! 123: } ! 124: ! 125: isc_result_t ! 126: isc_base32hex_totext(isc_region_t *source, int wordlength, ! 127: const char *wordbreak, isc_buffer_t *target) ! 128: { ! 129: return (base32_totext(source, wordlength, wordbreak, target, ! 130: base32hex)); ! 131: } ! 132: ! 133: /*% ! 134: * State of a base32 decoding process in progress. ! 135: */ ! 136: typedef struct { ! 137: int length; /*%< Desired length of binary data or -1 */ ! 138: isc_buffer_t *target; /*%< Buffer for resulting binary data */ ! 139: int digits; /*%< Number of buffered base32 digits */ ! 140: isc_boolean_t seen_end; /*%< True if "=" end marker seen */ ! 141: int val[8]; ! 142: const char *base; /*%< Which encoding we are using */ ! 143: int seen_32; /*%< Number of significant bytes if non zero */ ! 144: } base32_decode_ctx_t; ! 145: ! 146: static inline void ! 147: base32_decode_init(base32_decode_ctx_t *ctx, int length, ! 148: const char base[], isc_buffer_t *target) ! 149: { ! 150: ctx->digits = 0; ! 151: ctx->seen_end = ISC_FALSE; ! 152: ctx->seen_32 = 0; ! 153: ctx->length = length; ! 154: ctx->target = target; ! 155: ctx->base = base; ! 156: } ! 157: ! 158: static inline isc_result_t ! 159: base32_decode_char(base32_decode_ctx_t *ctx, int c) { ! 160: char *s; ! 161: unsigned int last; ! 162: ! 163: if (ctx->seen_end) ! 164: return (ISC_R_BADBASE32); ! 165: if ((s = strchr(ctx->base, c)) == NULL) ! 166: return (ISC_R_BADBASE32); ! 167: last = s - ctx->base; ! 168: /* ! 169: * Handle lower case. ! 170: */ ! 171: if (last > 32) ! 172: last -= 33; ! 173: /* ! 174: * Check that padding is contiguous. ! 175: */ ! 176: if (last != 32 && ctx->seen_32 != 0) ! 177: return (ISC_R_BADBASE32); ! 178: /* ! 179: * Check that padding starts at the right place and that ! 180: * bits that should be zero are. ! 181: * Record how many significant bytes in answer (seen_32). ! 182: */ ! 183: if (last == 32 && ctx->seen_32 == 0) ! 184: switch (ctx->digits) { ! 185: case 0: ! 186: case 1: ! 187: return (ISC_R_BADBASE32); ! 188: case 2: ! 189: if ((ctx->val[1]&0x03) != 0) ! 190: return (ISC_R_BADBASE32); ! 191: ctx->seen_32 = 1; ! 192: break; ! 193: case 3: ! 194: return (ISC_R_BADBASE32); ! 195: case 4: ! 196: if ((ctx->val[3]&0x0f) != 0) ! 197: return (ISC_R_BADBASE32); ! 198: ctx->seen_32 = 3; ! 199: break; ! 200: case 5: ! 201: if ((ctx->val[4]&0x01) != 0) ! 202: return (ISC_R_BADBASE32); ! 203: ctx->seen_32 = 3; ! 204: break; ! 205: case 6: ! 206: return (ISC_R_BADBASE32); ! 207: case 7: ! 208: if ((ctx->val[6]&0x07) != 0) ! 209: return (ISC_R_BADBASE32); ! 210: ctx->seen_32 = 4; ! 211: break; ! 212: } ! 213: /* ! 214: * Zero fill pad values. ! 215: */ ! 216: ctx->val[ctx->digits++] = (last == 32) ? 0 : last; ! 217: ! 218: if (ctx->digits == 8) { ! 219: int n = 5; ! 220: unsigned char buf[5]; ! 221: ! 222: if (ctx->seen_32 != 0) { ! 223: ctx->seen_end = ISC_TRUE; ! 224: n = ctx->seen_32; ! 225: } ! 226: buf[0] = (ctx->val[0]<<3)|(ctx->val[1]>>2); ! 227: buf[1] = (ctx->val[1]<<6)|(ctx->val[2]<<1)|(ctx->val[3]>>4); ! 228: buf[2] = (ctx->val[3]<<4)|(ctx->val[4]>>1); ! 229: buf[3] = (ctx->val[4]<<7)|(ctx->val[5]<<2)|(ctx->val[6]>>3); ! 230: buf[4] = (ctx->val[6]<<5)|(ctx->val[7]); ! 231: RETERR(mem_tobuffer(ctx->target, buf, n)); ! 232: if (ctx->length >= 0) { ! 233: if (n > ctx->length) ! 234: return (ISC_R_BADBASE32); ! 235: else ! 236: ctx->length -= n; ! 237: } ! 238: ctx->digits = 0; ! 239: } ! 240: return (ISC_R_SUCCESS); ! 241: } ! 242: ! 243: static inline isc_result_t ! 244: base32_decode_finish(base32_decode_ctx_t *ctx) { ! 245: if (ctx->length > 0) ! 246: return (ISC_R_UNEXPECTEDEND); ! 247: if (ctx->digits != 0) ! 248: return (ISC_R_BADBASE32); ! 249: return (ISC_R_SUCCESS); ! 250: } ! 251: ! 252: static isc_result_t ! 253: base32_tobuffer(isc_lex_t *lexer, const char base[], isc_buffer_t *target, ! 254: int length) ! 255: { ! 256: base32_decode_ctx_t ctx; ! 257: isc_textregion_t *tr; ! 258: isc_token_t token; ! 259: isc_boolean_t eol; ! 260: ! 261: base32_decode_init(&ctx, length, base, target); ! 262: ! 263: while (!ctx.seen_end && (ctx.length != 0)) { ! 264: unsigned int i; ! 265: ! 266: if (length > 0) ! 267: eol = ISC_FALSE; ! 268: else ! 269: eol = ISC_TRUE; ! 270: RETERR(isc_lex_getmastertoken(lexer, &token, ! 271: isc_tokentype_string, eol)); ! 272: if (token.type != isc_tokentype_string) ! 273: break; ! 274: tr = &token.value.as_textregion; ! 275: for (i = 0; i < tr->length; i++) ! 276: RETERR(base32_decode_char(&ctx, tr->base[i])); ! 277: } ! 278: if (ctx.length < 0 && !ctx.seen_end) ! 279: isc_lex_ungettoken(lexer, &token); ! 280: RETERR(base32_decode_finish(&ctx)); ! 281: return (ISC_R_SUCCESS); ! 282: } ! 283: ! 284: isc_result_t ! 285: isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { ! 286: return (base32_tobuffer(lexer, base32, target, length)); ! 287: } ! 288: ! 289: isc_result_t ! 290: isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { ! 291: return (base32_tobuffer(lexer, base32hex, target, length)); ! 292: } ! 293: ! 294: static isc_result_t ! 295: base32_decodestring(const char *cstr, const char base[], isc_buffer_t *target) { ! 296: base32_decode_ctx_t ctx; ! 297: ! 298: base32_decode_init(&ctx, -1, base, target); ! 299: for (;;) { ! 300: int c = *cstr++; ! 301: if (c == '\0') ! 302: break; ! 303: if (c == ' ' || c == '\t' || c == '\n' || c== '\r') ! 304: continue; ! 305: RETERR(base32_decode_char(&ctx, c)); ! 306: } ! 307: RETERR(base32_decode_finish(&ctx)); ! 308: return (ISC_R_SUCCESS); ! 309: } ! 310: ! 311: isc_result_t ! 312: isc_base32_decodestring(const char *cstr, isc_buffer_t *target) { ! 313: return (base32_decodestring(cstr, base32, target)); ! 314: } ! 315: ! 316: isc_result_t ! 317: isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) { ! 318: return (base32_decodestring(cstr, base32hex, target)); ! 319: } ! 320: ! 321: static isc_result_t ! 322: base32_decoderegion(isc_region_t *source, const char base[], isc_buffer_t *target) { ! 323: base32_decode_ctx_t ctx; ! 324: ! 325: base32_decode_init(&ctx, -1, base, target); ! 326: while (source->length != 0) { ! 327: int c = *source->base; ! 328: RETERR(base32_decode_char(&ctx, c)); ! 329: isc_region_consume(source, 1); ! 330: } ! 331: RETERR(base32_decode_finish(&ctx)); ! 332: return (ISC_R_SUCCESS); ! 333: } ! 334: ! 335: isc_result_t ! 336: isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) { ! 337: return (base32_decoderegion(source, base32, target)); ! 338: } ! 339: ! 340: isc_result_t ! 341: isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) { ! 342: return (base32_decoderegion(source, base32hex, target)); ! 343: } ! 344: ! 345: static isc_result_t ! 346: str_totext(const char *source, isc_buffer_t *target) { ! 347: unsigned int l; ! 348: isc_region_t region; ! 349: ! 350: isc_buffer_availableregion(target, ®ion); ! 351: l = strlen(source); ! 352: ! 353: if (l > region.length) ! 354: return (ISC_R_NOSPACE); ! 355: ! 356: memcpy(region.base, source, l); ! 357: isc_buffer_add(target, l); ! 358: return (ISC_R_SUCCESS); ! 359: } ! 360: ! 361: static isc_result_t ! 362: mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { ! 363: isc_region_t tr; ! 364: ! 365: isc_buffer_availableregion(target, &tr); ! 366: if (length > tr.length) ! 367: return (ISC_R_NOSPACE); ! 368: memcpy(tr.base, base, length); ! 369: isc_buffer_add(target, length); ! 370: return (ISC_R_SUCCESS); ! 371: }