base64.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2009, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: base64.c,v 1.34 2009/10/21 23:48:05 tbox Exp $ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <isc/base64.h>
00025 #include <isc/buffer.h>
00026 #include <isc/lex.h>
00027 #include <isc/string.h>
00028 #include <isc/util.h>
00029 
00030 #define RETERR(x) do { \
00031         isc_result_t _r = (x); \
00032         if (_r != ISC_R_SUCCESS) \
00033                 return (_r); \
00034         } while (0)
00035 
00036 
00037 /*@{*/
00038 /*!
00039  * These static functions are also present in lib/dns/rdata.c.  I'm not
00040  * sure where they should go. -- bwelling
00041  */
00042 static isc_result_t
00043 str_totext(const char *source, isc_buffer_t *target);
00044 
00045 static isc_result_t
00046 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
00047 
00048 static const char base64[] =
00049         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
00050 /*@}*/
00051 
00052 isc_result_t
00053 isc_base64_totext(isc_region_t *source, int wordlength,
00054                   const char *wordbreak, isc_buffer_t *target)
00055 {
00056         char buf[5];
00057         unsigned int loops = 0;
00058 
00059         if (wordlength < 4)
00060                 wordlength = 4;
00061 
00062         memset(buf, 0, sizeof(buf));
00063         while (source->length > 2) {
00064                 buf[0] = base64[(source->base[0]>>2)&0x3f];
00065                 buf[1] = base64[((source->base[0]<<4)&0x30)|
00066                                 ((source->base[1]>>4)&0x0f)];
00067                 buf[2] = base64[((source->base[1]<<2)&0x3c)|
00068                                 ((source->base[2]>>6)&0x03)];
00069                 buf[3] = base64[source->base[2]&0x3f];
00070                 RETERR(str_totext(buf, target));
00071                 isc_region_consume(source, 3);
00072 
00073                 loops++;
00074                 if (source->length != 0 &&
00075                     (int)((loops + 1) * 4) >= wordlength)
00076                 {
00077                         loops = 0;
00078                         RETERR(str_totext(wordbreak, target));
00079                 }
00080         }
00081         if (source->length == 2) {
00082                 buf[0] = base64[(source->base[0]>>2)&0x3f];
00083                 buf[1] = base64[((source->base[0]<<4)&0x30)|
00084                                 ((source->base[1]>>4)&0x0f)];
00085                 buf[2] = base64[((source->base[1]<<2)&0x3c)];
00086                 buf[3] = '=';
00087                 RETERR(str_totext(buf, target));
00088                 isc_region_consume(source, 2);
00089         } else if (source->length == 1) {
00090                 buf[0] = base64[(source->base[0]>>2)&0x3f];
00091                 buf[1] = base64[((source->base[0]<<4)&0x30)];
00092                 buf[2] = buf[3] = '=';
00093                 RETERR(str_totext(buf, target));
00094                 isc_region_consume(source, 1);
00095         }
00096         return (ISC_R_SUCCESS);
00097 }
00098 
00099 /*%
00100  * State of a base64 decoding process in progress.
00101  */
00102 typedef struct {
00103         int length;             /*%< Desired length of binary data or -1 */
00104         isc_buffer_t *target;   /*%< Buffer for resulting binary data */
00105         int digits;             /*%< Number of buffered base64 digits */
00106         isc_boolean_t seen_end; /*%< True if "=" end marker seen */
00107         int val[4];
00108 } base64_decode_ctx_t;
00109 
00110 static inline void
00111 base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target)
00112 {
00113         ctx->digits = 0;
00114         ctx->seen_end = ISC_FALSE;
00115         ctx->length = length;
00116         ctx->target = target;
00117 }
00118 
00119 static inline isc_result_t
00120 base64_decode_char(base64_decode_ctx_t *ctx, int c) {
00121         char *s;
00122 
00123         if (ctx->seen_end)
00124                 return (ISC_R_BADBASE64);
00125         if ((s = strchr(base64, c)) == NULL)
00126                 return (ISC_R_BADBASE64);
00127         ctx->val[ctx->digits++] = (int)(s - base64);
00128         if (ctx->digits == 4) {
00129                 int n;
00130                 unsigned char buf[3];
00131                 if (ctx->val[0] == 64 || ctx->val[1] == 64)
00132                         return (ISC_R_BADBASE64);
00133                 if (ctx->val[2] == 64 && ctx->val[3] != 64)
00134                         return (ISC_R_BADBASE64);
00135                 /*
00136                  * Check that bits that should be zero are.
00137                  */
00138                 if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0)
00139                         return (ISC_R_BADBASE64);
00140                 /*
00141                  * We don't need to test for ctx->val[2] != 64 as
00142                  * the bottom two bits of 64 are zero.
00143                  */
00144                 if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0)
00145                         return (ISC_R_BADBASE64);
00146                 n = (ctx->val[2] == 64) ? 1 :
00147                         (ctx->val[3] == 64) ? 2 : 3;
00148                 if (n != 3) {
00149                         ctx->seen_end = ISC_TRUE;
00150                         if (ctx->val[2] == 64)
00151                                 ctx->val[2] = 0;
00152                         if (ctx->val[3] == 64)
00153                                 ctx->val[3] = 0;
00154                 }
00155                 buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4);
00156                 buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2);
00157                 buf[2] = (ctx->val[2]<<6)|(ctx->val[3]);
00158                 RETERR(mem_tobuffer(ctx->target, buf, n));
00159                 if (ctx->length >= 0) {
00160                         if (n > ctx->length)
00161                                 return (ISC_R_BADBASE64);
00162                         else
00163                                 ctx->length -= n;
00164                 }
00165                 ctx->digits = 0;
00166         }
00167         return (ISC_R_SUCCESS);
00168 }
00169 
00170 static inline isc_result_t
00171 base64_decode_finish(base64_decode_ctx_t *ctx) {
00172         if (ctx->length > 0)
00173                 return (ISC_R_UNEXPECTEDEND);
00174         if (ctx->digits != 0)
00175                 return (ISC_R_BADBASE64);
00176         return (ISC_R_SUCCESS);
00177 }
00178 
00179 isc_result_t
00180 isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
00181         base64_decode_ctx_t ctx;
00182         isc_textregion_t *tr;
00183         isc_token_t token;
00184         isc_boolean_t eol;
00185 
00186         base64_decode_init(&ctx, length, target);
00187 
00188         while (!ctx.seen_end && (ctx.length != 0)) {
00189                 unsigned int i;
00190 
00191                 if (length > 0)
00192                         eol = ISC_FALSE;
00193                 else
00194                         eol = ISC_TRUE;
00195                 RETERR(isc_lex_getmastertoken(lexer, &token,
00196                                               isc_tokentype_string, eol));
00197                 if (token.type != isc_tokentype_string)
00198                         break;
00199                 tr = &token.value.as_textregion;
00200                 for (i = 0; i < tr->length; i++)
00201                         RETERR(base64_decode_char(&ctx, tr->base[i]));
00202         }
00203         if (ctx.length < 0 && !ctx.seen_end)
00204                 isc_lex_ungettoken(lexer, &token);
00205         RETERR(base64_decode_finish(&ctx));
00206         return (ISC_R_SUCCESS);
00207 }
00208 
00209 isc_result_t
00210 isc_base64_decodestring(const char *cstr, isc_buffer_t *target) {
00211         base64_decode_ctx_t ctx;
00212 
00213         base64_decode_init(&ctx, -1, target);
00214         for (;;) {
00215                 int c = *cstr++;
00216                 if (c == '\0')
00217                         break;
00218                 if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
00219                         continue;
00220                 RETERR(base64_decode_char(&ctx, c));
00221         }
00222         RETERR(base64_decode_finish(&ctx));
00223         return (ISC_R_SUCCESS);
00224 }
00225 
00226 static isc_result_t
00227 str_totext(const char *source, isc_buffer_t *target) {
00228         unsigned int l;
00229         isc_region_t region;
00230 
00231         isc_buffer_availableregion(target, &region);
00232         l = strlen(source);
00233 
00234         if (l > region.length)
00235                 return (ISC_R_NOSPACE);
00236 
00237         memmove(region.base, source, l);
00238         isc_buffer_add(target, l);
00239         return (ISC_R_SUCCESS);
00240 }
00241 
00242 static isc_result_t
00243 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
00244         isc_region_t tr;
00245 
00246         isc_buffer_availableregion(target, &tr);
00247         if (length > tr.length)
00248                 return (ISC_R_NOSPACE);
00249         memmove(tr.base, base, length);
00250         isc_buffer_add(target, length);
00251         return (ISC_R_SUCCESS);
00252 }

Generated on Tue Apr 28 17:41:03 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha