blob: d33429645b5893aa25cce215958e7b483ac2b079 [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 */
Gilles Peskine831fd762021-07-30 12:56:21 +0200174 unsigned accumulated_digits = 0;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200175 unsigned equals = 0;
176 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000177 unsigned char *p;
178
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200179 /* First pass: check for validity and get output length */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200180 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000181 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200182 /* Skip spaces before checking for EOL */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200183 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200184 while( i < slen && src[i] == ' ' )
185 {
186 ++i;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200187 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200188 }
189
190 /* Spaces at end of buffer are OK */
191 if( i == slen )
192 break;
193
Paul Bakker5121ce52009-01-03 21:22:43 +0000194 if( ( slen - i ) >= 2 &&
195 src[i] == '\r' && src[i + 1] == '\n' )
196 continue;
197
198 if( src[i] == '\n' )
199 continue;
200
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200201 /* Space inside a line is an error */
Gilles Peskinea97e9112021-07-28 14:20:06 +0200202 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200203 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200204
Gilles Peskine6b541a02021-07-28 11:33:04 +0200205 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200206 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000207
Gilles Peskine6b541a02021-07-28 11:33:04 +0200208 if( src[i] == '=' )
209 {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200210 if( ++equals > 2 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200211 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
212 }
213 else
214 {
Gilles Peskinea97e9112021-07-28 14:20:06 +0200215 if( equals != 0 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200216 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gilles Peskinec48ab112021-07-28 13:54:02 +0200217 if( dec_value( src[i] ) < 0 )
Gilles Peskine6b541a02021-07-28 11:33:04 +0200218 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
219 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000220 n++;
221 }
222
223 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100224 {
225 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000226 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100227 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000228
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000229 /* The following expression is to calculate the following formula without
230 * risk of integer overflow in n:
231 * n = ( ( n * 6 ) + 7 ) >> 3;
232 */
Andres AG4623d832017-01-18 17:21:03 +0000233 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskinea97e9112021-07-28 14:20:06 +0200234 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000235
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100236 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000237 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100238 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200239 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000240 }
241
Gilles Peskinea97e9112021-07-28 14:20:06 +0200242 equals = 0;
Gilles Peskine831fd762021-07-30 12:56:21 +0200243 for( x = 0, p = dst; i > 0; i--, src++ )
Gilles Peskinea97e9112021-07-28 14:20:06 +0200244 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200245 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000246 continue;
247
Gilles Peskinea97e9112021-07-28 14:20:06 +0200248 x = x << 6;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200249 if( *src == '=' )
Gilles Peskinea97e9112021-07-28 14:20:06 +0200250 ++equals;
Gilles Peskine6b541a02021-07-28 11:33:04 +0200251 else
Gilles Peskinea97e9112021-07-28 14:20:06 +0200252 x |= dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000253
Gilles Peskine831fd762021-07-30 12:56:21 +0200254 if( ++accumulated_digits == 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000255 {
Gilles Peskine831fd762021-07-30 12:56:21 +0200256 accumulated_digits = 0;
Gilles Peskinea97e9112021-07-28 14:20:06 +0200257 *p++ = MBEDTLS_BYTE_2( x );
258 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
259 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000260 }
261 }
262
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100263 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000264
265 return( 0 );
266}
267
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200268#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000269
Paul Bakker5121ce52009-01-03 21:22:43 +0000270static const unsigned char base64_test_dec[64] =
271{
272 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
273 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
274 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
275 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
276 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
277 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
278 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
279 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
280};
281
282static const unsigned char base64_test_enc[] =
283 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
284 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
285
286/*
287 * Checkup routine
288 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200289int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000290{
Paul Bakker23986e52011-04-24 08:57:21 +0000291 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200292 const unsigned char *src;
293 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000294
295 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200296 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000297
Paul Bakker3c2122f2013-06-24 19:03:14 +0200298 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000299
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100300 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200301 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000302 {
303 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200304 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000305
306 return( 1 );
307 }
308
309 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200310 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000311
Paul Bakker3c2122f2013-06-24 19:03:14 +0200312 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000313
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100314 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000315 memcmp( base64_test_dec, buffer, 64 ) != 0 )
316 {
317 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200318 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000319
320 return( 1 );
321 }
322
323 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200324 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000325
326 return( 0 );
327}
328
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200329#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000330
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200331#endif /* MBEDTLS_BASE64_C */