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