blob: 1f1a90a9374477399cfa80d365da67425443eaf3 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Dave Rodgman7ff79652023-11-03 12:04:52 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Paul Bakker5121ce52009-01-03 21:22:43 +00006 */
7
Gilles Peskinedb09ef62020-06-03 01:43:33 +02008#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +00009
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020010#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000011
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000012#include "mbedtls/base64.h"
Gabor Mezei200708d2021-11-15 16:18:54 +010013#include "constant_time_internal.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000014
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020015#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000016
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020017#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000018#include <string.h>
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000019#include "mbedtls/platform.h"
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020020#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010021
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010022#define BASE64_SIZE_T_MAX ((size_t) -1) /* SIZE_T_MAX is not standard */
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010023
Paul Bakker5121ce52009-01-03 21:22:43 +000024/*
25 * Encode a buffer into base64 format
26 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010027int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
28 const unsigned char *src, size_t slen)
Paul Bakker5121ce52009-01-03 21:22:43 +000029{
Paul Bakker23986e52011-04-24 08:57:21 +000030 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000031 int C1, C2, C3;
32 unsigned char *p;
33
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010034 if (slen == 0) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010035 *olen = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010036 return 0;
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000037 }
Paul Bakker5121ce52009-01-03 21:22:43 +000038
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010039 n = slen / 3 + (slen % 3 != 0);
Paul Bakker5121ce52009-01-03 21:22:43 +000040
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010041 if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010042 *olen = BASE64_SIZE_T_MAX;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010043 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +000044 }
45
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020046 n *= 4;
47
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010048 if ((dlen < n + 1) || (NULL == dst)) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010049 *olen = n + 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010050 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +000051 }
52
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010053 n = (slen / 3) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +000054
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010055 for (i = 0, p = dst; i < n; i += 3) {
Paul Bakker5121ce52009-01-03 21:22:43 +000056 C1 = *src++;
57 C2 = *src++;
58 C3 = *src++;
59
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010060 *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
61 *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
62 & 0x3F);
63 *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
64 & 0x3F);
65 *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
Paul Bakker5121ce52009-01-03 21:22:43 +000066 }
67
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010068 if (i < slen) {
Paul Bakker5121ce52009-01-03 21:22:43 +000069 C1 = *src++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010070 C2 = ((i + 1) < slen) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000071
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010072 *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
73 *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
74 & 0x3F);
Paul Bakker5121ce52009-01-03 21:22:43 +000075
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010076 if ((i + 1) < slen) {
77 *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
78 } else {
79 *p++ = '=';
80 }
Paul Bakker5121ce52009-01-03 21:22:43 +000081
82 *p++ = '=';
83 }
84
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010085 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +000086 *p = 0;
87
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010088 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000089}
90
91/*
92 * Decode a base64-formatted buffer
93 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010094int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,
95 const unsigned char *src, size_t slen)
Paul Bakker5121ce52009-01-03 21:22:43 +000096{
Gilles Peskinea97e9112021-07-28 14:20:06 +020097 size_t i; /* index in source */
98 size_t n; /* number of digits or trailing = in source */
99 uint32_t x; /* value accumulator */
Gilles Peskine831fd762021-07-30 12:56:21 +0200100 unsigned accumulated_digits = 0;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200101 unsigned equals = 0;
102 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000103 unsigned char *p;
104
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200105 /* First pass: check for validity and get output length */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100106 for (i = n = 0; i < slen; i++) {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200107 /* Skip spaces before checking for EOL */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200108 spaces_present = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100109 while (i < slen && src[i] == ' ') {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200110 ++i;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200111 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200112 }
113
114 /* Spaces at end of buffer are OK */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100115 if (i == slen) {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200116 break;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100117 }
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200118
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100119 if ((slen - i) >= 2 &&
120 src[i] == '\r' && src[i + 1] == '\n') {
Paul Bakker5121ce52009-01-03 21:22:43 +0000121 continue;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100122 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000123
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100124 if (src[i] == '\n') {
Paul Bakker5121ce52009-01-03 21:22:43 +0000125 continue;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100126 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000127
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200128 /* Space inside a line is an error */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100129 if (spaces_present) {
130 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200131 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100132
133 if (src[i] > 127) {
134 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
135 }
136
137 if (src[i] == '=') {
138 if (++equals > 2) {
139 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
140 }
141 } else {
142 if (equals != 0) {
143 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
144 }
145 if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
146 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
147 }
Gilles Peskine6b541a02021-07-28 11:33:04 +0200148 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000149 n++;
150 }
151
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100152 if (n == 0) {
Simon Butchera45aa132015-10-05 00:26:36 +0100153 *olen = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100154 return 0;
Simon Butchera45aa132015-10-05 00:26:36 +0100155 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000156
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000157 /* The following expression is to calculate the following formula without
158 * risk of integer overflow in n:
159 * n = ( ( n * 6 ) + 7 ) >> 3;
160 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100161 n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
Gilles Peskinea97e9112021-07-28 14:20:06 +0200162 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000163
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100164 if (dst == NULL || dlen < n) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100165 *olen = n;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100166 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000167 }
168
Gilles Peskinea97e9112021-07-28 14:20:06 +0200169 equals = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100170 for (x = 0, p = dst; i > 0; i--, src++) {
171 if (*src == '\r' || *src == '\n' || *src == ' ') {
Paul Bakker5121ce52009-01-03 21:22:43 +0000172 continue;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100173 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000174
Gilles Peskinea97e9112021-07-28 14:20:06 +0200175 x = x << 6;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100176 if (*src == '=') {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200177 ++equals;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100178 } else {
179 x |= mbedtls_ct_base64_dec_value(*src);
180 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000181
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100182 if (++accumulated_digits == 4) {
Gilles Peskine831fd762021-07-30 12:56:21 +0200183 accumulated_digits = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100184 *p++ = MBEDTLS_BYTE_2(x);
185 if (equals <= 1) {
186 *p++ = MBEDTLS_BYTE_1(x);
187 }
188 if (equals <= 0) {
189 *p++ = MBEDTLS_BYTE_0(x);
190 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000191 }
192 }
193
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100194 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000195
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100196 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000197}
198
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200199#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000200
Paul Bakker5121ce52009-01-03 21:22:43 +0000201static const unsigned char base64_test_dec[64] =
202{
203 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
204 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
205 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
206 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
207 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
208 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
209 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
210 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
211};
212
213static const unsigned char base64_test_enc[] =
214 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
215 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
216
217/*
218 * Checkup routine
219 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100220int mbedtls_base64_self_test(int verbose)
Paul Bakker5121ce52009-01-03 21:22:43 +0000221{
Paul Bakker23986e52011-04-24 08:57:21 +0000222 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200223 const unsigned char *src;
224 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000225
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100226 if (verbose != 0) {
227 mbedtls_printf(" Base64 encoding test: ");
228 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000229
Paul Bakker3c2122f2013-06-24 19:03:14 +0200230 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000231
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100232 if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
233 memcmp(base64_test_enc, buffer, 88) != 0) {
234 if (verbose != 0) {
235 mbedtls_printf("failed\n");
236 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000237
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100238 return 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000239 }
240
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100241 if (verbose != 0) {
242 mbedtls_printf("passed\n Base64 decoding test: ");
243 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000244
Paul Bakker3c2122f2013-06-24 19:03:14 +0200245 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000246
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100247 if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
248 memcmp(base64_test_dec, buffer, 64) != 0) {
249 if (verbose != 0) {
250 mbedtls_printf("failed\n");
251 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000252
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100253 return 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000254 }
255
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100256 if (verbose != 0) {
257 mbedtls_printf("passed\n\n");
258 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000259
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100260 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000261}
262
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200263#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000264
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200265#endif /* MBEDTLS_BASE64_C */