Path: blob/master/thirdparty/mbedtls/library/base64.c
9898 views
/*1* RFC 1521 base64 encoding/decoding2*3* Copyright The Mbed TLS Contributors4* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later5*/67#include <limits.h>89#include "common.h"1011#if defined(MBEDTLS_BASE64_C)1213#include "mbedtls/base64.h"14#include "base64_internal.h"15#include "constant_time_internal.h"16#include "mbedtls/error.h"1718#include <stdint.h>1920#if defined(MBEDTLS_SELF_TEST)21#include <string.h>22#include "mbedtls/platform.h"23#endif /* MBEDTLS_SELF_TEST */2425MBEDTLS_STATIC_TESTABLE26unsigned char mbedtls_ct_base64_enc_char(unsigned char value)27{28unsigned char digit = 0;29/* For each range of values, if value is in that range, mask digit with30* the corresponding value. Since value can only be in a single range,31* only at most one masking will change digit. */32digit |= mbedtls_ct_uchar_in_range_if(0, 25, value, 'A' + value);33digit |= mbedtls_ct_uchar_in_range_if(26, 51, value, 'a' + value - 26);34digit |= mbedtls_ct_uchar_in_range_if(52, 61, value, '0' + value - 52);35digit |= mbedtls_ct_uchar_in_range_if(62, 62, value, '+');36digit |= mbedtls_ct_uchar_in_range_if(63, 63, value, '/');37return digit;38}3940MBEDTLS_STATIC_TESTABLE41signed char mbedtls_ct_base64_dec_value(unsigned char c)42{43unsigned char val = 0;44/* For each range of digits, if c is in that range, mask val with45* the corresponding value. Since c can only be in a single range,46* only at most one masking will change val. Set val to one plus47* the desired value so that it stays 0 if c is in none of the ranges. */48val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' + 0 + 1);49val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1);50val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1);51val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1);52val |= mbedtls_ct_uchar_in_range_if('/', '/', c, c - '/' + 63 + 1);53/* At this point, val is 0 if c is an invalid digit and v+1 if c is54* a digit with the value v. */55return val - 1;56}5758/*59* Encode a buffer into base64 format60*/61int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,62const unsigned char *src, size_t slen)63{64size_t i, n;65int C1, C2, C3;66unsigned char *p;6768if (slen == 0) {69*olen = 0;70return 0;71}7273n = slen / 3 + (slen % 3 != 0);7475if (n > (SIZE_MAX - 1) / 4) {76*olen = SIZE_MAX;77return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;78}7980n *= 4;8182if ((dlen < n + 1) || (NULL == dst)) {83*olen = n + 1;84return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;85}8687n = (slen / 3) * 3;8889for (i = 0, p = dst; i < n; i += 3) {90C1 = *src++;91C2 = *src++;92C3 = *src++;9394*p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);95*p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))96& 0x3F);97*p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))98& 0x3F);99*p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);100}101102if (i < slen) {103C1 = *src++;104C2 = ((i + 1) < slen) ? *src++ : 0;105106*p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);107*p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))108& 0x3F);109110if ((i + 1) < slen) {111*p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);112} else {113*p++ = '=';114}115116*p++ = '=';117}118119*olen = (size_t) (p - dst);120*p = 0;121122return 0;123}124125/*126* Decode a base64-formatted buffer127*/128int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,129const unsigned char *src, size_t slen)130{131size_t i; /* index in source */132size_t n; /* number of digits or trailing = in source */133uint32_t x; /* value accumulator */134unsigned accumulated_digits = 0;135unsigned equals = 0;136int spaces_present = 0;137unsigned char *p;138139/* First pass: check for validity and get output length */140for (i = n = 0; i < slen; i++) {141/* Skip spaces before checking for EOL */142spaces_present = 0;143while (i < slen && src[i] == ' ') {144++i;145spaces_present = 1;146}147148/* Spaces at end of buffer are OK */149if (i == slen) {150break;151}152153if ((slen - i) >= 2 &&154src[i] == '\r' && src[i + 1] == '\n') {155continue;156}157158if (src[i] == '\n') {159continue;160}161162/* Space inside a line is an error */163if (spaces_present) {164return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;165}166167if (src[i] > 127) {168return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;169}170171if (src[i] == '=') {172if (++equals > 2) {173return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;174}175} else {176if (equals != 0) {177return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;178}179if (mbedtls_ct_base64_dec_value(src[i]) < 0) {180return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;181}182}183n++;184}185186/* In valid base64, the number of digits (n-equals) is always of the form187* 4*k, 4*k+2 or *4k+3. Also, the number n of digits plus the number of188* equal signs at the end is always a multiple of 4. */189if ((n - equals) % 4 == 1) {190return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;191}192if (n % 4 != 0) {193return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;194}195196/* We've determined that the input is valid, and that it contains197* exactly k blocks of digits-or-equals, with n = 4 * k,198* and equals only present at the end of the last block if at all.199* Now we can calculate the length of the output.200*201* Each block of 4 digits in the input map to 3 bytes of output.202* For the last block:203* - abcd (where abcd are digits) is a full 3-byte block;204* - abc= means 1 byte less than a full 3-byte block of output;205* - ab== means 2 bytes less than a full 3-byte block of output;206* - a==== and ==== is rejected above.207*/208*olen = (n / 4) * 3 - equals;209210/* If the output buffer is too small, signal this and stop here.211* Also, as documented, stop here if `dst` is null, independently of212* `dlen`.213*214* There is an edge case when the output is empty: in this case,215* `dlen == 0` with `dst == NULL` is valid (on some platforms,216* `malloc(0)` returns `NULL`). Since the call is valid, we return217* 0 in this case.218*/219if ((*olen != 0 && dst == NULL) || dlen < *olen) {220return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;221}222223for (x = 0, p = dst; i > 0; i--, src++) {224if (*src == '\r' || *src == '\n' || *src == ' ') {225continue;226}227if (*src == '=') {228/* We already know from the first loop that equal signs are229* only at the end. */230break;231}232x = x << 6;233x |= mbedtls_ct_base64_dec_value(*src);234235if (++accumulated_digits == 4) {236accumulated_digits = 0;237*p++ = MBEDTLS_BYTE_2(x);238*p++ = MBEDTLS_BYTE_1(x);239*p++ = MBEDTLS_BYTE_0(x);240}241}242if (accumulated_digits == 3) {243*p++ = MBEDTLS_BYTE_2(x << 6);244*p++ = MBEDTLS_BYTE_1(x << 6);245} else if (accumulated_digits == 2) {246*p++ = MBEDTLS_BYTE_2(x << 12);247}248249if (*olen != (size_t) (p - dst)) {250return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;251}252253return 0;254}255256#if defined(MBEDTLS_SELF_TEST)257258static const unsigned char base64_test_dec[64] =259{2600x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,2610xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,2620x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,2630x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,2640xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,2650x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,2660x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,2670xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97268};269270static const unsigned char base64_test_enc[] =271"JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"272"swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";273274/*275* Checkup routine276*/277int mbedtls_base64_self_test(int verbose)278{279size_t len;280const unsigned char *src;281unsigned char buffer[128];282283if (verbose != 0) {284mbedtls_printf(" Base64 encoding test: ");285}286287src = base64_test_dec;288289if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||290memcmp(base64_test_enc, buffer, 88) != 0) {291if (verbose != 0) {292mbedtls_printf("failed\n");293}294295return 1;296}297298if (verbose != 0) {299mbedtls_printf("passed\n Base64 decoding test: ");300}301302src = base64_test_enc;303304if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||305memcmp(base64_test_dec, buffer, 64) != 0) {306if (verbose != 0) {307mbedtls_printf("failed\n");308}309310return 1;311}312313if (verbose != 0) {314mbedtls_printf("passed\n\n");315}316317return 0;318}319320#endif /* MBEDTLS_SELF_TEST */321322#endif /* MBEDTLS_BASE64_C */323324325