diff options
Diffstat (limited to 'crypto/bn/bn_lib.c')
-rw-r--r-- | crypto/bn/bn_lib.c | 52 |
1 files changed, 30 insertions, 22 deletions
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 |