aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/alloc/locking_allocator/locking_allocator.cpp13
-rw-r--r--src/lib/asn1/asn1_obj.h12
-rw-r--r--src/lib/asn1/asn1_time.cpp349
-rw-r--r--src/lib/asn1/asn1_time.h41
-rw-r--r--src/lib/cert/x509/x509_crl.cpp8
-rw-r--r--src/lib/cert/x509/x509cert.cpp4
-rw-r--r--src/lib/cert/x509/x509opt.cpp4
-rw-r--r--src/lib/cert/x509/x509path.cpp4
-rw-r--r--src/lib/compression/compression.cpp22
-rw-r--r--src/lib/compression/zlib/zlib.h14
-rw-r--r--src/lib/filters/secqueue.cpp48
-rw-r--r--src/lib/filters/secqueue.h9
-rw-r--r--src/lib/math/ec_gfp/curve_gfp.cpp172
-rw-r--r--src/lib/math/ec_gfp/curve_gfp.h14
-rw-r--r--src/lib/math/ec_gfp/curve_nistp.cpp137
-rw-r--r--src/lib/math/ec_gfp/curve_nistp.h152
-rw-r--r--src/lib/math/ec_gfp/info.txt9
-rw-r--r--src/lib/math/ec_gfp/point_gfp.cpp351
-rw-r--r--src/lib/math/ec_gfp/point_gfp.h51
-rw-r--r--src/lib/math/mp/mp_asm.cpp4
-rw-r--r--src/lib/math/mp/mp_comba.cpp4
-rw-r--r--src/lib/math/mp/mp_core.h4
-rw-r--r--src/lib/math/mp/mp_generic/mp_asmi.h4
-rw-r--r--src/lib/math/mp/mp_generic/mp_madd.h4
-rw-r--r--src/lib/math/mp/mp_karat.cpp4
-rw-r--r--src/lib/math/mp/mp_misc.cpp4
-rw-r--r--src/lib/math/mp/mp_monty.cpp4
-rw-r--r--src/lib/math/mp/mp_mulop.cpp4
-rw-r--r--src/lib/math/mp/mp_shift.cpp4
-rw-r--r--src/lib/math/mp/mp_x86_32/mp_asmi.h4
-rw-r--r--src/lib/math/mp/mp_x86_32/mp_madd.h4
-rw-r--r--src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h4
-rw-r--r--src/lib/math/mp/mp_x86_64/mp_asmi.h4
-rw-r--r--src/lib/math/mp/mp_x86_64/mp_madd.h4
-rw-r--r--src/lib/math/numbertheory/info.txt14
-rw-r--r--src/lib/math/numbertheory/pow_mod.cpp44
-rw-r--r--src/lib/math/numbertheory/pow_mod.h2
-rw-r--r--src/lib/misc/benchmark/benchmark.cpp18
-rw-r--r--src/lib/pubkey/ecdsa/ecdsa.cpp35
-rw-r--r--src/lib/pubkey/gost_3410/gost_3410.cpp38
-rw-r--r--src/lib/pubkey/pk_utils.h1
-rw-r--r--src/lib/pubkey/rsa/rsa.cpp12
-rw-r--r--src/lib/rng/rng.h30
-rw-r--r--src/lib/tls/tls_server.cpp2
-rw-r--r--src/lib/utils/exceptn.h21
-rw-r--r--src/lib/utils/parsing.cpp29
-rw-r--r--src/lib/vendor/openssl/openssl_ecdsa.cpp217
47 files changed, 1126 insertions, 811 deletions
diff --git a/src/lib/alloc/locking_allocator/locking_allocator.cpp b/src/lib/alloc/locking_allocator/locking_allocator.cpp
index 6a9cc2579..c145cfd7f 100644
--- a/src/lib/alloc/locking_allocator/locking_allocator.cpp
+++ b/src/lib/alloc/locking_allocator/locking_allocator.cpp
@@ -18,15 +18,11 @@ namespace Botan {
namespace {
-/**
-* Requests for objects of sizeof(T) will be aligned at
-* sizeof(T)*ALIGNMENT_MULTIPLE bytes.
-*/
-const size_t ALIGNMENT_MULTIPLE = 2;
-
size_t reset_mlock_limit(size_t max_req)
{
+#if defined(RLIMIT_MEMLOCK)
struct rlimit limits;
+
::getrlimit(RLIMIT_MEMLOCK, &limits);
if(limits.rlim_cur < limits.rlim_max)
@@ -37,6 +33,9 @@ size_t reset_mlock_limit(size_t max_req)
}
return std::min<size_t>(limits.rlim_cur, max_req);
+#endif
+
+ return 0;
}
size_t mlock_limit()
@@ -99,7 +98,7 @@ void* mlock_allocator::allocate(size_t num_elems, size_t elem_size)
return nullptr;
const size_t n = num_elems * elem_size;
- const size_t alignment = ALIGNMENT_MULTIPLE * elem_size;
+ const size_t alignment = 16;
if(n / elem_size != num_elems)
return nullptr; // overflow!
diff --git a/src/lib/asn1/asn1_obj.h b/src/lib/asn1/asn1_obj.h
index d208ec78e..f68ef675e 100644
--- a/src/lib/asn1/asn1_obj.h
+++ b/src/lib/asn1/asn1_obj.h
@@ -13,6 +13,9 @@
namespace Botan {
+class BER_Decoder;
+class DER_Encoder;
+
/**
* ASN.1 Type and Class Tags
*/
@@ -44,8 +47,9 @@ enum ASN1_Tag {
VISIBLE_STRING = 0x1A,
BMP_STRING = 0x1E,
- UTC_TIME = 0x17,
- GENERALIZED_TIME = 0x18,
+ UTC_TIME = 0x17,
+ GENERALIZED_TIME = 0x18,
+ UTC_OR_GENERALIZED_TIME = 0x19,
NO_OBJECT = 0xFF00,
DIRECTORY_STRING = 0xFF01
@@ -61,13 +65,13 @@ class BOTAN_DLL ASN1_Object
* Encode whatever this object is into to
* @param to the DER_Encoder that will be written to
*/
- virtual void encode_into(class DER_Encoder& to) const = 0;
+ virtual void encode_into(DER_Encoder& to) const = 0;
/**
* Decode whatever this object is from from
* @param from the BER_Decoder that will be read from
*/
- virtual void decode_from(class BER_Decoder& from) = 0;
+ virtual void decode_from(BER_Decoder& from) = 0;
virtual ~ASN1_Object() {}
};
diff --git a/src/lib/asn1/asn1_time.cpp b/src/lib/asn1/asn1_time.cpp
index 72bf87df9..a9dffa95c 100644
--- a/src/lib/asn1/asn1_time.cpp
+++ b/src/lib/asn1/asn1_time.cpp
@@ -9,6 +9,7 @@
#include <botan/der_enc.h>
#include <botan/ber_dec.h>
#include <botan/charset.h>
+#include <botan/exceptn.h>
#include <botan/parsing.h>
#include <botan/calendar.h>
#include <sstream>
@@ -16,162 +17,36 @@
namespace Botan {
-/*
-* Create an X509_Time
-*/
-X509_Time::X509_Time(const std::string& time_str)
- {
- set_to(time_str);
- }
-
-/*
-* Create a X509_Time from a time point
-*/
X509_Time::X509_Time(const std::chrono::system_clock::time_point& time)
{
calendar_point cal = calendar_value(time);
- year = cal.year;
- month = cal.month;
- day = cal.day;
- hour = cal.hour;
- minute = cal.minutes;
- second = cal.seconds;
+ m_year = cal.year;
+ m_month = cal.month;
+ m_day = cal.day;
+ m_hour = cal.hour;
+ m_minute = cal.minutes;
+ m_second = cal.seconds;
- tag = (year >= 2050) ? GENERALIZED_TIME : UTC_TIME;
+ m_tag = (m_year >= 2050) ? GENERALIZED_TIME : UTC_TIME;
}
-/*
-* Create an X509_Time
-*/
-X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag t) : tag(t)
+X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag tag)
{
set_to(t_spec, tag);
}
-/*
-* Set the time with a human readable string
-*/
-void X509_Time::set_to(const std::string& time_str)
- {
- if(time_str == "")
- {
- year = month = day = hour = minute = second = 0;
- tag = NO_OBJECT;
- return;
- }
-
- std::vector<std::string> params;
- std::string current;
-
- for(size_t j = 0; j != time_str.size(); ++j)
- {
- if(Charset::is_digit(time_str[j]))
- current += time_str[j];
- else
- {
- if(current != "")
- params.push_back(current);
- current.clear();
- }
- }
- if(current != "")
- params.push_back(current);
-
- if(params.size() < 3 || params.size() > 6)
- throw Invalid_Argument("Invalid time specification " + time_str);
-
- year = to_u32bit(params[0]);
- month = to_u32bit(params[1]);
- day = to_u32bit(params[2]);
- hour = (params.size() >= 4) ? to_u32bit(params[3]) : 0;
- minute = (params.size() >= 5) ? to_u32bit(params[4]) : 0;
- second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
-
- tag = (year >= 2050) ? GENERALIZED_TIME : UTC_TIME;
-
- if(!passes_sanity_check())
- throw Invalid_Argument("Invalid time specification " + time_str);
- }
-
-/*
-* Set the time with an ISO time format string
-*/
-void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
- {
- if(spec_tag == GENERALIZED_TIME)
- {
- if(t_spec.size() != 13 && t_spec.size() != 15)
- throw Invalid_Argument("Invalid GeneralizedTime: " + t_spec);
- }
- else if(spec_tag == UTC_TIME)
- {
- if(t_spec.size() != 11 && t_spec.size() != 13)
- throw Invalid_Argument("Invalid UTCTime: " + t_spec);
- }
- else
- {
- throw Invalid_Argument("Invalid time tag " + std::to_string(spec_tag) + " val " + t_spec);
- }
-
- if(t_spec[t_spec.size()-1] != 'Z')
- throw Invalid_Argument("Invalid time encoding: " + t_spec);
-
- const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4;
-
- std::vector<std::string> params;
- std::string current;
-
- for(size_t j = 0; j != YEAR_SIZE; ++j)
- current += t_spec[j];
- params.push_back(current);
- current.clear();
-
- for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j)
- {
- current += t_spec[j];
- if(current.size() == 2)
- {
- params.push_back(current);
- current.clear();
- }
- }
-
- year = to_u32bit(params[0]);
- month = to_u32bit(params[1]);
- day = to_u32bit(params[2]);
- hour = to_u32bit(params[3]);
- minute = to_u32bit(params[4]);
- second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
- tag = spec_tag;
-
- if(spec_tag == UTC_TIME)
- {
- if(year >= 50) year += 1900;
- else year += 2000;
- }
-
- if(!passes_sanity_check())
- throw Invalid_Argument("Invalid time specification " + t_spec);
- }
-
-/*
-* DER encode a X509_Time
-*/
void X509_Time::encode_into(DER_Encoder& der) const
{
- if(tag != GENERALIZED_TIME && tag != UTC_TIME)
+ if(m_tag != GENERALIZED_TIME && m_tag != UTC_TIME)
throw Invalid_Argument("X509_Time: Bad encoding tag");
- der.add_object(tag, UNIVERSAL,
- Charset::transcode(as_string(),
+ der.add_object(m_tag, UNIVERSAL,
+ Charset::transcode(to_string(),
LOCAL_CHARSET,
LATIN1_CHARSET));
}
-/*
-* Decode a BER encoded X509_Time
-*/
void X509_Time::decode_from(BER_Decoder& source)
{
BER_Object ber_time = source.get_next_object();
@@ -182,33 +57,36 @@ void X509_Time::decode_from(BER_Decoder& source)
ber_time.type_tag);
}
-/*
-* Return a string representation of the time
-*/
-std::string X509_Time::as_string() const
+std::string X509_Time::to_string() const
{
if(time_is_set() == false)
throw Invalid_State("X509_Time::as_string: No time set");
- u32bit full_year = year;
+ u32bit full_year = m_year;
- if(tag == UTC_TIME)
+ if(m_tag == UTC_TIME)
{
- if(year < 1950 || year >= 2050)
+ if(m_year < 1950 || m_year >= 2050)
throw Encoding_Error("X509_Time: The time " + readable_string() +
" cannot be encoded as a UTCTime");
- full_year = (year >= 2000) ? (year - 2000) : (year - 1900);
+ full_year = (m_year >= 2000) ? (m_year - 2000) : (m_year - 1900);
}
- std::string repr = std::to_string(full_year*10000000000 +
- month*100000000 +
- day*1000000 +
- hour*10000 +
- minute*100 +
- second) + "Z";
+ const auto factor_y = uint64_t{10000000000ull}; // literal exceeds 32bit int range
+ const auto factor_m = uint64_t{100000000ull};
+ const auto factor_d = uint64_t{1000000ull};
+ const auto factor_h = uint64_t{10000ull};
+ const auto factor_i = uint64_t{100ull};
- u32bit desired_size = (tag == UTC_TIME) ? 13 : 15;
+ std::string repr = std::to_string(factor_y * full_year +
+ factor_m * m_month +
+ factor_d * m_day +
+ factor_h * m_hour +
+ factor_i * m_minute +
+ m_second) + "Z";
+
+ u32bit desired_size = (m_tag == UTC_TIME) ? 13 : 15;
while(repr.size() < desired_size)
repr = "0" + repr;
@@ -216,17 +94,6 @@ std::string X509_Time::as_string() const
return repr;
}
-/*
-* Return if the time has been set somehow
-*/
-bool X509_Time::time_is_set() const
- {
- return (year != 0);
- }
-
-/*
-* Return a human readable string representation
-*/
std::string X509_Time::readable_string() const
{
if(time_is_set() == false)
@@ -237,33 +104,19 @@ std::string X509_Time::readable_string() const
{
using namespace std;
output << setfill('0')
- << setw(4) << year << "/" << setw(2) << month << "/" << setw(2) << day
+ << setw(4) << m_year << "/" << setw(2) << m_month << "/" << setw(2) << m_day
<< " "
- << setw(2) << hour << ":" << setw(2) << minute << ":" << setw(2) << second
+ << setw(2) << m_hour << ":" << setw(2) << m_minute << ":" << setw(2) << m_second
<< " UTC";
}
return output.str();
}
-/*
-* Do a general sanity check on the time
-*/
-bool X509_Time::passes_sanity_check() const
+bool X509_Time::time_is_set() const
{
- if(year < 1950 || year > 2100)
- return false;
- if(month == 0 || month > 12)
- return false;
- if(day == 0 || day > 31)
- return false;
- if(hour >= 24 || minute > 60 || second > 60)
- return false;
- return true;
+ return (m_year != 0);
}
-/*
-* Compare this time against another
-*/
s32bit X509_Time::cmp(const X509_Time& other) const
{
if(time_is_set() == false)
@@ -271,22 +124,132 @@ s32bit X509_Time::cmp(const X509_Time& other) const
const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0;
- if(year < other.year) return EARLIER;
- if(year > other.year) return LATER;
- if(month < other.month) return EARLIER;
- if(month > other.month) return LATER;
- if(day < other.day) return EARLIER;
- if(day > other.day) return LATER;
- if(hour < other.hour) return EARLIER;
- if(hour > other.hour) return LATER;
- if(minute < other.minute) return EARLIER;
- if(minute > other.minute) return LATER;
- if(second < other.second) return EARLIER;
- if(second > other.second) return LATER;
+ if(m_year < other.m_year) return EARLIER;
+ if(m_year > other.m_year) return LATER;
+ if(m_month < other.m_month) return EARLIER;
+ if(m_month > other.m_month) return LATER;
+ if(m_day < other.m_day) return EARLIER;
+ if(m_day > other.m_day) return LATER;
+ if(m_hour < other.m_hour) return EARLIER;
+ if(m_hour > other.m_hour) return LATER;
+ if(m_minute < other.m_minute) return EARLIER;
+ if(m_minute > other.m_minute) return LATER;
+ if(m_second < other.m_second) return EARLIER;
+ if(m_second > other.m_second) return LATER;
return SAME_TIME;
}
+void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
+ {
+ if(spec_tag == UTC_OR_GENERALIZED_TIME)
+ {
+ try
+ {
+ set_to(t_spec, GENERALIZED_TIME);
+ return;
+ }
+ catch(Invalid_Argument) {} // Not a generalized time. Continue
+
+ try
+ {
+ set_to(t_spec, UTC_TIME);
+ return;
+ }
+ catch(Invalid_Argument) {} // Not a UTC time. Continue
+
+ throw Invalid_Argument("Time string could not be parsed as GeneralizedTime or UTCTime.");
+ }
+
+ BOTAN_ASSERT(spec_tag == UTC_TIME || spec_tag == GENERALIZED_TIME, "Invalid tag.");
+
+ if(t_spec.empty())
+ throw Invalid_Argument("Time string must not be empty.");
+
+ if(t_spec.back() != 'Z')
+ throw Unsupported_Argument("Botan does not support times with timezones other than Z: " + t_spec);
+
+ if(spec_tag == GENERALIZED_TIME)
+ {
+ if(t_spec.size() != 13 && t_spec.size() != 15)
+ throw Invalid_Argument("Invalid GeneralizedTime string: '" + t_spec + "'");
+ }
+ else if(spec_tag == UTC_TIME)
+ {
+ if(t_spec.size() != 11 && t_spec.size() != 13)
+ throw Invalid_Argument("Invalid UTCTime string: '" + t_spec + "'");
+ }
+
+ const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4;
+
+ std::vector<std::string> params;
+ std::string current;
+
+ for(size_t j = 0; j != YEAR_SIZE; ++j)
+ current += t_spec[j];
+ params.push_back(current);
+ current.clear();
+
+ for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j)
+ {
+ current += t_spec[j];
+ if(current.size() == 2)
+ {
+ params.push_back(current);
+ current.clear();
+ }
+ }
+
+ m_year = to_u32bit(params[0]);
+ m_month = to_u32bit(params[1]);
+ m_day = to_u32bit(params[2]);
+ m_hour = to_u32bit(params[3]);
+ m_minute = to_u32bit(params[4]);
+ m_second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
+ m_tag = spec_tag;
+
+ if(spec_tag == UTC_TIME)
+ {
+ if(m_year >= 50) m_year += 1900;
+ else m_year += 2000;
+ }
+
+ if(!passes_sanity_check())
+ throw Invalid_Argument("Time did not pass sanity check: " + t_spec);
+ }
+
+/*
+* Do a general sanity check on the time
+*/
+bool X509_Time::passes_sanity_check() const
+ {
+ if(m_year < 1950 || m_year > 2100)
+ return false;
+ if(m_month == 0 || m_month > 12)
+ return false;
+ if(m_day == 0 || m_day > 31)
+ return false;
+ if(m_hour >= 24 || m_minute > 60 || m_second > 60)
+ return false;
+
+ if (m_tag == UTC_TIME)
+ {
+ /*
+ UTCTime limits the value of components such that leap seconds
+ are not covered. See "UNIVERSAL 23" in "Information technology
+ Abstract Syntax Notation One (ASN.1): Specification of basic notation"
+
+ http://www.itu.int/ITU-T/studygroups/com17/languages/
+ */
+ if (m_hour > 23 || m_minute > 59 || m_second > 59)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/*
* Compare two X509_Times for in various ways
*/
diff --git a/src/lib/asn1/asn1_time.h b/src/lib/asn1/asn1_time.h
index 6200d7b62..313b26b06 100644
--- a/src/lib/asn1/asn1_time.h
+++ b/src/lib/asn1/asn1_time.h
@@ -19,27 +19,44 @@ namespace Botan {
class BOTAN_DLL X509_Time : public ASN1_Object
{
public:
- void encode_into(class DER_Encoder&) const override;
- void decode_from(class BER_Decoder&) override;
+ /// DER encode a X509_Time
+ void encode_into(DER_Encoder&) const override;
- std::string as_string() const;
+ // Decode a BER encoded X509_Time
+ void decode_from(BER_Decoder&) override;
+
+ /// Return an internal string representation of the time
+ std::string to_string() const;
+
+ /// Returns a human friendly string replesentation of no particular formatting
std::string readable_string() const;
- bool time_is_set() const;
- std::string to_string() const { return readable_string(); }
+ /// Return if the time has been set somehow
+ bool time_is_set() const;
- s32bit cmp(const X509_Time&) const;
+ /// Compare this time against another
+ s32bit cmp(const X509_Time& other) const;
- void set_to(const std::string&);
- void set_to(const std::string&, ASN1_Tag);
+ /// Create an invalid X509_Time
+ X509_Time() {}
+ /// Create a X509_Time from a time point
X509_Time(const std::chrono::system_clock::time_point& time);
- X509_Time(const std::string& = "");
- X509_Time(const std::string&, ASN1_Tag);
+
+ /// Create an X509_Time from string
+ X509_Time(const std::string& t_spec, ASN1_Tag tag);
+
private:
+ void set_to(const std::string& t_spec, ASN1_Tag);
bool passes_sanity_check() const;
- u32bit year, month, day, hour, minute, second;
- ASN1_Tag tag;
+
+ u32bit m_year = 0;
+ u32bit m_month = 0;
+ u32bit m_day = 0;
+ u32bit m_hour = 0;
+ u32bit m_minute = 0;
+ u32bit m_second = 0;
+ ASN1_Tag m_tag = NO_OBJECT;
};
/*
diff --git a/src/lib/cert/x509/x509_crl.cpp b/src/lib/cert/x509/x509_crl.cpp
index e3dfb787e..8b6d1522b 100644
--- a/src/lib/cert/x509/x509_crl.cpp
+++ b/src/lib/cert/x509/x509_crl.cpp
@@ -102,8 +102,8 @@ void X509_CRL::force_decode()
X509_Time start, end;
tbs_crl.decode(start).decode(end);
- info.add("X509.CRL.start", start.readable_string());
- info.add("X509.CRL.end", end.readable_string());
+ info.add("X509.CRL.start", start.to_string());
+ info.add("X509.CRL.end", end.to_string());
BER_Object next = tbs_crl.get_next_object();
@@ -177,7 +177,7 @@ u32bit X509_CRL::crl_number() const
*/
X509_Time X509_CRL::this_update() const
{
- return info.get1("X509.CRL.start");
+ return X509_Time(info.get1("X509.CRL.start"), ASN1_Tag::UTC_OR_GENERALIZED_TIME);
}
/*
@@ -185,7 +185,7 @@ X509_Time X509_CRL::this_update() const
*/
X509_Time X509_CRL::next_update() const
{
- return info.get1("X509.CRL.end");
+ return X509_Time(info.get1("X509.CRL.end"), ASN1_Tag::UTC_OR_GENERALIZED_TIME);
}
}
diff --git a/src/lib/cert/x509/x509cert.cpp b/src/lib/cert/x509/x509cert.cpp
index 195af7730..f6f87bbf4 100644
--- a/src/lib/cert/x509/x509cert.cpp
+++ b/src/lib/cert/x509/x509cert.cpp
@@ -136,8 +136,8 @@ void X509_Certificate::force_decode()
subject.add("X509.Certificate.version", version);
subject.add("X509.Certificate.serial", BigInt::encode(serial_bn));
- subject.add("X509.Certificate.start", start.readable_string());
- subject.add("X509.Certificate.end", end.readable_string());
+ subject.add("X509.Certificate.start", start.to_string());
+ subject.add("X509.Certificate.end", end.to_string());
issuer.add("X509.Certificate.v2.key_id", v2_issuer_key_id);
subject.add("X509.Certificate.v2.key_id", v2_subject_key_id);
diff --git a/src/lib/cert/x509/x509opt.cpp b/src/lib/cert/x509/x509opt.cpp
index c620ab25b..52845658f 100644
--- a/src/lib/cert/x509/x509opt.cpp
+++ b/src/lib/cert/x509/x509opt.cpp
@@ -17,7 +17,7 @@ namespace Botan {
*/
void X509_Cert_Options::not_before(const std::string& time_string)
{
- start = X509_Time(time_string);
+ start = X509_Time(time_string, ASN1_Tag::UTC_OR_GENERALIZED_TIME);
}
/*
@@ -25,7 +25,7 @@ void X509_Cert_Options::not_before(const std::string& time_string)
*/
void X509_Cert_Options::not_after(const std::string& time_string)
{
- end = X509_Time(time_string);
+ end = X509_Time(time_string, ASN1_Tag::UTC_OR_GENERALIZED_TIME);
}
/*
diff --git a/src/lib/cert/x509/x509path.cpp b/src/lib/cert/x509/x509path.cpp
index fa6d34a2d..09cabcb65 100644
--- a/src/lib/cert/x509/x509path.cpp
+++ b/src/lib/cert/x509/x509path.cpp
@@ -107,10 +107,10 @@ check_chain(const std::vector<X509_Certificate>& cert_path,
}
// Check all certs for valid time range
- if(current_time < X509_Time(subject.start_time()))
+ if(current_time < X509_Time(subject.start_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
status.insert(Certificate_Status_Code::CERT_NOT_YET_VALID);
- if(current_time > X509_Time(subject.end_time()))
+ if(current_time > X509_Time(subject.end_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
status.insert(Certificate_Status_Code::CERT_HAS_EXPIRED);
// Check issuer constraints
diff --git a/src/lib/compression/compression.cpp b/src/lib/compression/compression.cpp
index 6057f9408..ddbcd7cec 100644
--- a/src/lib/compression/compression.cpp
+++ b/src/lib/compression/compression.cpp
@@ -104,8 +104,16 @@ void Stream_Compression::process(secure_vector<byte>& buf, size_t offset, u32bit
if(m_buffer.size() < buf.size() + offset)
m_buffer.resize(buf.size() + offset);
- m_stream->next_in(&buf[offset], buf.size() - offset);
- m_stream->next_out(&m_buffer[offset], m_buffer.size() - offset);
+ // If the output buffer has zero length, .data() might return nullptr. This would
+ // make some compression algorithms (notably those provided by zlib) fail.
+ // Any small positive value works fine, but we choose 32 as it is the smallest power
+ // of two that is large enough to hold all the headers and trailers of the common
+ // formats, preventing further resizings to make room for output data.
+ if(m_buffer.size() == 0)
+ m_buffer.resize(32);
+
+ m_stream->next_in(buf.data() + offset, buf.size() - offset);
+ m_stream->next_out(m_buffer.data() + offset, m_buffer.size() - offset);
while(true)
{
@@ -115,7 +123,7 @@ void Stream_Compression::process(secure_vector<byte>& buf, size_t offset, u32bit
{
const size_t added = 8 + m_buffer.size();
m_buffer.resize(m_buffer.size() + added);
- m_stream->next_out(&m_buffer[m_buffer.size() - added], added);
+ m_stream->next_out(m_buffer.data() + m_buffer.size() - added, added);
}
else if(m_stream->avail_in() == 0)
{
@@ -170,8 +178,8 @@ void Stream_Decompression::process(secure_vector<byte>& buf, size_t offset, u32b
if(m_buffer.size() < buf.size() + offset)
m_buffer.resize(buf.size() + offset);
- m_stream->next_in(&buf[offset], buf.size() - offset);
- m_stream->next_out(&m_buffer[offset], m_buffer.size() - offset);
+ m_stream->next_in(buf.data() + offset, buf.size() - offset);
+ m_stream->next_out(m_buffer.data() + offset, m_buffer.size() - offset);
while(true)
{
@@ -189,14 +197,14 @@ void Stream_Decompression::process(secure_vector<byte>& buf, size_t offset, u32b
// More data follows: try to process as a following stream
const size_t read = (buf.size() - offset) - m_stream->avail_in();
start();
- m_stream->next_in(&buf[offset + read], buf.size() - offset - read);
+ m_stream->next_in(buf.data() + offset + read, buf.size() - offset - read);
}
if(m_stream->avail_out() == 0)
{
const size_t added = 8 + m_buffer.size();
m_buffer.resize(m_buffer.size() + added);
- m_stream->next_out(&m_buffer[m_buffer.size() - added], added);
+ m_stream->next_out(m_buffer.data() + m_buffer.size() - added, added);
}
else if(m_stream->avail_in() == 0)
{
diff --git a/src/lib/compression/zlib/zlib.h b/src/lib/compression/zlib/zlib.h
index 19bae3480..2437e6133 100644
--- a/src/lib/compression/zlib/zlib.h
+++ b/src/lib/compression/zlib/zlib.h
@@ -30,7 +30,7 @@ class BOTAN_DLL Zlib_Compression : public Stream_Compression
std::string name() const override { return "Zlib_Compression"; }
private:
- Compression_Stream* make_stream() const;
+ Compression_Stream* make_stream() const override;
const size_t m_level;
};
@@ -44,7 +44,7 @@ class BOTAN_DLL Zlib_Decompression : public Stream_Decompression
std::string name() const override { return "Zlib_Decompression"; }
private:
- Compression_Stream* make_stream() const;
+ Compression_Stream* make_stream() const override;
};
/**
@@ -63,7 +63,7 @@ class BOTAN_DLL Deflate_Compression : public Stream_Compression
std::string name() const override { return "Deflate_Compression"; }
private:
- Compression_Stream* make_stream() const;
+ Compression_Stream* make_stream() const override;
const size_t m_level;
};
@@ -77,7 +77,7 @@ class BOTAN_DLL Deflate_Decompression : public Stream_Decompression
std::string name() const override { return "Deflate_Decompression"; }
private:
- Compression_Stream* make_stream() const;
+ Compression_Stream* make_stream() const override;
};
/**
@@ -97,7 +97,7 @@ class BOTAN_DLL Gzip_Compression : public Stream_Compression
std::string name() const override { return "Gzip_Compression"; }
private:
- Compression_Stream* make_stream() const;
+ Compression_Stream* make_stream() const override;
const size_t m_level;
const byte m_os_code;
@@ -106,13 +106,13 @@ class BOTAN_DLL Gzip_Compression : public Stream_Compression
/**
* Gzip Decompression
*/
-class BOTAN_DLL Gzip_Decompression : public Stream_Compression
+class BOTAN_DLL Gzip_Decompression : public Stream_Decompression
{
public:
std::string name() const override { return "Gzip_Decompression"; }
private:
- Compression_Stream* make_stream() const;
+ Compression_Stream* make_stream() const override;
};
}
diff --git a/src/lib/filters/secqueue.cpp b/src/lib/filters/secqueue.cpp
index 718223876..120e8dd0d 100644
--- a/src/lib/filters/secqueue.cpp
+++ b/src/lib/filters/secqueue.cpp
@@ -60,9 +60,9 @@ class SecureQueueNode
*/
SecureQueue::SecureQueue()
{
- bytes_read = 0;
+ m_bytes_read = 0;
set_next(nullptr, 0);
- head = tail = new SecureQueueNode;
+ m_head = m_tail = new SecureQueueNode;
}
/*
@@ -71,11 +71,11 @@ SecureQueue::SecureQueue()
SecureQueue::SecureQueue(const SecureQueue& input) :
Fanout_Filter(), DataSource()
{
- bytes_read = 0;
+ m_bytes_read = 0;
set_next(nullptr, 0);
- head = tail = new SecureQueueNode;
- SecureQueueNode* temp = input.head;
+ m_head = m_tail = new SecureQueueNode;
+ SecureQueueNode* temp = input.m_head;
while(temp)
{
write(&temp->buffer[temp->start], temp->end - temp->start);
@@ -88,14 +88,14 @@ SecureQueue::SecureQueue(const SecureQueue& input) :
*/
void SecureQueue::destroy()
{
- SecureQueueNode* temp = head;
+ SecureQueueNode* temp = m_head;
while(temp)
{
SecureQueueNode* holder = temp->next;
delete temp;
temp = holder;
}
- head = tail = nullptr;
+ m_head = m_tail = nullptr;
}
/*
@@ -104,8 +104,8 @@ void SecureQueue::destroy()
SecureQueue& SecureQueue::operator=(const SecureQueue& input)
{
destroy();
- head = tail = new SecureQueueNode;
- SecureQueueNode* temp = input.head;
+ m_head = m_tail = new SecureQueueNode;
+ SecureQueueNode* temp = input.m_head;
while(temp)
{
write(&temp->buffer[temp->start], temp->end - temp->start);
@@ -119,17 +119,17 @@ SecureQueue& SecureQueue::operator=(const SecureQueue& input)
*/
void SecureQueue::write(const byte input[], size_t length)
{
- if(!head)
- head = tail = new SecureQueueNode;
+ if(!m_head)
+ m_head = m_tail = new SecureQueueNode;
while(length)
{
- const size_t n = tail->write(input, length);
+ const size_t n = m_tail->write(input, length);
input += n;
length -= n;
if(length)
{
- tail->next = new SecureQueueNode;
- tail = tail->next;
+ m_tail->next = new SecureQueueNode;
+ m_tail = m_tail->next;
}
}
}
@@ -140,20 +140,20 @@ void SecureQueue::write(const byte input[], size_t length)
size_t SecureQueue::read(byte output[], size_t length)
{
size_t got = 0;
- while(length && head)
+ while(length && m_head)
{
- const size_t n = head->read(output, length);
+ const size_t n = m_head->read(output, length);
output += n;
got += n;
length -= n;
- if(head->size() == 0)
+ if(m_head->size() == 0)
{
- SecureQueueNode* holder = head->next;
- delete head;
- head = holder;
+ SecureQueueNode* holder = m_head->next;
+ delete m_head;
+ m_head = holder;
}
}
- bytes_read += got;
+ m_bytes_read += got;
return got;
}
@@ -162,7 +162,7 @@ size_t SecureQueue::read(byte output[], size_t length)
*/
size_t SecureQueue::peek(byte output[], size_t length, size_t offset) const
{
- SecureQueueNode* current = head;
+ SecureQueueNode* current = m_head;
while(offset && current)
{
@@ -193,7 +193,7 @@ size_t SecureQueue::peek(byte output[], size_t length, size_t offset) const
*/
size_t SecureQueue::get_bytes_read() const
{
- return bytes_read;
+ return m_bytes_read;
}
/*
@@ -201,7 +201,7 @@ size_t SecureQueue::get_bytes_read() const
*/
size_t SecureQueue::size() const
{
- SecureQueueNode* current = head;
+ SecureQueueNode* current = m_head;
size_t count = 0;
while(current)
diff --git a/src/lib/filters/secqueue.h b/src/lib/filters/secqueue.h
index b548f367f..33afd478a 100644
--- a/src/lib/filters/secqueue.h
+++ b/src/lib/filters/secqueue.h
@@ -32,7 +32,7 @@ class BOTAN_DLL SecureQueue : public Fanout_Filter, public DataSource
bool empty() const;
- bool check_available(size_t n) { return n <= size(); }
+ bool check_available(size_t n) override { return n <= size(); }
/**
* @return number of bytes available in the queue
@@ -59,11 +59,12 @@ class BOTAN_DLL SecureQueue : public Fanout_Filter, public DataSource
SecureQueue(const SecureQueue& other);
~SecureQueue() { destroy(); }
+
private:
- size_t bytes_read;
void destroy();
- class SecureQueueNode* head;
- class SecureQueueNode* tail;
+ size_t m_bytes_read;
+ class SecureQueueNode* m_head;
+ class SecureQueueNode* m_tail;
};
}
diff --git a/src/lib/math/ec_gfp/curve_gfp.cpp b/src/lib/math/ec_gfp/curve_gfp.cpp
index 64d45572d..96fe873af 100644
--- a/src/lib/math/ec_gfp/curve_gfp.cpp
+++ b/src/lib/math/ec_gfp/curve_gfp.cpp
@@ -1,12 +1,12 @@
/*
* Elliptic curves over GF(p) Montgomery Representation
-* (C) 2014 Jack Lloyd
+* (C) 2014,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/curve_gfp.h>
-#include <botan/internal/curve_nistp.h>
+#include <botan/curve_nistp.h>
#include <botan/internal/mp_core.h>
#include <botan/internal/mp_asmi.h>
@@ -115,54 +115,170 @@ void CurveGFp_Montgomery::curve_sqr(BigInt& z, const BigInt& x,
ws.data());
}
-}
+class CurveGFp_NIST : public CurveGFp_Repr
+ {
+ public:
+ CurveGFp_NIST(size_t p_bits, const BigInt& a, const BigInt& b) :
+ m_a(a), m_b(b), m_p_words((p_bits + BOTAN_MP_WORD_BITS - 1) / BOTAN_MP_WORD_BITS)
+ {
+ }
+
+ const BigInt& get_a() const override { return m_a; }
+
+ const BigInt& get_b() const override { return m_b; }
+
+ size_t get_p_words() const override { return m_p_words; }
+
+ const BigInt& get_a_rep() const override { return m_a; }
+
+ const BigInt& get_b_rep() const override { return m_b; }
+
+ void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override
+ { redc(x, ws); }
+
+ void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override
+ { redc(x, ws); }
+
+ void curve_mul(BigInt& z, const BigInt& x, const BigInt& y,
+ secure_vector<word>& ws) const override;
+
+ void curve_sqr(BigInt& z, const BigInt& x,
+ secure_vector<word>& ws) const override;
+ private:
+ virtual void redc(BigInt& x, secure_vector<word>& ws) const = 0;
+
+ // Curve parameters
+ BigInt m_a, m_b;
+ size_t m_p_words; // cache of m_p.sig_words()
+ };
-// Default implementation
-void CurveGFp_Repr::normalize(BigInt& x, secure_vector<word>& ws, size_t bound) const
+void CurveGFp_NIST::curve_mul(BigInt& z, const BigInt& x, const BigInt& y,
+ secure_vector<word>& ws) const
{
- const BigInt& p = get_p();
- const word* prime = p.data();
+ if(x.is_zero() || y.is_zero())
+ {
+ z = 0;
+ return;
+ }
+
const size_t p_words = get_p_words();
+ const size_t output_size = 2*p_words + 1;
+ ws.resize(2*(p_words+2));
- while(x.is_negative())
- x += p;
+ z.grow_to(output_size);
+ z.clear();
- x.grow_to(p_words + 1);
+ bigint_mul(z.mutable_data(), output_size, ws.data(),
+ x.data(), x.size(), x.sig_words(),
+ y.data(), y.size(), y.sig_words());
- if(ws.size() < p_words + 1)
- ws.resize(p_words + 1);
+ this->redc(z, ws);
+ }
- for(size_t i = 0; bound == 0 || i < bound; ++i)
+void CurveGFp_NIST::curve_sqr(BigInt& z, const BigInt& x,
+ secure_vector<word>& ws) const
+ {
+ if(x.is_zero())
{
- const word* xd = x.data();
- word borrow = 0;
+ z = 0;
+ return;
+ }
+
+ const size_t p_words = get_p_words();
+ const size_t output_size = 2*p_words + 1;
- for(size_t i = 0; i != p_words; ++i)
- ws[i] = word_sub(xd[i], prime[i], &borrow);
- ws[p_words] = word_sub(xd[p_words], 0, &borrow);
+ ws.resize(2*(p_words+2));
- if(borrow)
- break;
+ z.grow_to(output_size);
+ z.clear();
- x.swap_reg(ws);
- }
+ bigint_sqr(z.mutable_data(), output_size, ws.data(),
+ x.data(), x.size(), x.sig_words());
+
+ this->redc(z, ws);
}
+#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32)
+
+/**
+* The NIST P-192 curve
+*/
+class CurveGFp_P192 : public CurveGFp_NIST
+ {
+ public:
+ CurveGFp_P192(const BigInt& a, const BigInt& b) : CurveGFp_NIST(192, a, b) {}
+ const BigInt& get_p() const override { return prime_p192(); }
+ private:
+ void redc(BigInt& x, secure_vector<word>& ws) const override { redc_p192(x, ws); }
+ };
+
+/**
+* The NIST P-224 curve
+*/
+class CurveGFp_P224 : public CurveGFp_NIST
+ {
+ public:
+ CurveGFp_P224(const BigInt& a, const BigInt& b) : CurveGFp_NIST(224, a, b) {}
+ const BigInt& get_p() const override { return prime_p224(); }
+ private:
+ void redc(BigInt& x, secure_vector<word>& ws) const override { redc_p224(x, ws); }
+ };
+
+/**
+* The NIST P-256 curve
+*/
+class CurveGFp_P256 : public CurveGFp_NIST
+ {
+ public:
+ CurveGFp_P256(const BigInt& a, const BigInt& b) : CurveGFp_NIST(256, a, b) {}
+ const BigInt& get_p() const override { return prime_p256(); }
+ private:
+ void redc(BigInt& x, secure_vector<word>& ws) const override { redc_p256(x, ws); }
+ };
+
+/**
+* The NIST P-384 curve
+*/
+class CurveGFp_P384 : public CurveGFp_NIST
+ {
+ public:
+ CurveGFp_P384(const BigInt& a, const BigInt& b) : CurveGFp_NIST(384, a, b) {}
+ const BigInt& get_p() const override { return prime_p384(); }
+ private:
+ void redc(BigInt& x, secure_vector<word>& ws) const override { redc_p384(x, ws); }
+ };
+
+#endif
+
+/**
+* The NIST P-521 curve
+*/
+class CurveGFp_P521 : public CurveGFp_NIST
+ {
+ public:
+ CurveGFp_P521(const BigInt& a, const BigInt& b) : CurveGFp_NIST(521, a, b) {}
+ const BigInt& get_p() const override { return prime_p521(); }
+ private:
+ void redc(BigInt& x, secure_vector<word>& ws) const override { redc_p521(x, ws); }
+ };
+
+}
+
std::shared_ptr<CurveGFp_Repr>
CurveGFp::choose_repr(const BigInt& p, const BigInt& a, const BigInt& b)
{
-#if defined(BOTAN_HAS_CURVEGFP_NISTP_M32)
- if(p == CurveGFp_P192::prime())
+#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32)
+ if(p == prime_p192())
return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P192(a, b));
- if(p == CurveGFp_P224::prime())
+ if(p == prime_p224())
return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P224(a, b));
- if(p == CurveGFp_P256::prime())
+ if(p == prime_p256())
return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P256(a, b));
- if(p == CurveGFp_P384::prime())
+ if(p == prime_p384())
return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P384(a, b));
#endif
- if(p == CurveGFp_P521::prime())
+ if(p == prime_p521())
return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P521(a, b));
return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_Montgomery(p, a, b));
diff --git a/src/lib/math/ec_gfp/curve_gfp.h b/src/lib/math/ec_gfp/curve_gfp.h
index 68fe93274..dde9f633e 100644
--- a/src/lib/math/ec_gfp/curve_gfp.h
+++ b/src/lib/math/ec_gfp/curve_gfp.h
@@ -45,10 +45,6 @@ class CurveGFp_Repr
virtual void curve_sqr(BigInt& z, const BigInt& x,
secure_vector<word>& ws) const = 0;
-
- virtual void normalize(BigInt& x,
- secure_vector<word>& ws,
- size_t bound) const;
};
/**
@@ -141,16 +137,6 @@ class BOTAN_DLL CurveGFp
return z;
}
- /**
- * Adjust x to be in [0,p)
- * @param bound if greater than zero, assume that no more than bound
- * additions or subtractions are required to move x into range.
- */
- void normalize(BigInt& x, secure_vector<word>& ws, size_t bound = 0) const
- {
- m_repr->normalize(x, ws, bound);
- }
-
void swap(CurveGFp& other)
{
std::swap(m_repr, other.m_repr);
diff --git a/src/lib/math/ec_gfp/curve_nistp.cpp b/src/lib/math/ec_gfp/curve_nistp.cpp
index 002cf2d47..bbc11ff21 100644
--- a/src/lib/math/ec_gfp/curve_nistp.cpp
+++ b/src/lib/math/ec_gfp/curve_nistp.cpp
@@ -1,63 +1,51 @@
/*
-* NIST curve reduction
+* NIST prime reductions
* (C) 2014,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
-#include <botan/internal/curve_nistp.h>
+#include <botan/curve_nistp.h>
#include <botan/internal/mp_core.h>
+#include <botan/internal/mp_asmi.h>
namespace Botan {
-void CurveGFp_NIST::curve_mul(BigInt& z, const BigInt& x, const BigInt& y,
- secure_vector<word>& ws) const
- {
- if(x.is_zero() || y.is_zero())
- {
- z = 0;
- return;
- }
+namespace {
- const size_t p_words = get_p_words();
- const size_t output_size = 2*p_words + 1;
- ws.resize(2*(p_words+2));
+void normalize(const BigInt& p, BigInt& x, secure_vector<word>& ws, size_t bound)
+ {
+ const word* prime = p.data();
+ const size_t p_words = p.sig_words();
- z.grow_to(output_size);
- z.clear();
+ while(x.is_negative())
+ x += p;
- bigint_mul(z.mutable_data(), output_size, ws.data(),
- x.data(), x.size(), x.sig_words(),
- y.data(), y.size(), y.sig_words());
+ // TODO: provide a high level function for this compare-and-sub operation
+ x.grow_to(p_words + 1);
- this->redc(z, ws);
- }
+ if(ws.size() < p_words + 1)
+ ws.resize(p_words + 1);
-void CurveGFp_NIST::curve_sqr(BigInt& z, const BigInt& x,
- secure_vector<word>& ws) const
- {
- if(x.is_zero())
+ for(size_t i = 0; bound == 0 || i < bound; ++i)
{
- z = 0;
- return;
- }
-
- const size_t p_words = get_p_words();
- const size_t output_size = 2*p_words + 1;
-
- ws.resize(2*(p_words+2));
+ const word* xd = x.data();
+ word borrow = 0;
- z.grow_to(output_size);
- z.clear();
+ for(size_t i = 0; i != p_words; ++i)
+ ws[i] = word_sub(xd[i], prime[i], &borrow);
+ ws[p_words] = word_sub(xd[p_words], 0, &borrow);
- bigint_sqr(z.mutable_data(), output_size, ws.data(),
- x.data(), x.size(), x.sig_words());
+ if(borrow)
+ break;
- this->redc(z, ws);
+ x.swap_reg(ws);
+ }
}
-//static
-const BigInt& CurveGFp_P521::prime()
+}
+
+const BigInt& prime_p521()
{
static const BigInt p521("0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
@@ -65,12 +53,11 @@ const BigInt& CurveGFp_P521::prime()
return p521;
}
-void CurveGFp_P521::redc(BigInt& x, secure_vector<word>& ws) const
+void redc_p521(BigInt& x, secure_vector<word>& ws)
{
- const size_t p_words = get_p_words();
-
- const size_t shift_words = 521 / MP_WORD_BITS,
- shift_bits = 521 % MP_WORD_BITS;
+ const size_t p_full_words = 521 / MP_WORD_BITS;
+ const size_t p_top_bits = 521 % MP_WORD_BITS;
+ const size_t p_words = p_full_words + 1;
const size_t x_sw = x.sig_words();
@@ -81,16 +68,16 @@ void CurveGFp_P521::redc(BigInt& x, secure_vector<word>& ws) const
ws.resize(p_words + 1);
clear_mem(ws.data(), ws.size());
- bigint_shr2(ws.data(), x.data(), x_sw, shift_words, shift_bits);
+ bigint_shr2(ws.data(), x.data(), x_sw, p_full_words, p_top_bits);
x.mask_bits(521);
bigint_add3(x.mutable_data(), x.data(), p_words, ws.data(), p_words);
- normalize(x, ws, max_redc_subtractions());
+ normalize(prime_p521(), x, ws, 1);
}
-#if defined(BOTAN_HAS_CURVEGFP_NISTP_M32)
+#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32)
namespace {
@@ -130,14 +117,13 @@ inline void set_u32bit(BigInt& x, size_t i, T v_in)
}
-//static
-const BigInt& CurveGFp_P192::prime()
+const BigInt& prime_p192()
{
static const BigInt p192("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF");
return p192;
}
-void CurveGFp_P192::redc(BigInt& x, secure_vector<word>& ws) const
+void redc_p192(BigInt& x, secure_vector<word>& ws)
{
const u32bit X6 = get_u32bit(x, 6);
const u32bit X7 = get_u32bit(x, 7);
@@ -192,17 +178,16 @@ void CurveGFp_P192::redc(BigInt& x, secure_vector<word>& ws) const
// No underflow possible
- normalize(x, ws, max_redc_subtractions());
+ normalize(prime_p192(), x, ws, 3);
}
-//static
-const BigInt& CurveGFp_P224::prime()
+const BigInt& prime_p224()
{
static const BigInt p224("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001");
return p224;
}
-void CurveGFp_P224::redc(BigInt& x, secure_vector<word>& ws) const
+void redc_p224(BigInt& x, secure_vector<word>& ws)
{
const u32bit X7 = get_u32bit(x, 7);
const u32bit X8 = get_u32bit(x, 8);
@@ -271,17 +256,16 @@ void CurveGFp_P224::redc(BigInt& x, secure_vector<word>& ws) const
BOTAN_ASSERT_EQUAL(S >> 32, 0, "No underflow");
- normalize(x, ws, max_redc_subtractions());
+ normalize(prime_p224(), x, ws, 3);
}
-//static
-const BigInt& CurveGFp_P256::prime()
+const BigInt& prime_p256()
{
static const BigInt p256("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
return p256;
}
-void CurveGFp_P256::redc(BigInt& x, secure_vector<word>& ws) const
+void redc_p256(BigInt& x, secure_vector<word>& ws)
{
const u32bit X8 = get_u32bit(x, 8);
const u32bit X9 = get_u32bit(x, 9);
@@ -396,34 +380,35 @@ void CurveGFp_P256::redc(BigInt& x, secure_vector<word>& ws) const
BOTAN_ASSERT_EQUAL(S >> 32, 0, "No underflow");
+ #if 0
if(S >= 2)
{
BOTAN_ASSERT(S <= 10, "Expected overflow");
static const BigInt P256_mults[9] = {
- 2*get_p(),
- 3*get_p(),
- 4*get_p(),
- 5*get_p(),
- 6*get_p(),
- 7*get_p(),
- 8*get_p(),
- 9*get_p(),
- 10*get_p()
+ 2*CurveGFp_P256::prime(),
+ 3*CurveGFp_P256::prime(),
+ 4*CurveGFp_P256::prime(),
+ 5*CurveGFp_P256::prime(),
+ 6*CurveGFp_P256::prime(),
+ 7*CurveGFp_P256::prime(),
+ 8*CurveGFp_P256::prime(),
+ 9*CurveGFp_P256::prime(),
+ 10*CurveGFp_P256::prime()
};
x -= P256_mults[S - 2];
}
+ #endif
- normalize(x, ws, max_redc_subtractions());
+ normalize(prime_p256(), x, ws, 10);
}
-//static
-const BigInt& CurveGFp_P384::prime()
+const BigInt& prime_p384()
{
static const BigInt p384("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF");
return p384;
}
-void CurveGFp_P384::redc(BigInt& x, secure_vector<word>& ws) const
+void redc_p384(BigInt& x, secure_vector<word>& ws)
{
const u32bit X12 = get_u32bit(x, 12);
const u32bit X13 = get_u32bit(x, 13);
@@ -569,20 +554,22 @@ void CurveGFp_P384::redc(BigInt& x, secure_vector<word>& ws) const
BOTAN_ASSERT_EQUAL(S >> 32, 0, "No underflow");
set_u32bit(x, 12, S);
+ #if 0
if(S >= 2)
{
BOTAN_ASSERT(S <= 4, "Expected overflow");
static const BigInt P384_mults[3] = {
- 2*get_p(),
- 3*get_p(),
- 4*get_p()
+ 2*CurveGFp_P384::prime(),
+ 3*CurveGFp_P384::prime(),
+ 4*CurveGFp_P384::prime()
};
x -= P384_mults[S - 2];
}
+ #endif
- normalize(x, ws, max_redc_subtractions());
+ normalize(prime_p384(), x, ws, 4);
}
#endif
diff --git a/src/lib/math/ec_gfp/curve_nistp.h b/src/lib/math/ec_gfp/curve_nistp.h
index 0bf707f58..e7af69964 100644
--- a/src/lib/math/ec_gfp/curve_nistp.h
+++ b/src/lib/math/ec_gfp/curve_nistp.h
@@ -1,152 +1,46 @@
/*
-* NIST elliptic curves over GF(p)
-* (C) 2014 Jack Lloyd
+* Arithmetic operations specialized for NIST ECC primes
+* (C) 2014,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
-#ifndef BOTAN_GFP_CURVE_NIST_H__
-#define BOTAN_GFP_CURVE_NIST_H__
+#ifndef BOTAN_NIST_PRIMES_H__
+#define BOTAN_NIST_PRIMES_H__
-#include <botan/curve_gfp.h>
-#include <memory>
+#include <botan/bigint.h>
namespace Botan {
-class CurveGFp_NIST : public CurveGFp_Repr
- {
- public:
- CurveGFp_NIST(size_t p_bits, const BigInt& a, const BigInt& b) :
- m_a(a), m_b(b), m_p_words((p_bits + BOTAN_MP_WORD_BITS - 1) / BOTAN_MP_WORD_BITS)
- {
- }
-
- size_t get_p_words() const override { return m_p_words; }
-
- const BigInt& get_a() const override { return m_a; }
-
- const BigInt& get_b() const override { return m_b; }
-
- const BigInt& get_a_rep() const override { return m_a; }
-
- const BigInt& get_b_rep() const override { return m_b; }
-
- void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override
- { redc(x, ws); }
-
- void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override
- { redc(x, ws); }
-
- void curve_mul(BigInt& z, const BigInt& x, const BigInt& y,
- secure_vector<word>& ws) const override;
-
- void curve_sqr(BigInt& z, const BigInt& x,
- secure_vector<word>& ws) const override;
- private:
- virtual void redc(BigInt& x, secure_vector<word>& ws) const = 0;
-
- virtual size_t max_redc_subtractions() const = 0;
-
- // Curve parameters
- BigInt m_a, m_b;
- size_t m_p_words; // cache of m_p.sig_words()
- };
-
-#if (BOTAN_MP_WORD_BITS == 32) || (BOTAN_MP_WORD_BITS == 64)
-
-#define BOTAN_HAS_CURVEGFP_NISTP_M32
-
-/**
-* The NIST P-192 curve
-*/
-class CurveGFp_P192 : public CurveGFp_NIST
- {
- public:
- CurveGFp_P192(const BigInt& a, const BigInt& b) : CurveGFp_NIST(192, a, b) {}
-
- static const BigInt& prime();
-
- const BigInt& get_p() const override { return CurveGFp_P192::prime(); }
-
- private:
- void redc(BigInt& x, secure_vector<word>& ws) const override;
-
- size_t max_redc_subtractions() const override { return 3; }
- };
-
/**
-* The NIST P-224 curve
-*/
-class CurveGFp_P224 : public CurveGFp_NIST
- {
- public:
- CurveGFp_P224(const BigInt& a, const BigInt& b) : CurveGFp_NIST(224, a, b) {}
-
- static const BigInt& prime();
-
- const BigInt& get_p() const override { return CurveGFp_P224::prime(); }
- private:
- void redc(BigInt& x, secure_vector<word>& ws) const override;
-
- size_t max_redc_subtractions() const override { return 3; }
- };
-
-/**
-* The NIST P-256 curve
+* NIST Prime reduction functions.
+*
+* Reduces the value in place
+*
+* ws is a workspace function which is used as a temporary,
+* and will be resized as needed.
*/
-class CurveGFp_P256 : public CurveGFp_NIST
- {
- public:
- CurveGFp_P256(const BigInt& a, const BigInt& b) : CurveGFp_NIST(256, a, b) {}
-
- static const BigInt& prime();
-
- const BigInt& get_p() const override { return CurveGFp_P256::prime(); }
-
- private:
- void redc(BigInt& x, secure_vector<word>& ws) const override;
+BOTAN_DLL const BigInt& prime_p521();
+BOTAN_DLL void redc_p521(BigInt& x, secure_vector<word>& ws);
- size_t max_redc_subtractions() const override { return 10; }
- };
+#if (BOTAN_MP_WORD_BITS == 32) || (BOTAN_MP_WORD_BITS == 64)
-/**
-* The NIST P-384 curve
-*/
-class CurveGFp_P384 : public CurveGFp_NIST
- {
- public:
- CurveGFp_P384(const BigInt& a, const BigInt& b) : CurveGFp_NIST(384, a, b) {}
+#define BOTAN_HAS_NIST_PRIME_REDUCERS_W32
- static const BigInt& prime();
+BOTAN_DLL const BigInt& prime_p384();
+BOTAN_DLL void redc_p384(BigInt& x, secure_vector<word>& ws);
- const BigInt& get_p() const override { return CurveGFp_P384::prime(); }
+BOTAN_DLL const BigInt& prime_p256();
+BOTAN_DLL void redc_p256(BigInt& x, secure_vector<word>& ws);
- private:
- void redc(BigInt& x, secure_vector<word>& ws) const override;
+BOTAN_DLL const BigInt& prime_p224();
+BOTAN_DLL void redc_p224(BigInt& x, secure_vector<word>& ws);
- size_t max_redc_subtractions() const override { return 4; }
- };
+BOTAN_DLL const BigInt& prime_p192();
+BOTAN_DLL void redc_p192(BigInt& x, secure_vector<word>& ws);
#endif
-/**
-* The NIST P-521 curve
-*/
-class CurveGFp_P521 : public CurveGFp_NIST
- {
- public:
- CurveGFp_P521(const BigInt& a, const BigInt& b) : CurveGFp_NIST(521, a, b) {}
-
- static const BigInt& prime();
-
- const BigInt& get_p() const override { return CurveGFp_P521::prime(); }
-
- private:
- void redc(BigInt& x, secure_vector<word>& ws) const override;
-
- size_t max_redc_subtractions() const override { return 1; }
- };
-
}
#endif
diff --git a/src/lib/math/ec_gfp/info.txt b/src/lib/math/ec_gfp/info.txt
index 9af40c752..060551562 100644
--- a/src/lib/math/ec_gfp/info.txt
+++ b/src/lib/math/ec_gfp/info.txt
@@ -2,15 +2,6 @@ define EC_CURVE_GFP 20131128
load_on auto
-<header:public>
-curve_gfp.h
-point_gfp.h
-</header:public>
-
-<header:internal>
-curve_nistp.h
-</header:internal>
-
<requires>
numbertheory
</requires>
diff --git a/src/lib/math/ec_gfp/point_gfp.cpp b/src/lib/math/ec_gfp/point_gfp.cpp
index 2505e4d54..705b14c52 100644
--- a/src/lib/math/ec_gfp/point_gfp.cpp
+++ b/src/lib/math/ec_gfp/point_gfp.cpp
@@ -2,36 +2,57 @@
* Point arithmetic on elliptic curves over GF(p)
*
* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
-* 2008-2011,2012,2014 Jack Lloyd
+* 2008-2011,2012,2014,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/point_gfp.h>
#include <botan/numthry.h>
+#include <botan/loadstor.h>
+#include <botan/internal/rounding.h>
namespace Botan {
+
PointGFp::PointGFp(const CurveGFp& curve) :
- curve(curve),
- coord_x(0),
- coord_y(1),
- coord_z(0)
+ m_curve(curve),
+ m_coord_x(0),
+ m_coord_y(1),
+ m_coord_z(0)
{
- curve.to_rep(coord_x, ws);
- curve.to_rep(coord_y, ws);
- curve.to_rep(coord_z, ws);
+ m_curve.to_rep(m_coord_x, m_monty_ws);
+ m_curve.to_rep(m_coord_y, m_monty_ws);
+ m_curve.to_rep(m_coord_z, m_monty_ws);
}
PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) :
- curve(curve),
- coord_x(x),
- coord_y(y),
- coord_z(1)
+ m_curve(curve),
+ m_coord_x(x),
+ m_coord_y(y),
+ m_coord_z(1)
{
- curve.to_rep(coord_x, ws);
- curve.to_rep(coord_y, ws);
- curve.to_rep(coord_z, ws);
+ m_curve.to_rep(m_coord_x, m_monty_ws);
+ m_curve.to_rep(m_coord_y, m_monty_ws);
+ m_curve.to_rep(m_coord_z, m_monty_ws);
+ }
+
+void PointGFp::randomize_repr(RandomNumberGenerator& rng)
+ {
+ if(BOTAN_POINTGFP_RANDOMIZE_BLINDING_BITS > 1)
+ {
+ BigInt mask;
+ while(mask.is_zero())
+ mask.randomize(rng, BOTAN_POINTGFP_RANDOMIZE_BLINDING_BITS, false);
+
+ m_curve.to_rep(mask, m_monty_ws);
+ const BigInt mask2 = curve_mult(mask, mask);
+ const BigInt mask3 = curve_mult(mask2, mask);
+
+ m_coord_x = curve_mult(m_coord_x, mask2);
+ m_coord_y = curve_mult(m_coord_y, mask3);
+ m_coord_z = curve_mult(m_coord_z, mask);
+ }
}
// Point addition
@@ -39,15 +60,15 @@ void PointGFp::add(const PointGFp& rhs, std::vector<BigInt>& ws_bn)
{
if(is_zero())
{
- coord_x = rhs.coord_x;
- coord_y = rhs.coord_y;
- coord_z = rhs.coord_z;
+ m_coord_x = rhs.m_coord_x;
+ m_coord_y = rhs.m_coord_y;
+ m_coord_z = rhs.m_coord_z;
return;
}
else if(rhs.is_zero())
return;
- const BigInt& p = curve.get_p();
+ const BigInt& p = m_curve.get_p();
BigInt& rhs_z2 = ws_bn[0];
BigInt& U1 = ws_bn[1];
@@ -64,13 +85,13 @@ void PointGFp::add(const PointGFp& rhs, std::vector<BigInt>& ws_bn)
http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
*/
- curve_sqr(rhs_z2, rhs.coord_z);
- curve_mult(U1, coord_x, rhs_z2);
- curve_mult(S1, coord_y, curve_mult(rhs.coord_z, rhs_z2));
+ curve_sqr(rhs_z2, rhs.m_coord_z);
+ curve_mult(U1, m_coord_x, rhs_z2);
+ curve_mult(S1, m_coord_y, curve_mult(rhs.m_coord_z, rhs_z2));
- curve_sqr(lhs_z2, coord_z);
- curve_mult(U2, rhs.coord_x, lhs_z2);
- curve_mult(S2, rhs.coord_y, curve_mult(coord_z, lhs_z2));
+ curve_sqr(lhs_z2, m_coord_z);
+ curve_mult(U2, rhs.m_coord_x, lhs_z2);
+ curve_mult(S2, rhs.m_coord_y, curve_mult(m_coord_z, lhs_z2));
H = U2;
H -= U1;
@@ -90,7 +111,10 @@ void PointGFp::add(const PointGFp& rhs, std::vector<BigInt>& ws_bn)
return;
}
- *this = PointGFp(curve); // setting myself to zero
+ // setting to zero:
+ m_coord_x = 0;
+ m_coord_y = 1;
+ m_coord_z = 0;
return;
}
@@ -100,22 +124,22 @@ void PointGFp::add(const PointGFp& rhs, std::vector<BigInt>& ws_bn)
U2 = curve_mult(U1, U2);
- curve_sqr(coord_x, r);
- coord_x -= S2;
- coord_x -= (U2 << 1);
- while(coord_x.is_negative())
- coord_x += p;
+ curve_sqr(m_coord_x, r);
+ m_coord_x -= S2;
+ m_coord_x -= (U2 << 1);
+ while(m_coord_x.is_negative())
+ m_coord_x += p;
- U2 -= coord_x;
+ U2 -= m_coord_x;
if(U2.is_negative())
U2 += p;
- curve_mult(coord_y, r, U2);
- coord_y -= curve_mult(S1, S2);
- if(coord_y.is_negative())
- coord_y += p;
+ curve_mult(m_coord_y, r, U2);
+ m_coord_y -= curve_mult(S1, S2);
+ if(m_coord_y.is_negative())
+ m_coord_y += p;
- curve_mult(coord_z, curve_mult(coord_z, rhs.coord_z), H);
+ curve_mult(m_coord_z, curve_mult(m_coord_z, rhs.m_coord_z), H);
}
// *this *= 2
@@ -123,9 +147,9 @@ void PointGFp::mult2(std::vector<BigInt>& ws_bn)
{
if(is_zero())
return;
- else if(coord_y.is_zero())
+ else if(m_coord_y.is_zero())
{
- *this = PointGFp(curve); // setting myself to zero
+ *this = PointGFp(m_curve); // setting myself to zero
return;
}
@@ -133,7 +157,7 @@ void PointGFp::mult2(std::vector<BigInt>& ws_bn)
http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc
*/
- const BigInt& p = curve.get_p();
+ const BigInt& p = m_curve.get_p();
BigInt& y_2 = ws_bn[0];
BigInt& S = ws_bn[1];
@@ -145,17 +169,17 @@ void PointGFp::mult2(std::vector<BigInt>& ws_bn)
BigInt& y = ws_bn[7];
BigInt& z = ws_bn[8];
- curve_sqr(y_2, coord_y);
+ curve_sqr(y_2, m_coord_y);
- curve_mult(S, coord_x, y_2);
+ curve_mult(S, m_coord_x, y_2);
S <<= 2; // * 4
while(S >= p)
S -= p;
- curve_sqr(z4, curve_sqr(coord_z));
- curve_mult(a_z4, curve.get_a_rep(), z4);
+ curve_sqr(z4, curve_sqr(m_coord_z));
+ curve_mult(a_z4, m_curve.get_a_rep(), z4);
- M = curve_sqr(coord_x);
+ M = curve_sqr(m_coord_x);
M *= 3;
M += a_z4;
while(M >= p)
@@ -180,14 +204,14 @@ void PointGFp::mult2(std::vector<BigInt>& ws_bn)
if(y.is_negative())
y += p;
- curve_mult(z, coord_y, coord_z);
+ curve_mult(z, m_coord_y, m_coord_z);
z <<= 1;
if(z >= p)
z -= p;
- coord_x = x;
- coord_y = y;
- coord_z = z;
+ m_coord_x = x;
+ m_coord_y = y;
+ m_coord_z = z;
}
// arithmetic operators
@@ -221,7 +245,7 @@ PointGFp multi_exponentiate(const PointGFp& p1, const BigInt& z1,
{
const PointGFp p3 = p1 + p2;
- PointGFp H(p1.curve); // create as zero
+ PointGFp H(p1.get_curve()); // create as zero
size_t bits_left = std::max(z1.bits(), z2.bits());
std::vector<BigInt> ws(9);
@@ -251,22 +275,24 @@ PointGFp multi_exponentiate(const PointGFp& p1, const BigInt& z1,
PointGFp operator*(const BigInt& scalar, const PointGFp& point)
{
- //BOTAN_ASSERT(point.on_the_curve(), "Input is valid");
+ //BOTAN_ASSERT(point.on_the_curve(), "Input is on the curve");
const CurveGFp& curve = point.get_curve();
- if(scalar.is_zero())
- return PointGFp(curve); // zero point
+ const size_t scalar_bits = scalar.bits();
std::vector<BigInt> ws(9);
- if(scalar.abs() <= 2) // special cases for small values
+ if(scalar_bits <= 2)
{
- byte value = scalar.abs().byte_at(0);
+ const byte abs_val = scalar.byte_at(0);
+
+ if(abs_val == 0)
+ return PointGFp::zero_of(curve);
PointGFp result = point;
- if(value == 2)
+ if(abs_val == 2)
result.mult2(ws);
if(scalar.is_negative())
@@ -275,94 +301,177 @@ PointGFp operator*(const BigInt& scalar, const PointGFp& point)
return result;
}
- const size_t scalar_bits = scalar.bits();
+ PointGFp R[2] = { PointGFp(curve), point };
- PointGFp x1(curve); // zero
+ for(size_t i = scalar_bits; i > 0; i--)
+ {
+ const size_t b = scalar.get_bit(i - 1);
+ R[b ^ 1].add(R[b], ws);
+ R[b].mult2(ws);
+ }
- size_t bits_left = scalar_bits;
+ if(scalar.is_negative())
+ R[0].negate();
-#if BOTAN_CURVE_GFP_USE_MONTGOMERY_LADDER
+ //BOTAN_ASSERT(R[0].on_the_curve(), "Output is on the curve");
- PointGFp x2 = point;
- while(bits_left)
+ return R[0];
+ }
+
+Blinded_Point_Multiply::Blinded_Point_Multiply(const PointGFp& base, const BigInt& order, size_t h) :
+ m_h(h > 0 ? h : 4), m_order(order), m_ws(9)
+ {
+ // Upper bound is a sanity check rather than hard limit
+ if(m_h < 1 || m_h > 8)
+ throw std::invalid_argument("Blinded_Point_Multiply invalid h param");
+
+ const CurveGFp& curve = base.get_curve();
+
+#if BOTAN_POINTGFP_BLINDED_MULTIPLY_USE_MONTGOMERY_LADDER
+
+ const PointGFp inv = -base;
+
+ m_U.resize(6*m_h + 3);
+
+ m_U[3*m_h+0] = inv;
+ m_U[3*m_h+1] = PointGFp::zero_of(curve);
+ m_U[3*m_h+2] = base;
+
+ for(size_t i = 1; i <= 3 * m_h + 1; ++i)
{
- if(scalar.get_bit(bits_left - 1))
- {
- x1.add(x2, ws);
- x2.mult2(ws);
- }
- else
- {
- x2.add(x1, ws);
- x1.mult2(ws);
- }
+ m_U[3*m_h+1+i] = m_U[3*m_h+i];
+ m_U[3*m_h+1+i].add(base, m_ws);
- --bits_left;
+ m_U[3*m_h+1-i] = m_U[3*m_h+2-i];
+ m_U[3*m_h+1-i].add(inv, m_ws);
}
-
#else
- const size_t window_bits = 4;
-
- std::vector<PointGFp> Ps(1 << window_bits);
- Ps[0] = x1;
- Ps[1] = point;
+ m_U.resize(1 << m_h);
+ m_U[0] = PointGFp::zero_of(curve);
+ m_U[1] = base;
- for(size_t i = 2; i < Ps.size(); ++i)
+ for(size_t i = 2; i < m_U.size(); ++i)
{
- Ps[i] = Ps[i-1];
- Ps[i].add(point, ws);
+ m_U[i] = m_U[i-1];
+ m_U[i].add(base, m_ws);
}
+#endif
+ }
+
+PointGFp Blinded_Point_Multiply::blinded_multiply(const BigInt& scalar_in,
+ RandomNumberGenerator& rng)
+ {
+ if(scalar_in.is_negative())
+ throw std::invalid_argument("Blinded_Point_Multiply scalar must be positive");
+
+#if BOTAN_POINTGFP_SCALAR_BLINDING_BITS > 0
+ // Choose a small mask m and use k' = k + m*order (Coron's 1st countermeasure)
+ const BigInt mask(rng, BOTAN_POINTGFP_SCALAR_BLINDING_BITS, false);
+ const BigInt scalar = scalar_in + m_order * mask;
+#else
+ const BigInt& scalar = scalar_in;
+#endif
+
+ const size_t scalar_bits = scalar.bits();
+
+ // Randomize each point representation (Coron's 3rd countermeasure)
+ for(size_t i = 0; i != m_U.size(); ++i)
+ m_U[i].randomize_repr(rng);
+
+#if BOTAN_POINTGFP_BLINDED_MULTIPLY_USE_MONTGOMERY_LADDER
+ PointGFp R = m_U.at(3*m_h + 2); // base point
+ int32_t alpha = 0;
+
+ R.randomize_repr(rng);
- while(bits_left >= window_bits)
+ /*
+ Algorithm 7 from "Randomizing the Montgomery Powering Ladder"
+ Duc-Phong Le, Chik How Tan and Michael Tunstall
+ http://eprint.iacr.org/2015/657
+
+ It takes a random walk through (a subset of) the set of addition
+ chains that end in k.
+ */
+ for(size_t i = scalar_bits; i > 0; i--)
{
- for(size_t i = 0; i != window_bits; ++i)
- x1.mult2(ws);
+ const int32_t ki = scalar.get_bit(i);
+
+ // choose gamma from -h,...,h
+ const int32_t gamma = static_cast<int32_t>((rng.next_byte() % (2*m_h))) - m_h;
+ const int32_t l = gamma - 2*alpha + ki - (ki ^ 1);
- const u32bit nibble = scalar.get_substring(bits_left - window_bits, window_bits);
- x1.add(Ps[nibble], ws);
- bits_left -= window_bits;
+ R.mult2(m_ws);
+ R.add(m_U.at(3*m_h + 1 + l), m_ws);
+ alpha = gamma;
}
- while(bits_left)
+ const int32_t k0 = scalar.get_bit(0);
+ R.add(m_U[3*m_h + 1 - alpha - (k0 ^ 1)], m_ws);
+
+#else
+
+ // N-bit windowing exponentiation:
+
+ size_t windows = round_up(scalar_bits, m_h) / m_h;
+
+ PointGFp R = m_U[0];
+
+ if(windows > 0)
{
- x1.mult2(ws);
- if(scalar.get_bit(bits_left-1))
- x1.add(point, ws);
- --bits_left;
- }
+ windows--;
+ const u32bit nibble = scalar.get_substring(windows*m_h, m_h);
+ R.add(m_U[nibble], m_ws);
+
+ /*
+ Randomize after adding the first nibble as before the addition R
+ is zero, and we cannot effectively randomize the point
+ representation of the zero point.
+ */
+ R.randomize_repr(rng);
+
+ while(windows)
+ {
+ for(size_t i = 0; i != m_h; ++i)
+ R.mult2(m_ws);
+ const u32bit nibble = scalar.get_substring((windows-1)*m_h, m_h);
+ R.add(m_U[nibble], m_ws);
+ windows--;
+ }
+ }
#endif
- if(scalar.is_negative())
- x1.negate();
-
- //BOTAN_ASSERT(x1.on_the_curve(), "Output is on the curve");
+ //BOTAN_ASSERT(R.on_the_curve(), "Output is on the curve");
- return x1;
+ return R;
}
BigInt PointGFp::get_affine_x() const
{
if(is_zero())
+ abort();
+ if(is_zero())
throw Illegal_Transformation("Cannot convert zero point to affine");
- BigInt z2 = curve_sqr(coord_z);
- curve.from_rep(z2, ws);
- z2 = inverse_mod(z2, curve.get_p());
+ BigInt z2 = curve_sqr(m_coord_z);
+ m_curve.from_rep(z2, m_monty_ws);
+ z2 = inverse_mod(z2, m_curve.get_p());
- return curve_mult(z2, coord_x);
+ return curve_mult(z2, m_coord_x);
}
BigInt PointGFp::get_affine_y() const
{
if(is_zero())
+ abort();
+ if(is_zero())
throw Illegal_Transformation("Cannot convert zero point to affine");
- BigInt z3 = curve_mult(coord_z, curve_sqr(coord_z));
- z3 = inverse_mod(z3, curve.get_p());
- curve.to_rep(z3, ws);
+ BigInt z3 = curve_mult(m_coord_z, curve_sqr(m_coord_z));
+ z3 = inverse_mod(z3, m_curve.get_p());
+ m_curve.to_rep(z3, m_monty_ws);
- return curve_mult(z3, coord_y);
+ return curve_mult(z3, m_coord_y);
}
bool PointGFp::on_the_curve() const
@@ -376,22 +485,22 @@ bool PointGFp::on_the_curve() const
if(is_zero())
return true;
- const BigInt y2 = curve.from_rep(curve_sqr(coord_y), ws);
- const BigInt x3 = curve_mult(coord_x, curve_sqr(coord_x));
- const BigInt ax = curve_mult(coord_x, curve.get_a_rep());
- const BigInt z2 = curve_sqr(coord_z);
+ const BigInt y2 = m_curve.from_rep(curve_sqr(m_coord_y), m_monty_ws);
+ const BigInt x3 = curve_mult(m_coord_x, curve_sqr(m_coord_x));
+ const BigInt ax = curve_mult(m_coord_x, m_curve.get_a_rep());
+ const BigInt z2 = curve_sqr(m_coord_z);
- if(coord_z == z2) // Is z equal to 1 (in Montgomery form)?
+ if(m_coord_z == z2) // Is z equal to 1 (in Montgomery form)?
{
- if(y2 != curve.from_rep(x3 + ax + curve.get_b_rep(), ws))
+ if(y2 != m_curve.from_rep(x3 + ax + m_curve.get_b_rep(), m_monty_ws))
return false;
}
- const BigInt z3 = curve_mult(coord_z, z2);
+ const BigInt z3 = curve_mult(m_coord_z, z2);
const BigInt ax_z4 = curve_mult(ax, curve_sqr(z2));
- const BigInt b_z6 = curve_mult(curve.get_b_rep(), curve_sqr(z3));
+ const BigInt b_z6 = curve_mult(m_curve.get_b_rep(), curve_sqr(z3));
- if(y2 != curve.from_rep(x3 + ax_z4 + b_z6, ws))
+ if(y2 != m_curve.from_rep(x3 + ax_z4 + b_z6, m_monty_ws))
return false;
return true;
@@ -400,11 +509,11 @@ bool PointGFp::on_the_curve() const
// swaps the states of *this and other, does not throw!
void PointGFp::swap(PointGFp& other)
{
- curve.swap(other.curve);
- coord_x.swap(other.coord_x);
- coord_y.swap(other.coord_y);
- coord_z.swap(other.coord_z);
- ws.swap(other.ws);
+ m_curve.swap(other.m_curve);
+ m_coord_x.swap(other.m_coord_x);
+ m_coord_y.swap(other.m_coord_y);
+ m_coord_z.swap(other.m_coord_z);
+ m_monty_ws.swap(other.m_monty_ws);
}
bool PointGFp::operator==(const PointGFp& other) const
diff --git a/src/lib/math/ec_gfp/point_gfp.h b/src/lib/math/ec_gfp/point_gfp.h
index 813ead81e..206e43155 100644
--- a/src/lib/math/ec_gfp/point_gfp.h
+++ b/src/lib/math/ec_gfp/point_gfp.h
@@ -2,7 +2,7 @@
* Point arithmetic on elliptic curves over GF(p)
*
* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
-* 2008-2011,2014 Jack Lloyd
+* 2008-2011,2014,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -58,6 +58,11 @@ class BOTAN_DLL PointGFp
*/
PointGFp(const CurveGFp& curve);
+ static PointGFp zero_of(const CurveGFp& curve)
+ {
+ return PointGFp(curve);
+ }
+
/**
* Copy constructor
*/
@@ -113,6 +118,7 @@ class BOTAN_DLL PointGFp
* @param scalar the PointGFp to multiply with *this
* @result resulting PointGFp
*/
+
PointGFp& operator*=(const BigInt& scalar);
/**
@@ -142,7 +148,7 @@ class BOTAN_DLL PointGFp
PointGFp& negate()
{
if(!is_zero())
- coord_y = curve.get_p() - coord_y;
+ m_coord_y = m_curve.get_p() - m_coord_y;
return *this;
}
@@ -150,7 +156,7 @@ class BOTAN_DLL PointGFp
* Return base curve of this point
* @result the curve over GF(p) of this point
*/
- const CurveGFp& get_curve() const { return curve; }
+ const CurveGFp& get_curve() const { return m_curve; }
/**
* get affine x coordinate
@@ -169,7 +175,7 @@ class BOTAN_DLL PointGFp
* @result true, if this point is at infinity, false otherwise.
*/
bool is_zero() const
- { return (coord_x.is_zero() && coord_z.is_zero()); }
+ { return (m_coord_x.is_zero() && m_coord_z.is_zero()); }
/**
* Checks whether the point is to be found on the underlying
@@ -185,33 +191,40 @@ class BOTAN_DLL PointGFp
void swap(PointGFp& other);
/**
+ * Randomize the point representation
+ * The actual value (get_affine_x, get_affine_y) does not change
+ */
+ void randomize_repr(RandomNumberGenerator& rng);
+
+ /**
* Equality operator
*/
bool operator==(const PointGFp& other) const;
private:
+ friend class Blinded_Point_Multiply;
BigInt curve_mult(const BigInt& x, const BigInt& y) const
{
BigInt z;
- curve.mul(z, x, y, ws);
+ m_curve.mul(z, x, y, m_monty_ws);
return z;
}
void curve_mult(BigInt& z, const BigInt& x, const BigInt& y) const
{
- curve.mul(z, x, y, ws);
+ m_curve.mul(z, x, y, m_monty_ws);
}
BigInt curve_sqr(const BigInt& x) const
{
BigInt z;
- curve.sqr(z, x, ws);
+ m_curve.sqr(z, x, m_monty_ws);
return z;
}
void curve_sqr(BigInt& z, const BigInt& x) const
{
- curve.sqr(z, x, ws);
+ m_curve.sqr(z, x, m_monty_ws);
}
/**
@@ -226,9 +239,9 @@ class BOTAN_DLL PointGFp
*/
void mult2(std::vector<BigInt>& workspace);
- CurveGFp curve;
- BigInt coord_x, coord_y, coord_z;
- mutable secure_vector<word> ws; // workspace for Montgomery
+ CurveGFp m_curve;
+ BigInt m_coord_x, m_coord_y, m_coord_z;
+ mutable secure_vector<word> m_monty_ws; // workspace for Montgomery
};
// relational operators
@@ -270,6 +283,22 @@ template<typename Alloc>
PointGFp OS2ECP(const std::vector<byte, Alloc>& data, const CurveGFp& curve)
{ return OS2ECP(data.data(), data.size(), curve); }
+/**
+
+*/
+class BOTAN_DLL Blinded_Point_Multiply
+ {
+ public:
+ Blinded_Point_Multiply(const PointGFp& base, const BigInt& order, size_t h = 0);
+
+ PointGFp blinded_multiply(const BigInt& scalar, RandomNumberGenerator& rng);
+ private:
+ const size_t m_h;
+ const BigInt& m_order;
+ std::vector<BigInt> m_ws;
+ std::vector<PointGFp> m_U;
+ };
+
}
namespace std {
diff --git a/src/lib/math/mp/mp_asm.cpp b/src/lib/math/mp/mp_asm.cpp
index 6941a22e9..cc573a792 100644
--- a/src/lib/math/mp/mp_asm.cpp
+++ b/src/lib/math/mp/mp_asm.cpp
@@ -14,8 +14,6 @@
namespace Botan {
-extern "C" {
-
/*
* Two Operand Addition, No Carry
*/
@@ -185,5 +183,3 @@ void bigint_linmul3(word z[], const word x[], size_t x_size, word y)
}
}
-
-}
diff --git a/src/lib/math/mp/mp_comba.cpp b/src/lib/math/mp/mp_comba.cpp
index a21b25ed6..0170c9fcd 100644
--- a/src/lib/math/mp/mp_comba.cpp
+++ b/src/lib/math/mp/mp_comba.cpp
@@ -10,8 +10,6 @@
namespace Botan {
-extern "C" {
-
/*
* Comba 4x4 Squaring
*/
@@ -1128,5 +1126,3 @@ void bigint_comba_mul16(word z[32], const word x[16], const word y[16])
}
}
-
-}
diff --git a/src/lib/math/mp/mp_core.h b/src/lib/math/mp/mp_core.h
index 06f1d4a2d..b97384d18 100644
--- a/src/lib/math/mp/mp_core.h
+++ b/src/lib/math/mp/mp_core.h
@@ -18,8 +18,6 @@ namespace Botan {
*/
const size_t MP_WORD_BITS = BOTAN_MP_WORD_BITS;
-extern "C" {
-
/**
* Two operand addition
* @param x the first operand (and output)
@@ -160,8 +158,6 @@ void bigint_comba_sqr8(word out[16], const word in[8]);
void bigint_comba_sqr9(word out[18], const word in[9]);
void bigint_comba_sqr16(word out[32], const word in[16]);
-}
-
/*
* High Level Multiplication/Squaring Interfaces
*/
diff --git a/src/lib/math/mp/mp_generic/mp_asmi.h b/src/lib/math/mp/mp_generic/mp_asmi.h
index c094436f6..708afdfa0 100644
--- a/src/lib/math/mp/mp_generic/mp_asmi.h
+++ b/src/lib/math/mp/mp_generic/mp_asmi.h
@@ -13,8 +13,6 @@
namespace Botan {
-extern "C" {
-
/*
* Word Addition
*/
@@ -202,6 +200,4 @@ inline void word3_muladd_2(word* w2, word* w1, word* w0, word a, word b)
}
-}
-
#endif
diff --git a/src/lib/math/mp/mp_generic/mp_madd.h b/src/lib/math/mp/mp_generic/mp_madd.h
index d0d56c23f..292c23e97 100644
--- a/src/lib/math/mp/mp_generic/mp_madd.h
+++ b/src/lib/math/mp/mp_generic/mp_madd.h
@@ -13,8 +13,6 @@
namespace Botan {
-extern "C" {
-
/*
* Word Multiply/Add
*/
@@ -68,6 +66,4 @@ inline word word_madd3(word a, word b, word c, word* d)
}
-}
-
#endif
diff --git a/src/lib/math/mp/mp_karat.cpp b/src/lib/math/mp/mp_karat.cpp
index faa91040c..96d9adae2 100644
--- a/src/lib/math/mp/mp_karat.cpp
+++ b/src/lib/math/mp/mp_karat.cpp
@@ -13,8 +13,8 @@ namespace Botan {
namespace {
-static const size_t KARATSUBA_MULTIPLY_THRESHOLD = 32;
-static const size_t KARATSUBA_SQUARE_THRESHOLD = 32;
+const size_t KARATSUBA_MULTIPLY_THRESHOLD = 32;
+const size_t KARATSUBA_SQUARE_THRESHOLD = 32;
/*
* Karatsuba Multiplication Operation
diff --git a/src/lib/math/mp/mp_misc.cpp b/src/lib/math/mp/mp_misc.cpp
index bd04818e5..542b0509e 100644
--- a/src/lib/math/mp/mp_misc.cpp
+++ b/src/lib/math/mp/mp_misc.cpp
@@ -11,8 +11,6 @@
namespace Botan {
-extern "C" {
-
/*
* Compare two MP integers
*/
@@ -79,5 +77,3 @@ word bigint_modop(word n1, word n0, word d)
}
}
-
-}
diff --git a/src/lib/math/mp/mp_monty.cpp b/src/lib/math/mp/mp_monty.cpp
index ffceaab9b..820f41e6c 100644
--- a/src/lib/math/mp/mp_monty.cpp
+++ b/src/lib/math/mp/mp_monty.cpp
@@ -13,8 +13,6 @@
namespace Botan {
-extern "C" {
-
/*
* Montgomery Reduction Algorithm
*/
@@ -112,5 +110,3 @@ void bigint_monty_sqr(word z[], size_t z_size,
}
}
-
-}
diff --git a/src/lib/math/mp/mp_mulop.cpp b/src/lib/math/mp/mp_mulop.cpp
index 95a0e015e..432c7ef53 100644
--- a/src/lib/math/mp/mp_mulop.cpp
+++ b/src/lib/math/mp/mp_mulop.cpp
@@ -12,8 +12,6 @@
namespace Botan {
-extern "C" {
-
/*
* Simple O(N^2) Multiplication
*/
@@ -73,5 +71,3 @@ void bigint_simple_sqr(word z[], const word x[], size_t x_size)
}
}
-
-}
diff --git a/src/lib/math/mp/mp_shift.cpp b/src/lib/math/mp/mp_shift.cpp
index d58a0c809..1850888a0 100644
--- a/src/lib/math/mp/mp_shift.cpp
+++ b/src/lib/math/mp/mp_shift.cpp
@@ -10,8 +10,6 @@
namespace Botan {
-extern "C" {
-
/*
* Single Operand Left Shift
*/
@@ -133,5 +131,3 @@ void bigint_shr2(word y[], const word x[], size_t x_size,
}
}
-
-}
diff --git a/src/lib/math/mp/mp_x86_32/mp_asmi.h b/src/lib/math/mp/mp_x86_32/mp_asmi.h
index 49ca428d6..95af89fc0 100644
--- a/src/lib/math/mp/mp_x86_32/mp_asmi.h
+++ b/src/lib/math/mp/mp_x86_32/mp_asmi.h
@@ -13,8 +13,6 @@
namespace Botan {
-extern "C" {
-
/*
* Helper Macros for x86 Assembly
*/
@@ -235,6 +233,4 @@ inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y)
}
-}
-
#endif
diff --git a/src/lib/math/mp/mp_x86_32/mp_madd.h b/src/lib/math/mp/mp_x86_32/mp_madd.h
index b6a60aecd..9c0990398 100644
--- a/src/lib/math/mp/mp_x86_32/mp_madd.h
+++ b/src/lib/math/mp/mp_x86_32/mp_madd.h
@@ -17,8 +17,6 @@
namespace Botan {
-extern "C" {
-
/*
* Helper Macros for x86 Assembly
*/
@@ -62,6 +60,4 @@ inline word word_madd3(word a, word b, word c, word* d)
}
-}
-
#endif
diff --git a/src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h b/src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h
index b4a9af1e3..1887e57ce 100644
--- a/src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h
+++ b/src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h
@@ -13,8 +13,6 @@
namespace Botan {
-extern "C" {
-
/*
* Word Addition
*/
@@ -537,6 +535,4 @@ inline void word3_muladd_2(word* w2, word* w1, word* w0, word a, word b)
}
-}
-
#endif
diff --git a/src/lib/math/mp/mp_x86_64/mp_asmi.h b/src/lib/math/mp/mp_x86_64/mp_asmi.h
index 2c7683650..cd5884867 100644
--- a/src/lib/math/mp/mp_x86_64/mp_asmi.h
+++ b/src/lib/math/mp/mp_x86_64/mp_asmi.h
@@ -13,8 +13,6 @@
namespace Botan {
-extern "C" {
-
/*
* Helper Macros for x86-64 Assembly
*/
@@ -233,7 +231,6 @@ inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y)
: "cc");
}
-
#undef ASM
#undef DO_8_TIMES
#undef ADD_OR_SUBTRACT
@@ -244,5 +241,4 @@ inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y)
}
-}
#endif
diff --git a/src/lib/math/mp/mp_x86_64/mp_madd.h b/src/lib/math/mp/mp_x86_64/mp_madd.h
index 25f791da4..6f9185dc0 100644
--- a/src/lib/math/mp/mp_x86_64/mp_madd.h
+++ b/src/lib/math/mp/mp_x86_64/mp_madd.h
@@ -17,8 +17,6 @@
namespace Botan {
-extern "C" {
-
/*
* Helper Macros for x86-64 Assembly
*/
@@ -64,6 +62,4 @@ inline word word_madd3(word a, word b, word c, word* d)
}
-}
-
#endif
diff --git a/src/lib/math/numbertheory/info.txt b/src/lib/math/numbertheory/info.txt
index e39a236cb..49f7ab2fb 100644
--- a/src/lib/math/numbertheory/info.txt
+++ b/src/lib/math/numbertheory/info.txt
@@ -12,20 +12,6 @@ reducer.h
def_powm.h
</header:internal>
-<source>
-dsa_gen.cpp
-jacobi.cpp
-make_prm.cpp
-mp_numth.cpp
-numthry.cpp
-pow_mod.cpp
-powm_fw.cpp
-powm_mnt.cpp
-primes.cpp
-reducer.cpp
-ressol.cpp
-</source>
-
<requires>
bigint
hash
diff --git a/src/lib/math/numbertheory/pow_mod.cpp b/src/lib/math/numbertheory/pow_mod.cpp
index 9a9bff2ad..49ff6cca2 100644
--- a/src/lib/math/numbertheory/pow_mod.cpp
+++ b/src/lib/math/numbertheory/pow_mod.cpp
@@ -15,7 +15,7 @@ namespace Botan {
*/
Power_Mod::Power_Mod(const BigInt& n, Usage_Hints hints)
{
- core = nullptr;
+ m_core = nullptr;
set_modulus(n, hints);
}
@@ -24,9 +24,9 @@ Power_Mod::Power_Mod(const BigInt& n, Usage_Hints hints)
*/
Power_Mod::Power_Mod(const Power_Mod& other)
{
- core = nullptr;
- if(other.core)
- core = other.core->copy();
+ m_core = nullptr;
+ if(other.m_core)
+ m_core = other.m_core->copy();
}
/*
@@ -34,10 +34,10 @@ Power_Mod::Power_Mod(const Power_Mod& other)
*/
Power_Mod& Power_Mod::operator=(const Power_Mod& other)
{
- delete core;
- core = nullptr;
- if(other.core)
- core = other.core->copy();
+ delete m_core;
+ m_core = nullptr;
+ if(other.m_core)
+ m_core = other.m_core->copy();
return (*this);
}
@@ -46,8 +46,8 @@ Power_Mod& Power_Mod::operator=(const Power_Mod& other)
*/
Power_Mod::~Power_Mod()
{
- delete core;
- core = nullptr;
+ delete m_core;
+ m_core = nullptr;
}
/*
@@ -55,12 +55,12 @@ Power_Mod::~Power_Mod()
*/
void Power_Mod::set_modulus(const BigInt& n, Usage_Hints hints) const
{
- delete core;
+ delete m_core;
if(n.is_odd())
- core = new Montgomery_Exponentiator(n, hints);
+ m_core = new Montgomery_Exponentiator(n, hints);
else if(n != 0)
- core = new Fixed_Window_Exponentiator(n, hints);
+ m_core = new Fixed_Window_Exponentiator(n, hints);
}
/*
@@ -71,9 +71,9 @@ void Power_Mod::set_base(const BigInt& b) const
if(b.is_zero() || b.is_negative())
throw Invalid_Argument("Power_Mod::set_base: arg must be > 0");
- if(!core)
- throw Internal_Error("Power_Mod::set_base: core was NULL");
- core->set_base(b);
+ if(!m_core)
+ throw Internal_Error("Power_Mod::set_base: m_core was NULL");
+ m_core->set_base(b);
}
/*
@@ -84,9 +84,9 @@ void Power_Mod::set_exponent(const BigInt& e) const
if(e.is_negative())
throw Invalid_Argument("Power_Mod::set_exponent: arg must be > 0");
- if(!core)
- throw Internal_Error("Power_Mod::set_exponent: core was NULL");
- core->set_exponent(e);
+ if(!m_core)
+ throw Internal_Error("Power_Mod::set_exponent: m_core was NULL");
+ m_core->set_exponent(e);
}
/*
@@ -94,9 +94,9 @@ void Power_Mod::set_exponent(const BigInt& e) const
*/
BigInt Power_Mod::execute() const
{
- if(!core)
- throw Internal_Error("Power_Mod::execute: core was NULL");
- return core->execute();
+ if(!m_core)
+ throw Internal_Error("Power_Mod::execute: m_core was NULL");
+ return m_core->execute();
}
/*
diff --git a/src/lib/math/numbertheory/pow_mod.h b/src/lib/math/numbertheory/pow_mod.h
index 9a827562e..4f94fd62d 100644
--- a/src/lib/math/numbertheory/pow_mod.h
+++ b/src/lib/math/numbertheory/pow_mod.h
@@ -63,7 +63,7 @@ class BOTAN_DLL Power_Mod
Power_Mod(const Power_Mod&);
virtual ~Power_Mod();
private:
- mutable Modular_Exponentiator* core;
+ mutable Modular_Exponentiator* m_core;
};
/**
diff --git a/src/lib/misc/benchmark/benchmark.cpp b/src/lib/misc/benchmark/benchmark.cpp
index 90d8b1aca..152b45d37 100644
--- a/src/lib/misc/benchmark/benchmark.cpp
+++ b/src/lib/misc/benchmark/benchmark.cpp
@@ -6,6 +6,7 @@
*/
#include <botan/benchmark.h>
+#include <botan/exceptn.h>
#include <botan/lookup.h>
#include <botan/buf_comp.h>
#include <botan/cipher_mode.h>
@@ -153,19 +154,18 @@ algorithm_benchmark(const std::string& name,
size_t buf_size)
{
//Algorithm_Factory& af = global_state().algorithm_factory();
- const auto providers = get_all_providers_of(name);
+ const auto provider_names = get_all_providers_of(name);
+ if (provider_names.empty())
+ throw No_Provider_Found(name);
std::map<std::string, double> all_results; // provider -> ops/sec
- if(!providers.empty())
- {
- const std::chrono::nanoseconds ns_per_provider = milliseconds / providers.size();
+ const std::chrono::nanoseconds ns_per_provider = milliseconds / provider_names.size();
- for(auto provider : providers)
- {
- auto results = time_algorithm_ops(name, provider, rng, ns_per_provider, buf_size);
- all_results[provider] = find_first_in(results, { "", "update", "encrypt" });
- }
+ for(auto provider : provider_names)
+ {
+ auto results = time_algorithm_ops(name, provider, rng, ns_per_provider, buf_size);
+ all_results[provider] = find_first_in(results, { "", "update", "encrypt" });
}
return all_results;
diff --git a/src/lib/pubkey/ecdsa/ecdsa.cpp b/src/lib/pubkey/ecdsa/ecdsa.cpp
index 2518a14fe..4a4b0c037 100644
--- a/src/lib/pubkey/ecdsa/ecdsa.cpp
+++ b/src/lib/pubkey/ecdsa/ecdsa.cpp
@@ -2,14 +2,13 @@
* ECDSA implemenation
* (C) 2007 Manuel Hartl, FlexSecure GmbH
* 2007 Falko Strenzke, FlexSecure GmbH
-* 2008-2010 Jack Lloyd
+* 2008-2010,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/internal/pk_utils.h>
#include <botan/ecdsa.h>
-#include <botan/reducer.h>
#include <botan/keypair.h>
#include <botan/rfc6979.h>
@@ -40,10 +39,10 @@ class ECDSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa,
const std::string& emsa) :
PK_Ops::Signature_with_EMSA(emsa),
- base_point(ecdsa.domain().get_base_point()),
- order(ecdsa.domain().get_order()),
- x(ecdsa.private_value()),
- mod_order(order),
+ m_order(ecdsa.domain().get_order()),
+ m_base_point(ecdsa.domain().get_base_point(), m_order),
+ m_x(ecdsa.private_value()),
+ m_mod_order(m_order),
m_hash(hash_for_deterministic_signature(emsa))
{
}
@@ -52,34 +51,34 @@ class ECDSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
RandomNumberGenerator& rng) override;
size_t message_parts() const override { return 2; }
- size_t message_part_size() const override { return order.bytes(); }
- size_t max_input_bits() const override { return order.bits(); }
+ size_t message_part_size() const override { return m_order.bytes(); }
+ size_t max_input_bits() const override { return m_order.bits(); }
private:
- const PointGFp& base_point;
- const BigInt& order;
- const BigInt& x;
- Modular_Reducer mod_order;
+ const BigInt& m_order;
+ Blinded_Point_Multiply m_base_point;
+ const BigInt& m_x;
+ Modular_Reducer m_mod_order;
std::string m_hash;
};
secure_vector<byte>
ECDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
- RandomNumberGenerator&)
+ RandomNumberGenerator& rng)
{
const BigInt m(msg, msg_len);
- const BigInt k = generate_rfc6979_nonce(x, order, m, m_hash);
+ const BigInt k = generate_rfc6979_nonce(m_x, m_order, m, m_hash);
- const PointGFp k_times_P = base_point * k;
- const BigInt r = mod_order.reduce(k_times_P.get_affine_x());
- const BigInt s = mod_order.multiply(inverse_mod(k, order), mul_add(x, r, m));
+ const PointGFp k_times_P = m_base_point.blinded_multiply(k, rng);
+ const BigInt r = m_mod_order.reduce(k_times_P.get_affine_x());
+ const BigInt s = m_mod_order.multiply(inverse_mod(k, m_order), mul_add(m_x, r, m));
// With overwhelming probability, a bug rather than actual zero r/s
BOTAN_ASSERT(s != 0, "invalid s");
BOTAN_ASSERT(r != 0, "invalid r");
- secure_vector<byte> output(2*order.bytes());
+ secure_vector<byte> output(2*m_order.bytes());
r.binary_encode(&output[output.size() / 2 - r.bytes()]);
s.binary_encode(&output[output.size() - s.bytes()]);
return output;
diff --git a/src/lib/pubkey/gost_3410/gost_3410.cpp b/src/lib/pubkey/gost_3410/gost_3410.cpp
index 9c3a0ef3c..f04692d12 100644
--- a/src/lib/pubkey/gost_3410/gost_3410.cpp
+++ b/src/lib/pubkey/gost_3410/gost_3410.cpp
@@ -2,7 +2,7 @@
* GOST 34.10-2001 implemenation
* (C) 2007 Falko Strenzke, FlexSecure GmbH
* Manuel Hartl, FlexSecure GmbH
-* (C) 2008-2010 Jack Lloyd
+* (C) 2008-2010,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -16,7 +16,6 @@ namespace Botan {
std::vector<byte> GOST_3410_PublicKey::x509_subject_public_key() const
{
- // Trust CryptoPro to come up with something obnoxious
const BigInt x = public_point().get_affine_x();
const BigInt y = public_point().get_affine_y();
@@ -53,7 +52,7 @@ GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id,
{
OID ecc_param_id;
- // Also includes hash and cipher OIDs... brilliant design guys
+ // The parameters also includes hash and cipher OIDs
BER_Decoder(alg_id.parameters).start_cons(SEQUENCE).decode(ecc_param_id);
domain_params = EC_Group(ecc_param_id);
@@ -101,21 +100,23 @@ class GOST_3410_Signature_Operation : public PK_Ops::Signature_with_EMSA
GOST_3410_Signature_Operation(const GOST_3410_PrivateKey& gost_3410,
const std::string& emsa) :
PK_Ops::Signature_with_EMSA(emsa),
- base_point(gost_3410.domain().get_base_point()),
- order(gost_3410.domain().get_order()),
- x(gost_3410.private_value()) {}
+ m_order(gost_3410.domain().get_order()),
+ m_mod_order(m_order),
+ m_base_point(gost_3410.domain().get_base_point(), m_order),
+ m_x(gost_3410.private_value()) {}
size_t message_parts() const override { return 2; }
- size_t message_part_size() const override { return order.bytes(); }
- size_t max_input_bits() const override { return order.bits(); }
+ size_t message_part_size() const override { return m_order.bytes(); }
+ size_t max_input_bits() const override { return m_order.bits(); }
secure_vector<byte> raw_sign(const byte msg[], size_t msg_len,
RandomNumberGenerator& rng) override;
private:
- const PointGFp& base_point;
- const BigInt& order;
- const BigInt& x;
+ const BigInt& m_order;
+ Modular_Reducer m_mod_order;
+ Blinded_Point_Multiply m_base_point;
+ const BigInt& m_x;
};
secure_vector<byte>
@@ -124,26 +125,25 @@ GOST_3410_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
{
BigInt k;
do
- k.randomize(rng, order.bits()-1);
- while(k >= order);
+ k.randomize(rng, m_order.bits()-1);
+ while(k >= m_order);
BigInt e = decode_le(msg, msg_len);
- e %= order;
+ e = m_mod_order.reduce(e);
if(e == 0)
e = 1;
- PointGFp k_times_P = base_point * k;
+ const PointGFp k_times_P = m_base_point.blinded_multiply(k, rng);
BOTAN_ASSERT(k_times_P.on_the_curve(), "GOST 34.10 k*g is on the curve");
- BigInt r = k_times_P.get_affine_x() % order;
-
- BigInt s = (r*x + k*e) % order;
+ const BigInt r = m_mod_order.reduce(k_times_P.get_affine_x());
+ const BigInt s = m_mod_order.reduce(r*m_x + k*e);
if(r == 0 || s == 0)
throw Invalid_State("GOST 34.10: r == 0 || s == 0");
- secure_vector<byte> output(2*order.bytes());
+ secure_vector<byte> output(2*m_order.bytes());
s.binary_encode(&output[output.size() / 2 - s.bytes()]);
r.binary_encode(&output[output.size() - r.bytes()]);
return output;
diff --git a/src/lib/pubkey/pk_utils.h b/src/lib/pubkey/pk_utils.h
index 14c304ac5..326a6ea68 100644
--- a/src/lib/pubkey/pk_utils.h
+++ b/src/lib/pubkey/pk_utils.h
@@ -11,6 +11,7 @@
#include <botan/internal/algo_registry.h>
#include <botan/internal/pk_ops_impl.h>
#include <botan/numthry.h>
+#include <botan/reducer.h>
#include <algorithm>
namespace Botan {
diff --git a/src/lib/pubkey/rsa/rsa.cpp b/src/lib/pubkey/rsa/rsa.cpp
index 13425a46f..5804d0034 100644
--- a/src/lib/pubkey/rsa/rsa.cpp
+++ b/src/lib/pubkey/rsa/rsa.cpp
@@ -87,14 +87,14 @@ class RSA_Private_Operation
BigInt blinded_private_op(const BigInt& m) const
{
+ if(m >= n)
+ throw Invalid_Argument("RSA private op - input is too large");
+
return m_blinder.unblind(private_op(m_blinder.blind(m)));
}
BigInt private_op(const BigInt& m) const
{
- if(m >= n)
- throw Invalid_Argument("RSA private op - input is too large");
-
auto future_j1 = std::async(std::launch::async, m_powermod_d1_p, m);
BigInt j2 = m_powermod_d2_q(m);
BigInt j1 = future_j1.get();
@@ -131,7 +131,8 @@ class RSA_Signature_Operation : public PK_Ops::Signature_with_EMSA,
{
const BigInt m(msg, msg_len);
const BigInt x = blinded_private_op(m);
- BOTAN_ASSERT(m == m_powermod_e_n(x), "RSA sign consistency check");
+ const BigInt c = m_powermod_e_n(x);
+ BOTAN_ASSERT(m == c, "RSA sign consistency check");
return BigInt::encode_1363(x, n.bytes());
}
};
@@ -154,7 +155,8 @@ class RSA_Decryption_Operation : public PK_Ops::Decryption_with_EME,
{
const BigInt m(msg, msg_len);
const BigInt x = blinded_private_op(m);
- BOTAN_ASSERT(m == m_powermod_e_n(x), "RSA decrypt consistency check");
+ const BigInt c = m_powermod_e_n(x);
+ BOTAN_ASSERT(m == c, "RSA sign consistency check");
return BigInt::encode_locked(x);
}
};
diff --git a/src/lib/rng/rng.h b/src/lib/rng/rng.h
index b1f78f75d..6ee67f66f 100644
--- a/src/lib/rng/rng.h
+++ b/src/lib/rng/rng.h
@@ -47,17 +47,35 @@ class BOTAN_DLL RandomNumberGenerator
}
/**
- * Return a random byte
- * @return random byte
+ * Only usable with POD types, only useful with integers
+ * get_random<u64bit>()
*/
- byte next_byte()
+ template<typename T> T get_random()
{
- byte out;
- this->randomize(&out, 1);
- return out;
+ T r;
+ this->randomize(reinterpret_cast<byte*>(&r), sizeof(r));
+ return r;
}
/**
+ * Return a value in range [0,2^bits)
+ */
+ u64bit gen_mask(size_t bits)
+ {
+ if(bits == 0 || bits > 64)
+ throw std::invalid_argument("RandomNumberGenerator::gen_mask invalid argument");
+
+ const u64bit mask = ((1 << bits) - 1);
+ return this->get_random<u64bit>() & mask;
+ }
+
+ /**
+ * Return a random byte
+ * @return random byte
+ */
+ byte next_byte() { return get_random<byte>(); }
+
+ /**
* Check whether this RNG is seeded.
* @return true if this RNG was already seeded, false otherwise.
*/
diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp
index 2f5a0e00d..330135e63 100644
--- a/src/lib/tls/tls_server.cpp
+++ b/src/lib/tls/tls_server.cpp
@@ -371,7 +371,7 @@ void Server::process_handshake_msg(const Handshake_State* active_state,
catch(...) {}
m_next_protocol = "";
- if(state.client_hello()->supports_alpn())
+ if(m_choose_next_protocol && state.client_hello()->supports_alpn())
m_next_protocol = m_choose_next_protocol(state.client_hello()->next_protocols());
if(resuming)
diff --git a/src/lib/utils/exceptn.h b/src/lib/utils/exceptn.h
index 23ac01cff..eef1b4d43 100644
--- a/src/lib/utils/exceptn.h
+++ b/src/lib/utils/exceptn.h
@@ -20,6 +20,17 @@ typedef std::runtime_error Exception;
typedef std::invalid_argument Invalid_Argument;
/**
+* Unsupported_Argument Exception
+*
+* An argument that is invalid because it is not supported by Botan.
+* It might or might not be valid in another context like a standard.
+*/
+struct BOTAN_DLL Unsupported_Argument : public Invalid_Argument
+ {
+ Unsupported_Argument(const std::string& msg) : Invalid_Argument(msg) {}
+ };
+
+/**
* Invalid_State Exception
*/
struct BOTAN_DLL Invalid_State : public Exception
@@ -102,6 +113,16 @@ struct BOTAN_DLL Algorithm_Not_Found : public Lookup_Error
};
/**
+* No_Provider_Found Exception
+*/
+struct BOTAN_DLL No_Provider_Found : public Exception
+ {
+ No_Provider_Found(const std::string& name) :
+ Exception("Could not find any provider for algorithm named \"" + name + "\"")
+ {}
+ };
+
+/**
* Invalid_Algorithm_Name Exception
*/
struct BOTAN_DLL Invalid_Algorithm_Name : public Invalid_Argument
diff --git a/src/lib/utils/parsing.cpp b/src/lib/utils/parsing.cpp
index 36b168290..4feea8d60 100644
--- a/src/lib/utils/parsing.cpp
+++ b/src/lib/utils/parsing.cpp
@@ -1,6 +1,7 @@
/*
* Various string utils and parsing functions
* (C) 1999-2007,2013,2014 Jack Lloyd
+* (C) 2015 Simon Warta (Kullo GmbH)
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -9,6 +10,7 @@
#include <botan/exceptn.h>
#include <botan/charset.h>
#include <botan/get_byte.h>
+#include <limits>
#include <set>
#include <stdexcept>
@@ -18,11 +20,32 @@ u32bit to_u32bit(const std::string& str)
{
try
{
- return std::stoul(str, nullptr);
+ // std::stoul is not strict enough. Ensure that str is digit only [0-9]*
+ for (const char chr : str)
+ {
+ if (chr < '0' || chr > '9')
+ {
+ auto chrAsString = std::string(1, chr);
+ throw Invalid_Argument("String contains non-digit char: " + chrAsString);
+ }
+ }
+
+ const auto integerValue = std::stoul(str);
+
+ // integerValue might be uint64
+ if (integerValue > std::numeric_limits<u32bit>::max())
+ {
+ throw Invalid_Argument("Integer value exceeds 32 bit range: " + std::to_string(integerValue));
+ }
+
+ return integerValue;
}
- catch(std::exception&)
+ catch(std::exception& e)
{
- throw std::runtime_error("Could not read '" + str + "' as decimal string");
+ auto message = std::string("Could not read '" + str + "' as decimal string");
+ auto exceptionMessage = std::string(e.what());
+ if (!exceptionMessage.empty()) message += ": " + exceptionMessage;
+ throw std::runtime_error(message);
}
}
diff --git a/src/lib/vendor/openssl/openssl_ecdsa.cpp b/src/lib/vendor/openssl/openssl_ecdsa.cpp
new file mode 100644
index 000000000..9016986da
--- /dev/null
+++ b/src/lib/vendor/openssl/openssl_ecdsa.cpp
@@ -0,0 +1,217 @@
+/*
+* ECDSA via OpenSSL
+* (C) 2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/build.h>
+#include <botan/internal/pk_utils.h>
+#include <functional>
+#include <memory>
+
+#include <openssl/x509.h>
+#include <openssl/err.h>
+
+#if defined(BOTAN_HAS_ECDSA) && !defined(OPENSSL_NO_ECDSA)
+
+#include <botan/der_enc.h>
+#include <botan/ecdsa.h>
+#include <botan/pkcs8.h>
+#include <botan/oids.h>
+
+#include <openssl/ecdsa.h>
+#include <openssl/ec.h>
+#include <openssl/objects.h>
+
+namespace Botan {
+
+namespace {
+
+secure_vector<byte> PKCS8_for_openssl(const EC_PrivateKey& ec)
+ {
+ const PointGFp& pub_key = ec.public_point();
+ const BigInt& priv_key = ec.private_value();
+
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(static_cast<size_t>(1))
+ .encode(BigInt::encode_1363(priv_key, priv_key.bytes()), OCTET_STRING)
+ .start_cons(ASN1_Tag(0), PRIVATE)
+ .raw_bytes(ec.domain().DER_encode(EC_DOMPAR_ENC_OID))
+ .end_cons()
+ .start_cons(ASN1_Tag(1), PRIVATE)
+ .encode(EC2OSP(pub_key, PointGFp::UNCOMPRESSED), BIT_STRING)
+ .end_cons()
+ .end_cons()
+ .get_contents();
+ }
+
+class OpenSSL_Error : public Exception
+ {
+ public:
+ OpenSSL_Error(const std::string& what) :
+ Exception(what + " failed: " + ERR_error_string(ERR_get_error(), nullptr)) {}
+ };
+
+int OpenSSL_EC_nid_for(const OID& oid)
+ {
+ if(oid.empty())
+ return -1;
+
+ static const std::map<std::string, int> nid_map = {
+ //{ "secp160r1", NID_secp160r1 },
+ //{ "secp160r2", NID_secp160r2 },
+ { "secp192r1", NID_X9_62_prime192v1 },
+ { "secp224r1", NID_secp224r1 },
+ { "secp256r1", NID_X9_62_prime256v1 },
+ { "secp384r1", NID_secp384r1 },
+ { "secp521r1", NID_secp521r1 }
+ // TODO: OpenSSL 1.0.2 added brainpool curves
+ };
+
+ const std::string name = OIDS::lookup(oid);
+ auto i = nid_map.find(name);
+ if(i != nid_map.end())
+ return i->second;
+
+ return -1;
+ }
+
+class OpenSSL_ECDSA_Verification_Operation : public PK_Ops::Verification_with_EMSA
+ {
+ public:
+ typedef ECDSA_PublicKey Key_Type;
+
+ static OpenSSL_ECDSA_Verification_Operation* make(const Spec& spec)
+ {
+ if(const ECDSA_PublicKey* ecdsa = dynamic_cast<const ECDSA_PublicKey*>(&spec.key()))
+ {
+ const int nid = OpenSSL_EC_nid_for(ecdsa->domain().get_oid());
+ if(nid > 0)
+ return new OpenSSL_ECDSA_Verification_Operation(*ecdsa, spec.padding(), nid);
+ }
+
+ return nullptr;
+ }
+
+ OpenSSL_ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, const std::string& emsa, int nid) :
+ PK_Ops::Verification_with_EMSA(emsa), m_ossl_ec(::EC_KEY_new(), ::EC_KEY_free)
+ {
+ std::unique_ptr<::EC_GROUP, std::function<void (::EC_GROUP*)>> grp(::EC_GROUP_new_by_curve_name(nid),
+ ::EC_GROUP_free);
+
+ if(!grp)
+ throw OpenSSL_Error("EC_GROUP_new_by_curve_name");
+
+ ::EC_KEY_set_group(m_ossl_ec.get(), grp.get());
+
+ const secure_vector<byte> enc = EC2OSP(ecdsa.public_point(), PointGFp::UNCOMPRESSED);
+ const byte* enc_ptr = enc.data();
+ EC_KEY* key_ptr = m_ossl_ec.get();
+ if(!::o2i_ECPublicKey(&key_ptr, &enc_ptr, enc.size()))
+ throw OpenSSL_Error("o2i_ECPublicKey");
+
+ const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
+ m_order_bits = ::EC_GROUP_get_degree(group);
+ }
+
+ size_t message_parts() const override { return 2; }
+ size_t message_part_size() const override { return (m_order_bits + 7) / 8; }
+ size_t max_input_bits() const override { return m_order_bits; }
+
+ bool with_recovery() const override { return false; }
+
+ bool verify(const byte msg[], size_t msg_len,
+ const byte sig_bytes[], size_t sig_len) override
+ {
+ if(sig_len != message_part_size() * message_parts())
+ return false;
+
+ std::unique_ptr<ECDSA_SIG, std::function<void (ECDSA_SIG*)>> sig(nullptr, ECDSA_SIG_free);
+ sig.reset(::ECDSA_SIG_new());
+
+ sig->r = BN_bin2bn(sig_bytes , sig_len / 2, nullptr);
+ sig->s = BN_bin2bn(sig_bytes + sig_len / 2, sig_len / 2, nullptr);
+
+ const int res = ECDSA_do_verify(msg, msg_len, sig.get(), m_ossl_ec.get());
+ if(res < 0)
+ throw OpenSSL_Error("ECDSA_do_verify");
+ return (res == 1);
+ }
+
+ private:
+ std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
+ size_t m_order_bits = 0;
+ };
+
+class OpenSSL_ECDSA_Signing_Operation : public PK_Ops::Signature_with_EMSA
+ {
+ public:
+ typedef ECDSA_PrivateKey Key_Type;
+
+ static OpenSSL_ECDSA_Signing_Operation* make(const Spec& spec)
+ {
+ if(const ECDSA_PrivateKey* ecdsa = dynamic_cast<const ECDSA_PrivateKey*>(&spec.key()))
+ {
+ const int nid = OpenSSL_EC_nid_for(ecdsa->domain().get_oid());
+ if(nid > 0)
+ return new OpenSSL_ECDSA_Signing_Operation(*ecdsa, spec.padding());
+ }
+
+ return nullptr;
+ }
+
+ OpenSSL_ECDSA_Signing_Operation(const ECDSA_PrivateKey& ecdsa, const std::string& emsa) :
+ PK_Ops::Signature_with_EMSA(emsa),
+ m_ossl_ec(nullptr, ::EC_KEY_free)
+ {
+ const secure_vector<byte> der = PKCS8_for_openssl(ecdsa);
+ const byte* der_ptr = der.data();
+ m_ossl_ec.reset(d2i_ECPrivateKey(nullptr, &der_ptr, der.size()));
+ if(!m_ossl_ec)
+ throw OpenSSL_Error("d2i_ECPrivateKey");
+
+ const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
+ m_order_bits = ::EC_GROUP_get_degree(group);
+ }
+
+ secure_vector<byte> raw_sign(const byte msg[], size_t msg_len,
+ RandomNumberGenerator&) override
+ {
+ std::unique_ptr<ECDSA_SIG, std::function<void (ECDSA_SIG*)>> sig(nullptr, ECDSA_SIG_free);
+ sig.reset(::ECDSA_do_sign(msg, msg_len, m_ossl_ec.get()));
+
+ if(!sig)
+ throw OpenSSL_Error("ECDSA_do_sign");
+
+ const size_t order_bytes = message_part_size();
+ const size_t r_bytes = BN_num_bytes(sig->r);
+ const size_t s_bytes = BN_num_bytes(sig->s);
+ secure_vector<byte> sigval(2*order_bytes);
+ BN_bn2bin(sig->r, &sigval[order_bytes - r_bytes]);
+ BN_bn2bin(sig->s, &sigval[2*order_bytes - s_bytes]);
+ return sigval;
+ }
+
+ size_t message_parts() const override { return 2; }
+ size_t message_part_size() const override { return (m_order_bits + 7) / 8; }
+ size_t max_input_bits() const override { return m_order_bits; }
+
+ private:
+ std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
+ size_t m_order_bits = 0;
+ };
+
+BOTAN_REGISTER_TYPE(PK_Ops::Verification, OpenSSL_ECDSA_Verification_Operation, "ECDSA",
+ OpenSSL_ECDSA_Verification_Operation::make,
+ "openssl", 255);
+
+BOTAN_REGISTER_TYPE(PK_Ops::Signature, OpenSSL_ECDSA_Signing_Operation, "ECDSA",
+ OpenSSL_ECDSA_Signing_Operation::make, "openssl", 255);
+
+}
+
+}
+
+#endif // BOTAN_HAS_ECDSA && !OPENSSL_NO_ECDSA