1 /* 2 * RFC 1521 base64 encoding/decoding 3 * 4 * Copyright The Mbed TLS Contributors 5 * 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. 18 */ 19 20 #include "common.h" 21 22 #if defined(MBEDTLS_BASE64_C) 23 24 #include "mbedtls/base64.h" 25 26 #include <stdint.h> 27 28 #if defined(MBEDTLS_SELF_TEST) 29 #include <string.h> 30 #if defined(MBEDTLS_PLATFORM_C) 31 #include "mbedtls/platform.h" 32 #else 33 #include <stdio.h> 34 #define mbedtls_printf printf 35 #endif /* MBEDTLS_PLATFORM_C */ 36 #endif /* MBEDTLS_SELF_TEST */ 37 38 static const unsigned char base64_enc_map[64] = 39 { 40 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 41 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 42 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 43 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 44 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 45 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', 46 '8', '9', '+', '/' 47 }; 48 49 static const unsigned char base64_dec_map[128] = 50 { 51 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 52 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 53 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 54 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 55 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, 56 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, 57 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, 58 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 59 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 60 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, 61 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 62 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 63 49, 50, 51, 127, 127, 127, 127, 127 64 }; 65 66 #define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ 67 68 /* 69 * Constant flow conditional assignment to unsigned char 70 */ 71 static void mbedtls_base64_cond_assign_uchar( unsigned char * dest, const unsigned char * const src, 72 unsigned char condition ) 73 { 74 /* MSVC has a warning about unary minus on unsigned integer types, 75 * but this is well-defined and precisely what we want to do here. */ 76 #if defined(_MSC_VER) 77 #pragma warning( push ) 78 #pragma warning( disable : 4146 ) 79 #endif 80 81 /* Generate bitmask from condition, mask will either be 0xFF or 0 */ 82 unsigned char mask = ( condition | -condition ); 83 mask >>= 7; 84 mask = -mask; 85 86 #if defined(_MSC_VER) 87 #pragma warning( pop ) 88 #endif 89 90 *dest = ( ( *src ) & mask ) | ( ( *dest ) & ~mask ); 91 } 92 93 /* 94 * Constant flow conditional assignment to uint_32 95 */ 96 static void mbedtls_base64_cond_assign_uint32( uint32_t * dest, const uint32_t src, 97 uint32_t condition ) 98 { 99 /* MSVC has a warning about unary minus on unsigned integer types, 100 * but this is well-defined and precisely what we want to do here. */ 101 #if defined(_MSC_VER) 102 #pragma warning( push ) 103 #pragma warning( disable : 4146 ) 104 #endif 105 106 /* Generate bitmask from condition, mask will either be 0xFFFFFFFF or 0 */ 107 uint32_t mask = ( condition | -condition ); 108 mask >>= 31; 109 mask = -mask; 110 111 #if defined(_MSC_VER) 112 #pragma warning( pop ) 113 #endif 114 115 *dest = ( src & mask ) | ( ( *dest ) & ~mask ); 116 } 117 118 /* 119 * Constant flow check for equality 120 */ 121 static unsigned char mbedtls_base64_eq( size_t in_a, size_t in_b ) 122 { 123 size_t difference = in_a ^ in_b; 124 125 /* MSVC has a warning about unary minus on unsigned integer types, 126 * but this is well-defined and precisely what we want to do here. */ 127 #if defined(_MSC_VER) 128 #pragma warning( push ) 129 #pragma warning( disable : 4146 ) 130 #endif 131 132 difference |= -difference; 133 134 #if defined(_MSC_VER) 135 #pragma warning( pop ) 136 #endif 137 138 /* cope with the varying size of size_t per platform */ 139 difference >>= ( sizeof( difference ) * 8 - 1 ); 140 141 return (unsigned char) ( 1 ^ difference ); 142 } 143 144 /* 145 * Constant flow lookup into table. 146 */ 147 static unsigned char mbedtls_base64_table_lookup( const unsigned char * const table, 148 const size_t table_size, const size_t table_index ) 149 { 150 size_t i; 151 unsigned char result = 0; 152 153 for( i = 0; i < table_size; ++i ) 154 { 155 mbedtls_base64_cond_assign_uchar( &result, &table[i], mbedtls_base64_eq( i, table_index ) ); 156 } 157 158 return result; 159 } 160 161 /* 162 * Encode a buffer into base64 format 163 */ 164 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, 165 const unsigned char *src, size_t slen ) 166 { 167 size_t i, n; 168 int C1, C2, C3; 169 unsigned char *p; 170 171 if( slen == 0 ) 172 { 173 *olen = 0; 174 return( 0 ); 175 } 176 177 n = slen / 3 + ( slen % 3 != 0 ); 178 179 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 ) 180 { 181 *olen = BASE64_SIZE_T_MAX; 182 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 183 } 184 185 n *= 4; 186 187 if( ( dlen < n + 1 ) || ( NULL == dst ) ) 188 { 189 *olen = n + 1; 190 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 191 } 192 193 n = ( slen / 3 ) * 3; 194 195 for( i = 0, p = dst; i < n; i += 3 ) 196 { 197 C1 = *src++; 198 C2 = *src++; 199 C3 = *src++; 200 201 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), 202 ( ( C1 >> 2 ) & 0x3F ) ); 203 204 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), 205 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) ); 206 207 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), 208 ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) ); 209 210 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), 211 ( C3 & 0x3F ) ); 212 } 213 214 if( i < slen ) 215 { 216 C1 = *src++; 217 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0; 218 219 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), 220 ( ( C1 >> 2 ) & 0x3F ) ); 221 222 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), 223 ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) ); 224 225 if( ( i + 1 ) < slen ) 226 *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), 227 ( ( ( C2 & 15 ) << 2 ) & 0x3F ) ); 228 else *p++ = '='; 229 230 *p++ = '='; 231 } 232 233 *olen = p - dst; 234 *p = 0; 235 236 return( 0 ); 237 } 238 239 /* 240 * Decode a base64-formatted buffer 241 */ 242 int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, 243 const unsigned char *src, size_t slen ) 244 { 245 size_t i, n; 246 uint32_t j, x; 247 unsigned char *p; 248 unsigned char dec_map_lookup; 249 250 /* First pass: check for validity and get output length */ 251 for( i = n = j = 0; i < slen; i++ ) 252 { 253 /* Skip spaces before checking for EOL */ 254 x = 0; 255 while( i < slen && src[i] == ' ' ) 256 { 257 ++i; 258 ++x; 259 } 260 261 /* Spaces at end of buffer are OK */ 262 if( i == slen ) 263 break; 264 265 if( ( slen - i ) >= 2 && 266 src[i] == '\r' && src[i + 1] == '\n' ) 267 continue; 268 269 if( src[i] == '\n' ) 270 continue; 271 272 /* Space inside a line is an error */ 273 if( x != 0 ) 274 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 275 276 if( src[i] == '=' && ++j > 2 ) 277 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 278 279 dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] ); 280 281 if( src[i] > 127 || dec_map_lookup == 127 ) 282 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 283 284 if( dec_map_lookup < 64 && j != 0 ) 285 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 286 287 n++; 288 } 289 290 if( n == 0 ) 291 { 292 *olen = 0; 293 return( 0 ); 294 } 295 296 /* The following expression is to calculate the following formula without 297 * risk of integer overflow in n: 298 * n = ( ( n * 6 ) + 7 ) >> 3; 299 */ 300 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 ); 301 n -= j; 302 303 if( dst == NULL || dlen < n ) 304 { 305 *olen = n; 306 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 307 } 308 309 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) 310 { 311 if( *src == '\r' || *src == '\n' || *src == ' ' ) 312 continue; 313 314 dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src ); 315 316 mbedtls_base64_cond_assign_uint32( &j, j - 1, mbedtls_base64_eq( dec_map_lookup, 64 ) ); 317 x = ( x << 6 ) | ( dec_map_lookup & 0x3F ); 318 319 if( ++n == 4 ) 320 { 321 n = 0; 322 if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); 323 if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); 324 if( j > 2 ) *p++ = (unsigned char)( x ); 325 } 326 } 327 328 *olen = p - dst; 329 330 return( 0 ); 331 } 332 333 #if defined(MBEDTLS_SELF_TEST) 334 335 static const unsigned char base64_test_dec[64] = 336 { 337 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, 338 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01, 339 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09, 340 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13, 341 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31, 342 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38, 343 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B, 344 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97 345 }; 346 347 static const unsigned char base64_test_enc[] = 348 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK" 349 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw=="; 350 351 /* 352 * Checkup routine 353 */ 354 int mbedtls_base64_self_test( int verbose ) 355 { 356 size_t len; 357 const unsigned char *src; 358 unsigned char buffer[128]; 359 360 if( verbose != 0 ) 361 mbedtls_printf( " Base64 encoding test: " ); 362 363 src = base64_test_dec; 364 365 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 || 366 memcmp( base64_test_enc, buffer, 88 ) != 0 ) 367 { 368 if( verbose != 0 ) 369 mbedtls_printf( "failed\n" ); 370 371 return( 1 ); 372 } 373 374 if( verbose != 0 ) 375 mbedtls_printf( "passed\n Base64 decoding test: " ); 376 377 src = base64_test_enc; 378 379 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 || 380 memcmp( base64_test_dec, buffer, 64 ) != 0 ) 381 { 382 if( verbose != 0 ) 383 mbedtls_printf( "failed\n" ); 384 385 return( 1 ); 386 } 387 388 if( verbose != 0 ) 389 mbedtls_printf( "passed\n\n" ); 390 391 return( 0 ); 392 } 393 394 #endif /* MBEDTLS_SELF_TEST */ 395 396 #endif /* MBEDTLS_BASE64_C */ 397