blob: 41706106424697d5b41ce96f3848a7f4f1aa42f5 [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
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Paul Bakker5121ce52009-01-03 21:22:43 +000018 */
19
Gilles Peskinedb09ef62020-06-03 01:43:33 +020020#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000021
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020022#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000023
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000024#include "mbedtls/base64.h"
Gabor Mezei200708d2021-11-15 16:18:54 +010025#include "constant_time_internal.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000026
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020027#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000028
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020029#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000030#include <string.h>
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000031#include "mbedtls/platform.h"
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020032#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010033
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010034#define BASE64_SIZE_T_MAX ((size_t) -1) /* SIZE_T_MAX is not standard */
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010035
Paul Bakker5121ce52009-01-03 21:22:43 +000036/*
37 * Encode a buffer into base64 format
38 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010039int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
40 const unsigned char *src, size_t slen)
Paul Bakker5121ce52009-01-03 21:22:43 +000041{
Paul Bakker23986e52011-04-24 08:57:21 +000042 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000043 int C1, C2, C3;
44 unsigned char *p;
45
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010046 if (slen == 0) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010047 *olen = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010048 return 0;
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000049 }
Paul Bakker5121ce52009-01-03 21:22:43 +000050
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010051 n = slen / 3 + (slen % 3 != 0);
Paul Bakker5121ce52009-01-03 21:22:43 +000052
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010053 if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010054 *olen = BASE64_SIZE_T_MAX;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010055 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +000056 }
57
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020058 n *= 4;
59
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010060 if ((dlen < n + 1) || (NULL == dst)) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010061 *olen = n + 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010062 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +000063 }
64
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010065 n = (slen / 3) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +000066
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010067 for (i = 0, p = dst; i < n; i += 3) {
Paul Bakker5121ce52009-01-03 21:22:43 +000068 C1 = *src++;
69 C2 = *src++;
70 C3 = *src++;
71
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);
75 *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
76 & 0x3F);
77 *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
Paul Bakker5121ce52009-01-03 21:22:43 +000078 }
79
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010080 if (i < slen) {
Paul Bakker5121ce52009-01-03 21:22:43 +000081 C1 = *src++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010082 C2 = ((i + 1) < slen) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000083
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010084 *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
85 *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
86 & 0x3F);
Paul Bakker5121ce52009-01-03 21:22:43 +000087
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010088 if ((i + 1) < slen) {
89 *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
90 } else {
91 *p++ = '=';
92 }
Paul Bakker5121ce52009-01-03 21:22:43 +000093
94 *p++ = '=';
95 }
96
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010097 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +000098 *p = 0;
99
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100100 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000101}
102
103/*
104 * Decode a base64-formatted buffer
105 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100106int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,
107 const unsigned char *src, size_t slen)
Paul Bakker5121ce52009-01-03 21:22:43 +0000108{
Gilles Peskinea97e9112021-07-28 14:20:06 +0200109 size_t i; /* index in source */
110 size_t n; /* number of digits or trailing = in source */
111 uint32_t x; /* value accumulator */
Gilles Peskine831fd762021-07-30 12:56:21 +0200112 unsigned accumulated_digits = 0;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200113 unsigned equals = 0;
114 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000115 unsigned char *p;
116
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200117 /* First pass: check for validity and get output length */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100118 for (i = n = 0; i < slen; i++) {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200119 /* Skip spaces before checking for EOL */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200120 spaces_present = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100121 while (i < slen && src[i] == ' ') {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200122 ++i;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200123 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200124 }
125
126 /* Spaces at end of buffer are OK */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100127 if (i == slen) {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200128 break;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100129 }
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200130
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100131 if ((slen - i) >= 2 &&
132 src[i] == '\r' && src[i + 1] == '\n') {
Paul Bakker5121ce52009-01-03 21:22:43 +0000133 continue;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100134 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000135
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100136 if (src[i] == '\n') {
Paul Bakker5121ce52009-01-03 21:22:43 +0000137 continue;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100138 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000139
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200140 /* Space inside a line is an error */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100141 if (spaces_present) {
142 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200143 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100144
145 if (src[i] > 127) {
146 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
147 }
148
149 if (src[i] == '=') {
150 if (++equals > 2) {
151 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
152 }
153 } else {
154 if (equals != 0) {
155 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
156 }
157 if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
158 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
159 }
Gilles Peskine6b541a02021-07-28 11:33:04 +0200160 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000161 n++;
162 }
163
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100164 if (n == 0) {
Simon Butchera45aa132015-10-05 00:26:36 +0100165 *olen = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100166 return 0;
Simon Butchera45aa132015-10-05 00:26:36 +0100167 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000168
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000169 /* The following expression is to calculate the following formula without
170 * risk of integer overflow in n:
171 * n = ( ( n * 6 ) + 7 ) >> 3;
172 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100173 n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
Gilles Peskinea97e9112021-07-28 14:20:06 +0200174 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000175
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100176 if (dst == NULL || dlen < n) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100177 *olen = n;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100178 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000179 }
180
Gilles Peskinea97e9112021-07-28 14:20:06 +0200181 equals = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100182 for (x = 0, p = dst; i > 0; i--, src++) {
183 if (*src == '\r' || *src == '\n' || *src == ' ') {
Paul Bakker5121ce52009-01-03 21:22:43 +0000184 continue;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100185 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000186
Gilles Peskinea97e9112021-07-28 14:20:06 +0200187 x = x << 6;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100188 if (*src == '=') {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200189 ++equals;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100190 } else {
191 x |= mbedtls_ct_base64_dec_value(*src);
192 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000193
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100194 if (++accumulated_digits == 4) {
Gilles Peskine831fd762021-07-30 12:56:21 +0200195 accumulated_digits = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100196 *p++ = MBEDTLS_BYTE_2(x);
197 if (equals <= 1) {
198 *p++ = MBEDTLS_BYTE_1(x);
199 }
200 if (equals <= 0) {
201 *p++ = MBEDTLS_BYTE_0(x);
202 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000203 }
204 }
205
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100206 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000207
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100208 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000209}
210
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200211#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000212
Paul Bakker5121ce52009-01-03 21:22:43 +0000213static const unsigned char base64_test_dec[64] =
214{
215 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
216 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
217 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
218 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
219 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
220 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
221 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
222 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
223};
224
225static const unsigned char base64_test_enc[] =
226 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
227 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
228
229/*
230 * Checkup routine
231 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100232int mbedtls_base64_self_test(int verbose)
Paul Bakker5121ce52009-01-03 21:22:43 +0000233{
Paul Bakker23986e52011-04-24 08:57:21 +0000234 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200235 const unsigned char *src;
236 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000237
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100238 if (verbose != 0) {
239 mbedtls_printf(" Base64 encoding test: ");
240 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000241
Paul Bakker3c2122f2013-06-24 19:03:14 +0200242 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000243
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100244 if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
245 memcmp(base64_test_enc, buffer, 88) != 0) {
246 if (verbose != 0) {
247 mbedtls_printf("failed\n");
248 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000249
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100250 return 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000251 }
252
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100253 if (verbose != 0) {
254 mbedtls_printf("passed\n Base64 decoding test: ");
255 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000256
Paul Bakker3c2122f2013-06-24 19:03:14 +0200257 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000258
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100259 if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
260 memcmp(base64_test_dec, buffer, 64) != 0) {
261 if (verbose != 0) {
262 mbedtls_printf("failed\n");
263 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000264
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100265 return 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000266 }
267
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100268 if (verbose != 0) {
269 mbedtls_printf("passed\n\n");
270 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000271
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100272 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000273}
274
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200275#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000276
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200277#endif /* MBEDTLS_BASE64_C */