blob: 9677dee5b29577b0decaa2c55ffa2036fe78e2d8 [file] [log] [blame]
Jens Wiklander817466c2018-05-22 13:49:31 +02001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Jerome Forissier79013242021-07-28 10:24:04 +02004 * Copyright The Mbed TLS Contributors
Tom Van Eyckc1633172024-04-09 18:44:13 +02005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Jens Wiklander817466c2018-05-22 13:49:31 +02006 */
7
Tom Van Eyckc1633172024-04-09 18:44:13 +02008#include <limits.h>
9
Jerome Forissier79013242021-07-28 10:24:04 +020010#include "common.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020011
12#if defined(MBEDTLS_BASE64_C)
13
14#include "mbedtls/base64.h"
Tom Van Eyckc1633172024-04-09 18:44:13 +020015#include "base64_internal.h"
Jerome Forissier039e02d2022-08-09 17:10:15 +020016#include "constant_time_internal.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020017
18#include <stdint.h>
19
20#if defined(MBEDTLS_SELF_TEST)
21#include <string.h>
Jens Wiklander817466c2018-05-22 13:49:31 +020022#include "mbedtls/platform.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020023#endif /* MBEDTLS_SELF_TEST */
24
Tom Van Eyckc1633172024-04-09 18:44:13 +020025MBEDTLS_STATIC_TESTABLE
26unsigned char mbedtls_ct_base64_enc_char(unsigned char value)
27{
28 unsigned char digit = 0;
29 /* For each range of values, if value is in that range, mask digit with
30 * the corresponding value. Since value can only be in a single range,
31 * only at most one masking will change digit. */
32 digit |= mbedtls_ct_uchar_in_range_if(0, 25, value, 'A' + value);
33 digit |= mbedtls_ct_uchar_in_range_if(26, 51, value, 'a' + value - 26);
34 digit |= mbedtls_ct_uchar_in_range_if(52, 61, value, '0' + value - 52);
35 digit |= mbedtls_ct_uchar_in_range_if(62, 62, value, '+');
36 digit |= mbedtls_ct_uchar_in_range_if(63, 63, value, '/');
37 return digit;
38}
39
40MBEDTLS_STATIC_TESTABLE
41signed char mbedtls_ct_base64_dec_value(unsigned char c)
42{
43 unsigned char val = 0;
44 /* For each range of digits, if c is in that range, mask val with
45 * the corresponding value. Since c can only be in a single range,
46 * only at most one masking will change val. Set val to one plus
47 * the desired value so that it stays 0 if c is in none of the ranges. */
48 val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' + 0 + 1);
49 val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1);
50 val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1);
51 val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1);
52 val |= mbedtls_ct_uchar_in_range_if('/', '/', c, c - '/' + 63 + 1);
53 /* At this point, val is 0 if c is an invalid digit and v+1 if c is
54 * a digit with the value v. */
55 return val - 1;
56}
Jens Wiklander817466c2018-05-22 13:49:31 +020057
58/*
59 * Encode a buffer into base64 format
60 */
Jens Wiklander32b31802023-10-06 16:59:46 +020061int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
62 const unsigned char *src, size_t slen)
Jens Wiklander817466c2018-05-22 13:49:31 +020063{
64 size_t i, n;
65 int C1, C2, C3;
66 unsigned char *p;
67
Jens Wiklander32b31802023-10-06 16:59:46 +020068 if (slen == 0) {
Jens Wiklander817466c2018-05-22 13:49:31 +020069 *olen = 0;
Jens Wiklander32b31802023-10-06 16:59:46 +020070 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +020071 }
72
Jens Wiklander32b31802023-10-06 16:59:46 +020073 n = slen / 3 + (slen % 3 != 0);
Jens Wiklander817466c2018-05-22 13:49:31 +020074
Tom Van Eyckc1633172024-04-09 18:44:13 +020075 if (n > (SIZE_MAX - 1) / 4) {
76 *olen = SIZE_MAX;
Jens Wiklander32b31802023-10-06 16:59:46 +020077 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Jens Wiklander817466c2018-05-22 13:49:31 +020078 }
79
80 n *= 4;
81
Jens Wiklander32b31802023-10-06 16:59:46 +020082 if ((dlen < n + 1) || (NULL == dst)) {
Jens Wiklander817466c2018-05-22 13:49:31 +020083 *olen = n + 1;
Jens Wiklander32b31802023-10-06 16:59:46 +020084 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Jens Wiklander817466c2018-05-22 13:49:31 +020085 }
86
Jens Wiklander32b31802023-10-06 16:59:46 +020087 n = (slen / 3) * 3;
Jens Wiklander817466c2018-05-22 13:49:31 +020088
Jens Wiklander32b31802023-10-06 16:59:46 +020089 for (i = 0, p = dst; i < n; i += 3) {
Jens Wiklander817466c2018-05-22 13:49:31 +020090 C1 = *src++;
91 C2 = *src++;
92 C3 = *src++;
93
Jens Wiklander32b31802023-10-06 16:59:46 +020094 *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
95 *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
96 & 0x3F);
97 *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
98 & 0x3F);
99 *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
Jens Wiklander817466c2018-05-22 13:49:31 +0200100 }
101
Jens Wiklander32b31802023-10-06 16:59:46 +0200102 if (i < slen) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200103 C1 = *src++;
Jens Wiklander32b31802023-10-06 16:59:46 +0200104 C2 = ((i + 1) < slen) ? *src++ : 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200105
Jens Wiklander32b31802023-10-06 16:59:46 +0200106 *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
107 *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
108 & 0x3F);
Jens Wiklander817466c2018-05-22 13:49:31 +0200109
Jens Wiklander32b31802023-10-06 16:59:46 +0200110 if ((i + 1) < slen) {
111 *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
112 } else {
113 *p++ = '=';
114 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200115
116 *p++ = '=';
117 }
118
Tom Van Eyckc1633172024-04-09 18:44:13 +0200119 *olen = (size_t) (p - dst);
Jens Wiklander817466c2018-05-22 13:49:31 +0200120 *p = 0;
121
Jens Wiklander32b31802023-10-06 16:59:46 +0200122 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200123}
124
125/*
126 * Decode a base64-formatted buffer
127 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200128int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,
129 const unsigned char *src, size_t slen)
Jens Wiklander817466c2018-05-22 13:49:31 +0200130{
Jerome Forissier039e02d2022-08-09 17:10:15 +0200131 size_t i; /* index in source */
132 size_t n; /* number of digits or trailing = in source */
133 uint32_t x; /* value accumulator */
134 unsigned accumulated_digits = 0;
135 unsigned equals = 0;
136 int spaces_present = 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200137 unsigned char *p;
138
139 /* First pass: check for validity and get output length */
Jens Wiklander32b31802023-10-06 16:59:46 +0200140 for (i = n = 0; i < slen; i++) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200141 /* Skip spaces before checking for EOL */
Jerome Forissier039e02d2022-08-09 17:10:15 +0200142 spaces_present = 0;
Jens Wiklander32b31802023-10-06 16:59:46 +0200143 while (i < slen && src[i] == ' ') {
Jens Wiklander817466c2018-05-22 13:49:31 +0200144 ++i;
Jerome Forissier039e02d2022-08-09 17:10:15 +0200145 spaces_present = 1;
Jens Wiklander817466c2018-05-22 13:49:31 +0200146 }
147
148 /* Spaces at end of buffer are OK */
Jens Wiklander32b31802023-10-06 16:59:46 +0200149 if (i == slen) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200150 break;
Jens Wiklander32b31802023-10-06 16:59:46 +0200151 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200152
Jens Wiklander32b31802023-10-06 16:59:46 +0200153 if ((slen - i) >= 2 &&
154 src[i] == '\r' && src[i + 1] == '\n') {
Jens Wiklander817466c2018-05-22 13:49:31 +0200155 continue;
Jens Wiklander32b31802023-10-06 16:59:46 +0200156 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200157
Jens Wiklander32b31802023-10-06 16:59:46 +0200158 if (src[i] == '\n') {
Jens Wiklander817466c2018-05-22 13:49:31 +0200159 continue;
Jens Wiklander32b31802023-10-06 16:59:46 +0200160 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200161
162 /* Space inside a line is an error */
Jens Wiklander32b31802023-10-06 16:59:46 +0200163 if (spaces_present) {
164 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
Jerome Forissier039e02d2022-08-09 17:10:15 +0200165 }
Jens Wiklander32b31802023-10-06 16:59:46 +0200166
167 if (src[i] > 127) {
168 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
169 }
170
171 if (src[i] == '=') {
172 if (++equals > 2) {
173 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
174 }
175 } else {
176 if (equals != 0) {
177 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
178 }
179 if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
180 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
181 }
Jerome Forissier039e02d2022-08-09 17:10:15 +0200182 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200183 n++;
184 }
185
Jens Wiklander32b31802023-10-06 16:59:46 +0200186 if (n == 0) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200187 *olen = 0;
Jens Wiklander32b31802023-10-06 16:59:46 +0200188 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200189 }
190
191 /* The following expression is to calculate the following formula without
192 * risk of integer overflow in n:
193 * n = ( ( n * 6 ) + 7 ) >> 3;
194 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200195 n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
Jerome Forissier039e02d2022-08-09 17:10:15 +0200196 n -= equals;
Jens Wiklander817466c2018-05-22 13:49:31 +0200197
Jens Wiklander32b31802023-10-06 16:59:46 +0200198 if (dst == NULL || dlen < n) {
Jens Wiklander817466c2018-05-22 13:49:31 +0200199 *olen = n;
Jens Wiklander32b31802023-10-06 16:59:46 +0200200 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Jens Wiklander817466c2018-05-22 13:49:31 +0200201 }
202
Jerome Forissier039e02d2022-08-09 17:10:15 +0200203 equals = 0;
Jens Wiklander32b31802023-10-06 16:59:46 +0200204 for (x = 0, p = dst; i > 0; i--, src++) {
205 if (*src == '\r' || *src == '\n' || *src == ' ') {
Jens Wiklander817466c2018-05-22 13:49:31 +0200206 continue;
Jens Wiklander32b31802023-10-06 16:59:46 +0200207 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200208
Jerome Forissier039e02d2022-08-09 17:10:15 +0200209 x = x << 6;
Jens Wiklander32b31802023-10-06 16:59:46 +0200210 if (*src == '=') {
Jerome Forissier039e02d2022-08-09 17:10:15 +0200211 ++equals;
Jens Wiklander32b31802023-10-06 16:59:46 +0200212 } else {
213 x |= mbedtls_ct_base64_dec_value(*src);
214 }
Jerome Forissier79013242021-07-28 10:24:04 +0200215
Jens Wiklander32b31802023-10-06 16:59:46 +0200216 if (++accumulated_digits == 4) {
Jerome Forissier039e02d2022-08-09 17:10:15 +0200217 accumulated_digits = 0;
Jens Wiklander32b31802023-10-06 16:59:46 +0200218 *p++ = MBEDTLS_BYTE_2(x);
219 if (equals <= 1) {
220 *p++ = MBEDTLS_BYTE_1(x);
221 }
222 if (equals <= 0) {
223 *p++ = MBEDTLS_BYTE_0(x);
224 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200225 }
226 }
227
Tom Van Eyckc1633172024-04-09 18:44:13 +0200228 *olen = (size_t) (p - dst);
Jens Wiklander817466c2018-05-22 13:49:31 +0200229
Jens Wiklander32b31802023-10-06 16:59:46 +0200230 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200231}
232
233#if defined(MBEDTLS_SELF_TEST)
234
235static const unsigned char base64_test_dec[64] =
236{
237 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
238 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
239 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
240 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
241 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
242 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
243 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
244 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
245};
246
247static const unsigned char base64_test_enc[] =
248 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
249 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
250
251/*
252 * Checkup routine
253 */
Jens Wiklander32b31802023-10-06 16:59:46 +0200254int mbedtls_base64_self_test(int verbose)
Jens Wiklander817466c2018-05-22 13:49:31 +0200255{
256 size_t len;
257 const unsigned char *src;
258 unsigned char buffer[128];
259
Jens Wiklander32b31802023-10-06 16:59:46 +0200260 if (verbose != 0) {
261 mbedtls_printf(" Base64 encoding test: ");
262 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200263
264 src = base64_test_dec;
265
Jens Wiklander32b31802023-10-06 16:59:46 +0200266 if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
267 memcmp(base64_test_enc, buffer, 88) != 0) {
268 if (verbose != 0) {
269 mbedtls_printf("failed\n");
270 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200271
Jens Wiklander32b31802023-10-06 16:59:46 +0200272 return 1;
Jens Wiklander817466c2018-05-22 13:49:31 +0200273 }
274
Jens Wiklander32b31802023-10-06 16:59:46 +0200275 if (verbose != 0) {
276 mbedtls_printf("passed\n Base64 decoding test: ");
277 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200278
279 src = base64_test_enc;
280
Jens Wiklander32b31802023-10-06 16:59:46 +0200281 if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
282 memcmp(base64_test_dec, buffer, 64) != 0) {
283 if (verbose != 0) {
284 mbedtls_printf("failed\n");
285 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200286
Jens Wiklander32b31802023-10-06 16:59:46 +0200287 return 1;
Jens Wiklander817466c2018-05-22 13:49:31 +0200288 }
289
Jens Wiklander32b31802023-10-06 16:59:46 +0200290 if (verbose != 0) {
291 mbedtls_printf("passed\n\n");
292 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200293
Jens Wiklander32b31802023-10-06 16:59:46 +0200294 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200295}
296
297#endif /* MBEDTLS_SELF_TEST */
298
299#endif /* MBEDTLS_BASE64_C */