diff options
Diffstat (limited to 'src/lib')
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 |