1 // SPDX-License-Identifier: Apache-2.0 2 /* 3 * RFC 1521 base64 encoding/decoding 4 * 5 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 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 * This file is part of mbed TLS (https://tls.mbed.org) 20 */ 21 22 #if !defined(MBEDTLS_CONFIG_FILE) 23 #include "mbedtls/config.h" 24 #else 25 #include MBEDTLS_CONFIG_FILE 26 #endif 27 28 #if defined(MBEDTLS_BASE64_C) 29 30 #include "mbedtls/base64.h" 31 32 #include <stdint.h> 33 34 #if defined(MBEDTLS_SELF_TEST) 35 #include <string.h> 36 #if defined(MBEDTLS_PLATFORM_C) 37 #include "mbedtls/platform.h" 38 #else 39 #include <stdio.h> 40 #define mbedtls_printf printf 41 #endif /* MBEDTLS_PLATFORM_C */ 42 #endif /* MBEDTLS_SELF_TEST */ 43 44 static const unsigned char base64_enc_map[64] = 45 { 46 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 47 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 48 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 49 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 50 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 51 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', 52 '8', '9', '+', '/' 53 }; 54 55 static const unsigned char base64_dec_map[128] = 56 { 57 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 58 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 59 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 60 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 61 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, 62 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, 63 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, 64 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 65 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 66 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, 67 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 68 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 69 49, 50, 51, 127, 127, 127, 127, 127 70 }; 71 72 #define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ 73 74 /* 75 * Encode a buffer into base64 format 76 */ 77 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, 78 const unsigned char *src, size_t slen ) 79 { 80 size_t i, n; 81 int C1, C2, C3; 82 unsigned char *p; 83 84 if( slen == 0 ) 85 { 86 *olen = 0; 87 return( 0 ); 88 } 89 90 n = slen / 3 + ( slen % 3 != 0 ); 91 92 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 ) 93 { 94 *olen = BASE64_SIZE_T_MAX; 95 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 96 } 97 98 n *= 4; 99 100 if( ( dlen < n + 1 ) || ( NULL == dst ) ) 101 { 102 *olen = n + 1; 103 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 104 } 105 106 n = ( slen / 3 ) * 3; 107 108 for( i = 0, p = dst; i < n; i += 3 ) 109 { 110 C1 = *src++; 111 C2 = *src++; 112 C3 = *src++; 113 114 *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; 115 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; 116 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; 117 *p++ = base64_enc_map[C3 & 0x3F]; 118 } 119 120 if( i < slen ) 121 { 122 C1 = *src++; 123 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0; 124 125 *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; 126 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; 127 128 if( ( i + 1 ) < slen ) 129 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; 130 else *p++ = '='; 131 132 *p++ = '='; 133 } 134 135 *olen = p - dst; 136 *p = 0; 137 138 return( 0 ); 139 } 140 141 /* 142 * Decode a base64-formatted buffer 143 */ 144 int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, 145 const unsigned char *src, size_t slen ) 146 { 147 size_t i, n; 148 uint32_t j, x; 149 unsigned char *p; 150 151 /* First pass: check for validity and get output length */ 152 for( i = n = j = 0; i < slen; i++ ) 153 { 154 /* Skip spaces before checking for EOL */ 155 x = 0; 156 while( i < slen && src[i] == ' ' ) 157 { 158 ++i; 159 ++x; 160 } 161 162 /* Spaces at end of buffer are OK */ 163 if( i == slen ) 164 break; 165 166 if( ( slen - i ) >= 2 && 167 src[i] == '\r' && src[i + 1] == '\n' ) 168 continue; 169 170 if( src[i] == '\n' ) 171 continue; 172 173 /* Space inside a line is an error */ 174 if( x != 0 ) 175 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 176 177 if( src[i] == '=' && ++j > 2 ) 178 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 179 180 if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) 181 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 182 183 if( base64_dec_map[src[i]] < 64 && j != 0 ) 184 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); 185 186 n++; 187 } 188 189 if( n == 0 ) 190 { 191 *olen = 0; 192 return( 0 ); 193 } 194 195 /* The following expression is to calculate the following formula without 196 * risk of integer overflow in n: 197 * n = ( ( n * 6 ) + 7 ) >> 3; 198 */ 199 n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 ); 200 n -= j; 201 202 if( dst == NULL || dlen < n ) 203 { 204 *olen = n; 205 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 206 } 207 208 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) 209 { 210 if( *src == '\r' || *src == '\n' || *src == ' ' ) 211 continue; 212 213 j -= ( base64_dec_map[*src] == 64 ); 214 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F ); 215 216 if( ++n == 4 ) 217 { 218 n = 0; 219 if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); 220 if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); 221 if( j > 2 ) *p++ = (unsigned char)( x ); 222 } 223 } 224 225 *olen = p - dst; 226 227 return( 0 ); 228 } 229 230 #if defined(MBEDTLS_SELF_TEST) 231 232 static const unsigned char base64_test_dec[64] = 233 { 234 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, 235 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01, 236 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09, 237 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13, 238 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31, 239 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38, 240 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B, 241 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97 242 }; 243 244 static const unsigned char base64_test_enc[] = 245 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK" 246 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw=="; 247 248 /* 249 * Checkup routine 250 */ 251 int mbedtls_base64_self_test( int verbose ) 252 { 253 size_t len; 254 const unsigned char *src; 255 unsigned char buffer[128]; 256 257 if( verbose != 0 ) 258 mbedtls_printf( " Base64 encoding test: " ); 259 260 src = base64_test_dec; 261 262 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 || 263 memcmp( base64_test_enc, buffer, 88 ) != 0 ) 264 { 265 if( verbose != 0 ) 266 mbedtls_printf( "failed\n" ); 267 268 return( 1 ); 269 } 270 271 if( verbose != 0 ) 272 mbedtls_printf( "passed\n Base64 decoding test: " ); 273 274 src = base64_test_enc; 275 276 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 || 277 memcmp( base64_test_dec, buffer, 64 ) != 0 ) 278 { 279 if( verbose != 0 ) 280 mbedtls_printf( "failed\n" ); 281 282 return( 1 ); 283 } 284 285 if( verbose != 0 ) 286 mbedtls_printf( "passed\n\n" ); 287 288 return( 0 ); 289 } 290 291 #endif /* MBEDTLS_SELF_TEST */ 292 293 #endif /* MBEDTLS_BASE64_C */ 294