blob: 6ddd501a4f3bf140e1ee10cd7e38a5cf19920ac2 [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{
Gilles Peskinea2dc0cc2021-07-30 12:57:22 +020047 /* low_mask is: 0 if low <= c, 0x...ff if low > c */
48 unsigned low_mask = ( (unsigned) c - low ) >> 8;
49 /* high_mask is: 0 if c <= high, 0x...ff if high > c */
50 unsigned high_mask = ( (unsigned) high - c ) >> 8;
51 return( ~( low_mask | high_mask ) & 0xff );
Gilles Peskinec48ab112021-07-28 13:54:02 +020052}
53
Gilles Peskined6e3f462021-07-28 14:31:39 +020054/* Given a value in the range 0..63, return the corresponding Base64 digit.
55 * The implementation assumes that letters are consecutive (e.g. ASCII
56 * but not EBCDIC).
57 */
58static unsigned char enc_char( unsigned char val )
59{
60 unsigned char digit = 0;
61 /* For each range of values, if val is in that range, mask digit with
62 * the corresponding value. Since val can only be in a single range,
63 * only at most one masking will change digit. */
64 digit |= mask_of_range( 0, 25, val ) & ( 'A' + val );
65 digit |= mask_of_range( 26, 51, val ) & ( 'a' + val - 26 );
66 digit |= mask_of_range( 52, 61, val ) & ( '0' + val - 52 );
67 digit |= mask_of_range( 62, 62, val ) & '+';
68 digit |= mask_of_range( 63, 63, val ) & '/';
69 return( digit );
70}
71
Paul Bakker5121ce52009-01-03 21:22:43 +000072/*
73 * Encode a buffer into base64 format
74 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010075int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000076 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000077{
Paul Bakker23986e52011-04-24 08:57:21 +000078 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000079 int C1, C2, C3;
80 unsigned char *p;
81
82 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000083 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010084 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000085 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000086 }
Paul Bakker5121ce52009-01-03 21:22:43 +000087
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020088 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000089
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010090 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000091 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010092 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020093 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000094 }
95
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020096 n *= 4;
97
Janos Follath98e28a72016-05-31 14:03:54 +010098 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000099 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100100 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200101 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000102 }
103
Paul Bakker66d5d072014-06-17 16:39:18 +0200104 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000105
106 for( i = 0, p = dst; i < n; i += 3 )
107 {
108 C1 = *src++;
109 C2 = *src++;
110 C3 = *src++;
111
Gilles Peskined6e3f462021-07-28 14:31:39 +0200112 *p++ = enc_char( ( C1 >> 2 ) & 0x3F );
113 *p++ = enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F );
114 *p++ = enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F );
115 *p++ = enc_char( C3 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000116 }
117
118 if( i < slen )
119 {
120 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200121 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000122
Gilles Peskined6e3f462021-07-28 14:31:39 +0200123 *p++ = enc_char( ( C1 >> 2 ) & 0x3F );
124 *p++ = enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000125
Paul Bakker66d5d072014-06-17 16:39:18 +0200126 if( ( i + 1 ) < slen )
Gilles Peskined6e3f462021-07-28 14:31:39 +0200127 *p++ = enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000128 else *p++ = '=';
129
130 *p++ = '=';
131 }
132
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100133 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000134 *p = 0;
135
136 return( 0 );
137}
138
Gilles Peskinec48ab112021-07-28 13:54:02 +0200139/* Given a Base64 digit, return its value.
140 * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
141 * return -1.
142 *
143 * The implementation assumes that letters are consecutive (e.g. ASCII
144 * but not EBCDIC).
145 *
146 * The implementation is constant-flow (no branch or memory access depending
147 * on the value of c) unless the compiler inlines and optimizes a specific
148 * access.
149 */
150static signed char dec_value( unsigned char c )
151{
152 unsigned char val = 0;
153 /* For each range of digits, if c is in that range, mask val with
154 * the corresponding value. Since c can only be in a single range,
155 * only at most one masking will change val. Set val to one plus
156 * the desired value so that it stays 0 if c is in none of the ranges. */
157 val |= mask_of_range( 'A', 'Z', c ) & ( c - 'A' + 0 + 1 );
158 val |= mask_of_range( 'a', 'z', c ) & ( c - 'a' + 26 + 1 );
159 val |= mask_of_range( '0', '9', c ) & ( c - '0' + 52 + 1 );
160 val |= mask_of_range( '+', '+', c ) & ( c - '+' + 62 + 1 );
161 val |= mask_of_range( '/', '/', c ) & ( c - '/' + 63 + 1 );
162 /* At this point, val is 0 if c is an invalid digit and v+1 if c is
163 * a digit with the value v. */
164 return( val - 1 );
165}
166
Paul Bakker5121ce52009-01-03 21:22:43 +0000167/*
168 * Decode a base64-formatted buffer
169 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100170int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000171 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000172{
Gilles Peskinea97e9112021-07-28 14:20:06 +0200173 size_t i; /* index in source */
174 size_t n; /* number of digits or trailing = in source */
175 uint32_t x; /* value accumulator */
Gilles Peskine831fd762021-07-30 12:56:21 +0200176 unsigned accumulated_digits = 0;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200177 unsigned equals = 0;
178 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000179 unsigned char *p;
180
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200181 /* First pass: check for validity and get output length */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200182 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000183 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200184 /* Skip spaces before checking for EOL */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200185 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200186 while( i < slen && src[i] == ' ' )
187 {
188 ++i;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200189 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200190 }
191
192 /* Spaces at end of buffer are OK */
193 if( i == slen )
194 break;
195
Paul Bakker5121ce52009-01-03 21:22:43 +0000196 if( ( slen - i ) >= 2 &&
197 src[i] == '\r' && src[i + 1] == '\n' )
198 continue;
199
200 if( src[i] == '\n' )
201 continue;
202
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200203 /* Space inside a line is an error */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200204 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200205 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200206
Gilles Peskine6b541a02021-07-28 11:33:04 +0200207 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200208 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000209
Gilles Peskine6b541a02021-07-28 11:33:04 +0200210 if( src[i] == '=' )
211 {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200212 if( ++equals > 2 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200213 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
214 }
215 else
216 {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200217 if( equals != 0 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200218 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gilles Peskinec48ab112021-07-28 13:54:02 +0200219 if( dec_value( src[i] ) < 0 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200220 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
221 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000222 n++;
223 }
224
225 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100226 {
227 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000228 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100229 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000230
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000231 /* The following expression is to calculate the following formula without
232 * risk of integer overflow in n:
233 * n = ( ( n * 6 ) + 7 ) >> 3;
234 */
Andres AG4623d832017-01-18 17:21:03 +0000235 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskinea97e9112021-07-28 14:20:06 +0200236 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000237
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100238 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000239 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100240 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200241 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000242 }
243
Gilles Peskinea97e9112021-07-28 14:20:06 +0200244 equals = 0;
Gilles Peskine831fd762021-07-30 12:56:21 +0200245 for( x = 0, p = dst; i > 0; i--, src++ )
Gilles Peskinea97e9112021-07-28 14:20:06 +0200246 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200247 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000248 continue;
249
Gilles Peskinea97e9112021-07-28 14:20:06 +0200250 x = x << 6;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200251 if( *src == '=' )
Gilles Peskinea97e9112021-07-28 14:20:06 +0200252 ++equals;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200253 else
Gilles Peskinea97e9112021-07-28 14:20:06 +0200254 x |= dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000255
Gilles Peskine831fd762021-07-30 12:56:21 +0200256 if( ++accumulated_digits == 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000257 {
Gilles Peskine831fd762021-07-30 12:56:21 +0200258 accumulated_digits = 0;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200259 *p++ = MBEDTLS_BYTE_2( x );
260 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
261 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000262 }
263 }
264
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100265 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000266
267 return( 0 );
268}
269
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200270#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000271
Paul Bakker5121ce52009-01-03 21:22:43 +0000272static const unsigned char base64_test_dec[64] =
273{
274 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
275 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
276 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
277 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
278 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
279 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
280 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
281 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
282};
283
284static const unsigned char base64_test_enc[] =
285 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
286 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
287
288/*
289 * Checkup routine
290 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200291int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000292{
Paul Bakker23986e52011-04-24 08:57:21 +0000293 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200294 const unsigned char *src;
295 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000296
297 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200298 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000299
Paul Bakker3c2122f2013-06-24 19:03:14 +0200300 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000301
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100302 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200303 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000304 {
305 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200306 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000307
308 return( 1 );
309 }
310
311 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200312 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000313
Paul Bakker3c2122f2013-06-24 19:03:14 +0200314 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000315
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100316 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000317 memcmp( base64_test_dec, buffer, 64 ) != 0 )
318 {
319 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200320 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000321
322 return( 1 );
323 }
324
325 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200326 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000327
328 return( 0 );
329}
330
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200331#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000332
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200333#endif /* MBEDTLS_BASE64_C */