aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-08-14 21:42:42 -0400
committerJack Lloyd <[email protected]>2018-08-14 21:52:24 -0400
commit759d55886dcc1f5351c22e568c87b3a30644e055 (patch)
tree64fd9b69344152fa618983045bce7dd1b519c80b
parentb100a4f1de538e120413d72f09fd2ab9e43d81b5 (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.cpp2
-rw-r--r--src/lib/ffi/ffi_mp.cpp19
-rw-r--r--src/lib/math/bigint/big_code.cpp51
-rw-r--r--src/lib/math/bigint/bigint.cpp2
-rw-r--r--src/lib/math/bigint/bigint.h101
-rw-r--r--src/tests/test_ffi.cpp20
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));