diff options
author | Matt Braithwaite <mab@google.com> | 2015-08-12 03:17:28 +0300 |
---|---|---|
committer | Adam Langley <agl@google.com> | 2015-08-19 02:49:31 +0300 |
commit | 6488725e5e1ba04276733f67035ae44abd6641ec (patch) | |
tree | 30b4f03b2af6ebcd832c5506edf1d5fbe43863b3 /crypto/bn | |
parent | 1f4881fb950f248be7dbdd98a7575bc0650f1116 (diff) |
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>
Diffstat (limited to 'crypto/bn')
-rw-r--r-- | crypto/bn/bn_test.cc | 60 | ||||
-rw-r--r-- | crypto/bn/convert.c | 78 |
2 files changed, 138 insertions, 0 deletions
diff --git a/crypto/bn/bn_test.cc b/crypto/bn/bn_test.cc index e1588f71..74299c55 100644 --- a/crypto/bn/bn_test.cc +++ b/crypto/bn/bn_test.cc @@ -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) { diff --git a/crypto/bn/convert.c b/crypto/bn/convert.c index 0f2f2a51..01227091 100644 --- a/crypto/bn/convert.c +++ b/crypto/bn/convert.c @@ -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; +} |