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 #include "constant_time_internal.h" 26 27 #include <stdint.h> 28 29 #if defined(MBEDTLS_SELF_TEST) 30 #include <string.h> 31 #if defined(MBEDTLS_PLATFORM_C) 32 #include "mbedtls/platform.h" 33 #else 34 #include <stdio.h> 35 #define mbedtls_printf printf 36 #endif /* MBEDTLS_PLATFORM_C */ 37 #endif /* MBEDTLS_SELF_TEST */ 38 39 #define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ 40 41 /* 42 * Encode a buffer into base64 format 43 */ 44 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, 45 const unsigned char *src, size_t slen ) 46 { 47 size_t i, n; 48 int C1, C2, C3; 49 unsigned char *p; 50 51 if( slen == 0 ) 52 { 53 *olen = 0; 54 return( 0 ); 55 } 56 57 n = slen / 3 + ( slen % 3 != 0 ); 58 59 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 ) 60 { 61 *olen = BASE64_SIZE_T_MAX; 62 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 63 } 64 65 n *= 4; 66 67 if( ( dlen < n + 1 ) || ( NULL == dst ) ) 68 { 69 *olen = n + 1; 70 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 71 } 72 73 n = ( slen / 3 ) * 3; 74 75 for( i = 0, p = dst; i < n; i += 3 ) 76 { 77 C1 = *src++; 78 C2 = *src++; 79 C3 = *src++; 80 81 *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F ); 82 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) 83 & 0x3F ); 84 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) 85 & 0x3F ); 86 *p++ = mbedtls_ct_base64_enc_char( C3 & 0x3F ); 87 } 88 89 if( i < slen ) 90 { 91 C1 = *src++; 92 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0; 93 94 *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F ); 95 *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) 96 & 0x3F ); 97 98 if( ( i + 1 ) < slen ) 99 *p++ = mbedtls_ct_base64_enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F ); 100 else *p++ = '='; 101 102 *p++ = '='; 103 } 104 105 *olen = p - dst; 106 *p = 0; 107 108 return( 0 ); 109 } 110 111 /* 112 * Decode a base64-formatted buffer 113 */ 114 int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, 115 const unsigned char *src, size_t slen ) 116 { 117 size_t i; /* index in source */ 118 size_t n; /* number of digits or trailing = in source */ 119 uint32_t x; /* value accumulator */ 120 unsigned accumulated_digits = 0; 121 unsigned equals = 0; 122 int spaces_present = 0; 123 unsigned char *p; 124 125 /* First pass: check for validity and get output length */ 126 for( i = n = 0; i < slen; i++ ) 127 { 128 /* Skip spaces before checking for EOL */ 129 spaces_present = 0; 130 while( i < slen && src[i] == ' ' ) 131 { 132 ++i; 133 spaces_present = 1; 134 } 135 136 /* Spaces at end of buffer are OK */ 137 if( i == slen ) 138 break; 139 140 if( ( slen - i ) >= 2 && 141 src[i] == '\r' && src[i + 1] == '\n' ) 142 continue; 143 144 if( src[i] == '\n' ) 145 continue; 146 147 /* Space inside a line is an error */ 148 if( spaces_present ) 149 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 150 151 if( src[i] > 127 ) 152 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 153 154 if( src[i] == '=' ) 155 { 156 if( ++equals > 2 ) 157 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 158 } 159 else 160 { 161 if( equals != 0 ) 162 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 163 if( mbedtls_ct_base64_dec_value( src[i] ) < 0 ) 164 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 165 } 166 n++; 167 } 168 169 if( n == 0 ) 170 { 171 *olen = 0; 172 return( 0 ); 173 } 174 175 /* The following expression is to calculate the following formula without 176 * risk of integer overflow in n: 177 * n = ( ( n * 6 ) + 7 ) >> 3; 178 */ 179 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 ); 180 n -= equals; 181 182 if( dst == NULL || dlen < n ) 183 { 184 *olen = n; 185 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 186 } 187 188 equals = 0; 189 for( x = 0, p = dst; i > 0; i--, src++ ) 190 { 191 if( *src == '\r' || *src == '\n' || *src == ' ' ) 192 continue; 193 194 x = x << 6; 195 if( *src == '=' ) 196 ++equals; 197 else 198 x |= mbedtls_ct_base64_dec_value( *src ); 199 200 if( ++accumulated_digits == 4 ) 201 { 202 accumulated_digits = 0; 203 *p++ = MBEDTLS_BYTE_2( x ); 204 if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x ); 205 if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x ); 206 } 207 } 208 209 *olen = p - dst; 210 211 return( 0 ); 212 } 213 214 #if defined(MBEDTLS_SELF_TEST) 215 216 static const unsigned char base64_test_dec[64] = 217 { 218 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, 219 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01, 220 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09, 221 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13, 222 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31, 223 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38, 224 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B, 225 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97 226 }; 227 228 static const unsigned char base64_test_enc[] = 229 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK" 230 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw=="; 231 232 /* 233 * Checkup routine 234 */ 235 int mbedtls_base64_self_test( int verbose ) 236 { 237 size_t len; 238 const unsigned char *src; 239 unsigned char buffer[128]; 240 241 if( verbose != 0 ) 242 mbedtls_printf( " Base64 encoding test: " ); 243 244 src = base64_test_dec; 245 246 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 || 247 memcmp( base64_test_enc, buffer, 88 ) != 0 ) 248 { 249 if( verbose != 0 ) 250 mbedtls_printf( "failed\n" ); 251 252 return( 1 ); 253 } 254 255 if( verbose != 0 ) 256 mbedtls_printf( "passed\n Base64 decoding test: " ); 257 258 src = base64_test_enc; 259 260 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 || 261 memcmp( base64_test_dec, buffer, 64 ) != 0 ) 262 { 263 if( verbose != 0 ) 264 mbedtls_printf( "failed\n" ); 265 266 return( 1 ); 267 } 268 269 if( verbose != 0 ) 270 mbedtls_printf( "passed\n\n" ); 271 272 return( 0 ); 273 } 274 275 #endif /* MBEDTLS_SELF_TEST */ 276 277 #endif /* MBEDTLS_BASE64_C */ 278