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
35 static const char base32hex[] =
36 "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
37
38 static isc_result_t
base32_totext(isc_region_t * source,int wordlength,const char * wordbreak,isc_buffer_t * target,const char base[],char pad)39 base32_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
103 isc_result_t
isc_base32hexnp_totext(isc_region_t * source,int wordlength,const char * wordbreak,isc_buffer_t * target)104 isc_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 */
114 typedef 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
125 static inline void
base32_decode_init(base32_decode_ctx_t * ctx,int length,const char base[],int pad,isc_buffer_t * target)126 base32_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
138 static inline isc_result_t
base32_decode_char(base32_decode_ctx_t * ctx,int c)139 base32_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
233 static inline isc_result_t
base32_decode_finish(base32_decode_ctx_t * ctx)234 base32_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
252 static isc_result_t
base32_decoderegion(isc_region_t * source,const char base[],int pad,isc_buffer_t * target)253 base32_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
268 isc_result_t
isc_base32hexnp_decoderegion(isc_region_t * source,isc_buffer_t * target)269 isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target) {
270 return (base32_decoderegion(source, base32hex, 0, target));
271 }
272