Browse Source

Implement base64 in constant-time.

This is not actually sensible, but it seemed really funny. PEM files
sometimes carry private keys so, in principle, we'd probably prefer not
to leak the contents when we encode or decode them?

Change-Id: I7b056612bd7f22c28853bc89f56aee1f5103b8fb
Reviewed-on: https://boringssl-review.googlesource.com/15047
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
kris/onging/CECPQ3_patch15
David Benjamin 7 years ago
committed by CQ bot account: commit-bot@chromium.org
parent
commit
536036abf4
1 changed files with 31 additions and 26 deletions
  1. +31
    -26
      crypto/base64/base64.c

+ 31
- 26
crypto/base64/base64.c View File

@@ -67,10 +67,16 @@

/* Encoding. */

static const unsigned char data_bin2ascii[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

#define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f])
static uint8_t conv_bin2ascii(uint8_t a) {
/* Since PEM is sometimes used to carry private keys, we encode base64 data
* itself in constant-time. */
a &= 0x3f;
uint8_t ret = constant_time_select_8(constant_time_eq_8(a, 62), '+', '/');
ret = constant_time_select_8(constant_time_lt_8(a, 62), a - 52 + '0', ret);
ret = constant_time_select_8(constant_time_lt_8(a, 52), a - 26 + 'a', ret);
ret = constant_time_select_8(constant_time_lt_8(a, 26), a + 'A', ret);
return ret;
}

OPENSSL_COMPILE_ASSERT(sizeof(((EVP_ENCODE_CTX *)(NULL))->data) % 3 == 0,
data_length_must_be_multiple_of_base64_chunk_size);
@@ -229,29 +235,28 @@ void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
OPENSSL_memset(ctx, 0, sizeof(EVP_ENCODE_CTX));
}

/* kBase64ASCIIToBinData maps characters (c < 128) to their base64 value, or
* else 0xff if they are invalid. As a special case, the padding character
* ('=') is mapped to zero. */
static const uint8_t kBase64ASCIIToBinData[128] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
};

static uint8_t base64_ascii_to_bin(uint8_t a) {
if (a >= 128) {
return 0xFF;
}

return kBase64ASCIIToBinData[a];
/* Since PEM is sometimes used to carry private keys, we decode base64 data
* itself in constant-time. */
const uint8_t is_upper =
constant_time_ge_8(a, 'A') & constant_time_ge_8('Z', a);
const uint8_t is_lower =
constant_time_ge_8(a, 'a') & constant_time_ge_8('z', a);
const uint8_t is_digit =
constant_time_ge_8(a, '0') & constant_time_ge_8('9', a);
const uint8_t is_plus = constant_time_eq_8(a, '+');
const uint8_t is_slash = constant_time_eq_8(a, '/');
const uint8_t is_equals = constant_time_eq_8(a, '=');

uint8_t ret = 0xff; /* 0xff signals invalid. */
ret = constant_time_select_8(is_upper, a - 'A', ret); /* [0,26) */
ret = constant_time_select_8(is_lower, a - 'a' + 26, ret); /* [26,52) */
ret = constant_time_select_8(is_digit, a - '0' + 52, ret); /* [52,62) */
ret = constant_time_select_8(is_plus, 62, ret);
ret = constant_time_select_8(is_slash, 63, ret);
/* Padding maps to zero, to be further handled by the caller. */
ret = constant_time_select_8(is_equals, 0, ret);
return ret;
}

/* base64_decode_quad decodes a single “quad” (i.e. four characters) of base64


Loading…
Cancel
Save