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