Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/crypto/bn
diff options
context:
space:
mode:
authorMatt Braithwaite <mab@google.com>2015-08-12 03:17:28 +0300
committerAdam Langley <agl@google.com>2015-08-19 02:49:31 +0300
commit6488725e5e1ba04276733f67035ae44abd6641ec (patch)
tree30b4f03b2af6ebcd832c5506edf1d5fbe43863b3 /crypto/bn
parent1f4881fb950f248be7dbdd98a7575bc0650f1116 (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.cc60
-rw-r--r--crypto/bn/convert.c78
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;
+}