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 8 #include <limits.h> 9 10 #include "common.h" 11 12 #if defined(MBEDTLS_BASE64_C) 13 14 #include "mbedtls/base64.h" 15 #include "base64_internal.h" 16 #include "constant_time_internal.h" 17 #include "mbedtls/error.h" 18 19 #include <stdint.h> 20 21 #if defined(MBEDTLS_SELF_TEST) 22 #include <string.h> 23 #include "mbedtls/platform.h" 24 #endif /* MBEDTLS_SELF_TEST */ 25 26 MBEDTLS_STATIC_TESTABLE 27 unsigned char mbedtls_ct_base64_enc_char(unsigned char value) 28 { 29 unsigned char digit = 0; 30 /* For each range of values, if value is in that range, mask digit with 31 * the corresponding value. Since value can only be in a single range, 32 * only at most one masking will change digit. */ 33 digit |= mbedtls_ct_uchar_in_range_if(0, 25, value, 'A' + value); 34 digit |= mbedtls_ct_uchar_in_range_if(26, 51, value, 'a' + value - 26); 35 digit |= mbedtls_ct_uchar_in_range_if(52, 61, value, '0' + value - 52); 36 digit |= mbedtls_ct_uchar_in_range_if(62, 62, value, '+'); 37 digit |= mbedtls_ct_uchar_in_range_if(63, 63, value, '/'); 38 return digit; 39 } 40 41 MBEDTLS_STATIC_TESTABLE 42 signed char mbedtls_ct_base64_dec_value(unsigned char c) 43 { 44 unsigned char val = 0; 45 /* For each range of digits, if c is in that range, mask val with 46 * the corresponding value. Since c can only be in a single range, 47 * only at most one masking will change val. Set val to one plus 48 * the desired value so that it stays 0 if c is in none of the ranges. */ 49 val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' + 0 + 1); 50 val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1); 51 val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1); 52 val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1); 53 val |= mbedtls_ct_uchar_in_range_if('/', '/', c, c - '/' + 63 + 1); 54 /* At this point, val is 0 if c is an invalid digit and v+1 if c is 55 * a digit with the value v. */ 56 return val - 1; 57 } 58 59 /* 60 * Encode a buffer into base64 format 61 */ 62 int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen, 63 const unsigned char *src, size_t slen) 64 { 65 size_t i, n; 66 int C1, C2, C3; 67 unsigned char *p; 68 69 if (slen == 0) { 70 *olen = 0; 71 return 0; 72 } 73 74 n = slen / 3 + (slen % 3 != 0); 75 76 if (n > (SIZE_MAX - 1) / 4) { 77 *olen = SIZE_MAX; 78 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL; 79 } 80 81 n *= 4; 82 83 if ((dlen < n + 1) || (NULL == dst)) { 84 *olen = n + 1; 85 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL; 86 } 87 88 n = (slen / 3) * 3; 89 90 for (i = 0, p = dst; i < n; i += 3) { 91 C1 = *src++; 92 C2 = *src++; 93 C3 = *src++; 94 95 *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F); 96 *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4)) 97 & 0x3F); 98 *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6)) 99 & 0x3F); 100 *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F); 101 } 102 103 if (i < slen) { 104 C1 = *src++; 105 C2 = ((i + 1) < slen) ? *src++ : 0; 106 107 *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F); 108 *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4)) 109 & 0x3F); 110 111 if ((i + 1) < slen) { 112 *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F); 113 } else { 114 *p++ = '='; 115 } 116 117 *p++ = '='; 118 } 119 120 *olen = (size_t) (p - dst); 121 *p = 0; 122 123 return 0; 124 } 125 126 /* 127 * Decode a base64-formatted buffer 128 */ 129 int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen, 130 const unsigned char *src, size_t slen) 131 { 132 size_t i; /* index in source */ 133 size_t n; /* number of digits or trailing = in source */ 134 uint32_t x; /* value accumulator */ 135 unsigned accumulated_digits = 0; 136 unsigned equals = 0; 137 int spaces_present = 0; 138 unsigned char *p; 139 140 /* First pass: check for validity and get output length */ 141 for (i = n = 0; i < slen; i++) { 142 /* Skip spaces before checking for EOL */ 143 spaces_present = 0; 144 while (i < slen && src[i] == ' ') { 145 ++i; 146 spaces_present = 1; 147 } 148 149 /* Spaces at end of buffer are OK */ 150 if (i == slen) { 151 break; 152 } 153 154 if ((slen - i) >= 2 && 155 src[i] == '\r' && src[i + 1] == '\n') { 156 continue; 157 } 158 159 if (src[i] == '\n') { 160 continue; 161 } 162 163 /* Space inside a line is an error */ 164 if (spaces_present) { 165 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER; 166 } 167 168 if (src[i] > 127) { 169 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER; 170 } 171 172 if (src[i] == '=') { 173 if (++equals > 2) { 174 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER; 175 } 176 } else { 177 if (equals != 0) { 178 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER; 179 } 180 if (mbedtls_ct_base64_dec_value(src[i]) < 0) { 181 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER; 182 } 183 } 184 n++; 185 } 186 187 /* In valid base64, the number of digits (n-equals) is always of the form 188 * 4*k, 4*k+2 or *4k+3. Also, the number n of digits plus the number of 189 * equal signs at the end is always a multiple of 4. */ 190 if ((n - equals) % 4 == 1) { 191 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER; 192 } 193 if (n % 4 != 0) { 194 return MBEDTLS_ERR_BASE64_INVALID_CHARACTER; 195 } 196 197 /* We've determined that the input is valid, and that it contains 198 * exactly k blocks of digits-or-equals, with n = 4 * k, 199 * and equals only present at the end of the last block if at all. 200 * Now we can calculate the length of the output. 201 * 202 * Each block of 4 digits in the input map to 3 bytes of output. 203 * For the last block: 204 * - abcd (where abcd are digits) is a full 3-byte block; 205 * - abc= means 1 byte less than a full 3-byte block of output; 206 * - ab== means 2 bytes less than a full 3-byte block of output; 207 * - a==== and ==== is rejected above. 208 */ 209 *olen = (n / 4) * 3 - equals; 210 211 /* If the output buffer is too small, signal this and stop here. 212 * Also, as documented, stop here if `dst` is null, independently of 213 * `dlen`. 214 * 215 * There is an edge case when the output is empty: in this case, 216 * `dlen == 0` with `dst == NULL` is valid (on some platforms, 217 * `malloc(0)` returns `NULL`). Since the call is valid, we return 218 * 0 in this case. 219 */ 220 if ((*olen != 0 && dst == NULL) || dlen < *olen) { 221 return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL; 222 } 223 224 for (x = 0, p = dst; i > 0; i--, src++) { 225 if (*src == '\r' || *src == '\n' || *src == ' ') { 226 continue; 227 } 228 if (*src == '=') { 229 /* We already know from the first loop that equal signs are 230 * only at the end. */ 231 break; 232 } 233 x = x << 6; 234 x |= mbedtls_ct_base64_dec_value(*src); 235 236 if (++accumulated_digits == 4) { 237 accumulated_digits = 0; 238 *p++ = MBEDTLS_BYTE_2(x); 239 *p++ = MBEDTLS_BYTE_1(x); 240 *p++ = MBEDTLS_BYTE_0(x); 241 } 242 } 243 if (accumulated_digits == 3) { 244 *p++ = MBEDTLS_BYTE_2(x << 6); 245 *p++ = MBEDTLS_BYTE_1(x << 6); 246 } else if (accumulated_digits == 2) { 247 *p++ = MBEDTLS_BYTE_2(x << 12); 248 } 249 250 if (*olen != (size_t) (p - dst)) { 251 return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 252 } 253 254 return 0; 255 } 256 257 #if defined(MBEDTLS_SELF_TEST) 258 259 static const unsigned char base64_test_dec[64] = 260 { 261 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, 262 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01, 263 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09, 264 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13, 265 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31, 266 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38, 267 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B, 268 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97 269 }; 270 271 static const unsigned char base64_test_enc[] = 272 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK" 273 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw=="; 274 275 /* 276 * Checkup routine 277 */ 278 int mbedtls_base64_self_test(int verbose) 279 { 280 size_t len; 281 const unsigned char *src; 282 unsigned char buffer[128]; 283 284 if (verbose != 0) { 285 mbedtls_printf(" Base64 encoding test: "); 286 } 287 288 src = base64_test_dec; 289 290 if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 || 291 memcmp(base64_test_enc, buffer, 88) != 0) { 292 if (verbose != 0) { 293 mbedtls_printf("failed\n"); 294 } 295 296 return 1; 297 } 298 299 if (verbose != 0) { 300 mbedtls_printf("passed\n Base64 decoding test: "); 301 } 302 303 src = base64_test_enc; 304 305 if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 || 306 memcmp(base64_test_dec, buffer, 64) != 0) { 307 if (verbose != 0) { 308 mbedtls_printf("failed\n"); 309 } 310 311 return 1; 312 } 313 314 if (verbose != 0) { 315 mbedtls_printf("passed\n\n"); 316 } 317 318 return 0; 319 } 320 321 #endif /* MBEDTLS_SELF_TEST */ 322 323 #endif /* MBEDTLS_BASE64_C */ 324