Browse Source

Optimize constant-time base64 implementation slightly.

Rather than comparing against both endpoints, subtract the minimum and
rely on unsigned wraparound to do both comparisons at once. This seems
to be slightly faster.

In addition, constant_time_lt_8 becomes much simpler if it can assume
that |a| and |b| have the same MSB. But we can arrange that by casting
up to |crypto_word_t| (which is otherwise happening anyway).

Change-Id: I82bd676e487eb7bb079ba7286df724c1c380bbb4
Reviewed-on: https://boringssl-review.googlesource.com/16445
Reviewed-by: Adam Langley <agl@google.com>
kris/onging/CECPQ3_patch15
David Benjamin 7 years ago
committed by Adam Langley
parent
commit
c49c9e7e61
1 changed files with 26 additions and 9 deletions
  1. +26
    -9
      crypto/base64/base64.c

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

@@ -65,6 +65,24 @@
#include "../internal.h"


/* constant_time_lt_args_8 behaves like |constant_time_lt_8| but takes |uint8_t|
* arguments for a slightly simpler implementation. */
static inline uint8_t constant_time_lt_args_8(uint8_t a, uint8_t b) {
crypto_word_t aw = a;
crypto_word_t bw = b;
/* |crypto_word_t| is larger than |uint8_t|, so |aw| and |bw| have the same
* MSB. |aw| < |bw| iff MSB(|aw| - |bw|) is 1. */
return constant_time_msb_w(aw - bw);
}

/* constant_time_in_range_8 returns |CONSTTIME_TRUE_8| if |min| <= |a| <= |max|
* and |CONSTTIME_FALSE_8| otherwise. */
static inline uint8_t constant_time_in_range_8(uint8_t a, uint8_t min,
uint8_t max) {
a -= min;
return constant_time_lt_args_8(a, max - min + 1);
}

/* Encoding. */

static uint8_t conv_bin2ascii(uint8_t a) {
@@ -72,9 +90,11 @@ static uint8_t conv_bin2ascii(uint8_t a) {
* 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);
ret =
constant_time_select_8(constant_time_lt_args_8(a, 62), a - 52 + '0', ret);
ret =
constant_time_select_8(constant_time_lt_args_8(a, 52), a - 26 + 'a', ret);
ret = constant_time_select_8(constant_time_lt_args_8(a, 26), a + 'A', ret);
return ret;
}

@@ -238,12 +258,9 @@ void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
static uint8_t base64_ascii_to_bin(uint8_t 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_upper = constant_time_in_range_8(a, 'A', 'Z');
const uint8_t is_lower = constant_time_in_range_8(a, 'a', 'z');
const uint8_t is_digit = constant_time_in_range_8(a, '0', '9');
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, '=');


Loading…
Cancel
Save