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:
Matt Braithwaite 2015-08-11 17:17:28 -07:00 committed by Adam Langley
parent 1f4881fb95
commit 6488725e5e
3 changed files with 157 additions and 0 deletions

View File

@ -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) {

View File

@ -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;
}

View File

@ -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 {