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