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