"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/isc/base32.c" (4 Sep 2020, 11156 Bytes) of package /linux/misc/dns/bind9/9.16.7/bind-9.16.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "base32.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 9.16.6_vs_9.16.7.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 #include <stdbool.h>
   15 
   16 #include <isc/base32.h>
   17 #include <isc/buffer.h>
   18 #include <isc/lex.h>
   19 #include <isc/region.h>
   20 #include <isc/string.h>
   21 #include <isc/util.h>
   22 
   23 #define RETERR(x)                        \
   24     do {                             \
   25         isc_result_t _r = (x);   \
   26         if (_r != ISC_R_SUCCESS) \
   27             return ((_r));   \
   28     } while (0)
   29 
   30 /*@{*/
   31 /*!
   32  * These static functions are also present in lib/dns/rdata.c.  I'm not
   33  * sure where they should go. -- bwelling
   34  */
   35 static isc_result_t
   36 str_totext(const char *source, isc_buffer_t *target);
   37 
   38 static isc_result_t
   39 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
   40 
   41 /*@}*/
   42 
   43 static const char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567="
   44                  "abcdefghijklmnopqrstuvwxyz234567";
   45 static const char base32hex[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV="
   46                 "0123456789abcdefghijklmnopqrstuv";
   47 
   48 static isc_result_t
   49 base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
   50           isc_buffer_t *target, const char base[], char pad) {
   51     char buf[9];
   52     unsigned int loops = 0;
   53 
   54     if (wordlength >= 0 && wordlength < 8) {
   55         wordlength = 8;
   56     }
   57 
   58     memset(buf, 0, sizeof(buf));
   59     while (source->length > 0) {
   60         buf[0] = base[((source->base[0] >> 3) & 0x1f)]; /* 5 + */
   61         if (source->length == 1) {
   62             buf[1] = base[(source->base[0] << 2) & 0x1c];
   63             buf[2] = buf[3] = buf[4] = pad;
   64             buf[5] = buf[6] = buf[7] = pad;
   65             RETERR(str_totext(buf, target));
   66             break;
   67         }
   68         buf[1] = base[((source->base[0] << 2) & 0x1c) | /* 3 = 8 */
   69                   ((source->base[1] >> 6) & 0x03)]; /* 2 + */
   70         buf[2] = base[((source->base[1] >> 1) & 0x1f)]; /* 5 + */
   71         if (source->length == 2) {
   72             buf[3] = base[(source->base[1] << 4) & 0x10];
   73             buf[4] = buf[5] = buf[6] = buf[7] = pad;
   74             RETERR(str_totext(buf, target));
   75             break;
   76         }
   77         buf[3] = base[((source->base[1] << 4) & 0x10) | /* 1 = 8 */
   78                   ((source->base[2] >> 4) & 0x0f)]; /* 4 + */
   79         if (source->length == 3) {
   80             buf[4] = base[(source->base[2] << 1) & 0x1e];
   81             buf[5] = buf[6] = buf[7] = pad;
   82             RETERR(str_totext(buf, target));
   83             break;
   84         }
   85         buf[4] = base[((source->base[2] << 1) & 0x1e) | /* 4 = 8 */
   86                   ((source->base[3] >> 7) & 0x01)]; /* 1 + */
   87         buf[5] = base[((source->base[3] >> 2) & 0x1f)]; /* 5 + */
   88         if (source->length == 4) {
   89             buf[6] = base[(source->base[3] << 3) & 0x18];
   90             buf[7] = pad;
   91             RETERR(str_totext(buf, target));
   92             break;
   93         }
   94         buf[6] = base[((source->base[3] << 3) & 0x18) | /* 2 = 8 */
   95                   ((source->base[4] >> 5) & 0x07)]; /* 3 + */
   96         buf[7] = base[source->base[4] & 0x1f];      /* 5 = 8 */
   97         RETERR(str_totext(buf, target));
   98         isc_region_consume(source, 5);
   99 
  100         loops++;
  101         if (source->length != 0 && wordlength >= 0 &&
  102             (int)((loops + 1) * 8) >= wordlength)
  103         {
  104             loops = 0;
  105             RETERR(str_totext(wordbreak, target));
  106         }
  107     }
  108     if (source->length > 0) {
  109         isc_region_consume(source, source->length);
  110     }
  111     return (ISC_R_SUCCESS);
  112 }
  113 
  114 isc_result_t
  115 isc_base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
  116           isc_buffer_t *target) {
  117     return (base32_totext(source, wordlength, wordbreak, target, base32,
  118                   '='));
  119 }
  120 
  121 isc_result_t
  122 isc_base32hex_totext(isc_region_t *source, int wordlength,
  123              const char *wordbreak, isc_buffer_t *target) {
  124     return (base32_totext(source, wordlength, wordbreak, target, base32hex,
  125                   '='));
  126 }
  127 
  128 isc_result_t
  129 isc_base32hexnp_totext(isc_region_t *source, int wordlength,
  130                const char *wordbreak, isc_buffer_t *target) {
  131     return (base32_totext(source, wordlength, wordbreak, target, base32hex,
  132                   0));
  133 }
  134 
  135 /*%
  136  * State of a base32 decoding process in progress.
  137  */
  138 typedef struct {
  139     int length;       /*%< Desired length of binary data or -1 */
  140     isc_buffer_t *target; /*%< Buffer for resulting binary data */
  141     int digits;       /*%< Number of buffered base32 digits */
  142     bool seen_end;        /*%< True if "=" end marker seen */
  143     int val[8];
  144     const char *base; /*%< Which encoding we are using */
  145     int seen_32;      /*%< Number of significant bytes if non
  146                * zero */
  147     bool pad;     /*%< Expect padding */
  148 } base32_decode_ctx_t;
  149 
  150 static inline void
  151 base32_decode_init(base32_decode_ctx_t *ctx, int length, const char base[],
  152            bool pad, isc_buffer_t *target) {
  153     ctx->digits = 0;
  154     ctx->seen_end = false;
  155     ctx->seen_32 = 0;
  156     ctx->length = length;
  157     ctx->target = target;
  158     ctx->base = base;
  159     ctx->pad = pad;
  160 }
  161 
  162 static inline isc_result_t
  163 base32_decode_char(base32_decode_ctx_t *ctx, int c) {
  164     const char *s;
  165     unsigned int last;
  166 
  167     if (ctx->seen_end) {
  168         return (ISC_R_BADBASE32);
  169     }
  170     if ((s = strchr(ctx->base, c)) == NULL) {
  171         return (ISC_R_BADBASE32);
  172     }
  173     last = (unsigned int)(s - ctx->base);
  174 
  175     /*
  176      * Handle lower case.
  177      */
  178     if (last > 32) {
  179         last -= 33;
  180     }
  181 
  182     /*
  183      * Check that padding is contiguous.
  184      */
  185     if (last != 32 && ctx->seen_32 != 0) {
  186         return (ISC_R_BADBASE32);
  187     }
  188 
  189     /*
  190      * If padding is not permitted flag padding as a error.
  191      */
  192     if (last == 32 && !ctx->pad) {
  193         return (ISC_R_BADBASE32);
  194     }
  195 
  196     /*
  197      * Check that padding starts at the right place and that
  198      * bits that should be zero are.
  199      * Record how many significant bytes in answer (seen_32).
  200      */
  201     if (last == 32 && ctx->seen_32 == 0) {
  202         switch (ctx->digits) {
  203         case 0:
  204         case 1:
  205             return (ISC_R_BADBASE32);
  206         case 2:
  207             if ((ctx->val[1] & 0x03) != 0) {
  208                 return (ISC_R_BADBASE32);
  209             }
  210             ctx->seen_32 = 1;
  211             break;
  212         case 3:
  213             return (ISC_R_BADBASE32);
  214         case 4:
  215             if ((ctx->val[3] & 0x0f) != 0) {
  216                 return (ISC_R_BADBASE32);
  217             }
  218             ctx->seen_32 = 2;
  219             break;
  220         case 5:
  221             if ((ctx->val[4] & 0x01) != 0) {
  222                 return (ISC_R_BADBASE32);
  223             }
  224             ctx->seen_32 = 3;
  225             break;
  226         case 6:
  227             return (ISC_R_BADBASE32);
  228         case 7:
  229             if ((ctx->val[6] & 0x07) != 0) {
  230                 return (ISC_R_BADBASE32);
  231             }
  232             ctx->seen_32 = 4;
  233             break;
  234         }
  235     }
  236 
  237     /*
  238      * Zero fill pad values.
  239      */
  240     ctx->val[ctx->digits++] = (last == 32) ? 0 : last;
  241 
  242     if (ctx->digits == 8) {
  243         int n = 5;
  244         unsigned char buf[5];
  245 
  246         if (ctx->seen_32 != 0) {
  247             ctx->seen_end = true;
  248             n = ctx->seen_32;
  249         }
  250         buf[0] = (ctx->val[0] << 3) | (ctx->val[1] >> 2);
  251         buf[1] = (ctx->val[1] << 6) | (ctx->val[2] << 1) |
  252              (ctx->val[3] >> 4);
  253         buf[2] = (ctx->val[3] << 4) | (ctx->val[4] >> 1);
  254         buf[3] = (ctx->val[4] << 7) | (ctx->val[5] << 2) |
  255              (ctx->val[6] >> 3);
  256         buf[4] = (ctx->val[6] << 5) | (ctx->val[7]);
  257         RETERR(mem_tobuffer(ctx->target, buf, n));
  258         if (ctx->length >= 0) {
  259             if (n > ctx->length) {
  260                 return (ISC_R_BADBASE32);
  261             } else {
  262                 ctx->length -= n;
  263             }
  264         }
  265         ctx->digits = 0;
  266     }
  267     return (ISC_R_SUCCESS);
  268 }
  269 
  270 static inline isc_result_t
  271 base32_decode_finish(base32_decode_ctx_t *ctx) {
  272     if (ctx->length > 0) {
  273         return (ISC_R_UNEXPECTEDEND);
  274     }
  275     /*
  276      * Add missing padding if required.
  277      */
  278     if (!ctx->pad && ctx->digits != 0) {
  279         ctx->pad = true;
  280         do {
  281             RETERR(base32_decode_char(ctx, '='));
  282         } while (ctx->digits != 0);
  283     }
  284     if (ctx->digits != 0) {
  285         return (ISC_R_BADBASE32);
  286     }
  287     return (ISC_R_SUCCESS);
  288 }
  289 
  290 static isc_result_t
  291 base32_tobuffer(isc_lex_t *lexer, const char base[], bool pad,
  292         isc_buffer_t *target, int length) {
  293     unsigned int before, after;
  294     base32_decode_ctx_t ctx;
  295     isc_textregion_t *tr;
  296     isc_token_t token;
  297     bool eol;
  298 
  299     REQUIRE(length >= -2);
  300 
  301     base32_decode_init(&ctx, length, base, pad, target);
  302 
  303     before = isc_buffer_usedlength(target);
  304     while (!ctx.seen_end && (ctx.length != 0)) {
  305         unsigned int i;
  306 
  307         if (length > 0) {
  308             eol = false;
  309         } else {
  310             eol = true;
  311         }
  312         RETERR(isc_lex_getmastertoken(lexer, &token,
  313                           isc_tokentype_string, eol));
  314         if (token.type != isc_tokentype_string) {
  315             break;
  316         }
  317         tr = &token.value.as_textregion;
  318         for (i = 0; i < tr->length; i++) {
  319             RETERR(base32_decode_char(&ctx, tr->base[i]));
  320         }
  321     }
  322     after = isc_buffer_usedlength(target);
  323     if (ctx.length < 0 && !ctx.seen_end) {
  324         isc_lex_ungettoken(lexer, &token);
  325     }
  326     RETERR(base32_decode_finish(&ctx));
  327     if (length == -2 && before == after) {
  328         return (ISC_R_UNEXPECTEDEND);
  329     }
  330     return (ISC_R_SUCCESS);
  331 }
  332 
  333 isc_result_t
  334 isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
  335     return (base32_tobuffer(lexer, base32, true, target, length));
  336 }
  337 
  338 isc_result_t
  339 isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
  340     return (base32_tobuffer(lexer, base32hex, true, target, length));
  341 }
  342 
  343 isc_result_t
  344 isc_base32hexnp_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
  345     return (base32_tobuffer(lexer, base32hex, false, target, length));
  346 }
  347 
  348 static isc_result_t
  349 base32_decodestring(const char *cstr, const char base[], bool pad,
  350             isc_buffer_t *target) {
  351     base32_decode_ctx_t ctx;
  352 
  353     base32_decode_init(&ctx, -1, base, pad, target);
  354     for (;;) {
  355         int c = *cstr++;
  356         if (c == '\0') {
  357             break;
  358         }
  359         if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
  360             continue;
  361         }
  362         RETERR(base32_decode_char(&ctx, c));
  363     }
  364     RETERR(base32_decode_finish(&ctx));
  365     return (ISC_R_SUCCESS);
  366 }
  367 
  368 isc_result_t
  369 isc_base32_decodestring(const char *cstr, isc_buffer_t *target) {
  370     return (base32_decodestring(cstr, base32, true, target));
  371 }
  372 
  373 isc_result_t
  374 isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) {
  375     return (base32_decodestring(cstr, base32hex, true, target));
  376 }
  377 
  378 isc_result_t
  379 isc_base32hexnp_decodestring(const char *cstr, isc_buffer_t *target) {
  380     return (base32_decodestring(cstr, base32hex, false, target));
  381 }
  382 
  383 static isc_result_t
  384 base32_decoderegion(isc_region_t *source, const char base[], bool pad,
  385             isc_buffer_t *target) {
  386     base32_decode_ctx_t ctx;
  387 
  388     base32_decode_init(&ctx, -1, base, pad, target);
  389     while (source->length != 0) {
  390         int c = *source->base;
  391         RETERR(base32_decode_char(&ctx, c));
  392         isc_region_consume(source, 1);
  393     }
  394     RETERR(base32_decode_finish(&ctx));
  395     return (ISC_R_SUCCESS);
  396 }
  397 
  398 isc_result_t
  399 isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) {
  400     return (base32_decoderegion(source, base32, true, target));
  401 }
  402 
  403 isc_result_t
  404 isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) {
  405     return (base32_decoderegion(source, base32hex, true, target));
  406 }
  407 
  408 isc_result_t
  409 isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target) {
  410     return (base32_decoderegion(source, base32hex, false, target));
  411 }
  412 
  413 static isc_result_t
  414 str_totext(const char *source, isc_buffer_t *target) {
  415     unsigned int l;
  416     isc_region_t region;
  417 
  418     isc_buffer_availableregion(target, &region);
  419     l = strlen(source);
  420 
  421     if (l > region.length) {
  422         return (ISC_R_NOSPACE);
  423     }
  424 
  425     memmove(region.base, source, l);
  426     isc_buffer_add(target, l);
  427     return (ISC_R_SUCCESS);
  428 }
  429 
  430 static isc_result_t
  431 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
  432     isc_region_t tr;
  433 
  434     isc_buffer_availableregion(target, &tr);
  435     if (length > tr.length) {
  436         return (ISC_R_NOSPACE);
  437     }
  438     memmove(tr.base, base, length);
  439     isc_buffer_add(target, length);
  440     return (ISC_R_SUCCESS);
  441 }