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
David Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +000046 if (slen == 0) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010047 *olen = 0;
David Horstmannceeaeb92023-01-05 15:44:23 +000048 return 0;
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000049 }
Paul Bakker5121ce52009-01-03 21:22:43 +000050
David Horstmannceeaeb92023-01-05 15:44:23 +000051 n = slen / 3 + (slen % 3 != 0);
Paul Bakker5121ce52009-01-03 21:22:43 +000052
David Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +000060 if ((dlen < n + 1) || (NULL == dst)) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010061 *olen = n + 1;
David Horstmannceeaeb92023-01-05 15:44:23 +000062 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
Paul Bakker5121ce52009-01-03 21:22:43 +000063 }
64
David Horstmannceeaeb92023-01-05 15:44:23 +000065 n = (slen / 3) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +000066
David Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +000080 if (i < slen) {
Paul Bakker5121ce52009-01-03 21:22:43 +000081 C1 = *src++;
David Horstmannceeaeb92023-01-05 15:44:23 +000082 C2 = ((i + 1) < slen) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000083
David Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +0000100 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000101}
102
103/*
104 * Decode a base64-formatted buffer
105 */
David Horstmannceeaeb92023-01-05 15:44:23 +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 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 */
David Horstmannceeaeb92023-01-05 15:44:23 +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 Peskinea97e9112021-07-28 14:20:06 +0200120 spaces_present = 0;
David Horstmannceeaeb92023-01-05 15:44:23 +0000121 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 */
David Horstmannceeaeb92023-01-05 15:44:23 +0000127 if (i == slen) {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200128 break;
David Horstmannceeaeb92023-01-05 15:44:23 +0000129 }
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200130
David Horstmannceeaeb92023-01-05 15:44:23 +0000131 if ((slen - i) >= 2 &&
132 src[i] == '\r' && src[i + 1] == '\n') {
Paul Bakker5121ce52009-01-03 21:22:43 +0000133 continue;
David Horstmannceeaeb92023-01-05 15:44:23 +0000134 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000135
David Horstmannceeaeb92023-01-05 15:44:23 +0000136 if (src[i] == '\n') {
Paul Bakker5121ce52009-01-03 21:22:43 +0000137 continue;
David Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +0000141 if (spaces_present) {
142 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200143 }
David Horstmannceeaeb92023-01-05 15:44:23 +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 Peskine6b541a02021-07-28 11:33:04 +0200160 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000161 n++;
162 }
163
David Horstmannceeaeb92023-01-05 15:44:23 +0000164 if (n == 0) {
Simon Butchera45aa132015-10-05 00:26:36 +0100165 *olen = 0;
David Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +0000173 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
David Horstmannceeaeb92023-01-05 15:44:23 +0000176 if (dst == NULL || dlen < n) {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100177 *olen = n;
David Horstmannceeaeb92023-01-05 15:44:23 +0000178 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;
David Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +0000185 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000186
Gilles Peskinea97e9112021-07-28 14:20:06 +0200187 x = x << 6;
David Horstmannceeaeb92023-01-05 15:44:23 +0000188 if (*src == '=') {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200189 ++equals;
David Horstmannceeaeb92023-01-05 15:44:23 +0000190 } else {
191 x |= mbedtls_ct_base64_dec_value(*src);
192 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000193
David Horstmannceeaeb92023-01-05 15:44:23 +0000194 if (++accumulated_digits == 4) {
Gilles Peskine831fd762021-07-30 12:56:21 +0200195 accumulated_digits = 0;
David Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +0000250 return 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000251 }
252
David Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +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 Horstmannceeaeb92023-01-05 15:44:23 +0000265 return 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000266 }
267
David Horstmannceeaeb92023-01-05 15:44:23 +0000268 if (verbose != 0) {
269 mbedtls_printf("passed\n\n");
270 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000271
David Horstmannceeaeb92023-01-05 15:44:23 +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 */