From bde4a001b3ad4b90a4dbf5d31b18e30e42230e69 Mon Sep 17 00:00:00 2001 From: Nicola Tuveri Date: Fri, 6 Sep 2019 00:18:36 +0300 Subject: [PATCH] Uniform bn_bn2binpad() and bn_bn2lebinpad() implementations Reviewed-by: Matt Caswell Reviewed-by: Bernd Edlinger (Merged from https://github.com/openssl/openssl/pull/9793) --- crypto/bn/bn_lib.c | 77 +++++++++++++++++++++++++++++++++++++++------- crypto/bn_int.h | 3 ++ 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/crypto/bn/bn_lib.c b/crypto/bn/bn_lib.c index 8d9d8b32de..d4419a382c 100644 --- a/crypto/bn/bn_lib.c +++ b/crypto/bn/bn_lib.c @@ -658,8 +658,11 @@ BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret) return (ret); } +typedef enum {big, little} endianess_t; + /* ignore negative */ -static int bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) +static +int bn2binpad(const BIGNUM *a, unsigned char *to, int tolen, endianess_t endianess) { int n; size_t i, lasti, j, atop, mask; @@ -691,10 +694,17 @@ static int bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) lasti = atop - 1; atop = a->top * BN_BYTES; - for (i = 0, j = 0, to += tolen; j < (size_t)tolen; j++) { + if (endianess == big) + to += tolen; /* start from the end of the buffer */ + for (i = 0, j = 0; j < (size_t)tolen; j++) { + unsigned char val; l = a->d[i / BN_BYTES]; mask = 0 - ((j - atop) >> (8 * sizeof(i) - 1)); - *--to = (unsigned char)(l >> (8 * (i % BN_BYTES)) & mask); + val = (unsigned char)(l >> (8 * (i % BN_BYTES)) & mask); + if (endianess == big) + *--to = val; + else + *to++ = val; i += (i - lasti) >> (8 * sizeof(i) - 1); /* stay on last limb */ } @@ -705,21 +715,66 @@ int bn_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) { if (tolen < 0) return -1; - return bn2binpad(a, to, tolen); + return bn2binpad(a, to, tolen, big); } int BN_bn2bin(const BIGNUM *a, unsigned char *to) { - int n, i; + return bn2binpad(a, to, -1, big); +} + +BIGNUM *bn_lebin2bn(const unsigned char *s, int len, BIGNUM *ret) +{ + unsigned int i, m; + unsigned int n; BN_ULONG l; + BIGNUM *bn = NULL; - bn_check_top(a); - n = i = BN_num_bytes(a); - while (i--) { - l = a->d[i / BN_BYTES]; - *(to++) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff; + if (ret == NULL) + ret = bn = BN_new(); + if (ret == NULL) + return NULL; + bn_check_top(ret); + s += len; + /* Skip trailing zeroes. */ + for ( ; len > 0 && s[-1] == 0; s--, len--) + continue; + n = len; + if (n == 0) { + ret->top = 0; + return ret; + } + i = ((n - 1) / BN_BYTES) + 1; + m = ((n - 1) % (BN_BYTES)); + if (bn_wexpand(ret, (int)i) == NULL) { + BN_free(bn); + return NULL; + } + ret->top = i; + ret->neg = 0; + l = 0; + while (n--) { + s--; + l = (l << 8L) | *s; + if (m-- == 0) { + ret->d[--i] = l; + l = 0; + m = BN_BYTES - 1; + } } - return (n); + /* + * need to call this due to clear byte at top if avoiding having the top + * bit set (-ve number) + */ + bn_correct_top(ret); + return ret; +} + +int bn_bn2lebinpad(const BIGNUM *a, unsigned char *to, int tolen) +{ + if (tolen < 0) + return -1; + return bn2binpad(a, to, tolen, little); } int BN_ucmp(const BIGNUM *a, const BIGNUM *b) diff --git a/crypto/bn_int.h b/crypto/bn_int.h index a552cc20be..6791154818 100644 --- a/crypto/bn_int.h +++ b/crypto/bn_int.h @@ -19,3 +19,6 @@ int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); int bn_sqr_fixed_top(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx); int bn_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen); + +BIGNUM *bn_lebin2bn(const unsigned char *s, int len, BIGNUM *ret); +int bn_bn2lebinpad(const BIGNUM *a, unsigned char *to, int tolen); -- 2.25.1