Changeset 771 in openpam for trunk/lib/liboath/oath_base32.c


Ignore:
Timestamp:
Mar 6, 2014, 5:54:58 PM (7 years ago)
Author:
Dag-Erling Smørgrav
Message:

Replace base{32,64}_decode() with table-driven implementations. The new
code is less strict about padding, thus ensuring compatibility with
implementations which do not understand padding, such as MIME::Base32.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/lib/liboath/oath_base32.c

    r770 r771  
    3838#include <errno.h>
    3939#include <stdint.h>
     40#include <stdio.h>
    4041
    4142#include <security/oath.h>
    4243
    43 static const char b32[] =
     44static const char b32enc[] =
    4445    "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
    4546
     47static const uint8_t b32dec[256] = {
     48        ['A'] =  0, ['B'] =  1, ['C'] =  2, ['D'] =  3,
     49        ['E'] =  4, ['F'] =  5, ['G'] =  6, ['H'] =  7,
     50        ['I'] =  8, ['J'] =  9, ['K'] = 10, ['L'] = 11,
     51        ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
     52        ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19,
     53        ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23,
     54        ['Y'] = 24, ['Z'] = 25,
     55
     56        ['a'] =  0, ['b'] =  1, ['c'] =  2, ['d'] =  3,
     57        ['e'] =  4, ['f'] =  5, ['g'] =  6, ['h'] =  7,
     58        ['i'] =  8, ['j'] =  9, ['k'] = 10, ['l'] = 11,
     59        ['m'] = 12, ['n'] = 13, ['o'] = 14, ['p'] = 15,
     60        ['q'] = 16, ['r'] = 17, ['s'] = 18, ['t'] = 19,
     61        ['u'] = 20, ['v'] = 21, ['w'] = 22, ['x'] = 23,
     62        ['y'] = 24, ['z'] = 25,
     63
     64        ['2'] = 26, ['3'] = 27, ['4'] = 28, ['5'] = 29,
     65        ['6'] = 30, ['7'] = 31,
     66};
     67
    4668/*
    47  * Encode data in RFC 3548 base 32 representation.  The target buffer must
     69 * Encode data in RFC 4648 base 32 representation.  The target buffer must
    4870 * have room for base32_enclen(len) characters and a terminating NUL.
    4971 */
     
    5375        uint64_t bits;
    5476
    55         if (*olen <= base32_enclen(ilen))
     77        if (*olen <= base32_enclen(ilen)) {
     78                errno = ENOSPC;
    5679                return (-1);
     80        }
    5781        *olen = 0;
    5882        while (ilen >= 5) {
     
    6589                ilen -= 5;
    6690                in += 5;
    67                 out[0] = b32[bits >> 35 & 0x1f];
    68                 out[1] = b32[bits >> 30 & 0x1f];
    69                 out[2] = b32[bits >> 25 & 0x1f];
    70                 out[3] = b32[bits >> 20 & 0x1f];
    71                 out[4] = b32[bits >> 15 & 0x1f];
    72                 out[5] = b32[bits >> 10 & 0x1f];
    73                 out[6] = b32[bits >> 5 & 0x1f];
    74                 out[7] = b32[bits & 0x1f];
     91                out[0] = b32enc[bits >> 35 & 0x1f];
     92                out[1] = b32enc[bits >> 30 & 0x1f];
     93                out[2] = b32enc[bits >> 25 & 0x1f];
     94                out[3] = b32enc[bits >> 20 & 0x1f];
     95                out[4] = b32enc[bits >> 15 & 0x1f];
     96                out[5] = b32enc[bits >> 10 & 0x1f];
     97                out[6] = b32enc[bits >> 5 & 0x1f];
     98                out[7] = b32enc[bits & 0x1f];
    7599                *olen += 8;
    76100                out += 8;
     
    88112                        bits |= (uint64_t)in[0] << 32;
    89113                }
    90                 out[0] = b32[bits >> 35 & 0x1f];
    91                 out[1] = b32[bits >> 30 & 0x1f];
    92                 out[2] = ilen > 1 ? b32[bits >> 25 & 0x1f] : '=';
    93                 out[3] = ilen > 1 ? b32[bits >> 20 & 0x1f] : '=';
    94                 out[4] = ilen > 2 ? b32[bits >> 15 & 0x1f] : '=';
    95                 out[5] = ilen > 3 ? b32[bits >> 10 & 0x1f] : '=';
    96                 out[6] = ilen > 3 ? b32[bits >> 5 & 0x1f] : '=';
     114                out[0] = b32enc[bits >> 35 & 0x1f];
     115                out[1] = b32enc[bits >> 30 & 0x1f];
     116                out[2] = ilen > 1 ? b32enc[bits >> 25 & 0x1f] : '=';
     117                out[3] = ilen > 1 ? b32enc[bits >> 20 & 0x1f] : '=';
     118                out[4] = ilen > 2 ? b32enc[bits >> 15 & 0x1f] : '=';
     119                out[5] = ilen > 3 ? b32enc[bits >> 10 & 0x1f] : '=';
     120                out[6] = ilen > 3 ? b32enc[bits >> 5 & 0x1f] : '=';
    97121                out[7] = '=';
    98122                *olen += 8;
     
    105129
    106130/*
    107  * Decode data in RFC 2548 base 32 representation, stopping at the
     131 * Decode data in RFC 4648 base 32 representation, stopping at the
    108132 * terminating NUL, the first invalid (non-base32, non-whitespace)
    109133 * character or after len characters, whichever comes first.
     134 *
     135 * Padding is handled sloppily: any padding character following the data
     136 * is silently consumed.  This not only simplifies the code but ensures
     137 * compatibility with implementations which do not emit or understand
     138 * padding.
    110139 *
    111140 * The olen argument is used by the caller to pass the size of the buffer
     
    118147{
    119148        size_t len;
    120         uint64_t bits;
    121         int shift;
     149        int bits, shift, padding;
    122150
    123         for (len = 0, bits = 0, shift = 40; ilen && *in && *in != '='; --ilen, ++in) {
    124                 if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n') {
     151        for (bits = shift = padding = len = 0; ilen && *in; --ilen, ++in) {
     152                if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n' ||
     153                    (padding && *in == '=')) {
     154                        /* consume */
    125155                        continue;
    126                 } else if (*in >= 'A' && *in <= 'Z') {
    127                         shift -= 5;
    128                         bits |= (uint64_t)(*in - 'A') << shift;
    129                 } else if (*in >= 'a' && *in <= 'z') {
    130                         shift -= 5;
    131                         bits |= (uint64_t)(*in - 'a') << shift;
    132                 } else if (*in >= '2' && *in <= '7') { 
    133                         shift -= 5;
    134                         bits |= (uint64_t)(*in - '2' + 26) << shift;
    135                 } else if (*in == '=') {
    136                         /* handled below */
    137                         break;
     156                } else if (!padding && b32dec[(int)*in]) {
     157                        /* shift into accumulator */
     158                        shift += 5;
     159                        bits = bits << 5 | b32dec[(int)*in];
     160                } else if (!padding && shift && *in == '=') {
     161                        /* final byte */
     162                        shift = 0;
     163                        padding = 1;
    138164                } else {
    139                         goto bad;
     165                        /* error */
     166                        *olen = 0;
     167                        errno = EINVAL;
     168                        return (-1);
    140169                }
    141                 if (shift == 0) {
    142                         if ((len += 5) <= *olen) {
    143                                 *out++ = (bits >> 32) & 0xff;
    144                                 *out++ = (bits >> 24) & 0xff;
    145                                 *out++ = (bits >> 16) & 0xff;
    146                                 *out++ = (bits >> 8) & 0xff;
    147                                 *out++ = bits & 0xff;
    148                         }
    149                         bits = 0;
    150                         shift = 40;
     170                if (shift >= 8) {
     171                        /* output accumulated byte */
     172                        shift -= 8;
     173                        if (len++ < *olen)
     174                                *out++ = (bits >> shift) & 0xff;
    151175                }
    152176        }
    153         if (ilen && *in == '=' &&
    154             (shift == 30 || shift == 20 || shift == 15 || shift == 5)) {
    155                 /*
    156                  * Padding:
    157                  *
    158                  * 00            8 AA====== 30
    159                  * 00 00        16 AAAA==== 20
    160                  * 00 00 00     24 AAAAA=== 15
    161                  * 00 00 00 00  32 AAAAAAA= 5
    162                  *
    163                  * XXX We should check that the last few bits before the
    164                  * padding starts are zero.
    165                  */
    166                 switch (shift) {
    167                 case 5:
    168                         if (++len <= *olen)
    169                                 *out++ = (bits >> 32) & 0xff;
    170                         bits <<= 8;
    171                 case 15:
    172                         if (++len <= *olen)
    173                                 *out++ = (bits >> 32) & 0xff;
    174                         bits <<= 8;
    175                 case 20:
    176                         if (++len <= *olen)
    177                                 *out++ = (bits >> 32) & 0xff;
    178                         bits <<= 8;
    179                 case 30:
    180                         if (++len <= *olen)
    181                                 *out++ = (bits >> 32) & 0xff;
    182                         bits <<= 8;
    183                         break;
    184                 default:
    185                         goto bad;
    186                 }
    187                 /* consume remaining padding and whitespace */
    188                 for (; ilen && *in; --ilen, ++in) {
    189                         if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n')
    190                                 continue;
    191                         else if (*in == '=' && shift)
    192                                 shift -= 5;
    193                         else
    194                                 goto bad;
    195                 }
     177        /* report decoded length */
     178        *olen = len;
     179        if (len > *olen) {
     180                /* overflow */
     181                errno = ENOSPC;
     182                return (-1);
    196183        }
    197         if (ilen)
    198                 goto bad;
    199         *olen = len;
    200         if (len > *olen)
    201                 return (-1);
    202184        return (0);
    203 bad:
    204         *olen = 0;
    205         return (-1);
    206185}
Note: See TracChangeset for help on using the changeset viewer.