1/* 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17/* $Id: base32.c,v 1.8 2020/09/14 08:40:44 florian Exp $ */ 18 19/*! \file */ 20 21#include <isc/base32.h> 22#include <isc/buffer.h> 23#include <isc/region.h> 24#include <string.h> 25#include <isc/util.h> 26 27#define RETERR(x) do { \ 28 isc_result_t _r = (x); \ 29 if (_r != ISC_R_SUCCESS) \ 30 return (_r); \ 31 } while (0) 32 33/*@}*/ 34 35static const char base32hex[] = 36 "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv"; 37 38static isc_result_t 39base32_totext(isc_region_t *source, int wordlength, const char *wordbreak, 40 isc_buffer_t *target, const char base[], char pad) 41{ 42 char buf[9]; 43 unsigned int loops = 0; 44 45 if (wordlength >= 0 && wordlength < 8) 46 wordlength = 8; 47 48 memset(buf, 0, sizeof(buf)); 49 while (source->length > 0) { 50 buf[0] = base[((source->base[0]>>3)&0x1f)]; /* 5 + */ 51 if (source->length == 1) { 52 buf[1] = base[(source->base[0]<<2)&0x1c]; 53 buf[2] = buf[3] = buf[4] = pad; 54 buf[5] = buf[6] = buf[7] = pad; 55 RETERR(isc_str_tobuffer(buf, target)); 56 break; 57 } 58 buf[1] = base[((source->base[0]<<2)&0x1c)| /* 3 = 8 */ 59 ((source->base[1]>>6)&0x03)]; /* 2 + */ 60 buf[2] = base[((source->base[1]>>1)&0x1f)]; /* 5 + */ 61 if (source->length == 2) { 62 buf[3] = base[(source->base[1]<<4)&0x10]; 63 buf[4] = buf[5] = buf[6] = buf[7] = pad; 64 RETERR(isc_str_tobuffer(buf, target)); 65 break; 66 } 67 buf[3] = base[((source->base[1]<<4)&0x10)| /* 1 = 8 */ 68 ((source->base[2]>>4)&0x0f)]; /* 4 + */ 69 if (source->length == 3) { 70 buf[4] = base[(source->base[2]<<1)&0x1e]; 71 buf[5] = buf[6] = buf[7] = pad; 72 RETERR(isc_str_tobuffer(buf, target)); 73 break; 74 } 75 buf[4] = base[((source->base[2]<<1)&0x1e)| /* 4 = 8 */ 76 ((source->base[3]>>7)&0x01)]; /* 1 + */ 77 buf[5] = base[((source->base[3]>>2)&0x1f)]; /* 5 + */ 78 if (source->length == 4) { 79 buf[6] = base[(source->base[3]<<3)&0x18]; 80 buf[7] = pad; 81 RETERR(isc_str_tobuffer(buf, target)); 82 break; 83 } 84 buf[6] = base[((source->base[3]<<3)&0x18)| /* 2 = 8 */ 85 ((source->base[4]>>5)&0x07)]; /* 3 + */ 86 buf[7] = base[source->base[4]&0x1f]; /* 5 = 8 */ 87 RETERR(isc_str_tobuffer(buf, target)); 88 isc_region_consume(source, 5); 89 90 loops++; 91 if (source->length != 0 && wordlength >= 0 && 92 (int)((loops + 1) * 8) >= wordlength) 93 { 94 loops = 0; 95 RETERR(isc_str_tobuffer(wordbreak, target)); 96 } 97 } 98 if (source->length > 0) 99 isc_region_consume(source, source->length); 100 return (ISC_R_SUCCESS); 101} 102 103isc_result_t 104isc_base32hexnp_totext(isc_region_t *source, int wordlength, 105 const char *wordbreak, isc_buffer_t *target) 106{ 107 return (base32_totext(source, wordlength, wordbreak, target, 108 base32hex, 0)); 109} 110 111/*% 112 * State of a base32 decoding process in progress. 113 */ 114typedef struct { 115 int length; /*%< Desired length of binary data or -1 */ 116 isc_buffer_t *target; /*%< Buffer for resulting binary data */ 117 int digits; /*%< Number of buffered base32 digits */ 118 int seen_end; /*%< True if "=" end marker seen */ 119 int val[8]; 120 const char *base; /*%< Which encoding we are using */ 121 int seen_32; /*%< Number of significant bytes if non zero */ 122 int pad; /*%< Expect padding */ 123} base32_decode_ctx_t; 124 125static inline void 126base32_decode_init(base32_decode_ctx_t *ctx, int length, const char base[], 127 int pad, isc_buffer_t *target) 128{ 129 ctx->digits = 0; 130 ctx->seen_end = 0; 131 ctx->seen_32 = 0; 132 ctx->length = length; 133 ctx->target = target; 134 ctx->base = base; 135 ctx->pad = pad; 136} 137 138static inline isc_result_t 139base32_decode_char(base32_decode_ctx_t *ctx, int c) { 140 const char *s; 141 unsigned int last; 142 143 if (ctx->seen_end) 144 return (ISC_R_BADBASE32); 145 if ((s = strchr(ctx->base, c)) == NULL) 146 return (ISC_R_BADBASE32); 147 last = (unsigned int)(s - ctx->base); 148 149 /* 150 * Handle lower case. 151 */ 152 if (last > 32) 153 last -= 33; 154 155 /* 156 * Check that padding is contiguous. 157 */ 158 if (last != 32 && ctx->seen_32 != 0) 159 return (ISC_R_BADBASE32); 160 161 /* 162 * If padding is not permitted flag padding as a error. 163 */ 164 if (last == 32 && !ctx->pad) 165 return (ISC_R_BADBASE32); 166 167 /* 168 * Check that padding starts at the right place and that 169 * bits that should be zero are. 170 * Record how many significant bytes in answer (seen_32). 171 */ 172 if (last == 32 && ctx->seen_32 == 0) 173 switch (ctx->digits) { 174 case 0: 175 case 1: 176 return (ISC_R_BADBASE32); 177 case 2: 178 if ((ctx->val[1]&0x03) != 0) 179 return (ISC_R_BADBASE32); 180 ctx->seen_32 = 1; 181 break; 182 case 3: 183 return (ISC_R_BADBASE32); 184 case 4: 185 if ((ctx->val[3]&0x0f) != 0) 186 return (ISC_R_BADBASE32); 187 ctx->seen_32 = 3; 188 break; 189 case 5: 190 if ((ctx->val[4]&0x01) != 0) 191 return (ISC_R_BADBASE32); 192 ctx->seen_32 = 3; 193 break; 194 case 6: 195 return (ISC_R_BADBASE32); 196 case 7: 197 if ((ctx->val[6]&0x07) != 0) 198 return (ISC_R_BADBASE32); 199 ctx->seen_32 = 4; 200 break; 201 } 202 203 /* 204 * Zero fill pad values. 205 */ 206 ctx->val[ctx->digits++] = (last == 32) ? 0 : last; 207 208 if (ctx->digits == 8) { 209 int n = 5; 210 unsigned char buf[5]; 211 212 if (ctx->seen_32 != 0) { 213 ctx->seen_end = 1; 214 n = ctx->seen_32; 215 } 216 buf[0] = (ctx->val[0]<<3)|(ctx->val[1]>>2); 217 buf[1] = (ctx->val[1]<<6)|(ctx->val[2]<<1)|(ctx->val[3]>>4); 218 buf[2] = (ctx->val[3]<<4)|(ctx->val[4]>>1); 219 buf[3] = (ctx->val[4]<<7)|(ctx->val[5]<<2)|(ctx->val[6]>>3); 220 buf[4] = (ctx->val[6]<<5)|(ctx->val[7]); 221 RETERR(isc_mem_tobuffer(ctx->target, buf, n)); 222 if (ctx->length >= 0) { 223 if (n > ctx->length) 224 return (ISC_R_BADBASE32); 225 else 226 ctx->length -= n; 227 } 228 ctx->digits = 0; 229 } 230 return (ISC_R_SUCCESS); 231} 232 233static inline isc_result_t 234base32_decode_finish(base32_decode_ctx_t *ctx) { 235 236 if (ctx->length > 0) 237 return (ISC_R_UNEXPECTEDEND); 238 /* 239 * Add missing padding if required. 240 */ 241 if (!ctx->pad && ctx->digits != 0) { 242 ctx->pad = 1; 243 do { 244 RETERR(base32_decode_char(ctx, '=')); 245 } while (ctx->digits != 0); 246 } 247 if (ctx->digits != 0) 248 return (ISC_R_BADBASE32); 249 return (ISC_R_SUCCESS); 250} 251 252static isc_result_t 253base32_decoderegion(isc_region_t *source, const char base[], 254 int pad, isc_buffer_t *target) 255{ 256 base32_decode_ctx_t ctx; 257 258 base32_decode_init(&ctx, -1, base, pad, target); 259 while (source->length != 0) { 260 int c = *source->base; 261 RETERR(base32_decode_char(&ctx, c)); 262 isc_region_consume(source, 1); 263 } 264 RETERR(base32_decode_finish(&ctx)); 265 return (ISC_R_SUCCESS); 266} 267 268isc_result_t 269isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target) { 270 return (base32_decoderegion(source, base32hex, 0, target)); 271} 272