Add Little-endian BIGNUM conversions
Towards an eventual goal of opaquifying BoringSSL structs, we want
our consumers -- in this case, Android's libcore -- to not directly
manipulate BigNums; and it would be convenient for them if we would
perform the appropriate gymnastics to interpret little-endian byte
streams.
It also seems a priori a bit strange to have only big-endian varieties
of BN byte-conversions.
This CL provides little-endian equivalents of BN_bn2bin_padded
and BN_bin2bn.
BUG=97
Change-Id: I0e92483286def86d9bd71a46d6a967a3be50f80b
Reviewed-on: https://boringssl-review.googlesource.com/12641
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/bn/bn_test.cc b/crypto/bn/bn_test.cc
index 89d9fed..4f544a7 100644
--- a/crypto/bn/bn_test.cc
+++ b/crypto/bn/bn_test.cc
@@ -747,6 +747,82 @@
return true;
}
+static bool TestLittleEndian() {
+ bssl::UniquePtr<BIGNUM> x(BN_new());
+ bssl::UniquePtr<BIGNUM> y(BN_new());
+ if (!x || !y) {
+ fprintf(stderr, "BN_new failed to malloc.\n");
+ return false;
+ }
+
+ // Test edge case at 0. Fill |out| with garbage to ensure |BN_bn2le_padded|
+ // wrote the result.
+ uint8_t out[256], zeros[256];
+ OPENSSL_memset(out, -1, sizeof(out));
+ OPENSSL_memset(zeros, 0, sizeof(zeros));
+ if (!BN_bn2le_padded(out, sizeof(out), x.get()) ||
+ OPENSSL_memcmp(zeros, out, sizeof(out))) {
+ fprintf(stderr, "BN_bn2le_padded failed to encode 0.\n");
+ return false;
+ }
+
+ if (!BN_le2bn(out, sizeof(out), y.get()) ||
+ BN_cmp(x.get(), y.get()) != 0) {
+ fprintf(stderr, "BN_le2bn failed to decode 0 correctly.\n");
+ return false;
+ }
+
+ // Test random numbers at various byte lengths.
+ for (size_t bytes = 128 - 7; bytes <= 128; bytes++) {
+ if (!BN_rand(x.get(), bytes * 8, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY)) {
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ // Fill |out| with garbage to ensure |BN_bn2le_padded| wrote the result.
+ OPENSSL_memset(out, -1, sizeof(out));
+ if (!BN_bn2le_padded(out, sizeof(out), x.get())) {
+ fprintf(stderr, "BN_bn2le_padded failed to encode random value.\n");
+ return false;
+ }
+
+ // Compute the expected value by reversing the big-endian output.
+ uint8_t expected[sizeof(out)];
+ if (!BN_bn2bin_padded(expected, sizeof(expected), x.get())) {
+ return false;
+ }
+ for (size_t i = 0; i < sizeof(expected) / 2; i++) {
+ uint8_t tmp = expected[i];
+ expected[i] = expected[sizeof(expected) - 1 - i];
+ expected[sizeof(expected) - 1 - i] = tmp;
+ }
+
+ if (OPENSSL_memcmp(expected, out, sizeof(out))) {
+ fprintf(stderr, "BN_bn2le_padded failed to encode value correctly.\n");
+ hexdump(stderr, "Expected: ", expected, sizeof(expected));
+ hexdump(stderr, "Got: ", out, sizeof(out));
+ return false;
+ }
+
+ // Make sure the decoding produces the same BIGNUM.
+ if (!BN_le2bn(out, bytes, y.get()) ||
+ BN_cmp(x.get(), y.get()) != 0) {
+ bssl::UniquePtr<char> x_hex(BN_bn2hex(x.get())),
+ y_hex(BN_bn2hex(y.get()));
+ if (!x_hex || !y_hex) {
+ return false;
+ }
+ fprintf(stderr, "BN_le2bn failed to decode value correctly.\n");
+ fprintf(stderr, "Expected: %s\n", x_hex.get());
+ hexdump(stderr, "Encoding: ", out, bytes);
+ fprintf(stderr, "Got: %s\n", y_hex.get());
+ return false;
+ }
+ }
+
+ return true;
+}
+
static int DecimalToBIGNUM(bssl::UniquePtr<BIGNUM> *out, const char *in) {
BIGNUM *raw = NULL;
int ret = BN_dec2bn(&raw, in);
@@ -1569,6 +1645,7 @@
!TestDec2BN(ctx.get()) ||
!TestHex2BN(ctx.get()) ||
!TestASC2BN(ctx.get()) ||
+ !TestLittleEndian() ||
!TestMPI() ||
!TestRand() ||
!TestASN1() ||