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: base64.c,v 1.7 2020/09/14 08:40:44 florian Exp $ */ 18 19 /*! \file */ 20 21 #include <string.h> 22 23 #include <isc/base64.h> 24 #include <isc/buffer.h> 25 #include <isc/region.h> 26 #include <isc/util.h> 27 28 #define RETERR(x) do { \ 29 isc_result_t _r = (x); \ 30 if (_r != ISC_R_SUCCESS) \ 31 return (_r); \ 32 } while (0) 33 34 /*@{*/ 35 36 static const char base64[] = 37 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 38 /*@}*/ 39 40 isc_result_t 41 isc_base64_totext(isc_region_t *source, int wordlength, 42 const char *wordbreak, isc_buffer_t *target) 43 { 44 char buf[5]; 45 unsigned int loops = 0; 46 47 if (wordlength < 4) 48 wordlength = 4; 49 50 memset(buf, 0, sizeof(buf)); 51 while (source->length > 2) { 52 buf[0] = base64[(source->base[0]>>2)&0x3f]; 53 buf[1] = base64[((source->base[0]<<4)&0x30)| 54 ((source->base[1]>>4)&0x0f)]; 55 buf[2] = base64[((source->base[1]<<2)&0x3c)| 56 ((source->base[2]>>6)&0x03)]; 57 buf[3] = base64[source->base[2]&0x3f]; 58 RETERR(isc_str_tobuffer(buf, target)); 59 isc_region_consume(source, 3); 60 61 loops++; 62 if (source->length != 0 && 63 (int)((loops + 1) * 4) >= wordlength) 64 { 65 loops = 0; 66 RETERR(isc_str_tobuffer(wordbreak, target)); 67 } 68 } 69 if (source->length == 2) { 70 buf[0] = base64[(source->base[0]>>2)&0x3f]; 71 buf[1] = base64[((source->base[0]<<4)&0x30)| 72 ((source->base[1]>>4)&0x0f)]; 73 buf[2] = base64[((source->base[1]<<2)&0x3c)]; 74 buf[3] = '='; 75 RETERR(isc_str_tobuffer(buf, target)); 76 isc_region_consume(source, 2); 77 } else if (source->length == 1) { 78 buf[0] = base64[(source->base[0]>>2)&0x3f]; 79 buf[1] = base64[((source->base[0]<<4)&0x30)]; 80 buf[2] = buf[3] = '='; 81 RETERR(isc_str_tobuffer(buf, target)); 82 isc_region_consume(source, 1); 83 } 84 return (ISC_R_SUCCESS); 85 } 86 87 /*% 88 * State of a base64 decoding process in progress. 89 */ 90 typedef struct { 91 int length; /*%< Desired length of binary data or -1 */ 92 isc_buffer_t *target; /*%< Buffer for resulting binary data */ 93 int digits; /*%< Number of buffered base64 digits */ 94 int seen_end; /*%< True if "=" end marker seen */ 95 int val[4]; 96 } base64_decode_ctx_t; 97 98 static inline void 99 base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target) 100 { 101 ctx->digits = 0; 102 ctx->seen_end = 0; 103 ctx->length = length; 104 ctx->target = target; 105 } 106 107 static inline isc_result_t 108 base64_decode_char(base64_decode_ctx_t *ctx, int c) { 109 const char *s; 110 111 if (ctx->seen_end) 112 return (ISC_R_BADBASE64); 113 if ((s = strchr(base64, c)) == NULL) 114 return (ISC_R_BADBASE64); 115 ctx->val[ctx->digits++] = (int)(s - base64); 116 if (ctx->digits == 4) { 117 int n; 118 unsigned char buf[3]; 119 if (ctx->val[0] == 64 || ctx->val[1] == 64) 120 return (ISC_R_BADBASE64); 121 if (ctx->val[2] == 64 && ctx->val[3] != 64) 122 return (ISC_R_BADBASE64); 123 /* 124 * Check that bits that should be zero are. 125 */ 126 if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0) 127 return (ISC_R_BADBASE64); 128 /* 129 * We don't need to test for ctx->val[2] != 64 as 130 * the bottom two bits of 64 are zero. 131 */ 132 if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0) 133 return (ISC_R_BADBASE64); 134 n = (ctx->val[2] == 64) ? 1 : 135 (ctx->val[3] == 64) ? 2 : 3; 136 if (n != 3) { 137 ctx->seen_end = 1; 138 if (ctx->val[2] == 64) 139 ctx->val[2] = 0; 140 if (ctx->val[3] == 64) 141 ctx->val[3] = 0; 142 } 143 buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4); 144 buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2); 145 buf[2] = (ctx->val[2]<<6)|(ctx->val[3]); 146 RETERR(isc_mem_tobuffer(ctx->target, buf, n)); 147 if (ctx->length >= 0) { 148 if (n > ctx->length) 149 return (ISC_R_BADBASE64); 150 else 151 ctx->length -= n; 152 } 153 ctx->digits = 0; 154 } 155 return (ISC_R_SUCCESS); 156 } 157 158 static inline isc_result_t 159 base64_decode_finish(base64_decode_ctx_t *ctx) { 160 if (ctx->length > 0) 161 return (ISC_R_UNEXPECTEDEND); 162 if (ctx->digits != 0) 163 return (ISC_R_BADBASE64); 164 return (ISC_R_SUCCESS); 165 } 166 167 isc_result_t 168 isc_base64_decodestring(const char *cstr, isc_buffer_t *target) { 169 base64_decode_ctx_t ctx; 170 171 base64_decode_init(&ctx, -1, target); 172 for (;;) { 173 int c = *cstr++; 174 if (c == '\0') 175 break; 176 if (c == ' ' || c == '\t' || c == '\n' || c== '\r') 177 continue; 178 RETERR(base64_decode_char(&ctx, c)); 179 } 180 RETERR(base64_decode_finish(&ctx)); 181 return (ISC_R_SUCCESS); 182 } 183