Re-add |BN_bn2mpi| and |BN_mpi2bn| from OpenSSL at fd682e4c.
This benefits mainly M2Crypto. Change-Id: I29bd0fa31b218760055ba467673f3882e46010c7 Reviewed-on: https://boringssl-review.googlesource.com/5722 Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
parent
1f4881fb95
commit
6488725e5e
@ -82,6 +82,7 @@
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../crypto/test/scoped_types.h"
|
||||
#include "../crypto/test/test_util.h"
|
||||
|
||||
|
||||
// This program tests the BIGNUM implementation. It takes an optional -bc
|
||||
@ -121,6 +122,7 @@ static bool test_bn2bin_padded(BN_CTX *ctx);
|
||||
static bool test_dec2bn(BN_CTX *ctx);
|
||||
static bool test_hex2bn(BN_CTX *ctx);
|
||||
static bool test_asc2bn(BN_CTX *ctx);
|
||||
static bool test_mpi();
|
||||
static bool test_rand();
|
||||
static bool test_asn1();
|
||||
|
||||
@ -316,6 +318,7 @@ int main(int argc, char *argv[]) {
|
||||
!test_dec2bn(ctx.get()) ||
|
||||
!test_hex2bn(ctx.get()) ||
|
||||
!test_asc2bn(ctx.get()) ||
|
||||
!test_mpi() ||
|
||||
!test_rand() ||
|
||||
!test_asn1()) {
|
||||
return 1;
|
||||
@ -1582,6 +1585,63 @@ static bool test_asc2bn(BN_CTX *ctx) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct MPITest {
|
||||
const char *base10;
|
||||
const char *mpi;
|
||||
size_t mpi_len;
|
||||
};
|
||||
|
||||
static const MPITest kMPITests[] = {
|
||||
{ "0", "\x00\x00\x00\x00", 4 },
|
||||
{ "1", "\x00\x00\x00\x01\x01", 5 },
|
||||
{ "-1", "\x00\x00\x00\x01\x81", 5 },
|
||||
{ "128", "\x00\x00\x00\x02\x00\x80", 6 },
|
||||
{ "256", "\x00\x00\x00\x02\x01\x00", 6 },
|
||||
{ "-256", "\x00\x00\x00\x02\x81\x00", 6 },
|
||||
};
|
||||
|
||||
static bool test_mpi() {
|
||||
uint8_t scratch[8];
|
||||
|
||||
for (size_t i = 0; i < sizeof(kMPITests) / sizeof(kMPITests[0]); i++) {
|
||||
const MPITest &test = kMPITests[i];
|
||||
ScopedBIGNUM bn(ASCIIToBIGNUM(test.base10));
|
||||
const size_t mpi_len = BN_bn2mpi(bn.get(), NULL);
|
||||
if (mpi_len > sizeof(scratch)) {
|
||||
fprintf(stderr, "MPI test #%u: MPI size is too large to test.\n",
|
||||
(unsigned)i);
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t mpi_len2 = BN_bn2mpi(bn.get(), scratch);
|
||||
if (mpi_len != mpi_len2) {
|
||||
fprintf(stderr, "MPI test #%u: length changes.\n", (unsigned)i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mpi_len != test.mpi_len ||
|
||||
memcmp(test.mpi, scratch, mpi_len) != 0) {
|
||||
fprintf(stderr, "MPI test #%u failed:\n", (unsigned)i);
|
||||
hexdump(stderr, "Expected: ", test.mpi, test.mpi_len);
|
||||
hexdump(stderr, "Got: ", scratch, mpi_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedBIGNUM bn2(BN_mpi2bn(scratch, mpi_len, NULL));
|
||||
if (bn2.get() == nullptr) {
|
||||
fprintf(stderr, "MPI test #%u: failed to parse\n", (unsigned)i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (BN_cmp(bn.get(), bn2.get()) != 0) {
|
||||
fprintf(stderr, "MPI test #%u: wrong result\n", (unsigned)i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_rand() {
|
||||
ScopedBIGNUM bn(BN_new());
|
||||
if (!bn) {
|
||||
|
@ -517,3 +517,81 @@ BN_ULONG BN_get_word(const BIGNUM *bn) {
|
||||
return BN_MASK2;
|
||||
}
|
||||
}
|
||||
|
||||
size_t BN_bn2mpi(const BIGNUM *in, uint8_t *out) {
|
||||
const size_t bits = BN_num_bits(in);
|
||||
const size_t bytes = (bits + 7) / 8;
|
||||
/* If the number of bits is a multiple of 8, i.e. if the MSB is set,
|
||||
* prefix with a zero byte. */
|
||||
int extend = 0;
|
||||
if (bytes != 0 && (bits & 0x07) == 0) {
|
||||
extend = 1;
|
||||
}
|
||||
|
||||
const size_t len = bytes + extend;
|
||||
if (len < bytes ||
|
||||
4 + len < len ||
|
||||
(len & 0xffffffff) != len) {
|
||||
/* If we cannot represent the number then we emit zero as the interface
|
||||
* doesn't allow an error to be signalled. */
|
||||
if (out) {
|
||||
memset(out, 0, 4);
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (out == NULL) {
|
||||
return 4 + len;
|
||||
}
|
||||
|
||||
out[0] = len >> 24;
|
||||
out[1] = len >> 16;
|
||||
out[2] = len >> 8;
|
||||
out[3] = len;
|
||||
if (extend) {
|
||||
out[4] = 0;
|
||||
}
|
||||
BN_bn2bin(in, out + 4 + extend);
|
||||
if (in->neg && len > 0) {
|
||||
out[4] |= 0x80;
|
||||
}
|
||||
return len + 4;
|
||||
}
|
||||
|
||||
BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) {
|
||||
if (len < 4) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
|
||||
return NULL;
|
||||
}
|
||||
const size_t in_len = ((size_t)in[0] << 24) |
|
||||
((size_t)in[1] << 16) |
|
||||
((size_t)in[2] << 8) |
|
||||
((size_t)in[3]);
|
||||
if (in_len != len - 4) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (out == NULL) {
|
||||
out = BN_new();
|
||||
}
|
||||
if (out == NULL) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (in_len == 0) {
|
||||
BN_zero(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
in += 4;
|
||||
if (BN_bin2bn(in, in_len, out) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
out->neg = ((*in) & 0x80) != 0;
|
||||
if (out->neg) {
|
||||
BN_clear_bit(out, BN_num_bits(out) - 1);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -794,6 +794,25 @@ OPENSSL_EXPORT int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1,
|
||||
BN_CTX *ctx, BN_MONT_CTX *m_ctx);
|
||||
|
||||
|
||||
/* Deprecated functions */
|
||||
|
||||
/* BN_bn2mpi serialises the value of |in| to |out|, using a format that consists
|
||||
* of the number's length in bytes represented as a 4-byte big-endian number,
|
||||
* and the number itself in big-endian format, where the most significant bit
|
||||
* signals a negative number. (The representation of numbers with the MSB set is
|
||||
* prefixed with null byte). |out| must have sufficient space available; to
|
||||
* find the needed amount of space, call the function with |out| set to NULL. */
|
||||
OPENSSL_EXPORT size_t BN_bn2mpi(const BIGNUM *in, uint8_t *out);
|
||||
|
||||
/* BN_bin2bn parses |len| bytes from |in| and returns the resulting value. The
|
||||
* bytes at |in| are expected to be in the format emitted by |BN_bn2mpi|.
|
||||
*
|
||||
* If |out| is NULL then a fresh |BIGNUM| is allocated and returned, otherwise
|
||||
* |out| is reused and returned. On error, NULL is returned and the error queue
|
||||
* is updated. */
|
||||
OPENSSL_EXPORT BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out);
|
||||
|
||||
|
||||
/* Private functions */
|
||||
|
||||
struct bignum_st {
|
||||
|
Loading…
x
Reference in New Issue
Block a user