xref: /optee_os/lib/libmbedtls/mbedtls/library/base64.c (revision 32b3180828fa15a49ccc86ecb4be9d274c140c89)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  RFC 1521 base64 encoding/decoding
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
57901324dSJerome Forissier  *  SPDX-License-Identifier: Apache-2.0
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  */
19817466cbSJens Wiklander 
207901324dSJerome Forissier #include "common.h"
21817466cbSJens Wiklander 
22817466cbSJens Wiklander #if defined(MBEDTLS_BASE64_C)
23817466cbSJens Wiklander 
24817466cbSJens Wiklander #include "mbedtls/base64.h"
25039e02dfSJerome Forissier #include "constant_time_internal.h"
26817466cbSJens Wiklander 
27817466cbSJens Wiklander #include <stdint.h>
28817466cbSJens Wiklander 
29817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
30817466cbSJens Wiklander #include <string.h>
31817466cbSJens Wiklander #include "mbedtls/platform.h"
32817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
33817466cbSJens Wiklander 
34817466cbSJens Wiklander #define BASE64_SIZE_T_MAX   ((size_t) -1)   /* SIZE_T_MAX is not standard */
35817466cbSJens Wiklander 
36817466cbSJens Wiklander /*
37817466cbSJens Wiklander  * Encode a buffer into base64 format
38817466cbSJens Wiklander  */
39817466cbSJens Wiklander int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
40817466cbSJens Wiklander                           const unsigned char *src, size_t slen)
41817466cbSJens Wiklander {
42817466cbSJens Wiklander     size_t i, n;
43817466cbSJens Wiklander     int C1, C2, C3;
44817466cbSJens Wiklander     unsigned char *p;
45817466cbSJens Wiklander 
46*32b31808SJens Wiklander     if (slen == 0) {
47817466cbSJens Wiklander         *olen = 0;
48*32b31808SJens Wiklander         return 0;
49817466cbSJens Wiklander     }
50817466cbSJens Wiklander 
51817466cbSJens Wiklander     n = slen / 3 + (slen % 3 != 0);
52817466cbSJens Wiklander 
53*32b31808SJens Wiklander     if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
54817466cbSJens Wiklander         *olen = BASE64_SIZE_T_MAX;
55*32b31808SJens Wiklander         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
56817466cbSJens Wiklander     }
57817466cbSJens Wiklander 
58817466cbSJens Wiklander     n *= 4;
59817466cbSJens Wiklander 
60*32b31808SJens Wiklander     if ((dlen < n + 1) || (NULL == dst)) {
61817466cbSJens Wiklander         *olen = n + 1;
62*32b31808SJens Wiklander         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
63817466cbSJens Wiklander     }
64817466cbSJens Wiklander 
65817466cbSJens Wiklander     n = (slen / 3) * 3;
66817466cbSJens Wiklander 
67*32b31808SJens Wiklander     for (i = 0, p = dst; i < n; i += 3) {
68817466cbSJens Wiklander         C1 = *src++;
69817466cbSJens Wiklander         C2 = *src++;
70817466cbSJens Wiklander         C3 = *src++;
71817466cbSJens Wiklander 
72039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
73039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char((((C1 &  3) << 4) + (C2 >> 4))
74039e02dfSJerome Forissier                                           & 0x3F);
75039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
76039e02dfSJerome Forissier                                           & 0x3F);
77039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
78817466cbSJens Wiklander     }
79817466cbSJens Wiklander 
80*32b31808SJens Wiklander     if (i < slen) {
81817466cbSJens Wiklander         C1 = *src++;
82817466cbSJens Wiklander         C2 = ((i + 1) < slen) ? *src++ : 0;
83817466cbSJens Wiklander 
84039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
85039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
86039e02dfSJerome Forissier                                           & 0x3F);
87817466cbSJens Wiklander 
88*32b31808SJens Wiklander         if ((i + 1) < slen) {
89039e02dfSJerome Forissier             *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
90*32b31808SJens Wiklander         } else {
91*32b31808SJens Wiklander             *p++ = '=';
92*32b31808SJens Wiklander         }
93817466cbSJens Wiklander 
94817466cbSJens Wiklander         *p++ = '=';
95817466cbSJens Wiklander     }
96817466cbSJens Wiklander 
97817466cbSJens Wiklander     *olen = p - dst;
98817466cbSJens Wiklander     *p = 0;
99817466cbSJens Wiklander 
100*32b31808SJens Wiklander     return 0;
101817466cbSJens Wiklander }
102817466cbSJens Wiklander 
103817466cbSJens Wiklander /*
104817466cbSJens Wiklander  * Decode a base64-formatted buffer
105817466cbSJens Wiklander  */
106817466cbSJens Wiklander int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,
107817466cbSJens Wiklander                           const unsigned char *src, size_t slen)
108817466cbSJens Wiklander {
109039e02dfSJerome Forissier     size_t i; /* index in source */
110039e02dfSJerome Forissier     size_t n; /* number of digits or trailing = in source */
111039e02dfSJerome Forissier     uint32_t x; /* value accumulator */
112039e02dfSJerome Forissier     unsigned accumulated_digits = 0;
113039e02dfSJerome Forissier     unsigned equals = 0;
114039e02dfSJerome Forissier     int spaces_present = 0;
115817466cbSJens Wiklander     unsigned char *p;
116817466cbSJens Wiklander 
117817466cbSJens Wiklander     /* First pass: check for validity and get output length */
118*32b31808SJens Wiklander     for (i = n = 0; i < slen; i++) {
119817466cbSJens Wiklander         /* Skip spaces before checking for EOL */
120039e02dfSJerome Forissier         spaces_present = 0;
121*32b31808SJens Wiklander         while (i < slen && src[i] == ' ') {
122817466cbSJens Wiklander             ++i;
123039e02dfSJerome Forissier             spaces_present = 1;
124817466cbSJens Wiklander         }
125817466cbSJens Wiklander 
126817466cbSJens Wiklander         /* Spaces at end of buffer are OK */
127*32b31808SJens Wiklander         if (i == slen) {
128817466cbSJens Wiklander             break;
129*32b31808SJens Wiklander         }
130817466cbSJens Wiklander 
131817466cbSJens Wiklander         if ((slen - i) >= 2 &&
132*32b31808SJens Wiklander             src[i] == '\r' && src[i + 1] == '\n') {
133817466cbSJens Wiklander             continue;
134*32b31808SJens Wiklander         }
135817466cbSJens Wiklander 
136*32b31808SJens Wiklander         if (src[i] == '\n') {
137817466cbSJens Wiklander             continue;
138*32b31808SJens Wiklander         }
139817466cbSJens Wiklander 
140817466cbSJens Wiklander         /* Space inside a line is an error */
141*32b31808SJens Wiklander         if (spaces_present) {
142*32b31808SJens Wiklander             return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
143039e02dfSJerome Forissier         }
144*32b31808SJens Wiklander 
145*32b31808SJens Wiklander         if (src[i] > 127) {
146*32b31808SJens Wiklander             return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
147*32b31808SJens Wiklander         }
148*32b31808SJens Wiklander 
149*32b31808SJens Wiklander         if (src[i] == '=') {
150*32b31808SJens Wiklander             if (++equals > 2) {
151*32b31808SJens Wiklander                 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
152*32b31808SJens Wiklander             }
153*32b31808SJens Wiklander         } else {
154*32b31808SJens Wiklander             if (equals != 0) {
155*32b31808SJens Wiklander                 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
156*32b31808SJens Wiklander             }
157*32b31808SJens Wiklander             if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
158*32b31808SJens Wiklander                 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
159*32b31808SJens Wiklander             }
160039e02dfSJerome Forissier         }
161817466cbSJens Wiklander         n++;
162817466cbSJens Wiklander     }
163817466cbSJens Wiklander 
164*32b31808SJens Wiklander     if (n == 0) {
165817466cbSJens Wiklander         *olen = 0;
166*32b31808SJens Wiklander         return 0;
167817466cbSJens Wiklander     }
168817466cbSJens Wiklander 
169817466cbSJens Wiklander     /* The following expression is to calculate the following formula without
170817466cbSJens Wiklander      * risk of integer overflow in n:
171817466cbSJens Wiklander      *     n = ( ( n * 6 ) + 7 ) >> 3;
172817466cbSJens Wiklander      */
173817466cbSJens Wiklander     n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
174039e02dfSJerome Forissier     n -= equals;
175817466cbSJens Wiklander 
176*32b31808SJens Wiklander     if (dst == NULL || dlen < n) {
177817466cbSJens Wiklander         *olen = n;
178*32b31808SJens Wiklander         return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
179817466cbSJens Wiklander     }
180817466cbSJens Wiklander 
181039e02dfSJerome Forissier     equals = 0;
182*32b31808SJens Wiklander     for (x = 0, p = dst; i > 0; i--, src++) {
183*32b31808SJens Wiklander         if (*src == '\r' || *src == '\n' || *src == ' ') {
184817466cbSJens Wiklander             continue;
185*32b31808SJens Wiklander         }
186817466cbSJens Wiklander 
187039e02dfSJerome Forissier         x = x << 6;
188*32b31808SJens Wiklander         if (*src == '=') {
189039e02dfSJerome Forissier             ++equals;
190*32b31808SJens Wiklander         } else {
191039e02dfSJerome Forissier             x |= mbedtls_ct_base64_dec_value(*src);
192*32b31808SJens Wiklander         }
1937901324dSJerome Forissier 
194*32b31808SJens Wiklander         if (++accumulated_digits == 4) {
195039e02dfSJerome Forissier             accumulated_digits = 0;
196039e02dfSJerome Forissier             *p++ = MBEDTLS_BYTE_2(x);
197*32b31808SJens Wiklander             if (equals <= 1) {
198*32b31808SJens Wiklander                 *p++ = MBEDTLS_BYTE_1(x);
199*32b31808SJens Wiklander             }
200*32b31808SJens Wiklander             if (equals <= 0) {
201*32b31808SJens Wiklander                 *p++ = MBEDTLS_BYTE_0(x);
202*32b31808SJens Wiklander             }
203817466cbSJens Wiklander         }
204817466cbSJens Wiklander     }
205817466cbSJens Wiklander 
206817466cbSJens Wiklander     *olen = p - dst;
207817466cbSJens Wiklander 
208*32b31808SJens Wiklander     return 0;
209817466cbSJens Wiklander }
210817466cbSJens Wiklander 
211817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
212817466cbSJens Wiklander 
213817466cbSJens Wiklander static const unsigned char base64_test_dec[64] =
214817466cbSJens Wiklander {
215817466cbSJens Wiklander     0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
216817466cbSJens Wiklander     0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
217817466cbSJens Wiklander     0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
218817466cbSJens Wiklander     0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
219817466cbSJens Wiklander     0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
220817466cbSJens Wiklander     0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
221817466cbSJens Wiklander     0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
222817466cbSJens Wiklander     0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
223817466cbSJens Wiklander };
224817466cbSJens Wiklander 
225817466cbSJens Wiklander static const unsigned char base64_test_enc[] =
226817466cbSJens Wiklander     "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
227817466cbSJens Wiklander     "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
228817466cbSJens Wiklander 
229817466cbSJens Wiklander /*
230817466cbSJens Wiklander  * Checkup routine
231817466cbSJens Wiklander  */
232817466cbSJens Wiklander int mbedtls_base64_self_test(int verbose)
233817466cbSJens Wiklander {
234817466cbSJens Wiklander     size_t len;
235817466cbSJens Wiklander     const unsigned char *src;
236817466cbSJens Wiklander     unsigned char buffer[128];
237817466cbSJens Wiklander 
238*32b31808SJens Wiklander     if (verbose != 0) {
239817466cbSJens Wiklander         mbedtls_printf("  Base64 encoding test: ");
240*32b31808SJens Wiklander     }
241817466cbSJens Wiklander 
242817466cbSJens Wiklander     src = base64_test_dec;
243817466cbSJens Wiklander 
244817466cbSJens Wiklander     if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
245*32b31808SJens Wiklander         memcmp(base64_test_enc, buffer, 88) != 0) {
246*32b31808SJens Wiklander         if (verbose != 0) {
247817466cbSJens Wiklander             mbedtls_printf("failed\n");
248817466cbSJens Wiklander         }
249817466cbSJens Wiklander 
250*32b31808SJens Wiklander         return 1;
251*32b31808SJens Wiklander     }
252*32b31808SJens Wiklander 
253*32b31808SJens Wiklander     if (verbose != 0) {
254817466cbSJens Wiklander         mbedtls_printf("passed\n  Base64 decoding test: ");
255*32b31808SJens Wiklander     }
256817466cbSJens Wiklander 
257817466cbSJens Wiklander     src = base64_test_enc;
258817466cbSJens Wiklander 
259817466cbSJens Wiklander     if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
260*32b31808SJens Wiklander         memcmp(base64_test_dec, buffer, 64) != 0) {
261*32b31808SJens Wiklander         if (verbose != 0) {
262817466cbSJens Wiklander             mbedtls_printf("failed\n");
263817466cbSJens Wiklander         }
264817466cbSJens Wiklander 
265*32b31808SJens Wiklander         return 1;
266*32b31808SJens Wiklander     }
267817466cbSJens Wiklander 
268*32b31808SJens Wiklander     if (verbose != 0) {
269*32b31808SJens Wiklander         mbedtls_printf("passed\n\n");
270*32b31808SJens Wiklander     }
271*32b31808SJens Wiklander 
272*32b31808SJens Wiklander     return 0;
273817466cbSJens Wiklander }
274817466cbSJens Wiklander 
275817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
276817466cbSJens Wiklander 
277817466cbSJens Wiklander #endif /* MBEDTLS_BASE64_C */
278