base32.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008, 2009, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  *
00004  * Permission to use, copy, modify, and/or distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00009  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00010  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00011  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00012  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00013  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00014  * PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 /* $Id: base32.c,v 1.6.698.1 2012/02/15 05:00:16 marka Exp $ */
00018 
00019 /*! \file */
00020 
00021 #include <config.h>
00022 
00023 #include <isc/base32.h>
00024 #include <isc/buffer.h>
00025 #include <isc/lex.h>
00026 #include <isc/region.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 /*@}*/
00049 
00050 static const char base32[] =
00051          "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=abcdefghijklmnopqrstuvwxyz234567";
00052 static const char base32hex[] =
00053         "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
00054 
00055 static isc_result_t
00056 base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
00057               isc_buffer_t *target, const char base[], char pad)
00058 {
00059         char buf[9];
00060         unsigned int loops = 0;
00061 
00062         if (wordlength >= 0 && wordlength < 8)
00063                 wordlength = 8;
00064 
00065         memset(buf, 0, sizeof(buf));
00066         while (source->length > 0) {
00067                 buf[0] = base[((source->base[0]>>3)&0x1f)];     /* 5 + */
00068                 if (source->length == 1) {
00069                         buf[1] = base[(source->base[0]<<2)&0x1c];
00070                         buf[2] = buf[3] = buf[4] = pad;
00071                         buf[5] = buf[6] = buf[7] = pad;
00072                         RETERR(str_totext(buf, target));
00073                         break;
00074                 }
00075                 buf[1] = base[((source->base[0]<<2)&0x1c)|      /* 3 = 8 */
00076                               ((source->base[1]>>6)&0x03)];     /* 2 + */
00077                 buf[2] = base[((source->base[1]>>1)&0x1f)];     /* 5 + */
00078                 if (source->length == 2) {
00079                         buf[3] = base[(source->base[1]<<4)&0x10];
00080                         buf[4] = buf[5] = buf[6] = buf[7] = pad;
00081                         RETERR(str_totext(buf, target));
00082                         break;
00083                 }
00084                 buf[3] = base[((source->base[1]<<4)&0x10)|      /* 1 = 8 */
00085                               ((source->base[2]>>4)&0x0f)];     /* 4 + */
00086                 if (source->length == 3) {
00087                         buf[4] = base[(source->base[2]<<1)&0x1e];
00088                         buf[5] = buf[6] = buf[7] = pad;
00089                         RETERR(str_totext(buf, target));
00090                         break;
00091                 }
00092                 buf[4] = base[((source->base[2]<<1)&0x1e)|      /* 4 = 8 */
00093                               ((source->base[3]>>7)&0x01)];     /* 1 + */
00094                 buf[5] = base[((source->base[3]>>2)&0x1f)];     /* 5 + */
00095                 if (source->length == 4) {
00096                         buf[6] = base[(source->base[3]<<3)&0x18];
00097                         buf[7] = pad;
00098                         RETERR(str_totext(buf, target));
00099                         break;
00100                 }
00101                 buf[6] = base[((source->base[3]<<3)&0x18)|      /* 2 = 8 */
00102                               ((source->base[4]>>5)&0x07)];     /* 3 + */
00103                 buf[7] = base[source->base[4]&0x1f];            /* 5 = 8 */
00104                 RETERR(str_totext(buf, target));
00105                 isc_region_consume(source, 5);
00106 
00107                 loops++;
00108                 if (source->length != 0 && wordlength >= 0 &&
00109                     (int)((loops + 1) * 8) >= wordlength)
00110                 {
00111                         loops = 0;
00112                         RETERR(str_totext(wordbreak, target));
00113                 }
00114         }
00115         if (source->length > 0)
00116                 isc_region_consume(source, source->length);
00117         return (ISC_R_SUCCESS);
00118 }
00119 
00120 isc_result_t
00121 isc_base32_totext(isc_region_t *source, int wordlength,
00122                   const char *wordbreak, isc_buffer_t *target)
00123 {
00124         return (base32_totext(source, wordlength, wordbreak, target,
00125                               base32, '='));
00126 }
00127 
00128 isc_result_t
00129 isc_base32hex_totext(isc_region_t *source, int wordlength,
00130                      const char *wordbreak, isc_buffer_t *target)
00131 {
00132         return (base32_totext(source, wordlength, wordbreak, target,
00133                               base32hex, '='));
00134 }
00135 
00136 isc_result_t
00137 isc_base32hexnp_totext(isc_region_t *source, int wordlength,
00138                      const char *wordbreak, isc_buffer_t *target)
00139 {
00140         return (base32_totext(source, wordlength, wordbreak, target,
00141                               base32hex, 0));
00142 }
00143 
00144 /*%
00145  * State of a base32 decoding process in progress.
00146  */
00147 typedef struct {
00148         int length;             /*%< Desired length of binary data or -1 */
00149         isc_buffer_t *target;   /*%< Buffer for resulting binary data */
00150         int digits;             /*%< Number of buffered base32 digits */
00151         isc_boolean_t seen_end; /*%< True if "=" end marker seen */
00152         int val[8];
00153         const char *base;       /*%< Which encoding we are using */
00154         int seen_32;            /*%< Number of significant bytes if non zero */
00155         isc_boolean_t pad;      /*%< Expect padding */
00156 } base32_decode_ctx_t;
00157 
00158 static inline void
00159 base32_decode_init(base32_decode_ctx_t *ctx, int length, const char base[],
00160                    isc_boolean_t pad, isc_buffer_t *target)
00161 {
00162         ctx->digits = 0;
00163         ctx->seen_end = ISC_FALSE;
00164         ctx->seen_32 = 0;
00165         ctx->length = length;
00166         ctx->target = target;
00167         ctx->base = base;
00168         ctx->pad = pad;
00169 }
00170 
00171 static inline isc_result_t
00172 base32_decode_char(base32_decode_ctx_t *ctx, int c) {
00173         char *s;
00174         unsigned int last;
00175 
00176         if (ctx->seen_end)
00177                 return (ISC_R_BADBASE32);
00178         if ((s = strchr(ctx->base, c)) == NULL)
00179                 return (ISC_R_BADBASE32);
00180         last = (unsigned int)(s - ctx->base);
00181 
00182         /*
00183          * Handle lower case.
00184          */
00185         if (last > 32)
00186                 last -= 33;
00187 
00188         /*
00189          * Check that padding is contiguous.
00190          */
00191         if (last != 32 && ctx->seen_32 != 0)
00192                 return (ISC_R_BADBASE32);
00193 
00194         /*
00195          * If padding is not permitted flag padding as a error.
00196          */
00197         if (last == 32 && !ctx->pad)
00198                 return (ISC_R_BADBASE32);
00199 
00200         /*
00201          * Check that padding starts at the right place and that
00202          * bits that should be zero are.
00203          * Record how many significant bytes in answer (seen_32).
00204          */
00205         if (last == 32 && ctx->seen_32 == 0)
00206                 switch (ctx->digits) {
00207                 case 0:
00208                 case 1:
00209                         return (ISC_R_BADBASE32);
00210                 case 2:
00211                         if ((ctx->val[1]&0x03) != 0)
00212                                 return (ISC_R_BADBASE32);
00213                         ctx->seen_32 = 1;
00214                         break;
00215                 case 3:
00216                         return (ISC_R_BADBASE32);
00217                 case 4:
00218                         if ((ctx->val[3]&0x0f) != 0)
00219                                 return (ISC_R_BADBASE32);
00220                         ctx->seen_32 = 3;
00221                         break;
00222                 case 5:
00223                         if ((ctx->val[4]&0x01) != 0)
00224                                 return (ISC_R_BADBASE32);
00225                         ctx->seen_32 = 3;
00226                         break;
00227                 case 6:
00228                         return (ISC_R_BADBASE32);
00229                 case 7:
00230                         if ((ctx->val[6]&0x07) != 0)
00231                                 return (ISC_R_BADBASE32);
00232                         ctx->seen_32 = 4;
00233                         break;
00234                 }
00235 
00236         /*
00237          * Zero fill pad values.
00238          */
00239         ctx->val[ctx->digits++] = (last == 32) ? 0 : last;
00240 
00241         if (ctx->digits == 8) {
00242                 int n = 5;
00243                 unsigned char buf[5];
00244 
00245                 if (ctx->seen_32 != 0) {
00246                         ctx->seen_end = ISC_TRUE;
00247                         n = ctx->seen_32;
00248                 }
00249                 buf[0] = (ctx->val[0]<<3)|(ctx->val[1]>>2);
00250                 buf[1] = (ctx->val[1]<<6)|(ctx->val[2]<<1)|(ctx->val[3]>>4);
00251                 buf[2] = (ctx->val[3]<<4)|(ctx->val[4]>>1);
00252                 buf[3] = (ctx->val[4]<<7)|(ctx->val[5]<<2)|(ctx->val[6]>>3);
00253                 buf[4] = (ctx->val[6]<<5)|(ctx->val[7]);
00254                 RETERR(mem_tobuffer(ctx->target, buf, n));
00255                 if (ctx->length >= 0) {
00256                         if (n > ctx->length)
00257                                 return (ISC_R_BADBASE32);
00258                         else
00259                                 ctx->length -= n;
00260                 }
00261                 ctx->digits = 0;
00262         }
00263         return (ISC_R_SUCCESS);
00264 }
00265 
00266 static inline isc_result_t
00267 base32_decode_finish(base32_decode_ctx_t *ctx) {
00268 
00269         if (ctx->length > 0)
00270                 return (ISC_R_UNEXPECTEDEND);
00271         /*
00272          * Add missing padding if required.
00273          */
00274         if (!ctx->pad && ctx->digits != 0) {
00275                 ctx->pad = ISC_TRUE;
00276                 do {
00277                         RETERR(base32_decode_char(ctx, '='));
00278                 } while (ctx->digits != 0);
00279         }
00280         if (ctx->digits != 0)
00281                 return (ISC_R_BADBASE32);
00282         return (ISC_R_SUCCESS);
00283 }
00284 
00285 static isc_result_t
00286 base32_tobuffer(isc_lex_t *lexer, const char base[], isc_boolean_t pad,
00287                 isc_buffer_t *target, int length)
00288 {
00289         base32_decode_ctx_t ctx;
00290         isc_textregion_t *tr;
00291         isc_token_t token;
00292         isc_boolean_t eol;
00293 
00294         base32_decode_init(&ctx, length, base, pad, target);
00295 
00296         while (!ctx.seen_end && (ctx.length != 0)) {
00297                 unsigned int i;
00298 
00299                 if (length > 0)
00300                         eol = ISC_FALSE;
00301                 else
00302                         eol = ISC_TRUE;
00303                 RETERR(isc_lex_getmastertoken(lexer, &token,
00304                                               isc_tokentype_string, eol));
00305                 if (token.type != isc_tokentype_string)
00306                         break;
00307                 tr = &token.value.as_textregion;
00308                 for (i = 0; i < tr->length; i++)
00309                         RETERR(base32_decode_char(&ctx, tr->base[i]));
00310         }
00311         if (ctx.length < 0 && !ctx.seen_end)
00312                 isc_lex_ungettoken(lexer, &token);
00313         RETERR(base32_decode_finish(&ctx));
00314         return (ISC_R_SUCCESS);
00315 }
00316 
00317 isc_result_t
00318 isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
00319         return (base32_tobuffer(lexer, base32, ISC_TRUE, target, length));
00320 }
00321 
00322 isc_result_t
00323 isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
00324         return (base32_tobuffer(lexer, base32hex, ISC_TRUE, target, length));
00325 }
00326 
00327 isc_result_t
00328 isc_base32hexnp_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
00329         return (base32_tobuffer(lexer, base32hex, ISC_FALSE, target, length));
00330 }
00331 
00332 static isc_result_t
00333 base32_decodestring(const char *cstr, const char base[], isc_boolean_t pad,
00334                     isc_buffer_t *target)
00335 {
00336         base32_decode_ctx_t ctx;
00337 
00338         base32_decode_init(&ctx, -1, base, pad, target);
00339         for (;;) {
00340                 int c = *cstr++;
00341                 if (c == '\0')
00342                         break;
00343                 if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
00344                         continue;
00345                 RETERR(base32_decode_char(&ctx, c));
00346         }
00347         RETERR(base32_decode_finish(&ctx));
00348         return (ISC_R_SUCCESS);
00349 }
00350 
00351 isc_result_t
00352 isc_base32_decodestring(const char *cstr, isc_buffer_t *target) {
00353         return (base32_decodestring(cstr, base32, ISC_TRUE, target));
00354 }
00355 
00356 isc_result_t
00357 isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) {
00358         return (base32_decodestring(cstr, base32hex, ISC_TRUE, target));
00359 }
00360 
00361 isc_result_t
00362 isc_base32hexnp_decodestring(const char *cstr, isc_buffer_t *target) {
00363         return (base32_decodestring(cstr, base32hex, ISC_FALSE, target));
00364 }
00365 
00366 static isc_result_t
00367 base32_decoderegion(isc_region_t *source, const char base[],
00368                     isc_boolean_t pad, isc_buffer_t *target)
00369 {
00370         base32_decode_ctx_t ctx;
00371 
00372         base32_decode_init(&ctx, -1, base, pad, target);
00373         while (source->length != 0) {
00374                 int c = *source->base;
00375                 RETERR(base32_decode_char(&ctx, c));
00376                 isc_region_consume(source, 1);
00377         }
00378         RETERR(base32_decode_finish(&ctx));
00379         return (ISC_R_SUCCESS);
00380 }
00381 
00382 isc_result_t
00383 isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) {
00384         return (base32_decoderegion(source, base32, ISC_TRUE, target));
00385 }
00386 
00387 isc_result_t
00388 isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) {
00389         return (base32_decoderegion(source, base32hex, ISC_TRUE, target));
00390 }
00391 
00392 isc_result_t
00393 isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target) {
00394         return (base32_decoderegion(source, base32hex, ISC_FALSE, target));
00395 }
00396 
00397 static isc_result_t
00398 str_totext(const char *source, isc_buffer_t *target) {
00399         unsigned int l;
00400         isc_region_t region;
00401 
00402         isc_buffer_availableregion(target, &region);
00403         l = strlen(source);
00404 
00405         if (l > region.length)
00406                 return (ISC_R_NOSPACE);
00407 
00408         memmove(region.base, source, l);
00409         isc_buffer_add(target, l);
00410         return (ISC_R_SUCCESS);
00411 }
00412 
00413 static isc_result_t
00414 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
00415         isc_region_t tr;
00416 
00417         isc_buffer_availableregion(target, &tr);
00418         if (length > tr.length)
00419                 return (ISC_R_NOSPACE);
00420         memmove(tr.base, base, length);
00421         isc_buffer_add(target, length);
00422         return (ISC_R_SUCCESS);
00423 }

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