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 Mezei9a4074a2021-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
David Horstmann8b6068b2023-01-05 15:42:32 +000034#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 */
David Horstmann8b6068b2023-01-05 15:42:32 +000039int 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
David Horstmann8b6068b2023-01-05 15:42:32 +000046 if (slen == 0) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010047 *olen = 0;
David Horstmann8b6068b2023-01-05 15:42:32 +000048 return 0;
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000049 }
Paul Bakker5121ce52009-01-03 21:22:43 +000050
David Horstmann8b6068b2023-01-05 15:42:32 +000051 n = slen / 3 + (slen % 3 != 0);
Paul Bakker5121ce52009-01-03 21:22:43 +000052
David Horstmann8b6068b2023-01-05 15:42:32 +000053 if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010054 *olen = BASE64_SIZE_T_MAX;
David Horstmann8b6068b2023-01-05 15:42:32 +000055 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
David Horstmann8b6068b2023-01-05 15:42:32 +000060 if ((dlen < n + 1) || (NULL == dst)) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010061 *olen = n + 1;
David Horstmann8b6068b2023-01-05 15:42:32 +000062 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +000063 }
64
David Horstmann8b6068b2023-01-05 15:42:32 +000065 n = (slen / 3) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +000066
David Horstmann8b6068b2023-01-05 15:42:32 +000067 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
David Horstmann8b6068b2023-01-05 15:42:32 +000072 *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
David Horstmann8b6068b2023-01-05 15:42:32 +000080 if (i < slen) {
Paul Bakker5121ce52009-01-03 21:22:43 +000081 C1 = *src++;
David Horstmann8b6068b2023-01-05 15:42:32 +000082 C2 = ((i + 1) < slen) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000083
David Horstmann8b6068b2023-01-05 15:42:32 +000084 *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
David Horstmann8b6068b2023-01-05 15:42:32 +000088 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
David Horstmann8b6068b2023-01-05 15:42:32 +0000100 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000101}
102
103/*
104 * Decode a base64-formatted buffer
105 */
David Horstmann8b6068b2023-01-05 15:42:32 +0000106int 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 Peskine1121cd22021-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 Peskine67468e82021-07-30 12:56:21 +0200112 unsigned accumulated_digits = 0;
Gilles Peskine1121cd22021-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 */
David Horstmann8b6068b2023-01-05 15:42:32 +0000118 for (i = n = 0; i < slen; i++) {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200119 /* Skip spaces before checking for EOL */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200120 spaces_present = 0;
David Horstmann8b6068b2023-01-05 15:42:32 +0000121 while (i < slen && src[i] == ' ') {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200122 ++i;
Gilles Peskine1121cd22021-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 */
David Horstmann8b6068b2023-01-05 15:42:32 +0000127 if (i == slen) {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200128 break;
David Horstmann8b6068b2023-01-05 15:42:32 +0000129 }
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200130
David Horstmann8b6068b2023-01-05 15:42:32 +0000131 if ((slen - i) >= 2 &&
132 src[i] == '\r' && src[i + 1] == '\n') {
Paul Bakker5121ce52009-01-03 21:22:43 +0000133 continue;
David Horstmann8b6068b2023-01-05 15:42:32 +0000134 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000135
David Horstmann8b6068b2023-01-05 15:42:32 +0000136 if (src[i] == '\n') {
Paul Bakker5121ce52009-01-03 21:22:43 +0000137 continue;
David Horstmann8b6068b2023-01-05 15:42:32 +0000138 }
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 */
David Horstmann8b6068b2023-01-05 15:42:32 +0000141 if (spaces_present) {
142 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200143 }
David Horstmann8b6068b2023-01-05 15:42:32 +0000144
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 Peskineb553eaa2021-07-28 11:33:04 +0200160 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000161 n++;
162 }
163
David Horstmann8b6068b2023-01-05 15:42:32 +0000164 if (n == 0) {
Simon Butchera45aa132015-10-05 00:26:36 +0100165 *olen = 0;
David Horstmann8b6068b2023-01-05 15:42:32 +0000166 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 */
David Horstmann8b6068b2023-01-05 15:42:32 +0000173 n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
Gilles Peskine1121cd22021-07-28 14:20:06 +0200174 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000175
David Horstmann8b6068b2023-01-05 15:42:32 +0000176 if (dst == NULL || dlen < n) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100177 *olen = n;
David Horstmann8b6068b2023-01-05 15:42:32 +0000178 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +0000179 }
180
Gilles Peskine1121cd22021-07-28 14:20:06 +0200181 equals = 0;
David Horstmann8b6068b2023-01-05 15:42:32 +0000182 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;
David Horstmann8b6068b2023-01-05 15:42:32 +0000185 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000186
Gilles Peskine1121cd22021-07-28 14:20:06 +0200187 x = x << 6;
David Horstmann8b6068b2023-01-05 15:42:32 +0000188 if (*src == '=') {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200189 ++equals;
David Horstmann8b6068b2023-01-05 15:42:32 +0000190 } else {
191 x |= mbedtls_ct_base64_dec_value(*src);
192 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000193
David Horstmann8b6068b2023-01-05 15:42:32 +0000194 if (++accumulated_digits == 4) {
Gilles Peskine67468e82021-07-30 12:56:21 +0200195 accumulated_digits = 0;
David Horstmann8b6068b2023-01-05 15:42:32 +0000196 *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
David Horstmann8b6068b2023-01-05 15:42:32 +0000208 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 */
David Horstmann8b6068b2023-01-05 15:42:32 +0000232int 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
David Horstmann8b6068b2023-01-05 15:42:32 +0000238 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
David Horstmann8b6068b2023-01-05 15:42:32 +0000244 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
David Horstmann8b6068b2023-01-05 15:42:32 +0000250 return 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000251 }
252
David Horstmann8b6068b2023-01-05 15:42:32 +0000253 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
David Horstmann8b6068b2023-01-05 15:42:32 +0000259 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
David Horstmann8b6068b2023-01-05 15:42:32 +0000265 return 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000266 }
267
David Horstmann8b6068b2023-01-05 15:42:32 +0000268 if (verbose != 0) {
269 mbedtls_printf("passed\n\n");
270 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000271
David Horstmann8b6068b2023-01-05 15:42:32 +0000272 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 */