diff options
author | Jack Lloyd <[email protected]> | 2018-08-14 21:42:42 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-08-14 21:52:24 -0400 |
commit | 759d55886dcc1f5351c22e568c87b3a30644e055 (patch) | |
tree | 64fd9b69344152fa618983045bce7dd1b519c80b | |
parent | b100a4f1de538e120413d72f09fd2ab9e43d81b5 (diff) |
Cleanup of BigInt encoding/decoding functions
Instigated by finding a bug where BigInt::encode with decimal output
would often have a leading '0' char. Which is papered over in the IO
operator, but was exposed by botan_mp_to_str which called BigInt::encode
directly.
Split BigInt::encode/decode into two versions, one taking the Base
argument and the other using the (previously default) binary base.
With a view of eventually deprecating the versions taking a base.
Add BigInt::to_dec_string() and BigInt::to_hex_string()
-rw-r--r-- | src/lib/asn1/asn1_print.cpp | 2 | ||||
-rw-r--r-- | src/lib/ffi/ffi_mp.cpp | 19 | ||||
-rw-r--r-- | src/lib/math/bigint/big_code.cpp | 51 | ||||
-rw-r--r-- | src/lib/math/bigint/bigint.cpp | 2 | ||||
-rw-r--r-- | src/lib/math/bigint/bigint.h | 101 | ||||
-rw-r--r-- | src/tests/test_ffi.cpp | 20 |
6 files changed, 162 insertions, 33 deletions
diff --git a/src/lib/asn1/asn1_print.cpp b/src/lib/asn1/asn1_print.cpp index 1f9178266..5c05d6589 100644 --- a/src/lib/asn1/asn1_print.cpp +++ b/src/lib/asn1/asn1_print.cpp @@ -174,7 +174,7 @@ void ASN1_Formatter::decode(std::ostream& output, data.decode(number, ENUMERATED, class_tag); } - std::vector<uint8_t> rep = BigInt::encode(number, BigInt::Binary); + std::vector<uint8_t> rep = BigInt::encode(number); if(rep.empty()) // if zero rep.resize(1); diff --git a/src/lib/ffi/ffi_mp.cpp b/src/lib/ffi/ffi_mp.cpp index 17d5d19c7..c7854ce9a 100644 --- a/src/lib/ffi/ffi_mp.cpp +++ b/src/lib/ffi/ffi_mp.cpp @@ -67,7 +67,7 @@ int botan_mp_set_from_radix_str(botan_mp_t mp, const char* str, size_t radix) const uint8_t* bytes = Botan::cast_char_ptr_to_uint8(str); const size_t len = strlen(str); - bn = Botan::BigInt::decode(bytes, len, base); + bn = Botan::BigInt(bytes, len, base); }); } @@ -99,26 +99,21 @@ int botan_mp_from_bin(botan_mp_t mp, const uint8_t bin[], size_t bin_len) int botan_mp_to_hex(const botan_mp_t mp, char* out) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { - std::vector<uint8_t> hex = Botan::BigInt::encode(bn, Botan::BigInt::Hexadecimal); - std::memcpy(out, hex.data(), hex.size()); - out[hex.size()] = 0; // null terminate + const std::string hex = bn.to_hex_string(); + std::strcpy(out, hex.c_str()); }); } int botan_mp_to_str(const botan_mp_t mp, uint8_t digit_base, char* out, size_t* out_len) { return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { - Botan::BigInt::Base base; + if(digit_base == 0 || digit_base == 10) - base = Botan::BigInt::Decimal; + return write_str_output(out, out_len, bn.to_dec_string()); else if(digit_base == 16) - base = Botan::BigInt::Hexadecimal; + return write_str_output(out, out_len, bn.to_hex_string()); else - throw FFI_Error("botan_mp_to_str invalid digit base", BOTAN_FFI_ERROR_BAD_PARAMETER); - - std::vector<uint8_t> hex = Botan::BigInt::encode(bn, base); - hex.push_back(0); // null terminator - return write_str_output(out, out_len, hex); + return BOTAN_FFI_ERROR_BAD_PARAMETER; }); } diff --git a/src/lib/math/bigint/big_code.cpp b/src/lib/math/bigint/big_code.cpp index c42819965..8bbbdbe2b 100644 --- a/src/lib/math/bigint/big_code.cpp +++ b/src/lib/math/bigint/big_code.cpp @@ -12,6 +12,35 @@ namespace Botan { +std::string BigInt::to_dec_string() const + { + BigInt copy = *this; + copy.set_sign(Positive); + + BigInt remainder; + std::vector<uint8_t> digits; + + while(copy > 0) + { + divide(copy, 10, copy, remainder); + digits.push_back(static_cast<uint8_t>(remainder.word_at(0))); + } + + std::string s; + + for(auto i = digits.rbegin(); i != digits.rend(); ++i) + { + s.push_back(Charset::digit2char(*i)); + } + + return s; + } + +std::string BigInt::to_hex_string() const + { + return hex_encode(BigInt::encode(*this)); + } + /* * Encode a BigInt */ @@ -53,12 +82,15 @@ void BigInt::encode(uint8_t output[], const BigInt& n, Base base) */ std::vector<uint8_t> BigInt::encode(const BigInt& n, Base base) { + if(base == Binary) + return BigInt::encode(n); + std::vector<uint8_t> output(n.encoded_size(base)); encode(output.data(), n, base); - if(base != Binary) - for(size_t j = 0; j != output.size(); ++j) - if(output[j] == 0) - output[j] = '0'; + for(size_t j = 0; j != output.size(); ++j) + if(output[j] == 0) + output[j] = '0'; + return output; } @@ -67,12 +99,15 @@ std::vector<uint8_t> BigInt::encode(const BigInt& n, Base base) */ secure_vector<uint8_t> BigInt::encode_locked(const BigInt& n, Base base) { + if(base == Binary) + return BigInt::encode_locked(n); + secure_vector<uint8_t> output(n.encoded_size(base)); encode(output.data(), n, base); - if(base != Binary) - for(size_t j = 0; j != output.size(); ++j) - if(output[j] == 0) - output[j] = '0'; + for(size_t j = 0; j != output.size(); ++j) + if(output[j] == 0) + output[j] = '0'; + return output; } diff --git a/src/lib/math/bigint/bigint.cpp b/src/lib/math/bigint/bigint.cpp index 5283c893c..b996f0fa2 100644 --- a/src/lib/math/bigint/bigint.cpp +++ b/src/lib/math/bigint/bigint.cpp @@ -96,7 +96,7 @@ BigInt::BigInt(const uint8_t input[], size_t length, Base base) BigInt::BigInt(const uint8_t buf[], size_t length, size_t max_bits) { const size_t max_bytes = std::min(length, (max_bits + 7) / 8); - *this = decode(buf, max_bytes); + binary_decode(buf, max_bytes); const size_t b = this->bits(); if(b > max_bits) diff --git a/src/lib/math/bigint/bigint.h b/src/lib/math/bigint/bigint.h index 8e09e4283..e7eca06af 100644 --- a/src/lib/math/bigint/bigint.h +++ b/src/lib/math/bigint/bigint.h @@ -79,6 +79,13 @@ class BOTAN_PUBLIC_API(2,0) BigInt final /** * Create a BigInt from an integer in a byte array + * @param vec the byte vector holding the value + */ + template<typename Alloc> + explicit BigInt(const std::vector<uint8_t, Alloc>& vec) : BigInt(vec.data(), vec.size()) {} + + /** + * Create a BigInt from an integer in a byte array * @param buf the byte array holding the value * @param length size of buf * @param base is the number base of the integer in buf @@ -423,6 +430,17 @@ class BOTAN_PUBLIC_API(2,0) BigInt final uint32_t to_u32bit() const; /** + * Convert this value to a decimal string. + * Warning: decimal conversions are relatively slow + */ + std::string to_dec_string() const; + + /** + * Convert this value to a hexadecimal string. + */ + std::string to_hex_string() const; + + /** * @param n the offset to get a byte from * @result byte at offset n */ @@ -655,10 +673,76 @@ class BOTAN_PUBLIC_API(2,0) BigInt final /** * Encode the integer value from a BigInt to a std::vector of bytes * @param n the BigInt to use as integer source + * @result secure_vector of bytes containing the bytes of the integer + */ + static std::vector<uint8_t> encode(const BigInt& n) + { + std::vector<uint8_t> output(n.bytes()); + n.binary_encode(output.data()); + return output; + } + + /** + * Encode the integer value from a BigInt to a secure_vector of bytes + * @param n the BigInt to use as integer source + * @result secure_vector of bytes containing the bytes of the integer + */ + static secure_vector<uint8_t> encode_locked(const BigInt& n) + { + secure_vector<uint8_t> output(n.bytes()); + n.binary_encode(output.data()); + return output; + } + + /** + * Encode the integer value from a BigInt to a byte array + * @param buf destination byte array for the encoded integer + * @param n the BigInt to use as integer source + */ + static void encode(uint8_t buf[], const BigInt& n) + { + n.binary_encode(buf); + } + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param length size of buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const uint8_t buf[], size_t length) + { + return BigInt(buf, length); + } + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const secure_vector<uint8_t>& buf) + { + return BigInt(buf); + } + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const std::vector<uint8_t>& buf) + { + return BigInt(buf); + } + + /** + * Encode the integer value from a BigInt to a std::vector of bytes + * @param n the BigInt to use as integer source * @param base number-base of resulting byte array representation * @result secure_vector of bytes containing the integer with given base */ - static std::vector<uint8_t> encode(const BigInt& n, Base base = Binary); + static std::vector<uint8_t> encode(const BigInt& n, Base base); /** * Encode the integer value from a BigInt to a secure_vector of bytes @@ -667,7 +751,7 @@ class BOTAN_PUBLIC_API(2,0) BigInt final * @result secure_vector of bytes containing the integer with given base */ static secure_vector<uint8_t> encode_locked(const BigInt& n, - Base base = Binary); + Base base); /** * Encode the integer value from a BigInt to a byte array @@ -676,7 +760,7 @@ class BOTAN_PUBLIC_API(2,0) BigInt final * @param n the BigInt to use as integer source * @param base number-base of resulting byte array representation */ - static void encode(uint8_t buf[], const BigInt& n, Base base = Binary); + static void encode(uint8_t buf[], const BigInt& n, Base base); /** * Create a BigInt from an integer in a byte array @@ -686,7 +770,7 @@ class BOTAN_PUBLIC_API(2,0) BigInt final * @result BigInt representing the integer in the byte array */ static BigInt decode(const uint8_t buf[], size_t length, - Base base = Binary); + Base base); /** * Create a BigInt from an integer in a byte array @@ -695,8 +779,10 @@ class BOTAN_PUBLIC_API(2,0) BigInt final * @result BigInt representing the integer in the byte array */ static BigInt decode(const secure_vector<uint8_t>& buf, - Base base = Binary) + Base base) { + if(base == Binary) + return BigInt(buf); return BigInt::decode(buf.data(), buf.size(), base); } @@ -706,9 +792,10 @@ class BOTAN_PUBLIC_API(2,0) BigInt final * @param base number-base of the integer in buf * @result BigInt representing the integer in the byte array */ - static BigInt decode(const std::vector<uint8_t>& buf, - Base base = Binary) + static BigInt decode(const std::vector<uint8_t>& buf, Base base) { + if(base == Binary) + return BigInt(buf); return BigInt::decode(buf.data(), buf.size(), base); } diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index 8bcdbeffc..eb0eacdf4 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -1100,6 +1100,9 @@ class FFI_Unit_Tests final : public Test { Test::Result result("FFI MP"); + char str_buf[1024] = { 0 }; + size_t str_len = 0; + botan_mp_t x; botan_mp_init(&x); TEST_FFI_RC(0, botan_mp_is_odd, (x)); @@ -1118,10 +1121,22 @@ class FFI_Unit_Tests final : public Test TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes)); result.test_eq("Expected size for MP 5", bn_bytes, 1); + botan_mp_set_from_int(x, 80); + TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes)); + result.test_eq("Expected size for MP 80", bn_bytes, 1); + + str_len = sizeof(str_buf); + TEST_FFI_OK(botan_mp_to_str, (x, 10, str_buf, &str_len)); + result.test_eq("botan_mp_add", std::string(str_buf), "80"); + botan_mp_set_from_int(x, 259); TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes)); result.test_eq("Expected size for MP 259", bn_bytes, 2); + str_len = sizeof(str_buf); + TEST_FFI_OK(botan_mp_to_str, (x, 10, str_buf, &str_len)); + result.test_eq("botan_mp_add", std::string(str_buf), "259"); + TEST_FFI_RC(1, botan_mp_is_odd, (x)); TEST_FFI_RC(0, botan_mp_is_even, (x)); TEST_FFI_RC(0, botan_mp_is_negative, (x)); @@ -1173,9 +1188,6 @@ class FFI_Unit_Tests final : public Test TEST_FFI_OK(botan_mp_num_bits, (x, &x_bits)); result.test_eq("botan_mp_num_bits", x_bits, 9); - char str_buf[1024] = { 0 }; - size_t str_len = 0; - TEST_FFI_OK(botan_mp_to_hex, (x, str_buf)); result.test_eq("botan_mp_to_hex", std::string(str_buf), "0103"); @@ -1218,7 +1230,7 @@ class FFI_Unit_Tests final : public Test str_len = sizeof(str_buf); TEST_FFI_OK(botan_mp_to_str, (q, 10, str_buf, &str_len)); - result.test_eq("botan_mp_div_q", std::string(str_buf), "073701"); + result.test_eq("botan_mp_div_q", std::string(str_buf), "73701"); str_len = sizeof(str_buf); TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len)); |