Return to base64.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc |
1.1 ! misho 1: /* ! 2: * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") ! 3: * Copyright (C) 1998-2001, 2003 Internet Software Consortium. ! 4: * ! 5: * Permission to use, copy, modify, and/or distribute this software for any ! 6: * purpose with or without fee is hereby granted, provided that the above ! 7: * copyright notice and this permission notice appear in all copies. ! 8: * ! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ! 10: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ! 11: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ! 12: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ! 13: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ! 14: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ! 15: * PERFORMANCE OF THIS SOFTWARE. ! 16: */ ! 17: ! 18: /* $Id: base64.c,v 1.32 2007/06/19 23:47:17 tbox Exp $ */ ! 19: ! 20: /*! \file */ ! 21: ! 22: #include <config.h> ! 23: ! 24: #include <isc/base64.h> ! 25: #include <isc/buffer.h> ! 26: #include <isc/lex.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: static const char base64[] = ! 49: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; ! 50: /*@}*/ ! 51: ! 52: isc_result_t ! 53: isc_base64_totext(isc_region_t *source, int wordlength, ! 54: const char *wordbreak, isc_buffer_t *target) ! 55: { ! 56: char buf[5]; ! 57: unsigned int loops = 0; ! 58: ! 59: if (wordlength < 4) ! 60: wordlength = 4; ! 61: ! 62: memset(buf, 0, sizeof(buf)); ! 63: while (source->length > 2) { ! 64: buf[0] = base64[(source->base[0]>>2)&0x3f]; ! 65: buf[1] = base64[((source->base[0]<<4)&0x30)| ! 66: ((source->base[1]>>4)&0x0f)]; ! 67: buf[2] = base64[((source->base[1]<<2)&0x3c)| ! 68: ((source->base[2]>>6)&0x03)]; ! 69: buf[3] = base64[source->base[2]&0x3f]; ! 70: RETERR(str_totext(buf, target)); ! 71: isc_region_consume(source, 3); ! 72: ! 73: loops++; ! 74: if (source->length != 0 && ! 75: (int)((loops + 1) * 4) >= wordlength) ! 76: { ! 77: loops = 0; ! 78: RETERR(str_totext(wordbreak, target)); ! 79: } ! 80: } ! 81: if (source->length == 2) { ! 82: buf[0] = base64[(source->base[0]>>2)&0x3f]; ! 83: buf[1] = base64[((source->base[0]<<4)&0x30)| ! 84: ((source->base[1]>>4)&0x0f)]; ! 85: buf[2] = base64[((source->base[1]<<2)&0x3c)]; ! 86: buf[3] = '='; ! 87: RETERR(str_totext(buf, target)); ! 88: } else if (source->length == 1) { ! 89: buf[0] = base64[(source->base[0]>>2)&0x3f]; ! 90: buf[1] = base64[((source->base[0]<<4)&0x30)]; ! 91: buf[2] = buf[3] = '='; ! 92: RETERR(str_totext(buf, target)); ! 93: } ! 94: return (ISC_R_SUCCESS); ! 95: } ! 96: ! 97: /*% ! 98: * State of a base64 decoding process in progress. ! 99: */ ! 100: typedef struct { ! 101: int length; /*%< Desired length of binary data or -1 */ ! 102: isc_buffer_t *target; /*%< Buffer for resulting binary data */ ! 103: int digits; /*%< Number of buffered base64 digits */ ! 104: isc_boolean_t seen_end; /*%< True if "=" end marker seen */ ! 105: int val[4]; ! 106: } base64_decode_ctx_t; ! 107: ! 108: static inline void ! 109: base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target) ! 110: { ! 111: ctx->digits = 0; ! 112: ctx->seen_end = ISC_FALSE; ! 113: ctx->length = length; ! 114: ctx->target = target; ! 115: } ! 116: ! 117: static inline isc_result_t ! 118: base64_decode_char(base64_decode_ctx_t *ctx, int c) { ! 119: char *s; ! 120: ! 121: if (ctx->seen_end) ! 122: return (ISC_R_BADBASE64); ! 123: if ((s = strchr(base64, c)) == NULL) ! 124: return (ISC_R_BADBASE64); ! 125: ctx->val[ctx->digits++] = s - base64; ! 126: if (ctx->digits == 4) { ! 127: int n; ! 128: unsigned char buf[3]; ! 129: if (ctx->val[0] == 64 || ctx->val[1] == 64) ! 130: return (ISC_R_BADBASE64); ! 131: if (ctx->val[2] == 64 && ctx->val[3] != 64) ! 132: return (ISC_R_BADBASE64); ! 133: /* ! 134: * Check that bits that should be zero are. ! 135: */ ! 136: if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0) ! 137: return (ISC_R_BADBASE64); ! 138: /* ! 139: * We don't need to test for ctx->val[2] != 64 as ! 140: * the bottom two bits of 64 are zero. ! 141: */ ! 142: if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0) ! 143: return (ISC_R_BADBASE64); ! 144: n = (ctx->val[2] == 64) ? 1 : ! 145: (ctx->val[3] == 64) ? 2 : 3; ! 146: if (n != 3) { ! 147: ctx->seen_end = ISC_TRUE; ! 148: if (ctx->val[2] == 64) ! 149: ctx->val[2] = 0; ! 150: if (ctx->val[3] == 64) ! 151: ctx->val[3] = 0; ! 152: } ! 153: buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4); ! 154: buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2); ! 155: buf[2] = (ctx->val[2]<<6)|(ctx->val[3]); ! 156: RETERR(mem_tobuffer(ctx->target, buf, n)); ! 157: if (ctx->length >= 0) { ! 158: if (n > ctx->length) ! 159: return (ISC_R_BADBASE64); ! 160: else ! 161: ctx->length -= n; ! 162: } ! 163: ctx->digits = 0; ! 164: } ! 165: return (ISC_R_SUCCESS); ! 166: } ! 167: ! 168: static inline isc_result_t ! 169: base64_decode_finish(base64_decode_ctx_t *ctx) { ! 170: if (ctx->length > 0) ! 171: return (ISC_R_UNEXPECTEDEND); ! 172: if (ctx->digits != 0) ! 173: return (ISC_R_BADBASE64); ! 174: return (ISC_R_SUCCESS); ! 175: } ! 176: ! 177: isc_result_t ! 178: isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { ! 179: base64_decode_ctx_t ctx; ! 180: isc_textregion_t *tr; ! 181: isc_token_t token; ! 182: isc_boolean_t eol; ! 183: ! 184: base64_decode_init(&ctx, length, target); ! 185: ! 186: while (!ctx.seen_end && (ctx.length != 0)) { ! 187: unsigned int i; ! 188: ! 189: if (length > 0) ! 190: eol = ISC_FALSE; ! 191: else ! 192: eol = ISC_TRUE; ! 193: RETERR(isc_lex_getmastertoken(lexer, &token, ! 194: isc_tokentype_string, eol)); ! 195: if (token.type != isc_tokentype_string) ! 196: break; ! 197: tr = &token.value.as_textregion; ! 198: for (i = 0; i < tr->length; i++) ! 199: RETERR(base64_decode_char(&ctx, tr->base[i])); ! 200: } ! 201: if (ctx.length < 0 && !ctx.seen_end) ! 202: isc_lex_ungettoken(lexer, &token); ! 203: RETERR(base64_decode_finish(&ctx)); ! 204: return (ISC_R_SUCCESS); ! 205: } ! 206: ! 207: isc_result_t ! 208: isc_base64_decodestring(const char *cstr, isc_buffer_t *target) { ! 209: base64_decode_ctx_t ctx; ! 210: ! 211: base64_decode_init(&ctx, -1, target); ! 212: for (;;) { ! 213: int c = *cstr++; ! 214: if (c == '\0') ! 215: break; ! 216: if (c == ' ' || c == '\t' || c == '\n' || c== '\r') ! 217: continue; ! 218: RETERR(base64_decode_char(&ctx, c)); ! 219: } ! 220: RETERR(base64_decode_finish(&ctx)); ! 221: return (ISC_R_SUCCESS); ! 222: } ! 223: ! 224: static isc_result_t ! 225: str_totext(const char *source, isc_buffer_t *target) { ! 226: unsigned int l; ! 227: isc_region_t region; ! 228: ! 229: isc_buffer_availableregion(target, ®ion); ! 230: l = strlen(source); ! 231: ! 232: if (l > region.length) ! 233: return (ISC_R_NOSPACE); ! 234: ! 235: memcpy(region.base, source, l); ! 236: isc_buffer_add(target, l); ! 237: return (ISC_R_SUCCESS); ! 238: } ! 239: ! 240: static isc_result_t ! 241: mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { ! 242: isc_region_t tr; ! 243: ! 244: isc_buffer_availableregion(target, &tr); ! 245: if (length > tr.length) ! 246: return (ISC_R_NOSPACE); ! 247: memcpy(tr.base, base, length); ! 248: isc_buffer_add(target, length); ! 249: return (ISC_R_SUCCESS); ! 250: }