1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2020, Linaro Limited
4  * Copyright (c) 2014, STMicroelectronics International N.V.
5  */
6 #include "base64.h"
7 
8 static const char base64_table[] =
9 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
10 
_base64_enc_len(size_t size)11 size_t _base64_enc_len(size_t size)
12 {
13 	return 4 * ((size + 2) / 3) + 1;
14 }
15 
_base64_enc(const void * data,size_t dlen,char * buf,size_t * blen)16 bool _base64_enc(const void *data, size_t dlen, char *buf, size_t *blen)
17 {
18 	size_t n = 0;
19 	size_t boffs = 0;
20 	const unsigned char *d = data;
21 
22 	n = _base64_enc_len(dlen);
23 	if (*blen < n) {
24 		*blen = n;
25 		return false;
26 	}
27 
28 	for (n = 0; n < dlen; n += 3) {
29 		uint32_t igrp;
30 
31 		igrp = d[n];
32 		igrp <<= 8;
33 
34 		if ((n + 1) < dlen)
35 			igrp |= d[n + 1];
36 		igrp <<= 8;
37 
38 		if ((n + 2) < dlen)
39 			igrp |= d[n + 2];
40 
41 		buf[boffs] = base64_table[(igrp >> 18) & 0x3f];
42 		buf[boffs + 1] = base64_table[(igrp >> 12) & 0x3f];
43 		if ((n + 1) < dlen)
44 			buf[boffs + 2] = base64_table[(igrp >> 6) & 0x3f];
45 		else
46 			buf[boffs + 2] = '=';
47 		if ((n + 2) < dlen)
48 			buf[boffs + 3] = base64_table[igrp & 0x3f];
49 		else
50 			buf[boffs + 3] = '=';
51 
52 		boffs += 4;
53 	}
54 	buf[boffs++] = '\0';
55 
56 	*blen = boffs;
57 	return true;
58 }
59 
get_idx(char ch,uint8_t * idx)60 static bool get_idx(char ch, uint8_t *idx)
61 {
62 	size_t n = 0;
63 
64 	for (n = 0; base64_table[n] != '\0'; n++) {
65 		if (ch == base64_table[n]) {
66 			*idx = n;
67 			return true;
68 		}
69 	}
70 	return false;
71 }
72 
_base64_dec(const char * data,size_t size,void * buf,size_t * blen)73 bool _base64_dec(const char *data, size_t size, void *buf, size_t *blen)
74 {
75 	bool ret = false;
76 	size_t n = 0;
77 	uint8_t idx = 0;
78 	uint8_t *b = buf;
79 	size_t m = 0;
80 	size_t s = 0;
81 	uint8_t byte = 0;
82 
83 	for (n = 0; n < size && data[n] != '\0'; n++) {
84 		if (data[n] == '=')
85 			break;	/* Reached pad characters, we're done */
86 
87 		if (!get_idx(data[n], &idx))
88 			continue;
89 
90 		switch (s) {
91 		case 0:
92 			byte = idx << 2;
93 			s++;
94 			break;
95 		case 1:
96 			if (b && m < *blen)
97 				b[m] = byte | (idx >> 4);
98 			m++;
99 			byte = (idx & 0xf) << 4;
100 			s++;
101 			break;
102 		case 2:
103 			if (b && m < *blen)
104 				b[m] = byte | (idx >> 2);
105 			m++;
106 			byte = (idx & 0x3) << 6;
107 			s++;
108 			break;
109 		case 3:
110 			if (b && m < *blen)
111 				b[m] = byte | idx;
112 			m++;
113 			s = 0;
114 			break;
115 		default:
116 			return false;	/* "Can't happen" */
117 		}
118 	}
119 
120 	/*
121 	 * We don't detect if input was bad, but that's OK with the spec.
122 	 * We expect that each fully extracted byte is stored in output buffer.
123 	 */
124 	ret = (!m && !*blen) || (b && (m <= *blen));
125 	*blen = m;
126 
127 	return ret;
128 }
129