1193141Sdougb/*
2262706Serwin * Copyright (C) 2008, 2009, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
3193141Sdougb *
4193141Sdougb * Permission to use, copy, modify, and/or distribute this software for any
5193141Sdougb * purpose with or without fee is hereby granted, provided that the above
6193141Sdougb * copyright notice and this permission notice appear in all copies.
7193141Sdougb *
8193141Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9193141Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10193141Sdougb * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11193141Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12193141Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13193141Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14193141Sdougb * PERFORMANCE OF THIS SOFTWARE.
15193141Sdougb */
16193141Sdougb
17234010Sdougb/* $Id: base32.c,v 1.6 2009/10/21 01:22:29 each Exp $ */
18193141Sdougb
19193141Sdougb/*! \file */
20193141Sdougb
21193141Sdougb#include <config.h>
22193141Sdougb
23193141Sdougb#include <isc/base32.h>
24193141Sdougb#include <isc/buffer.h>
25193141Sdougb#include <isc/lex.h>
26193141Sdougb#include <isc/region.h>
27193141Sdougb#include <isc/string.h>
28193141Sdougb#include <isc/util.h>
29193141Sdougb
30193141Sdougb#define RETERR(x) do { \
31193141Sdougb	isc_result_t _r = (x); \
32193141Sdougb	if (_r != ISC_R_SUCCESS) \
33193141Sdougb		return (_r); \
34193141Sdougb	} while (0)
35193141Sdougb
36193141Sdougb
37193141Sdougb/*@{*/
38193141Sdougb/*!
39193141Sdougb * These static functions are also present in lib/dns/rdata.c.  I'm not
40193141Sdougb * sure where they should go. -- bwelling
41193141Sdougb */
42193141Sdougbstatic isc_result_t
43193141Sdougbstr_totext(const char *source, isc_buffer_t *target);
44193141Sdougb
45193141Sdougbstatic isc_result_t
46193141Sdougbmem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
47193141Sdougb
48193141Sdougb/*@}*/
49193141Sdougb
50193141Sdougbstatic const char base32[] =
51193141Sdougb	 "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=abcdefghijklmnopqrstuvwxyz234567";
52193141Sdougbstatic const char base32hex[] =
53193141Sdougb	"0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
54193141Sdougb
55193141Sdougbstatic isc_result_t
56193141Sdougbbase32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
57193141Sdougb	      isc_buffer_t *target, const char base[])
58193141Sdougb{
59193141Sdougb	char buf[9];
60193141Sdougb	unsigned int loops = 0;
61193141Sdougb
62193141Sdougb	if (wordlength >= 0 && wordlength < 8)
63193141Sdougb		wordlength = 8;
64193141Sdougb
65193141Sdougb	memset(buf, 0, sizeof(buf));
66193141Sdougb	while (source->length > 0) {
67193141Sdougb		buf[0] = base[((source->base[0]>>3)&0x1f)];	/* 5 + */
68193141Sdougb		if (source->length == 1) {
69193141Sdougb			buf[1] = base[(source->base[0]<<2)&0x1c];
70193141Sdougb			buf[2] = buf[3] = buf[4] = '=';
71193141Sdougb			buf[5] = buf[6] = buf[7] = '=';
72193141Sdougb			RETERR(str_totext(buf, target));
73193141Sdougb			break;
74193141Sdougb		}
75193141Sdougb		buf[1] = base[((source->base[0]<<2)&0x1c)|	/* 3 = 8 */
76193141Sdougb			      ((source->base[1]>>6)&0x03)];	/* 2 + */
77193141Sdougb		buf[2] = base[((source->base[1]>>1)&0x1f)];	/* 5 + */
78193141Sdougb		if (source->length == 2) {
79193141Sdougb			buf[3] = base[(source->base[1]<<4)&0x10];
80193141Sdougb			buf[4] = buf[5] = buf[6] = buf[7] = '=';
81193141Sdougb			RETERR(str_totext(buf, target));
82193141Sdougb			break;
83193141Sdougb		}
84193141Sdougb		buf[3] = base[((source->base[1]<<4)&0x10)|	/* 1 = 8 */
85193141Sdougb			      ((source->base[2]>>4)&0x0f)];	/* 4 + */
86193141Sdougb		if (source->length == 3) {
87193141Sdougb			buf[4] = base[(source->base[2]<<1)&0x1e];
88193141Sdougb			buf[5] = buf[6] = buf[7] = '=';
89193141Sdougb			RETERR(str_totext(buf, target));
90193141Sdougb			break;
91193141Sdougb		}
92193141Sdougb		buf[4] = base[((source->base[2]<<1)&0x1e)|	/* 4 = 8 */
93193141Sdougb			      ((source->base[3]>>7)&0x01)];	/* 1 + */
94193141Sdougb		buf[5] = base[((source->base[3]>>2)&0x1f)];	/* 5 + */
95193141Sdougb		if (source->length == 4) {
96193141Sdougb			buf[6] = base[(source->base[3]<<3)&0x18];
97193141Sdougb			buf[7] = '=';
98193141Sdougb			RETERR(str_totext(buf, target));
99193141Sdougb			break;
100193141Sdougb		}
101193141Sdougb		buf[6] = base[((source->base[3]<<3)&0x18)|	/* 2 = 8 */
102193141Sdougb			      ((source->base[4]>>5)&0x07)];	/* 3 + */
103193141Sdougb		buf[7] = base[source->base[4]&0x1f];		/* 5 = 8 */
104193141Sdougb		RETERR(str_totext(buf, target));
105193141Sdougb		isc_region_consume(source, 5);
106193141Sdougb
107193141Sdougb		loops++;
108193141Sdougb		if (source->length != 0 && wordlength >= 0 &&
109193141Sdougb		    (int)((loops + 1) * 8) >= wordlength)
110193141Sdougb		{
111193141Sdougb			loops = 0;
112193141Sdougb			RETERR(str_totext(wordbreak, target));
113193141Sdougb		}
114193141Sdougb	}
115204619Sdougb	if (source->length > 0)
116204619Sdougb		isc_region_consume(source, source->length);
117193141Sdougb	return (ISC_R_SUCCESS);
118193141Sdougb}
119193141Sdougb
120193141Sdougbisc_result_t
121193141Sdougbisc_base32_totext(isc_region_t *source, int wordlength,
122193141Sdougb		  const char *wordbreak, isc_buffer_t *target)
123193141Sdougb{
124193141Sdougb	return (base32_totext(source, wordlength, wordbreak, target, base32));
125193141Sdougb}
126193141Sdougb
127193141Sdougbisc_result_t
128193141Sdougbisc_base32hex_totext(isc_region_t *source, int wordlength,
129193141Sdougb		     const char *wordbreak, isc_buffer_t *target)
130193141Sdougb{
131193141Sdougb	return (base32_totext(source, wordlength, wordbreak, target,
132193141Sdougb			      base32hex));
133193141Sdougb}
134193141Sdougb
135193141Sdougb/*%
136193141Sdougb * State of a base32 decoding process in progress.
137193141Sdougb */
138193141Sdougbtypedef struct {
139193141Sdougb	int length;		/*%< Desired length of binary data or -1 */
140193141Sdougb	isc_buffer_t *target;	/*%< Buffer for resulting binary data */
141193141Sdougb	int digits;		/*%< Number of buffered base32 digits */
142193141Sdougb	isc_boolean_t seen_end;	/*%< True if "=" end marker seen */
143193141Sdougb	int val[8];
144193141Sdougb	const char *base;	/*%< Which encoding we are using */
145193141Sdougb	int seen_32;		/*%< Number of significant bytes if non zero */
146193141Sdougb} base32_decode_ctx_t;
147193141Sdougb
148193141Sdougbstatic inline void
149193141Sdougbbase32_decode_init(base32_decode_ctx_t *ctx, int length,
150193141Sdougb		   const char base[], isc_buffer_t *target)
151193141Sdougb{
152193141Sdougb	ctx->digits = 0;
153193141Sdougb	ctx->seen_end = ISC_FALSE;
154193141Sdougb	ctx->seen_32 = 0;
155193141Sdougb	ctx->length = length;
156193141Sdougb	ctx->target = target;
157193141Sdougb	ctx->base = base;
158193141Sdougb}
159193141Sdougb
160193141Sdougbstatic inline isc_result_t
161193141Sdougbbase32_decode_char(base32_decode_ctx_t *ctx, int c) {
162193141Sdougb	char *s;
163193141Sdougb	unsigned int last;
164193141Sdougb
165193141Sdougb	if (ctx->seen_end)
166193141Sdougb		return (ISC_R_BADBASE32);
167193141Sdougb	if ((s = strchr(ctx->base, c)) == NULL)
168193141Sdougb		return (ISC_R_BADBASE32);
169262706Serwin	last = (unsigned int)(s - ctx->base);
170193141Sdougb	/*
171193141Sdougb	 * Handle lower case.
172193141Sdougb	 */
173193141Sdougb	if (last > 32)
174193141Sdougb		last -= 33;
175193141Sdougb	/*
176193141Sdougb	 * Check that padding is contiguous.
177193141Sdougb	 */
178193141Sdougb	if (last != 32 && ctx->seen_32 != 0)
179193141Sdougb		return (ISC_R_BADBASE32);
180193141Sdougb	/*
181193141Sdougb	 * Check that padding starts at the right place and that
182193141Sdougb	 * bits that should be zero are.
183193141Sdougb	 * Record how many significant bytes in answer (seen_32).
184193141Sdougb	 */
185193141Sdougb	if (last == 32 && ctx->seen_32 == 0)
186193141Sdougb		switch (ctx->digits) {
187193141Sdougb		case 0:
188193141Sdougb		case 1:
189193141Sdougb			return (ISC_R_BADBASE32);
190193141Sdougb		case 2:
191193141Sdougb			if ((ctx->val[1]&0x03) != 0)
192193141Sdougb				return (ISC_R_BADBASE32);
193193141Sdougb			ctx->seen_32 = 1;
194193141Sdougb			break;
195193141Sdougb		case 3:
196193141Sdougb			return (ISC_R_BADBASE32);
197193141Sdougb		case 4:
198193141Sdougb			if ((ctx->val[3]&0x0f) != 0)
199193141Sdougb				return (ISC_R_BADBASE32);
200193141Sdougb			ctx->seen_32 = 3;
201193141Sdougb			break;
202193141Sdougb		case 5:
203193141Sdougb			if ((ctx->val[4]&0x01) != 0)
204193141Sdougb				return (ISC_R_BADBASE32);
205193141Sdougb			ctx->seen_32 = 3;
206193141Sdougb			break;
207193141Sdougb		case 6:
208193141Sdougb			return (ISC_R_BADBASE32);
209193141Sdougb		case 7:
210193141Sdougb			if ((ctx->val[6]&0x07) != 0)
211193141Sdougb				return (ISC_R_BADBASE32);
212193141Sdougb			ctx->seen_32 = 4;
213193141Sdougb			break;
214193141Sdougb		}
215193141Sdougb	/*
216193141Sdougb	 * Zero fill pad values.
217193141Sdougb	 */
218193141Sdougb	ctx->val[ctx->digits++] = (last == 32) ? 0 : last;
219193141Sdougb
220193141Sdougb	if (ctx->digits == 8) {
221193141Sdougb		int n = 5;
222193141Sdougb		unsigned char buf[5];
223193141Sdougb
224193141Sdougb		if (ctx->seen_32 != 0) {
225193141Sdougb			ctx->seen_end = ISC_TRUE;
226193141Sdougb			n = ctx->seen_32;
227193141Sdougb		}
228193141Sdougb		buf[0] = (ctx->val[0]<<3)|(ctx->val[1]>>2);
229193141Sdougb		buf[1] = (ctx->val[1]<<6)|(ctx->val[2]<<1)|(ctx->val[3]>>4);
230193141Sdougb		buf[2] = (ctx->val[3]<<4)|(ctx->val[4]>>1);
231193141Sdougb		buf[3] = (ctx->val[4]<<7)|(ctx->val[5]<<2)|(ctx->val[6]>>3);
232193141Sdougb		buf[4] = (ctx->val[6]<<5)|(ctx->val[7]);
233193141Sdougb		RETERR(mem_tobuffer(ctx->target, buf, n));
234193141Sdougb		if (ctx->length >= 0) {
235193141Sdougb			if (n > ctx->length)
236193141Sdougb				return (ISC_R_BADBASE32);
237193141Sdougb			else
238193141Sdougb				ctx->length -= n;
239193141Sdougb		}
240193141Sdougb		ctx->digits = 0;
241193141Sdougb	}
242193141Sdougb	return (ISC_R_SUCCESS);
243193141Sdougb}
244193141Sdougb
245193141Sdougbstatic inline isc_result_t
246193141Sdougbbase32_decode_finish(base32_decode_ctx_t *ctx) {
247193141Sdougb	if (ctx->length > 0)
248193141Sdougb		return (ISC_R_UNEXPECTEDEND);
249193141Sdougb	if (ctx->digits != 0)
250193141Sdougb		return (ISC_R_BADBASE32);
251193141Sdougb	return (ISC_R_SUCCESS);
252193141Sdougb}
253193141Sdougb
254193141Sdougbstatic isc_result_t
255193141Sdougbbase32_tobuffer(isc_lex_t *lexer, const char base[], isc_buffer_t *target,
256193141Sdougb		int length)
257193141Sdougb{
258193141Sdougb	base32_decode_ctx_t ctx;
259193141Sdougb	isc_textregion_t *tr;
260193141Sdougb	isc_token_t token;
261193141Sdougb	isc_boolean_t eol;
262193141Sdougb
263193141Sdougb	base32_decode_init(&ctx, length, base, target);
264193141Sdougb
265193141Sdougb	while (!ctx.seen_end && (ctx.length != 0)) {
266193141Sdougb		unsigned int i;
267193141Sdougb
268193141Sdougb		if (length > 0)
269193141Sdougb			eol = ISC_FALSE;
270193141Sdougb		else
271193141Sdougb			eol = ISC_TRUE;
272193141Sdougb		RETERR(isc_lex_getmastertoken(lexer, &token,
273193141Sdougb					      isc_tokentype_string, eol));
274193141Sdougb		if (token.type != isc_tokentype_string)
275193141Sdougb			break;
276193141Sdougb		tr = &token.value.as_textregion;
277193141Sdougb		for (i = 0; i < tr->length; i++)
278193141Sdougb			RETERR(base32_decode_char(&ctx, tr->base[i]));
279193141Sdougb	}
280193141Sdougb	if (ctx.length < 0 && !ctx.seen_end)
281193141Sdougb		isc_lex_ungettoken(lexer, &token);
282193141Sdougb	RETERR(base32_decode_finish(&ctx));
283193141Sdougb	return (ISC_R_SUCCESS);
284193141Sdougb}
285193141Sdougb
286193141Sdougbisc_result_t
287193141Sdougbisc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
288193141Sdougb	return (base32_tobuffer(lexer, base32, target, length));
289193141Sdougb}
290193141Sdougb
291193141Sdougbisc_result_t
292193141Sdougbisc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
293193141Sdougb	return (base32_tobuffer(lexer, base32hex, target, length));
294193141Sdougb}
295193141Sdougb
296193141Sdougbstatic isc_result_t
297193141Sdougbbase32_decodestring(const char *cstr, const char base[], isc_buffer_t *target) {
298193141Sdougb	base32_decode_ctx_t ctx;
299193141Sdougb
300193141Sdougb	base32_decode_init(&ctx, -1, base, target);
301193141Sdougb	for (;;) {
302193141Sdougb		int c = *cstr++;
303193141Sdougb		if (c == '\0')
304193141Sdougb			break;
305193141Sdougb		if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
306193141Sdougb			continue;
307193141Sdougb		RETERR(base32_decode_char(&ctx, c));
308193141Sdougb	}
309193141Sdougb	RETERR(base32_decode_finish(&ctx));
310193141Sdougb	return (ISC_R_SUCCESS);
311193141Sdougb}
312193141Sdougb
313193141Sdougbisc_result_t
314193141Sdougbisc_base32_decodestring(const char *cstr, isc_buffer_t *target) {
315193141Sdougb	return (base32_decodestring(cstr, base32, target));
316193141Sdougb}
317193141Sdougb
318193141Sdougbisc_result_t
319193141Sdougbisc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) {
320193141Sdougb	return (base32_decodestring(cstr, base32hex, target));
321193141Sdougb}
322193141Sdougb
323193141Sdougbstatic isc_result_t
324193141Sdougbbase32_decoderegion(isc_region_t *source, const char base[], isc_buffer_t *target) {
325193141Sdougb	base32_decode_ctx_t ctx;
326193141Sdougb
327193141Sdougb	base32_decode_init(&ctx, -1, base, target);
328193141Sdougb	while (source->length != 0) {
329193141Sdougb		int c = *source->base;
330193141Sdougb		RETERR(base32_decode_char(&ctx, c));
331193141Sdougb		isc_region_consume(source, 1);
332193141Sdougb	}
333193141Sdougb	RETERR(base32_decode_finish(&ctx));
334193141Sdougb	return (ISC_R_SUCCESS);
335193141Sdougb}
336193141Sdougb
337193141Sdougbisc_result_t
338193141Sdougbisc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) {
339193141Sdougb	return (base32_decoderegion(source, base32, target));
340193141Sdougb}
341193141Sdougb
342193141Sdougbisc_result_t
343193141Sdougbisc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) {
344193141Sdougb	return (base32_decoderegion(source, base32hex, target));
345193141Sdougb}
346193141Sdougb
347193141Sdougbstatic isc_result_t
348193141Sdougbstr_totext(const char *source, isc_buffer_t *target) {
349193141Sdougb	unsigned int l;
350193141Sdougb	isc_region_t region;
351193141Sdougb
352193141Sdougb	isc_buffer_availableregion(target, &region);
353193141Sdougb	l = strlen(source);
354193141Sdougb
355193141Sdougb	if (l > region.length)
356193141Sdougb		return (ISC_R_NOSPACE);
357193141Sdougb
358262706Serwin	memmove(region.base, source, l);
359193141Sdougb	isc_buffer_add(target, l);
360193141Sdougb	return (ISC_R_SUCCESS);
361193141Sdougb}
362193141Sdougb
363193141Sdougbstatic isc_result_t
364193141Sdougbmem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
365193141Sdougb	isc_region_t tr;
366193141Sdougb
367193141Sdougb	isc_buffer_availableregion(target, &tr);
368193141Sdougb	if (length > tr.length)
369193141Sdougb		return (ISC_R_NOSPACE);
370262706Serwin	memmove(tr.base, base, length);
371193141Sdougb	isc_buffer_add(target, length);
372193141Sdougb	return (ISC_R_SUCCESS);
373193141Sdougb}
374