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