xref: /freebsd/contrib/ldns/compat/b64_ntop.c (revision ee7b0571c2c18bdec848ed2044223cc88db29bd8)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * Copyright (c) 1996, 1998 by Internet Software Consortium.
37b5038d7SDag-Erling Smørgrav  *
47b5038d7SDag-Erling Smørgrav  * Permission to use, copy, modify, and distribute this software for any
57b5038d7SDag-Erling Smørgrav  * purpose with or without fee is hereby granted, provided that the above
67b5038d7SDag-Erling Smørgrav  * copyright notice and this permission notice appear in all copies.
77b5038d7SDag-Erling Smørgrav  *
87b5038d7SDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
97b5038d7SDag-Erling Smørgrav  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
107b5038d7SDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
117b5038d7SDag-Erling Smørgrav  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
127b5038d7SDag-Erling Smørgrav  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
137b5038d7SDag-Erling Smørgrav  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
147b5038d7SDag-Erling Smørgrav  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
157b5038d7SDag-Erling Smørgrav  * SOFTWARE.
167b5038d7SDag-Erling Smørgrav  */
177b5038d7SDag-Erling Smørgrav 
187b5038d7SDag-Erling Smørgrav /*
197b5038d7SDag-Erling Smørgrav  * Portions Copyright (c) 1995 by International Business Machines, Inc.
207b5038d7SDag-Erling Smørgrav  *
217b5038d7SDag-Erling Smørgrav  * International Business Machines, Inc. (hereinafter called IBM) grants
227b5038d7SDag-Erling Smørgrav  * permission under its copyrights to use, copy, modify, and distribute this
237b5038d7SDag-Erling Smørgrav  * Software with or without fee, provided that the above copyright notice and
247b5038d7SDag-Erling Smørgrav  * all paragraphs of this notice appear in all copies, and that the name of IBM
257b5038d7SDag-Erling Smørgrav  * not be used in connection with the marketing of any product incorporating
267b5038d7SDag-Erling Smørgrav  * the Software or modifications thereof, without specific, written prior
277b5038d7SDag-Erling Smørgrav  * permission.
287b5038d7SDag-Erling Smørgrav  *
297b5038d7SDag-Erling Smørgrav  * To the extent it has a right to do so, IBM grants an immunity from suit
307b5038d7SDag-Erling Smørgrav  * under its patents, if any, for the use, sale or manufacture of products to
317b5038d7SDag-Erling Smørgrav  * the extent that such products are used for performing Domain Name System
327b5038d7SDag-Erling Smørgrav  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
337b5038d7SDag-Erling Smørgrav  * granted for any product per se or for any other function of any product.
347b5038d7SDag-Erling Smørgrav  *
357b5038d7SDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
367b5038d7SDag-Erling Smørgrav  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
377b5038d7SDag-Erling Smørgrav  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
387b5038d7SDag-Erling Smørgrav  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
397b5038d7SDag-Erling Smørgrav  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
407b5038d7SDag-Erling Smørgrav  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
417b5038d7SDag-Erling Smørgrav  */
427b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
437b5038d7SDag-Erling Smørgrav #include <ctype.h>
447b5038d7SDag-Erling Smørgrav #include <stdlib.h>
457b5038d7SDag-Erling Smørgrav #include <string.h>
467b5038d7SDag-Erling Smørgrav 
477b5038d7SDag-Erling Smørgrav static const char Base64[] =
487b5038d7SDag-Erling Smørgrav 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
497b5038d7SDag-Erling Smørgrav static const char Pad64 = '=';
507b5038d7SDag-Erling Smørgrav 
517b5038d7SDag-Erling Smørgrav /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
527b5038d7SDag-Erling Smørgrav    The following encoding technique is taken from RFC 1521 by Borenstein
537b5038d7SDag-Erling Smørgrav    and Freed.  It is reproduced here in a slightly edited form for
547b5038d7SDag-Erling Smørgrav    convenience.
557b5038d7SDag-Erling Smørgrav 
567b5038d7SDag-Erling Smørgrav    A 65-character subset of US-ASCII is used, enabling 6 bits to be
577b5038d7SDag-Erling Smørgrav    represented per printable character. (The extra 65th character, "=",
587b5038d7SDag-Erling Smørgrav    is used to signify a special processing function.)
597b5038d7SDag-Erling Smørgrav 
607b5038d7SDag-Erling Smørgrav    The encoding process represents 24-bit groups of input bits as output
617b5038d7SDag-Erling Smørgrav    strings of 4 encoded characters. Proceeding from left to right, a
627b5038d7SDag-Erling Smørgrav    24-bit input group is formed by concatenating 3 8-bit input groups.
637b5038d7SDag-Erling Smørgrav    These 24 bits are then treated as 4 concatenated 6-bit groups, each
647b5038d7SDag-Erling Smørgrav    of which is translated into a single digit in the base64 alphabet.
657b5038d7SDag-Erling Smørgrav 
667b5038d7SDag-Erling Smørgrav    Each 6-bit group is used as an index into an array of 64 printable
677b5038d7SDag-Erling Smørgrav    characters. The character referenced by the index is placed in the
687b5038d7SDag-Erling Smørgrav    output string.
697b5038d7SDag-Erling Smørgrav 
707b5038d7SDag-Erling Smørgrav                          Table 1: The Base64 Alphabet
717b5038d7SDag-Erling Smørgrav 
727b5038d7SDag-Erling Smørgrav       Value Encoding  Value Encoding  Value Encoding  Value Encoding
737b5038d7SDag-Erling Smørgrav           0 A            17 R            34 i            51 z
747b5038d7SDag-Erling Smørgrav           1 B            18 S            35 j            52 0
757b5038d7SDag-Erling Smørgrav           2 C            19 T            36 k            53 1
767b5038d7SDag-Erling Smørgrav           3 D            20 U            37 l            54 2
777b5038d7SDag-Erling Smørgrav           4 E            21 V            38 m            55 3
787b5038d7SDag-Erling Smørgrav           5 F            22 W            39 n            56 4
797b5038d7SDag-Erling Smørgrav           6 G            23 X            40 o            57 5
807b5038d7SDag-Erling Smørgrav           7 H            24 Y            41 p            58 6
817b5038d7SDag-Erling Smørgrav           8 I            25 Z            42 q            59 7
827b5038d7SDag-Erling Smørgrav           9 J            26 a            43 r            60 8
837b5038d7SDag-Erling Smørgrav          10 K            27 b            44 s            61 9
847b5038d7SDag-Erling Smørgrav          11 L            28 c            45 t            62 +
857b5038d7SDag-Erling Smørgrav          12 M            29 d            46 u            63 /
867b5038d7SDag-Erling Smørgrav          13 N            30 e            47 v
877b5038d7SDag-Erling Smørgrav          14 O            31 f            48 w         (pad) =
887b5038d7SDag-Erling Smørgrav          15 P            32 g            49 x
897b5038d7SDag-Erling Smørgrav          16 Q            33 h            50 y
907b5038d7SDag-Erling Smørgrav 
917b5038d7SDag-Erling Smørgrav    Special processing is performed if fewer than 24 bits are available
927b5038d7SDag-Erling Smørgrav    at the end of the data being encoded.  A full encoding quantum is
937b5038d7SDag-Erling Smørgrav    always completed at the end of a quantity.  When fewer than 24 input
947b5038d7SDag-Erling Smørgrav    bits are available in an input group, zero bits are added (on the
957b5038d7SDag-Erling Smørgrav    right) to form an integral number of 6-bit groups.  Padding at the
967b5038d7SDag-Erling Smørgrav    end of the data is performed using the '=' character.
977b5038d7SDag-Erling Smørgrav 
987b5038d7SDag-Erling Smørgrav    Since all base64 input is an integral number of octets, only the
997b5038d7SDag-Erling Smørgrav          -------------------------------------------------
1007b5038d7SDag-Erling Smørgrav    following cases can arise:
1017b5038d7SDag-Erling Smørgrav 
1027b5038d7SDag-Erling Smørgrav        (1) the final quantum of encoding input is an integral
1037b5038d7SDag-Erling Smørgrav            multiple of 24 bits; here, the final unit of encoded
1047b5038d7SDag-Erling Smørgrav 	   output will be an integral multiple of 4 characters
1057b5038d7SDag-Erling Smørgrav 	   with no "=" padding,
1067b5038d7SDag-Erling Smørgrav        (2) the final quantum of encoding input is exactly 8 bits;
1077b5038d7SDag-Erling Smørgrav            here, the final unit of encoded output will be two
1087b5038d7SDag-Erling Smørgrav 	   characters followed by two "=" padding characters, or
1097b5038d7SDag-Erling Smørgrav        (3) the final quantum of encoding input is exactly 16 bits;
1107b5038d7SDag-Erling Smørgrav            here, the final unit of encoded output will be three
1117b5038d7SDag-Erling Smørgrav 	   characters followed by one "=" padding character.
1127b5038d7SDag-Erling Smørgrav    */
1137b5038d7SDag-Erling Smørgrav 
1147b5038d7SDag-Erling Smørgrav int
ldns_b64_ntop(uint8_t const * src,size_t srclength,char * target,size_t targsize)1157b5038d7SDag-Erling Smørgrav ldns_b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
1167b5038d7SDag-Erling Smørgrav 	size_t datalength = 0;
1177b5038d7SDag-Erling Smørgrav 	uint8_t input[3];
1187b5038d7SDag-Erling Smørgrav 	uint8_t output[4];
1197b5038d7SDag-Erling Smørgrav 	size_t i;
1207b5038d7SDag-Erling Smørgrav 
1217b5038d7SDag-Erling Smørgrav 	if (srclength == 0) {
1227b5038d7SDag-Erling Smørgrav 		if (targsize > 0) {
1237b5038d7SDag-Erling Smørgrav 			target[0] = '\0';
1247b5038d7SDag-Erling Smørgrav 			return 0;
1257b5038d7SDag-Erling Smørgrav 		} else {
1267b5038d7SDag-Erling Smørgrav 			return -1;
1277b5038d7SDag-Erling Smørgrav 		}
1287b5038d7SDag-Erling Smørgrav 	}
1297b5038d7SDag-Erling Smørgrav 
1307b5038d7SDag-Erling Smørgrav 	while (2 < srclength) {
1317b5038d7SDag-Erling Smørgrav 		input[0] = *src++;
1327b5038d7SDag-Erling Smørgrav 		input[1] = *src++;
1337b5038d7SDag-Erling Smørgrav 		input[2] = *src++;
1347b5038d7SDag-Erling Smørgrav 		srclength -= 3;
1357b5038d7SDag-Erling Smørgrav 
1367b5038d7SDag-Erling Smørgrav 		output[0] = input[0] >> 2;
1377b5038d7SDag-Erling Smørgrav 		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
1387b5038d7SDag-Erling Smørgrav 		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
1397b5038d7SDag-Erling Smørgrav 		output[3] = input[2] & 0x3f;
140*17d15b25SDag-Erling Smørgrav 		assert(output[0] < 64);
141*17d15b25SDag-Erling Smørgrav 		assert(output[1] < 64);
142*17d15b25SDag-Erling Smørgrav 		assert(output[2] < 64);
143*17d15b25SDag-Erling Smørgrav 		assert(output[3] < 64);
1447b5038d7SDag-Erling Smørgrav 
1457b5038d7SDag-Erling Smørgrav 		if (datalength + 4 > targsize) {
1467b5038d7SDag-Erling Smørgrav 			return (-1);
1477b5038d7SDag-Erling Smørgrav 		}
1487b5038d7SDag-Erling Smørgrav 		target[datalength++] = Base64[output[0]];
1497b5038d7SDag-Erling Smørgrav 		target[datalength++] = Base64[output[1]];
1507b5038d7SDag-Erling Smørgrav 		target[datalength++] = Base64[output[2]];
1517b5038d7SDag-Erling Smørgrav 		target[datalength++] = Base64[output[3]];
1527b5038d7SDag-Erling Smørgrav 	}
1537b5038d7SDag-Erling Smørgrav 
1547b5038d7SDag-Erling Smørgrav 	/* Now we worry about padding. */
1557b5038d7SDag-Erling Smørgrav 	if (0 != srclength) {
1567b5038d7SDag-Erling Smørgrav 		/* Get what's left. */
1577b5038d7SDag-Erling Smørgrav 		input[0] = input[1] = input[2] = (uint8_t) '\0';
1587b5038d7SDag-Erling Smørgrav 		for (i = 0; i < srclength; i++)
1597b5038d7SDag-Erling Smørgrav 			input[i] = *src++;
1607b5038d7SDag-Erling Smørgrav 
1617b5038d7SDag-Erling Smørgrav 		output[0] = input[0] >> 2;
1627b5038d7SDag-Erling Smørgrav 		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
1637b5038d7SDag-Erling Smørgrav 		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
164*17d15b25SDag-Erling Smørgrav 		assert(output[0] < 64);
165*17d15b25SDag-Erling Smørgrav 		assert(output[1] < 64);
166*17d15b25SDag-Erling Smørgrav 		assert(output[2] < 64);
1677b5038d7SDag-Erling Smørgrav 
1687b5038d7SDag-Erling Smørgrav 		if (datalength + 4 > targsize) {
1697b5038d7SDag-Erling Smørgrav 			return (-2);
1707b5038d7SDag-Erling Smørgrav 		}
1717b5038d7SDag-Erling Smørgrav 		target[datalength++] = Base64[output[0]];
1727b5038d7SDag-Erling Smørgrav 		target[datalength++] = Base64[output[1]];
1737b5038d7SDag-Erling Smørgrav 		if (srclength == 1) {
1747b5038d7SDag-Erling Smørgrav 			target[datalength++] = Pad64;
1757b5038d7SDag-Erling Smørgrav 		} else {
1767b5038d7SDag-Erling Smørgrav 			target[datalength++] = Base64[output[2]];
1777b5038d7SDag-Erling Smørgrav 		}
1787b5038d7SDag-Erling Smørgrav 		target[datalength++] = Pad64;
1797b5038d7SDag-Erling Smørgrav 	}
1807b5038d7SDag-Erling Smørgrav 	if (datalength >= targsize) {
1817b5038d7SDag-Erling Smørgrav 		return (-3);
1827b5038d7SDag-Erling Smørgrav 	}
1837b5038d7SDag-Erling Smørgrav 	target[datalength] = '\0';	/* Returned value doesn't count \0. */
1847b5038d7SDag-Erling Smørgrav 	return (int) (datalength);
1857b5038d7SDag-Erling Smørgrav }
186