xref: /openbsd/usr.bin/dig/lib/isc/base32.c (revision 1fb015a8)
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