blob: 832484f98fa9fb20c9c1814edc9a3f6186eb1316 [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"
Paul Bakker5121ce52009-01-03 21:22:43 +000025
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020026#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000027
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020028#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000029#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020030#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000031#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010032#else
Rich Evans00ab4702015-02-06 13:43:58 +000033#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020034#define mbedtls_printf printf
35#endif /* MBEDTLS_PLATFORM_C */
36#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010037
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010038#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
39
Gilles Peskinec48ab112021-07-28 13:54:02 +020040/* Return 0xff if low <= c <= high, 0 otherwise.
41 *
42 * Constant flow with respect to c.
43 */
44static unsigned char mask_of_range( unsigned char low, unsigned char high,
45 unsigned char c )
46{
47 unsigned low_mask = ( c - low ) >> 8;
48 unsigned high_mask = ( c - high - 1 ) >> 8;
49 return( ~low_mask & high_mask & 0xff );
50}
51
Gilles Peskined6e3f462021-07-28 14:31:39 +020052/* Given a value in the range 0..63, return the corresponding Base64 digit.
53 * The implementation assumes that letters are consecutive (e.g. ASCII
54 * but not EBCDIC).
55 */
56static unsigned char enc_char( unsigned char val )
57{
58 unsigned char digit = 0;
59 /* For each range of values, if val is in that range, mask digit with
60 * the corresponding value. Since val can only be in a single range,
61 * only at most one masking will change digit. */
62 digit |= mask_of_range( 0, 25, val ) & ( 'A' + val );
63 digit |= mask_of_range( 26, 51, val ) & ( 'a' + val - 26 );
64 digit |= mask_of_range( 52, 61, val ) & ( '0' + val - 52 );
65 digit |= mask_of_range( 62, 62, val ) & '+';
66 digit |= mask_of_range( 63, 63, val ) & '/';
67 return( digit );
68}
69
Paul Bakker5121ce52009-01-03 21:22:43 +000070/*
71 * Encode a buffer into base64 format
72 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010073int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000074 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000075{
Paul Bakker23986e52011-04-24 08:57:21 +000076 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000077 int C1, C2, C3;
78 unsigned char *p;
79
80 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000081 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010082 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000083 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000084 }
Paul Bakker5121ce52009-01-03 21:22:43 +000085
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020086 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000087
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010088 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000089 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010090 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020091 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000092 }
93
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020094 n *= 4;
95
Janos Follath98e28a72016-05-31 14:03:54 +010096 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000097 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010098 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020099 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000100 }
101
Paul Bakker66d5d072014-06-17 16:39:18 +0200102 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000103
104 for( i = 0, p = dst; i < n; i += 3 )
105 {
106 C1 = *src++;
107 C2 = *src++;
108 C3 = *src++;
109
Gilles Peskined6e3f462021-07-28 14:31:39 +0200110 *p++ = enc_char( ( C1 >> 2 ) & 0x3F );
111 *p++ = enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F );
112 *p++ = enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F );
113 *p++ = enc_char( C3 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000114 }
115
116 if( i < slen )
117 {
118 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200119 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000120
Gilles Peskined6e3f462021-07-28 14:31:39 +0200121 *p++ = enc_char( ( C1 >> 2 ) & 0x3F );
122 *p++ = enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000123
Paul Bakker66d5d072014-06-17 16:39:18 +0200124 if( ( i + 1 ) < slen )
Gilles Peskined6e3f462021-07-28 14:31:39 +0200125 *p++ = enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000126 else *p++ = '=';
127
128 *p++ = '=';
129 }
130
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100131 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000132 *p = 0;
133
134 return( 0 );
135}
136
Gilles Peskinec48ab112021-07-28 13:54:02 +0200137/* Given a Base64 digit, return its value.
138 * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
139 * return -1.
140 *
141 * The implementation assumes that letters are consecutive (e.g. ASCII
142 * but not EBCDIC).
143 *
144 * The implementation is constant-flow (no branch or memory access depending
145 * on the value of c) unless the compiler inlines and optimizes a specific
146 * access.
147 */
148static signed char dec_value( unsigned char c )
149{
150 unsigned char val = 0;
151 /* For each range of digits, if c is in that range, mask val with
152 * the corresponding value. Since c can only be in a single range,
153 * only at most one masking will change val. Set val to one plus
154 * the desired value so that it stays 0 if c is in none of the ranges. */
155 val |= mask_of_range( 'A', 'Z', c ) & ( c - 'A' + 0 + 1 );
156 val |= mask_of_range( 'a', 'z', c ) & ( c - 'a' + 26 + 1 );
157 val |= mask_of_range( '0', '9', c ) & ( c - '0' + 52 + 1 );
158 val |= mask_of_range( '+', '+', c ) & ( c - '+' + 62 + 1 );
159 val |= mask_of_range( '/', '/', c ) & ( c - '/' + 63 + 1 );
160 /* At this point, val is 0 if c is an invalid digit and v+1 if c is
161 * a digit with the value v. */
162 return( val - 1 );
163}
164
Paul Bakker5121ce52009-01-03 21:22:43 +0000165/*
166 * Decode a base64-formatted buffer
167 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100168int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000169 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000170{
Gilles Peskinea97e9112021-07-28 14:20:06 +0200171 size_t i; /* index in source */
172 size_t n; /* number of digits or trailing = in source */
173 uint32_t x; /* value accumulator */
174 unsigned equals = 0;
175 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000176 unsigned char *p;
177
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200178 /* First pass: check for validity and get output length */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200179 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000180 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200181 /* Skip spaces before checking for EOL */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200182 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200183 while( i < slen && src[i] == ' ' )
184 {
185 ++i;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200186 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200187 }
188
189 /* Spaces at end of buffer are OK */
190 if( i == slen )
191 break;
192
Paul Bakker5121ce52009-01-03 21:22:43 +0000193 if( ( slen - i ) >= 2 &&
194 src[i] == '\r' && src[i + 1] == '\n' )
195 continue;
196
197 if( src[i] == '\n' )
198 continue;
199
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200200 /* Space inside a line is an error */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200201 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200202 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200203
Gilles Peskine6b541a02021-07-28 11:33:04 +0200204 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200205 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000206
Gilles Peskine6b541a02021-07-28 11:33:04 +0200207 if( src[i] == '=' )
208 {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200209 if( ++equals > 2 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200210 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
211 }
212 else
213 {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200214 if( equals != 0 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200215 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gilles Peskinec48ab112021-07-28 13:54:02 +0200216 if( dec_value( src[i] ) < 0 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200217 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
218 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000219 n++;
220 }
221
222 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100223 {
224 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000225 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100226 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000227
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000228 /* The following expression is to calculate the following formula without
229 * risk of integer overflow in n:
230 * n = ( ( n * 6 ) + 7 ) >> 3;
231 */
Andres AG4623d832017-01-18 17:21:03 +0000232 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskinea97e9112021-07-28 14:20:06 +0200233 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000234
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100235 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000236 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100237 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200238 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000239 }
240
Gilles Peskinea97e9112021-07-28 14:20:06 +0200241 equals = 0;
242 for( n = x = 0, p = dst; i > 0; i--, src++ )
243 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200244 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000245 continue;
246
Gilles Peskinea97e9112021-07-28 14:20:06 +0200247 x = x << 6;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200248 if( *src == '=' )
Gilles Peskinea97e9112021-07-28 14:20:06 +0200249 ++equals;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200250 else
Gilles Peskinea97e9112021-07-28 14:20:06 +0200251 x |= dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000252
253 if( ++n == 4 )
254 {
255 n = 0;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200256 *p++ = MBEDTLS_BYTE_2( x );
257 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
258 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000259 }
260 }
261
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100262 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000263
264 return( 0 );
265}
266
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200267#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000268
Paul Bakker5121ce52009-01-03 21:22:43 +0000269static const unsigned char base64_test_dec[64] =
270{
271 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
272 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
273 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
274 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
275 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
276 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
277 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
278 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
279};
280
281static const unsigned char base64_test_enc[] =
282 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
283 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
284
285/*
286 * Checkup routine
287 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200288int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000289{
Paul Bakker23986e52011-04-24 08:57:21 +0000290 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200291 const unsigned char *src;
292 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000293
294 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200295 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000296
Paul Bakker3c2122f2013-06-24 19:03:14 +0200297 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000298
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100299 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200300 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000301 {
302 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200303 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000304
305 return( 1 );
306 }
307
308 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200309 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000310
Paul Bakker3c2122f2013-06-24 19:03:14 +0200311 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000312
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100313 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000314 memcmp( base64_test_dec, buffer, 64 ) != 0 )
315 {
316 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200317 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000318
319 return( 1 );
320 }
321
322 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200323 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000324
325 return( 0 );
326}
327
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200328#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000329
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200330#endif /* MBEDTLS_BASE64_C */