blob: 96c94d1c61042178ccaea4e2b3a6c50b74e01a44 [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 Peskineab043352021-07-28 13:54:02 +020040/* Return 0xff if low <= c <= high, 0 otherwise.
41 *
42 * Constant flow with respect to c.
43 */
Gilles Peskined7d32792021-08-03 12:19:30 +020044MBEDTLS_STATIC_TESTABLE
45unsigned char mbedtls_base64_mask_of_range( unsigned char low,
46 unsigned char high,
47 unsigned char c )
Gilles Peskineab043352021-07-28 13:54:02 +020048{
Gilles Peskine8635e232021-07-30 12:57:22 +020049 /* low_mask is: 0 if low <= c, 0x...ff if low > c */
50 unsigned low_mask = ( (unsigned) c - low ) >> 8;
51 /* high_mask is: 0 if c <= high, 0x...ff if high > c */
52 unsigned high_mask = ( (unsigned) high - c ) >> 8;
53 return( ~( low_mask | high_mask ) & 0xff );
Gilles Peskineab043352021-07-28 13:54:02 +020054}
55
Gilles Peskine2c4a3682021-07-28 14:31:39 +020056/* Given a value in the range 0..63, return the corresponding Base64 digit.
57 * The implementation assumes that letters are consecutive (e.g. ASCII
58 * but not EBCDIC).
59 */
Gilles Peskined7d32792021-08-03 12:19:30 +020060MBEDTLS_STATIC_TESTABLE
61unsigned char mbedtls_base64_enc_char( unsigned char val )
Gilles Peskine2c4a3682021-07-28 14:31:39 +020062{
63 unsigned char digit = 0;
64 /* For each range of values, if val is in that range, mask digit with
65 * the corresponding value. Since val can only be in a single range,
66 * only at most one masking will change digit. */
Gilles Peskined7d32792021-08-03 12:19:30 +020067 digit |= mbedtls_base64_mask_of_range( 0, 25, val ) & ( 'A' + val );
68 digit |= mbedtls_base64_mask_of_range( 26, 51, val ) & ( 'a' + val - 26 );
69 digit |= mbedtls_base64_mask_of_range( 52, 61, val ) & ( '0' + val - 52 );
70 digit |= mbedtls_base64_mask_of_range( 62, 62, val ) & '+';
71 digit |= mbedtls_base64_mask_of_range( 63, 63, val ) & '/';
Gilles Peskine2c4a3682021-07-28 14:31:39 +020072 return( digit );
73}
74
Paul Bakker5121ce52009-01-03 21:22:43 +000075/*
76 * Encode a buffer into base64 format
77 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010078int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000079 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000080{
Paul Bakker23986e52011-04-24 08:57:21 +000081 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000082 int C1, C2, C3;
83 unsigned char *p;
84
85 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000086 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010087 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000088 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000089 }
Paul Bakker5121ce52009-01-03 21:22:43 +000090
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020091 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000092
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010093 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000094 {
Manuel Pégourié-Gonnard2d708342015-10-05 15:23:11 +010095 *olen = BASE64_SIZE_T_MAX;
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020096 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000097 }
98
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020099 n *= 4;
100
Janos Follath98e28a72016-05-31 14:03:54 +0100101 if( ( dlen < n + 1 ) || ( NULL == dst ) )
Paul Bakker5121ce52009-01-03 21:22:43 +0000102 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100103 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200104 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000105 }
106
Paul Bakker66d5d072014-06-17 16:39:18 +0200107 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000108
109 for( i = 0, p = dst; i < n; i += 3 )
110 {
111 C1 = *src++;
112 C2 = *src++;
113 C3 = *src++;
114
Gilles Peskined7d32792021-08-03 12:19:30 +0200115 *p++ = mbedtls_base64_enc_char( ( C1 >> 2 ) & 0x3F );
116 *p++ = mbedtls_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
117 & 0x3F );
118 *p++ = mbedtls_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) )
119 & 0x3F );
120 *p++ = mbedtls_base64_enc_char( C3 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000121 }
122
123 if( i < slen )
124 {
125 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200126 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000127
Gilles Peskined7d32792021-08-03 12:19:30 +0200128 *p++ = mbedtls_base64_enc_char( ( C1 >> 2 ) & 0x3F );
129 *p++ = mbedtls_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
130 & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000131
Paul Bakker66d5d072014-06-17 16:39:18 +0200132 if( ( i + 1 ) < slen )
Gilles Peskined7d32792021-08-03 12:19:30 +0200133 *p++ = mbedtls_base64_enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000134 else *p++ = '=';
135
136 *p++ = '=';
137 }
138
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100139 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000140 *p = 0;
141
142 return( 0 );
143}
144
Gilles Peskineab043352021-07-28 13:54:02 +0200145/* Given a Base64 digit, return its value.
146 * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
147 * return -1.
148 *
149 * The implementation assumes that letters are consecutive (e.g. ASCII
150 * but not EBCDIC).
151 *
152 * The implementation is constant-flow (no branch or memory access depending
153 * on the value of c) unless the compiler inlines and optimizes a specific
154 * access.
155 */
Gilles Peskined7d32792021-08-03 12:19:30 +0200156MBEDTLS_STATIC_TESTABLE
157signed char mbedtls_base64_dec_value( unsigned char c )
Gilles Peskineab043352021-07-28 13:54:02 +0200158{
159 unsigned char val = 0;
160 /* For each range of digits, if c is in that range, mask val with
161 * the corresponding value. Since c can only be in a single range,
162 * only at most one masking will change val. Set val to one plus
163 * the desired value so that it stays 0 if c is in none of the ranges. */
Gilles Peskined7d32792021-08-03 12:19:30 +0200164 val |= mbedtls_base64_mask_of_range( 'A', 'Z', c ) & ( c - 'A' + 0 + 1 );
165 val |= mbedtls_base64_mask_of_range( 'a', 'z', c ) & ( c - 'a' + 26 + 1 );
166 val |= mbedtls_base64_mask_of_range( '0', '9', c ) & ( c - '0' + 52 + 1 );
167 val |= mbedtls_base64_mask_of_range( '+', '+', c ) & ( c - '+' + 62 + 1 );
168 val |= mbedtls_base64_mask_of_range( '/', '/', c ) & ( c - '/' + 63 + 1 );
Gilles Peskineab043352021-07-28 13:54:02 +0200169 /* At this point, val is 0 if c is an invalid digit and v+1 if c is
170 * a digit with the value v. */
171 return( val - 1 );
172}
173
Paul Bakker5121ce52009-01-03 21:22:43 +0000174/*
175 * Decode a base64-formatted buffer
176 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100177int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000178 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000179{
Gilles Peskine1121cd22021-07-28 14:20:06 +0200180 size_t i; /* index in source */
181 size_t n; /* number of digits or trailing = in source */
182 uint32_t x; /* value accumulator */
Gilles Peskine67468e82021-07-30 12:56:21 +0200183 unsigned accumulated_digits = 0;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200184 unsigned equals = 0;
185 int spaces_present = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000186 unsigned char *p;
187
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200188 /* First pass: check for validity and get output length */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200189 for( i = n = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000190 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200191 /* Skip spaces before checking for EOL */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200192 spaces_present = 0;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200193 while( i < slen && src[i] == ' ' )
194 {
195 ++i;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200196 spaces_present = 1;
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200197 }
198
199 /* Spaces at end of buffer are OK */
200 if( i == slen )
201 break;
202
Paul Bakker5121ce52009-01-03 21:22:43 +0000203 if( ( slen - i ) >= 2 &&
204 src[i] == '\r' && src[i + 1] == '\n' )
205 continue;
206
207 if( src[i] == '\n' )
208 continue;
209
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200210 /* Space inside a line is an error */
Gilles Peskine1121cd22021-07-28 14:20:06 +0200211 if( spaces_present )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200212 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200213
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200214 if( src[i] > 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200215 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000216
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200217 if( src[i] == '=' )
218 {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200219 if( ++equals > 2 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200220 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
221 }
222 else
223 {
Gilles Peskine1121cd22021-07-28 14:20:06 +0200224 if( equals != 0 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200225 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Gilles Peskined7d32792021-08-03 12:19:30 +0200226 if( mbedtls_base64_dec_value( src[i] ) < 0 )
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200227 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
228 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000229 n++;
230 }
231
232 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100233 {
234 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000235 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100236 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000237
Simon Butchera29c5e9e2017-02-02 08:46:53 +0000238 /* The following expression is to calculate the following formula without
239 * risk of integer overflow in n:
240 * n = ( ( n * 6 ) + 7 ) >> 3;
241 */
Andres AG4623d832017-01-18 17:21:03 +0000242 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
Gilles Peskine1121cd22021-07-28 14:20:06 +0200243 n -= equals;
Paul Bakker5121ce52009-01-03 21:22:43 +0000244
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100245 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000246 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100247 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200248 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000249 }
250
Gilles Peskine1121cd22021-07-28 14:20:06 +0200251 equals = 0;
Gilles Peskine67468e82021-07-30 12:56:21 +0200252 for( x = 0, p = dst; i > 0; i--, src++ )
Gilles Peskine1121cd22021-07-28 14:20:06 +0200253 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200254 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000255 continue;
256
Gilles Peskine1121cd22021-07-28 14:20:06 +0200257 x = x << 6;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200258 if( *src == '=' )
Gilles Peskine1121cd22021-07-28 14:20:06 +0200259 ++equals;
Gilles Peskineb553eaa2021-07-28 11:33:04 +0200260 else
Gilles Peskined7d32792021-08-03 12:19:30 +0200261 x |= mbedtls_base64_dec_value( *src );
Paul Bakker5121ce52009-01-03 21:22:43 +0000262
Gilles Peskine67468e82021-07-30 12:56:21 +0200263 if( ++accumulated_digits == 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000264 {
Gilles Peskine67468e82021-07-30 12:56:21 +0200265 accumulated_digits = 0;
Gilles Peskine1121cd22021-07-28 14:20:06 +0200266 *p++ = MBEDTLS_BYTE_2( x );
267 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
268 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
Paul Bakker5121ce52009-01-03 21:22:43 +0000269 }
270 }
271
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100272 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000273
274 return( 0 );
275}
276
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200277#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000278
Paul Bakker5121ce52009-01-03 21:22:43 +0000279static const unsigned char base64_test_dec[64] =
280{
281 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
282 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
283 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
284 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
285 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
286 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
287 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
288 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
289};
290
291static const unsigned char base64_test_enc[] =
292 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
293 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
294
295/*
296 * Checkup routine
297 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200298int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000299{
Paul Bakker23986e52011-04-24 08:57:21 +0000300 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200301 const unsigned char *src;
302 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000303
304 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200305 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000306
Paul Bakker3c2122f2013-06-24 19:03:14 +0200307 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000308
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100309 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200310 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000311 {
312 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200313 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000314
315 return( 1 );
316 }
317
318 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200319 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000320
Paul Bakker3c2122f2013-06-24 19:03:14 +0200321 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000322
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100323 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000324 memcmp( base64_test_dec, buffer, 64 ) != 0 )
325 {
326 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200327 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000328
329 return( 1 );
330 }
331
332 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200333 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000334
335 return( 0 );
336}
337
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200338#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000339
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200340#endif /* MBEDTLS_BASE64_C */