xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/base32_code.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1*e89934bbSchristos /*	$NetBSD: base32_code.c,v 1.2 2017/02/14 01:16:49 christos Exp $	*/
2a30b880eStron 
3a30b880eStron /*++
4a30b880eStron /* NAME
5a30b880eStron /*	base32_code 3
6a30b880eStron /* SUMMARY
7a30b880eStron /*	encode/decode data, base 32 style
8a30b880eStron /* SYNOPSIS
9a30b880eStron /*	#include <base32_code.h>
10a30b880eStron /*
11a30b880eStron /*	VSTRING	*base32_encode(result, in, len)
12a30b880eStron /*	VSTRING	*result;
13a30b880eStron /*	const char *in;
14a30b880eStron /*	ssize_t	len;
15a30b880eStron /*
16a30b880eStron /*	VSTRING	*base32_decode(result, in, len)
17a30b880eStron /*	VSTRING	*result;
18a30b880eStron /*	const char *in;
19a30b880eStron /*	ssize_t	len;
20a30b880eStron /* DESCRIPTION
21a30b880eStron /*	base32_encode() takes a block of len bytes and encodes it as one
22a30b880eStron /*	null-terminated string.  The result value is the result argument.
23a30b880eStron /*
24a30b880eStron /*	base32_decode() performs the opposite transformation. The result
25a30b880eStron /*	value is the result argument. The result is null terminated, whether
26a30b880eStron /*	or not that makes sense.
27a30b880eStron /* DIAGNOSTICS
28a30b880eStron /*	base32_decode() returns a null pointer when the input contains
29a30b880eStron /*	characters not in the base 32 alphabet.
30a30b880eStron /* SEE ALSO
31a30b880eStron /*	RFC 4648; padding is strictly enforced
32a30b880eStron /* LICENSE
33a30b880eStron /* .ad
34a30b880eStron /* .fi
35a30b880eStron /*	The Secure Mailer license must be distributed with this software.
36a30b880eStron /* AUTHOR(S)
37a30b880eStron /*	Wietse Venema
38a30b880eStron /*	IBM T.J. Watson Research
39a30b880eStron /*	P.O. Box 704
40a30b880eStron /*	Yorktown Heights, NY 10598, USA
41a30b880eStron /*--*/
42a30b880eStron 
43a30b880eStron /* System library. */
44a30b880eStron 
45a30b880eStron #include "sys_defs.h"
46a30b880eStron #include <ctype.h>
47a30b880eStron #include <string.h>
48a30b880eStron #include <limits.h>
49a30b880eStron 
50a30b880eStron #ifndef UCHAR_MAX
51a30b880eStron #define UCHAR_MAX 0xff
52a30b880eStron #endif
53a30b880eStron 
54a30b880eStron /* Utility library. */
55a30b880eStron 
56a30b880eStron #include <msg.h>
57a30b880eStron #include <mymalloc.h>
58a30b880eStron #include <vstring.h>
59a30b880eStron #include <base32_code.h>
60a30b880eStron 
61a30b880eStron /* Application-specific. */
62a30b880eStron 
63a30b880eStron static unsigned char to_b32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
64a30b880eStron 
65a30b880eStron #define UNSIG_CHAR_PTR(x) ((unsigned char *)(x))
66a30b880eStron 
67a30b880eStron /* base32_encode - raw data to encoded */
68a30b880eStron 
base32_encode(VSTRING * result,const char * in,ssize_t len)69a30b880eStron VSTRING *base32_encode(VSTRING *result, const char *in, ssize_t len)
70a30b880eStron {
71a30b880eStron     const unsigned char *cp;
72a30b880eStron     ssize_t count;
73a30b880eStron     static int pad_count[] = {0, 6, 4, 3, 1};
74a30b880eStron 
75a30b880eStron     /*
76a30b880eStron      * Encode 5 -> 8.
77a30b880eStron      */
78a30b880eStron     VSTRING_RESET(result);
79a30b880eStron     for (cp = UNSIG_CHAR_PTR(in), count = len; count > 0; count -= 5, cp += 5) {
80a30b880eStron 	VSTRING_ADDCH(result, to_b32[cp[0] >> 3]);
81a30b880eStron 	if (count < 2) {
82a30b880eStron 	    VSTRING_ADDCH(result, to_b32[(cp[0] & 0x7) << 2]);
83a30b880eStron 	    break;
84a30b880eStron 	}
85a30b880eStron 	VSTRING_ADDCH(result, to_b32[(cp[0] & 0x7) << 2 | cp[1] >> 6]);
86a30b880eStron 	VSTRING_ADDCH(result, to_b32[(cp[1] & 0x3f) >> 1]);
87a30b880eStron 	if (count < 3) {
88a30b880eStron 	    VSTRING_ADDCH(result, to_b32[(cp[1] & 0x1) << 4]);
89a30b880eStron 	    break;
90a30b880eStron 	}
91a30b880eStron 	VSTRING_ADDCH(result, to_b32[(cp[1] & 0x1) << 4 | cp[2] >> 4]);
92a30b880eStron 	if (count < 4) {
93a30b880eStron 	    VSTRING_ADDCH(result, to_b32[(cp[2] & 0xf) << 1]);
94a30b880eStron 	    break;
95a30b880eStron 	}
96a30b880eStron 	VSTRING_ADDCH(result, to_b32[(cp[2] & 0xf) << 1 | cp[3] >> 7]);
97a30b880eStron 	VSTRING_ADDCH(result, to_b32[(cp[3] & 0x7f) >> 2]);
98a30b880eStron 	if (count < 5) {
99a30b880eStron 	    VSTRING_ADDCH(result, to_b32[(cp[3] & 0x3) << 3]);
100a30b880eStron 	    break;
101a30b880eStron 	}
102a30b880eStron 	VSTRING_ADDCH(result, to_b32[(cp[3] & 0x3) << 3 | cp[4] >> 5]);
103a30b880eStron 	VSTRING_ADDCH(result, to_b32[cp[4] & 0x1f]);
104a30b880eStron     }
105a30b880eStron     if (count > 0)
106a30b880eStron 	vstring_strncat(result, "======", pad_count[count]);
107a30b880eStron     VSTRING_TERMINATE(result);
108a30b880eStron     return (result);
109a30b880eStron }
110a30b880eStron 
111a30b880eStron /* base32_decode - encoded data to raw */
112a30b880eStron 
base32_decode(VSTRING * result,const char * in,ssize_t len)113a30b880eStron VSTRING *base32_decode(VSTRING *result, const char *in, ssize_t len)
114a30b880eStron {
115a30b880eStron     static unsigned char *un_b32 = 0;
116a30b880eStron     const unsigned char *cp;
117a30b880eStron     ssize_t count;
118a30b880eStron     unsigned int ch0;
119a30b880eStron     unsigned int ch1;
120a30b880eStron     unsigned int ch2;
121a30b880eStron     unsigned int ch3;
122a30b880eStron     unsigned int ch4;
123a30b880eStron     unsigned int ch5;
124a30b880eStron     unsigned int ch6;
125a30b880eStron     unsigned int ch7;
126a30b880eStron 
127a30b880eStron #define CHARS_PER_BYTE		(UCHAR_MAX + 1)
128a30b880eStron #define INVALID			0xff
129a30b880eStron #if 1
130a30b880eStron #define ENFORCE_LENGTH(x)	(x)
131a30b880eStron #define ENFORCE_PADDING(x)	(x)
132a30b880eStron #define ENFORCE_NULL_BITS(x)	(x)
133a30b880eStron #else
134a30b880eStron #define ENFORCE_LENGTH(x)	(1)
135a30b880eStron #define ENFORCE_PADDING(x)	(1)
136a30b880eStron #define ENFORCE_NULL_BITS(x)	(1)
137a30b880eStron #endif
138a30b880eStron 
139a30b880eStron     /*
140a30b880eStron      * Sanity check.
141a30b880eStron      */
142a30b880eStron     if (ENFORCE_LENGTH(len % 8))
143a30b880eStron 	return (0);
144a30b880eStron 
145a30b880eStron     /*
146a30b880eStron      * Once: initialize the decoding lookup table on the fly.
147a30b880eStron      */
148a30b880eStron     if (un_b32 == 0) {
149a30b880eStron 	un_b32 = (unsigned char *) mymalloc(CHARS_PER_BYTE);
150a30b880eStron 	memset(un_b32, INVALID, CHARS_PER_BYTE);
151e262b48eSchristos 	for (cp = to_b32; cp < to_b32 + sizeof(to_b32) - 1; cp++)
152a30b880eStron 	    un_b32[*cp] = cp - to_b32;
153a30b880eStron     }
154a30b880eStron 
155a30b880eStron     /*
156a30b880eStron      * Decode 8 -> 5.
157a30b880eStron      */
158a30b880eStron     VSTRING_RESET(result);
159a30b880eStron     for (cp = UNSIG_CHAR_PTR(in), count = 0; count < len; count += 8) {
160a30b880eStron 	if ((ch0 = un_b32[*cp++]) == INVALID
161a30b880eStron 	    || (ch1 = un_b32[*cp++]) == INVALID)
162a30b880eStron 	    return (0);
163a30b880eStron 	VSTRING_ADDCH(result, ch0 << 3 | ch1 >> 2);
164a30b880eStron 	if ((ch2 = *cp++) == '='
165a30b880eStron 	    && ENFORCE_PADDING(strcmp((char *) cp, "=====") == 0)
166a30b880eStron 	    && ENFORCE_NULL_BITS((ch1 & 0x3) == 0))
167a30b880eStron 	    break;
168a30b880eStron 	if ((ch2 = un_b32[ch2]) == INVALID)
169a30b880eStron 	    return (0);
170a30b880eStron 	if ((ch3 = un_b32[*cp++]) == INVALID)
171a30b880eStron 	    return (0);
172a30b880eStron 	VSTRING_ADDCH(result, ch1 << 6 | ch2 << 1 | ch3 >> 4);
173a30b880eStron 	if ((ch4 = *cp++) == '='
174a30b880eStron 	    && ENFORCE_PADDING(strcmp((char *) cp, "===") == 0)
175a30b880eStron 	    && ENFORCE_NULL_BITS((ch3 & 0xf) == 0))
176a30b880eStron 	    break;
177a30b880eStron 	if ((ch4 = un_b32[ch4]) == INVALID)
178a30b880eStron 	    return (0);
179a30b880eStron 	VSTRING_ADDCH(result, ch3 << 4 | ch4 >> 1);
180a30b880eStron 	if ((ch5 = *cp++) == '='
181a30b880eStron 	    && ENFORCE_PADDING(strcmp((char *) cp, "==") == 0)
182a30b880eStron 	    && ENFORCE_NULL_BITS((ch4 & 0x1) == 0))
183a30b880eStron 	    break;
184a30b880eStron 	if ((ch5 = un_b32[ch5]) == INVALID)
185a30b880eStron 	    return (0);
186a30b880eStron 	if ((ch6 = un_b32[*cp++]) == INVALID)
187a30b880eStron 	    return (0);
188a30b880eStron 	VSTRING_ADDCH(result, ch4 << 7 | ch5 << 2 | ch6 >> 3);
189a30b880eStron 	if ((ch7 = *cp++) == '='
190a30b880eStron 	    && ENFORCE_NULL_BITS((ch6 & 0x7) == 0))
191a30b880eStron 	    break;
192a30b880eStron 	if ((ch7 = un_b32[ch7]) == INVALID)
193a30b880eStron 	    return (0);
194a30b880eStron 	VSTRING_ADDCH(result, ch6 << 5 | ch7);
195a30b880eStron     }
196a30b880eStron     VSTRING_TERMINATE(result);
197a30b880eStron     return (result);
198a30b880eStron }
199a30b880eStron 
200a30b880eStron #ifdef TEST
201a30b880eStron 
202a30b880eStron  /*
203a30b880eStron   * Proof-of-concept test program: convert to base 32 and back.
204a30b880eStron   */
205a30b880eStron 
206a30b880eStron #define STR(x)	vstring_str(x)
207a30b880eStron #define LEN(x)	VSTRING_LEN(x)
208a30b880eStron 
main(int unused_argc,char ** unused_argv)209a30b880eStron int     main(int unused_argc, char **unused_argv)
210a30b880eStron {
211a30b880eStron     VSTRING *b1 = vstring_alloc(1);
212a30b880eStron     VSTRING *b2 = vstring_alloc(1);
213a30b880eStron     VSTRING *test = vstring_alloc(1);
214a30b880eStron     int     i, j;
215a30b880eStron 
216a30b880eStron     /*
217a30b880eStron      * Test all byte values (except null) on all byte positions.
218a30b880eStron      */
219a30b880eStron     for (j = 0; j < 256; j++)
220a30b880eStron 	for (i = 1; i < 256; i++)
221a30b880eStron 	    VSTRING_ADDCH(test, i);
222a30b880eStron     VSTRING_TERMINATE(test);
223a30b880eStron 
224a30b880eStron #define DECODE(b,x,l) { \
225a30b880eStron 	if (base32_decode((b),(x),(l)) == 0) \
226a30b880eStron 	    msg_panic("bad base32: %s", (x)); \
227a30b880eStron     }
228a30b880eStron #define VERIFY(b,t,l) { \
229a30b880eStron 	if (memcmp((b), (t), (l)) != 0) \
230a30b880eStron 	    msg_panic("bad test: %s", (b)); \
231a30b880eStron     }
232a30b880eStron 
233a30b880eStron     /*
234a30b880eStron      * Test all padding variants.
235a30b880eStron      */
236a30b880eStron     for (i = 1; i <= 8; i++) {
237a30b880eStron 	base32_encode(b1, STR(test), LEN(test));
238a30b880eStron 	DECODE(b2, STR(b1), LEN(b1));
239a30b880eStron 	VERIFY(STR(b2), STR(test), LEN(test));
240a30b880eStron 
241a30b880eStron 	base32_encode(b1, STR(test), LEN(test));
242a30b880eStron 	base32_encode(b2, STR(b1), LEN(b1));
243a30b880eStron 	base32_encode(b1, STR(b2), LEN(b2));
244a30b880eStron 	DECODE(b2, STR(b1), LEN(b1));
245a30b880eStron 	DECODE(b1, STR(b2), LEN(b2));
246a30b880eStron 	DECODE(b2, STR(b1), LEN(b1));
247a30b880eStron 	VERIFY(STR(b2), STR(test), LEN(test));
248a30b880eStron 
249a30b880eStron 	base32_encode(b1, STR(test), LEN(test));
250a30b880eStron 	base32_encode(b2, STR(b1), LEN(b1));
251a30b880eStron 	base32_encode(b1, STR(b2), LEN(b2));
252a30b880eStron 	base32_encode(b2, STR(b1), LEN(b1));
253a30b880eStron 	base32_encode(b1, STR(b2), LEN(b2));
254a30b880eStron 	DECODE(b2, STR(b1), LEN(b1));
255a30b880eStron 	DECODE(b1, STR(b2), LEN(b2));
256a30b880eStron 	DECODE(b2, STR(b1), LEN(b1));
257a30b880eStron 	DECODE(b1, STR(b2), LEN(b2));
258a30b880eStron 	DECODE(b2, STR(b1), LEN(b1));
259a30b880eStron 	VERIFY(STR(b2), STR(test), LEN(test));
260a30b880eStron 	vstring_truncate(test, LEN(test) - 1);
261a30b880eStron     }
262a30b880eStron     vstring_free(test);
263a30b880eStron     vstring_free(b1);
264a30b880eStron     vstring_free(b2);
265a30b880eStron     return (0);
266a30b880eStron }
267a30b880eStron 
268a30b880eStron #endif
269