xref: /freebsd/lib/libc/net/base64.c (revision 513004a23dac3416f8f9c11aaa148bf8606c8617)
1ca785773SPeter Wemm /*
214b93edaSPeter Wemm  * Copyright (c) 1996, 1998 by Internet Software Consortium.
3ca785773SPeter Wemm  *
4ca785773SPeter Wemm  * Permission to use, copy, modify, and distribute this software for any
5ca785773SPeter Wemm  * purpose with or without fee is hereby granted, provided that the above
6ca785773SPeter Wemm  * copyright notice and this permission notice appear in all copies.
7ca785773SPeter Wemm  *
8ca785773SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9ca785773SPeter Wemm  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10ca785773SPeter Wemm  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11ca785773SPeter Wemm  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12ca785773SPeter Wemm  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13ca785773SPeter Wemm  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14ca785773SPeter Wemm  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15ca785773SPeter Wemm  * SOFTWARE.
16ca785773SPeter Wemm  */
17ca785773SPeter Wemm 
18ca785773SPeter Wemm /*
19ca785773SPeter Wemm  * Portions Copyright (c) 1995 by International Business Machines, Inc.
20ca785773SPeter Wemm  *
21ca785773SPeter Wemm  * International Business Machines, Inc. (hereinafter called IBM) grants
22ca785773SPeter Wemm  * permission under its copyrights to use, copy, modify, and distribute this
23ca785773SPeter Wemm  * Software with or without fee, provided that the above copyright notice and
24ca785773SPeter Wemm  * all paragraphs of this notice appear in all copies, and that the name of IBM
25ca785773SPeter Wemm  * not be used in connection with the marketing of any product incorporating
26ca785773SPeter Wemm  * the Software or modifications thereof, without specific, written prior
27ca785773SPeter Wemm  * permission.
28ca785773SPeter Wemm  *
29ca785773SPeter Wemm  * To the extent it has a right to do so, IBM grants an immunity from suit
30ca785773SPeter Wemm  * under its patents, if any, for the use, sale or manufacture of products to
31ca785773SPeter Wemm  * the extent that such products are used for performing Domain Name System
32ca785773SPeter Wemm  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
33ca785773SPeter Wemm  * granted for any product per se or for any other function of any product.
34ca785773SPeter Wemm  *
35ca785773SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
36ca785773SPeter Wemm  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
37ca785773SPeter Wemm  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
38ca785773SPeter Wemm  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
39ca785773SPeter Wemm  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
40ca785773SPeter Wemm  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
41ca785773SPeter Wemm  */
42ca785773SPeter Wemm 
43333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
44333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
4514b93edaSPeter Wemm 
46ca785773SPeter Wemm #include <sys/types.h>
47ca785773SPeter Wemm #include <sys/param.h>
48ca785773SPeter Wemm #include <sys/socket.h>
4914b93edaSPeter Wemm 
50ca785773SPeter Wemm #include <netinet/in.h>
51ca785773SPeter Wemm #include <arpa/inet.h>
52ca785773SPeter Wemm #include <arpa/nameser.h>
53ca785773SPeter Wemm 
54ca785773SPeter Wemm #include <ctype.h>
55ca785773SPeter Wemm #include <resolv.h>
56ca785773SPeter Wemm #include <stdio.h>
57ca785773SPeter Wemm #include <stdlib.h>
58ca785773SPeter Wemm #include <string.h>
59ca785773SPeter Wemm 
60ca785773SPeter Wemm #define Assert(Cond) if (!(Cond)) abort()
61ca785773SPeter Wemm 
62ca785773SPeter Wemm static const char Base64[] =
63ca785773SPeter Wemm 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
64ca785773SPeter Wemm static const char Pad64 = '=';
65ca785773SPeter Wemm 
66ca785773SPeter Wemm /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
67ca785773SPeter Wemm    The following encoding technique is taken from RFC 1521 by Borenstein
68ca785773SPeter Wemm    and Freed.  It is reproduced here in a slightly edited form for
69ca785773SPeter Wemm    convenience.
70ca785773SPeter Wemm 
71ca785773SPeter Wemm    A 65-character subset of US-ASCII is used, enabling 6 bits to be
72ca785773SPeter Wemm    represented per printable character. (The extra 65th character, "=",
73ca785773SPeter Wemm    is used to signify a special processing function.)
74ca785773SPeter Wemm 
75ca785773SPeter Wemm    The encoding process represents 24-bit groups of input bits as output
76ca785773SPeter Wemm    strings of 4 encoded characters. Proceeding from left to right, a
77ca785773SPeter Wemm    24-bit input group is formed by concatenating 3 8-bit input groups.
78ca785773SPeter Wemm    These 24 bits are then treated as 4 concatenated 6-bit groups, each
79ca785773SPeter Wemm    of which is translated into a single digit in the base64 alphabet.
80ca785773SPeter Wemm 
81ca785773SPeter Wemm    Each 6-bit group is used as an index into an array of 64 printable
82ca785773SPeter Wemm    characters. The character referenced by the index is placed in the
83ca785773SPeter Wemm    output string.
84ca785773SPeter Wemm 
85ca785773SPeter Wemm                          Table 1: The Base64 Alphabet
86ca785773SPeter Wemm 
87ca785773SPeter Wemm       Value Encoding  Value Encoding  Value Encoding  Value Encoding
88ca785773SPeter Wemm           0 A            17 R            34 i            51 z
89ca785773SPeter Wemm           1 B            18 S            35 j            52 0
90ca785773SPeter Wemm           2 C            19 T            36 k            53 1
91ca785773SPeter Wemm           3 D            20 U            37 l            54 2
92ca785773SPeter Wemm           4 E            21 V            38 m            55 3
93ca785773SPeter Wemm           5 F            22 W            39 n            56 4
94ca785773SPeter Wemm           6 G            23 X            40 o            57 5
95ca785773SPeter Wemm           7 H            24 Y            41 p            58 6
96ca785773SPeter Wemm           8 I            25 Z            42 q            59 7
97ca785773SPeter Wemm           9 J            26 a            43 r            60 8
98ca785773SPeter Wemm          10 K            27 b            44 s            61 9
99ca785773SPeter Wemm          11 L            28 c            45 t            62 +
100ca785773SPeter Wemm          12 M            29 d            46 u            63 /
101ca785773SPeter Wemm          13 N            30 e            47 v
102ca785773SPeter Wemm          14 O            31 f            48 w         (pad) =
103ca785773SPeter Wemm          15 P            32 g            49 x
104ca785773SPeter Wemm          16 Q            33 h            50 y
105ca785773SPeter Wemm 
106ca785773SPeter Wemm    Special processing is performed if fewer than 24 bits are available
107ca785773SPeter Wemm    at the end of the data being encoded.  A full encoding quantum is
108ca785773SPeter Wemm    always completed at the end of a quantity.  When fewer than 24 input
109ca785773SPeter Wemm    bits are available in an input group, zero bits are added (on the
110ca785773SPeter Wemm    right) to form an integral number of 6-bit groups.  Padding at the
111ca785773SPeter Wemm    end of the data is performed using the '=' character.
112ca785773SPeter Wemm 
113ca785773SPeter Wemm    Since all base64 input is an integral number of octets, only the
114ca785773SPeter Wemm          -------------------------------------------------
115ca785773SPeter Wemm    following cases can arise:
116ca785773SPeter Wemm 
117ca785773SPeter Wemm        (1) the final quantum of encoding input is an integral
118ca785773SPeter Wemm            multiple of 24 bits; here, the final unit of encoded
119ca785773SPeter Wemm 	   output will be an integral multiple of 4 characters
120ca785773SPeter Wemm 	   with no "=" padding,
121ca785773SPeter Wemm        (2) the final quantum of encoding input is exactly 8 bits;
122ca785773SPeter Wemm            here, the final unit of encoded output will be two
123ca785773SPeter Wemm 	   characters followed by two "=" padding characters, or
124ca785773SPeter Wemm        (3) the final quantum of encoding input is exactly 16 bits;
125ca785773SPeter Wemm            here, the final unit of encoded output will be three
126ca785773SPeter Wemm 	   characters followed by one "=" padding character.
127ca785773SPeter Wemm    */
128ca785773SPeter Wemm 
129ca785773SPeter Wemm int
13014b93edaSPeter Wemm b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
131ca785773SPeter Wemm 	size_t datalength = 0;
132ca785773SPeter Wemm 	u_char input[3];
133ca785773SPeter Wemm 	u_char output[4];
13414b93edaSPeter Wemm 	size_t i;
135ca785773SPeter Wemm 
136ca785773SPeter Wemm 	while (2 < srclength) {
137ca785773SPeter Wemm 		input[0] = *src++;
138ca785773SPeter Wemm 		input[1] = *src++;
139ca785773SPeter Wemm 		input[2] = *src++;
140ca785773SPeter Wemm 		srclength -= 3;
141ca785773SPeter Wemm 
142ca785773SPeter Wemm 		output[0] = input[0] >> 2;
143ca785773SPeter Wemm 		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
144ca785773SPeter Wemm 		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
145ca785773SPeter Wemm 		output[3] = input[2] & 0x3f;
146ca785773SPeter Wemm 		Assert(output[0] < 64);
147ca785773SPeter Wemm 		Assert(output[1] < 64);
148ca785773SPeter Wemm 		Assert(output[2] < 64);
149ca785773SPeter Wemm 		Assert(output[3] < 64);
150ca785773SPeter Wemm 
151ca785773SPeter Wemm 		if (datalength + 4 > targsize)
152ca785773SPeter Wemm 			return (-1);
153ca785773SPeter Wemm 		target[datalength++] = Base64[output[0]];
154ca785773SPeter Wemm 		target[datalength++] = Base64[output[1]];
155ca785773SPeter Wemm 		target[datalength++] = Base64[output[2]];
156ca785773SPeter Wemm 		target[datalength++] = Base64[output[3]];
157ca785773SPeter Wemm 	}
158ca785773SPeter Wemm 
159ca785773SPeter Wemm 	/* Now we worry about padding. */
160ca785773SPeter Wemm 	if (0 != srclength) {
161ca785773SPeter Wemm 		/* Get what's left. */
162ca785773SPeter Wemm 		input[0] = input[1] = input[2] = '\0';
163ca785773SPeter Wemm 		for (i = 0; i < srclength; i++)
164ca785773SPeter Wemm 			input[i] = *src++;
165ca785773SPeter Wemm 
166ca785773SPeter Wemm 		output[0] = input[0] >> 2;
167ca785773SPeter Wemm 		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
168ca785773SPeter Wemm 		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
169ca785773SPeter Wemm 		Assert(output[0] < 64);
170ca785773SPeter Wemm 		Assert(output[1] < 64);
171ca785773SPeter Wemm 		Assert(output[2] < 64);
172ca785773SPeter Wemm 
173ca785773SPeter Wemm 		if (datalength + 4 > targsize)
174ca785773SPeter Wemm 			return (-1);
175ca785773SPeter Wemm 		target[datalength++] = Base64[output[0]];
176ca785773SPeter Wemm 		target[datalength++] = Base64[output[1]];
177ca785773SPeter Wemm 		if (srclength == 1)
178ca785773SPeter Wemm 			target[datalength++] = Pad64;
179ca785773SPeter Wemm 		else
180ca785773SPeter Wemm 			target[datalength++] = Base64[output[2]];
181ca785773SPeter Wemm 		target[datalength++] = Pad64;
182ca785773SPeter Wemm 	}
183ca785773SPeter Wemm 	if (datalength >= targsize)
184ca785773SPeter Wemm 		return (-1);
185ca785773SPeter Wemm 	target[datalength] = '\0';	/* Returned value doesn't count \0. */
186ca785773SPeter Wemm 	return (datalength);
187ca785773SPeter Wemm }
188ca785773SPeter Wemm 
189ca785773SPeter Wemm /* skips all whitespace anywhere.
190ca785773SPeter Wemm    converts characters, four at a time, starting at (or after)
191ca785773SPeter Wemm    src from base - 64 numbers into three 8 bit bytes in the target area.
192ca785773SPeter Wemm    it returns the number of data bytes stored at the target, or -1 on error.
193ca785773SPeter Wemm  */
194ca785773SPeter Wemm 
195ca785773SPeter Wemm int
196d4287c30SEd Maste b64_pton(const char *src, u_char *target, size_t targsize)
197ca785773SPeter Wemm {
198ca785773SPeter Wemm 	int tarindex, state, ch;
199333cabbeSEd Maste 	u_char nextbyte;
200ca785773SPeter Wemm 	char *pos;
201ca785773SPeter Wemm 
202ca785773SPeter Wemm 	state = 0;
203ca785773SPeter Wemm 	tarindex = 0;
204ca785773SPeter Wemm 
205ca785773SPeter Wemm 	while ((ch = *src++) != '\0') {
2069ea99d34SAndrey A. Chernov 		if (isspace((unsigned char)ch))        /* Skip whitespace anywhere. */
207ca785773SPeter Wemm 			continue;
208ca785773SPeter Wemm 
209ca785773SPeter Wemm 		if (ch == Pad64)
210ca785773SPeter Wemm 			break;
211ca785773SPeter Wemm 
212ca785773SPeter Wemm 		pos = strchr(Base64, ch);
213*513004a2SPedro F. Giffuni 		if (pos == NULL)		/* A non-base64 character. */
214ca785773SPeter Wemm 			return (-1);
215ca785773SPeter Wemm 
216ca785773SPeter Wemm 		switch (state) {
217ca785773SPeter Wemm 		case 0:
218ca785773SPeter Wemm 			if (target) {
21914b93edaSPeter Wemm 				if ((size_t)tarindex >= targsize)
220ca785773SPeter Wemm 					return (-1);
221ca785773SPeter Wemm 				target[tarindex] = (pos - Base64) << 2;
222ca785773SPeter Wemm 			}
223ca785773SPeter Wemm 			state = 1;
224ca785773SPeter Wemm 			break;
225ca785773SPeter Wemm 		case 1:
226ca785773SPeter Wemm 			if (target) {
227333cabbeSEd Maste 				if ((size_t)tarindex >= targsize)
228ca785773SPeter Wemm 					return (-1);
229ca785773SPeter Wemm 				target[tarindex]   |=  (pos - Base64) >> 4;
230333cabbeSEd Maste 				nextbyte = ((pos - Base64) & 0x0f) << 4;
231333cabbeSEd Maste 				if ((size_t)tarindex + 1 < targsize)
232333cabbeSEd Maste 					target[tarindex + 1] = nextbyte;
233333cabbeSEd Maste 				else if (nextbyte)
234333cabbeSEd Maste 					return (-1);
235ca785773SPeter Wemm 			}
236ca785773SPeter Wemm 			tarindex++;
237ca785773SPeter Wemm 			state = 2;
238ca785773SPeter Wemm 			break;
239ca785773SPeter Wemm 		case 2:
240ca785773SPeter Wemm 			if (target) {
241333cabbeSEd Maste 				if ((size_t)tarindex >= targsize)
242ca785773SPeter Wemm 					return (-1);
243ca785773SPeter Wemm 				target[tarindex]   |=  (pos - Base64) >> 2;
244333cabbeSEd Maste 				nextbyte = ((pos - Base64) & 0x03) << 6;
245333cabbeSEd Maste 				if ((size_t)tarindex + 1 < targsize)
246333cabbeSEd Maste 					target[tarindex + 1] = nextbyte;
247333cabbeSEd Maste 				else if (nextbyte)
248333cabbeSEd Maste 					return (-1);
249ca785773SPeter Wemm 			}
250ca785773SPeter Wemm 			tarindex++;
251ca785773SPeter Wemm 			state = 3;
252ca785773SPeter Wemm 			break;
253ca785773SPeter Wemm 		case 3:
254ca785773SPeter Wemm 			if (target) {
25514b93edaSPeter Wemm 				if ((size_t)tarindex >= targsize)
256ca785773SPeter Wemm 					return (-1);
257ca785773SPeter Wemm 				target[tarindex] |= (pos - Base64);
258ca785773SPeter Wemm 			}
259ca785773SPeter Wemm 			tarindex++;
260ca785773SPeter Wemm 			state = 0;
261ca785773SPeter Wemm 			break;
262ca785773SPeter Wemm 		default:
263ca785773SPeter Wemm 			abort();
264ca785773SPeter Wemm 		}
265ca785773SPeter Wemm 	}
266ca785773SPeter Wemm 
267ca785773SPeter Wemm 	/*
268ca785773SPeter Wemm 	 * We are done decoding Base-64 chars.  Let's see if we ended
269ca785773SPeter Wemm 	 * on a byte boundary, and/or with erroneous trailing characters.
270ca785773SPeter Wemm 	 */
271ca785773SPeter Wemm 
272ca785773SPeter Wemm 	if (ch == Pad64) {		/* We got a pad char. */
273ca785773SPeter Wemm 		ch = *src++;		/* Skip it, get next. */
274ca785773SPeter Wemm 		switch (state) {
275ca785773SPeter Wemm 		case 0:		/* Invalid = in first position */
276ca785773SPeter Wemm 		case 1:		/* Invalid = in second position */
277ca785773SPeter Wemm 			return (-1);
278ca785773SPeter Wemm 
279ca785773SPeter Wemm 		case 2:		/* Valid, means one byte of info */
280ca785773SPeter Wemm 			/* Skip any number of spaces. */
28114b93edaSPeter Wemm 			for ((void)NULL; ch != '\0'; ch = *src++)
2829ea99d34SAndrey A. Chernov 				if (!isspace((unsigned char)ch))
283ca785773SPeter Wemm 					break;
284ca785773SPeter Wemm 			/* Make sure there is another trailing = sign. */
285ca785773SPeter Wemm 			if (ch != Pad64)
286ca785773SPeter Wemm 				return (-1);
287ca785773SPeter Wemm 			ch = *src++;		/* Skip the = */
288ca785773SPeter Wemm 			/* Fall through to "single trailing =" case. */
289ca785773SPeter Wemm 			/* FALLTHROUGH */
290ca785773SPeter Wemm 
291ca785773SPeter Wemm 		case 3:		/* Valid, means two bytes of info */
292ca785773SPeter Wemm 			/*
293ca785773SPeter Wemm 			 * We know this char is an =.  Is there anything but
294ca785773SPeter Wemm 			 * whitespace after it?
295ca785773SPeter Wemm 			 */
29614b93edaSPeter Wemm 			for ((void)NULL; ch != '\0'; ch = *src++)
2979ea99d34SAndrey A. Chernov 				if (!isspace((unsigned char)ch))
298ca785773SPeter Wemm 					return (-1);
299ca785773SPeter Wemm 
300ca785773SPeter Wemm 			/*
301ca785773SPeter Wemm 			 * Now make sure for cases 2 and 3 that the "extra"
302ca785773SPeter Wemm 			 * bits that slopped past the last full byte were
303ca785773SPeter Wemm 			 * zeros.  If we don't check them, they become a
304ca785773SPeter Wemm 			 * subliminal channel.
305ca785773SPeter Wemm 			 */
306333cabbeSEd Maste 			if (target && (size_t)tarindex < targsize &&
307333cabbeSEd Maste 			    target[tarindex] != 0)
308ca785773SPeter Wemm 				return (-1);
309ca785773SPeter Wemm 		}
310ca785773SPeter Wemm 	} else {
311ca785773SPeter Wemm 		/*
312ca785773SPeter Wemm 		 * We ended by seeing the end of the string.  Make sure we
313ca785773SPeter Wemm 		 * have no partial bytes lying around.
314ca785773SPeter Wemm 		 */
315ca785773SPeter Wemm 		if (state != 0)
316ca785773SPeter Wemm 			return (-1);
317ca785773SPeter Wemm 	}
318ca785773SPeter Wemm 
319ca785773SPeter Wemm 	return (tarindex);
320ca785773SPeter Wemm }
321