From c30de601850f367e4c16ad91c0168a2e0dc647c0 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Wed, 24 Nov 2021 08:23:02 +0100 Subject: [refactor] BIGNUM: Modify bin2bn() to work from least to most significant chunk This will make it easier to introduce the possibility for signed input numbers. We also refactor the inner loop to simplify the calculation of each bignum chunk. Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/17139) --- crypto/bn/bn_lib.c | 52 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) (limited to 'crypto/bn/bn_lib.c') diff --git a/crypto/bn/bn_lib.c b/crypto/bn/bn_lib.c index 6e7ed93837..a08286cab1 100644 --- a/crypto/bn/bn_lib.c +++ b/crypto/bn/bn_lib.c @@ -436,9 +436,10 @@ static BIGNUM *bin2bn(const unsigned char *s, int len, BIGNUM *ret, endianess_t endianess) { int inc; - unsigned int i, m; + const unsigned char *s2; + int inc2; + unsigned int i; unsigned int n; - BN_ULONG l; BIGNUM *bn = NULL; if (ret == NULL) @@ -448,45 +449,52 @@ static BIGNUM *bin2bn(const unsigned char *s, int len, BIGNUM *ret, bn_check_top(ret); /* - * The loop that does the work iterates from most to least + * The loop that does the work iterates from least to most * significant BIGNUM chunk, so we adapt parameters to tranfer * input bytes accordingly. */ switch (endianess) { case LITTLE: - inc = -1; - s += len - 1; + s2 = s + len - 1; + inc2 = -1; + inc = 1; break; case BIG: - inc = 1; + s2 = s; + inc2 = 1; + inc = -1; + s += len - 1; break; } - /* Skip leading zero's. */ - for ( ; len > 0 && *s == 0; s += inc, len--) + /* + * Skip leading sign extensions (zero for unsigned numbers). + * This is the only spot where |s2| and |inc2| are used. + */ + for ( ; len > 0 && *s2 == xor; s2 += inc2, len--) continue; - n = len; - if (n == 0) { + + if (len == 0) { ret->top = 0; return ret; } - i = ((n - 1) / BN_BYTES) + 1; - m = ((n - 1) % (BN_BYTES)); - if (bn_wexpand(ret, (int)i) == NULL) { + n = ((len - 1) / BN_BYTES) + 1; /* Number of resulting bignum chunks */ + if (!ossl_assert(bn_wexpand(ret, (int)n) != NULL)) { BN_free(bn); return NULL; } - ret->top = i; + ret->top = n; ret->neg = 0; - l = 0; - while (n--) { - l = (l << 8L) | *s; - s += inc; - if (m-- == 0) { - ret->d[--i] = l; - l = 0; - m = BN_BYTES - 1; + for (i = 0; n-- > 0; i++) { + BN_ULONG l = 0; /* Accumulator */ + unsigned int m = 0; /* Offset in a bignum chunk, in bits */ + + for (; len > 0 && m < BN_BYTES * 8; len--, s += inc, m += 8) { + BN_ULONG byte = *s; + + l |= (byte << m); } + ret->d[i] = l; } /* * need to call this due to clear byte at top if avoiding having the top -- cgit v1.2.3