diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2018-01-03 17:56:52 +0100 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2018-08-10 09:23:42 +0000 |
commit | a44fe2e4f03fc18ce9c3d050f71fe369916259b8 (patch) | |
tree | e5f3211ced0bc7fc1628ff5e7a051007dfa18207 /src/libs/3rdparty/botan/src/lib | |
parent | 78c4cf9884770149fb9d69f923aa2169baa3f42a (diff) |
SSH: Use Botan2
Botan 1.10 will be completely unsupported by the end of this year, so we
now target API version 2 instead.
Also upgrade our bundled Botan to the latest version 2.7. We no longer
check in pre-processed files, but use the upstream sources directly
(with unneeded parts removed), employing Botan's own configure
script for building. This will make future upgrades much simpler. A
script to automate this process is also provided.
Task-number: QTCREATORBUG-18802
Task-number: QTCREATORBUG-8107
Change-Id: I5a5ea62cfd30d720b556217142e8b7e06bf49f7e
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Diffstat (limited to 'src/libs/3rdparty/botan/src/lib')
404 files changed, 70030 insertions, 0 deletions
diff --git a/src/libs/3rdparty/botan/src/lib/asn1/alg_id.cpp b/src/libs/3rdparty/botan/src/lib/asn1/alg_id.cpp new file mode 100644 index 0000000000..0637a8f8d1 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/alg_id.cpp @@ -0,0 +1,117 @@ +/* +* Algorithm Identifier +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/alg_id.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/oids.h> + +namespace Botan { + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, + const std::vector<uint8_t>& param) : + oid(alg_id), + parameters(param) + {} + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, + const std::vector<uint8_t>& param) : + oid(OIDS::lookup(alg_id)), + parameters(param) + {} + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, + Encoding_Option option) : + oid(alg_id), + parameters() + { + const uint8_t DER_NULL[] = { 0x05, 0x00 }; + + if(option == USE_NULL_PARAM) + parameters.assign(DER_NULL, DER_NULL + 2); + } + +/* +* Create an AlgorithmIdentifier +*/ +AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, + Encoding_Option option) : + oid(OIDS::lookup(alg_id)), + parameters() + { + const uint8_t DER_NULL[] = { 0x05, 0x00 }; + + if(option == USE_NULL_PARAM) + parameters.assign(DER_NULL, DER_NULL + 2); + } + +/* +* Compare two AlgorithmIdentifiers +*/ +namespace { + +bool param_null_or_empty(const std::vector<uint8_t>& p) + { + if(p.size() == 2 && (p[0] == 0x05) && (p[1] == 0x00)) + return true; + return p.empty(); + } + +} + +bool operator==(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2) + { + if(a1.get_oid() != a2.get_oid()) + return false; + + if(param_null_or_empty(a1.get_parameters()) && + param_null_or_empty(a2.get_parameters())) + return true; + + return (a1.get_parameters() == a2.get_parameters()); + } + +/* +* Compare two AlgorithmIdentifiers +*/ +bool operator!=(const AlgorithmIdentifier& a1, const AlgorithmIdentifier& a2) + { + return !(a1 == a2); + } + +/* +* DER encode an AlgorithmIdentifier +*/ +void AlgorithmIdentifier::encode_into(DER_Encoder& codec) const + { + codec.start_cons(SEQUENCE) + .encode(get_oid()) + .raw_bytes(get_parameters()) + .end_cons(); + } + +/* +* Decode a BER encoded AlgorithmIdentifier +*/ +void AlgorithmIdentifier::decode_from(BER_Decoder& codec) + { + codec.start_cons(SEQUENCE) + .decode(oid) + .raw_bytes(parameters) + .end_cons(); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/asn1/alg_id.h b/src/libs/3rdparty/botan/src/lib/asn1/alg_id.h new file mode 100644 index 0000000000..dc9ca23986 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/alg_id.h @@ -0,0 +1,59 @@ +/* +* Algorithm Identifier +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ALGORITHM_IDENTIFIER_H_ +#define BOTAN_ALGORITHM_IDENTIFIER_H_ + +#include <botan/asn1_obj.h> +#include <botan/asn1_oid.h> +#include <string> +#include <vector> + +namespace Botan { + +/** +* Algorithm Identifier +*/ +class BOTAN_PUBLIC_API(2,0) AlgorithmIdentifier final : public ASN1_Object + { + public: + enum Encoding_Option { USE_NULL_PARAM, USE_EMPTY_PARAM }; + + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + AlgorithmIdentifier() = default; + + AlgorithmIdentifier(const OID& oid, Encoding_Option enc); + AlgorithmIdentifier(const std::string& oid_name, Encoding_Option enc); + + AlgorithmIdentifier(const OID& oid, const std::vector<uint8_t>& params); + AlgorithmIdentifier(const std::string& oid_name, const std::vector<uint8_t>& params); + + const OID& get_oid() const { return oid; } + const std::vector<uint8_t>& get_parameters() const { return parameters; } + + BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES: + /* + * These values are public for historical reasons, but in a future release + * they will be made private. Do not access them. + */ + OID oid; + std::vector<uint8_t> parameters; + }; + +/* +* Comparison Operations +*/ +bool BOTAN_PUBLIC_API(2,0) operator==(const AlgorithmIdentifier&, + const AlgorithmIdentifier&); +bool BOTAN_PUBLIC_API(2,0) operator!=(const AlgorithmIdentifier&, + const AlgorithmIdentifier&); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_attribute.cpp b/src/libs/3rdparty/botan/src/lib/asn1/asn1_attribute.cpp new file mode 100644 index 0000000000..8ecd8fd5f3 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_attribute.cpp @@ -0,0 +1,58 @@ +/* +* Attribute +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/asn1_attribute.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/oids.h> + +namespace Botan { + +/* +* Create an Attribute +*/ +Attribute::Attribute(const OID& attr_oid, const std::vector<uint8_t>& attr_value) : + oid(attr_oid), + parameters(attr_value) + {} + +/* +* Create an Attribute +*/ +Attribute::Attribute(const std::string& attr_oid, + const std::vector<uint8_t>& attr_value) : + oid(OIDS::lookup(attr_oid)), + parameters(attr_value) + {} + +/* +* DER encode a Attribute +*/ +void Attribute::encode_into(DER_Encoder& codec) const + { + codec.start_cons(SEQUENCE) + .encode(oid) + .start_cons(SET) + .raw_bytes(parameters) + .end_cons() + .end_cons(); + } + +/* +* Decode a BER encoded Attribute +*/ +void Attribute::decode_from(BER_Decoder& codec) + { + codec.start_cons(SEQUENCE) + .decode(oid) + .start_cons(SET) + .raw_bytes(parameters) + .end_cons() + .end_cons(); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_attribute.h b/src/libs/3rdparty/botan/src/lib/asn1/asn1_attribute.h new file mode 100644 index 0000000000..c9f69eb772 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_attribute.h @@ -0,0 +1,45 @@ +/* +* ASN.1 Attribute +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_ATTRIBUTE_H_ +#define BOTAN_ASN1_ATTRIBUTE_H_ + +#include <botan/asn1_obj.h> +#include <botan/asn1_oid.h> +#include <vector> + +namespace Botan { + +/** +* Attribute +*/ +class BOTAN_PUBLIC_API(2,0) Attribute final : public ASN1_Object + { + public: + void encode_into(class DER_Encoder& to) const override; + void decode_from(class BER_Decoder& from) override; + + Attribute() = default; + Attribute(const OID&, const std::vector<uint8_t>&); + Attribute(const std::string&, const std::vector<uint8_t>&); + + const OID& get_oid() const { return oid; } + + const std::vector<uint8_t>& get_parameters() const { return parameters; } + + BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES: + /* + * These values are public for historical reasons, but in a future release + * they will be made private. Do not access them. + */ + OID oid; + std::vector<uint8_t> parameters; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_obj.cpp b/src/libs/3rdparty/botan/src/lib/asn1/asn1_obj.cpp new file mode 100644 index 0000000000..815bc4ef83 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_obj.cpp @@ -0,0 +1,235 @@ +/* +* ASN.1 Internals +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/asn1_obj.h> +#include <botan/der_enc.h> +#include <botan/data_src.h> +#include <botan/internal/stl_util.h> +#include <sstream> + +namespace Botan { + +std::vector<uint8_t> ASN1_Object::BER_encode() const + { + std::vector<uint8_t> output; + DER_Encoder der(output); + this->encode_into(der); + return output; + } + +/* +* Check a type invariant on BER data +*/ +void BER_Object::assert_is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_, + const std::string& descr) const + { + if(this->is_a(type_tag_, class_tag_) == false) + { + std::stringstream msg; + + msg << "Tag mismatch when decoding " << descr << " got "; + + if(class_tag == NO_OBJECT && type_tag == NO_OBJECT) + { + msg << "EOF"; + } + else + { + if(class_tag == UNIVERSAL || class_tag == CONSTRUCTED) + { + msg << asn1_tag_to_string(type_tag); + } + else + { + msg << std::to_string(type_tag); + } + + msg << "/" << asn1_class_to_string(class_tag); + } + + msg << " expected "; + + if(class_tag_ == UNIVERSAL || class_tag_ == CONSTRUCTED) + { + msg << asn1_tag_to_string(type_tag_); + } + else + { + msg << std::to_string(type_tag_); + } + + msg << "/" << asn1_class_to_string(class_tag_); + + throw BER_Decoding_Error(msg.str()); + } + } + +bool BER_Object::is_a(ASN1_Tag type_tag_, ASN1_Tag class_tag_) const + { + return (type_tag == type_tag_ && class_tag == class_tag_); + } + +bool BER_Object::is_a(int type_tag_, ASN1_Tag class_tag_) const + { + return is_a(ASN1_Tag(type_tag_), class_tag_); + } + +void BER_Object::set_tagging(ASN1_Tag t, ASN1_Tag c) + { + type_tag = t; + class_tag = c; + } + +std::string asn1_class_to_string(ASN1_Tag type) + { + switch(type) + { + case UNIVERSAL: + return "UNIVERSAL"; + case CONSTRUCTED: + return "CONSTRUCTED"; + case CONTEXT_SPECIFIC: + return "CONTEXT_SPECIFIC"; + case APPLICATION: + return "APPLICATION"; + case CONSTRUCTED | CONTEXT_SPECIFIC: + return "PRIVATE"; + case Botan::NO_OBJECT: + return "NO_OBJECT"; + default: + return "CLASS(" + std::to_string(static_cast<size_t>(type)) + ")"; + } + } + +std::string asn1_tag_to_string(ASN1_Tag type) + { + switch(type) + { + case Botan::SEQUENCE: + return "SEQUENCE"; + + case Botan::SET: + return "SET"; + + case Botan::PRINTABLE_STRING: + return "PRINTABLE STRING"; + + case Botan::NUMERIC_STRING: + return "NUMERIC STRING"; + + case Botan::IA5_STRING: + return "IA5 STRING"; + + case Botan::T61_STRING: + return "T61 STRING"; + + case Botan::UTF8_STRING: + return "UTF8 STRING"; + + case Botan::VISIBLE_STRING: + return "VISIBLE STRING"; + + case Botan::BMP_STRING: + return "BMP STRING"; + + case Botan::UTC_TIME: + return "UTC TIME"; + + case Botan::GENERALIZED_TIME: + return "GENERALIZED TIME"; + + case Botan::OCTET_STRING: + return "OCTET STRING"; + + case Botan::BIT_STRING: + return "BIT STRING"; + + case Botan::ENUMERATED: + return "ENUMERATED"; + + case Botan::INTEGER: + return "INTEGER"; + + case Botan::NULL_TAG: + return "NULL"; + + case Botan::OBJECT_ID: + return "OBJECT"; + + case Botan::BOOLEAN: + return "BOOLEAN"; + + case Botan::NO_OBJECT: + return "NO_OBJECT"; + + default: + return "TAG(" + std::to_string(static_cast<size_t>(type)) + ")"; + } + } + +/* +* BER Decoding Exceptions +*/ +BER_Decoding_Error::BER_Decoding_Error(const std::string& str) : + Decoding_Error("BER: " + str) {} + +BER_Bad_Tag::BER_Bad_Tag(const std::string& str, ASN1_Tag tag) : + BER_Decoding_Error(str + ": " + std::to_string(tag)) {} + +BER_Bad_Tag::BER_Bad_Tag(const std::string& str, + ASN1_Tag tag1, ASN1_Tag tag2) : + BER_Decoding_Error(str + ": " + std::to_string(tag1) + "/" + std::to_string(tag2)) {} + +namespace ASN1 { + +/* +* Put some arbitrary bytes into a SEQUENCE +*/ +std::vector<uint8_t> put_in_sequence(const std::vector<uint8_t>& contents) + { + return ASN1::put_in_sequence(contents.data(), contents.size()); + } + +std::vector<uint8_t> put_in_sequence(const uint8_t bits[], size_t len) + { + std::vector<uint8_t> output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .raw_bytes(bits, len) + .end_cons(); + return output; + } + +/* +* Convert a BER object into a string object +*/ +std::string to_string(const BER_Object& obj) + { + return std::string(cast_uint8_ptr_to_char(obj.bits()), + obj.length()); + } + +/* +* Do heuristic tests for BER data +*/ +bool maybe_BER(DataSource& source) + { + uint8_t first_u8; + if(!source.peek_byte(first_u8)) + { + BOTAN_ASSERT_EQUAL(source.read_byte(first_u8), 0, "Expected EOF"); + throw Stream_IO_Error("ASN1::maybe_BER: Source was empty"); + } + + if(first_u8 == (SEQUENCE | CONSTRUCTED)) + return true; + return false; + } + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_obj.h b/src/libs/3rdparty/botan/src/lib/asn1/asn1_obj.h new file mode 100644 index 0000000000..572453b21a --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_obj.h @@ -0,0 +1,191 @@ +/* +* ASN.1 Internals +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_H_ +#define BOTAN_ASN1_H_ + +#include <botan/secmem.h> +#include <botan/exceptn.h> + +namespace Botan { + +class BER_Decoder; +class DER_Encoder; + +/** +* ASN.1 Type and Class Tags +*/ +enum ASN1_Tag : uint32_t { + UNIVERSAL = 0x00, + APPLICATION = 0x40, + CONTEXT_SPECIFIC = 0x80, + + CONSTRUCTED = 0x20, + + PRIVATE = CONSTRUCTED | CONTEXT_SPECIFIC, + + EOC = 0x00, + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + NULL_TAG = 0x05, + OBJECT_ID = 0x06, + ENUMERATED = 0x0A, + SEQUENCE = 0x10, + SET = 0x11, + + UTF8_STRING = 0x0C, + NUMERIC_STRING = 0x12, + PRINTABLE_STRING = 0x13, + T61_STRING = 0x14, + IA5_STRING = 0x16, + VISIBLE_STRING = 0x1A, + UNIVERSAL_STRING = 0x1C, + BMP_STRING = 0x1E, + + UTC_TIME = 0x17, + GENERALIZED_TIME = 0x18, + UTC_OR_GENERALIZED_TIME = 0x19, + + NO_OBJECT = 0xFF00, + DIRECTORY_STRING = 0xFF01 +}; + +std::string BOTAN_UNSTABLE_API asn1_tag_to_string(ASN1_Tag type); +std::string BOTAN_UNSTABLE_API asn1_class_to_string(ASN1_Tag type); + +/** +* Basic ASN.1 Object Interface +*/ +class BOTAN_PUBLIC_API(2,0) ASN1_Object + { + public: + /** + * Encode whatever this object is into to + * @param to the DER_Encoder that will be written to + */ + 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(BER_Decoder& from) = 0; + + /** + * Return the encoding of this object. This is a convenience + * method when just one object needs to be serialized. Use + * DER_Encoder for complicated encodings. + */ + std::vector<uint8_t> BER_encode() const; + + ASN1_Object() = default; + ASN1_Object(const ASN1_Object&) = default; + ASN1_Object & operator=(const ASN1_Object&) = default; + virtual ~ASN1_Object() = default; + }; + +/** +* BER Encoded Object +*/ +class BOTAN_PUBLIC_API(2,0) BER_Object final + { + public: + BER_Object() : type_tag(NO_OBJECT), class_tag(UNIVERSAL) {} + + BER_Object(const BER_Object& other) = default; + + BER_Object& operator=(const BER_Object& other) = default; + +#if !defined(BOTAN_BUILD_COMPILER_IS_MSVC_2013) + BER_Object(BER_Object&& other) = default; + + BER_Object& operator=(BER_Object&& other) = default; +#endif + + bool is_set() const { return type_tag != NO_OBJECT; } + + ASN1_Tag tagging() const { return ASN1_Tag(type() | get_class()); } + + ASN1_Tag type() const { return type_tag; } + ASN1_Tag get_class() const { return class_tag; } + + const uint8_t* bits() const { return value.data(); } + + size_t length() const { return value.size(); } + + void assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& descr = "object") const; + + bool is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) const; + + bool is_a(int type_tag, ASN1_Tag class_tag) const; + + BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES: + /* + * The following member variables are public for historical reasons, but + * will be made private in a future major release. Use the accessor + * functions above. + */ + ASN1_Tag type_tag, class_tag; + secure_vector<uint8_t> value; + + private: + + friend class BER_Decoder; + + void set_tagging(ASN1_Tag type_tag, ASN1_Tag class_tag); + + uint8_t* mutable_bits(size_t length) + { + value.resize(length); + return value.data(); + } + }; + +/* +* ASN.1 Utility Functions +*/ +class DataSource; + +namespace ASN1 { + +std::vector<uint8_t> put_in_sequence(const std::vector<uint8_t>& val); +std::vector<uint8_t> put_in_sequence(const uint8_t bits[], size_t len); +std::string to_string(const BER_Object& obj); + +/** +* Heuristics tests; is this object possibly BER? +* @param src a data source that will be peeked at but not modified +*/ +bool maybe_BER(DataSource& src); + +} + +/** +* General BER Decoding Error Exception +*/ +class BOTAN_PUBLIC_API(2,0) BER_Decoding_Error : public Decoding_Error + { + public: + explicit BER_Decoding_Error(const std::string&); + }; + +/** +* Exception For Incorrect BER Taggings +*/ +class BOTAN_PUBLIC_API(2,0) BER_Bad_Tag final : public BER_Decoding_Error + { + public: + BER_Bad_Tag(const std::string& msg, ASN1_Tag tag); + BER_Bad_Tag(const std::string& msg, ASN1_Tag tag1, ASN1_Tag tag2); + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_oid.cpp b/src/libs/3rdparty/botan/src/lib/asn1/asn1_oid.cpp new file mode 100644 index 0000000000..c94f7c8b54 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_oid.cpp @@ -0,0 +1,199 @@ +/* +* ASN.1 OID +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/asn1_oid.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/internal/bit_ops.h> +#include <botan/parsing.h> + +namespace Botan { + +/* +* ASN.1 OID Constructor +*/ +OID::OID(const std::string& oid_str) + { + if(!oid_str.empty()) + { + try + { + m_id = parse_asn1_oid(oid_str); + } + catch(...) + { + throw Invalid_OID(oid_str); + } + + if(m_id.size() < 2 || m_id[0] > 2) + throw Invalid_OID(oid_str); + if((m_id[0] == 0 || m_id[0] == 1) && m_id[1] > 39) + throw Invalid_OID(oid_str); + } + } + +/* +* Clear the current OID +*/ +void OID::clear() + { + m_id.clear(); + } + +/* +* Return this OID as a string +*/ +std::string OID::to_string() const + { + std::string oid_str; + for(size_t i = 0; i != m_id.size(); ++i) + { + oid_str += std::to_string(m_id[i]); + if(i != m_id.size() - 1) + oid_str += "."; + } + return oid_str; + } + +/* +* OID equality comparison +*/ +bool OID::operator==(const OID& oid) const + { + if(m_id.size() != oid.m_id.size()) + return false; + for(size_t i = 0; i != m_id.size(); ++i) + if(m_id[i] != oid.m_id[i]) + return false; + return true; + } + +/* +* Append another component to the OID +*/ +OID& OID::operator+=(uint32_t component) + { + m_id.push_back(component); + return (*this); + } + +/* +* Append another component to the OID +*/ +OID operator+(const OID& oid, uint32_t component) + { + OID new_oid(oid); + new_oid += component; + return new_oid; + } + +/* +* OID inequality comparison +*/ +bool operator!=(const OID& a, const OID& b) + { + return !(a == b); + } + +/* +* Compare two OIDs +*/ +bool operator<(const OID& a, const OID& b) + { + const std::vector<uint32_t>& oid1 = a.get_id(); + const std::vector<uint32_t>& oid2 = b.get_id(); + + if(oid1.size() < oid2.size()) + return true; + if(oid1.size() > oid2.size()) + return false; + for(size_t i = 0; i != oid1.size(); ++i) + { + if(oid1[i] < oid2[i]) + return true; + if(oid1[i] > oid2[i]) + return false; + } + return false; + } + +/* +* DER encode an OBJECT IDENTIFIER +*/ +void OID::encode_into(DER_Encoder& der) const + { + if(m_id.size() < 2) + throw Invalid_Argument("OID::encode_into: OID is invalid"); + + std::vector<uint8_t> encoding; + + if(m_id[0] > 2 || m_id[1] >= 40) + throw Encoding_Error("Invalid OID prefix, cannot encode"); + + encoding.push_back(static_cast<uint8_t>(40 * m_id[0] + m_id[1])); + + for(size_t i = 2; i != m_id.size(); ++i) + { + if(m_id[i] == 0) + encoding.push_back(0); + else + { + size_t blocks = high_bit(m_id[i]) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + BOTAN_ASSERT(blocks > 0, "Math works"); + + for(size_t j = 0; j != blocks - 1; ++j) + encoding.push_back(0x80 | ((m_id[i] >> 7*(blocks-j-1)) & 0x7F)); + encoding.push_back(m_id[i] & 0x7F); + } + } + der.add_object(OBJECT_ID, UNIVERSAL, encoding); + } + +/* +* Decode a BER encoded OBJECT IDENTIFIER +*/ +void OID::decode_from(BER_Decoder& decoder) + { + BER_Object obj = decoder.get_next_object(); + if(obj.tagging() != OBJECT_ID) + throw BER_Bad_Tag("Error decoding OID, unknown tag", obj.tagging()); + + const size_t length = obj.length(); + const uint8_t* bits = obj.bits(); + + if(length < 2 && !(length == 1 && bits[0] == 0)) + { + throw BER_Decoding_Error("OID encoding is too short"); + } + + clear(); + m_id.push_back(bits[0] / 40); + m_id.push_back(bits[0] % 40); + + size_t i = 0; + while(i != length - 1) + { + uint32_t component = 0; + while(i != length - 1) + { + ++i; + + if(component >> (32-7)) + throw Decoding_Error("OID component overflow"); + + component = (component << 7) + (bits[i] & 0x7F); + + if(!(bits[i] & 0x80)) + break; + } + m_id.push_back(component); + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_oid.h b/src/libs/3rdparty/botan/src/lib/asn1/asn1_oid.h new file mode 100644 index 0000000000..6198819ad9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_oid.h @@ -0,0 +1,110 @@ +/* +* ASN.1 OID +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_OID_H_ +#define BOTAN_ASN1_OID_H_ + +#include <botan/asn1_obj.h> +#include <string> +#include <vector> + +namespace Botan { + +/** +* This class represents ASN.1 object identifiers. +*/ +class BOTAN_PUBLIC_API(2,0) OID final : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + /** + * Find out whether this OID is empty + * @return true is no OID value is set + */ + bool empty() const { return m_id.empty(); } + + /** + * Find out whether this OID has a value + * @return true is this OID has a value + */ + bool has_value() const { return (m_id.empty() == false); } + + /** + * Get this OID as list (vector) of its components. + * @return vector representing this OID + */ + const std::vector<uint32_t>& get_id() const { return m_id; } + + /** + * Get this OID as a string + * @return string representing this OID + */ + std::string as_string() const { return this->to_string(); } + + /** + * Get this OID as a string + * @return string representing this OID + */ + std::string to_string() const; + + /** + * Compare two OIDs. + * @return true if they are equal, false otherwise + */ + bool operator==(const OID&) const; + + /** + * Reset this instance to an empty OID. + */ + void clear(); + + /** + * Add a component to this OID. + * @param new_comp the new component to add to the end of this OID + * @return reference to *this + */ + OID& operator+=(uint32_t new_comp); + + /** + * Construct an OID from a string. + * @param str a string in the form "a.b.c" etc., where a,b,c are numbers + */ + OID(const std::string& str = ""); + + explicit OID(std::initializer_list<uint32_t> init) : m_id(init) {} + private: + std::vector<uint32_t> m_id; + }; + +/** +* Append another component onto the OID. +* @param oid the OID to add the new component to +* @param new_comp the new component to add +*/ +OID BOTAN_PUBLIC_API(2,0) operator+(const OID& oid, uint32_t new_comp); + +/** +* Compare two OIDs. +* @param a the first OID +* @param b the second OID +* @return true if a is not equal to b +*/ +bool BOTAN_PUBLIC_API(2,0) operator!=(const OID& a, const OID& b); + +/** +* Compare two OIDs. +* @param a the first OID +* @param b the second OID +* @return true if a is lexicographically smaller than b +*/ +bool BOTAN_PUBLIC_API(2,0) operator<(const OID& a, const OID& b); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_print.cpp b/src/libs/3rdparty/botan/src/lib/asn1/asn1_print.cpp new file mode 100644 index 0000000000..1f91782665 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_print.cpp @@ -0,0 +1,329 @@ +/* +* (C) 2014,2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/asn1_print.h> +#include <botan/bigint.h> +#include <botan/hex.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/asn1_time.h> +#include <botan/asn1_str.h> +#include <botan/oids.h> +#include <iomanip> +#include <sstream> +#include <cctype> + +namespace Botan { + +namespace { + +bool all_printable_chars(const uint8_t bits[], size_t bits_len) + { + for(size_t i = 0; i != bits_len; ++i) + { + int c = bits[i]; + if(c > 127) + return false; + + if((std::isalnum(c) || c == '.' || c == ':' || c == '/' || c == '-') == false) + return false; + } + return true; + } + +/* +* Special hack to handle GeneralName [2] and [6] (DNS name and URI) +*/ +bool possibly_a_general_name(const uint8_t bits[], size_t bits_len) + { + if(bits_len <= 2) + return false; + + if(bits[0] != 0x82 && bits[0] != 0x86) + return false; + + if(bits[1] != bits_len - 2) + return false; + + if(all_printable_chars(bits + 2, bits_len - 2) == false) + return false; + + return true; + } + +} + +std::string ASN1_Formatter::print(const uint8_t in[], size_t len) const + { + std::ostringstream output; + print_to_stream(output, in, len); + return output.str(); + } + +void ASN1_Formatter::print_to_stream(std::ostream& output, + const uint8_t in[], + size_t len) const + { + BER_Decoder dec(in, len); + decode(output, dec, 0); + } + +void ASN1_Formatter::decode(std::ostream& output, + BER_Decoder& decoder, + size_t level) const + { + BER_Object obj = decoder.get_next_object(); + + const bool recurse_deeper = (m_max_depth == 0 || level < m_max_depth); + + while(obj.is_set()) + { + const ASN1_Tag type_tag = obj.type(); + const ASN1_Tag class_tag = obj.get_class(); + const size_t length = obj.length(); + + /* hack to insert the tag+length back in front of the stuff now + that we've gotten the type info */ + std::vector<uint8_t> bits; + DER_Encoder(bits).add_object(type_tag, class_tag, obj.bits(), obj.length()); + + BER_Decoder data(bits); + + if(class_tag & CONSTRUCTED) + { + BER_Decoder cons_info(obj.bits(), obj.length()); + + if(recurse_deeper) + { + output << format(type_tag, class_tag, level, length, ""); + decode(output, cons_info, level + 1); // recurse + } + else + { + output << format(type_tag, class_tag, level, length, + format_bin(type_tag, class_tag, bits)); + } + } + else if((class_tag & APPLICATION) || (class_tag & CONTEXT_SPECIFIC)) + { + bool success_parsing_cs = false; + + if(m_print_context_specific) + { + try + { + if(possibly_a_general_name(bits.data(), bits.size())) + { + output << format(type_tag, class_tag, level, level, + std::string(cast_uint8_ptr_to_char(&bits[2]), bits.size() - 2)); + success_parsing_cs = true; + } + else if(recurse_deeper) + { + std::vector<uint8_t> inner_bits; + data.decode(inner_bits, type_tag); + + BER_Decoder inner(inner_bits); + std::ostringstream inner_data; + decode(inner_data, inner, level + 1); // recurse + output << inner_data.str(); + success_parsing_cs = true; + } + } + catch(...) + { + } + } + + if(success_parsing_cs == false) + { + output << format(type_tag, class_tag, level, length, + format_bin(type_tag, class_tag, bits)); + } + } + else if(type_tag == OBJECT_ID) + { + OID oid; + data.decode(oid); + + std::string out = OIDS::lookup(oid); + if(out.empty()) + { + out = oid.as_string(); + } + else + { + out += " [" + oid.as_string() + "]"; + } + + output << format(type_tag, class_tag, level, length, out); + } + else if(type_tag == INTEGER || type_tag == ENUMERATED) + { + BigInt number; + + if(type_tag == INTEGER) + { + data.decode(number); + } + else if(type_tag == ENUMERATED) + { + data.decode(number, ENUMERATED, class_tag); + } + + std::vector<uint8_t> rep = BigInt::encode(number, BigInt::Binary); + if(rep.empty()) // if zero + rep.resize(1); + + output << format(type_tag, class_tag, level, length, hex_encode(rep)); + } + else if(type_tag == BOOLEAN) + { + bool boolean; + data.decode(boolean); + output << format(type_tag, class_tag, level, length, (boolean ? "true" : "false")); + } + else if(type_tag == NULL_TAG) + { + output << format(type_tag, class_tag, level, length, ""); + } + else if(type_tag == OCTET_STRING || type_tag == BIT_STRING) + { + std::vector<uint8_t> decoded_bits; + data.decode(decoded_bits, type_tag); + bool printing_octet_string_worked = false; + + if(recurse_deeper) + { + try + { + BER_Decoder inner(decoded_bits); + + std::ostringstream inner_data; + decode(inner_data, inner, level + 1); // recurse + + output << format(type_tag, class_tag, level, length, ""); + output << inner_data.str(); + printing_octet_string_worked = true; + } + catch(...) + { + } + } + + if(!printing_octet_string_worked) + { + output << format(type_tag, class_tag, level, length, + format_bin(type_tag, class_tag, decoded_bits)); + } + } + else if(ASN1_String::is_string_type(type_tag)) + { + ASN1_String str; + data.decode(str); + output << format(type_tag, class_tag, level, length, str.value()); + } + else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME) + { + X509_Time time; + data.decode(time); + output << format(type_tag, class_tag, level, length, time.readable_string()); + } + else + { + output << "Unknown ASN.1 tag class=" << static_cast<int>(class_tag) + << " type=" << static_cast<int>(type_tag) << "\n"; + } + + obj = decoder.get_next_object(); + } + } + +namespace { + +std::string format_type(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(class_tag == UNIVERSAL) + return asn1_tag_to_string(type_tag); + + if(class_tag == CONSTRUCTED && (type_tag == SEQUENCE || type_tag == SET)) + return asn1_tag_to_string(type_tag); + + std::string name; + + if(class_tag & CONSTRUCTED) + name += "cons "; + + name += "[" + std::to_string(type_tag) + "]"; + + if(class_tag & APPLICATION) + { + name += " appl"; + } + if(class_tag & CONTEXT_SPECIFIC) + { + name += " context"; + } + + return name; + } + +} + +std::string ASN1_Pretty_Printer::format(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t level, + size_t length, + const std::string& value) const + { + bool should_skip = false; + + if(value.length() > m_print_limit) + { + should_skip = true; + } + + if((type_tag == OCTET_STRING || type_tag == BIT_STRING) && + value.length() > m_print_binary_limit) + { + should_skip = true; + } + + level += m_initial_level; + + std::ostringstream oss; + + oss << " d=" << std::setw(2) << level + << ", l=" << std::setw(4) << length << ":" + << std::string(level + 1, ' ') << format_type(type_tag, class_tag); + + if(value != "" && !should_skip) + { + const size_t current_pos = static_cast<size_t>(oss.tellp()); + const size_t spaces_to_align = + (current_pos >= m_value_column) ? 1 : (m_value_column - current_pos); + + oss << std::string(spaces_to_align, ' ') << value; + } + + oss << "\n"; + + return oss.str(); + } + +std::string ASN1_Pretty_Printer::format_bin(ASN1_Tag /*type_tag*/, + ASN1_Tag /*class_tag*/, + const std::vector<uint8_t>& vec) const + { + if(all_printable_chars(vec.data(), vec.size())) + { + return std::string(cast_uint8_ptr_to_char(vec.data()), vec.size()); + } + else + return hex_encode(vec); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_print.h b/src/libs/3rdparty/botan/src/lib/asn1/asn1_print.h new file mode 100644 index 0000000000..a6bc6b15f2 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_print.h @@ -0,0 +1,125 @@ +/* +* (C) 2014,2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_PRINT_H_ +#define BOTAN_ASN1_PRINT_H_ + +#include <botan/asn1_obj.h> +#include <string> +#include <vector> +#include <iosfwd> + +namespace Botan { + +class BER_Decoder; + +/** +* Format ASN.1 data and call a virtual to format +*/ +class BOTAN_PUBLIC_API(2,4) ASN1_Formatter + { + public: + virtual ~ASN1_Formatter() = default; + + /** + * @param print_context_specific if true, try to parse nested context specific data. + * @param max_depth do not recurse more than this many times. If zero, recursion + * is unbounded. + */ + ASN1_Formatter(bool print_context_specific, size_t max_depth) : + m_print_context_specific(print_context_specific), + m_max_depth(max_depth) + {} + + void print_to_stream(std::ostream& out, + const uint8_t in[], + size_t len) const; + + std::string print(const uint8_t in[], size_t len) const; + + template<typename Alloc> + std::string print(const std::vector<uint8_t, Alloc>& vec) const + { + return print(vec.data(), vec.size()); + } + + protected: + /** + * This is called for each element + */ + virtual std::string format(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t level, + size_t length, + const std::string& value) const = 0; + + /** + * This is called to format binary elements that we don't know how to + * convert to a string The result will be passed as value to format; the + * tags are included as a hint to aid decoding. + */ + virtual std::string format_bin(ASN1_Tag type_tag, + ASN1_Tag class_tag, + const std::vector<uint8_t>& vec) const = 0; + + private: + void decode(std::ostream& output, + BER_Decoder& decoder, + size_t level) const; + + const bool m_print_context_specific; + const size_t m_max_depth; + }; + +/** +* Format ASN.1 data into human readable output. The exact form of the output for +* any particular input is not guaranteed and may change from release to release. +*/ +class BOTAN_PUBLIC_API(2,4) ASN1_Pretty_Printer final : public ASN1_Formatter + { + public: + /** + * @param print_limit strings larger than this are not printed + * @param print_binary_limit binary strings larger than this are not printed + * @param print_context_specific if true, try to parse nested context specific data. + * @param initial_level the initial depth (0 or 1 are the only reasonable values) + * @param value_column ASN.1 values are lined up at this column in output + * @param max_depth do not recurse more than this many times. If zero, recursion + * is unbounded. + */ + ASN1_Pretty_Printer(size_t print_limit = 4096, + size_t print_binary_limit = 2048, + bool print_context_specific = true, + size_t initial_level = 0, + size_t value_column = 60, + size_t max_depth = 64) : + ASN1_Formatter(print_context_specific, max_depth), + m_print_limit(print_limit), + m_print_binary_limit(print_binary_limit), + m_initial_level(initial_level), + m_value_column(value_column) + {} + + private: + std::string format(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t level, + size_t length, + const std::string& value) const override; + + std::string format_bin(ASN1_Tag type_tag, + ASN1_Tag class_tag, + const std::vector<uint8_t>& vec) const override; + + const size_t m_print_limit; + const size_t m_print_binary_limit; + const size_t m_initial_level; + const size_t m_value_column; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_str.cpp b/src/libs/3rdparty/botan/src/lib/asn1/asn1_str.cpp new file mode 100644 index 0000000000..416e4f0ac5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_str.cpp @@ -0,0 +1,153 @@ +/* +* Simple ASN.1 String Types +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/asn1_str.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/charset.h> + +namespace Botan { + +namespace { + +/* +* Choose an encoding for the string +*/ +ASN1_Tag choose_encoding(const std::string& str) + { + static const uint8_t IS_PRINTABLE[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + + for(size_t i = 0; i != str.size(); ++i) + { + if(!IS_PRINTABLE[static_cast<uint8_t>(str[i])]) + { + return UTF8_STRING; + } + } + return PRINTABLE_STRING; + } + +void assert_is_string_type(ASN1_Tag tag) + { + if(!ASN1_String::is_string_type(tag)) + { + throw Invalid_Argument("ASN1_String: Unknown string type " + + std::to_string(tag)); + } + } + +} + +//static +bool ASN1_String::is_string_type(ASN1_Tag tag) + { + return (tag == NUMERIC_STRING || + tag == PRINTABLE_STRING || + tag == VISIBLE_STRING || + tag == T61_STRING || + tag == IA5_STRING || + tag == UTF8_STRING || + tag == BMP_STRING || + tag == UNIVERSAL_STRING); + } + + +/* +* Create an ASN1_String +*/ +ASN1_String::ASN1_String(const std::string& str, ASN1_Tag t) : m_utf8_str(str), m_tag(t) + { + if(m_tag == DIRECTORY_STRING) + { + m_tag = choose_encoding(m_utf8_str); + } + + assert_is_string_type(m_tag); + } + +/* +* Create an ASN1_String +*/ +ASN1_String::ASN1_String(const std::string& str) : + m_utf8_str(str), + m_tag(choose_encoding(m_utf8_str)) + {} + +/* +* Return this string in ISO 8859-1 encoding +*/ +std::string ASN1_String::iso_8859() const + { + return utf8_to_latin1(m_utf8_str); + } + +/* +* DER encode an ASN1_String +*/ +void ASN1_String::encode_into(DER_Encoder& encoder) const + { + if(m_data.empty()) + { + encoder.add_object(tagging(), UNIVERSAL, m_utf8_str); + } + else + { + // If this string was decoded, reserialize using original encoding + encoder.add_object(tagging(), UNIVERSAL, m_data.data(), m_data.size()); + } + } + +/* +* Decode a BER encoded ASN1_String +*/ +void ASN1_String::decode_from(BER_Decoder& source) + { + BER_Object obj = source.get_next_object(); + + assert_is_string_type(obj.type()); + + m_tag = obj.type(); + m_data.assign(obj.bits(), obj.bits() + obj.length()); + + if(m_tag == BMP_STRING) + { + m_utf8_str = ucs2_to_utf8(m_data.data(), m_data.size()); + } + else if(m_tag == UNIVERSAL_STRING) + { + m_utf8_str = ucs4_to_utf8(m_data.data(), m_data.size()); + } + else + { + // All other supported string types are UTF-8 or some subset thereof + m_utf8_str = ASN1::to_string(obj); + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_str.h b/src/libs/3rdparty/botan/src/lib/asn1/asn1_str.h new file mode 100644 index 0000000000..41dbd005c5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_str.h @@ -0,0 +1,55 @@ +/* +* ASN.1 string type +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_STRING_H_ +#define BOTAN_ASN1_STRING_H_ + +#include <botan/asn1_obj.h> + +namespace Botan { + +/** +* ASN.1 string type +* This class normalizes all inputs to a UTF-8 std::string +*/ +class BOTAN_PUBLIC_API(2,0) ASN1_String final : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + ASN1_Tag tagging() const { return m_tag; } + + const std::string& value() const { return m_utf8_str; } + + size_t size() const { return value().size(); } + + bool empty() const { return m_utf8_str.empty(); } + + std::string BOTAN_DEPRECATED("Use value() to get UTF-8 string instead") + iso_8859() const; + + /** + * Return true iff this is a tag for a known string type we can handle. + * This ignores string types that are not supported, eg teletexString + */ + static bool is_string_type(ASN1_Tag tag); + + bool operator==(const ASN1_String& other) const + { return value() == other.value(); } + + explicit ASN1_String(const std::string& utf8 = ""); + ASN1_String(const std::string& utf8, ASN1_Tag tag); + private: + std::vector<uint8_t> m_data; + std::string m_utf8_str; + ASN1_Tag m_tag; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_time.cpp b/src/libs/3rdparty/botan/src/lib/asn1/asn1_time.cpp new file mode 100644 index 0000000000..43f94af6aa --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_time.cpp @@ -0,0 +1,283 @@ +/* +* X.509 Time Types +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/asn1_time.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/exceptn.h> +#include <botan/parsing.h> +#include <botan/calendar.h> +#include <sstream> +#include <iomanip> + +namespace Botan { + +X509_Time::X509_Time(const std::chrono::system_clock::time_point& time) + { + calendar_point cal = calendar_value(time); + + m_year = cal.get_year(); + m_month = cal.get_month(); + m_day = cal.get_day(); + m_hour = cal.get_hour(); + m_minute = cal.get_minutes(); + m_second = cal.get_seconds(); + + m_tag = (m_year >= 2050) ? GENERALIZED_TIME : UTC_TIME; + } + +X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag tag) + { + set_to(t_spec, tag); + } + +void X509_Time::encode_into(DER_Encoder& der) const + { + BOTAN_ARG_CHECK(m_tag == UTC_TIME || m_tag == GENERALIZED_TIME, + "X509_Time: Bad encoding tag"); + + der.add_object(m_tag, UNIVERSAL, to_string()); + } + +void X509_Time::decode_from(BER_Decoder& source) + { + BER_Object ber_time = source.get_next_object(); + + set_to(ASN1::to_string(ber_time), ber_time.type()); + } + +std::string X509_Time::to_string() const + { + if(time_is_set() == false) + throw Invalid_State("X509_Time::as_string: No time set"); + + uint32_t full_year = m_year; + + if(m_tag == UTC_TIME) + { + if(m_year < 1950 || m_year >= 2050) + throw Encoding_Error("X509_Time: The time " + readable_string() + + " cannot be encoded as a UTCTime"); + + full_year = (m_year >= 2000) ? (m_year - 2000) : (m_year - 1900); + } + + const uint64_t YEAR_FACTOR = 10000000000ULL; + const uint64_t MON_FACTOR = 100000000; + const uint64_t DAY_FACTOR = 1000000; + const uint64_t HOUR_FACTOR = 10000; + const uint64_t MIN_FACTOR = 100; + + const uint64_t int_repr = + YEAR_FACTOR * full_year + + MON_FACTOR * m_month + + DAY_FACTOR * m_day + + HOUR_FACTOR * m_hour + + MIN_FACTOR * m_minute + + m_second; + + std::string repr = std::to_string(int_repr) + "Z"; + + uint32_t desired_size = (m_tag == UTC_TIME) ? 13 : 15; + + while(repr.size() < desired_size) + repr = "0" + repr; + + return repr; + } + +std::string X509_Time::readable_string() const + { + if(time_is_set() == false) + throw Invalid_State("X509_Time::readable_string: No time set"); + + // desired format: "%04d/%02d/%02d %02d:%02d:%02d UTC" + std::stringstream output; + output << std::setfill('0') + << std::setw(4) << m_year << "/" + << std::setw(2) << m_month << "/" + << std::setw(2) << m_day + << " " + << std::setw(2) << m_hour << ":" + << std::setw(2) << m_minute << ":" + << std::setw(2) << m_second + << " UTC"; + + return output.str(); + } + +bool X509_Time::time_is_set() const + { + return (m_year != 0); + } + +int32_t X509_Time::cmp(const X509_Time& other) const + { + if(time_is_set() == false) + throw Invalid_State("X509_Time::cmp: No time set"); + + const int32_t EARLIER = -1, LATER = 1, SAME_TIME = 0; + + 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."); + + BOTAN_ARG_CHECK(t_spec.size() > 0, "Time string must not be empty."); + + BOTAN_ARG_CHECK(t_spec.back() == 'Z', "Botan does not support times with timezones other than Z"); + + if(spec_tag == GENERALIZED_TIME) + { + BOTAN_ARG_CHECK(t_spec.size() == 15, "Invalid GeneralizedTime string"); + } + else if(spec_tag == UTC_TIME) + { + BOTAN_ARG_CHECK(t_spec.size() == 13, "Invalid UTCTime string"); + } + + 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 " + t_spec + " does not seem to be valid"); + } + +/* +* Do a general sanity check on the time +*/ +bool X509_Time::passes_sanity_check() const + { + if(m_year < 1950 || m_year > 2200) + return false; + if(m_month == 0 || m_month > 12) + return false; + + const uint32_t days_in_month[12] = { 31, 28+1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if(m_day == 0 || m_day > days_in_month[m_month-1]) + return false; + + if(m_month == 2 && m_day == 29) + { + if(m_year % 4 != 0) + return false; // not a leap year + + if(m_year % 100 == 0 && m_year % 400 != 0) + 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; + } + +std::chrono::system_clock::time_point X509_Time::to_std_timepoint() const + { + return calendar_point(m_year, m_month, m_day, m_hour, m_minute, m_second).to_std_timepoint(); + } + +/* +* Compare two X509_Times for in various ways +*/ +bool operator==(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) == 0); } +bool operator!=(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) != 0); } + +bool operator<=(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) <= 0); } +bool operator>=(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) >= 0); } + +bool operator<(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) < 0); } +bool operator>(const X509_Time& t1, const X509_Time& t2) + { return (t1.cmp(t2) > 0); } + +} diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_time.h b/src/libs/3rdparty/botan/src/lib/asn1/asn1_time.h new file mode 100644 index 0000000000..717c58a7d9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_time.h @@ -0,0 +1,79 @@ +/* +* ASN.1 Time Representation +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASN1_TIME_H_ +#define BOTAN_ASN1_TIME_H_ + +#include <botan/asn1_obj.h> +#include <chrono> + +namespace Botan { + +/** +* X.509 Time +*/ +class BOTAN_PUBLIC_API(2,0) X509_Time final : public ASN1_Object + { + public: + /// DER encode a X509_Time + void encode_into(DER_Encoder&) const override; + + // 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; + + /// Return if the time has been set somehow + bool time_is_set() const; + + /// Compare this time against another + int32_t cmp(const X509_Time& other) const; + + /// Create an invalid X509_Time + X509_Time() = default; + + /// Create a X509_Time from a time point + explicit X509_Time(const std::chrono::system_clock::time_point& time); + + /// Create an X509_Time from string + X509_Time(const std::string& t_spec, ASN1_Tag tag); + + /// Returns a STL timepoint object + std::chrono::system_clock::time_point to_std_timepoint() const; + + private: + void set_to(const std::string& t_spec, ASN1_Tag); + bool passes_sanity_check() const; + + uint32_t m_year = 0; + uint32_t m_month = 0; + uint32_t m_day = 0; + uint32_t m_hour = 0; + uint32_t m_minute = 0; + uint32_t m_second = 0; + ASN1_Tag m_tag = NO_OBJECT; + }; + +/* +* Comparison Operations +*/ +bool BOTAN_PUBLIC_API(2,0) operator==(const X509_Time&, const X509_Time&); +bool BOTAN_PUBLIC_API(2,0) operator!=(const X509_Time&, const X509_Time&); +bool BOTAN_PUBLIC_API(2,0) operator<=(const X509_Time&, const X509_Time&); +bool BOTAN_PUBLIC_API(2,0) operator>=(const X509_Time&, const X509_Time&); +bool BOTAN_PUBLIC_API(2,0) operator<(const X509_Time&, const X509_Time&); +bool BOTAN_PUBLIC_API(2,0) operator>(const X509_Time&, const X509_Time&); + +typedef X509_Time ASN1_Time; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/asn1/ber_dec.cpp b/src/libs/3rdparty/botan/src/lib/asn1/ber_dec.cpp new file mode 100644 index 0000000000..c5af2f9338 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/ber_dec.cpp @@ -0,0 +1,549 @@ +/* +* BER Decoder +* (C) 1999-2008,2015,2017,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ber_dec.h> +#include <botan/bigint.h> +#include <botan/loadstor.h> +#include <botan/internal/safeint.h> + +namespace Botan { + +namespace { + +/* +* This value is somewhat arbitrary. OpenSSL allows up to 128 nested +* indefinite length sequences. If you increase this, also increase the +* limit in the test in test_asn1.cpp +*/ +const size_t ALLOWED_EOC_NESTINGS = 16; + +/* +* BER decode an ASN.1 type tag +*/ +size_t decode_tag(DataSource* ber, ASN1_Tag& type_tag, ASN1_Tag& class_tag) + { + uint8_t b; + if(!ber->read_byte(b)) + { + class_tag = type_tag = NO_OBJECT; + return 0; + } + + if((b & 0x1F) != 0x1F) + { + type_tag = ASN1_Tag(b & 0x1F); + class_tag = ASN1_Tag(b & 0xE0); + return 1; + } + + size_t tag_bytes = 1; + class_tag = ASN1_Tag(b & 0xE0); + + size_t tag_buf = 0; + while(true) + { + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Long-form tag truncated"); + if(tag_buf & 0xFF000000) + throw BER_Decoding_Error("Long-form tag overflowed 32 bits"); + ++tag_bytes; + tag_buf = (tag_buf << 7) | (b & 0x7F); + if((b & 0x80) == 0) break; + } + type_tag = ASN1_Tag(tag_buf); + return tag_bytes; + } + +/* +* Find the EOC marker +*/ +size_t find_eoc(DataSource* src, size_t allow_indef); + +/* +* BER decode an ASN.1 length field +*/ +size_t decode_length(DataSource* ber, size_t& field_size, size_t allow_indef) + { + uint8_t b; + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Length field not found"); + field_size = 1; + if((b & 0x80) == 0) + return b; + + field_size += (b & 0x7F); + if(field_size > 5) + throw BER_Decoding_Error("Length field is too large"); + + if(field_size == 1) + { + if(allow_indef == 0) + { + throw BER_Decoding_Error("Nested EOC markers too deep, rejecting to avoid stack exhaustion"); + } + else + { + return find_eoc(ber, allow_indef - 1); + } + } + + size_t length = 0; + + for(size_t i = 0; i != field_size - 1; ++i) + { + if(get_byte(0, length) != 0) + throw BER_Decoding_Error("Field length overflow"); + if(!ber->read_byte(b)) + throw BER_Decoding_Error("Corrupted length field"); + length = (length << 8) | b; + } + return length; + } + +/* +* Find the EOC marker +*/ +size_t find_eoc(DataSource* ber, size_t allow_indef) + { + secure_vector<uint8_t> buffer(BOTAN_DEFAULT_BUFFER_SIZE), data; + + while(true) + { + const size_t got = ber->peek(buffer.data(), buffer.size(), data.size()); + if(got == 0) + break; + + data += std::make_pair(buffer.data(), got); + } + + DataSource_Memory source(data); + data.clear(); + + size_t length = 0; + while(true) + { + ASN1_Tag type_tag, class_tag; + size_t tag_size = decode_tag(&source, type_tag, class_tag); + if(type_tag == NO_OBJECT) + break; + + size_t length_size = 0; + size_t item_size = decode_length(&source, length_size, allow_indef); + source.discard_next(item_size); + + length = BOTAN_CHECKED_ADD(length, item_size); + length = BOTAN_CHECKED_ADD(length, tag_size); + length = BOTAN_CHECKED_ADD(length, length_size); + + if(type_tag == EOC && class_tag == UNIVERSAL) + break; + } + return length; + } + +class DataSource_BERObject final : public DataSource + { + public: + size_t read(uint8_t out[], size_t length) override + { + BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length()); + const size_t got = std::min<size_t>(m_obj.length() - m_offset, length); + copy_mem(out, m_obj.bits() + m_offset, got); + m_offset += got; + return got; + } + + size_t peek(uint8_t out[], size_t length, size_t peek_offset) const override + { + BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length()); + const size_t bytes_left = m_obj.length() - m_offset; + + if(peek_offset >= bytes_left) + return 0; + + const size_t got = std::min(bytes_left - peek_offset, length); + copy_mem(out, m_obj.bits() + peek_offset, got); + return got; + } + + bool check_available(size_t n) override + { + BOTAN_ASSERT_NOMSG(m_offset <= m_obj.length()); + return (n <= (m_obj.length() - m_offset)); + } + + bool end_of_data() const override + { + return get_bytes_read() == m_obj.length(); + } + + size_t get_bytes_read() const override { return m_offset; } + + explicit DataSource_BERObject(BER_Object&& obj) : m_obj(std::move(obj)), m_offset(0) {} + + private: + BER_Object m_obj; + size_t m_offset; + }; + +} + +/* +* Check if more objects are there +*/ +bool BER_Decoder::more_items() const + { + if(m_source->end_of_data() && !m_pushed.is_set()) + return false; + return true; + } + +/* +* Verify that no bytes remain in the source +*/ +BER_Decoder& BER_Decoder::verify_end() + { + return verify_end("BER_Decoder::verify_end called, but data remains"); + } + +/* +* Verify that no bytes remain in the source +*/ +BER_Decoder& BER_Decoder::verify_end(const std::string& err) + { + if(!m_source->end_of_data() || m_pushed.is_set()) + throw Decoding_Error(err); + return (*this); + } + +/* +* Discard all the bytes remaining in the source +*/ +BER_Decoder& BER_Decoder::discard_remaining() + { + uint8_t buf; + while(m_source->read_byte(buf)) + {} + return (*this); + } + +/* +* Return the BER encoding of the next object +*/ +BER_Object BER_Decoder::get_next_object() + { + BER_Object next; + + if(m_pushed.is_set()) + { + std::swap(next, m_pushed); + return next; + } + + for(;;) + { + ASN1_Tag type_tag, class_tag; + decode_tag(m_source, type_tag, class_tag); + next.set_tagging(type_tag, class_tag); + if(next.is_set() == false) // no more objects + return next; + + size_t field_size; + const size_t length = decode_length(m_source, field_size, ALLOWED_EOC_NESTINGS); + if(!m_source->check_available(length)) + throw BER_Decoding_Error("Value truncated"); + + uint8_t* out = next.mutable_bits(length); + if(m_source->read(out, length) != length) + throw BER_Decoding_Error("Value truncated"); + + if(next.tagging() == EOC) + continue; + else + break; + } + + return next; + } + +/* +* Push a object back into the stream +*/ +void BER_Decoder::push_back(const BER_Object& obj) + { + if(m_pushed.is_set()) + throw Invalid_State("BER_Decoder: Only one push back is allowed"); + m_pushed = obj; + } + +void BER_Decoder::push_back(BER_Object&& obj) + { + if(m_pushed.is_set()) + throw Invalid_State("BER_Decoder: Only one push back is allowed"); + m_pushed = std::move(obj); + } + +BER_Decoder BER_Decoder::start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, ASN1_Tag(class_tag | CONSTRUCTED)); + return BER_Decoder(std::move(obj), this); + } + +/* +* Finish decoding a CONSTRUCTED type +*/ +BER_Decoder& BER_Decoder::end_cons() + { + if(!m_parent) + throw Invalid_State("BER_Decoder::end_cons called with null parent"); + if(!m_source->end_of_data()) + throw Decoding_Error("BER_Decoder::end_cons called with data left"); + return (*m_parent); + } + +BER_Decoder::BER_Decoder(BER_Object&& obj, BER_Decoder* parent) + { + m_data_src.reset(new DataSource_BERObject(std::move(obj))); + m_source = m_data_src.get(); + m_parent = parent; + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(DataSource& src) + { + m_source = &src; + } + +/* +* BER_Decoder Constructor + */ +BER_Decoder::BER_Decoder(const uint8_t data[], size_t length) + { + m_data_src.reset(new DataSource_Memory(data, length)); + m_source = m_data_src.get(); + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(const secure_vector<uint8_t>& data) + { + m_data_src.reset(new DataSource_Memory(data)); + m_source = m_data_src.get(); + } + +/* +* BER_Decoder Constructor +*/ +BER_Decoder::BER_Decoder(const std::vector<uint8_t>& data) + { + m_data_src.reset(new DataSource_Memory(data.data(), data.size())); + m_source = m_data_src.get(); + } + +/* +* BER_Decoder Copy Constructor +*/ +BER_Decoder::BER_Decoder(const BER_Decoder& other) + { + m_source = other.m_source; + + // take ownership + std::swap(m_data_src, other.m_data_src); + m_parent = other.m_parent; + } + +/* +* Request for an object to decode itself +*/ +BER_Decoder& BER_Decoder::decode(ASN1_Object& obj, + ASN1_Tag, ASN1_Tag) + { + obj.decode_from(*this); + return (*this); + } + +/* +* Decode a BER encoded NULL +*/ +BER_Decoder& BER_Decoder::decode_null() + { + BER_Object obj = get_next_object(); + obj.assert_is_a(NULL_TAG, UNIVERSAL); + if(obj.length() > 0) + throw BER_Decoding_Error("NULL object had nonzero size"); + return (*this); + } + +BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out) + { + secure_vector<uint8_t> out_vec; + decode(out_vec, OCTET_STRING); + out = BigInt::decode(out_vec.data(), out_vec.size()); + return (*this); + } + +/* +* Decode a BER encoded BOOLEAN +*/ +BER_Decoder& BER_Decoder::decode(bool& out, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(obj.length() != 1) + throw BER_Decoding_Error("BER boolean value had invalid size"); + + out = (obj.bits()[0]) ? true : false; + return (*this); + } + +/* +* Decode a small BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(size_t& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + BigInt integer; + decode(integer, type_tag, class_tag); + + if(integer.is_negative()) + throw BER_Decoding_Error("Decoded small integer value was negative"); + + if(integer.bits() > 32) + throw BER_Decoding_Error("Decoded integer value larger than expected"); + + out = 0; + for(size_t i = 0; i != 4; ++i) + out = (out << 8) | integer.byte_at(3-i); + + return (*this); + } + +/* +* Decode a small BER encoded INTEGER +*/ +uint64_t BER_Decoder::decode_constrained_integer(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t T_bytes) + { + if(T_bytes > 8) + throw BER_Decoding_Error("Can't decode small integer over 8 bytes"); + + BigInt integer; + decode(integer, type_tag, class_tag); + + if(integer.bits() > 8*T_bytes) + throw BER_Decoding_Error("Decoded integer value larger than expected"); + + uint64_t out = 0; + for(size_t i = 0; i != 8; ++i) + out = (out << 8) | integer.byte_at(7-i); + + return out; + } + +/* +* Decode a BER encoded INTEGER +*/ +BER_Decoder& BER_Decoder::decode(BigInt& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if(obj.length() == 0) + { + out = 0; + } + else + { + const bool negative = (obj.bits()[0] & 0x80) ? true : false; + + if(negative) + { + secure_vector<uint8_t> vec(obj.bits(), obj.bits() + obj.length()); + for(size_t i = obj.length(); i > 0; --i) + if(vec[i-1]--) + break; + for(size_t i = 0; i != obj.length(); ++i) + vec[i] = ~vec[i]; + out = BigInt(vec.data(), vec.size()); + out.flip_sign(); + } + else + { + out = BigInt(obj.bits(), obj.length()); + } + } + + return (*this); + } + +namespace { + +template<typename Alloc> +void asn1_decode_binary_string(std::vector<uint8_t, Alloc>& buffer, + const BER_Object& obj, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + obj.assert_is_a(type_tag, class_tag); + + if(real_type == OCTET_STRING) + { + buffer.assign(obj.bits(), obj.bits() + obj.length()); + } + else + { + if(obj.length() == 0) + throw BER_Decoding_Error("Invalid BIT STRING"); + if(obj.bits()[0] >= 8) + throw BER_Decoding_Error("Bad number of unused bits in BIT STRING"); + + buffer.resize(obj.length() - 1); + + if(obj.length() > 1) + copy_mem(buffer.data(), obj.bits() + 1, obj.length() - 1); + } + } + +} + +/* +* BER decode a BIT STRING or OCTET STRING +*/ +BER_Decoder& BER_Decoder::decode(secure_vector<uint8_t>& buffer, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type); + + asn1_decode_binary_string(buffer, get_next_object(), real_type, type_tag, class_tag); + return (*this); + } + +BER_Decoder& BER_Decoder::decode(std::vector<uint8_t>& buffer, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw BER_Bad_Tag("Bad tag for {BIT,OCTET} STRING", real_type); + + asn1_decode_binary_string(buffer, get_next_object(), real_type, type_tag, class_tag); + return (*this); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/asn1/ber_dec.h b/src/libs/3rdparty/botan/src/lib/asn1/ber_dec.h new file mode 100644 index 0000000000..0f2fb46074 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/ber_dec.h @@ -0,0 +1,418 @@ +/* +* BER Decoder +* (C) 1999-2010,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BER_DECODER_H_ +#define BOTAN_BER_DECODER_H_ + +#include <botan/asn1_obj.h> +#include <botan/data_src.h> + +namespace Botan { + +class BigInt; + +/** +* BER Decoding Object +*/ +class BOTAN_PUBLIC_API(2,0) BER_Decoder final + { + public: + /** + * Set up to BER decode the data in buf of length len + */ + BER_Decoder(const uint8_t buf[], size_t len); + + /** + * Set up to BER decode the data in vec + */ + explicit BER_Decoder(const secure_vector<uint8_t>& vec); + + /** + * Set up to BER decode the data in vec + */ + explicit BER_Decoder(const std::vector<uint8_t>& vec); + + /** + * Set up to BER decode the data in src + */ + explicit BER_Decoder(DataSource& src); + + /** + * Set up to BER decode the data in obj + */ + BER_Decoder(const BER_Object& obj) : + BER_Decoder(obj.bits(), obj.length()) {} + + /** + * Set up to BER decode the data in obj + */ + BER_Decoder(BER_Object&& obj) : + BER_Decoder(std::move(obj), nullptr) {} + + BER_Decoder(const BER_Decoder& other); + + BER_Decoder& operator=(const BER_Decoder&) = delete; + + /** + * Get the next object in the data stream. + * If EOF, returns an object with type NO_OBJECT. + */ + BER_Object get_next_object(); + + BER_Decoder& get_next(BER_Object& ber) + { + ber = get_next_object(); + return (*this); + } + + /** + * Push an object back onto the stream. Throws if another + * object was previously pushed and has not been subsequently + * read out. + */ + void push_back(const BER_Object& obj); + + /** + * Push an object back onto the stream. Throws if another + * object was previously pushed and has not been subsequently + * read out. + */ + void push_back(BER_Object&& obj); + + /** + * Return true if there is at least one more item remaining + */ + bool more_items() const; + + /** + * Verify the stream is concluded, throws otherwise. + * Returns (*this) + */ + BER_Decoder& verify_end(); + + /** + * Verify the stream is concluded, throws otherwise. + * Returns (*this) + */ + BER_Decoder& verify_end(const std::string& err_msg); + + /** + * Discard any data that remains unread + * Returns (*this) + */ + BER_Decoder& discard_remaining(); + + /** + * Start decoding a constructed data (sequence or set) + */ + BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag = UNIVERSAL); + + /** + * Finish decoding a constructed data, throws if any data remains. + * Returns the parent of *this (ie the object on which start_cons was called). + */ + BER_Decoder& end_cons(); + + /** + * Get next object and copy value to POD type + * Asserts value length is equal to POD type sizeof. + * Asserts Type tag and optional Class tag according to parameters. + * Copy value to POD type (struct, union, C-style array, std::array, etc.). + * @param out POD type reference where to copy object value + * @param type_tag ASN1_Tag enum to assert type on object read + * @param class_tag ASN1_Tag enum to assert class on object read (default: CONTEXT_SPECIFIC) + * @return this reference + */ + template <typename T> + BER_Decoder& get_next_value(T &out, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC) + { + static_assert(std::is_pod<T>::value, "Type must be POD"); + + BER_Object obj = get_next_object(); + obj.assert_is_a(type_tag, class_tag); + + if (obj.length() != sizeof(T)) + throw BER_Decoding_Error( + "Size mismatch. Object value size is " + + std::to_string(obj.length()) + + "; Output type size is " + + std::to_string(sizeof(T))); + + copy_mem(reinterpret_cast<uint8_t*>(&out), obj.bits(), obj.length()); + + return (*this); + } + + /* + * Save all the bytes remaining in the source + */ + template<typename Alloc> + BER_Decoder& raw_bytes(std::vector<uint8_t, Alloc>& out) + { + out.clear(); + uint8_t buf; + while(m_source->read_byte(buf)) + out.push_back(buf); + return (*this); + } + + BER_Decoder& decode_null(); + + /** + * Decode a BER encoded BOOLEAN + */ + BER_Decoder& decode(bool& out) + { + return decode(out, BOOLEAN, UNIVERSAL); + } + + /* + * Decode a small BER encoded INTEGER + */ + BER_Decoder& decode(size_t& out) + { + return decode(out, INTEGER, UNIVERSAL); + } + + /* + * Decode a BER encoded INTEGER + */ + BER_Decoder& decode(BigInt& out) + { + return decode(out, INTEGER, UNIVERSAL); + } + + std::vector<uint8_t> get_next_octet_string() + { + std::vector<uint8_t> out_vec; + decode(out_vec, OCTET_STRING); + return out_vec; + } + + /* + * BER decode a BIT STRING or OCTET STRING + */ + template<typename Alloc> + BER_Decoder& decode(std::vector<uint8_t, Alloc>& out, ASN1_Tag real_type) + { + return decode(out, real_type, real_type, UNIVERSAL); + } + + BER_Decoder& decode(bool& v, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(size_t& v, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(BigInt& v, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(std::vector<uint8_t>& v, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(secure_vector<uint8_t>& v, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + BER_Decoder& decode(class ASN1_Object& obj, + ASN1_Tag type_tag = NO_OBJECT, + ASN1_Tag class_tag = NO_OBJECT); + + /** + * Decode an integer value which is typed as an octet string + */ + BER_Decoder& decode_octet_string_bigint(BigInt& b); + + uint64_t decode_constrained_integer(ASN1_Tag type_tag, + ASN1_Tag class_tag, + size_t T_bytes); + + template<typename T> BER_Decoder& decode_integer_type(T& out) + { + return decode_integer_type<T>(out, INTEGER, UNIVERSAL); + } + + template<typename T> + BER_Decoder& decode_integer_type(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC) + { + out = static_cast<T>(decode_constrained_integer(type_tag, class_tag, sizeof(out))); + return (*this); + } + + template<typename T> + BER_Decoder& decode_optional(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + const T& default_value = T()); + + template<typename T> + BER_Decoder& decode_optional_implicit( + T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + ASN1_Tag real_type, + ASN1_Tag real_class, + const T& default_value = T()); + + template<typename T> + BER_Decoder& decode_list(std::vector<T>& out, + ASN1_Tag type_tag = SEQUENCE, + ASN1_Tag class_tag = UNIVERSAL); + + template<typename T> + BER_Decoder& decode_and_check(const T& expected, + const std::string& error_msg) + { + T actual; + decode(actual); + + if(actual != expected) + throw Decoding_Error(error_msg); + + return (*this); + } + + /* + * Decode an OPTIONAL string type + */ + template<typename Alloc> + BER_Decoder& decode_optional_string(std::vector<uint8_t, Alloc>& out, + ASN1_Tag real_type, + uint16_t type_no, + ASN1_Tag class_tag = CONTEXT_SPECIFIC) + { + BER_Object obj = get_next_object(); + + ASN1_Tag type_tag = static_cast<ASN1_Tag>(type_no); + + if(obj.is_a(type_tag, class_tag)) + { + if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC)) + { + BER_Decoder(std::move(obj)).decode(out, real_type).verify_end(); + } + else + { + push_back(std::move(obj)); + decode(out, real_type, type_tag, class_tag); + } + } + else + { + out.clear(); + push_back(std::move(obj)); + } + + return (*this); + } + + private: + BER_Decoder(BER_Object&& obj, BER_Decoder* parent); + + BER_Decoder* m_parent = nullptr; + BER_Object m_pushed; + // either m_data_src.get() or an unowned pointer + DataSource* m_source; + mutable std::unique_ptr<DataSource> m_data_src; + }; + +/* +* Decode an OPTIONAL or DEFAULT element +*/ +template<typename T> +BER_Decoder& BER_Decoder::decode_optional(T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + const T& default_value) + { + BER_Object obj = get_next_object(); + + if(obj.is_a(type_tag, class_tag)) + { + if((class_tag & CONSTRUCTED) && (class_tag & CONTEXT_SPECIFIC)) + { + BER_Decoder(std::move(obj)).decode(out).verify_end(); + } + else + { + push_back(std::move(obj)); + decode(out, type_tag, class_tag); + } + } + else + { + out = default_value; + push_back(std::move(obj)); + } + + return (*this); + } + +/* +* Decode an OPTIONAL or DEFAULT element +*/ +template<typename T> +BER_Decoder& BER_Decoder::decode_optional_implicit( + T& out, + ASN1_Tag type_tag, + ASN1_Tag class_tag, + ASN1_Tag real_type, + ASN1_Tag real_class, + const T& default_value) + { + BER_Object obj = get_next_object(); + + if(obj.is_a(type_tag, class_tag)) + { + obj.set_tagging(real_type, real_class); + push_back(std::move(obj)); + decode(out, real_type, real_class); + } + else + { + // Not what we wanted, push it back on the stream + out = default_value; + push_back(std::move(obj)); + } + + return (*this); + } +/* +* Decode a list of homogenously typed values +*/ +template<typename T> +BER_Decoder& BER_Decoder::decode_list(std::vector<T>& vec, + ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + BER_Decoder list = start_cons(type_tag, class_tag); + + while(list.more_items()) + { + T value; + list.decode(value); + vec.push_back(std::move(value)); + } + + list.end_cons(); + + return (*this); + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/asn1/der_enc.cpp b/src/libs/3rdparty/botan/src/lib/asn1/der_enc.cpp new file mode 100644 index 0000000000..99b833d27d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/der_enc.cpp @@ -0,0 +1,405 @@ +/* +* DER Encoder +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/der_enc.h> +#include <botan/asn1_obj.h> +#include <botan/bigint.h> +#include <botan/loadstor.h> +#include <botan/internal/bit_ops.h> +#include <algorithm> + +namespace Botan { + +namespace { + +/* +* DER encode an ASN.1 type tag +*/ +void encode_tag(std::vector<uint8_t>& encoded_tag, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if((class_tag | 0xE0) != 0xE0) + throw Encoding_Error("DER_Encoder: Invalid class tag " + + std::to_string(class_tag)); + + if(type_tag <= 30) + { + encoded_tag.push_back(static_cast<uint8_t>(type_tag | class_tag)); + } + else + { + size_t blocks = high_bit(type_tag) + 6; + blocks = (blocks - (blocks % 7)) / 7; + + BOTAN_ASSERT_NOMSG(blocks > 0); + + encoded_tag.push_back(static_cast<uint8_t>(class_tag | 0x1F)); + for(size_t i = 0; i != blocks - 1; ++i) + encoded_tag.push_back(0x80 | ((type_tag >> 7*(blocks-i-1)) & 0x7F)); + encoded_tag.push_back(type_tag & 0x7F); + } + } + +/* +* DER encode an ASN.1 length field +*/ +void encode_length(std::vector<uint8_t>& encoded_length, size_t length) + { + if(length <= 127) + { + encoded_length.push_back(static_cast<uint8_t>(length)); + } + else + { + const size_t bytes_needed = significant_bytes(length); + + encoded_length.push_back(static_cast<uint8_t>(0x80 | bytes_needed)); + + for(size_t i = sizeof(length) - bytes_needed; i < sizeof(length); ++i) + encoded_length.push_back(get_byte(i, length)); + } + } + +} + +DER_Encoder::DER_Encoder(secure_vector<uint8_t>& vec) + { + m_append_output = [&vec](const uint8_t b[], size_t l) + { + vec.insert(vec.end(), b, b + l); + }; + } + +DER_Encoder::DER_Encoder(std::vector<uint8_t>& vec) + { + m_append_output = [&vec](const uint8_t b[], size_t l) + { + vec.insert(vec.end(), b, b + l); + }; + } + +/* +* Push the encoded SEQUENCE/SET to the encoder stream +*/ +void DER_Encoder::DER_Sequence::push_contents(DER_Encoder& der) + { + const ASN1_Tag real_class_tag = ASN1_Tag(m_class_tag | CONSTRUCTED); + + if(m_type_tag == SET) + { + std::sort(m_set_contents.begin(), m_set_contents.end()); + for(size_t i = 0; i != m_set_contents.size(); ++i) + m_contents += m_set_contents[i]; + m_set_contents.clear(); + } + + der.add_object(m_type_tag, real_class_tag, m_contents.data(), m_contents.size()); + m_contents.clear(); + } + +/* +* Add an encoded value to the SEQUENCE/SET +*/ +void DER_Encoder::DER_Sequence::add_bytes(const uint8_t data[], size_t length) + { + if(m_type_tag == SET) + m_set_contents.push_back(secure_vector<uint8_t>(data, data + length)); + else + m_contents += std::make_pair(data, length); + } + +void DER_Encoder::DER_Sequence::add_bytes(const uint8_t hdr[], size_t hdr_len, + const uint8_t val[], size_t val_len) + { + if(m_type_tag == SET) + { + secure_vector<uint8_t> m; + m.reserve(hdr_len + val_len); + m += std::make_pair(hdr, hdr_len); + m += std::make_pair(val, val_len); + m_set_contents.push_back(std::move(m)); + } + else + { + m_contents += std::make_pair(hdr, hdr_len); + m_contents += std::make_pair(val, val_len); + } + } + +/* +* Return the type and class taggings +*/ +ASN1_Tag DER_Encoder::DER_Sequence::tag_of() const + { + return ASN1_Tag(m_type_tag | m_class_tag); + } + +/* +* DER_Sequence Constructor +*/ +DER_Encoder::DER_Sequence::DER_Sequence(ASN1_Tag t1, ASN1_Tag t2) : + m_type_tag(t1), m_class_tag(t2) + { + } + +/* +* Return the encoded contents +*/ +secure_vector<uint8_t> DER_Encoder::get_contents() + { + if(m_subsequences.size() != 0) + throw Invalid_State("DER_Encoder: Sequence hasn't been marked done"); + + if(m_append_output) + throw Invalid_State("DER_Encoder Cannot get contents when using output vector"); + + secure_vector<uint8_t> output; + std::swap(output, m_default_outbuf); + return output; + } + +std::vector<uint8_t> DER_Encoder::get_contents_unlocked() + { + if(m_subsequences.size() != 0) + throw Invalid_State("DER_Encoder: Sequence hasn't been marked done"); + + if(m_append_output) + throw Invalid_State("DER_Encoder Cannot get contents when using output vector"); + + std::vector<uint8_t> output(m_default_outbuf.begin(), m_default_outbuf.end()); + m_default_outbuf.clear(); + return output; + } + +/* +* Start a new ASN.1 SEQUENCE/SET/EXPLICIT +*/ +DER_Encoder& DER_Encoder::start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag) + { + m_subsequences.push_back(DER_Sequence(type_tag, class_tag)); + return (*this); + } + +/* +* Finish the current ASN.1 SEQUENCE/SET/EXPLICIT +*/ +DER_Encoder& DER_Encoder::end_cons() + { + if(m_subsequences.empty()) + throw Invalid_State("DER_Encoder::end_cons: No such sequence"); + + DER_Sequence last_seq = std::move(m_subsequences[m_subsequences.size()-1]); + m_subsequences.pop_back(); + last_seq.push_contents(*this); + + return (*this); + } + +/* +* Start a new ASN.1 EXPLICIT encoding +*/ +DER_Encoder& DER_Encoder::start_explicit(uint16_t type_no) + { + ASN1_Tag type_tag = static_cast<ASN1_Tag>(type_no); + + // This would confuse DER_Sequence + if(type_tag == SET) + throw Internal_Error("DER_Encoder.start_explicit(SET) not supported"); + + return start_cons(type_tag, CONTEXT_SPECIFIC); + } + +/* +* Finish the current ASN.1 EXPLICIT encoding +*/ +DER_Encoder& DER_Encoder::end_explicit() + { + return end_cons(); + } + +/* +* Write raw bytes into the stream +*/ +DER_Encoder& DER_Encoder::raw_bytes(const uint8_t bytes[], size_t length) + { + if(m_subsequences.size()) + { + m_subsequences[m_subsequences.size()-1].add_bytes(bytes, length); + } + else if(m_append_output) + { + m_append_output(bytes, length); + } + else + { + m_default_outbuf += std::make_pair(bytes, length); + } + + return (*this); + } + +/* +* Write the encoding of the byte(s) +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const uint8_t rep[], size_t length) + { + std::vector<uint8_t> hdr; + encode_tag(hdr, type_tag, class_tag); + encode_length(hdr, length); + + if(m_subsequences.size()) + { + m_subsequences[m_subsequences.size()-1].add_bytes(hdr.data(), hdr.size(), rep, length); + } + else if(m_append_output) + { + m_append_output(hdr.data(), hdr.size()); + m_append_output(rep, length); + } + else + { + m_default_outbuf += hdr; + m_default_outbuf += std::make_pair(rep, length); + } + + return (*this); + } + +/* +* Encode a NULL object +*/ +DER_Encoder& DER_Encoder::encode_null() + { + return add_object(NULL_TAG, UNIVERSAL, nullptr, 0); + } + +/* +* DER encode a BOOLEAN +*/ +DER_Encoder& DER_Encoder::encode(bool is_true) + { + return encode(is_true, BOOLEAN, UNIVERSAL); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(size_t n) + { + return encode(BigInt(n), INTEGER, UNIVERSAL); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(const BigInt& n) + { + return encode(n, INTEGER, UNIVERSAL); + } + +/* +* Encode this object +*/ +DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length, + ASN1_Tag real_type) + { + return encode(bytes, length, real_type, real_type, UNIVERSAL); + } + +/* +* DER encode a BOOLEAN +*/ +DER_Encoder& DER_Encoder::encode(bool is_true, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + uint8_t val = is_true ? 0xFF : 0x00; + return add_object(type_tag, class_tag, &val, 1); + } + +/* +* DER encode a small INTEGER +*/ +DER_Encoder& DER_Encoder::encode(size_t n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + return encode(BigInt(n), type_tag, class_tag); + } + +/* +* DER encode an INTEGER +*/ +DER_Encoder& DER_Encoder::encode(const BigInt& n, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(n == 0) + return add_object(type_tag, class_tag, 0); + + const size_t extra_zero = (n.bits() % 8 == 0) ? 1 : 0; + secure_vector<uint8_t> contents(extra_zero + n.bytes()); + BigInt::encode(&contents[extra_zero], n); + if(n < 0) + { + for(size_t i = 0; i != contents.size(); ++i) + contents[i] = ~contents[i]; + for(size_t i = contents.size(); i > 0; --i) + if(++contents[i-1]) + break; + } + + return add_object(type_tag, class_tag, contents); + } + +/* +* DER encode an OCTET STRING or BIT STRING +*/ +DER_Encoder& DER_Encoder::encode(const uint8_t bytes[], size_t length, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + if(real_type != OCTET_STRING && real_type != BIT_STRING) + throw Invalid_Argument("DER_Encoder: Invalid tag for byte/bit string"); + + if(real_type == BIT_STRING) + { + secure_vector<uint8_t> encoded; + encoded.push_back(0); + encoded += std::make_pair(bytes, length); + return add_object(type_tag, class_tag, encoded); + } + else + return add_object(type_tag, class_tag, bytes, length); + } + +DER_Encoder& DER_Encoder::encode(const ASN1_Object& obj) + { + obj.encode_into(*this); + return (*this); + } + +/* +* Write the encoding of the byte(s) +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& rep_str) + { + const uint8_t* rep = cast_char_ptr_to_uint8(rep_str.data()); + const size_t rep_len = rep_str.size(); + return add_object(type_tag, class_tag, rep, rep_len); + } + +/* +* Write the encoding of the byte +*/ +DER_Encoder& DER_Encoder::add_object(ASN1_Tag type_tag, + ASN1_Tag class_tag, uint8_t rep) + { + return add_object(type_tag, class_tag, &rep, 1); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/asn1/der_enc.h b/src/libs/3rdparty/botan/src/lib/asn1/der_enc.h new file mode 100644 index 0000000000..135a70d074 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/der_enc.h @@ -0,0 +1,221 @@ +/* +* DER Encoder +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DER_ENCODER_H_ +#define BOTAN_DER_ENCODER_H_ + +#include <botan/asn1_obj.h> +#include <vector> +#include <functional> + +namespace Botan { + +class BigInt; +class ASN1_Object; + +/** +* General DER Encoding Object +*/ +class BOTAN_PUBLIC_API(2,0) DER_Encoder final + { + public: + typedef std::function<void (const uint8_t[], size_t)> append_fn; + + /** + * DER encode, writing to an internal buffer + * Use get_contents or get_contents_unlocked to read the results + * after all encoding is completed. + */ + DER_Encoder() = default; + + /** + * DER encode, writing to @param vec + * If this constructor is used, get_contents* may not be called. + */ + DER_Encoder(secure_vector<uint8_t>& vec); + + /** + * DER encode, writing to @param vec + * If this constructor is used, get_contents* may not be called. + */ + DER_Encoder(std::vector<uint8_t>& vec); + + /** + * DER encode, calling append to write output + * If this constructor is used, get_contents* may not be called. + */ + DER_Encoder(append_fn append) : m_append_output(append) {} + + secure_vector<uint8_t> get_contents(); + + std::vector<uint8_t> get_contents_unlocked(); + + DER_Encoder& start_cons(ASN1_Tag type_tag, + ASN1_Tag class_tag = UNIVERSAL); + DER_Encoder& end_cons(); + + DER_Encoder& start_explicit(uint16_t type_tag); + DER_Encoder& end_explicit(); + + /** + * Insert raw bytes directly into the output stream + */ + DER_Encoder& raw_bytes(const uint8_t val[], size_t len); + + template<typename Alloc> + DER_Encoder& raw_bytes(const std::vector<uint8_t, Alloc>& val) + { + return raw_bytes(val.data(), val.size()); + } + + DER_Encoder& encode_null(); + DER_Encoder& encode(bool b); + DER_Encoder& encode(size_t s); + DER_Encoder& encode(const BigInt& n); + DER_Encoder& encode(const uint8_t val[], size_t len, ASN1_Tag real_type); + + template<typename Alloc> + DER_Encoder& encode(const std::vector<uint8_t, Alloc>& vec, ASN1_Tag real_type) + { + return encode(vec.data(), vec.size(), real_type); + } + + DER_Encoder& encode(bool b, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(size_t s, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const BigInt& n, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + DER_Encoder& encode(const uint8_t v[], size_t len, + ASN1_Tag real_type, + ASN1_Tag type_tag, + ASN1_Tag class_tag = CONTEXT_SPECIFIC); + + template<typename Alloc> + DER_Encoder& encode(const std::vector<uint8_t, Alloc>& bytes, + ASN1_Tag real_type, + ASN1_Tag type_tag, ASN1_Tag class_tag) + { + return encode(bytes.data(), bytes.size(), + real_type, type_tag, class_tag); + } + + template<typename T> + DER_Encoder& encode_optional(const T& value, const T& default_value) + { + if(value != default_value) + encode(value); + return (*this); + } + + template<typename T> + DER_Encoder& encode_list(const std::vector<T>& values) + { + for(size_t i = 0; i != values.size(); ++i) + encode(values[i]); + return (*this); + } + + /* + * Request for an object to encode itself to this stream + */ + DER_Encoder& encode(const ASN1_Object& obj); + + /* + * Conditionally write some values to the stream + */ + DER_Encoder& encode_if(bool pred, DER_Encoder& enc) + { + if(pred) + return raw_bytes(enc.get_contents()); + return (*this); + } + + DER_Encoder& encode_if(bool pred, const ASN1_Object& obj) + { + if(pred) + encode(obj); + return (*this); + } + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const uint8_t rep[], size_t length); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::vector<uint8_t>& rep) + { + return add_object(type_tag, class_tag, rep.data(), rep.size()); + } + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const secure_vector<uint8_t>& rep) + { + return add_object(type_tag, class_tag, rep.data(), rep.size()); + } + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + const std::string& str); + + DER_Encoder& add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, + uint8_t val); + + private: + class DER_Sequence final + { + public: + ASN1_Tag tag_of() const; + + void push_contents(DER_Encoder& der); + + void add_bytes(const uint8_t val[], size_t len); + + void add_bytes(const uint8_t hdr[], size_t hdr_len, + const uint8_t val[], size_t val_len); + + DER_Sequence(ASN1_Tag, ASN1_Tag); + + DER_Sequence(DER_Sequence&& seq) + { + std::swap(m_type_tag, seq.m_type_tag); + std::swap(m_class_tag, seq.m_class_tag); + std::swap(m_contents, seq.m_contents); + std::swap(m_set_contents, seq.m_set_contents); + } + + DER_Sequence& operator=(DER_Sequence&& seq) + { + std::swap(m_type_tag, seq.m_type_tag); + std::swap(m_class_tag, seq.m_class_tag); + std::swap(m_contents, seq.m_contents); + std::swap(m_set_contents, seq.m_set_contents); + return (*this); + } + + DER_Sequence(const DER_Sequence& seq) = default; + + DER_Sequence& operator=(const DER_Sequence& seq) = default; + + private: + ASN1_Tag m_type_tag, m_class_tag; + secure_vector<uint8_t> m_contents; + std::vector< secure_vector<uint8_t> > m_set_contents; + }; + + append_fn m_append_output; + secure_vector<uint8_t> m_default_outbuf; + std::vector<DER_Sequence> m_subsequences; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/asn1/info.txt b/src/libs/3rdparty/botan/src/lib/asn1/info.txt new file mode 100644 index 0000000000..4772e1ca70 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/info.txt @@ -0,0 +1,7 @@ +<defines> +ASN1 -> 20171109 +</defines> + +<requires> +bigint +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/asn1/oid_maps.cpp b/src/libs/3rdparty/botan/src/lib/asn1/oid_maps.cpp new file mode 100644 index 0000000000..138661a809 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/oid_maps.cpp @@ -0,0 +1,447 @@ +/* +* OID maps +* +* This file was automatically generated by ./src/scripts/oids.py on 2018-07-01 +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/oids.h> +#include <unordered_map> + +namespace Botan { + +std::unordered_map<std::string, std::string> OIDS::load_oid2str_map() + { + return std::unordered_map<std::string,std::string>{ + { "0.3.4401.5.3.1.9.26", "Camellia-192/GCM" }, + { "0.3.4401.5.3.1.9.46", "Camellia-256/GCM" }, + { "0.3.4401.5.3.1.9.6", "Camellia-128/GCM" }, + { "1.0.14888.3.0.5", "ECKCDSA" }, + { "1.2.156.10197.1.104.2", "SM4/CBC" }, + { "1.2.156.10197.1.104.8", "SM4/GCM" }, + { "1.2.156.10197.1.301", "sm2p256v1" }, + { "1.2.156.10197.1.301.1", "SM2_Sig" }, + { "1.2.156.10197.1.301.2", "SM2_Kex" }, + { "1.2.156.10197.1.301.3", "SM2_Enc" }, + { "1.2.156.10197.1.401", "SM3" }, + { "1.2.156.10197.1.504", "RSA/EMSA3(SM3)" }, + { "1.2.250.1.223.101.256.1", "frp256v1" }, + { "1.2.392.200011.61.1.1.1.2", "Camellia-128/CBC" }, + { "1.2.392.200011.61.1.1.1.3", "Camellia-192/CBC" }, + { "1.2.392.200011.61.1.1.1.4", "Camellia-256/CBC" }, + { "1.2.410.200004.1.100.4.3", "ECKCDSA/EMSA1(SHA-1)" }, + { "1.2.410.200004.1.100.4.4", "ECKCDSA/EMSA1(SHA-224)" }, + { "1.2.410.200004.1.100.4.5", "ECKCDSA/EMSA1(SHA-256)" }, + { "1.2.410.200004.1.4", "SEED/CBC" }, + { "1.2.643.2.2.19", "GOST-34.10" }, + { "1.2.643.2.2.3", "GOST-34.10/EMSA1(GOST-R-34.11-94)" }, + { "1.2.643.2.2.35.1", "gost_256A" }, + { "1.2.643.2.2.36.0", "gost_256A" }, + { "1.2.643.7.1.1.2.2", "Streebog-256" }, + { "1.2.643.7.1.1.2.3", "Streebog-512" }, + { "1.2.840.10040.4.1", "DSA" }, + { "1.2.840.10040.4.3", "DSA/EMSA1(SHA-160)" }, + { "1.2.840.10045.2.1", "ECDSA" }, + { "1.2.840.10045.3.1.1", "secp192r1" }, + { "1.2.840.10045.3.1.2", "x962_p192v2" }, + { "1.2.840.10045.3.1.3", "x962_p192v3" }, + { "1.2.840.10045.3.1.4", "x962_p239v1" }, + { "1.2.840.10045.3.1.5", "x962_p239v2" }, + { "1.2.840.10045.3.1.6", "x962_p239v3" }, + { "1.2.840.10045.3.1.7", "secp256r1" }, + { "1.2.840.10045.4.1", "ECDSA/EMSA1(SHA-160)" }, + { "1.2.840.10045.4.3.1", "ECDSA/EMSA1(SHA-224)" }, + { "1.2.840.10045.4.3.2", "ECDSA/EMSA1(SHA-256)" }, + { "1.2.840.10045.4.3.3", "ECDSA/EMSA1(SHA-384)" }, + { "1.2.840.10045.4.3.4", "ECDSA/EMSA1(SHA-512)" }, + { "1.2.840.10046.2.1", "DH" }, + { "1.2.840.113533.7.66.10", "CAST-128/CBC" }, + { "1.2.840.113533.7.66.15", "KeyWrap.CAST-128" }, + { "1.2.840.113549.1.1.1", "RSA" }, + { "1.2.840.113549.1.1.10", "RSA/EMSA4" }, + { "1.2.840.113549.1.1.11", "RSA/EMSA3(SHA-256)" }, + { "1.2.840.113549.1.1.12", "RSA/EMSA3(SHA-384)" }, + { "1.2.840.113549.1.1.13", "RSA/EMSA3(SHA-512)" }, + { "1.2.840.113549.1.1.14", "RSA/EMSA3(SHA-224)" }, + { "1.2.840.113549.1.1.16", "RSA/EMSA3(SHA-512-256)" }, + { "1.2.840.113549.1.1.4", "RSA/EMSA3(MD5)" }, + { "1.2.840.113549.1.1.5", "RSA/EMSA3(SHA-160)" }, + { "1.2.840.113549.1.1.7", "RSA/OAEP" }, + { "1.2.840.113549.1.1.8", "MGF1" }, + { "1.2.840.113549.1.5.12", "PKCS5.PBKDF2" }, + { "1.2.840.113549.1.5.13", "PBE-PKCS5v20" }, + { "1.2.840.113549.1.9.1", "PKCS9.EmailAddress" }, + { "1.2.840.113549.1.9.14", "PKCS9.ExtensionRequest" }, + { "1.2.840.113549.1.9.16.3.18", "ChaCha20Poly1305" }, + { "1.2.840.113549.1.9.16.3.6", "KeyWrap.TripleDES" }, + { "1.2.840.113549.1.9.16.3.7", "KeyWrap.RC2" }, + { "1.2.840.113549.1.9.16.3.8", "Compression.Zlib" }, + { "1.2.840.113549.1.9.2", "PKCS9.UnstructuredName" }, + { "1.2.840.113549.1.9.3", "PKCS9.ContentType" }, + { "1.2.840.113549.1.9.4", "PKCS9.MessageDigest" }, + { "1.2.840.113549.1.9.7", "PKCS9.ChallengePassword" }, + { "1.2.840.113549.2.10", "HMAC(SHA-384)" }, + { "1.2.840.113549.2.11", "HMAC(SHA-512)" }, + { "1.2.840.113549.2.5", "MD5" }, + { "1.2.840.113549.2.7", "HMAC(SHA-160)" }, + { "1.2.840.113549.2.8", "HMAC(SHA-224)" }, + { "1.2.840.113549.2.9", "HMAC(SHA-256)" }, + { "1.2.840.113549.3.2", "RC2/CBC" }, + { "1.2.840.113549.3.7", "TripleDES/CBC" }, + { "1.3.101.110", "Curve25519" }, + { "1.3.101.112", "Ed25519" }, + { "1.3.132.0.10", "secp256k1" }, + { "1.3.132.0.30", "secp160r2" }, + { "1.3.132.0.31", "secp192k1" }, + { "1.3.132.0.32", "secp224k1" }, + { "1.3.132.0.33", "secp224r1" }, + { "1.3.132.0.34", "secp384r1" }, + { "1.3.132.0.35", "secp521r1" }, + { "1.3.132.0.8", "secp160r1" }, + { "1.3.132.0.9", "secp160k1" }, + { "1.3.132.1.12", "ECDH" }, + { "1.3.14.3.2.26", "SHA-160" }, + { "1.3.14.3.2.7", "DES/CBC" }, + { "1.3.36.3.2.1", "RIPEMD-160" }, + { "1.3.36.3.3.1.2", "RSA/EMSA3(RIPEMD-160)" }, + { "1.3.36.3.3.2.5.2.1", "ECGDSA" }, + { "1.3.36.3.3.2.5.4.1", "ECGDSA/EMSA1(RIPEMD-160)" }, + { "1.3.36.3.3.2.5.4.2", "ECGDSA/EMSA1(SHA-160)" }, + { "1.3.36.3.3.2.5.4.3", "ECGDSA/EMSA1(SHA-224)" }, + { "1.3.36.3.3.2.5.4.4", "ECGDSA/EMSA1(SHA-256)" }, + { "1.3.36.3.3.2.5.4.5", "ECGDSA/EMSA1(SHA-384)" }, + { "1.3.36.3.3.2.5.4.6", "ECGDSA/EMSA1(SHA-512)" }, + { "1.3.36.3.3.2.8.1.1.1", "brainpool160r1" }, + { "1.3.36.3.3.2.8.1.1.11", "brainpool384r1" }, + { "1.3.36.3.3.2.8.1.1.13", "brainpool512r1" }, + { "1.3.36.3.3.2.8.1.1.3", "brainpool192r1" }, + { "1.3.36.3.3.2.8.1.1.5", "brainpool224r1" }, + { "1.3.36.3.3.2.8.1.1.7", "brainpool256r1" }, + { "1.3.36.3.3.2.8.1.1.9", "brainpool320r1" }, + { "1.3.6.1.4.1.11591.12.2", "Tiger(24,3)" }, + { "1.3.6.1.4.1.11591.15.1", "OpenPGP.Ed25519" }, + { "1.3.6.1.4.1.11591.4.11", "Scrypt" }, + { "1.3.6.1.4.1.25258.1.3", "McEliece" }, + { "1.3.6.1.4.1.25258.1.5", "XMSS" }, + { "1.3.6.1.4.1.25258.1.6.1", "GOST-34.10/EMSA1(SHA-256)" }, + { "1.3.6.1.4.1.25258.3.1", "Serpent/CBC" }, + { "1.3.6.1.4.1.25258.3.101", "Serpent/GCM" }, + { "1.3.6.1.4.1.25258.3.102", "Twofish/GCM" }, + { "1.3.6.1.4.1.25258.3.2", "Threefish-512/CBC" }, + { "1.3.6.1.4.1.25258.3.2.1", "AES-128/OCB" }, + { "1.3.6.1.4.1.25258.3.2.2", "AES-192/OCB" }, + { "1.3.6.1.4.1.25258.3.2.3", "AES-256/OCB" }, + { "1.3.6.1.4.1.25258.3.2.4", "Serpent/OCB" }, + { "1.3.6.1.4.1.25258.3.2.5", "Twofish/OCB" }, + { "1.3.6.1.4.1.25258.3.3", "Twofish/CBC" }, + { "1.3.6.1.4.1.3029.1.2.1", "ElGamal" }, + { "1.3.6.1.4.1.3029.1.5.1", "OpenPGP.Curve25519" }, + { "1.3.6.1.4.1.311.20.2.2", "Microsoft SmartcardLogon" }, + { "1.3.6.1.4.1.8301.3.1.2.9.0.38", "secp521r1" }, + { "1.3.6.1.5.5.7.1.1", "PKIX.AuthorityInformationAccess" }, + { "1.3.6.1.5.5.7.3.1", "PKIX.ServerAuth" }, + { "1.3.6.1.5.5.7.3.2", "PKIX.ClientAuth" }, + { "1.3.6.1.5.5.7.3.3", "PKIX.CodeSigning" }, + { "1.3.6.1.5.5.7.3.4", "PKIX.EmailProtection" }, + { "1.3.6.1.5.5.7.3.5", "PKIX.IPsecEndSystem" }, + { "1.3.6.1.5.5.7.3.6", "PKIX.IPsecTunnel" }, + { "1.3.6.1.5.5.7.3.7", "PKIX.IPsecUser" }, + { "1.3.6.1.5.5.7.3.8", "PKIX.TimeStamping" }, + { "1.3.6.1.5.5.7.3.9", "PKIX.OCSPSigning" }, + { "1.3.6.1.5.5.7.48.1", "PKIX.OCSP" }, + { "1.3.6.1.5.5.7.48.1.1", "PKIX.OCSP.BasicResponse" }, + { "1.3.6.1.5.5.7.48.2", "PKIX.CertificateAuthorityIssuers" }, + { "1.3.6.1.5.5.7.8.5", "PKIX.XMPPAddr" }, + { "2.16.840.1.101.3.4.1.2", "AES-128/CBC" }, + { "2.16.840.1.101.3.4.1.22", "AES-192/CBC" }, + { "2.16.840.1.101.3.4.1.25", "KeyWrap.AES-192" }, + { "2.16.840.1.101.3.4.1.26", "AES-192/GCM" }, + { "2.16.840.1.101.3.4.1.27", "AES-192/CCM" }, + { "2.16.840.1.101.3.4.1.42", "AES-256/CBC" }, + { "2.16.840.1.101.3.4.1.45", "KeyWrap.AES-256" }, + { "2.16.840.1.101.3.4.1.46", "AES-256/GCM" }, + { "2.16.840.1.101.3.4.1.47", "AES-256/CCM" }, + { "2.16.840.1.101.3.4.1.5", "KeyWrap.AES-128" }, + { "2.16.840.1.101.3.4.1.6", "AES-128/GCM" }, + { "2.16.840.1.101.3.4.1.7", "AES-128/CCM" }, + { "2.16.840.1.101.3.4.2.1", "SHA-256" }, + { "2.16.840.1.101.3.4.2.10", "SHA-3(512)" }, + { "2.16.840.1.101.3.4.2.11", "SHAKE-128" }, + { "2.16.840.1.101.3.4.2.12", "SHAKE-256" }, + { "2.16.840.1.101.3.4.2.2", "SHA-384" }, + { "2.16.840.1.101.3.4.2.3", "SHA-512" }, + { "2.16.840.1.101.3.4.2.4", "SHA-224" }, + { "2.16.840.1.101.3.4.2.6", "SHA-512-256" }, + { "2.16.840.1.101.3.4.2.7", "SHA-3(224)" }, + { "2.16.840.1.101.3.4.2.8", "SHA-3(256)" }, + { "2.16.840.1.101.3.4.2.9", "SHA-3(384)" }, + { "2.16.840.1.101.3.4.3.1", "DSA/EMSA1(SHA-224)" }, + { "2.16.840.1.101.3.4.3.10", "ECDSA/EMSA1(SHA-3(256))" }, + { "2.16.840.1.101.3.4.3.11", "ECDSA/EMSA1(SHA-3(384))" }, + { "2.16.840.1.101.3.4.3.12", "ECDSA/EMSA1(SHA-3(512))" }, + { "2.16.840.1.101.3.4.3.13", "RSA/EMSA3(SHA-3(224))" }, + { "2.16.840.1.101.3.4.3.14", "RSA/EMSA3(SHA-3(256))" }, + { "2.16.840.1.101.3.4.3.15", "RSA/EMSA3(SHA-3(384))" }, + { "2.16.840.1.101.3.4.3.16", "RSA/EMSA3(SHA-3(512))" }, + { "2.16.840.1.101.3.4.3.2", "DSA/EMSA1(SHA-256)" }, + { "2.16.840.1.101.3.4.3.3", "DSA/EMSA1(SHA-384)" }, + { "2.16.840.1.101.3.4.3.4", "DSA/EMSA1(SHA-512)" }, + { "2.16.840.1.101.3.4.3.5", "DSA/EMSA1(SHA-3(224))" }, + { "2.16.840.1.101.3.4.3.6", "DSA/EMSA1(SHA-3(256))" }, + { "2.16.840.1.101.3.4.3.7", "DSA/EMSA1(SHA-3(384))" }, + { "2.16.840.1.101.3.4.3.8", "DSA/EMSA1(SHA-3(512))" }, + { "2.16.840.1.101.3.4.3.9", "ECDSA/EMSA1(SHA-3(224))" }, + { "2.5.29.14", "X509v3.SubjectKeyIdentifier" }, + { "2.5.29.15", "X509v3.KeyUsage" }, + { "2.5.29.17", "X509v3.SubjectAlternativeName" }, + { "2.5.29.18", "X509v3.IssuerAlternativeName" }, + { "2.5.29.19", "X509v3.BasicConstraints" }, + { "2.5.29.20", "X509v3.CRLNumber" }, + { "2.5.29.21", "X509v3.ReasonCode" }, + { "2.5.29.23", "X509v3.HoldInstructionCode" }, + { "2.5.29.24", "X509v3.InvalidityDate" }, + { "2.5.29.28", "X509v3.CRLIssuingDistributionPoint" }, + { "2.5.29.30", "X509v3.NameConstraints" }, + { "2.5.29.31", "X509v3.CRLDistributionPoints" }, + { "2.5.29.32", "X509v3.CertificatePolicies" }, + { "2.5.29.32.0", "X509v3.AnyPolicy" }, + { "2.5.29.35", "X509v3.AuthorityKeyIdentifier" }, + { "2.5.29.36", "X509v3.PolicyConstraints" }, + { "2.5.29.37", "X509v3.ExtendedKeyUsage" }, + { "2.5.4.10", "X520.Organization" }, + { "2.5.4.11", "X520.OrganizationalUnit" }, + { "2.5.4.12", "X520.Title" }, + { "2.5.4.3", "X520.CommonName" }, + { "2.5.4.4", "X520.Surname" }, + { "2.5.4.42", "X520.GivenName" }, + { "2.5.4.43", "X520.Initials" }, + { "2.5.4.44", "X520.GenerationalQualifier" }, + { "2.5.4.46", "X520.DNQualifier" }, + { "2.5.4.5", "X520.SerialNumber" }, + { "2.5.4.6", "X520.Country" }, + { "2.5.4.65", "X520.Pseudonym" }, + { "2.5.4.7", "X520.Locality" }, + { "2.5.4.8", "X520.State" }, + { "2.5.8.1.1", "RSA" } + }; + } + +std::unordered_map<std::string, OID> OIDS::load_str2oid_map() + { + return std::unordered_map<std::string,OID>{ + { "AES-128/CBC", OID({2,16,840,1,101,3,4,1,2}) }, + { "AES-128/CCM", OID({2,16,840,1,101,3,4,1,7}) }, + { "AES-128/GCM", OID({2,16,840,1,101,3,4,1,6}) }, + { "AES-128/OCB", OID({1,3,6,1,4,1,25258,3,2,1}) }, + { "AES-192/CBC", OID({2,16,840,1,101,3,4,1,22}) }, + { "AES-192/CCM", OID({2,16,840,1,101,3,4,1,27}) }, + { "AES-192/GCM", OID({2,16,840,1,101,3,4,1,26}) }, + { "AES-192/OCB", OID({1,3,6,1,4,1,25258,3,2,2}) }, + { "AES-256/CBC", OID({2,16,840,1,101,3,4,1,42}) }, + { "AES-256/CCM", OID({2,16,840,1,101,3,4,1,47}) }, + { "AES-256/GCM", OID({2,16,840,1,101,3,4,1,46}) }, + { "AES-256/OCB", OID({1,3,6,1,4,1,25258,3,2,3}) }, + { "CAST-128/CBC", OID({1,2,840,113533,7,66,10}) }, + { "Camellia-128/CBC", OID({1,2,392,200011,61,1,1,1,2}) }, + { "Camellia-128/GCM", OID({0,3,4401,5,3,1,9,6}) }, + { "Camellia-192/CBC", OID({1,2,392,200011,61,1,1,1,3}) }, + { "Camellia-192/GCM", OID({0,3,4401,5,3,1,9,26}) }, + { "Camellia-256/CBC", OID({1,2,392,200011,61,1,1,1,4}) }, + { "Camellia-256/GCM", OID({0,3,4401,5,3,1,9,46}) }, + { "ChaCha20Poly1305", OID({1,2,840,113549,1,9,16,3,18}) }, + { "Compression.Zlib", OID({1,2,840,113549,1,9,16,3,8}) }, + { "Curve25519", OID({1,3,101,110}) }, + { "DES/CBC", OID({1,3,14,3,2,7}) }, + { "DH", OID({1,2,840,10046,2,1}) }, + { "DSA", OID({1,2,840,10040,4,1}) }, + { "DSA/EMSA1(SHA-160)", OID({1,2,840,10040,4,3}) }, + { "DSA/EMSA1(SHA-224)", OID({2,16,840,1,101,3,4,3,1}) }, + { "DSA/EMSA1(SHA-256)", OID({2,16,840,1,101,3,4,3,2}) }, + { "DSA/EMSA1(SHA-3(224))", OID({2,16,840,1,101,3,4,3,5}) }, + { "DSA/EMSA1(SHA-3(256))", OID({2,16,840,1,101,3,4,3,6}) }, + { "DSA/EMSA1(SHA-3(384))", OID({2,16,840,1,101,3,4,3,7}) }, + { "DSA/EMSA1(SHA-3(512))", OID({2,16,840,1,101,3,4,3,8}) }, + { "DSA/EMSA1(SHA-384)", OID({2,16,840,1,101,3,4,3,3}) }, + { "DSA/EMSA1(SHA-512)", OID({2,16,840,1,101,3,4,3,4}) }, + { "ECDH", OID({1,3,132,1,12}) }, + { "ECDSA", OID({1,2,840,10045,2,1}) }, + { "ECDSA/EMSA1(SHA-160)", OID({1,2,840,10045,4,1}) }, + { "ECDSA/EMSA1(SHA-224)", OID({1,2,840,10045,4,3,1}) }, + { "ECDSA/EMSA1(SHA-256)", OID({1,2,840,10045,4,3,2}) }, + { "ECDSA/EMSA1(SHA-3(224))", OID({2,16,840,1,101,3,4,3,9}) }, + { "ECDSA/EMSA1(SHA-3(256))", OID({2,16,840,1,101,3,4,3,10}) }, + { "ECDSA/EMSA1(SHA-3(384))", OID({2,16,840,1,101,3,4,3,11}) }, + { "ECDSA/EMSA1(SHA-3(512))", OID({2,16,840,1,101,3,4,3,12}) }, + { "ECDSA/EMSA1(SHA-384)", OID({1,2,840,10045,4,3,3}) }, + { "ECDSA/EMSA1(SHA-512)", OID({1,2,840,10045,4,3,4}) }, + { "ECGDSA", OID({1,3,36,3,3,2,5,2,1}) }, + { "ECGDSA/EMSA1(RIPEMD-160)", OID({1,3,36,3,3,2,5,4,1}) }, + { "ECGDSA/EMSA1(SHA-160)", OID({1,3,36,3,3,2,5,4,2}) }, + { "ECGDSA/EMSA1(SHA-224)", OID({1,3,36,3,3,2,5,4,3}) }, + { "ECGDSA/EMSA1(SHA-256)", OID({1,3,36,3,3,2,5,4,4}) }, + { "ECGDSA/EMSA1(SHA-384)", OID({1,3,36,3,3,2,5,4,5}) }, + { "ECGDSA/EMSA1(SHA-512)", OID({1,3,36,3,3,2,5,4,6}) }, + { "ECKCDSA", OID({1,0,14888,3,0,5}) }, + { "ECKCDSA/EMSA1(SHA-1)", OID({1,2,410,200004,1,100,4,3}) }, + { "ECKCDSA/EMSA1(SHA-224)", OID({1,2,410,200004,1,100,4,4}) }, + { "ECKCDSA/EMSA1(SHA-256)", OID({1,2,410,200004,1,100,4,5}) }, + { "Ed25519", OID({1,3,101,112}) }, + { "ElGamal", OID({1,3,6,1,4,1,3029,1,2,1}) }, + { "GOST-34.10", OID({1,2,643,2,2,19}) }, + { "GOST-34.10/EMSA1(GOST-R-34.11-94)", OID({1,2,643,2,2,3}) }, + { "GOST-34.10/EMSA1(SHA-256)", OID({1,3,6,1,4,1,25258,1,6,1}) }, + { "HMAC(SHA-160)", OID({1,2,840,113549,2,7}) }, + { "HMAC(SHA-224)", OID({1,2,840,113549,2,8}) }, + { "HMAC(SHA-256)", OID({1,2,840,113549,2,9}) }, + { "HMAC(SHA-384)", OID({1,2,840,113549,2,10}) }, + { "HMAC(SHA-512)", OID({1,2,840,113549,2,11}) }, + { "KeyWrap.AES-128", OID({2,16,840,1,101,3,4,1,5}) }, + { "KeyWrap.AES-192", OID({2,16,840,1,101,3,4,1,25}) }, + { "KeyWrap.AES-256", OID({2,16,840,1,101,3,4,1,45}) }, + { "KeyWrap.CAST-128", OID({1,2,840,113533,7,66,15}) }, + { "KeyWrap.RC2", OID({1,2,840,113549,1,9,16,3,7}) }, + { "KeyWrap.TripleDES", OID({1,2,840,113549,1,9,16,3,6}) }, + { "MD5", OID({1,2,840,113549,2,5}) }, + { "MGF1", OID({1,2,840,113549,1,1,8}) }, + { "McEliece", OID({1,3,6,1,4,1,25258,1,3}) }, + { "Microsoft SmartcardLogon", OID({1,3,6,1,4,1,311,20,2,2}) }, + { "OpenPGP.Curve25519", OID({1,3,6,1,4,1,3029,1,5,1}) }, + { "OpenPGP.Ed25519", OID({1,3,6,1,4,1,11591,15,1}) }, + { "PBE-PKCS5v20", OID({1,2,840,113549,1,5,13}) }, + { "PKCS5.PBKDF2", OID({1,2,840,113549,1,5,12}) }, + { "PKCS9.ChallengePassword", OID({1,2,840,113549,1,9,7}) }, + { "PKCS9.ContentType", OID({1,2,840,113549,1,9,3}) }, + { "PKCS9.EmailAddress", OID({1,2,840,113549,1,9,1}) }, + { "PKCS9.ExtensionRequest", OID({1,2,840,113549,1,9,14}) }, + { "PKCS9.MessageDigest", OID({1,2,840,113549,1,9,4}) }, + { "PKCS9.UnstructuredName", OID({1,2,840,113549,1,9,2}) }, + { "PKIX.AuthorityInformationAccess", OID({1,3,6,1,5,5,7,1,1}) }, + { "PKIX.CertificateAuthorityIssuers", OID({1,3,6,1,5,5,7,48,2}) }, + { "PKIX.ClientAuth", OID({1,3,6,1,5,5,7,3,2}) }, + { "PKIX.CodeSigning", OID({1,3,6,1,5,5,7,3,3}) }, + { "PKIX.EmailProtection", OID({1,3,6,1,5,5,7,3,4}) }, + { "PKIX.IPsecEndSystem", OID({1,3,6,1,5,5,7,3,5}) }, + { "PKIX.IPsecTunnel", OID({1,3,6,1,5,5,7,3,6}) }, + { "PKIX.IPsecUser", OID({1,3,6,1,5,5,7,3,7}) }, + { "PKIX.OCSP", OID({1,3,6,1,5,5,7,48,1}) }, + { "PKIX.OCSP.BasicResponse", OID({1,3,6,1,5,5,7,48,1,1}) }, + { "PKIX.OCSPSigning", OID({1,3,6,1,5,5,7,3,9}) }, + { "PKIX.ServerAuth", OID({1,3,6,1,5,5,7,3,1}) }, + { "PKIX.TimeStamping", OID({1,3,6,1,5,5,7,3,8}) }, + { "PKIX.XMPPAddr", OID({1,3,6,1,5,5,7,8,5}) }, + { "RC2/CBC", OID({1,2,840,113549,3,2}) }, + { "RIPEMD-160", OID({1,3,36,3,2,1}) }, + { "RSA", OID({1,2,840,113549,1,1,1}) }, + { "RSA/EMSA3(MD5)", OID({1,2,840,113549,1,1,4}) }, + { "RSA/EMSA3(RIPEMD-160)", OID({1,3,36,3,3,1,2}) }, + { "RSA/EMSA3(SHA-160)", OID({1,2,840,113549,1,1,5}) }, + { "RSA/EMSA3(SHA-224)", OID({1,2,840,113549,1,1,14}) }, + { "RSA/EMSA3(SHA-256)", OID({1,2,840,113549,1,1,11}) }, + { "RSA/EMSA3(SHA-3(224))", OID({2,16,840,1,101,3,4,3,13}) }, + { "RSA/EMSA3(SHA-3(256))", OID({2,16,840,1,101,3,4,3,14}) }, + { "RSA/EMSA3(SHA-3(384))", OID({2,16,840,1,101,3,4,3,15}) }, + { "RSA/EMSA3(SHA-3(512))", OID({2,16,840,1,101,3,4,3,16}) }, + { "RSA/EMSA3(SHA-384)", OID({1,2,840,113549,1,1,12}) }, + { "RSA/EMSA3(SHA-512)", OID({1,2,840,113549,1,1,13}) }, + { "RSA/EMSA3(SHA-512-256)", OID({1,2,840,113549,1,1,16}) }, + { "RSA/EMSA3(SM3)", OID({1,2,156,10197,1,504}) }, + { "RSA/EMSA4", OID({1,2,840,113549,1,1,10}) }, + { "RSA/OAEP", OID({1,2,840,113549,1,1,7}) }, + { "SEED/CBC", OID({1,2,410,200004,1,4}) }, + { "SHA-160", OID({1,3,14,3,2,26}) }, + { "SHA-224", OID({2,16,840,1,101,3,4,2,4}) }, + { "SHA-256", OID({2,16,840,1,101,3,4,2,1}) }, + { "SHA-3(224)", OID({2,16,840,1,101,3,4,2,7}) }, + { "SHA-3(256)", OID({2,16,840,1,101,3,4,2,8}) }, + { "SHA-3(384)", OID({2,16,840,1,101,3,4,2,9}) }, + { "SHA-3(512)", OID({2,16,840,1,101,3,4,2,10}) }, + { "SHA-384", OID({2,16,840,1,101,3,4,2,2}) }, + { "SHA-512", OID({2,16,840,1,101,3,4,2,3}) }, + { "SHA-512-256", OID({2,16,840,1,101,3,4,2,6}) }, + { "SHAKE-128", OID({2,16,840,1,101,3,4,2,11}) }, + { "SHAKE-256", OID({2,16,840,1,101,3,4,2,12}) }, + { "SM2_Enc", OID({1,2,156,10197,1,301,3}) }, + { "SM2_Kex", OID({1,2,156,10197,1,301,2}) }, + { "SM2_Sig", OID({1,2,156,10197,1,301,1}) }, + { "SM3", OID({1,2,156,10197,1,401}) }, + { "SM4/CBC", OID({1,2,156,10197,1,104,2}) }, + { "SM4/GCM", OID({1,2,156,10197,1,104,8}) }, + { "Scrypt", OID({1,3,6,1,4,1,11591,4,11}) }, + { "Serpent/CBC", OID({1,3,6,1,4,1,25258,3,1}) }, + { "Serpent/GCM", OID({1,3,6,1,4,1,25258,3,101}) }, + { "Serpent/OCB", OID({1,3,6,1,4,1,25258,3,2,4}) }, + { "Streebog-256", OID({1,2,643,7,1,1,2,2}) }, + { "Streebog-512", OID({1,2,643,7,1,1,2,3}) }, + { "Threefish-512/CBC", OID({1,3,6,1,4,1,25258,3,2}) }, + { "Tiger(24,3)", OID({1,3,6,1,4,1,11591,12,2}) }, + { "TripleDES/CBC", OID({1,2,840,113549,3,7}) }, + { "Twofish/CBC", OID({1,3,6,1,4,1,25258,3,3}) }, + { "Twofish/GCM", OID({1,3,6,1,4,1,25258,3,102}) }, + { "Twofish/OCB", OID({1,3,6,1,4,1,25258,3,2,5}) }, + { "X509v3.AnyPolicy", OID({2,5,29,32,0}) }, + { "X509v3.AuthorityKeyIdentifier", OID({2,5,29,35}) }, + { "X509v3.BasicConstraints", OID({2,5,29,19}) }, + { "X509v3.CRLDistributionPoints", OID({2,5,29,31}) }, + { "X509v3.CRLIssuingDistributionPoint", OID({2,5,29,28}) }, + { "X509v3.CRLNumber", OID({2,5,29,20}) }, + { "X509v3.CertificatePolicies", OID({2,5,29,32}) }, + { "X509v3.ExtendedKeyUsage", OID({2,5,29,37}) }, + { "X509v3.HoldInstructionCode", OID({2,5,29,23}) }, + { "X509v3.InvalidityDate", OID({2,5,29,24}) }, + { "X509v3.IssuerAlternativeName", OID({2,5,29,18}) }, + { "X509v3.KeyUsage", OID({2,5,29,15}) }, + { "X509v3.NameConstraints", OID({2,5,29,30}) }, + { "X509v3.PolicyConstraints", OID({2,5,29,36}) }, + { "X509v3.ReasonCode", OID({2,5,29,21}) }, + { "X509v3.SubjectAlternativeName", OID({2,5,29,17}) }, + { "X509v3.SubjectKeyIdentifier", OID({2,5,29,14}) }, + { "X520.CommonName", OID({2,5,4,3}) }, + { "X520.Country", OID({2,5,4,6}) }, + { "X520.DNQualifier", OID({2,5,4,46}) }, + { "X520.GenerationalQualifier", OID({2,5,4,44}) }, + { "X520.GivenName", OID({2,5,4,42}) }, + { "X520.Initials", OID({2,5,4,43}) }, + { "X520.Locality", OID({2,5,4,7}) }, + { "X520.Organization", OID({2,5,4,10}) }, + { "X520.OrganizationalUnit", OID({2,5,4,11}) }, + { "X520.Pseudonym", OID({2,5,4,65}) }, + { "X520.SerialNumber", OID({2,5,4,5}) }, + { "X520.State", OID({2,5,4,8}) }, + { "X520.Surname", OID({2,5,4,4}) }, + { "X520.Title", OID({2,5,4,12}) }, + { "XMSS", OID({1,3,6,1,4,1,25258,1,5}) }, + { "brainpool160r1", OID({1,3,36,3,3,2,8,1,1,1}) }, + { "brainpool192r1", OID({1,3,36,3,3,2,8,1,1,3}) }, + { "brainpool224r1", OID({1,3,36,3,3,2,8,1,1,5}) }, + { "brainpool256r1", OID({1,3,36,3,3,2,8,1,1,7}) }, + { "brainpool320r1", OID({1,3,36,3,3,2,8,1,1,9}) }, + { "brainpool384r1", OID({1,3,36,3,3,2,8,1,1,11}) }, + { "brainpool512r1", OID({1,3,36,3,3,2,8,1,1,13}) }, + { "frp256v1", OID({1,2,250,1,223,101,256,1}) }, + { "gost_256A", OID({1,2,643,2,2,35,1}) }, + { "secp160k1", OID({1,3,132,0,9}) }, + { "secp160r1", OID({1,3,132,0,8}) }, + { "secp160r2", OID({1,3,132,0,30}) }, + { "secp192k1", OID({1,3,132,0,31}) }, + { "secp192r1", OID({1,2,840,10045,3,1,1}) }, + { "secp224k1", OID({1,3,132,0,32}) }, + { "secp224r1", OID({1,3,132,0,33}) }, + { "secp256k1", OID({1,3,132,0,10}) }, + { "secp256r1", OID({1,2,840,10045,3,1,7}) }, + { "secp384r1", OID({1,3,132,0,34}) }, + { "secp521r1", OID({1,3,132,0,35}) }, + { "sm2p256v1", OID({1,2,156,10197,1,301}) }, + { "x962_p192v2", OID({1,2,840,10045,3,1,2}) }, + { "x962_p192v3", OID({1,2,840,10045,3,1,3}) }, + { "x962_p239v1", OID({1,2,840,10045,3,1,4}) }, + { "x962_p239v2", OID({1,2,840,10045,3,1,5}) }, + { "x962_p239v3", OID({1,2,840,10045,3,1,6}) } + }; + } + +} + diff --git a/src/libs/3rdparty/botan/src/lib/asn1/oids.cpp b/src/libs/3rdparty/botan/src/lib/asn1/oids.cpp new file mode 100644 index 0000000000..59ce08b357 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/oids.cpp @@ -0,0 +1,135 @@ +/* +* OID Registry +* (C) 1999-2008,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/oids.h> +#include <botan/mutex.h> + +namespace Botan { + +namespace OIDS { + +namespace { + +class OID_Map + { + public: + void add_oid(const OID& oid, const std::string& str) + { + add_str2oid(oid, str); + add_oid2str(oid, str); + } + + void add_str2oid(const OID& oid, const std::string& str) + { + lock_guard_type<mutex_type> lock(m_mutex); + auto i = m_str2oid.find(str); + if(i == m_str2oid.end()) + m_str2oid.insert(std::make_pair(str, oid.as_string())); + } + + void add_oid2str(const OID& oid, const std::string& str) + { + const std::string oid_str = oid.as_string(); + lock_guard_type<mutex_type> lock(m_mutex); + auto i = m_oid2str.find(oid_str); + if(i == m_oid2str.end()) + m_oid2str.insert(std::make_pair(oid_str, str)); + } + + std::string lookup(const OID& oid) + { + const std::string oid_str = oid.as_string(); + + lock_guard_type<mutex_type> lock(m_mutex); + + auto i = m_oid2str.find(oid_str); + if(i != m_oid2str.end()) + return i->second; + + return ""; + } + + OID lookup(const std::string& str) + { + lock_guard_type<mutex_type> lock(m_mutex); + auto i = m_str2oid.find(str); + if(i != m_str2oid.end()) + return i->second; + + return OID(); + } + + bool have_oid(const std::string& str) + { + lock_guard_type<mutex_type> lock(m_mutex); + return m_str2oid.find(str) != m_str2oid.end(); + } + + static OID_Map& global_registry() + { + static OID_Map g_map; + return g_map; + } + + private: + + OID_Map() + { + m_str2oid = load_str2oid_map(); + m_oid2str = load_oid2str_map(); + } + + mutex_type m_mutex; + std::unordered_map<std::string, OID> m_str2oid; + std::unordered_map<std::string, std::string> m_oid2str; + }; + +} + +void add_oid(const OID& oid, const std::string& name) + { + OID_Map::global_registry().add_oid(oid, name); + } + +void add_oidstr(const char* oidstr, const char* name) + { + add_oid(OID(oidstr), name); + } + +void add_oid2str(const OID& oid, const std::string& name) + { + OID_Map::global_registry().add_oid2str(oid, name); + } + +void add_str2oid(const OID& oid, const std::string& name) + { + OID_Map::global_registry().add_str2oid(oid, name); + } + +std::string lookup(const OID& oid) + { + return OID_Map::global_registry().lookup(oid); + } + +OID lookup(const std::string& name) + { + return OID_Map::global_registry().lookup(name); + } + +bool have_oid(const std::string& name) + { + return OID_Map::global_registry().have_oid(name); + } + +bool name_of(const OID& oid, const std::string& name) + { + return (oid == lookup(name)); + } + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/asn1/oids.h b/src/libs/3rdparty/botan/src/lib/asn1/oids.h new file mode 100644 index 0000000000..7b87b5eafe --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/asn1/oids.h @@ -0,0 +1,76 @@ +/* +* OID Registry +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OIDS_H_ +#define BOTAN_OIDS_H_ + +#include <botan/asn1_oid.h> +#include <unordered_map> + +namespace Botan { + +namespace OIDS { + +/** +* Register an OID to string mapping. +* @param oid the oid to register +* @param name the name to be associated with the oid +*/ +BOTAN_UNSTABLE_API void add_oid(const OID& oid, const std::string& name); + +BOTAN_UNSTABLE_API void add_oid2str(const OID& oid, const std::string& name); +BOTAN_UNSTABLE_API void add_str2oid(const OID& oid, const std::string& name); + +BOTAN_UNSTABLE_API void add_oidstr(const char* oidstr, const char* name); + +std::unordered_map<std::string, std::string> load_oid2str_map(); +std::unordered_map<std::string, OID> load_str2oid_map(); + +/** +* Resolve an OID +* @param oid the OID to look up +* @return name associated with this OID +*/ +BOTAN_PUBLIC_API(2,0) std::string lookup(const OID& oid); + +/** +* Find the OID to a name. The lookup will be performed in the +* general OID section of the configuration. +* @param name the name to resolve +* @return OID associated with the specified name +*/ +BOTAN_PUBLIC_API(2,0) OID lookup(const std::string& name); + +inline std::string oid2str(const OID& oid) + { + return lookup(oid); + } + +inline OID str2oid(const std::string& name) + { + return lookup(name); + } + +/** +* See if an OID exists in the internal table. +* @param oid the oid to check for +* @return true if the oid is registered +*/ +BOTAN_UNSTABLE_API bool have_oid(const std::string& oid); + +/** +* Tests whether the specified OID stands for the specified name. +* @param oid the OID to check +* @param name the name to check +* @return true if the specified OID stands for the specified name +*/ +BOTAN_UNSTABLE_API bool name_of(const OID& oid, const std::string& name); +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/base/botan.h b/src/libs/3rdparty/botan/src/lib/base/botan.h new file mode 100644 index 0000000000..26bfa75a79 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/botan.h @@ -0,0 +1,45 @@ +/* +* A vague catch all include file for Botan +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BOTAN_H_ +#define BOTAN_BOTAN_H_ + +/* +* There is no real reason for this header to exist beyond historical +* reasons. The application should instead include the specific header +* files that define the interfaces it intends to use. +* +* This header file will be removed in Botan 3.x +*/ + +#if defined(__GNUC__) + #warning "botan/botan.h is deprecated" +#elif defined(_MSC_VER) + #pragma message ("botan/botan.h is deprecated") +#endif + +#include <botan/lookup.h> +#include <botan/version.h> +#include <botan/parsing.h> +#include <botan/init.h> +#include <botan/rng.h> +#include <botan/secmem.h> + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + #include <botan/auto_rng.h> +#endif + +#if defined(BOTAN_HAS_FILTERS) + #include <botan/filters.h> +#endif + +#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) + #include <botan/x509_key.h> + #include <botan/pkcs8.h> +#endif + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/base/buf_comp.h b/src/libs/3rdparty/botan/src/lib/base/buf_comp.h new file mode 100644 index 0000000000..a6cc84ba35 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/buf_comp.h @@ -0,0 +1,184 @@ +/* +* Buffered Computation +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BUFFERED_COMPUTATION_H_ +#define BOTAN_BUFFERED_COMPUTATION_H_ + +#include <botan/secmem.h> +#include <botan/loadstor.h> +#include <string> + +namespace Botan { + +/** +* This class represents any kind of computation which uses an internal +* state, such as hash functions or MACs +*/ +class BOTAN_PUBLIC_API(2,0) Buffered_Computation + { + public: + /** + * @return length of the output of this function in bytes + */ + virtual size_t output_length() const = 0; + + /** + * Add new input to process. + * @param in the input to process as a byte array + * @param length of param in in bytes + */ + void update(const uint8_t in[], size_t length) { add_data(in, length); } + + /** + * Add new input to process. + * @param in the input to process as a secure_vector + */ + void update(const secure_vector<uint8_t>& in) + { + add_data(in.data(), in.size()); + } + + /** + * Add new input to process. + * @param in the input to process as a std::vector + */ + void update(const std::vector<uint8_t>& in) + { + add_data(in.data(), in.size()); + } + + /** + * Add an integer in big-endian order + * @param in the value + */ + template<typename T> void update_be(const T in) + { + for(size_t i = 0; i != sizeof(T); ++i) + { + uint8_t b = get_byte(i, in); + add_data(&b, 1); + } + } + + /** + * Add new input to process. + * @param str the input to process as a std::string. Will be interpreted + * as a byte array based on the strings encoding. + */ + void update(const std::string& str) + { + add_data(cast_char_ptr_to_uint8(str.data()), str.size()); + } + + /** + * Process a single byte. + * @param in the byte to process + */ + void update(uint8_t in) { add_data(&in, 1); } + + /** + * Complete the computation and retrieve the + * final result. + * @param out The byte array to be filled with the result. + * Must be of length output_length() + */ + void final(uint8_t out[]) { final_result(out); } + + /** + * Complete the computation and retrieve the + * final result. + * @return secure_vector holding the result + */ + secure_vector<uint8_t> final() + { + secure_vector<uint8_t> output(output_length()); + final_result(output.data()); + return output; + } + + std::vector<uint8_t> final_stdvec() + { + std::vector<uint8_t> output(output_length()); + final_result(output.data()); + return output; + } + + template<typename Alloc> + void final(std::vector<uint8_t, Alloc>& out) + { + out.resize(output_length()); + final_result(out.data()); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process as a byte array + * @param length the length of the byte array + * @result the result of the call to final() + */ + secure_vector<uint8_t> process(const uint8_t in[], size_t length) + { + add_data(in, length); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process + * @result the result of the call to final() + */ + secure_vector<uint8_t> process(const secure_vector<uint8_t>& in) + { + add_data(in.data(), in.size()); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process + * @result the result of the call to final() + */ + secure_vector<uint8_t> process(const std::vector<uint8_t>& in) + { + add_data(in.data(), in.size()); + return final(); + } + + /** + * Update and finalize computation. Does the same as calling update() + * and final() consecutively. + * @param in the input to process as a string + * @result the result of the call to final() + */ + secure_vector<uint8_t> process(const std::string& in) + { + update(in); + return final(); + } + + virtual ~Buffered_Computation() = default; + private: + /** + * Add more data to the computation + * @param input is an input buffer + * @param length is the length of input in bytes + */ + virtual void add_data(const uint8_t input[], size_t length) = 0; + + /** + * Write the final output to out + * @param out is an output buffer of output_length() + */ + virtual void final_result(uint8_t out[]) = 0; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/base/info.txt b/src/libs/3rdparty/botan/src/lib/base/info.txt new file mode 100644 index 0000000000..fd3f7b8905 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/info.txt @@ -0,0 +1,17 @@ +<header:public> +botan.h +buf_comp.h +init.h +key_spec.h +lookup.h +secmem.h +scan_name.h +sym_algo.h +symkey.h +</header:public> + +<requires> +hex +rng +utils +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/base/init.h b/src/libs/3rdparty/botan/src/lib/base/init.h new file mode 100644 index 0000000000..ba014d8e1d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/init.h @@ -0,0 +1,33 @@ +/* +* Library Initialization +* (C) 1999-2008,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_LIBRARY_INITIALIZER_H_ +#define BOTAN_LIBRARY_INITIALIZER_H_ + +#include <botan/types.h> +#include <string> + +namespace Botan { + +/* +* Previously botan had state whose lifetime had to be explicitly +* managed by the application. As of 1.11.14 this is no longer the +* case, and this class is no longer needed and kept only for backwards +* compatibility. +*/ +class BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("LibraryInitializer is no longer required") LibraryInitializer final + { + public: + explicit LibraryInitializer(const std::string& /*ignored*/ = "") { } + + static void initialize(const std::string& /*ignored*/ = "") {} + static void deinitialize() {} + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/base/key_spec.h b/src/libs/3rdparty/botan/src/lib/base/key_spec.h new file mode 100644 index 0000000000..6db20a9b63 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/key_spec.h @@ -0,0 +1,100 @@ +/* +* Symmetric Key Length Specification +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KEY_LEN_SPECIFICATION_H_ +#define BOTAN_KEY_LEN_SPECIFICATION_H_ + +#include <botan/types.h> + +namespace Botan { + +/** +* Represents the length requirements on an algorithm key +*/ +class BOTAN_PUBLIC_API(2,0) Key_Length_Specification final + { + public: + /** + * Constructor for fixed length keys + * @param keylen the supported key length + */ + explicit Key_Length_Specification(size_t keylen) : + m_min_keylen(keylen), + m_max_keylen(keylen), + m_keylen_mod(1) + { + } + + /** + * Constructor for variable length keys + * @param min_k the smallest supported key length + * @param max_k the largest supported key length + * @param k_mod the number of bytes the key must be a multiple of + */ + Key_Length_Specification(size_t min_k, + size_t max_k, + size_t k_mod = 1) : + m_min_keylen(min_k), + m_max_keylen(max_k ? max_k : min_k), + m_keylen_mod(k_mod) + { + } + + /** + * @param length is a key length in bytes + * @return true iff this length is a valid length for this algo + */ + bool valid_keylength(size_t length) const + { + return ((length >= m_min_keylen) && + (length <= m_max_keylen) && + (length % m_keylen_mod == 0)); + } + + /** + * @return minimum key length in bytes + */ + size_t minimum_keylength() const + { + return m_min_keylen; + } + + /** + * @return maximum key length in bytes + */ + size_t maximum_keylength() const + { + return m_max_keylen; + } + + /** + * @return key length multiple in bytes + */ + size_t keylength_multiple() const + { + return m_keylen_mod; + } + + /* + * Multiplies all length requirements with the given factor + * @param n the multiplication factor + * @return a key length specification multiplied by the factor + */ + Key_Length_Specification multiple(size_t n) const + { + return Key_Length_Specification(n * m_min_keylen, + n * m_max_keylen, + n * m_keylen_mod); + } + + private: + size_t m_min_keylen, m_max_keylen, m_keylen_mod; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/base/lookup.h b/src/libs/3rdparty/botan/src/lib/base/lookup.h new file mode 100644 index 0000000000..1cfa7d3c9c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/lookup.h @@ -0,0 +1,177 @@ +/* +* Algorithm Lookup +* (C) 1999-2007,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_LOOKUP_H_ +#define BOTAN_LOOKUP_H_ + +#include <botan/build.h> +#include <botan/exceptn.h> +#include <string> +#include <vector> +#include <memory> + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + #include <botan/block_cipher.h> +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + #include <botan/stream_cipher.h> +#endif + +#if defined(BOTAN_HAS_HASH) + #include <botan/hash.h> +#endif + +#if defined(BOTAN_HAS_MAC) + #include <botan/mac.h> +#endif + +namespace Botan { + +/* +* As of 1.11.26 this header is deprecated. Instead use the calls T::create and +* T::providers (as demonstrated in the implementation below). +*/ + +/* +* Get an algorithm object +* NOTE: these functions create and return new objects, letting the +* caller assume ownership of them +*/ + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + +/** +* Block cipher factory method. +* +* @param algo_spec the name of the desired block cipher +* @param provider the provider to use +* @return pointer to the block cipher object +*/ +BOTAN_DEPRECATED("Use BlockCipher::create") +inline BlockCipher* get_block_cipher(const std::string& algo_spec, + const std::string& provider = "") + { + return BlockCipher::create(algo_spec, provider).release(); + } + +BOTAN_DEPRECATED("Use BlockCipher::create_or_throw") +inline std::unique_ptr<BlockCipher> make_block_cipher(const std::string& algo_spec, + const std::string& provider = "") + { + return BlockCipher::create_or_throw(algo_spec, provider); + } + +BOTAN_DEPRECATED("Use BlockCipher::providers") +inline std::vector<std::string> get_block_cipher_providers(const std::string& algo_spec) + { + return BlockCipher::providers(algo_spec); + } + +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + +/** +* Stream cipher factory method. +* +* @param algo_spec the name of the desired stream cipher +* @param provider the provider to use +* @return pointer to the stream cipher object +*/ +BOTAN_DEPRECATED("Use StreamCipher::create") +inline StreamCipher* get_stream_cipher(const std::string& algo_spec, + const std::string& provider = "") + { + return StreamCipher::create(algo_spec, provider).release(); + } + +BOTAN_DEPRECATED("Use StreamCipher::create_or_throw") +inline std::unique_ptr<StreamCipher> make_stream_cipher(const std::string& algo_spec, + const std::string& provider = "") + { + return StreamCipher::create_or_throw(algo_spec, provider); + } + +BOTAN_DEPRECATED("Use StreamCipher::providers") +inline std::vector<std::string> get_stream_cipher_providers(const std::string& algo_spec) + { + return StreamCipher::providers(algo_spec); + } + +#endif + +#if defined(BOTAN_HAS_HASH) + +/** +* Hash function factory method. +* +* @param algo_spec the name of the desired hash function +* @param provider the provider to use +* @return pointer to the hash function object +*/ +BOTAN_DEPRECATED("Use HashFunction::create") +inline HashFunction* get_hash_function(const std::string& algo_spec, + const std::string& provider = "") + { + return HashFunction::create(algo_spec, provider).release(); + } + +BOTAN_DEPRECATED("Use HashFunction::create_or_throw") +inline std::unique_ptr<HashFunction> make_hash_function(const std::string& algo_spec, + const std::string& provider = "") + { + return HashFunction::create_or_throw(algo_spec, provider); + } + +BOTAN_DEPRECATED("Use HashFunction::create") +inline HashFunction* get_hash(const std::string& algo_spec, + const std::string& provider = "") + { + return HashFunction::create(algo_spec, provider).release(); + } + +BOTAN_DEPRECATED("Use HashFunction::providers") +inline std::vector<std::string> get_hash_function_providers(const std::string& algo_spec) + { + return HashFunction::providers(algo_spec); + } + +#endif + +#if defined(BOTAN_HAS_MAC) +/** +* MAC factory method. +* +* @param algo_spec the name of the desired MAC +* @param provider the provider to use +* @return pointer to the MAC object +*/ +BOTAN_DEPRECATED("MessageAuthenticationCode::create") +inline MessageAuthenticationCode* get_mac(const std::string& algo_spec, + const std::string& provider = "") + { + return MessageAuthenticationCode::create(algo_spec, provider).release(); + } + +BOTAN_DEPRECATED("MessageAuthenticationCode::create_or_throw") +inline std::unique_ptr<MessageAuthenticationCode> make_message_auth(const std::string& algo_spec, + const std::string& provider = "") + { + return MessageAuthenticationCode::create(algo_spec, provider); + } + +BOTAN_DEPRECATED("MessageAuthenticationCode::providers") +inline std::vector<std::string> get_mac_providers(const std::string& algo_spec) + { + return MessageAuthenticationCode::providers(algo_spec); + } +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/base/scan_name.cpp b/src/libs/3rdparty/botan/src/lib/base/scan_name.cpp new file mode 100644 index 0000000000..70c6e7f25c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/scan_name.cpp @@ -0,0 +1,144 @@ +/* +* SCAN Name Abstraction +* (C) 2008-2009,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/scan_name.h> +#include <botan/parsing.h> +#include <botan/exceptn.h> + +namespace Botan { + +namespace { + +std::string make_arg( + const std::vector<std::pair<size_t, std::string> >& name, size_t start) + { + std::string output = name[start].second; + size_t level = name[start].first; + + size_t paren_depth = 0; + + for(size_t i = start + 1; i != name.size(); ++i) + { + if(name[i].first <= name[start].first) + break; + + if(name[i].first > level) + { + output += "(" + name[i].second; + ++paren_depth; + } + else if(name[i].first < level) + { + output += ")," + name[i].second; + --paren_depth; + } + else + { + if(output[output.size() - 1] != '(') + output += ","; + output += name[i].second; + } + + level = name[i].first; + } + + for(size_t i = 0; i != paren_depth; ++i) + output += ")"; + + return output; + } + +} + +SCAN_Name::SCAN_Name(const char* algo_spec) : SCAN_Name(std::string(algo_spec)) + { + } + +SCAN_Name::SCAN_Name(std::string algo_spec) : m_orig_algo_spec(algo_spec), m_alg_name(), m_args(), m_mode_info() + { + std::vector<std::pair<size_t, std::string> > name; + size_t level = 0; + std::pair<size_t, std::string> accum = std::make_pair(level, ""); + + const std::string decoding_error = "Bad SCAN name '" + algo_spec + "': "; + + for(size_t i = 0; i != algo_spec.size(); ++i) + { + char c = algo_spec[i]; + + if(c == '/' || c == ',' || c == '(' || c == ')') + { + if(c == '(') + ++level; + else if(c == ')') + { + if(level == 0) + throw Decoding_Error(decoding_error + "Mismatched parens"); + --level; + } + + if(c == '/' && level > 0) + accum.second.push_back(c); + else + { + if(accum.second != "") + name.push_back(accum); + accum = std::make_pair(level, ""); + } + } + else + accum.second.push_back(c); + } + + if(accum.second != "") + name.push_back(accum); + + if(level != 0) + throw Decoding_Error(decoding_error + "Missing close paren"); + + if(name.size() == 0) + throw Decoding_Error(decoding_error + "Empty name"); + + m_alg_name = name[0].second; + + bool in_modes = false; + + for(size_t i = 1; i != name.size(); ++i) + { + if(name[i].first == 0) + { + m_mode_info.push_back(make_arg(name, i)); + in_modes = true; + } + else if(name[i].first == 1 && !in_modes) + m_args.push_back(make_arg(name, i)); + } + } + +std::string SCAN_Name::arg(size_t i) const + { + if(i >= arg_count()) + throw Invalid_Argument("SCAN_Name::arg " + std::to_string(i) + + " out of range for '" + as_string() + "'"); + return m_args[i]; + } + +std::string SCAN_Name::arg(size_t i, const std::string& def_value) const + { + if(i >= arg_count()) + return def_value; + return m_args[i]; + } + +size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const + { + if(i >= arg_count()) + return def_value; + return to_u32bit(m_args[i]); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/base/scan_name.h b/src/libs/3rdparty/botan/src/lib/base/scan_name.h new file mode 100644 index 0000000000..8aa45f50f0 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/scan_name.h @@ -0,0 +1,117 @@ +/* +* SCAN Name Abstraction +* (C) 2008,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SCAN_NAME_H_ +#define BOTAN_SCAN_NAME_H_ + +#include <botan/types.h> +#include <string> +#include <vector> + +namespace Botan { + +/** +A class encapsulating a SCAN name (similar to JCE conventions) +http://www.users.zetnet.co.uk/hopwood/crypto/scan/ +*/ +class BOTAN_PUBLIC_API(2,0) SCAN_Name final + { + public: + /** + * Create a SCAN_Name + * @param algo_spec A SCAN-format name + */ + explicit SCAN_Name(const char* algo_spec); + + /** + * Create a SCAN_Name + * @param algo_spec A SCAN-format name + */ + explicit SCAN_Name(std::string algo_spec); + + /** + * @return original input string + */ + const std::string& as_string() const { return m_orig_algo_spec; } + + /** + * @return algorithm name + */ + const std::string& algo_name() const { return m_alg_name; } + + /** + * @return number of arguments + */ + size_t arg_count() const { return m_args.size(); } + + /** + * @param lower is the lower bound + * @param upper is the upper bound + * @return if the number of arguments is between lower and upper + */ + bool arg_count_between(size_t lower, size_t upper) const + { return ((arg_count() >= lower) && (arg_count() <= upper)); } + + /** + * @param i which argument + * @return ith argument + */ + std::string arg(size_t i) const; + + /** + * @param i which argument + * @param def_value the default value + * @return ith argument or the default value + */ + std::string arg(size_t i, const std::string& def_value) const; + + /** + * @param i which argument + * @param def_value the default value + * @return ith argument as an integer, or the default value + */ + size_t arg_as_integer(size_t i, size_t def_value) const; + + /** + * @return cipher mode (if any) + */ + std::string cipher_mode() const + { return (m_mode_info.size() >= 1) ? m_mode_info[0] : ""; } + + /** + * @return cipher mode padding (if any) + */ + std::string cipher_mode_pad() const + { return (m_mode_info.size() >= 2) ? m_mode_info[1] : ""; } + + private: + std::string m_orig_algo_spec; + std::string m_alg_name; + std::vector<std::string> m_args; + std::vector<std::string> m_mode_info; + }; + +// This is unrelated but it is convenient to stash it here +template<typename T> +std::vector<std::string> probe_providers_of(const std::string& algo_spec, + const std::vector<std::string>& possible) + { + std::vector<std::string> providers; + for(auto&& prov : possible) + { + std::unique_ptr<T> o(T::create(algo_spec, prov)); + if(o) + { + providers.push_back(prov); // available + } + } + return providers; + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/base/secmem.h b/src/libs/3rdparty/botan/src/lib/base/secmem.h new file mode 100644 index 0000000000..12ea55a3b6 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/secmem.h @@ -0,0 +1,202 @@ +/* +* Secure Memory Buffers +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SECURE_MEMORY_BUFFERS_H_ +#define BOTAN_SECURE_MEMORY_BUFFERS_H_ + +#include <botan/types.h> // IWYU pragma: export +#include <botan/mem_ops.h> // IWYU pragma: export +#include <vector> // IWYU pragma: export +#include <algorithm> +#include <deque> +#include <type_traits> + +namespace Botan { + +template<typename T> +class secure_allocator + { + public: + /* + * Assert exists to prevent someone from doing something that will + * probably crash anyway (like secure_vector<non_POD_t> where ~non_POD_t + * deletes a member pointer which was zeroed before it ran). + * MSVC in debug mode uses non-integral proxy types in container types + * like std::vector, thus we disable the check there. + */ +#if !defined(_ITERATOR_DEBUG_LEVEL) || _ITERATOR_DEBUG_LEVEL == 0 + static_assert(std::is_integral<T>::value, "secure_allocator supports only integer types"); +#endif + + typedef T value_type; + typedef std::size_t size_type; + +#ifdef BOTAN_BUILD_COMPILER_IS_MSVC_2013 + secure_allocator() = default; + secure_allocator(const secure_allocator&) = default; + secure_allocator& operator=(const secure_allocator&) = default; + ~secure_allocator() = default; + + template <typename U> + struct rebind + { + typedef secure_allocator<U> other; + }; + + void construct(value_type* mem, const value_type& value) + { + std::_Construct(mem, value); + } + + void destroy(value_type* mem) + { + std::_Destroy(mem); + } +#else + secure_allocator() BOTAN_NOEXCEPT = default; + secure_allocator(const secure_allocator&) BOTAN_NOEXCEPT = default; + secure_allocator& operator=(const secure_allocator&) BOTAN_NOEXCEPT = default; + ~secure_allocator() BOTAN_NOEXCEPT = default; +#endif + + template<typename U> + secure_allocator(const secure_allocator<U>&) BOTAN_NOEXCEPT {} + + T* allocate(std::size_t n) + { + return static_cast<T*>(allocate_memory(n, sizeof(T))); + } + + void deallocate(T* p, std::size_t n) + { + deallocate_memory(p, n, sizeof(T)); + } + }; + +template<typename T, typename U> inline bool +operator==(const secure_allocator<T>&, const secure_allocator<U>&) + { return true; } + +template<typename T, typename U> inline bool +operator!=(const secure_allocator<T>&, const secure_allocator<U>&) + { return false; } + +template<typename T> using secure_vector = std::vector<T, secure_allocator<T>>; +template<typename T> using secure_deque = std::deque<T, secure_allocator<T>>; + +// For better compatability with 1.10 API +template<typename T> using SecureVector = secure_vector<T>; + +template<typename T> +std::vector<T> unlock(const secure_vector<T>& in) + { + std::vector<T> out(in.size()); + copy_mem(out.data(), in.data(), in.size()); + return out; + } + +template<typename T, typename Alloc> +size_t buffer_insert(std::vector<T, Alloc>& buf, + size_t buf_offset, + const T input[], + size_t input_length) + { + BOTAN_ASSERT_NOMSG(buf_offset <= buf.size()); + const size_t to_copy = std::min(input_length, buf.size() - buf_offset); + if(to_copy > 0) + { + copy_mem(&buf[buf_offset], input, to_copy); + } + return to_copy; + } + +template<typename T, typename Alloc, typename Alloc2> +size_t buffer_insert(std::vector<T, Alloc>& buf, + size_t buf_offset, + const std::vector<T, Alloc2>& input) + { + BOTAN_ASSERT_NOMSG(buf_offset <= buf.size()); + const size_t to_copy = std::min(input.size(), buf.size() - buf_offset); + if(to_copy > 0) + { + copy_mem(&buf[buf_offset], input.data(), to_copy); + } + return to_copy; + } + +template<typename T, typename Alloc, typename Alloc2> +std::vector<T, Alloc>& +operator+=(std::vector<T, Alloc>& out, + const std::vector<T, Alloc2>& in) + { + const size_t copy_offset = out.size(); + out.resize(out.size() + in.size()); + if(in.size() > 0) + { + copy_mem(&out[copy_offset], in.data(), in.size()); + } + return out; + } + +template<typename T, typename Alloc> +std::vector<T, Alloc>& operator+=(std::vector<T, Alloc>& out, T in) + { + out.push_back(in); + return out; + } + +template<typename T, typename Alloc, typename L> +std::vector<T, Alloc>& operator+=(std::vector<T, Alloc>& out, + const std::pair<const T*, L>& in) + { + const size_t copy_offset = out.size(); + out.resize(out.size() + in.second); + if(in.second > 0) + { + copy_mem(&out[copy_offset], in.first, in.second); + } + return out; + } + +template<typename T, typename Alloc, typename L> +std::vector<T, Alloc>& operator+=(std::vector<T, Alloc>& out, + const std::pair<T*, L>& in) + { + const size_t copy_offset = out.size(); + out.resize(out.size() + in.second); + if(in.second > 0) + { + copy_mem(&out[copy_offset], in.first, in.second); + } + return out; + } + +/** +* Zeroise the values; length remains unchanged +* @param vec the vector to zeroise +*/ +template<typename T, typename Alloc> +void zeroise(std::vector<T, Alloc>& vec) + { + clear_mem(vec.data(), vec.size()); + } + +/** +* Zeroise the values then free the memory +* @param vec the vector to zeroise and free +*/ +template<typename T, typename Alloc> +void zap(std::vector<T, Alloc>& vec) + { + zeroise(vec); + vec.clear(); + vec.shrink_to_fit(); + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/base/sym_algo.cpp b/src/libs/3rdparty/botan/src/lib/base/sym_algo.cpp new file mode 100644 index 0000000000..fff4afbd14 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/sym_algo.cpp @@ -0,0 +1,24 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sym_algo.h> +#include <botan/exceptn.h> + +namespace Botan { + +void SymmetricAlgorithm::throw_key_not_set_error() const + { + throw Key_Not_Set(name()); + } + +void SymmetricAlgorithm::set_key(const uint8_t key[], size_t length) + { + if(!valid_keylength(length)) + throw Invalid_Key_Length(name(), length); + key_schedule(key, length); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/base/sym_algo.h b/src/libs/3rdparty/botan/src/lib/base/sym_algo.h new file mode 100644 index 0000000000..e69d4f81eb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/sym_algo.h @@ -0,0 +1,108 @@ +/* +* Symmetric Algorithm Base Class +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SYMMETRIC_ALGORITHM_H_ +#define BOTAN_SYMMETRIC_ALGORITHM_H_ + +#include <botan/key_spec.h> +#include <botan/symkey.h> +#include <botan/types.h> + +namespace Botan { + +/** +* This class represents a symmetric algorithm object. +*/ +class BOTAN_PUBLIC_API(2,0) SymmetricAlgorithm + { + public: + virtual ~SymmetricAlgorithm() = default; + + /** + * Reset the state. + */ + virtual void clear() = 0; + + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * @return minimum allowed key length + */ + size_t maximum_keylength() const + { + return key_spec().maximum_keylength(); + } + + /** + * @return maximum allowed key length + */ + size_t minimum_keylength() const + { + return key_spec().minimum_keylength(); + } + + /** + * Check whether a given key length is valid for this algorithm. + * @param length the key length to be checked. + * @return true if the key length is valid. + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + /** + * Set the symmetric key of this object. + * @param key the SymmetricKey to be set. + */ + void set_key(const SymmetricKey& key) + { + set_key(key.begin(), key.length()); + } + + template<typename Alloc> + void set_key(const std::vector<uint8_t, Alloc>& key) + { + set_key(key.data(), key.size()); + } + + /** + * Set the symmetric key of this object. + * @param key the to be set as a byte array. + * @param length in bytes of key param + */ + void set_key(const uint8_t key[], size_t length); + + /** + * @return the algorithm name + */ + virtual std::string name() const = 0; + + protected: + void verify_key_set(bool cond) const + { + if(cond == false) + throw_key_not_set_error(); + } + + private: + void throw_key_not_set_error() const; + + /** + * Run the key schedule + * @param key the key + * @param length of key + */ + virtual void key_schedule(const uint8_t key[], size_t length) = 0; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/base/symkey.cpp b/src/libs/3rdparty/botan/src/lib/base/symkey.cpp new file mode 100644 index 0000000000..a012773ff3 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/symkey.cpp @@ -0,0 +1,131 @@ +/* +* OctetString +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/symkey.h> +#include <botan/rng.h> +#include <botan/hex.h> +#include <algorithm> + +namespace Botan { + +/* +* Create an OctetString from RNG output +*/ +OctetString::OctetString(RandomNumberGenerator& rng, + size_t len) + { + m_data = rng.random_vec(len); + } + +/* +* Create an OctetString from a hex string +*/ +OctetString::OctetString(const std::string& hex_string) + { + m_data.resize(1 + hex_string.length() / 2); + m_data.resize(hex_decode(m_data.data(), hex_string)); + } + +/* +* Create an OctetString from a byte string +*/ +OctetString::OctetString(const uint8_t in[], size_t n) + { + m_data.assign(in, in + n); + } + +/* +* Set the parity of each key byte to odd +*/ +void OctetString::set_odd_parity() + { + const uint8_t ODD_PARITY[256] = { + 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, + 0x0D, 0x0D, 0x0E, 0x0E, 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, + 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, 0x20, 0x20, 0x23, 0x23, + 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, + 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B, + 0x3D, 0x3D, 0x3E, 0x3E, 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, + 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, 0x51, 0x51, 0x52, 0x52, + 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, + 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B, + 0x6D, 0x6D, 0x6E, 0x6E, 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, + 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, 0x80, 0x80, 0x83, 0x83, + 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, + 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B, + 0x9D, 0x9D, 0x9E, 0x9E, 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, + 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, 0xB0, 0xB0, 0xB3, 0xB3, + 0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, + 0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB, + 0xCD, 0xCD, 0xCE, 0xCE, 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, + 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, 0xE0, 0xE0, 0xE3, 0xE3, + 0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, + 0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB, + 0xFD, 0xFD, 0xFE, 0xFE }; + + for(size_t j = 0; j != m_data.size(); ++j) + m_data[j] = ODD_PARITY[m_data[j]]; + } + +/* +* Hex encode an OctetString +*/ +std::string OctetString::as_string() const + { + return hex_encode(m_data.data(), m_data.size()); + } + +/* +* XOR Operation for OctetStrings +*/ +OctetString& OctetString::operator^=(const OctetString& k) + { + if(&k == this) { zeroise(m_data); return (*this); } + xor_buf(m_data.data(), k.begin(), std::min(length(), k.length())); + return (*this); + } + +/* +* Equality Operation for OctetStrings +*/ +bool operator==(const OctetString& s1, const OctetString& s2) + { + return (s1.bits_of() == s2.bits_of()); + } + +/* +* Unequality Operation for OctetStrings +*/ +bool operator!=(const OctetString& s1, const OctetString& s2) + { + return !(s1 == s2); + } + +/* +* Append Operation for OctetStrings +*/ +OctetString operator+(const OctetString& k1, const OctetString& k2) + { + secure_vector<uint8_t> out; + out += k1.bits_of(); + out += k2.bits_of(); + return OctetString(out); + } + +/* +* XOR Operation for OctetStrings +*/ +OctetString operator^(const OctetString& k1, const OctetString& k2) + { + secure_vector<uint8_t> out(std::max(k1.length(), k2.length())); + + copy_mem(out.data(), k1.begin(), k1.length()); + xor_buf(out.data(), k2.begin(), k2.length()); + return OctetString(out); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/base/symkey.h b/src/libs/3rdparty/botan/src/lib/base/symkey.h new file mode 100644 index 0000000000..a010cc4664 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/base/symkey.h @@ -0,0 +1,145 @@ +/* +* OctetString +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SYMKEY_H_ +#define BOTAN_SYMKEY_H_ + +#include <botan/secmem.h> +#include <string> + +namespace Botan { + +/** +* Octet String +*/ +class BOTAN_PUBLIC_API(2,0) OctetString final + { + public: + /** + * @return size of this octet string in bytes + */ + size_t length() const { return m_data.size(); } + size_t size() const { return m_data.size(); } + + /** + * @return this object as a secure_vector<uint8_t> + */ + secure_vector<uint8_t> bits_of() const { return m_data; } + + /** + * @return start of this string + */ + const uint8_t* begin() const { return m_data.data(); } + + /** + * @return end of this string + */ + const uint8_t* end() const { return begin() + m_data.size(); } + + /** + * @return this encoded as hex + */ + std::string as_string() const; + + /** + * XOR the contents of another octet string into this one + * @param other octet string + * @return reference to this + */ + OctetString& operator^=(const OctetString& other); + + /** + * Force to have odd parity + */ + void set_odd_parity(); + + /** + * Create a new OctetString + * @param str is a hex encoded string + */ + explicit OctetString(const std::string& str = ""); + + /** + * Create a new random OctetString + * @param rng is a random number generator + * @param len is the desired length in bytes + */ + OctetString(class RandomNumberGenerator& rng, size_t len); + + /** + * Create a new OctetString + * @param in is an array + * @param len is the length of in in bytes + */ + OctetString(const uint8_t in[], size_t len); + + /** + * Create a new OctetString + * @param in a bytestring + */ + OctetString(const secure_vector<uint8_t>& in) : m_data(in) {} + + /** + * Create a new OctetString + * @param in a bytestring + */ + OctetString(const std::vector<uint8_t>& in) : m_data(in.begin(), in.end()) {} + + private: + secure_vector<uint8_t> m_data; + }; + +/** +* Compare two strings +* @param x an octet string +* @param y an octet string +* @return if x is equal to y +*/ +BOTAN_PUBLIC_API(2,0) bool operator==(const OctetString& x, + const OctetString& y); + +/** +* Compare two strings +* @param x an octet string +* @param y an octet string +* @return if x is not equal to y +*/ +BOTAN_PUBLIC_API(2,0) bool operator!=(const OctetString& x, + const OctetString& y); + +/** +* Concatenate two strings +* @param x an octet string +* @param y an octet string +* @return x concatenated with y +*/ +BOTAN_PUBLIC_API(2,0) OctetString operator+(const OctetString& x, + const OctetString& y); + +/** +* XOR two strings +* @param x an octet string +* @param y an octet string +* @return x XORed with y +*/ +BOTAN_PUBLIC_API(2,0) OctetString operator^(const OctetString& x, + const OctetString& y); + + +/** +* Alternate name for octet string showing intent to use as a key +*/ +using SymmetricKey = OctetString; + +/** +* Alternate name for octet string showing intent to use as an IV +*/ +using InitializationVector = OctetString; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/aes.cpp b/src/libs/3rdparty/botan/src/lib/block/aes/aes.cpp new file mode 100644 index 0000000000..403945cc91 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/aes.cpp @@ -0,0 +1,750 @@ +/* +* AES +* (C) 1999-2010,2015,2017 Jack Lloyd +* +* Based on the public domain reference implementation by Paulo Baretto +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/aes.h> +#include <botan/loadstor.h> +#include <botan/cpuid.h> +#include <type_traits> + +/* +* This implementation is based on table lookups which are known to be +* vulnerable to timing and cache based side channel attacks. Some +* countermeasures are used which may be helpful in some situations: +* +* - Only a single 256-word T-table is used, with rotations applied. +* Most implementations use 4 T-tables which leaks much more +* information via cache usage. +* +* - The TE and TD tables are computed at runtime to avoid flush+reload +* attacks using clflush. As different processes will not share the +* same underlying table data, an attacker can't manipulate another +* processes cache lines via their shared reference to the library +* read only segment. +* +* - Each cache line of the lookup tables is accessed at the beginning +* of each call to encrypt or decrypt. (See the Z variable below) +* +* If available SSSE3 or AES-NI are used instead of this version, as both +* are faster and immune to side channel attacks. +* +* Some AES cache timing papers for reference: +* +* "Software mitigations to hedge AES against cache-based software side +* channel vulnerabilities" https://eprint.iacr.org/2006/052.pdf +* +* "Cache Games - Bringing Access-Based Cache Attacks on AES to Practice" +* http://www.ieee-security.org/TC/SP2011/PAPERS/2011/paper031.pdf +* +* "Cache-Collision Timing Attacks Against AES" Bonneau, Mironov +* http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.88.4753 +*/ + +namespace Botan { + +namespace { + +BOTAN_ALIGNAS(64) +const uint8_t SE[256] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, + 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, + 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, + 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, + 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, + 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, + 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, + 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, + 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, + 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, + 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, + 0xB0, 0x54, 0xBB, 0x16 }; + +BOTAN_ALIGNAS(64) +const uint8_t SD[256] = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, + 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, + 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, + 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, + 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, + 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, + 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, + 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, + 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, + 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0C, 0x7D }; + +inline uint8_t xtime(uint8_t s) { return static_cast<uint8_t>(s << 1) ^ ((s >> 7) * 0x1B); } +inline uint8_t xtime4(uint8_t s) { return xtime(xtime(s)); } +inline uint8_t xtime8(uint8_t s) { return xtime(xtime(xtime(s))); } + +inline uint8_t xtime3(uint8_t s) { return xtime(s) ^ s; } +inline uint8_t xtime9(uint8_t s) { return xtime8(s) ^ s; } +inline uint8_t xtime11(uint8_t s) { return xtime8(s) ^ xtime(s) ^ s; } +inline uint8_t xtime13(uint8_t s) { return xtime8(s) ^ xtime4(s) ^ s; } +inline uint8_t xtime14(uint8_t s) { return xtime8(s) ^ xtime4(s) ^ xtime(s); } + +inline uint32_t SE_word(uint32_t x) + { + return make_uint32(SE[get_byte(0, x)], + SE[get_byte(1, x)], + SE[get_byte(2, x)], + SE[get_byte(3, x)]); + } + +const uint32_t* AES_TE() + { + class TE_Table final + { + public: + TE_Table() + { + uint32_t* p = reinterpret_cast<uint32_t*>(&data); + for(size_t i = 0; i != 256; ++i) + { + const uint8_t s = SE[i]; + p[i] = make_uint32(xtime(s), s, s, xtime3(s)); + } + } + + const uint32_t* ptr() const + { + return reinterpret_cast<const uint32_t*>(&data); + } + private: + std::aligned_storage<256*sizeof(uint32_t), 64>::type data; + }; + + static TE_Table table; + return table.ptr(); + } + +const uint32_t* AES_TD() + { + class TD_Table final + { + public: + TD_Table() + { + uint32_t* p = reinterpret_cast<uint32_t*>(&data); + for(size_t i = 0; i != 256; ++i) + { + const uint8_t s = SD[i]; + p[i] = make_uint32(xtime14(s), xtime9(s), xtime13(s), xtime11(s)); + } + } + + const uint32_t* ptr() const + { + return reinterpret_cast<const uint32_t*>(&data); + } + private: + std::aligned_storage<256*sizeof(uint32_t), 64>::type data; + }; + + static TD_Table table; + return table.ptr(); + } + +#define AES_T(T, K, V0, V1, V2, V3) \ + (K ^ T[get_byte(0, V0)] ^ \ + rotr< 8>(T[get_byte(1, V1)]) ^ \ + rotr<16>(T[get_byte(2, V2)]) ^ \ + rotr<24>(T[get_byte(3, V3)])) + +/* +* AES Encryption +*/ +void aes_encrypt_n(const uint8_t in[], uint8_t out[], + size_t blocks, + const secure_vector<uint32_t>& EK, + const secure_vector<uint8_t>& ME) + { + BOTAN_ASSERT(EK.size() && ME.size() == 16, "Key was set"); + + const size_t cache_line_size = CPUID::cache_line_size(); + + const uint32_t* TE = AES_TE(); + + // Hit every cache line of TE + volatile uint32_t Z = 0; + for(size_t i = 0; i < 256; i += cache_line_size / sizeof(uint32_t)) + { + Z |= TE[i]; + } + Z &= TE[82]; // this is zero, which hopefully the compiler cannot deduce + + for(size_t i = 0; i < blocks; ++i) + { + uint32_t T0, T1, T2, T3; + load_be(in + 16*i, T0, T1, T2, T3); + + T0 ^= EK[0]; + T1 ^= EK[1]; + T2 ^= EK[2]; + T3 ^= EK[3]; + + T0 ^= Z; + + uint32_t B0 = AES_T(TE, EK[4], T0, T1, T2, T3); + uint32_t B1 = AES_T(TE, EK[5], T1, T2, T3, T0); + uint32_t B2 = AES_T(TE, EK[6], T2, T3, T0, T1); + uint32_t B3 = AES_T(TE, EK[7], T3, T0, T1, T2); + + for(size_t r = 2*4; r < EK.size(); r += 2*4) + { + T0 = AES_T(TE, EK[r ], B0, B1, B2, B3); + T1 = AES_T(TE, EK[r+1], B1, B2, B3, B0); + T2 = AES_T(TE, EK[r+2], B2, B3, B0, B1); + T3 = AES_T(TE, EK[r+3], B3, B0, B1, B2); + + B0 = AES_T(TE, EK[r+4], T0, T1, T2, T3); + B1 = AES_T(TE, EK[r+5], T1, T2, T3, T0); + B2 = AES_T(TE, EK[r+6], T2, T3, T0, T1); + B3 = AES_T(TE, EK[r+7], T3, T0, T1, T2); + } + + /* + * Use TE[x] >> 8 instead of SE[] so encryption only references a single + * lookup table. + */ + out[16*i+ 0] = static_cast<uint8_t>(TE[get_byte(0, B0)] >> 8) ^ ME[0]; + out[16*i+ 1] = static_cast<uint8_t>(TE[get_byte(1, B1)] >> 8) ^ ME[1]; + out[16*i+ 2] = static_cast<uint8_t>(TE[get_byte(2, B2)] >> 8) ^ ME[2]; + out[16*i+ 3] = static_cast<uint8_t>(TE[get_byte(3, B3)] >> 8) ^ ME[3]; + out[16*i+ 4] = static_cast<uint8_t>(TE[get_byte(0, B1)] >> 8) ^ ME[4]; + out[16*i+ 5] = static_cast<uint8_t>(TE[get_byte(1, B2)] >> 8) ^ ME[5]; + out[16*i+ 6] = static_cast<uint8_t>(TE[get_byte(2, B3)] >> 8) ^ ME[6]; + out[16*i+ 7] = static_cast<uint8_t>(TE[get_byte(3, B0)] >> 8) ^ ME[7]; + out[16*i+ 8] = static_cast<uint8_t>(TE[get_byte(0, B2)] >> 8) ^ ME[8]; + out[16*i+ 9] = static_cast<uint8_t>(TE[get_byte(1, B3)] >> 8) ^ ME[9]; + out[16*i+10] = static_cast<uint8_t>(TE[get_byte(2, B0)] >> 8) ^ ME[10]; + out[16*i+11] = static_cast<uint8_t>(TE[get_byte(3, B1)] >> 8) ^ ME[11]; + out[16*i+12] = static_cast<uint8_t>(TE[get_byte(0, B3)] >> 8) ^ ME[12]; + out[16*i+13] = static_cast<uint8_t>(TE[get_byte(1, B0)] >> 8) ^ ME[13]; + out[16*i+14] = static_cast<uint8_t>(TE[get_byte(2, B1)] >> 8) ^ ME[14]; + out[16*i+15] = static_cast<uint8_t>(TE[get_byte(3, B2)] >> 8) ^ ME[15]; + } + } + +/* +* AES Decryption +*/ +void aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks, + const secure_vector<uint32_t>& DK, + const secure_vector<uint8_t>& MD) + { + BOTAN_ASSERT(DK.size() && MD.size() == 16, "Key was set"); + + const size_t cache_line_size = CPUID::cache_line_size(); + const uint32_t* TD = AES_TD(); + + volatile uint32_t Z = 0; + for(size_t i = 0; i < 256; i += cache_line_size / sizeof(uint32_t)) + { + Z |= TD[i]; + } + Z &= TD[99]; // this is zero, which hopefully the compiler cannot deduce + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t T0 = load_be<uint32_t>(in, 0) ^ DK[0]; + uint32_t T1 = load_be<uint32_t>(in, 1) ^ DK[1]; + uint32_t T2 = load_be<uint32_t>(in, 2) ^ DK[2]; + uint32_t T3 = load_be<uint32_t>(in, 3) ^ DK[3]; + + T0 ^= Z; + + uint32_t B0 = AES_T(TD, DK[4], T0, T3, T2, T1); + uint32_t B1 = AES_T(TD, DK[5], T1, T0, T3, T2); + uint32_t B2 = AES_T(TD, DK[6], T2, T1, T0, T3); + uint32_t B3 = AES_T(TD, DK[7], T3, T2, T1, T0); + + for(size_t r = 2*4; r < DK.size(); r += 2*4) + { + T0 = AES_T(TD, DK[r ], B0, B3, B2, B1); + T1 = AES_T(TD, DK[r+1], B1, B0, B3, B2); + T2 = AES_T(TD, DK[r+2], B2, B1, B0, B3); + T3 = AES_T(TD, DK[r+3], B3, B2, B1, B0); + + B0 = AES_T(TD, DK[r+4], T0, T3, T2, T1); + B1 = AES_T(TD, DK[r+5], T1, T0, T3, T2); + B2 = AES_T(TD, DK[r+6], T2, T1, T0, T3); + B3 = AES_T(TD, DK[r+7], T3, T2, T1, T0); + } + + out[ 0] = SD[get_byte(0, B0)] ^ MD[0]; + out[ 1] = SD[get_byte(1, B3)] ^ MD[1]; + out[ 2] = SD[get_byte(2, B2)] ^ MD[2]; + out[ 3] = SD[get_byte(3, B1)] ^ MD[3]; + out[ 4] = SD[get_byte(0, B1)] ^ MD[4]; + out[ 5] = SD[get_byte(1, B0)] ^ MD[5]; + out[ 6] = SD[get_byte(2, B3)] ^ MD[6]; + out[ 7] = SD[get_byte(3, B2)] ^ MD[7]; + out[ 8] = SD[get_byte(0, B2)] ^ MD[8]; + out[ 9] = SD[get_byte(1, B1)] ^ MD[9]; + out[10] = SD[get_byte(2, B0)] ^ MD[10]; + out[11] = SD[get_byte(3, B3)] ^ MD[11]; + out[12] = SD[get_byte(0, B3)] ^ MD[12]; + out[13] = SD[get_byte(1, B2)] ^ MD[13]; + out[14] = SD[get_byte(2, B1)] ^ MD[14]; + out[15] = SD[get_byte(3, B0)] ^ MD[15]; + + in += 16; + out += 16; + } + } + +void aes_key_schedule(const uint8_t key[], size_t length, + secure_vector<uint32_t>& EK, + secure_vector<uint32_t>& DK, + secure_vector<uint8_t>& ME, + secure_vector<uint8_t>& MD) + { + static const uint32_t RC[10] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000 }; + + const size_t rounds = (length / 4) + 6; + + secure_vector<uint32_t> XEK(length + 32), XDK(length + 32); + + const size_t X = length / 4; + + // Can't happen, but make static analyzers happy + BOTAN_ARG_CHECK(X == 4 || X == 6 || X == 8, "Invalid AES key size"); + + for(size_t i = 0; i != X; ++i) + XEK[i] = load_be<uint32_t>(key, i); + + for(size_t i = X; i < 4*(rounds+1); i += X) + { + XEK[i] = XEK[i-X] ^ RC[(i-X)/X] ^ SE_word(rotl<8>(XEK[i-1])); + + for(size_t j = 1; j != X; ++j) + { + XEK[i+j] = XEK[i+j-X]; + + if(X == 8 && j == 4) + XEK[i+j] ^= SE_word(XEK[i+j-1]); + else + XEK[i+j] ^= XEK[i+j-1]; + } + } + + for(size_t i = 0; i != 4*(rounds+1); i += 4) + { + XDK[i ] = XEK[4*rounds-i ]; + XDK[i+1] = XEK[4*rounds-i+1]; + XDK[i+2] = XEK[4*rounds-i+2]; + XDK[i+3] = XEK[4*rounds-i+3]; + } + + for(size_t i = 4; i != length + 24; ++i) + { + XDK[i] = SE_word(XDK[i]); + XDK[i] = AES_T(AES_TD(), 0, XDK[i], XDK[i], XDK[i], XDK[i]); + } + + ME.resize(16); + MD.resize(16); + + for(size_t i = 0; i != 4; ++i) + { + store_be(XEK[i+4*rounds], &ME[4*i]); + store_be(XEK[i], &MD[4*i]); + } + + EK.resize(length + 24); + DK.resize(length + 24); + copy_mem(EK.data(), XEK.data(), EK.size()); + copy_mem(DK.data(), XDK.data(), DK.size()); + +#if defined(BOTAN_HAS_AES_ARMV8) + if(CPUID::has_arm_aes()) + { + // ARM needs the subkeys to be byte reversed + + for(size_t i = 0; i != EK.size(); ++i) + EK[i] = reverse_bytes(EK[i]); + for(size_t i = 0; i != DK.size(); ++i) + DK[i] = reverse_bytes(DK[i]); + } +#endif + + } + +#undef AES_T + +size_t aes_parallelism() + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return 4; + } +#endif + + return 1; + } + +const char* aes_provider() + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return "aesni"; + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return "ssse3"; + } +#endif + +#if defined(BOTAN_HAS_AES_POWER8) + if(CPUID::has_ppc_crypto()) + { + return "power8"; + } +#endif + +#if defined(BOTAN_HAS_AES_ARMV8) + if(CPUID::has_arm_aes()) + { + return "armv8"; + } +#endif + + return "base"; + } + +} + +std::string AES_128::provider() const { return aes_provider(); } +std::string AES_192::provider() const { return aes_provider(); } +std::string AES_256::provider() const { return aes_provider(); } + +size_t AES_128::parallelism() const { return aes_parallelism(); } +size_t AES_192::parallelism() const { return aes_parallelism(); } +size_t AES_256::parallelism() const { return aes_parallelism(); } + +void AES_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_ARMV8) + if(CPUID::has_arm_aes()) + { + return armv8_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_POWER8) + if(CPUID::has_ppc_crypto()) + { + return power8_encrypt_n(in, out, blocks); + } +#endif + + aes_encrypt_n(in, out, blocks, m_EK, m_ME); + } + +void AES_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DK.empty() == false); + +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_ARMV8) + if(CPUID::has_arm_aes()) + { + return armv8_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_POWER8) + if(CPUID::has_ppc_crypto()) + { + return power8_decrypt_n(in, out, blocks); + } +#endif + + aes_decrypt_n(in, out, blocks, m_DK, m_MD); + } + +void AES_128::key_schedule(const uint8_t key[], size_t length) + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_key_schedule(key, length); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_key_schedule(key, length); + } +#endif + + aes_key_schedule(key, length, m_EK, m_DK, m_ME, m_MD); + } + +void AES_128::clear() + { + zap(m_EK); + zap(m_DK); + zap(m_ME); + zap(m_MD); + } + +void AES_192::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_ARMV8) + if(CPUID::has_arm_aes()) + { + return armv8_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_POWER8) + if(CPUID::has_ppc_crypto()) + { + return power8_encrypt_n(in, out, blocks); + } +#endif + + aes_encrypt_n(in, out, blocks, m_EK, m_ME); + } + +void AES_192::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DK.empty() == false); + +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_ARMV8) + if(CPUID::has_arm_aes()) + { + return armv8_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_POWER8) + if(CPUID::has_ppc_crypto()) + { + return power8_decrypt_n(in, out, blocks); + } +#endif + + aes_decrypt_n(in, out, blocks, m_DK, m_MD); + } + +void AES_192::key_schedule(const uint8_t key[], size_t length) + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_key_schedule(key, length); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_key_schedule(key, length); + } +#endif + + aes_key_schedule(key, length, m_EK, m_DK, m_ME, m_MD); + } + +void AES_192::clear() + { + zap(m_EK); + zap(m_DK); + zap(m_ME); + zap(m_MD); + } + +void AES_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_EK.empty() == false); + +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_ARMV8) + if(CPUID::has_arm_aes()) + { + return armv8_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_POWER8) + if(CPUID::has_ppc_crypto()) + { + return power8_encrypt_n(in, out, blocks); + } +#endif + + aes_encrypt_n(in, out, blocks, m_EK, m_ME); + } + +void AES_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_DK.empty() == false); + +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_ARMV8) + if(CPUID::has_arm_aes()) + { + return armv8_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_POWER8) + if(CPUID::has_ppc_crypto()) + { + return power8_decrypt_n(in, out, blocks); + } +#endif + + aes_decrypt_n(in, out, blocks, m_DK, m_MD); + } + +void AES_256::key_schedule(const uint8_t key[], size_t length) + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_key_schedule(key, length); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_key_schedule(key, length); + } +#endif + + aes_key_schedule(key, length, m_EK, m_DK, m_ME, m_MD); + } + +void AES_256::clear() + { + zap(m_EK); + zap(m_DK); + zap(m_ME); + zap(m_MD); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/aes.h b/src/libs/3rdparty/botan/src/lib/block/aes/aes.h new file mode 100644 index 0000000000..294cdcad37 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/aes.h @@ -0,0 +1,153 @@ +/* +* AES +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AES_H_ +#define BOTAN_AES_H_ + +#include <botan/block_cipher.h> + +namespace Botan { + +/** +* AES-128 +*/ +class BOTAN_PUBLIC_API(2,0) AES_128 final : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + + std::string provider() const override; + std::string name() const override { return "AES-128"; } + BlockCipher* clone() const override { return new AES_128; } + size_t parallelism() const override; + + private: + void key_schedule(const uint8_t key[], size_t length) override; + +#if defined(BOTAN_HAS_AES_SSSE3) + void ssse3_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void ssse3_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void ssse3_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_NI) + void aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void aesni_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void aesni_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_ARMV8) + void armv8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void armv8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + +#if defined(BOTAN_HAS_AES_POWER8) + void power8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void power8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + + secure_vector<uint32_t> m_EK, m_DK; + secure_vector<uint8_t> m_ME, m_MD; + }; + +/** +* AES-192 +*/ +class BOTAN_PUBLIC_API(2,0) AES_192 final : public Block_Cipher_Fixed_Params<16, 24> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + + std::string provider() const override; + std::string name() const override { return "AES-192"; } + BlockCipher* clone() const override { return new AES_192; } + size_t parallelism() const override; + + private: +#if defined(BOTAN_HAS_AES_SSSE3) + void ssse3_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void ssse3_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void ssse3_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_NI) + void aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void aesni_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void aesni_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_ARMV8) + void armv8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void armv8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + +#if defined(BOTAN_HAS_AES_POWER8) + void power8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void power8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + + void key_schedule(const uint8_t key[], size_t length) override; + + secure_vector<uint32_t> m_EK, m_DK; + secure_vector<uint8_t> m_ME, m_MD; + }; + +/** +* AES-256 +*/ +class BOTAN_PUBLIC_API(2,0) AES_256 final : public Block_Cipher_Fixed_Params<16, 32> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + + std::string provider() const override; + + std::string name() const override { return "AES-256"; } + BlockCipher* clone() const override { return new AES_256; } + size_t parallelism() const override; + + private: +#if defined(BOTAN_HAS_AES_SSSE3) + void ssse3_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void ssse3_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void ssse3_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_NI) + void aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void aesni_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void aesni_key_schedule(const uint8_t key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_ARMV8) + void armv8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void armv8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + +#if defined(BOTAN_HAS_AES_POWER8) + void power8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; + void power8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const; +#endif + + void key_schedule(const uint8_t key[], size_t length) override; + + secure_vector<uint32_t> m_EK, m_DK; + secure_vector<uint8_t> m_ME, m_MD; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/aes_armv8/aes_armv8.cpp b/src/libs/3rdparty/botan/src/lib/block/aes/aes_armv8/aes_armv8.cpp new file mode 100644 index 0000000000..8a332ceafd --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/aes_armv8/aes_armv8.cpp @@ -0,0 +1,501 @@ +/* +* AES using ARMv8 +* Contributed by Jeffrey Walton +* +* Further changes +* (C) 2017,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/aes.h> +#include <botan/loadstor.h> +#include <arm_neon.h> + +namespace Botan { + +#define AES_ENC_4_ROUNDS(K) \ + do \ + { \ + B0 = vaesmcq_u8(vaeseq_u8(B0, K)); \ + B1 = vaesmcq_u8(vaeseq_u8(B1, K)); \ + B2 = vaesmcq_u8(vaeseq_u8(B2, K)); \ + B3 = vaesmcq_u8(vaeseq_u8(B3, K)); \ + } while(0) + +#define AES_ENC_4_LAST_ROUNDS(K, K2) \ + do \ + { \ + B0 = veorq_u8(vaeseq_u8(B0, K), K2); \ + B1 = veorq_u8(vaeseq_u8(B1, K), K2); \ + B2 = veorq_u8(vaeseq_u8(B2, K), K2); \ + B3 = veorq_u8(vaeseq_u8(B3, K), K2); \ + } while(0) + +#define AES_DEC_4_ROUNDS(K) \ + do \ + { \ + B0 = vaesimcq_u8(vaesdq_u8(B0, K)); \ + B1 = vaesimcq_u8(vaesdq_u8(B1, K)); \ + B2 = vaesimcq_u8(vaesdq_u8(B2, K)); \ + B3 = vaesimcq_u8(vaesdq_u8(B3, K)); \ + } while(0) + +#define AES_DEC_4_LAST_ROUNDS(K, K2) \ + do \ + { \ + B0 = veorq_u8(vaesdq_u8(B0, K), K2); \ + B1 = veorq_u8(vaesdq_u8(B1, K), K2); \ + B2 = veorq_u8(vaesdq_u8(B2, K), K2); \ + B3 = veorq_u8(vaesdq_u8(B3, K), K2); \ + } while(0) + +/* +* AES-128 Encryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_128::armv8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const uint8_t *skey = reinterpret_cast<const uint8_t*>(m_EK.data()); + const uint8_t *mkey = reinterpret_cast<const uint8_t*>(m_ME.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0); + const uint8x16_t K1 = vld1q_u8(skey + 16); + const uint8x16_t K2 = vld1q_u8(skey + 32); + const uint8x16_t K3 = vld1q_u8(skey + 48); + const uint8x16_t K4 = vld1q_u8(skey + 64); + const uint8x16_t K5 = vld1q_u8(skey + 80); + const uint8x16_t K6 = vld1q_u8(skey + 96); + const uint8x16_t K7 = vld1q_u8(skey + 112); + const uint8x16_t K8 = vld1q_u8(skey + 128); + const uint8x16_t K9 = vld1q_u8(skey + 144); + const uint8x16_t K10 = vld1q_u8(mkey); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_ENC_4_ROUNDS(K0); + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_LAST_ROUNDS(K9, K10); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesmcq_u8(vaeseq_u8(B, K0)); + B = vaesmcq_u8(vaeseq_u8(B, K1)); + B = vaesmcq_u8(vaeseq_u8(B, K2)); + B = vaesmcq_u8(vaeseq_u8(B, K3)); + B = vaesmcq_u8(vaeseq_u8(B, K4)); + B = vaesmcq_u8(vaeseq_u8(B, K5)); + B = vaesmcq_u8(vaeseq_u8(B, K6)); + B = vaesmcq_u8(vaeseq_u8(B, K7)); + B = vaesmcq_u8(vaeseq_u8(B, K8)); + B = veorq_u8(vaeseq_u8(B, K9), K10); + vst1q_u8(out+16*i, B); + } + } + +/* +* AES-128 Decryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_128::armv8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_DK.empty() == false, "Key was set"); + + const uint8_t *skey = reinterpret_cast<const uint8_t*>(m_DK.data()); + const uint8_t *mkey = reinterpret_cast<const uint8_t*>(m_MD.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0); + const uint8x16_t K1 = vld1q_u8(skey + 16); + const uint8x16_t K2 = vld1q_u8(skey + 32); + const uint8x16_t K3 = vld1q_u8(skey + 48); + const uint8x16_t K4 = vld1q_u8(skey + 64); + const uint8x16_t K5 = vld1q_u8(skey + 80); + const uint8x16_t K6 = vld1q_u8(skey + 96); + const uint8x16_t K7 = vld1q_u8(skey + 112); + const uint8x16_t K8 = vld1q_u8(skey + 128); + const uint8x16_t K9 = vld1q_u8(skey + 144); + const uint8x16_t K10 = vld1q_u8(mkey); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_DEC_4_ROUNDS(K0); + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_LAST_ROUNDS(K9, K10); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesimcq_u8(vaesdq_u8(B, K0)); + B = vaesimcq_u8(vaesdq_u8(B, K1)); + B = vaesimcq_u8(vaesdq_u8(B, K2)); + B = vaesimcq_u8(vaesdq_u8(B, K3)); + B = vaesimcq_u8(vaesdq_u8(B, K4)); + B = vaesimcq_u8(vaesdq_u8(B, K5)); + B = vaesimcq_u8(vaesdq_u8(B, K6)); + B = vaesimcq_u8(vaesdq_u8(B, K7)); + B = vaesimcq_u8(vaesdq_u8(B, K8)); + B = veorq_u8(vaesdq_u8(B, K9), K10); + vst1q_u8(out+16*i, B); + } + } + +/* +* AES-192 Encryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_192::armv8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const uint8_t *skey = reinterpret_cast<const uint8_t*>(m_EK.data()); + const uint8_t *mkey = reinterpret_cast<const uint8_t*>(m_ME.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0); + const uint8x16_t K1 = vld1q_u8(skey + 16); + const uint8x16_t K2 = vld1q_u8(skey + 32); + const uint8x16_t K3 = vld1q_u8(skey + 48); + const uint8x16_t K4 = vld1q_u8(skey + 64); + const uint8x16_t K5 = vld1q_u8(skey + 80); + const uint8x16_t K6 = vld1q_u8(skey + 96); + const uint8x16_t K7 = vld1q_u8(skey + 112); + const uint8x16_t K8 = vld1q_u8(skey + 128); + const uint8x16_t K9 = vld1q_u8(skey + 144); + const uint8x16_t K10 = vld1q_u8(skey + 160); + const uint8x16_t K11 = vld1q_u8(skey + 176); + const uint8x16_t K12 = vld1q_u8(mkey); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_ENC_4_ROUNDS(K0); + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_ROUNDS(K10); + AES_ENC_4_LAST_ROUNDS(K11, K12); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesmcq_u8(vaeseq_u8(B, K0)); + B = vaesmcq_u8(vaeseq_u8(B, K1)); + B = vaesmcq_u8(vaeseq_u8(B, K2)); + B = vaesmcq_u8(vaeseq_u8(B, K3)); + B = vaesmcq_u8(vaeseq_u8(B, K4)); + B = vaesmcq_u8(vaeseq_u8(B, K5)); + B = vaesmcq_u8(vaeseq_u8(B, K6)); + B = vaesmcq_u8(vaeseq_u8(B, K7)); + B = vaesmcq_u8(vaeseq_u8(B, K8)); + B = vaesmcq_u8(vaeseq_u8(B, K9)); + B = vaesmcq_u8(vaeseq_u8(B, K10)); + B = veorq_u8(vaeseq_u8(B, K11), K12); + vst1q_u8(out+16*i, B); + } + } + +/* +* AES-192 Decryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_192::armv8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_DK.empty() == false, "Key was set"); + const uint8_t *skey = reinterpret_cast<const uint8_t*>(m_DK.data()); + const uint8_t *mkey = reinterpret_cast<const uint8_t*>(m_MD.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0); + const uint8x16_t K1 = vld1q_u8(skey + 16); + const uint8x16_t K2 = vld1q_u8(skey + 32); + const uint8x16_t K3 = vld1q_u8(skey + 48); + const uint8x16_t K4 = vld1q_u8(skey + 64); + const uint8x16_t K5 = vld1q_u8(skey + 80); + const uint8x16_t K6 = vld1q_u8(skey + 96); + const uint8x16_t K7 = vld1q_u8(skey + 112); + const uint8x16_t K8 = vld1q_u8(skey + 128); + const uint8x16_t K9 = vld1q_u8(skey + 144); + const uint8x16_t K10 = vld1q_u8(skey + 160); + const uint8x16_t K11 = vld1q_u8(skey + 176); + const uint8x16_t K12 = vld1q_u8(mkey); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_DEC_4_ROUNDS(K0); + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_ROUNDS(K10); + AES_DEC_4_LAST_ROUNDS(K11, K12); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesimcq_u8(vaesdq_u8(B, K0)); + B = vaesimcq_u8(vaesdq_u8(B, K1)); + B = vaesimcq_u8(vaesdq_u8(B, K2)); + B = vaesimcq_u8(vaesdq_u8(B, K3)); + B = vaesimcq_u8(vaesdq_u8(B, K4)); + B = vaesimcq_u8(vaesdq_u8(B, K5)); + B = vaesimcq_u8(vaesdq_u8(B, K6)); + B = vaesimcq_u8(vaesdq_u8(B, K7)); + B = vaesimcq_u8(vaesdq_u8(B, K8)); + B = vaesimcq_u8(vaesdq_u8(B, K9)); + B = vaesimcq_u8(vaesdq_u8(B, K10)); + B = veorq_u8(vaesdq_u8(B, K11), K12); + vst1q_u8(out+16*i, B); + } + } + +/* +* AES-256 Encryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_256::armv8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const uint8_t *skey = reinterpret_cast<const uint8_t*>(m_EK.data()); + const uint8_t *mkey = reinterpret_cast<const uint8_t*>(m_ME.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0); + const uint8x16_t K1 = vld1q_u8(skey + 16); + const uint8x16_t K2 = vld1q_u8(skey + 32); + const uint8x16_t K3 = vld1q_u8(skey + 48); + const uint8x16_t K4 = vld1q_u8(skey + 64); + const uint8x16_t K5 = vld1q_u8(skey + 80); + const uint8x16_t K6 = vld1q_u8(skey + 96); + const uint8x16_t K7 = vld1q_u8(skey + 112); + const uint8x16_t K8 = vld1q_u8(skey + 128); + const uint8x16_t K9 = vld1q_u8(skey + 144); + const uint8x16_t K10 = vld1q_u8(skey + 160); + const uint8x16_t K11 = vld1q_u8(skey + 176); + const uint8x16_t K12 = vld1q_u8(skey + 192); + const uint8x16_t K13 = vld1q_u8(skey + 208); + const uint8x16_t K14 = vld1q_u8(mkey); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_ENC_4_ROUNDS(K0); + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_ROUNDS(K10); + AES_ENC_4_ROUNDS(K11); + AES_ENC_4_ROUNDS(K12); + AES_ENC_4_LAST_ROUNDS(K13, K14); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesmcq_u8(vaeseq_u8(B, K0)); + B = vaesmcq_u8(vaeseq_u8(B, K1)); + B = vaesmcq_u8(vaeseq_u8(B, K2)); + B = vaesmcq_u8(vaeseq_u8(B, K3)); + B = vaesmcq_u8(vaeseq_u8(B, K4)); + B = vaesmcq_u8(vaeseq_u8(B, K5)); + B = vaesmcq_u8(vaeseq_u8(B, K6)); + B = vaesmcq_u8(vaeseq_u8(B, K7)); + B = vaesmcq_u8(vaeseq_u8(B, K8)); + B = vaesmcq_u8(vaeseq_u8(B, K9)); + B = vaesmcq_u8(vaeseq_u8(B, K10)); + B = vaesmcq_u8(vaeseq_u8(B, K11)); + B = vaesmcq_u8(vaeseq_u8(B, K12)); + B = veorq_u8(vaeseq_u8(B, K13), K14); + vst1q_u8(out+16*i, B); + } + } + +/* +* AES-256 Decryption +*/ +BOTAN_FUNC_ISA("+crypto") +void AES_256::armv8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_DK.empty() == false, "Key was set"); + + const uint8_t *skey = reinterpret_cast<const uint8_t*>(m_DK.data()); + const uint8_t *mkey = reinterpret_cast<const uint8_t*>(m_MD.data()); + + const uint8x16_t K0 = vld1q_u8(skey + 0); + const uint8x16_t K1 = vld1q_u8(skey + 16); + const uint8x16_t K2 = vld1q_u8(skey + 32); + const uint8x16_t K3 = vld1q_u8(skey + 48); + const uint8x16_t K4 = vld1q_u8(skey + 64); + const uint8x16_t K5 = vld1q_u8(skey + 80); + const uint8x16_t K6 = vld1q_u8(skey + 96); + const uint8x16_t K7 = vld1q_u8(skey + 112); + const uint8x16_t K8 = vld1q_u8(skey + 128); + const uint8x16_t K9 = vld1q_u8(skey + 144); + const uint8x16_t K10 = vld1q_u8(skey + 160); + const uint8x16_t K11 = vld1q_u8(skey + 176); + const uint8x16_t K12 = vld1q_u8(skey + 192); + const uint8x16_t K13 = vld1q_u8(skey + 208); + const uint8x16_t K14 = vld1q_u8(mkey); + + while(blocks >= 4) + { + uint8x16_t B0 = vld1q_u8(in); + uint8x16_t B1 = vld1q_u8(in+16); + uint8x16_t B2 = vld1q_u8(in+32); + uint8x16_t B3 = vld1q_u8(in+48); + + AES_DEC_4_ROUNDS(K0); + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_ROUNDS(K10); + AES_DEC_4_ROUNDS(K11); + AES_DEC_4_ROUNDS(K12); + AES_DEC_4_LAST_ROUNDS(K13, K14); + + vst1q_u8(out, B0); + vst1q_u8(out+16, B1); + vst1q_u8(out+32, B2); + vst1q_u8(out+48, B3); + + in += 16*4; + out += 16*4; + blocks -= 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint8x16_t B = vld1q_u8(in+16*i); + B = vaesimcq_u8(vaesdq_u8(B, K0)); + B = vaesimcq_u8(vaesdq_u8(B, K1)); + B = vaesimcq_u8(vaesdq_u8(B, K2)); + B = vaesimcq_u8(vaesdq_u8(B, K3)); + B = vaesimcq_u8(vaesdq_u8(B, K4)); + B = vaesimcq_u8(vaesdq_u8(B, K5)); + B = vaesimcq_u8(vaesdq_u8(B, K6)); + B = vaesimcq_u8(vaesdq_u8(B, K7)); + B = vaesimcq_u8(vaesdq_u8(B, K8)); + B = vaesimcq_u8(vaesdq_u8(B, K9)); + B = vaesimcq_u8(vaesdq_u8(B, K10)); + B = vaesimcq_u8(vaesdq_u8(B, K11)); + B = vaesimcq_u8(vaesdq_u8(B, K12)); + B = veorq_u8(vaesdq_u8(B, K13), K14); + vst1q_u8(out+16*i, B); + } + } + +#undef AES_ENC_4_ROUNDS +#undef AES_ENC_4_LAST_ROUNDS +#undef AES_DEC_4_ROUNDS +#undef AES_DEC_4_LAST_ROUNDS + +} diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/aes_armv8/info.txt b/src/libs/3rdparty/botan/src/lib/block/aes/aes_armv8/info.txt new file mode 100644 index 0000000000..08d51a1b2d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/aes_armv8/info.txt @@ -0,0 +1,10 @@ +<defines> +AES_ARMV8 -> 20170903 +</defines> + +need_isa armv8crypto + +<cc> +gcc:5 +clang:3.8 +</cc> diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/aes_ni/aes_ni.cpp b/src/libs/3rdparty/botan/src/lib/block/aes/aes_ni/aes_ni.cpp new file mode 100644 index 0000000000..9f1ba8fcc2 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/aes_ni/aes_ni.cpp @@ -0,0 +1,792 @@ +/* +* AES using AES-NI instructions +* (C) 2009,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/aes.h> +#include <botan/loadstor.h> +#include <wmmintrin.h> + +namespace Botan { + +namespace { + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_128_key_expansion(__m128i key, __m128i key_with_rcon) + { + key_with_rcon = _mm_shuffle_epi32(key_with_rcon, _MM_SHUFFLE(3,3,3,3)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + return _mm_xor_si128(key, key_with_rcon); + } + +BOTAN_FUNC_ISA("ssse3") +void aes_192_key_expansion(__m128i* K1, __m128i* K2, __m128i key2_with_rcon, + uint32_t out[], bool last) + { + __m128i key1 = *K1; + __m128i key2 = *K2; + + key2_with_rcon = _mm_shuffle_epi32(key2_with_rcon, _MM_SHUFFLE(1,1,1,1)); + key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); + key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); + key1 = _mm_xor_si128(key1, _mm_slli_si128(key1, 4)); + key1 = _mm_xor_si128(key1, key2_with_rcon); + + *K1 = key1; + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), key1); + + if(last) + return; + + key2 = _mm_xor_si128(key2, _mm_slli_si128(key2, 4)); + key2 = _mm_xor_si128(key2, _mm_shuffle_epi32(key1, _MM_SHUFFLE(3,3,3,3))); + + *K2 = key2; + out[4] = _mm_cvtsi128_si32(key2); + out[5] = _mm_cvtsi128_si32(_mm_srli_si128(key2, 4)); + } + +/* +* The second half of the AES-256 key expansion (other half same as AES-128) +*/ +BOTAN_FUNC_ISA("ssse3,aes") +__m128i aes_256_key_expansion(__m128i key, __m128i key2) + { + __m128i key_with_rcon = _mm_aeskeygenassist_si128(key2, 0x00); + key_with_rcon = _mm_shuffle_epi32(key_with_rcon, _MM_SHUFFLE(2,2,2,2)); + + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); + return _mm_xor_si128(key, key_with_rcon); + } + +} + +#define AES_ENC_4_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesenc_si128(B0, K); \ + B1 = _mm_aesenc_si128(B1, K); \ + B2 = _mm_aesenc_si128(B2, K); \ + B3 = _mm_aesenc_si128(B3, K); \ + } while(0) + +#define AES_ENC_4_LAST_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesenclast_si128(B0, K); \ + B1 = _mm_aesenclast_si128(B1, K); \ + B2 = _mm_aesenclast_si128(B2, K); \ + B3 = _mm_aesenclast_si128(B3, K); \ + } while(0) + +#define AES_DEC_4_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesdec_si128(B0, K); \ + B1 = _mm_aesdec_si128(B1, K); \ + B2 = _mm_aesdec_si128(B2, K); \ + B3 = _mm_aesdec_si128(B3, K); \ + } while(0) + +#define AES_DEC_4_LAST_ROUNDS(K) \ + do \ + { \ + B0 = _mm_aesdeclast_si128(B0, K); \ + B1 = _mm_aesdeclast_si128(B1, K); \ + B2 = _mm_aesdeclast_si128(B2, K); \ + B3 = _mm_aesdeclast_si128(B3, K); \ + } while(0) + +/* +* AES-128 Encryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_128::aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast<const __m128i*>(m_EK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_LAST_ROUNDS(K10); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesenc_si128(B, K1); + B = _mm_aesenc_si128(B, K2); + B = _mm_aesenc_si128(B, K3); + B = _mm_aesenc_si128(B, K4); + B = _mm_aesenc_si128(B, K5); + B = _mm_aesenc_si128(B, K6); + B = _mm_aesenc_si128(B, K7); + B = _mm_aesenc_si128(B, K8); + B = _mm_aesenc_si128(B, K9); + B = _mm_aesenclast_si128(B, K10); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-128 Decryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_128::aesni_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_DK.empty() == false, "Key was set"); + + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast<const __m128i*>(m_DK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_LAST_ROUNDS(K10); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesdec_si128(B, K1); + B = _mm_aesdec_si128(B, K2); + B = _mm_aesdec_si128(B, K3); + B = _mm_aesdec_si128(B, K4); + B = _mm_aesdec_si128(B, K5); + B = _mm_aesdec_si128(B, K6); + B = _mm_aesdec_si128(B, K7); + B = _mm_aesdec_si128(B, K8); + B = _mm_aesdec_si128(B, K9); + B = _mm_aesdeclast_si128(B, K10); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-128 Key Schedule +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_128::aesni_key_schedule(const uint8_t key[], size_t) + { + m_EK.resize(44); + m_DK.resize(44); + + #define AES_128_key_exp(K, RCON) \ + aes_128_key_expansion(K, _mm_aeskeygenassist_si128(K, RCON)) + + const __m128i K0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(key)); + const __m128i K1 = AES_128_key_exp(K0, 0x01); + const __m128i K2 = AES_128_key_exp(K1, 0x02); + const __m128i K3 = AES_128_key_exp(K2, 0x04); + const __m128i K4 = AES_128_key_exp(K3, 0x08); + const __m128i K5 = AES_128_key_exp(K4, 0x10); + const __m128i K6 = AES_128_key_exp(K5, 0x20); + const __m128i K7 = AES_128_key_exp(K6, 0x40); + const __m128i K8 = AES_128_key_exp(K7, 0x80); + const __m128i K9 = AES_128_key_exp(K8, 0x1B); + const __m128i K10 = AES_128_key_exp(K9, 0x36); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(m_EK.data()); + _mm_storeu_si128(EK_mm , K0); + _mm_storeu_si128(EK_mm + 1, K1); + _mm_storeu_si128(EK_mm + 2, K2); + _mm_storeu_si128(EK_mm + 3, K3); + _mm_storeu_si128(EK_mm + 4, K4); + _mm_storeu_si128(EK_mm + 5, K5); + _mm_storeu_si128(EK_mm + 6, K6); + _mm_storeu_si128(EK_mm + 7, K7); + _mm_storeu_si128(EK_mm + 8, K8); + _mm_storeu_si128(EK_mm + 9, K9); + _mm_storeu_si128(EK_mm + 10, K10); + + // Now generate decryption keys + + __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); + _mm_storeu_si128(DK_mm , K10); + _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(K9)); + _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(K8)); + _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(K7)); + _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(K6)); + _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(K5)); + _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(K4)); + _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(K3)); + _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(K2)); + _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(K1)); + _mm_storeu_si128(DK_mm + 10, K0); + } + +/* +* AES-192 Encryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_192::aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast<const __m128i*>(m_EK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + const __m128i K11 = _mm_loadu_si128(key_mm + 11); + const __m128i K12 = _mm_loadu_si128(key_mm + 12); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_ROUNDS(K10); + AES_ENC_4_ROUNDS(K11); + AES_ENC_4_LAST_ROUNDS(K12); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesenc_si128(B, K1); + B = _mm_aesenc_si128(B, K2); + B = _mm_aesenc_si128(B, K3); + B = _mm_aesenc_si128(B, K4); + B = _mm_aesenc_si128(B, K5); + B = _mm_aesenc_si128(B, K6); + B = _mm_aesenc_si128(B, K7); + B = _mm_aesenc_si128(B, K8); + B = _mm_aesenc_si128(B, K9); + B = _mm_aesenc_si128(B, K10); + B = _mm_aesenc_si128(B, K11); + B = _mm_aesenclast_si128(B, K12); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-192 Decryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_192::aesni_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_DK.empty() == false, "Key was set"); + + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast<const __m128i*>(m_DK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + const __m128i K11 = _mm_loadu_si128(key_mm + 11); + const __m128i K12 = _mm_loadu_si128(key_mm + 12); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_ROUNDS(K10); + AES_DEC_4_ROUNDS(K11); + AES_DEC_4_LAST_ROUNDS(K12); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesdec_si128(B, K1); + B = _mm_aesdec_si128(B, K2); + B = _mm_aesdec_si128(B, K3); + B = _mm_aesdec_si128(B, K4); + B = _mm_aesdec_si128(B, K5); + B = _mm_aesdec_si128(B, K6); + B = _mm_aesdec_si128(B, K7); + B = _mm_aesdec_si128(B, K8); + B = _mm_aesdec_si128(B, K9); + B = _mm_aesdec_si128(B, K10); + B = _mm_aesdec_si128(B, K11); + B = _mm_aesdeclast_si128(B, K12); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-192 Key Schedule +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_192::aesni_key_schedule(const uint8_t key[], size_t) + { + m_EK.resize(52); + m_DK.resize(52); + + __m128i K0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(key)); + __m128i K1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(key + 8)); + K1 = _mm_srli_si128(K1, 8); + + load_le(m_EK.data(), key, 6); + + #define AES_192_key_exp(RCON, EK_OFF) \ + aes_192_key_expansion(&K0, &K1, \ + _mm_aeskeygenassist_si128(K1, RCON), \ + &m_EK[EK_OFF], EK_OFF == 48) + + AES_192_key_exp(0x01, 6); + AES_192_key_exp(0x02, 12); + AES_192_key_exp(0x04, 18); + AES_192_key_exp(0x08, 24); + AES_192_key_exp(0x10, 30); + AES_192_key_exp(0x20, 36); + AES_192_key_exp(0x40, 42); + AES_192_key_exp(0x80, 48); + + #undef AES_192_key_exp + + // Now generate decryption keys + const __m128i* EK_mm = reinterpret_cast<const __m128i*>(m_EK.data()); + + __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); + _mm_storeu_si128(DK_mm , _mm_loadu_si128(EK_mm + 12)); + _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 11))); + _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 10))); + _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 9))); + _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 8))); + _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 7))); + _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 6))); + _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 5))); + _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 4))); + _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 3))); + _mm_storeu_si128(DK_mm + 10, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 2))); + _mm_storeu_si128(DK_mm + 11, _mm_aesimc_si128(_mm_loadu_si128(EK_mm + 1))); + _mm_storeu_si128(DK_mm + 12, _mm_loadu_si128(EK_mm + 0)); + } + +/* +* AES-256 Encryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_256::aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast<const __m128i*>(m_EK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + const __m128i K11 = _mm_loadu_si128(key_mm + 11); + const __m128i K12 = _mm_loadu_si128(key_mm + 12); + const __m128i K13 = _mm_loadu_si128(key_mm + 13); + const __m128i K14 = _mm_loadu_si128(key_mm + 14); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_ENC_4_ROUNDS(K1); + AES_ENC_4_ROUNDS(K2); + AES_ENC_4_ROUNDS(K3); + AES_ENC_4_ROUNDS(K4); + AES_ENC_4_ROUNDS(K5); + AES_ENC_4_ROUNDS(K6); + AES_ENC_4_ROUNDS(K7); + AES_ENC_4_ROUNDS(K8); + AES_ENC_4_ROUNDS(K9); + AES_ENC_4_ROUNDS(K10); + AES_ENC_4_ROUNDS(K11); + AES_ENC_4_ROUNDS(K12); + AES_ENC_4_ROUNDS(K13); + AES_ENC_4_LAST_ROUNDS(K14); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesenc_si128(B, K1); + B = _mm_aesenc_si128(B, K2); + B = _mm_aesenc_si128(B, K3); + B = _mm_aesenc_si128(B, K4); + B = _mm_aesenc_si128(B, K5); + B = _mm_aesenc_si128(B, K6); + B = _mm_aesenc_si128(B, K7); + B = _mm_aesenc_si128(B, K8); + B = _mm_aesenc_si128(B, K9); + B = _mm_aesenc_si128(B, K10); + B = _mm_aesenc_si128(B, K11); + B = _mm_aesenc_si128(B, K12); + B = _mm_aesenc_si128(B, K13); + B = _mm_aesenclast_si128(B, K14); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-256 Decryption +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_256::aesni_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_DK.empty() == false, "Key was set"); + + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* key_mm = reinterpret_cast<const __m128i*>(m_DK.data()); + + const __m128i K0 = _mm_loadu_si128(key_mm); + const __m128i K1 = _mm_loadu_si128(key_mm + 1); + const __m128i K2 = _mm_loadu_si128(key_mm + 2); + const __m128i K3 = _mm_loadu_si128(key_mm + 3); + const __m128i K4 = _mm_loadu_si128(key_mm + 4); + const __m128i K5 = _mm_loadu_si128(key_mm + 5); + const __m128i K6 = _mm_loadu_si128(key_mm + 6); + const __m128i K7 = _mm_loadu_si128(key_mm + 7); + const __m128i K8 = _mm_loadu_si128(key_mm + 8); + const __m128i K9 = _mm_loadu_si128(key_mm + 9); + const __m128i K10 = _mm_loadu_si128(key_mm + 10); + const __m128i K11 = _mm_loadu_si128(key_mm + 11); + const __m128i K12 = _mm_loadu_si128(key_mm + 12); + const __m128i K13 = _mm_loadu_si128(key_mm + 13); + const __m128i K14 = _mm_loadu_si128(key_mm + 14); + + while(blocks >= 4) + { + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); + + B0 = _mm_xor_si128(B0, K0); + B1 = _mm_xor_si128(B1, K0); + B2 = _mm_xor_si128(B2, K0); + B3 = _mm_xor_si128(B3, K0); + + AES_DEC_4_ROUNDS(K1); + AES_DEC_4_ROUNDS(K2); + AES_DEC_4_ROUNDS(K3); + AES_DEC_4_ROUNDS(K4); + AES_DEC_4_ROUNDS(K5); + AES_DEC_4_ROUNDS(K6); + AES_DEC_4_ROUNDS(K7); + AES_DEC_4_ROUNDS(K8); + AES_DEC_4_ROUNDS(K9); + AES_DEC_4_ROUNDS(K10); + AES_DEC_4_ROUNDS(K11); + AES_DEC_4_ROUNDS(K12); + AES_DEC_4_ROUNDS(K13); + AES_DEC_4_LAST_ROUNDS(K14); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B1); + _mm_storeu_si128(out_mm + 2, B2); + _mm_storeu_si128(out_mm + 3, B3); + + blocks -= 4; + in_mm += 4; + out_mm += 4; + } + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + + B = _mm_xor_si128(B, K0); + + B = _mm_aesdec_si128(B, K1); + B = _mm_aesdec_si128(B, K2); + B = _mm_aesdec_si128(B, K3); + B = _mm_aesdec_si128(B, K4); + B = _mm_aesdec_si128(B, K5); + B = _mm_aesdec_si128(B, K6); + B = _mm_aesdec_si128(B, K7); + B = _mm_aesdec_si128(B, K8); + B = _mm_aesdec_si128(B, K9); + B = _mm_aesdec_si128(B, K10); + B = _mm_aesdec_si128(B, K11); + B = _mm_aesdec_si128(B, K12); + B = _mm_aesdec_si128(B, K13); + B = _mm_aesdeclast_si128(B, K14); + + _mm_storeu_si128(out_mm + i, B); + } + } + +/* +* AES-256 Key Schedule +*/ +BOTAN_FUNC_ISA("ssse3,aes") +void AES_256::aesni_key_schedule(const uint8_t key[], size_t) + { + m_EK.resize(60); + m_DK.resize(60); + + const __m128i K0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(key)); + const __m128i K1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(key + 16)); + + const __m128i K2 = aes_128_key_expansion(K0, _mm_aeskeygenassist_si128(K1, 0x01)); + const __m128i K3 = aes_256_key_expansion(K1, K2); + + const __m128i K4 = aes_128_key_expansion(K2, _mm_aeskeygenassist_si128(K3, 0x02)); + const __m128i K5 = aes_256_key_expansion(K3, K4); + + const __m128i K6 = aes_128_key_expansion(K4, _mm_aeskeygenassist_si128(K5, 0x04)); + const __m128i K7 = aes_256_key_expansion(K5, K6); + + const __m128i K8 = aes_128_key_expansion(K6, _mm_aeskeygenassist_si128(K7, 0x08)); + const __m128i K9 = aes_256_key_expansion(K7, K8); + + const __m128i K10 = aes_128_key_expansion(K8, _mm_aeskeygenassist_si128(K9, 0x10)); + const __m128i K11 = aes_256_key_expansion(K9, K10); + + const __m128i K12 = aes_128_key_expansion(K10, _mm_aeskeygenassist_si128(K11, 0x20)); + const __m128i K13 = aes_256_key_expansion(K11, K12); + + const __m128i K14 = aes_128_key_expansion(K12, _mm_aeskeygenassist_si128(K13, 0x40)); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(m_EK.data()); + _mm_storeu_si128(EK_mm , K0); + _mm_storeu_si128(EK_mm + 1, K1); + _mm_storeu_si128(EK_mm + 2, K2); + _mm_storeu_si128(EK_mm + 3, K3); + _mm_storeu_si128(EK_mm + 4, K4); + _mm_storeu_si128(EK_mm + 5, K5); + _mm_storeu_si128(EK_mm + 6, K6); + _mm_storeu_si128(EK_mm + 7, K7); + _mm_storeu_si128(EK_mm + 8, K8); + _mm_storeu_si128(EK_mm + 9, K9); + _mm_storeu_si128(EK_mm + 10, K10); + _mm_storeu_si128(EK_mm + 11, K11); + _mm_storeu_si128(EK_mm + 12, K12); + _mm_storeu_si128(EK_mm + 13, K13); + _mm_storeu_si128(EK_mm + 14, K14); + + // Now generate decryption keys + __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); + _mm_storeu_si128(DK_mm , K14); + _mm_storeu_si128(DK_mm + 1, _mm_aesimc_si128(K13)); + _mm_storeu_si128(DK_mm + 2, _mm_aesimc_si128(K12)); + _mm_storeu_si128(DK_mm + 3, _mm_aesimc_si128(K11)); + _mm_storeu_si128(DK_mm + 4, _mm_aesimc_si128(K10)); + _mm_storeu_si128(DK_mm + 5, _mm_aesimc_si128(K9)); + _mm_storeu_si128(DK_mm + 6, _mm_aesimc_si128(K8)); + _mm_storeu_si128(DK_mm + 7, _mm_aesimc_si128(K7)); + _mm_storeu_si128(DK_mm + 8, _mm_aesimc_si128(K6)); + _mm_storeu_si128(DK_mm + 9, _mm_aesimc_si128(K5)); + _mm_storeu_si128(DK_mm + 10, _mm_aesimc_si128(K4)); + _mm_storeu_si128(DK_mm + 11, _mm_aesimc_si128(K3)); + _mm_storeu_si128(DK_mm + 12, _mm_aesimc_si128(K2)); + _mm_storeu_si128(DK_mm + 13, _mm_aesimc_si128(K1)); + _mm_storeu_si128(DK_mm + 14, K0); + } + +#undef AES_ENC_4_ROUNDS +#undef AES_ENC_4_LAST_ROUNDS +#undef AES_DEC_4_ROUNDS +#undef AES_DEC_4_LAST_ROUNDS + +} diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/aes_ni/info.txt b/src/libs/3rdparty/botan/src/lib/block/aes/aes_ni/info.txt new file mode 100644 index 0000000000..d5d3593489 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/aes_ni/info.txt @@ -0,0 +1,7 @@ +<defines> +AES_NI -> 20131128 +</defines> + +load_on auto + +need_isa aesni diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/aes_power8/aes_power8.cpp b/src/libs/3rdparty/botan/src/lib/block/aes/aes_power8/aes_power8.cpp new file mode 100644 index 0000000000..98520a13cf --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/aes_power8/aes_power8.cpp @@ -0,0 +1,328 @@ +/* +* AES using POWER8 crypto extensions +* +* Contributed by Jeffrey Walton +* +* Further changes +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/aes.h> +#include <botan/cpuid.h> + +#include <altivec.h> +#undef vector +#undef bool + +namespace Botan { + +namespace { + +__vector unsigned long long LoadKey(const uint32_t* src) + { + __vector unsigned int vec = vec_vsx_ld(0, src); + + if(CPUID::is_little_endian()) + { + const __vector unsigned char mask = {12,13,14,15, 8,9,10,11, 4,5,6,7, 0,1,2,3}; + const __vector unsigned char zero = {0}; + return (__vector unsigned long long)vec_perm((__vector unsigned char)vec, zero, mask); + } + else + { + return (__vector unsigned long long)vec; + } + } + +__vector unsigned char Reverse8x16(const __vector unsigned char src) + { + if(CPUID::is_little_endian()) + { + const __vector unsigned char mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + const __vector unsigned char zero = {0}; + return vec_perm(src, zero, mask); + } + else + { + return src; + } + } + +__vector unsigned long long LoadBlock(const uint8_t* src) + { + return (__vector unsigned long long)Reverse8x16(vec_vsx_ld(0, src)); + } + +void StoreBlock(const __vector unsigned long long src, uint8_t* dest) + { + vec_vsx_st(Reverse8x16((__vector unsigned char)src), 0, dest); + } + +} + +BOTAN_FUNC_ISA("crypto") +void AES_128::power8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const __vector unsigned long long K0 = LoadKey(&m_EK[0]); + const __vector unsigned long long K1 = LoadKey(&m_EK[4]); + const __vector unsigned long long K2 = LoadKey(&m_EK[8]); + const __vector unsigned long long K3 = LoadKey(&m_EK[12]); + const __vector unsigned long long K4 = LoadKey(&m_EK[16]); + const __vector unsigned long long K5 = LoadKey(&m_EK[20]); + const __vector unsigned long long K6 = LoadKey(&m_EK[24]); + const __vector unsigned long long K7 = LoadKey(&m_EK[28]); + const __vector unsigned long long K8 = LoadKey(&m_EK[32]); + const __vector unsigned long long K9 = LoadKey(&m_EK[36]); + const __vector unsigned long long K10 = LoadBlock(m_ME.data()); + + for(size_t i = 0; i != blocks; ++i) + { + __vector unsigned long long B = LoadBlock(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vcipher(B, K1); + B = __builtin_crypto_vcipher(B, K2); + B = __builtin_crypto_vcipher(B, K3); + B = __builtin_crypto_vcipher(B, K4); + B = __builtin_crypto_vcipher(B, K5); + B = __builtin_crypto_vcipher(B, K6); + B = __builtin_crypto_vcipher(B, K7); + B = __builtin_crypto_vcipher(B, K8); + B = __builtin_crypto_vcipher(B, K9); + B = __builtin_crypto_vcipherlast(B, K10); + + StoreBlock(B, out); + + out += 16; + in += 16; + } + } + +BOTAN_FUNC_ISA("crypto") +void AES_128::power8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const __vector unsigned long long K0 = LoadBlock(m_ME.data()); + const __vector unsigned long long K1 = LoadKey(&m_EK[36]); + const __vector unsigned long long K2 = LoadKey(&m_EK[32]); + const __vector unsigned long long K3 = LoadKey(&m_EK[28]); + const __vector unsigned long long K4 = LoadKey(&m_EK[24]); + const __vector unsigned long long K5 = LoadKey(&m_EK[20]); + const __vector unsigned long long K6 = LoadKey(&m_EK[16]); + const __vector unsigned long long K7 = LoadKey(&m_EK[12]); + const __vector unsigned long long K8 = LoadKey(&m_EK[8]); + const __vector unsigned long long K9 = LoadKey(&m_EK[4]); + const __vector unsigned long long K10 = LoadKey(&m_EK[0]); + + for(size_t i = 0; i != blocks; ++i) + { + __vector unsigned long long B = LoadBlock(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vncipher(B, K1); + B = __builtin_crypto_vncipher(B, K2); + B = __builtin_crypto_vncipher(B, K3); + B = __builtin_crypto_vncipher(B, K4); + B = __builtin_crypto_vncipher(B, K5); + B = __builtin_crypto_vncipher(B, K6); + B = __builtin_crypto_vncipher(B, K7); + B = __builtin_crypto_vncipher(B, K8); + B = __builtin_crypto_vncipher(B, K9); + B = __builtin_crypto_vncipherlast(B, K10); + + StoreBlock(B, out); + + out += 16; + in += 16; + } + } + +BOTAN_FUNC_ISA("crypto") +void AES_192::power8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const __vector unsigned long long K0 = LoadKey(&m_EK[0]); + const __vector unsigned long long K1 = LoadKey(&m_EK[4]); + const __vector unsigned long long K2 = LoadKey(&m_EK[8]); + const __vector unsigned long long K3 = LoadKey(&m_EK[12]); + const __vector unsigned long long K4 = LoadKey(&m_EK[16]); + const __vector unsigned long long K5 = LoadKey(&m_EK[20]); + const __vector unsigned long long K6 = LoadKey(&m_EK[24]); + const __vector unsigned long long K7 = LoadKey(&m_EK[28]); + const __vector unsigned long long K8 = LoadKey(&m_EK[32]); + const __vector unsigned long long K9 = LoadKey(&m_EK[36]); + const __vector unsigned long long K10 = LoadKey(&m_EK[40]); + const __vector unsigned long long K11 = LoadKey(&m_EK[44]); + const __vector unsigned long long K12 = LoadBlock(m_ME.data()); + + for(size_t i = 0; i != blocks; ++i) + { + __vector unsigned long long B = LoadBlock(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vcipher(B, K1); + B = __builtin_crypto_vcipher(B, K2); + B = __builtin_crypto_vcipher(B, K3); + B = __builtin_crypto_vcipher(B, K4); + B = __builtin_crypto_vcipher(B, K5); + B = __builtin_crypto_vcipher(B, K6); + B = __builtin_crypto_vcipher(B, K7); + B = __builtin_crypto_vcipher(B, K8); + B = __builtin_crypto_vcipher(B, K9); + B = __builtin_crypto_vcipher(B, K10); + B = __builtin_crypto_vcipher(B, K11); + B = __builtin_crypto_vcipherlast(B, K12); + + StoreBlock(B, out); + + out += 16; + in += 16; + } + } + +BOTAN_FUNC_ISA("crypto") +void AES_192::power8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const __vector unsigned long long K0 = LoadBlock(m_ME.data()); + const __vector unsigned long long K1 = LoadKey(&m_EK[44]); + const __vector unsigned long long K2 = LoadKey(&m_EK[40]); + const __vector unsigned long long K3 = LoadKey(&m_EK[36]); + const __vector unsigned long long K4 = LoadKey(&m_EK[32]); + const __vector unsigned long long K5 = LoadKey(&m_EK[28]); + const __vector unsigned long long K6 = LoadKey(&m_EK[24]); + const __vector unsigned long long K7 = LoadKey(&m_EK[20]); + const __vector unsigned long long K8 = LoadKey(&m_EK[16]); + const __vector unsigned long long K9 = LoadKey(&m_EK[12]); + const __vector unsigned long long K10 = LoadKey(&m_EK[8]); + const __vector unsigned long long K11 = LoadKey(&m_EK[4]); + const __vector unsigned long long K12 = LoadKey(&m_EK[0]); + + for(size_t i = 0; i != blocks; ++i) + { + __vector unsigned long long B = LoadBlock(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vncipher(B, K1); + B = __builtin_crypto_vncipher(B, K2); + B = __builtin_crypto_vncipher(B, K3); + B = __builtin_crypto_vncipher(B, K4); + B = __builtin_crypto_vncipher(B, K5); + B = __builtin_crypto_vncipher(B, K6); + B = __builtin_crypto_vncipher(B, K7); + B = __builtin_crypto_vncipher(B, K8); + B = __builtin_crypto_vncipher(B, K9); + B = __builtin_crypto_vncipher(B, K10); + B = __builtin_crypto_vncipher(B, K11); + B = __builtin_crypto_vncipherlast(B, K12); + + StoreBlock(B, out); + + out += 16; + in += 16; + } + } + +BOTAN_FUNC_ISA("crypto") +void AES_256::power8_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + const __vector unsigned long long K0 = LoadKey(&m_EK[0]); + const __vector unsigned long long K1 = LoadKey(&m_EK[4]); + const __vector unsigned long long K2 = LoadKey(&m_EK[8]); + const __vector unsigned long long K3 = LoadKey(&m_EK[12]); + const __vector unsigned long long K4 = LoadKey(&m_EK[16]); + const __vector unsigned long long K5 = LoadKey(&m_EK[20]); + const __vector unsigned long long K6 = LoadKey(&m_EK[24]); + const __vector unsigned long long K7 = LoadKey(&m_EK[28]); + const __vector unsigned long long K8 = LoadKey(&m_EK[32]); + const __vector unsigned long long K9 = LoadKey(&m_EK[36]); + const __vector unsigned long long K10 = LoadKey(&m_EK[40]); + const __vector unsigned long long K11 = LoadKey(&m_EK[44]); + const __vector unsigned long long K12 = LoadKey(&m_EK[48]); + const __vector unsigned long long K13 = LoadKey(&m_EK[52]); + const __vector unsigned long long K14 = LoadBlock(m_ME.data()); + + for(size_t i = 0; i != blocks; ++i) + { + __vector unsigned long long B = LoadBlock(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vcipher(B, K1); + B = __builtin_crypto_vcipher(B, K2); + B = __builtin_crypto_vcipher(B, K3); + B = __builtin_crypto_vcipher(B, K4); + B = __builtin_crypto_vcipher(B, K5); + B = __builtin_crypto_vcipher(B, K6); + B = __builtin_crypto_vcipher(B, K7); + B = __builtin_crypto_vcipher(B, K8); + B = __builtin_crypto_vcipher(B, K9); + B = __builtin_crypto_vcipher(B, K10); + B = __builtin_crypto_vcipher(B, K11); + B = __builtin_crypto_vcipher(B, K12); + B = __builtin_crypto_vcipher(B, K13); + B = __builtin_crypto_vcipherlast(B, K14); + + StoreBlock(B, out); + + out += 16; + in += 16; + } + } + +BOTAN_FUNC_ISA("crypto") +void AES_256::power8_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + + const __vector unsigned long long K0 = LoadBlock(m_ME.data()); + const __vector unsigned long long K1 = LoadKey(&m_EK[52]); + const __vector unsigned long long K2 = LoadKey(&m_EK[48]); + const __vector unsigned long long K3 = LoadKey(&m_EK[44]); + const __vector unsigned long long K4 = LoadKey(&m_EK[40]); + const __vector unsigned long long K5 = LoadKey(&m_EK[36]); + const __vector unsigned long long K6 = LoadKey(&m_EK[32]); + const __vector unsigned long long K7 = LoadKey(&m_EK[28]); + const __vector unsigned long long K8 = LoadKey(&m_EK[24]); + const __vector unsigned long long K9 = LoadKey(&m_EK[20]); + const __vector unsigned long long K10 = LoadKey(&m_EK[16]); + const __vector unsigned long long K11 = LoadKey(&m_EK[12]); + const __vector unsigned long long K12 = LoadKey(&m_EK[8]); + const __vector unsigned long long K13 = LoadKey(&m_EK[4]); + const __vector unsigned long long K14 = LoadKey(&m_EK[0]); + + for(size_t i = 0; i != blocks; ++i) + { + __vector unsigned long long B = LoadBlock(in); + + B = vec_xor(B, K0); + B = __builtin_crypto_vncipher(B, K1); + B = __builtin_crypto_vncipher(B, K2); + B = __builtin_crypto_vncipher(B, K3); + B = __builtin_crypto_vncipher(B, K4); + B = __builtin_crypto_vncipher(B, K5); + B = __builtin_crypto_vncipher(B, K6); + B = __builtin_crypto_vncipher(B, K7); + B = __builtin_crypto_vncipher(B, K8); + B = __builtin_crypto_vncipher(B, K9); + B = __builtin_crypto_vncipher(B, K10); + B = __builtin_crypto_vncipher(B, K11); + B = __builtin_crypto_vncipher(B, K12); + B = __builtin_crypto_vncipher(B, K13); + B = __builtin_crypto_vncipherlast(B, K14); + + StoreBlock(B, out); + + out += 16; + in += 16; + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/aes_power8/info.txt b/src/libs/3rdparty/botan/src/lib/block/aes/aes_power8/info.txt new file mode 100644 index 0000000000..6aa52d25a0 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/aes_power8/info.txt @@ -0,0 +1,9 @@ +<defines> +AES_POWER8 -> 20180223 +</defines> + +<arch> +ppc64 +</arch> + +need_isa ppccrypto diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/aes_ssse3/aes_ssse3.cpp b/src/libs/3rdparty/botan/src/lib/block/aes/aes_ssse3/aes_ssse3.cpp new file mode 100644 index 0000000000..47d70d0b8b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/aes_ssse3/aes_ssse3.cpp @@ -0,0 +1,637 @@ +/* +* AES using SSSE3 +* (C) 2010,2016 Jack Lloyd +* +* This is more or less a direct translation of public domain x86-64 +* assembly written by Mike Hamburg, described in "Accelerating AES +* with Vector Permute Instructions" (CHES 2009). His original code is +* available at https://crypto.stanford.edu/vpaes/ +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/aes.h> +#include <botan/internal/ct_utils.h> +#include <tmmintrin.h> + +namespace Botan { + +namespace { + +const __m128i low_nibs = _mm_set1_epi8(0x0F); + +const __m128i k_ipt1 = _mm_set_epi32( + 0xCABAE090, 0x52227808, 0xC2B2E898, 0x5A2A7000); +const __m128i k_ipt2 = _mm_set_epi32( + 0xCD80B1FC, 0xB0FDCC81, 0x4C01307D, 0x317C4D00); + +const __m128i k_inv1 = _mm_set_epi32( + 0x04070309, 0x0A0B0C02, 0x0E05060F, 0x0D080180); +const __m128i k_inv2 = _mm_set_epi32( + 0x030D0E0C, 0x02050809, 0x01040A06, 0x0F0B0780); + +const __m128i sb1u = _mm_set_epi32( + 0xA5DF7A6E, 0x142AF544, 0xB19BE18F, 0xCB503E00); +const __m128i sb1t = _mm_set_epi32( + 0x3BF7CCC1, 0x0D2ED9EF, 0x3618D415, 0xFAE22300); + +const __m128i mc_forward[4] = { + _mm_set_epi32(0x0C0F0E0D, 0x080B0A09, 0x04070605, 0x00030201), + _mm_set_epi32(0x00030201, 0x0C0F0E0D, 0x080B0A09, 0x04070605), + _mm_set_epi32(0x04070605, 0x00030201, 0x0C0F0E0D, 0x080B0A09), + _mm_set_epi32(0x080B0A09, 0x04070605, 0x00030201, 0x0C0F0E0D) +}; + +const __m128i sr[4] = { + _mm_set_epi32(0x0F0E0D0C, 0x0B0A0908, 0x07060504, 0x03020100), + _mm_set_epi32(0x0B06010C, 0x07020D08, 0x030E0904, 0x0F0A0500), + _mm_set_epi32(0x070E050C, 0x030A0108, 0x0F060D04, 0x0B020900), + _mm_set_epi32(0x0306090C, 0x0F020508, 0x0B0E0104, 0x070A0D00), +}; + +#define mm_xor3(x, y, z) _mm_xor_si128(x, _mm_xor_si128(y, z)) + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_schedule_transform(__m128i input, + __m128i table_1, + __m128i table_2) + { + __m128i i_1 = _mm_and_si128(low_nibs, input); + __m128i i_2 = _mm_srli_epi32(_mm_andnot_si128(low_nibs, input), 4); + + return _mm_xor_si128( + _mm_shuffle_epi8(table_1, i_1), + _mm_shuffle_epi8(table_2, i_2)); + } + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_schedule_mangle(__m128i k, uint8_t round_no) + { + __m128i t = _mm_shuffle_epi8(_mm_xor_si128(k, _mm_set1_epi8(0x5B)), + mc_forward[0]); + + __m128i t2 = t; + + t = _mm_shuffle_epi8(t, mc_forward[0]); + + t2 = mm_xor3(t2, t, _mm_shuffle_epi8(t, mc_forward[0])); + + return _mm_shuffle_epi8(t2, sr[round_no % 4]); + } + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_schedule_192_smear(__m128i x, __m128i y) + { + return mm_xor3(y, + _mm_shuffle_epi32(x, 0xFE), + _mm_shuffle_epi32(y, 0x80)); + } + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_schedule_mangle_dec(__m128i k, uint8_t round_no) + { + const __m128i dsk[8] = { + _mm_set_epi32(0x4AED9334, 0x82255BFC, 0xB6116FC8, 0x7ED9A700), + _mm_set_epi32(0x8BB89FAC, 0xE9DAFDCE, 0x45765162, 0x27143300), + _mm_set_epi32(0x4622EE8A, 0xADC90561, 0x27438FEB, 0xCCA86400), + _mm_set_epi32(0x73AEE13C, 0xBD602FF2, 0x815C13CE, 0x4F92DD00), + _mm_set_epi32(0xF83F3EF9, 0xFA3D3CFB, 0x03C4C502, 0x01C6C700), + _mm_set_epi32(0xA5526A9D, 0x7384BC4B, 0xEE1921D6, 0x38CFF700), + _mm_set_epi32(0xA080D3F3, 0x10306343, 0xE3C390B0, 0x53732000), + _mm_set_epi32(0x2F45AEC4, 0x8CE60D67, 0xA0CA214B, 0x036982E8) + }; + + __m128i t = aes_schedule_transform(k, dsk[0], dsk[1]); + __m128i output = _mm_shuffle_epi8(t, mc_forward[0]); + + t = aes_schedule_transform(t, dsk[2], dsk[3]); + output = _mm_shuffle_epi8(_mm_xor_si128(t, output), mc_forward[0]); + + t = aes_schedule_transform(t, dsk[4], dsk[5]); + output = _mm_shuffle_epi8(_mm_xor_si128(t, output), mc_forward[0]); + + t = aes_schedule_transform(t, dsk[6], dsk[7]); + output = _mm_shuffle_epi8(_mm_xor_si128(t, output), mc_forward[0]); + + return _mm_shuffle_epi8(output, sr[round_no % 4]); + } + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_schedule_mangle_last(__m128i k, uint8_t round_no) + { + const __m128i out_tr1 = _mm_set_epi32( + 0xF7974121, 0xDEBE6808, 0xFF9F4929, 0xD6B66000); + const __m128i out_tr2 = _mm_set_epi32( + 0xE10D5DB1, 0xB05C0CE0, 0x01EDBD51, 0x50BCEC00); + + k = _mm_shuffle_epi8(k, sr[round_no % 4]); + k = _mm_xor_si128(k, _mm_set1_epi8(0x5B)); + return aes_schedule_transform(k, out_tr1, out_tr2); + } + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_schedule_mangle_last_dec(__m128i k) + { + const __m128i deskew1 = _mm_set_epi32( + 0x1DFEB95A, 0x5DBEF91A, 0x07E4A340, 0x47A4E300); + const __m128i deskew2 = _mm_set_epi32( + 0x2841C2AB, 0xF49D1E77, 0x5F36B5DC, 0x83EA6900); + + k = _mm_xor_si128(k, _mm_set1_epi8(0x5B)); + return aes_schedule_transform(k, deskew1, deskew2); + } + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_schedule_round(__m128i* rcon, __m128i input1, __m128i input2) + { + if(rcon) + { + input2 = _mm_xor_si128(_mm_alignr_epi8(_mm_setzero_si128(), *rcon, 15), + input2); + + *rcon = _mm_alignr_epi8(*rcon, *rcon, 15); // next rcon + + input1 = _mm_shuffle_epi32(input1, 0xFF); // rotate + input1 = _mm_alignr_epi8(input1, input1, 1); + } + + __m128i smeared = _mm_xor_si128(input2, _mm_slli_si128(input2, 4)); + smeared = mm_xor3(smeared, _mm_slli_si128(smeared, 8), _mm_set1_epi8(0x5B)); + + __m128i t = _mm_srli_epi32(_mm_andnot_si128(low_nibs, input1), 4); + + input1 = _mm_and_si128(low_nibs, input1); + + __m128i t2 = _mm_shuffle_epi8(k_inv2, input1); + + input1 = _mm_xor_si128(input1, t); + + __m128i t3 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, t)); + __m128i t4 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, input1)); + + __m128i t5 = _mm_xor_si128(input1, _mm_shuffle_epi8(k_inv1, t3)); + __m128i t6 = _mm_xor_si128(t, _mm_shuffle_epi8(k_inv1, t4)); + + return mm_xor3(_mm_shuffle_epi8(sb1u, t5), + _mm_shuffle_epi8(sb1t, t6), + smeared); + } + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_ssse3_encrypt(__m128i B, const __m128i* keys, size_t rounds) + { + const __m128i sb2u = _mm_set_epi32( + 0x5EB7E955, 0xBC982FCD, 0xE27A93C6, 0x0B712400); + const __m128i sb2t = _mm_set_epi32( + 0xC2A163C8, 0xAB82234A, 0x69EB8840, 0x0AE12900); + + const __m128i sbou = _mm_set_epi32( + 0x15AABF7A, 0xC502A878, 0xD0D26D17, 0x6FBDC700); + const __m128i sbot = _mm_set_epi32( + 0x8E1E90D1, 0x412B35FA, 0xCFE474A5, 0x5FBB6A00); + + const __m128i mc_backward[4] = { + _mm_set_epi32(0x0E0D0C0F, 0x0A09080B, 0x06050407, 0x02010003), + _mm_set_epi32(0x0A09080B, 0x06050407, 0x02010003, 0x0E0D0C0F), + _mm_set_epi32(0x06050407, 0x02010003, 0x0E0D0C0F, 0x0A09080B), + _mm_set_epi32(0x02010003, 0x0E0D0C0F, 0x0A09080B, 0x06050407), + }; + + B = mm_xor3(_mm_shuffle_epi8(k_ipt1, _mm_and_si128(low_nibs, B)), + _mm_shuffle_epi8(k_ipt2, + _mm_srli_epi32( + _mm_andnot_si128(low_nibs, B), + 4)), + _mm_loadu_si128(keys)); + + for(size_t r = 1; ; ++r) + { + const __m128i K = _mm_loadu_si128(keys + r); + + __m128i t = _mm_srli_epi32(_mm_andnot_si128(low_nibs, B), 4); + + B = _mm_and_si128(low_nibs, B); + + __m128i t2 = _mm_shuffle_epi8(k_inv2, B); + + B = _mm_xor_si128(B, t); + + __m128i t3 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, t)); + __m128i t4 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, B)); + + __m128i t5 = _mm_xor_si128(B, _mm_shuffle_epi8(k_inv1, t3)); + __m128i t6 = _mm_xor_si128(t, _mm_shuffle_epi8(k_inv1, t4)); + + if(r == rounds) + { + B = _mm_shuffle_epi8( + mm_xor3(_mm_shuffle_epi8(sbou, t5), + _mm_shuffle_epi8(sbot, t6), + K), + sr[r % 4]); + + return B; + } + + __m128i t7 = mm_xor3(_mm_shuffle_epi8(sb1t, t6), + _mm_shuffle_epi8(sb1u, t5), + K); + + __m128i t8 = mm_xor3(_mm_shuffle_epi8(sb2t, t6), + _mm_shuffle_epi8(sb2u, t5), + _mm_shuffle_epi8(t7, mc_forward[r % 4])); + + B = mm_xor3(_mm_shuffle_epi8(t8, mc_forward[r % 4]), + _mm_shuffle_epi8(t7, mc_backward[r % 4]), + t8); + } + } + +BOTAN_FUNC_ISA("ssse3") +__m128i aes_ssse3_decrypt(__m128i B, const __m128i* keys, size_t rounds) + { + const __m128i k_dipt1 = _mm_set_epi32( + 0x154A411E, 0x114E451A, 0x0F505B04, 0x0B545F00); + const __m128i k_dipt2 = _mm_set_epi32( + 0x12771772, 0xF491F194, 0x86E383E6, 0x60056500); + + const __m128i sb9u = _mm_set_epi32( + 0xCAD51F50, 0x4F994CC9, 0x851C0353, 0x9A86D600); + const __m128i sb9t = _mm_set_epi32( + 0x725E2C9E, 0xB2FBA565, 0xC03B1789, 0xECD74900); + + const __m128i sbeu = _mm_set_epi32( + 0x22426004, 0x64B4F6B0, 0x46F29296, 0x26D4D000); + const __m128i sbet = _mm_set_epi32( + 0x9467F36B, 0x98593E32, 0x0C55A6CD, 0xFFAAC100); + + const __m128i sbdu = _mm_set_epi32( + 0xF56E9B13, 0x882A4439, 0x7D57CCDF, 0xE6B1A200); + const __m128i sbdt = _mm_set_epi32( + 0x2931180D, 0x15DEEFD3, 0x3CE2FAF7, 0x24C6CB00); + + const __m128i sbbu = _mm_set_epi32( + 0x602646F6, 0xB0F2D404, 0xD0226492, 0x96B44200); + const __m128i sbbt = _mm_set_epi32( + 0xF3FF0C3E, 0x3255AA6B, 0xC19498A6, 0xCD596700); + + __m128i mc = mc_forward[3]; + + __m128i t = + _mm_shuffle_epi8(k_dipt2, + _mm_srli_epi32( + _mm_andnot_si128(low_nibs, B), + 4)); + + B = mm_xor3(t, _mm_loadu_si128(keys), + _mm_shuffle_epi8(k_dipt1, _mm_and_si128(B, low_nibs))); + + for(size_t r = 1; ; ++r) + { + const __m128i K = _mm_loadu_si128(keys + r); + + t = _mm_srli_epi32(_mm_andnot_si128(low_nibs, B), 4); + + B = _mm_and_si128(low_nibs, B); + + __m128i t2 = _mm_shuffle_epi8(k_inv2, B); + + B = _mm_xor_si128(B, t); + + __m128i t3 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, t)); + __m128i t4 = _mm_xor_si128(t2, _mm_shuffle_epi8(k_inv1, B)); + __m128i t5 = _mm_xor_si128(B, _mm_shuffle_epi8(k_inv1, t3)); + __m128i t6 = _mm_xor_si128(t, _mm_shuffle_epi8(k_inv1, t4)); + + if(r == rounds) + { + const __m128i sbou = _mm_set_epi32( + 0xC7AA6DB9, 0xD4943E2D, 0x1387EA53, 0x7EF94000); + const __m128i sbot = _mm_set_epi32( + 0xCA4B8159, 0xD8C58E9C, 0x12D7560F, 0x93441D00); + + __m128i x = _mm_shuffle_epi8(sbou, t5); + __m128i y = _mm_shuffle_epi8(sbot, t6); + x = _mm_xor_si128(x, K); + x = _mm_xor_si128(x, y); + + const uint32_t which_sr = ((((rounds - 1) << 4) ^ 48) & 48) / 16; + return _mm_shuffle_epi8(x, sr[which_sr]); + } + + __m128i t8 = _mm_xor_si128(_mm_shuffle_epi8(sb9t, t6), + _mm_xor_si128(_mm_shuffle_epi8(sb9u, t5), K)); + + __m128i t9 = mm_xor3(_mm_shuffle_epi8(t8, mc), + _mm_shuffle_epi8(sbdu, t5), + _mm_shuffle_epi8(sbdt, t6)); + + __m128i t12 = _mm_xor_si128( + _mm_xor_si128( + _mm_shuffle_epi8(t9, mc), + _mm_shuffle_epi8(sbbu, t5)), + _mm_shuffle_epi8(sbbt, t6)); + + B = _mm_xor_si128(_mm_xor_si128(_mm_shuffle_epi8(t12, mc), + _mm_shuffle_epi8(sbeu, t5)), + _mm_shuffle_epi8(sbet, t6)); + + mc = _mm_alignr_epi8(mc, mc, 12); + } + } + +} + +/* +* AES-128 Encryption +*/ +BOTAN_FUNC_ISA("ssse3") +void AES_128::ssse3_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast<const __m128i*>(m_EK.data()); + + CT::poison(in, blocks * block_size()); + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 10)); + } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); + } + +/* +* AES-128 Decryption +*/ +BOTAN_FUNC_ISA("ssse3") +void AES_128::ssse3_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast<const __m128i*>(m_DK.data()); + + CT::poison(in, blocks * block_size()); + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 10)); + } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); + } + +/* +* AES-128 Key Schedule +*/ +BOTAN_FUNC_ISA("ssse3") +void AES_128::ssse3_key_schedule(const uint8_t keyb[], size_t) + { + __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, + 0x1F8391B9, 0xAF9DEEB6); + + __m128i key = _mm_loadu_si128(reinterpret_cast<const __m128i*>(keyb)); + + m_EK.resize(11*4); + m_DK.resize(11*4); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(m_EK.data()); + __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); + + _mm_storeu_si128(DK_mm + 10, _mm_shuffle_epi8(key, sr[2])); + + key = aes_schedule_transform(key, k_ipt1, k_ipt2); + + _mm_storeu_si128(EK_mm, key); + + for(size_t i = 1; i != 10; ++i) + { + key = aes_schedule_round(&rcon, key, key); + + _mm_storeu_si128(EK_mm + i, + aes_schedule_mangle(key, (12-i) % 4)); + + _mm_storeu_si128(DK_mm + (10-i), + aes_schedule_mangle_dec(key, (10-i) % 4)); + } + + key = aes_schedule_round(&rcon, key, key); + _mm_storeu_si128(EK_mm + 10, aes_schedule_mangle_last(key, 2)); + _mm_storeu_si128(DK_mm, aes_schedule_mangle_last_dec(key)); + } + +/* +* AES-192 Encryption +*/ +BOTAN_FUNC_ISA("ssse3") +void AES_192::ssse3_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast<const __m128i*>(m_EK.data()); + + CT::poison(in, blocks * block_size()); + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 12)); + } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); + } + +/* +* AES-192 Decryption +*/ +BOTAN_FUNC_ISA("ssse3") +void AES_192::ssse3_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast<const __m128i*>(m_DK.data()); + + CT::poison(in, blocks * block_size()); + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 12)); + } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); + } + +/* +* AES-192 Key Schedule +*/ +BOTAN_FUNC_ISA("ssse3") +void AES_192::ssse3_key_schedule(const uint8_t keyb[], size_t) + { + __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, + 0x1F8391B9, 0xAF9DEEB6); + + m_EK.resize(13*4); + m_DK.resize(13*4); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(m_EK.data()); + __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); + + __m128i key1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(keyb)); + __m128i key2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>((keyb + 8))); + + _mm_storeu_si128(DK_mm + 12, _mm_shuffle_epi8(key1, sr[0])); + + key1 = aes_schedule_transform(key1, k_ipt1, k_ipt2); + key2 = aes_schedule_transform(key2, k_ipt1, k_ipt2); + + _mm_storeu_si128(EK_mm + 0, key1); + + // key2 with 8 high bytes masked off + __m128i t = _mm_slli_si128(_mm_srli_si128(key2, 8), 8); + + for(size_t i = 0; i != 4; ++i) + { + key2 = aes_schedule_round(&rcon, key2, key1); + + _mm_storeu_si128(EK_mm + 3*i+1, + aes_schedule_mangle(_mm_alignr_epi8(key2, t, 8), (i+3)%4)); + _mm_storeu_si128(DK_mm + 11-3*i, + aes_schedule_mangle_dec(_mm_alignr_epi8(key2, t, 8), (i+3)%4)); + + t = aes_schedule_192_smear(key2, t); + + _mm_storeu_si128(EK_mm + 3*i+2, + aes_schedule_mangle(t, (i+2)%4)); + _mm_storeu_si128(DK_mm + 10-3*i, + aes_schedule_mangle_dec(t, (i+2)%4)); + + key2 = aes_schedule_round(&rcon, t, key2); + + if(i == 3) + { + _mm_storeu_si128(EK_mm + 3*i+3, + aes_schedule_mangle_last(key2, (i+1)%4)); + _mm_storeu_si128(DK_mm + 9-3*i, + aes_schedule_mangle_last_dec(key2)); + } + else + { + _mm_storeu_si128(EK_mm + 3*i+3, + aes_schedule_mangle(key2, (i+1)%4)); + _mm_storeu_si128(DK_mm + 9-3*i, + aes_schedule_mangle_dec(key2, (i+1)%4)); + } + + key1 = key2; + key2 = aes_schedule_192_smear(key2, + _mm_slli_si128(_mm_srli_si128(t, 8), 8)); + t = _mm_slli_si128(_mm_srli_si128(key2, 8), 8); + } + } + +/* +* AES-256 Encryption +*/ +BOTAN_FUNC_ISA("ssse3") +void AES_256::ssse3_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast<const __m128i*>(m_EK.data()); + + CT::poison(in, blocks * block_size()); + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_encrypt(B, keys, 14)); + } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); + } + +/* +* AES-256 Decryption +*/ +BOTAN_FUNC_ISA("ssse3") +void AES_256::ssse3_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + const __m128i* keys = reinterpret_cast<const __m128i*>(m_DK.data()); + + CT::poison(in, blocks * block_size()); + + for(size_t i = 0; i != blocks; ++i) + { + __m128i B = _mm_loadu_si128(in_mm + i); + _mm_storeu_si128(out_mm + i, aes_ssse3_decrypt(B, keys, 14)); + } + + CT::unpoison(in, blocks * block_size()); + CT::unpoison(out, blocks * block_size()); + } + +/* +* AES-256 Key Schedule +*/ +BOTAN_FUNC_ISA("ssse3") +void AES_256::ssse3_key_schedule(const uint8_t keyb[], size_t) + { + __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, + 0x1F8391B9, 0xAF9DEEB6); + + m_EK.resize(15*4); + m_DK.resize(15*4); + + __m128i* EK_mm = reinterpret_cast<__m128i*>(m_EK.data()); + __m128i* DK_mm = reinterpret_cast<__m128i*>(m_DK.data()); + + __m128i key1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(keyb)); + __m128i key2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>((keyb + 16))); + + _mm_storeu_si128(DK_mm + 14, _mm_shuffle_epi8(key1, sr[2])); + + key1 = aes_schedule_transform(key1, k_ipt1, k_ipt2); + key2 = aes_schedule_transform(key2, k_ipt1, k_ipt2); + + _mm_storeu_si128(EK_mm + 0, key1); + _mm_storeu_si128(EK_mm + 1, aes_schedule_mangle(key2, 3)); + + _mm_storeu_si128(DK_mm + 13, aes_schedule_mangle_dec(key2, 1)); + + for(size_t i = 2; i != 14; i += 2) + { + __m128i k_t = key2; + key1 = key2 = aes_schedule_round(&rcon, key2, key1); + + _mm_storeu_si128(EK_mm + i, aes_schedule_mangle(key2, i % 4)); + _mm_storeu_si128(DK_mm + (14-i), aes_schedule_mangle_dec(key2, (i+2) % 4)); + + key2 = aes_schedule_round(nullptr, _mm_shuffle_epi32(key2, 0xFF), k_t); + _mm_storeu_si128(EK_mm + i + 1, aes_schedule_mangle(key2, (i - 1) % 4)); + _mm_storeu_si128(DK_mm + (13-i), aes_schedule_mangle_dec(key2, (i+1) % 4)); + } + + key2 = aes_schedule_round(&rcon, key2, key1); + + _mm_storeu_si128(EK_mm + 14, aes_schedule_mangle_last(key2, 2)); + _mm_storeu_si128(DK_mm + 0, aes_schedule_mangle_last_dec(key2)); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/aes_ssse3/info.txt b/src/libs/3rdparty/botan/src/lib/block/aes/aes_ssse3/info.txt new file mode 100644 index 0000000000..8457eed569 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/aes_ssse3/info.txt @@ -0,0 +1,15 @@ +<defines> +AES_SSSE3 -> 20131128 +</defines> + +load_on auto + +need_isa ssse3 + +# Intel C++ can't deal with syntax for defining constants :( +<cc> +gcc +clang +msvc +sunstudio +</cc> diff --git a/src/libs/3rdparty/botan/src/lib/block/aes/info.txt b/src/libs/3rdparty/botan/src/lib/block/aes/info.txt new file mode 100644 index 0000000000..62455cf2c3 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/aes/info.txt @@ -0,0 +1,3 @@ +<defines> +AES -> 20131128 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/block/block_cipher.cpp b/src/libs/3rdparty/botan/src/lib/block/block_cipher.cpp new file mode 100644 index 0000000000..3ace6cd4f4 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/block_cipher.cpp @@ -0,0 +1,349 @@ +/* +* Block Ciphers +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/block_cipher.h> +#include <botan/scan_name.h> +#include <botan/exceptn.h> + +#if defined(BOTAN_HAS_AES) + #include <botan/aes.h> +#endif + +#if defined(BOTAN_HAS_ARIA) + #include <botan/aria.h> +#endif + +#if defined(BOTAN_HAS_BLOWFISH) + #include <botan/blowfish.h> +#endif + +#if defined(BOTAN_HAS_CAMELLIA) + #include <botan/camellia.h> +#endif + +#if defined(BOTAN_HAS_CAST_128) + #include <botan/cast128.h> +#endif + +#if defined(BOTAN_HAS_CAST_256) + #include <botan/cast256.h> +#endif + +#if defined(BOTAN_HAS_CASCADE) + #include <botan/cascade.h> +#endif + +#if defined(BOTAN_HAS_DES) + #include <botan/des.h> + #include <botan/desx.h> +#endif + +#if defined(BOTAN_HAS_GOST_28147_89) + #include <botan/gost_28147.h> +#endif + +#if defined(BOTAN_HAS_IDEA) + #include <botan/idea.h> +#endif + +#if defined(BOTAN_HAS_KASUMI) + #include <botan/kasumi.h> +#endif + +#if defined(BOTAN_HAS_LION) + #include <botan/lion.h> +#endif + +#if defined(BOTAN_HAS_MISTY1) + #include <botan/misty1.h> +#endif + +#if defined(BOTAN_HAS_NOEKEON) + #include <botan/noekeon.h> +#endif + +#if defined(BOTAN_HAS_SEED) + #include <botan/seed.h> +#endif + +#if defined(BOTAN_HAS_SERPENT) + #include <botan/serpent.h> +#endif + +#if defined(BOTAN_HAS_SHACAL2) + #include <botan/shacal2.h> +#endif + +#if defined(BOTAN_HAS_SM4) + #include <botan/sm4.h> +#endif + +#if defined(BOTAN_HAS_TWOFISH) + #include <botan/twofish.h> +#endif + +#if defined(BOTAN_HAS_THREEFISH_512) + #include <botan/threefish_512.h> +#endif + +#if defined(BOTAN_HAS_XTEA) + #include <botan/xtea.h> +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include <botan/internal/openssl.h> +#endif + +namespace Botan { + +std::unique_ptr<BlockCipher> +BlockCipher::create(const std::string& algo, + const std::string& provider) + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + if(auto bc = make_openssl_block_cipher(algo)) + return bc; + + if(!provider.empty()) + return nullptr; + } +#endif + + // TODO: CommonCrypto + // TODO: CryptoAPI + // TODO: /dev/crypto + + // Only base providers from here on out + if(provider.empty() == false && provider != "base") + return nullptr; + +#if defined(BOTAN_HAS_AES) + if(algo == "AES-128") + { + return std::unique_ptr<BlockCipher>(new AES_128); + } + + if(algo == "AES-192") + { + return std::unique_ptr<BlockCipher>(new AES_192); + } + + if(algo == "AES-256") + { + return std::unique_ptr<BlockCipher>(new AES_256); + } +#endif + +#if defined(BOTAN_HAS_ARIA) + if(algo == "ARIA-128") + { + return std::unique_ptr<BlockCipher>(new ARIA_128); + } + + if(algo == "ARIA-192") + { + return std::unique_ptr<BlockCipher>(new ARIA_192); + } + + if(algo == "ARIA-256") + { + return std::unique_ptr<BlockCipher>(new ARIA_256); + } +#endif + +#if defined(BOTAN_HAS_SERPENT) + if(algo == "Serpent") + { + return std::unique_ptr<BlockCipher>(new Serpent); + } +#endif + +#if defined(BOTAN_HAS_SHACAL2) + if(algo == "SHACAL2") + { + return std::unique_ptr<BlockCipher>(new SHACAL2); + } +#endif + +#if defined(BOTAN_HAS_TWOFISH) + if(algo == "Twofish") + { + return std::unique_ptr<BlockCipher>(new Twofish); + } +#endif + +#if defined(BOTAN_HAS_THREEFISH_512) + if(algo == "Threefish-512") + { + return std::unique_ptr<BlockCipher>(new Threefish_512); + } +#endif + +#if defined(BOTAN_HAS_BLOWFISH) + if(algo == "Blowfish") + { + return std::unique_ptr<BlockCipher>(new Blowfish); + } +#endif + +#if defined(BOTAN_HAS_CAMELLIA) + if(algo == "Camellia-128") + { + return std::unique_ptr<BlockCipher>(new Camellia_128); + } + + if(algo == "Camellia-192") + { + return std::unique_ptr<BlockCipher>(new Camellia_192); + } + + if(algo == "Camellia-256") + { + return std::unique_ptr<BlockCipher>(new Camellia_256); + } +#endif + +#if defined(BOTAN_HAS_DES) + if(algo == "DES") + { + return std::unique_ptr<BlockCipher>(new DES); + } + + if(algo == "DESX") + { + return std::unique_ptr<BlockCipher>(new DESX); + } + + if(algo == "TripleDES" || algo == "3DES" || algo == "DES-EDE") + { + return std::unique_ptr<BlockCipher>(new TripleDES); + } +#endif + +#if defined(BOTAN_HAS_NOEKEON) + if(algo == "Noekeon") + { + return std::unique_ptr<BlockCipher>(new Noekeon); + } +#endif + +#if defined(BOTAN_HAS_CAST_128) + if(algo == "CAST-128" || algo == "CAST5") + { + return std::unique_ptr<BlockCipher>(new CAST_128); + } +#endif + +#if defined(BOTAN_HAS_CAST_256) + if(algo == "CAST-256") + { + return std::unique_ptr<BlockCipher>(new CAST_256); + } +#endif + +#if defined(BOTAN_HAS_IDEA) + if(algo == "IDEA") + { + return std::unique_ptr<BlockCipher>(new IDEA); + } +#endif + +#if defined(BOTAN_HAS_KASUMI) + if(algo == "KASUMI") + { + return std::unique_ptr<BlockCipher>(new KASUMI); + } +#endif + +#if defined(BOTAN_HAS_MISTY1) + if(algo == "MISTY1") + { + return std::unique_ptr<BlockCipher>(new MISTY1); + } +#endif + +#if defined(BOTAN_HAS_SEED) + if(algo == "SEED") + { + return std::unique_ptr<BlockCipher>(new SEED); + } +#endif + +#if defined(BOTAN_HAS_SM4) + if(algo == "SM4") + { + return std::unique_ptr<BlockCipher>(new SM4); + } +#endif + +#if defined(BOTAN_HAS_XTEA) + if(algo == "XTEA") + { + return std::unique_ptr<BlockCipher>(new XTEA); + } +#endif + + const SCAN_Name req(algo); + +#if defined(BOTAN_HAS_GOST_28147_89) + if(req.algo_name() == "GOST-28147-89") + { + return std::unique_ptr<BlockCipher>(new GOST_28147_89(req.arg(0, "R3411_94_TestParam"))); + } +#endif + +#if defined(BOTAN_HAS_CASCADE) + if(req.algo_name() == "Cascade" && req.arg_count() == 2) + { + std::unique_ptr<BlockCipher> c1(BlockCipher::create(req.arg(0))); + std::unique_ptr<BlockCipher> c2(BlockCipher::create(req.arg(1))); + + if(c1 && c2) + return std::unique_ptr<BlockCipher>(new Cascade_Cipher(c1.release(), c2.release())); + } +#endif + +#if defined(BOTAN_HAS_LION) + if(req.algo_name() == "Lion" && req.arg_count_between(2, 3)) + { + std::unique_ptr<HashFunction> hash(HashFunction::create(req.arg(0))); + std::unique_ptr<StreamCipher> stream(StreamCipher::create(req.arg(1))); + + if(hash && stream) + { + const size_t block_size = req.arg_as_integer(2, 1024); + return std::unique_ptr<BlockCipher>(new Lion(hash.release(), stream.release(), block_size)); + } + } +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +//static +std::unique_ptr<BlockCipher> +BlockCipher::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto bc = BlockCipher::create(algo, provider)) + { + return bc; + } + throw Lookup_Error("Block cipher", algo, provider); + } + +std::vector<std::string> BlockCipher::providers(const std::string& algo) + { + return probe_providers_of<BlockCipher>(algo, { "base", "openssl" }); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/block/block_cipher.h b/src/libs/3rdparty/botan/src/lib/block/block_cipher.h new file mode 100644 index 0000000000..a365397fa3 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/block_cipher.h @@ -0,0 +1,237 @@ +/* +* Block Cipher Base Class +* (C) 1999-2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BLOCK_CIPHER_H_ +#define BOTAN_BLOCK_CIPHER_H_ + +#include <botan/sym_algo.h> +#include <string> +#include <memory> + +namespace Botan { + +/** +* This class represents a block cipher object. +*/ +class BOTAN_PUBLIC_API(2,0) BlockCipher : public SymmetricAlgorithm + { + public: + + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to choose + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr<BlockCipher> + create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name, or throw if the + * algo/provider combination cannot be found. If provider is + * empty then best available is chosen. + */ + static std::unique_ptr<BlockCipher> + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + * @param algo_spec algorithm name + */ + static std::vector<std::string> providers(const std::string& algo_spec); + + /** + * @return block size of this algorithm + */ + virtual size_t block_size() const = 0; + + /** + * @return native parallelism of this cipher in blocks + */ + virtual size_t parallelism() const { return 1; } + + /** + * @return prefererred parallelism of this cipher in bytes + */ + size_t parallel_bytes() const + { + return parallelism() * block_size() * BOTAN_BLOCK_CIPHER_PAR_MULT; + } + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + + /** + * Encrypt a block. + * @param in The plaintext block to be encrypted as a byte array. + * Must be of length block_size(). + * @param out The byte array designated to hold the encrypted block. + * Must be of length block_size(). + */ + void encrypt(const uint8_t in[], uint8_t out[]) const + { encrypt_n(in, out, 1); } + + /** + * Decrypt a block. + * @param in The ciphertext block to be decypted as a byte array. + * Must be of length block_size(). + * @param out The byte array designated to hold the decrypted block. + * Must be of length block_size(). + */ + void decrypt(const uint8_t in[], uint8_t out[]) const + { decrypt_n(in, out, 1); } + + /** + * Encrypt a block. + * @param block the plaintext block to be encrypted + * Must be of length block_size(). Will hold the result when the function + * has finished. + */ + void encrypt(uint8_t block[]) const { encrypt_n(block, block, 1); } + + /** + * Decrypt a block. + * @param block the ciphertext block to be decrypted + * Must be of length block_size(). Will hold the result when the function + * has finished. + */ + void decrypt(uint8_t block[]) const { decrypt_n(block, block, 1); } + + /** + * Encrypt one or more blocks + * @param block the input/output buffer (multiple of block_size()) + */ + template<typename Alloc> + void encrypt(std::vector<uint8_t, Alloc>& block) const + { + return encrypt_n(block.data(), block.data(), block.size() / block_size()); + } + + /** + * Decrypt one or more blocks + * @param block the input/output buffer (multiple of block_size()) + */ + template<typename Alloc> + void decrypt(std::vector<uint8_t, Alloc>& block) const + { + return decrypt_n(block.data(), block.data(), block.size() / block_size()); + } + + /** + * Encrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + */ + template<typename Alloc, typename Alloc2> + void encrypt(const std::vector<uint8_t, Alloc>& in, + std::vector<uint8_t, Alloc2>& out) const + { + return encrypt_n(in.data(), out.data(), in.size() / block_size()); + } + + /** + * Decrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + */ + template<typename Alloc, typename Alloc2> + void decrypt(const std::vector<uint8_t, Alloc>& in, + std::vector<uint8_t, Alloc2>& out) const + { + return decrypt_n(in.data(), out.data(), in.size() / block_size()); + } + + /** + * Encrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + * @param blocks the number of blocks to process + */ + virtual void encrypt_n(const uint8_t in[], uint8_t out[], + size_t blocks) const = 0; + + /** + * Decrypt one or more blocks + * @param in the input buffer (multiple of block_size()) + * @param out the output buffer (same size as in) + * @param blocks the number of blocks to process + */ + virtual void decrypt_n(const uint8_t in[], uint8_t out[], + size_t blocks) const = 0; + + virtual void encrypt_n_xex(uint8_t data[], + const uint8_t mask[], + size_t blocks) const + { + const size_t BS = block_size(); + xor_buf(data, mask, blocks * BS); + encrypt_n(data, data, blocks); + xor_buf(data, mask, blocks * BS); + } + + virtual void decrypt_n_xex(uint8_t data[], + const uint8_t mask[], + size_t blocks) const + { + const size_t BS = block_size(); + xor_buf(data, mask, blocks * BS); + decrypt_n(data, data, blocks); + xor_buf(data, mask, blocks * BS); + } + + /** + * @return new object representing the same algorithm as *this + */ + virtual BlockCipher* clone() const = 0; + + virtual ~BlockCipher() = default; + }; + +/** +* Represents a block cipher with a single fixed block size +*/ +template<size_t BS, size_t KMIN, size_t KMAX = 0, size_t KMOD = 1> +class Block_Cipher_Fixed_Params : public BlockCipher + { + public: + enum { BLOCK_SIZE = BS }; + size_t block_size() const override { return BS; } + + // override to take advantage of compile time constant block size + void encrypt_n_xex(uint8_t data[], + const uint8_t mask[], + size_t blocks) const override + { + xor_buf(data, mask, blocks * BS); + encrypt_n(data, data, blocks); + xor_buf(data, mask, blocks * BS); + } + + void decrypt_n_xex(uint8_t data[], + const uint8_t mask[], + size_t blocks) const override + { + xor_buf(data, mask, blocks * BS); + decrypt_n(data, data, blocks); + xor_buf(data, mask, blocks * BS); + } + + Key_Length_Specification key_spec() const override + { + return Key_Length_Specification(KMIN, KMAX, KMOD); + } + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/block/des/des.cpp b/src/libs/3rdparty/botan/src/lib/block/des/des.cpp new file mode 100644 index 0000000000..885daa05ca --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/des/des.cpp @@ -0,0 +1,381 @@ +/* +* DES +* (C) 1999-2008,2018 Jack Lloyd +* +* Based on a public domain implemenation by Phil Karn (who in turn +* credited Richard Outerbridge and Jim Gillogly) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/des.h> +#include <botan/loadstor.h> + +namespace Botan { + +namespace { + +/* +* DES Key Schedule +*/ +void des_key_schedule(uint32_t round_key[32], const uint8_t key[8]) + { + static const uint8_t ROT[16] = { 1, 1, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 1 }; + + uint32_t C = ((key[7] & 0x80) << 20) | ((key[6] & 0x80) << 19) | + ((key[5] & 0x80) << 18) | ((key[4] & 0x80) << 17) | + ((key[3] & 0x80) << 16) | ((key[2] & 0x80) << 15) | + ((key[1] & 0x80) << 14) | ((key[0] & 0x80) << 13) | + ((key[7] & 0x40) << 13) | ((key[6] & 0x40) << 12) | + ((key[5] & 0x40) << 11) | ((key[4] & 0x40) << 10) | + ((key[3] & 0x40) << 9) | ((key[2] & 0x40) << 8) | + ((key[1] & 0x40) << 7) | ((key[0] & 0x40) << 6) | + ((key[7] & 0x20) << 6) | ((key[6] & 0x20) << 5) | + ((key[5] & 0x20) << 4) | ((key[4] & 0x20) << 3) | + ((key[3] & 0x20) << 2) | ((key[2] & 0x20) << 1) | + ((key[1] & 0x20) ) | ((key[0] & 0x20) >> 1) | + ((key[7] & 0x10) >> 1) | ((key[6] & 0x10) >> 2) | + ((key[5] & 0x10) >> 3) | ((key[4] & 0x10) >> 4); + uint32_t D = ((key[7] & 0x02) << 26) | ((key[6] & 0x02) << 25) | + ((key[5] & 0x02) << 24) | ((key[4] & 0x02) << 23) | + ((key[3] & 0x02) << 22) | ((key[2] & 0x02) << 21) | + ((key[1] & 0x02) << 20) | ((key[0] & 0x02) << 19) | + ((key[7] & 0x04) << 17) | ((key[6] & 0x04) << 16) | + ((key[5] & 0x04) << 15) | ((key[4] & 0x04) << 14) | + ((key[3] & 0x04) << 13) | ((key[2] & 0x04) << 12) | + ((key[1] & 0x04) << 11) | ((key[0] & 0x04) << 10) | + ((key[7] & 0x08) << 8) | ((key[6] & 0x08) << 7) | + ((key[5] & 0x08) << 6) | ((key[4] & 0x08) << 5) | + ((key[3] & 0x08) << 4) | ((key[2] & 0x08) << 3) | + ((key[1] & 0x08) << 2) | ((key[0] & 0x08) << 1) | + ((key[3] & 0x10) >> 1) | ((key[2] & 0x10) >> 2) | + ((key[1] & 0x10) >> 3) | ((key[0] & 0x10) >> 4); + + for(size_t i = 0; i != 16; ++i) + { + C = ((C << ROT[i]) | (C >> (28-ROT[i]))) & 0x0FFFFFFF; + D = ((D << ROT[i]) | (D >> (28-ROT[i]))) & 0x0FFFFFFF; + round_key[2*i ] = ((C & 0x00000010) << 22) | ((C & 0x00000800) << 17) | + ((C & 0x00000020) << 16) | ((C & 0x00004004) << 15) | + ((C & 0x00000200) << 11) | ((C & 0x00020000) << 10) | + ((C & 0x01000000) >> 6) | ((C & 0x00100000) >> 4) | + ((C & 0x00010000) << 3) | ((C & 0x08000000) >> 2) | + ((C & 0x00800000) << 1) | ((D & 0x00000010) << 8) | + ((D & 0x00000002) << 7) | ((D & 0x00000001) << 2) | + ((D & 0x00000200) ) | ((D & 0x00008000) >> 2) | + ((D & 0x00000088) >> 3) | ((D & 0x00001000) >> 7) | + ((D & 0x00080000) >> 9) | ((D & 0x02020000) >> 14) | + ((D & 0x00400000) >> 21); + round_key[2*i+1] = ((C & 0x00000001) << 28) | ((C & 0x00000082) << 18) | + ((C & 0x00002000) << 14) | ((C & 0x00000100) << 10) | + ((C & 0x00001000) << 9) | ((C & 0x00040000) << 6) | + ((C & 0x02400000) << 4) | ((C & 0x00008000) << 2) | + ((C & 0x00200000) >> 1) | ((C & 0x04000000) >> 10) | + ((D & 0x00000020) << 6) | ((D & 0x00000100) ) | + ((D & 0x00000800) >> 1) | ((D & 0x00000040) >> 3) | + ((D & 0x00010000) >> 4) | ((D & 0x00000400) >> 5) | + ((D & 0x00004000) >> 10) | ((D & 0x04000000) >> 13) | + ((D & 0x00800000) >> 14) | ((D & 0x00100000) >> 18) | + ((D & 0x01000000) >> 24) | ((D & 0x08000000) >> 26); + } + } + +inline uint32_t spbox(uint32_t T0, uint32_t T1) + { + return DES_SPBOX1[get_byte(0, T0)] ^ DES_SPBOX2[get_byte(0, T1)] ^ + DES_SPBOX3[get_byte(1, T0)] ^ DES_SPBOX4[get_byte(1, T1)] ^ + DES_SPBOX5[get_byte(2, T0)] ^ DES_SPBOX6[get_byte(2, T1)] ^ + DES_SPBOX7[get_byte(3, T0)] ^ DES_SPBOX8[get_byte(3, T1)]; + } + +/* +* DES Encryption +*/ +inline void des_encrypt(uint32_t& Lr, uint32_t& Rr, + const uint32_t round_key[32]) + { + uint32_t L = Lr; + uint32_t R = Rr; + for(size_t i = 0; i != 16; i += 2) + { + L ^= spbox(rotr<4>(R) ^ round_key[2*i ], R ^ round_key[2*i+1]); + R ^= spbox(rotr<4>(L) ^ round_key[2*i+2], L ^ round_key[2*i+3]); + } + + Lr = L; + Rr = R; + } + +inline void des_encrypt_x2(uint32_t& L0r, uint32_t& R0r, + uint32_t& L1r, uint32_t& R1r, + const uint32_t round_key[32]) + { + uint32_t L0 = L0r; + uint32_t R0 = R0r; + uint32_t L1 = L1r; + uint32_t R1 = R1r; + + for(size_t i = 0; i != 16; i += 2) + { + L0 ^= spbox(rotr<4>(R0) ^ round_key[2*i ], R0 ^ round_key[2*i+1]); + L1 ^= spbox(rotr<4>(R1) ^ round_key[2*i ], R1 ^ round_key[2*i+1]); + + R0 ^= spbox(rotr<4>(L0) ^ round_key[2*i+2], L0 ^ round_key[2*i+3]); + R1 ^= spbox(rotr<4>(L1) ^ round_key[2*i+2], L1 ^ round_key[2*i+3]); + } + + L0r = L0; + R0r = R0; + L1r = L1; + R1r = R1; + } + +/* +* DES Decryption +*/ +inline void des_decrypt(uint32_t& Lr, uint32_t& Rr, + const uint32_t round_key[32]) + { + uint32_t L = Lr; + uint32_t R = Rr; + for(size_t i = 16; i != 0; i -= 2) + { + L ^= spbox(rotr<4>(R) ^ round_key[2*i - 2], R ^ round_key[2*i - 1]); + R ^= spbox(rotr<4>(L) ^ round_key[2*i - 4], L ^ round_key[2*i - 3]); + } + Lr = L; + Rr = R; + } + +inline void des_decrypt_x2(uint32_t& L0r, uint32_t& R0r, + uint32_t& L1r, uint32_t& R1r, + const uint32_t round_key[32]) + { + uint32_t L0 = L0r; + uint32_t R0 = R0r; + uint32_t L1 = L1r; + uint32_t R1 = R1r; + + for(size_t i = 16; i != 0; i -= 2) + { + L0 ^= spbox(rotr<4>(R0) ^ round_key[2*i - 2], R0 ^ round_key[2*i - 1]); + L1 ^= spbox(rotr<4>(R1) ^ round_key[2*i - 2], R1 ^ round_key[2*i - 1]); + + R0 ^= spbox(rotr<4>(L0) ^ round_key[2*i - 4], L0 ^ round_key[2*i - 3]); + R1 ^= spbox(rotr<4>(L1) ^ round_key[2*i - 4], L1 ^ round_key[2*i - 3]); + } + + L0r = L0; + R0r = R0; + L1r = L1; + R1r = R1; + } + +inline void des_IP(uint32_t& L, uint32_t& R, const uint8_t block[]) + { + uint64_t T = (DES_IPTAB1[block[0]] ) | (DES_IPTAB1[block[1]] << 1) | + (DES_IPTAB1[block[2]] << 2) | (DES_IPTAB1[block[3]] << 3) | + (DES_IPTAB1[block[4]] << 4) | (DES_IPTAB1[block[5]] << 5) | + (DES_IPTAB1[block[6]] << 6) | (DES_IPTAB2[block[7]] ); + + L = static_cast<uint32_t>(T >> 32); + R = static_cast<uint32_t>(T); + } + +inline void des_FP(uint32_t L, uint32_t R, uint8_t out[]) + { + uint64_t T = (DES_FPTAB1[get_byte(0, L)] << 5) | (DES_FPTAB1[get_byte(1, L)] << 3) | + (DES_FPTAB1[get_byte(2, L)] << 1) | (DES_FPTAB2[get_byte(3, L)] << 1) | + (DES_FPTAB1[get_byte(0, R)] << 4) | (DES_FPTAB1[get_byte(1, R)] << 2) | + (DES_FPTAB1[get_byte(2, R)] ) | (DES_FPTAB2[get_byte(3, R)] ); + T = rotl<32>(T); + + store_be(T, out); + } + +} + +/* +* DES Encryption +*/ +void DES::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_round_key.empty() == false); + + while(blocks >= 2) + { + uint32_t L0, R0; + uint32_t L1, R1; + + des_IP(L0, R0, in); + des_IP(L1, R1, in + BLOCK_SIZE); + + des_encrypt_x2(L0, R0, L1, R1, m_round_key.data()); + + des_FP(L0, R0, out); + des_FP(L1, R1, out + BLOCK_SIZE); + + in += 2*BLOCK_SIZE; + out += 2*BLOCK_SIZE; + blocks -= 2; + } + + for(size_t i = 0; i < blocks; ++i) + { + uint32_t L, R; + des_IP(L, R, in + BLOCK_SIZE*i); + des_encrypt(L, R, m_round_key.data()); + des_FP(L, R, out + BLOCK_SIZE*i); + } + } + +/* +* DES Decryption +*/ +void DES::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_round_key.empty() == false); + + while(blocks >= 2) + { + uint32_t L0, R0; + uint32_t L1, R1; + + des_IP(L0, R0, in); + des_IP(L1, R1, in + BLOCK_SIZE); + + des_decrypt_x2(L0, R0, L1, R1, m_round_key.data()); + + des_FP(L0, R0, out); + des_FP(L1, R1, out + BLOCK_SIZE); + + in += 2*BLOCK_SIZE; + out += 2*BLOCK_SIZE; + blocks -= 2; + } + + for(size_t i = 0; i < blocks; ++i) + { + uint32_t L, R; + des_IP(L, R, in + BLOCK_SIZE*i); + des_decrypt(L, R, m_round_key.data()); + des_FP(L, R, out + BLOCK_SIZE*i); + } + } + +/* +* DES Key Schedule +*/ +void DES::key_schedule(const uint8_t key[], size_t) + { + m_round_key.resize(32); + des_key_schedule(m_round_key.data(), key); + } + +void DES::clear() + { + zap(m_round_key); + } + +/* +* TripleDES Encryption +*/ +void TripleDES::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_round_key.empty() == false); + + while(blocks >= 2) + { + uint32_t L0, R0; + uint32_t L1, R1; + + des_IP(L0, R0, in); + des_IP(L1, R1, in + BLOCK_SIZE); + + des_encrypt_x2(L0, R0, L1, R1, &m_round_key[0]); + des_decrypt_x2(R0, L0, R1, L1, &m_round_key[32]); + des_encrypt_x2(L0, R0, L1, R1, &m_round_key[64]); + + des_FP(L0, R0, out); + des_FP(L1, R1, out + BLOCK_SIZE); + + in += 2*BLOCK_SIZE; + out += 2*BLOCK_SIZE; + blocks -= 2; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t L, R; + des_IP(L, R, in + BLOCK_SIZE*i); + + des_encrypt(L, R, &m_round_key[0]); + des_decrypt(R, L, &m_round_key[32]); + des_encrypt(L, R, &m_round_key[64]); + + des_FP(L, R, out + BLOCK_SIZE*i); + } + } + +/* +* TripleDES Decryption +*/ +void TripleDES::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_round_key.empty() == false); + + while(blocks >= 2) + { + uint32_t L0, R0; + uint32_t L1, R1; + + des_IP(L0, R0, in); + des_IP(L1, R1, in + BLOCK_SIZE); + + des_decrypt_x2(L0, R0, L1, R1, &m_round_key[64]); + des_encrypt_x2(R0, L0, R1, L1, &m_round_key[32]); + des_decrypt_x2(L0, R0, L1, R1, &m_round_key[0]); + + des_FP(L0, R0, out); + des_FP(L1, R1, out + BLOCK_SIZE); + + in += 2*BLOCK_SIZE; + out += 2*BLOCK_SIZE; + blocks -= 2; + } + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t L, R; + des_IP(L, R, in + BLOCK_SIZE*i); + + des_decrypt(L, R, &m_round_key[64]); + des_encrypt(R, L, &m_round_key[32]); + des_decrypt(L, R, &m_round_key[0]); + + des_FP(L, R, out + BLOCK_SIZE*i); + } + } + +/* +* TripleDES Key Schedule +*/ +void TripleDES::key_schedule(const uint8_t key[], size_t length) + { + m_round_key.resize(3*32); + des_key_schedule(&m_round_key[0], key); + des_key_schedule(&m_round_key[32], key + 8); + + if(length == 24) + des_key_schedule(&m_round_key[64], key + 16); + else + copy_mem(&m_round_key[64], &m_round_key[0], 32); + } + +void TripleDES::clear() + { + zap(m_round_key); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/block/des/des.h b/src/libs/3rdparty/botan/src/lib/block/des/des.h new file mode 100644 index 0000000000..bdedeff642 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/des/des.h @@ -0,0 +1,70 @@ +/* +* DES +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DES_H_ +#define BOTAN_DES_H_ + +#include <botan/block_cipher.h> + +namespace Botan { + +/** +* DES +*/ +class BOTAN_PUBLIC_API(2,0) DES final : public Block_Cipher_Fixed_Params<8, 8> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "DES"; } + BlockCipher* clone() const override { return new DES; } + private: + void key_schedule(const uint8_t[], size_t) override; + + secure_vector<uint32_t> m_round_key; + }; + +/** +* Triple DES +*/ +class BOTAN_PUBLIC_API(2,0) TripleDES final : public Block_Cipher_Fixed_Params<8, 16, 24, 8> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "TripleDES"; } + BlockCipher* clone() const override { return new TripleDES; } + private: + void key_schedule(const uint8_t[], size_t) override; + + secure_vector<uint32_t> m_round_key; + }; + +/* +* DES Tables +*/ +extern const uint32_t DES_SPBOX1[256]; +extern const uint32_t DES_SPBOX2[256]; +extern const uint32_t DES_SPBOX3[256]; +extern const uint32_t DES_SPBOX4[256]; +extern const uint32_t DES_SPBOX5[256]; +extern const uint32_t DES_SPBOX6[256]; +extern const uint32_t DES_SPBOX7[256]; +extern const uint32_t DES_SPBOX8[256]; + +extern const uint64_t DES_IPTAB1[256]; +extern const uint64_t DES_IPTAB2[256]; +extern const uint64_t DES_FPTAB1[256]; +extern const uint64_t DES_FPTAB2[256]; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/block/des/des_tab.cpp b/src/libs/3rdparty/botan/src/lib/block/des/des_tab.cpp new file mode 100644 index 0000000000..c64b6baf62 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/des/des_tab.cpp @@ -0,0 +1,636 @@ +/* +* Substitution/Permutation Tables for DES +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/des.h> + +namespace Botan { + +const uint32_t DES_SPBOX1[256] = { + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, + 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, + 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, + 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, + 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, + 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004, 0x01010400, 0x00000000, + 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, + 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, + 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, + 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, + 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, + 0x00000000, 0x01010004, 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, + 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, + 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, + 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, + 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, + 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004, + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, + 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, + 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, + 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, + 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, + 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 }; + +const uint32_t DES_SPBOX2[256] = { + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, + 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, + 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, + 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, + 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, + 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000, 0x80108020, 0x80008000, + 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, + 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, + 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, + 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, + 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, + 0x80108020, 0x00108000, 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, + 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, + 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, + 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, + 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, + 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000, + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, + 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, + 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, + 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, + 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, + 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 }; + +const uint32_t DES_SPBOX3[256] = { + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, + 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, + 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, + 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, + 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, + 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200, 0x00000208, 0x08020200, + 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, + 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, + 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, + 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, + 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, + 0x08020008, 0x00020200, 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, + 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, + 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, + 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, + 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, + 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200, + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, + 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, + 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, + 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, + 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, + 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 }; + +const uint32_t DES_SPBOX4[256] = { + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, + 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, + 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, + 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, + 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080, 0x00802001, 0x00002081, + 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, + 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, + 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, + 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, + 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, + 0x00002000, 0x00802080, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, + 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, + 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, + 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, + 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, + 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, + 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, + 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, + 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, + 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 }; + +const uint32_t DES_SPBOX5[256] = { + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, + 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, + 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, + 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, + 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, + 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100, 0x00000100, 0x02080100, + 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, + 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, + 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, + 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, + 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, + 0x02080100, 0x40000100, 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, + 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, + 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, + 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, + 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, + 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100, + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, + 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, + 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, + 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, + 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, + 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 }; + +const uint32_t DES_SPBOX6[256] = { + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, + 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, + 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, + 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, + 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, + 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010, 0x20000010, 0x20400000, + 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, + 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, + 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, + 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, + 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, + 0x00400010, 0x20004010, 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, + 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, + 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, + 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, + 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, + 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010, + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, + 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, + 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, + 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, + 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, + 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 }; + +const uint32_t DES_SPBOX7[256] = { + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, + 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, + 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, + 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, + 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, + 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002, 0x00200000, 0x04200002, + 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, + 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, + 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, + 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, + 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, + 0x00000800, 0x00200002, 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, + 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, + 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, + 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, + 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, + 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002, + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, + 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, + 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, + 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, + 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, + 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 }; + +const uint32_t DES_SPBOX8[256] = { + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, + 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, + 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, + 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, + 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000, 0x10001040, 0x00001000, + 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, + 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, + 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, + 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, + 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, + 0x10000000, 0x10041000, 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, + 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, + 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, + 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, + 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, + 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000, + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, + 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, + 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, + 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, + 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, + 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 }; + +const uint64_t DES_IPTAB1[256] = { +0x0000000000000000, 0x0000000200000000, 0x0000000000000002, 0x0000000200000002, +0x0000020000000000, 0x0000020200000000, 0x0000020000000002, 0x0000020200000002, +0x0000000000000200, 0x0000000200000200, 0x0000000000000202, 0x0000000200000202, +0x0000020000000200, 0x0000020200000200, 0x0000020000000202, 0x0000020200000202, +0x0002000000000000, 0x0002000200000000, 0x0002000000000002, 0x0002000200000002, +0x0002020000000000, 0x0002020200000000, 0x0002020000000002, 0x0002020200000002, +0x0002000000000200, 0x0002000200000200, 0x0002000000000202, 0x0002000200000202, +0x0002020000000200, 0x0002020200000200, 0x0002020000000202, 0x0002020200000202, +0x0000000000020000, 0x0000000200020000, 0x0000000000020002, 0x0000000200020002, +0x0000020000020000, 0x0000020200020000, 0x0000020000020002, 0x0000020200020002, +0x0000000000020200, 0x0000000200020200, 0x0000000000020202, 0x0000000200020202, +0x0000020000020200, 0x0000020200020200, 0x0000020000020202, 0x0000020200020202, +0x0002000000020000, 0x0002000200020000, 0x0002000000020002, 0x0002000200020002, +0x0002020000020000, 0x0002020200020000, 0x0002020000020002, 0x0002020200020002, +0x0002000000020200, 0x0002000200020200, 0x0002000000020202, 0x0002000200020202, +0x0002020000020200, 0x0002020200020200, 0x0002020000020202, 0x0002020200020202, +0x0200000000000000, 0x0200000200000000, 0x0200000000000002, 0x0200000200000002, +0x0200020000000000, 0x0200020200000000, 0x0200020000000002, 0x0200020200000002, +0x0200000000000200, 0x0200000200000200, 0x0200000000000202, 0x0200000200000202, +0x0200020000000200, 0x0200020200000200, 0x0200020000000202, 0x0200020200000202, +0x0202000000000000, 0x0202000200000000, 0x0202000000000002, 0x0202000200000002, +0x0202020000000000, 0x0202020200000000, 0x0202020000000002, 0x0202020200000002, +0x0202000000000200, 0x0202000200000200, 0x0202000000000202, 0x0202000200000202, +0x0202020000000200, 0x0202020200000200, 0x0202020000000202, 0x0202020200000202, +0x0200000000020000, 0x0200000200020000, 0x0200000000020002, 0x0200000200020002, +0x0200020000020000, 0x0200020200020000, 0x0200020000020002, 0x0200020200020002, +0x0200000000020200, 0x0200000200020200, 0x0200000000020202, 0x0200000200020202, +0x0200020000020200, 0x0200020200020200, 0x0200020000020202, 0x0200020200020202, +0x0202000000020000, 0x0202000200020000, 0x0202000000020002, 0x0202000200020002, +0x0202020000020000, 0x0202020200020000, 0x0202020000020002, 0x0202020200020002, +0x0202000000020200, 0x0202000200020200, 0x0202000000020202, 0x0202000200020202, +0x0202020000020200, 0x0202020200020200, 0x0202020000020202, 0x0202020200020202, +0x0000000002000000, 0x0000000202000000, 0x0000000002000002, 0x0000000202000002, +0x0000020002000000, 0x0000020202000000, 0x0000020002000002, 0x0000020202000002, +0x0000000002000200, 0x0000000202000200, 0x0000000002000202, 0x0000000202000202, +0x0000020002000200, 0x0000020202000200, 0x0000020002000202, 0x0000020202000202, +0x0002000002000000, 0x0002000202000000, 0x0002000002000002, 0x0002000202000002, +0x0002020002000000, 0x0002020202000000, 0x0002020002000002, 0x0002020202000002, +0x0002000002000200, 0x0002000202000200, 0x0002000002000202, 0x0002000202000202, +0x0002020002000200, 0x0002020202000200, 0x0002020002000202, 0x0002020202000202, +0x0000000002020000, 0x0000000202020000, 0x0000000002020002, 0x0000000202020002, +0x0000020002020000, 0x0000020202020000, 0x0000020002020002, 0x0000020202020002, +0x0000000002020200, 0x0000000202020200, 0x0000000002020202, 0x0000000202020202, +0x0000020002020200, 0x0000020202020200, 0x0000020002020202, 0x0000020202020202, +0x0002000002020000, 0x0002000202020000, 0x0002000002020002, 0x0002000202020002, +0x0002020002020000, 0x0002020202020000, 0x0002020002020002, 0x0002020202020002, +0x0002000002020200, 0x0002000202020200, 0x0002000002020202, 0x0002000202020202, +0x0002020002020200, 0x0002020202020200, 0x0002020002020202, 0x0002020202020202, +0x0200000002000000, 0x0200000202000000, 0x0200000002000002, 0x0200000202000002, +0x0200020002000000, 0x0200020202000000, 0x0200020002000002, 0x0200020202000002, +0x0200000002000200, 0x0200000202000200, 0x0200000002000202, 0x0200000202000202, +0x0200020002000200, 0x0200020202000200, 0x0200020002000202, 0x0200020202000202, +0x0202000002000000, 0x0202000202000000, 0x0202000002000002, 0x0202000202000002, +0x0202020002000000, 0x0202020202000000, 0x0202020002000002, 0x0202020202000002, +0x0202000002000200, 0x0202000202000200, 0x0202000002000202, 0x0202000202000202, +0x0202020002000200, 0x0202020202000200, 0x0202020002000202, 0x0202020202000202, +0x0200000002020000, 0x0200000202020000, 0x0200000002020002, 0x0200000202020002, +0x0200020002020000, 0x0200020202020000, 0x0200020002020002, 0x0200020202020002, +0x0200000002020200, 0x0200000202020200, 0x0200000002020202, 0x0200000202020202, +0x0200020002020200, 0x0200020202020200, 0x0200020002020202, 0x0200020202020202, +0x0202000002020000, 0x0202000202020000, 0x0202000002020002, 0x0202000202020002, +0x0202020002020000, 0x0202020202020000, 0x0202020002020002, 0x0202020202020002, +0x0202000002020200, 0x0202000202020200, 0x0202000002020202, 0x0202000202020202, +0x0202020002020200, 0x0202020202020200, 0x0202020002020202, 0x0202020202020202 }; + +const uint64_t DES_IPTAB2[256] = { +0x0000000000000000, 0x0000010000000000, 0x0000000000000100, 0x0000010000000100, +0x0001000000000000, 0x0001010000000000, 0x0001000000000100, 0x0001010000000100, +0x0000000000010000, 0x0000010000010000, 0x0000000000010100, 0x0000010000010100, +0x0001000000010000, 0x0001010000010000, 0x0001000000010100, 0x0001010000010100, +0x0100000000000000, 0x0100010000000000, 0x0100000000000100, 0x0100010000000100, +0x0101000000000000, 0x0101010000000000, 0x0101000000000100, 0x0101010000000100, +0x0100000000010000, 0x0100010000010000, 0x0100000000010100, 0x0100010000010100, +0x0101000000010000, 0x0101010000010000, 0x0101000000010100, 0x0101010000010100, +0x0000000001000000, 0x0000010001000000, 0x0000000001000100, 0x0000010001000100, +0x0001000001000000, 0x0001010001000000, 0x0001000001000100, 0x0001010001000100, +0x0000000001010000, 0x0000010001010000, 0x0000000001010100, 0x0000010001010100, +0x0001000001010000, 0x0001010001010000, 0x0001000001010100, 0x0001010001010100, +0x0100000001000000, 0x0100010001000000, 0x0100000001000100, 0x0100010001000100, +0x0101000001000000, 0x0101010001000000, 0x0101000001000100, 0x0101010001000100, +0x0100000001010000, 0x0100010001010000, 0x0100000001010100, 0x0100010001010100, +0x0101000001010000, 0x0101010001010000, 0x0101000001010100, 0x0101010001010100, +0x0000000100000000, 0x0000010100000000, 0x0000000100000100, 0x0000010100000100, +0x0001000100000000, 0x0001010100000000, 0x0001000100000100, 0x0001010100000100, +0x0000000100010000, 0x0000010100010000, 0x0000000100010100, 0x0000010100010100, +0x0001000100010000, 0x0001010100010000, 0x0001000100010100, 0x0001010100010100, +0x0100000100000000, 0x0100010100000000, 0x0100000100000100, 0x0100010100000100, +0x0101000100000000, 0x0101010100000000, 0x0101000100000100, 0x0101010100000100, +0x0100000100010000, 0x0100010100010000, 0x0100000100010100, 0x0100010100010100, +0x0101000100010000, 0x0101010100010000, 0x0101000100010100, 0x0101010100010100, +0x0000000101000000, 0x0000010101000000, 0x0000000101000100, 0x0000010101000100, +0x0001000101000000, 0x0001010101000000, 0x0001000101000100, 0x0001010101000100, +0x0000000101010000, 0x0000010101010000, 0x0000000101010100, 0x0000010101010100, +0x0001000101010000, 0x0001010101010000, 0x0001000101010100, 0x0001010101010100, +0x0100000101000000, 0x0100010101000000, 0x0100000101000100, 0x0100010101000100, +0x0101000101000000, 0x0101010101000000, 0x0101000101000100, 0x0101010101000100, +0x0100000101010000, 0x0100010101010000, 0x0100000101010100, 0x0100010101010100, +0x0101000101010000, 0x0101010101010000, 0x0101000101010100, 0x0101010101010100, +0x0000000000000001, 0x0000010000000001, 0x0000000000000101, 0x0000010000000101, +0x0001000000000001, 0x0001010000000001, 0x0001000000000101, 0x0001010000000101, +0x0000000000010001, 0x0000010000010001, 0x0000000000010101, 0x0000010000010101, +0x0001000000010001, 0x0001010000010001, 0x0001000000010101, 0x0001010000010101, +0x0100000000000001, 0x0100010000000001, 0x0100000000000101, 0x0100010000000101, +0x0101000000000001, 0x0101010000000001, 0x0101000000000101, 0x0101010000000101, +0x0100000000010001, 0x0100010000010001, 0x0100000000010101, 0x0100010000010101, +0x0101000000010001, 0x0101010000010001, 0x0101000000010101, 0x0101010000010101, +0x0000000001000001, 0x0000010001000001, 0x0000000001000101, 0x0000010001000101, +0x0001000001000001, 0x0001010001000001, 0x0001000001000101, 0x0001010001000101, +0x0000000001010001, 0x0000010001010001, 0x0000000001010101, 0x0000010001010101, +0x0001000001010001, 0x0001010001010001, 0x0001000001010101, 0x0001010001010101, +0x0100000001000001, 0x0100010001000001, 0x0100000001000101, 0x0100010001000101, +0x0101000001000001, 0x0101010001000001, 0x0101000001000101, 0x0101010001000101, +0x0100000001010001, 0x0100010001010001, 0x0100000001010101, 0x0100010001010101, +0x0101000001010001, 0x0101010001010001, 0x0101000001010101, 0x0101010001010101, +0x0000000100000001, 0x0000010100000001, 0x0000000100000101, 0x0000010100000101, +0x0001000100000001, 0x0001010100000001, 0x0001000100000101, 0x0001010100000101, +0x0000000100010001, 0x0000010100010001, 0x0000000100010101, 0x0000010100010101, +0x0001000100010001, 0x0001010100010001, 0x0001000100010101, 0x0001010100010101, +0x0100000100000001, 0x0100010100000001, 0x0100000100000101, 0x0100010100000101, +0x0101000100000001, 0x0101010100000001, 0x0101000100000101, 0x0101010100000101, +0x0100000100010001, 0x0100010100010001, 0x0100000100010101, 0x0100010100010101, +0x0101000100010001, 0x0101010100010001, 0x0101000100010101, 0x0101010100010101, +0x0000000101000001, 0x0000010101000001, 0x0000000101000101, 0x0000010101000101, +0x0001000101000001, 0x0001010101000001, 0x0001000101000101, 0x0001010101000101, +0x0000000101010001, 0x0000010101010001, 0x0000000101010101, 0x0000010101010101, +0x0001000101010001, 0x0001010101010001, 0x0001000101010101, 0x0001010101010101, +0x0100000101000001, 0x0100010101000001, 0x0100000101000101, 0x0100010101000101, +0x0101000101000001, 0x0101010101000001, 0x0101000101000101, 0x0101010101000101, +0x0100000101010001, 0x0100010101010001, 0x0100000101010101, 0x0100010101010101, +0x0101000101010001, 0x0101010101010001, 0x0101000101010101, 0x0101010101010101 }; + +const uint64_t DES_FPTAB1[256] = { +0x0000000000000000, 0x0000000100000000, 0x0000000004000000, 0x0000000104000000, +0x0000000000040000, 0x0000000100040000, 0x0000000004040000, 0x0000000104040000, +0x0000000000000400, 0x0000000100000400, 0x0000000004000400, 0x0000000104000400, +0x0000000000040400, 0x0000000100040400, 0x0000000004040400, 0x0000000104040400, +0x0000000000000004, 0x0000000100000004, 0x0000000004000004, 0x0000000104000004, +0x0000000000040004, 0x0000000100040004, 0x0000000004040004, 0x0000000104040004, +0x0000000000000404, 0x0000000100000404, 0x0000000004000404, 0x0000000104000404, +0x0000000000040404, 0x0000000100040404, 0x0000000004040404, 0x0000000104040404, +0x0400000000000000, 0x0400000100000000, 0x0400000004000000, 0x0400000104000000, +0x0400000000040000, 0x0400000100040000, 0x0400000004040000, 0x0400000104040000, +0x0400000000000400, 0x0400000100000400, 0x0400000004000400, 0x0400000104000400, +0x0400000000040400, 0x0400000100040400, 0x0400000004040400, 0x0400000104040400, +0x0400000000000004, 0x0400000100000004, 0x0400000004000004, 0x0400000104000004, +0x0400000000040004, 0x0400000100040004, 0x0400000004040004, 0x0400000104040004, +0x0400000000000404, 0x0400000100000404, 0x0400000004000404, 0x0400000104000404, +0x0400000000040404, 0x0400000100040404, 0x0400000004040404, 0x0400000104040404, +0x0004000000000000, 0x0004000100000000, 0x0004000004000000, 0x0004000104000000, +0x0004000000040000, 0x0004000100040000, 0x0004000004040000, 0x0004000104040000, +0x0004000000000400, 0x0004000100000400, 0x0004000004000400, 0x0004000104000400, +0x0004000000040400, 0x0004000100040400, 0x0004000004040400, 0x0004000104040400, +0x0004000000000004, 0x0004000100000004, 0x0004000004000004, 0x0004000104000004, +0x0004000000040004, 0x0004000100040004, 0x0004000004040004, 0x0004000104040004, +0x0004000000000404, 0x0004000100000404, 0x0004000004000404, 0x0004000104000404, +0x0004000000040404, 0x0004000100040404, 0x0004000004040404, 0x0004000104040404, +0x0404000000000000, 0x0404000100000000, 0x0404000004000000, 0x0404000104000000, +0x0404000000040000, 0x0404000100040000, 0x0404000004040000, 0x0404000104040000, +0x0404000000000400, 0x0404000100000400, 0x0404000004000400, 0x0404000104000400, +0x0404000000040400, 0x0404000100040400, 0x0404000004040400, 0x0404000104040400, +0x0404000000000004, 0x0404000100000004, 0x0404000004000004, 0x0404000104000004, +0x0404000000040004, 0x0404000100040004, 0x0404000004040004, 0x0404000104040004, +0x0404000000000404, 0x0404000100000404, 0x0404000004000404, 0x0404000104000404, +0x0404000000040404, 0x0404000100040404, 0x0404000004040404, 0x0404000104040404, +0x0000040000000000, 0x0000040100000000, 0x0000040004000000, 0x0000040104000000, +0x0000040000040000, 0x0000040100040000, 0x0000040004040000, 0x0000040104040000, +0x0000040000000400, 0x0000040100000400, 0x0000040004000400, 0x0000040104000400, +0x0000040000040400, 0x0000040100040400, 0x0000040004040400, 0x0000040104040400, +0x0000040000000004, 0x0000040100000004, 0x0000040004000004, 0x0000040104000004, +0x0000040000040004, 0x0000040100040004, 0x0000040004040004, 0x0000040104040004, +0x0000040000000404, 0x0000040100000404, 0x0000040004000404, 0x0000040104000404, +0x0000040000040404, 0x0000040100040404, 0x0000040004040404, 0x0000040104040404, +0x0400040000000000, 0x0400040100000000, 0x0400040004000000, 0x0400040104000000, +0x0400040000040000, 0x0400040100040000, 0x0400040004040000, 0x0400040104040000, +0x0400040000000400, 0x0400040100000400, 0x0400040004000400, 0x0400040104000400, +0x0400040000040400, 0x0400040100040400, 0x0400040004040400, 0x0400040104040400, +0x0400040000000004, 0x0400040100000004, 0x0400040004000004, 0x0400040104000004, +0x0400040000040004, 0x0400040100040004, 0x0400040004040004, 0x0400040104040004, +0x0400040000000404, 0x0400040100000404, 0x0400040004000404, 0x0400040104000404, +0x0400040000040404, 0x0400040100040404, 0x0400040004040404, 0x0400040104040404, +0x0004040000000000, 0x0004040100000000, 0x0004040004000000, 0x0004040104000000, +0x0004040000040000, 0x0004040100040000, 0x0004040004040000, 0x0004040104040000, +0x0004040000000400, 0x0004040100000400, 0x0004040004000400, 0x0004040104000400, +0x0004040000040400, 0x0004040100040400, 0x0004040004040400, 0x0004040104040400, +0x0004040000000004, 0x0004040100000004, 0x0004040004000004, 0x0004040104000004, +0x0004040000040004, 0x0004040100040004, 0x0004040004040004, 0x0004040104040004, +0x0004040000000404, 0x0004040100000404, 0x0004040004000404, 0x0004040104000404, +0x0004040000040404, 0x0004040100040404, 0x0004040004040404, 0x0004040104040404, +0x0404040000000000, 0x0404040100000000, 0x0404040004000000, 0x0404040104000000, +0x0404040000040000, 0x0404040100040000, 0x0404040004040000, 0x0404040104040000, +0x0404040000000400, 0x0404040100000400, 0x0404040004000400, 0x0404040104000400, +0x0404040000040400, 0x0404040100040400, 0x0404040004040400, 0x0404040104040400, +0x0404040000000004, 0x0404040100000004, 0x0404040004000004, 0x0404040104000004, +0x0404040000040004, 0x0404040100040004, 0x0404040004040004, 0x0404040104040004, +0x0404040000000404, 0x0404040100000404, 0x0404040004000404, 0x0404040104000404, +0x0404040000040404, 0x0404040100040404, 0x0404040004040404, 0x0404040104040404 }; + +const uint64_t DES_FPTAB2[256] = { +0x0000000000000000, 0x0000004000000000, 0x0000000001000000, 0x0000004001000000, +0x0000000000010000, 0x0000004000010000, 0x0000000001010000, 0x0000004001010000, +0x0000000000000100, 0x0000004000000100, 0x0000000001000100, 0x0000004001000100, +0x0000000000010100, 0x0000004000010100, 0x0000000001010100, 0x0000004001010100, +0x0000000000000001, 0x0000004000000001, 0x0000000001000001, 0x0000004001000001, +0x0000000000010001, 0x0000004000010001, 0x0000000001010001, 0x0000004001010001, +0x0000000000000101, 0x0000004000000101, 0x0000000001000101, 0x0000004001000101, +0x0000000000010101, 0x0000004000010101, 0x0000000001010101, 0x0000004001010101, +0x0100000000000000, 0x0100004000000000, 0x0100000001000000, 0x0100004001000000, +0x0100000000010000, 0x0100004000010000, 0x0100000001010000, 0x0100004001010000, +0x0100000000000100, 0x0100004000000100, 0x0100000001000100, 0x0100004001000100, +0x0100000000010100, 0x0100004000010100, 0x0100000001010100, 0x0100004001010100, +0x0100000000000001, 0x0100004000000001, 0x0100000001000001, 0x0100004001000001, +0x0100000000010001, 0x0100004000010001, 0x0100000001010001, 0x0100004001010001, +0x0100000000000101, 0x0100004000000101, 0x0100000001000101, 0x0100004001000101, +0x0100000000010101, 0x0100004000010101, 0x0100000001010101, 0x0100004001010101, +0x0001000000000000, 0x0001004000000000, 0x0001000001000000, 0x0001004001000000, +0x0001000000010000, 0x0001004000010000, 0x0001000001010000, 0x0001004001010000, +0x0001000000000100, 0x0001004000000100, 0x0001000001000100, 0x0001004001000100, +0x0001000000010100, 0x0001004000010100, 0x0001000001010100, 0x0001004001010100, +0x0001000000000001, 0x0001004000000001, 0x0001000001000001, 0x0001004001000001, +0x0001000000010001, 0x0001004000010001, 0x0001000001010001, 0x0001004001010001, +0x0001000000000101, 0x0001004000000101, 0x0001000001000101, 0x0001004001000101, +0x0001000000010101, 0x0001004000010101, 0x0001000001010101, 0x0001004001010101, +0x0101000000000000, 0x0101004000000000, 0x0101000001000000, 0x0101004001000000, +0x0101000000010000, 0x0101004000010000, 0x0101000001010000, 0x0101004001010000, +0x0101000000000100, 0x0101004000000100, 0x0101000001000100, 0x0101004001000100, +0x0101000000010100, 0x0101004000010100, 0x0101000001010100, 0x0101004001010100, +0x0101000000000001, 0x0101004000000001, 0x0101000001000001, 0x0101004001000001, +0x0101000000010001, 0x0101004000010001, 0x0101000001010001, 0x0101004001010001, +0x0101000000000101, 0x0101004000000101, 0x0101000001000101, 0x0101004001000101, +0x0101000000010101, 0x0101004000010101, 0x0101000001010101, 0x0101004001010101, +0x0000010000000000, 0x0000014000000000, 0x0000010001000000, 0x0000014001000000, +0x0000010000010000, 0x0000014000010000, 0x0000010001010000, 0x0000014001010000, +0x0000010000000100, 0x0000014000000100, 0x0000010001000100, 0x0000014001000100, +0x0000010000010100, 0x0000014000010100, 0x0000010001010100, 0x0000014001010100, +0x0000010000000001, 0x0000014000000001, 0x0000010001000001, 0x0000014001000001, +0x0000010000010001, 0x0000014000010001, 0x0000010001010001, 0x0000014001010001, +0x0000010000000101, 0x0000014000000101, 0x0000010001000101, 0x0000014001000101, +0x0000010000010101, 0x0000014000010101, 0x0000010001010101, 0x0000014001010101, +0x0100010000000000, 0x0100014000000000, 0x0100010001000000, 0x0100014001000000, +0x0100010000010000, 0x0100014000010000, 0x0100010001010000, 0x0100014001010000, +0x0100010000000100, 0x0100014000000100, 0x0100010001000100, 0x0100014001000100, +0x0100010000010100, 0x0100014000010100, 0x0100010001010100, 0x0100014001010100, +0x0100010000000001, 0x0100014000000001, 0x0100010001000001, 0x0100014001000001, +0x0100010000010001, 0x0100014000010001, 0x0100010001010001, 0x0100014001010001, +0x0100010000000101, 0x0100014000000101, 0x0100010001000101, 0x0100014001000101, +0x0100010000010101, 0x0100014000010101, 0x0100010001010101, 0x0100014001010101, +0x0001010000000000, 0x0001014000000000, 0x0001010001000000, 0x0001014001000000, +0x0001010000010000, 0x0001014000010000, 0x0001010001010000, 0x0001014001010000, +0x0001010000000100, 0x0001014000000100, 0x0001010001000100, 0x0001014001000100, +0x0001010000010100, 0x0001014000010100, 0x0001010001010100, 0x0001014001010100, +0x0001010000000001, 0x0001014000000001, 0x0001010001000001, 0x0001014001000001, +0x0001010000010001, 0x0001014000010001, 0x0001010001010001, 0x0001014001010001, +0x0001010000000101, 0x0001014000000101, 0x0001010001000101, 0x0001014001000101, +0x0001010000010101, 0x0001014000010101, 0x0001010001010101, 0x0001014001010101, +0x0101010000000000, 0x0101014000000000, 0x0101010001000000, 0x0101014001000000, +0x0101010000010000, 0x0101014000010000, 0x0101010001010000, 0x0101014001010000, +0x0101010000000100, 0x0101014000000100, 0x0101010001000100, 0x0101014001000100, +0x0101010000010100, 0x0101014000010100, 0x0101010001010100, 0x0101014001010100, +0x0101010000000001, 0x0101014000000001, 0x0101010001000001, 0x0101014001000001, +0x0101010000010001, 0x0101014000010001, 0x0101010001010001, 0x0101014001010001, +0x0101010000000101, 0x0101014000000101, 0x0101010001000101, 0x0101014001000101, +0x0101010000010101, 0x0101014000010101, 0x0101010001010101, 0x0101014001010101 }; + +} diff --git a/src/libs/3rdparty/botan/src/lib/block/des/desx.cpp b/src/libs/3rdparty/botan/src/lib/block/des/desx.cpp new file mode 100644 index 0000000000..e869b3ebf8 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/des/desx.cpp @@ -0,0 +1,65 @@ +/* +* DES +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/desx.h> + +namespace Botan { + +/* +* DESX Encryption +*/ +void DESX::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_K1.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(out, in, m_K1.data(), BLOCK_SIZE); + m_des.encrypt(out); + xor_buf(out, m_K2.data(), BLOCK_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DESX Decryption +*/ +void DESX::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + { + verify_key_set(m_K1.empty() == false); + + for(size_t i = 0; i != blocks; ++i) + { + xor_buf(out, in, m_K2.data(), BLOCK_SIZE); + m_des.decrypt(out); + xor_buf(out, m_K1.data(), BLOCK_SIZE); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* DESX Key Schedule +*/ +void DESX::key_schedule(const uint8_t key[], size_t) + { + m_K1.assign(key, key + 8); + m_des.set_key(key + 8, 8); + m_K2.assign(key + 16, key + 24); + } + +void DESX::clear() + { + m_des.clear(); + zap(m_K1); + zap(m_K2); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/block/des/desx.h b/src/libs/3rdparty/botan/src/lib/block/des/desx.h new file mode 100644 index 0000000000..fa9a996631 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/des/desx.h @@ -0,0 +1,35 @@ +/* +* DESX +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DESX_H_ +#define BOTAN_DESX_H_ + +#include <botan/des.h> + +namespace Botan { + +/** +* DESX +*/ +class BOTAN_PUBLIC_API(2,0) DESX final : public Block_Cipher_Fixed_Params<8, 24> + { + public: + void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override; + + void clear() override; + std::string name() const override { return "DESX"; } + BlockCipher* clone() const override { return new DESX; } + private: + void key_schedule(const uint8_t[], size_t) override; + secure_vector<uint8_t> m_K1, m_K2; + DES m_des; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/block/des/info.txt b/src/libs/3rdparty/botan/src/lib/block/des/info.txt new file mode 100644 index 0000000000..05f85b523c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/des/info.txt @@ -0,0 +1,3 @@ +<defines> +DES -> 20131128 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/block/info.txt b/src/libs/3rdparty/botan/src/lib/block/info.txt new file mode 100644 index 0000000000..b03a8c8f59 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/block/info.txt @@ -0,0 +1,7 @@ +<defines> +BLOCK_CIPHER -> 20131128 +</defines> + +<header:public> +block_cipher.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/codec/base64/base64.cpp b/src/libs/3rdparty/botan/src/lib/codec/base64/base64.cpp new file mode 100644 index 0000000000..7f52fb5afb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/codec/base64/base64.cpp @@ -0,0 +1,261 @@ +/* +* Base64 Encoding and Decoding +* (C) 2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/base64.h> +#include <botan/exceptn.h> +#include <botan/mem_ops.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +namespace { + +static const uint8_t BIN_TO_BASE64[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +void do_base64_encode(char out[4], const uint8_t in[3]) + { + out[0] = BIN_TO_BASE64[(in[0] & 0xFC) >> 2]; + out[1] = BIN_TO_BASE64[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + out[2] = BIN_TO_BASE64[((in[1] & 0x0F) << 2) | (in[2] >> 6)]; + out[3] = BIN_TO_BASE64[in[2] & 0x3F]; + } + +} + +size_t base64_encode(char out[], + const uint8_t in[], + size_t input_length, + size_t& input_consumed, + bool final_inputs) + { + input_consumed = 0; + + size_t input_remaining = input_length; + size_t output_produced = 0; + + while(input_remaining >= 3) + { + do_base64_encode(out + output_produced, in + input_consumed); + + input_consumed += 3; + output_produced += 4; + input_remaining -= 3; + } + + if(final_inputs && input_remaining) + { + uint8_t remainder[3] = { 0 }; + for(size_t i = 0; i != input_remaining; ++i) + remainder[i] = in[input_consumed + i]; + + do_base64_encode(out + output_produced, remainder); + + size_t empty_bits = 8 * (3 - input_remaining); + size_t index = output_produced + 4 - 1; + while(empty_bits >= 8) + { + out[index--] = '='; + empty_bits -= 6; + } + + input_consumed += input_remaining; + output_produced += 4; + } + + return output_produced; + } + +std::string base64_encode(const uint8_t input[], + size_t input_length) + { + const size_t output_length = base64_encode_max_output(input_length); + std::string output(output_length, 0); + + size_t consumed = 0; + size_t produced = 0; + + if (output_length > 0) + { + produced = base64_encode(&output.front(), + input, input_length, + consumed, true); + } + + BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input"); + BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size"); + + return output; + } + +size_t base64_decode(uint8_t output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws) + { + /* + * Base64 Decoder Lookup Table + * Warning: assumes ASCII encodings + */ + static const uint8_t BASE64_TO_BIN[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, + 0x80, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, + 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, + 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + uint8_t* out_ptr = output; + uint8_t decode_buf[4]; + size_t decode_buf_pos = 0; + size_t final_truncate = 0; + + clear_mem(output, input_length * 3 / 4); + + for(size_t i = 0; i != input_length; ++i) + { + const uint8_t bin = BASE64_TO_BIN[static_cast<uint8_t>(input[i])]; + + if(bin <= 0x3F) + { + decode_buf[decode_buf_pos] = bin; + decode_buf_pos += 1; + } + else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws))) + { + std::string bad_char(1, input[i]); + if(bad_char == "\t") + bad_char = "\\t"; + else if(bad_char == "\n") + bad_char = "\\n"; + else if(bad_char == "\r") + bad_char = "\\r"; + + throw Invalid_Argument( + std::string("base64_decode: invalid base64 character '") + + bad_char + "'"); + } + + /* + * If we're at the end of the input, pad with 0s and truncate + */ + if(final_inputs && (i == input_length - 1)) + { + if(decode_buf_pos) + { + for(size_t j = decode_buf_pos; j != 4; ++j) + decode_buf[j] = 0; + final_truncate = (4 - decode_buf_pos); + decode_buf_pos = 4; + } + } + + if(decode_buf_pos == 4) + { + out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4); + out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2); + out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3]; + + out_ptr += 3; + decode_buf_pos = 0; + input_consumed = i+1; + } + } + + while(input_consumed < input_length && + BASE64_TO_BIN[static_cast<uint8_t>(input[input_consumed])] == 0x80) + { + ++input_consumed; + } + + size_t written = (out_ptr - output) - final_truncate; + + return written; + } + +size_t base64_decode(uint8_t output[], + const char input[], + size_t input_length, + bool ignore_ws) + { + size_t consumed = 0; + size_t written = base64_decode(output, input, input_length, + consumed, true, ignore_ws); + + if(consumed != input_length) + throw Invalid_Argument("base64_decode: input did not have full bytes"); + + return written; + } + +size_t base64_decode(uint8_t output[], + const std::string& input, + bool ignore_ws) + { + return base64_decode(output, input.data(), input.length(), ignore_ws); + } + +secure_vector<uint8_t> base64_decode(const char input[], + size_t input_length, + bool ignore_ws) + { + const size_t output_length = base64_decode_max_output(input_length); + secure_vector<uint8_t> bin(output_length); + + size_t written = base64_decode(bin.data(), + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +secure_vector<uint8_t> base64_decode(const std::string& input, + bool ignore_ws) + { + return base64_decode(input.data(), input.size(), ignore_ws); + } + +size_t base64_encode_max_output(size_t input_length) + { + return (round_up(input_length, 3) / 3) * 4; + } + +size_t base64_decode_max_output(size_t input_length) + { + return (round_up(input_length, 4) * 3) / 4; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/codec/base64/base64.h b/src/libs/3rdparty/botan/src/lib/codec/base64/base64.h new file mode 100644 index 0000000000..a20d03b0f7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/codec/base64/base64.h @@ -0,0 +1,141 @@ +/* +* Base64 Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BASE64_CODEC_H_ +#define BOTAN_BASE64_CODEC_H_ + +#include <botan/secmem.h> +#include <string> + +namespace Botan { + +/** +* Perform base64 encoding +* @param output an array of at least base64_encode_max_output bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding chars will be applied if needed +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) base64_encode(char output[], + const uint8_t input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs); + +/** +* Perform base64 encoding +* @param input some input +* @param input_length length of input in bytes +* @return base64adecimal representation of input +*/ +std::string BOTAN_PUBLIC_API(2,0) base64_encode(const uint8_t input[], + size_t input_length); + +/** +* Perform base64 encoding +* @param input some input +* @return base64adecimal representation of input +*/ +template<typename Alloc> +std::string base64_encode(const std::vector<uint8_t, Alloc>& input) + { + return base64_encode(input.data(), input.size()); + } + +/** +* Perform base64 decoding +* @param output an array of at least base64_decode_max_output bytes +* @param input some base64 input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding is allowed +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) base64_decode(uint8_t output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param output an array of at least base64_decode_max_output bytes +* @param input some base64 input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) base64_decode(uint8_t output[], + const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param output an array of at least base64_decode_max_output bytes +* @param input some base64 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) base64_decode(uint8_t output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param input some base64 input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base64 output +*/ +secure_vector<uint8_t> BOTAN_PUBLIC_API(2,0) base64_decode(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param input some base64 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base64 output +*/ +secure_vector<uint8_t> BOTAN_PUBLIC_API(2,0) base64_decode(const std::string& input, + bool ignore_ws = true); + +/** +* Calculate the size of output buffer for base64_encode +* @param input_length the length of input in bytes +* @return the size of output buffer in bytes +*/ +size_t BOTAN_PUBLIC_API(2,1) base64_encode_max_output(size_t input_length); + +/** +* Calculate the size of output buffer for base64_decode +* @param input_length the length of input in bytes +* @return the size of output buffer in bytes +*/ +size_t BOTAN_PUBLIC_API(2,1) base64_decode_max_output(size_t input_length); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/codec/base64/info.txt b/src/libs/3rdparty/botan/src/lib/codec/base64/info.txt new file mode 100644 index 0000000000..ceed636053 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/codec/base64/info.txt @@ -0,0 +1,3 @@ +<defines> +BASE64_CODEC -> 20131128 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/codec/hex/hex.cpp b/src/libs/3rdparty/botan/src/lib/codec/hex/hex.cpp new file mode 100644 index 0000000000..6bbd7c28e2 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/codec/hex/hex.cpp @@ -0,0 +1,207 @@ +/* +* Hex Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/hex.h> +#include <botan/mem_ops.h> +#include <botan/exceptn.h> + +namespace Botan { + +void hex_encode(char output[], + const uint8_t input[], + size_t input_length, + bool uppercase) + { + static const uint8_t BIN_TO_HEX_UPPER[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' }; + + static const uint8_t BIN_TO_HEX_LOWER[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' }; + + const uint8_t* tbl = uppercase ? BIN_TO_HEX_UPPER : BIN_TO_HEX_LOWER; + + for(size_t i = 0; i != input_length; ++i) + { + uint8_t x = input[i]; + output[2*i ] = tbl[(x >> 4) & 0x0F]; + output[2*i+1] = tbl[(x ) & 0x0F]; + } + } + +std::string hex_encode(const uint8_t input[], + size_t input_length, + bool uppercase) + { + std::string output(2 * input_length, 0); + + if(input_length) + hex_encode(&output.front(), input, input_length, uppercase); + + return output; + } + +size_t hex_decode(uint8_t output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool ignore_ws) + { + /* + * Mapping of hex characters to either their binary equivalent + * or to an error code. + * If valid hex (0-9 A-F a-f), the value. + * If whitespace, then 0x80 + * Otherwise 0xFF + * Warning: this table assumes ASCII character encodings + */ + + static const uint8_t HEX_TO_BIN[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, + 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + uint8_t* out_ptr = output; + bool top_nibble = true; + + clear_mem(output, input_length / 2); + + for(size_t i = 0; i != input_length; ++i) + { + const uint8_t bin = HEX_TO_BIN[static_cast<uint8_t>(input[i])]; + + if(bin >= 0x10) + { + if(bin == 0x80 && ignore_ws) + continue; + + std::string bad_char(1, input[i]); + if(bad_char == "\t") + bad_char = "\\t"; + else if(bad_char == "\n") + bad_char = "\\n"; + + throw Invalid_Argument( + std::string("hex_decode: invalid hex character '") + + bad_char + "'"); + } + + if(top_nibble) + *out_ptr |= bin << 4; + else + *out_ptr |= bin; + + top_nibble = !top_nibble; + if(top_nibble) + ++out_ptr; + } + + input_consumed = input_length; + size_t written = (out_ptr - output); + + /* + * We only got half of a uint8_t at the end; zap the half-written + * output and mark it as unread + */ + if(!top_nibble) + { + *out_ptr = 0; + input_consumed -= 1; + } + + return written; + } + +size_t hex_decode(uint8_t output[], + const char input[], + size_t input_length, + bool ignore_ws) + { + size_t consumed = 0; + size_t written = hex_decode(output, input, input_length, + consumed, ignore_ws); + + if(consumed != input_length) + throw Invalid_Argument("hex_decode: input did not have full bytes"); + + return written; + } + +size_t hex_decode(uint8_t output[], + const std::string& input, + bool ignore_ws) + { + return hex_decode(output, input.data(), input.length(), ignore_ws); + } + +secure_vector<uint8_t> hex_decode_locked(const char input[], + size_t input_length, + bool ignore_ws) + { + secure_vector<uint8_t> bin(1 + input_length / 2); + + size_t written = hex_decode(bin.data(), + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +secure_vector<uint8_t> hex_decode_locked(const std::string& input, + bool ignore_ws) + { + return hex_decode_locked(input.data(), input.size(), ignore_ws); + } + +std::vector<uint8_t> hex_decode(const char input[], + size_t input_length, + bool ignore_ws) + { + std::vector<uint8_t> bin(1 + input_length / 2); + + size_t written = hex_decode(bin.data(), + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +std::vector<uint8_t> hex_decode(const std::string& input, + bool ignore_ws) + { + return hex_decode(input.data(), input.size(), ignore_ws); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/codec/hex/hex.h b/src/libs/3rdparty/botan/src/lib/codec/hex/hex.h new file mode 100644 index 0000000000..330d8a69a5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/codec/hex/hex.h @@ -0,0 +1,148 @@ +/* +* Hex Encoding and Decoding +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HEX_CODEC_H_ +#define BOTAN_HEX_CODEC_H_ + +#include <botan/secmem.h> +#include <string> + +namespace Botan { + +/** +* Perform hex encoding +* @param output an array of at least input_length*2 bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param uppercase should output be upper or lower case? +*/ +void BOTAN_PUBLIC_API(2,0) hex_encode(char output[], + const uint8_t input[], + size_t input_length, + bool uppercase = true); + +/** +* Perform hex encoding +* @param input some input +* @param input_length length of input in bytes +* @param uppercase should output be upper or lower case? +* @return hexadecimal representation of input +*/ +std::string BOTAN_PUBLIC_API(2,0) hex_encode(const uint8_t input[], + size_t input_length, + bool uppercase = true); + +/** +* Perform hex encoding +* @param input some input +* @param uppercase should output be upper or lower case? +* @return hexadecimal representation of input +*/ +template<typename Alloc> +std::string hex_encode(const std::vector<uint8_t, Alloc>& input, + bool uppercase = true) + { + return hex_encode(input.data(), input.size(), uppercase); + } + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) hex_decode(uint8_t output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) hex_decode(uint8_t output[], + const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param output an array of at least input_length/2 bytes +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_PUBLIC_API(2,0) hex_decode(uint8_t output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +std::vector<uint8_t> BOTAN_PUBLIC_API(2,0) +hex_decode(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +std::vector<uint8_t> BOTAN_PUBLIC_API(2,0) +hex_decode(const std::string& input, + bool ignore_ws = true); + + +/** +* Perform hex decoding +* @param input some hex input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +secure_vector<uint8_t> BOTAN_PUBLIC_API(2,0) +hex_decode_locked(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform hex decoding +* @param input some hex input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded hex output +*/ +secure_vector<uint8_t> BOTAN_PUBLIC_API(2,0) +hex_decode_locked(const std::string& input, + bool ignore_ws = true); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/codec/hex/info.txt b/src/libs/3rdparty/botan/src/lib/codec/hex/info.txt new file mode 100644 index 0000000000..6ee27e57c2 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/codec/hex/info.txt @@ -0,0 +1,3 @@ +<defines> +HEX_CODEC -> 20131128 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp b/src/libs/3rdparty/botan/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp new file mode 100644 index 0000000000..1e36136155 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp @@ -0,0 +1,30 @@ +/* +* Darwin SecRandomCopyBytes EntropySource +* (C) 2015 Daniel Seither (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/darwin_secrandom.h> +#include <Security/Security.h> +#include <Security/SecRandom.h> + +namespace Botan { + +/** +* Gather entropy from SecRandomCopyBytes +*/ +size_t Darwin_SecRandom::poll(RandomNumberGenerator& rng) + { + secure_vector<uint8_t> buf(BOTAN_SYSTEM_RNG_POLL_REQUEST); + + if(0 == SecRandomCopyBytes(kSecRandomDefault, buf.size(), buf.data())) + { + rng.add_entropy(buf.data(), buf.size()); + return buf.size() * 8; + } + + return 0; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/entropy/darwin_secrandom/darwin_secrandom.h b/src/libs/3rdparty/botan/src/lib/entropy/darwin_secrandom/darwin_secrandom.h new file mode 100644 index 0000000000..83b4da4f50 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/darwin_secrandom/darwin_secrandom.h @@ -0,0 +1,28 @@ +/* +* Darwin SecRandomCopyBytes EntropySource +* (C) 2015 Daniel Seither (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_DARWIN_SECRANDOM_H_ +#define BOTAN_ENTROPY_SRC_DARWIN_SECRANDOM_H_ + +#include <botan/entropy_src.h> + +namespace Botan { + +/** +* Entropy source using SecRandomCopyBytes from Darwin's Security.framework +*/ +class Darwin_SecRandom final : public Entropy_Source + { + public: + std::string name() const override { return "darwin_secrandom"; } + + size_t poll(RandomNumberGenerator& rng) override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/entropy/darwin_secrandom/info.txt b/src/libs/3rdparty/botan/src/lib/entropy/darwin_secrandom/info.txt new file mode 100644 index 0000000000..c1943a04a4 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/darwin_secrandom/info.txt @@ -0,0 +1,16 @@ +<defines> +ENTROPY_SRC_DARWIN_SECRANDOM -> 20150925 +</defines> + +<header:internal> +darwin_secrandom.h +</header:internal> + +<os_features> +security_framework +</os_features> + +<frameworks> +darwin -> Security +ios -> Security +</frameworks> diff --git a/src/libs/3rdparty/botan/src/lib/entropy/dev_random/dev_random.cpp b/src/libs/3rdparty/botan/src/lib/entropy/dev_random/dev_random.cpp new file mode 100644 index 0000000000..56552228a3 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/dev_random/dev_random.cpp @@ -0,0 +1,123 @@ +/* +* Reader of /dev/random and company +* (C) 1999-2009,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/dev_random.h> +#include <botan/exceptn.h> + +#include <sys/types.h> +#include <sys/select.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +namespace Botan { + +/** +Device_EntropySource constructor +Open a file descriptor to each (available) device in fsnames +*/ +Device_EntropySource::Device_EntropySource(const std::vector<std::string>& fsnames) + { +#ifndef O_NONBLOCK + #define O_NONBLOCK 0 +#endif + +#ifndef O_NOCTTY + #define O_NOCTTY 0 +#endif + + const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY; + + m_max_fd = 0; + + for(auto fsname : fsnames) + { + int fd = ::open(fsname.c_str(), flags); + + if(fd < 0) + { + /* + ENOENT or EACCES is normal as some of the named devices may not exist + on this system. But any other errno value probably indicates + either a bug in the application or file descriptor exhaustion. + */ + if(errno != ENOENT && errno != EACCES) + throw Exception("Opening OS RNG device failed with errno " + + std::to_string(errno)); + } + else + { + if(fd > FD_SETSIZE) + { + ::close(fd); + throw Exception("Open of OS RNG succeeded but fd is too large for fd_set"); + } + + m_dev_fds.push_back(fd); + m_max_fd = std::max(m_max_fd, fd); + } + } + } + +/** +Device_EntropySource destructor: close all open devices +*/ +Device_EntropySource::~Device_EntropySource() + { + for(int fd : m_dev_fds) + { + // ignoring return value here, can't throw in destructor anyway + ::close(fd); + } + } + +/** +* Gather entropy from a RNG device +*/ +size_t Device_EntropySource::poll(RandomNumberGenerator& rng) + { + size_t bits = 0; + + if(m_dev_fds.size() > 0) + { + fd_set read_set; + FD_ZERO(&read_set); + + for(int dev_fd : m_dev_fds) + { + FD_SET(dev_fd, &read_set); + } + + secure_vector<uint8_t> io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST); + + struct ::timeval timeout; + timeout.tv_sec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS / 1000); + timeout.tv_usec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS % 1000) * 1000; + + if(::select(m_max_fd + 1, &read_set, nullptr, nullptr, &timeout) > 0) + { + for(int dev_fd : m_dev_fds) + { + if(FD_ISSET(dev_fd, &read_set)) + { + const ssize_t got = ::read(dev_fd, io_buf.data(), io_buf.size()); + + if(got > 0) + { + rng.add_entropy(io_buf.data(), static_cast<size_t>(got)); + bits += got * 8; + } + } + } + } + } + + return bits; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/entropy/dev_random/dev_random.h b/src/libs/3rdparty/botan/src/lib/entropy/dev_random/dev_random.h new file mode 100644 index 0000000000..6195f85648 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/dev_random/dev_random.h @@ -0,0 +1,37 @@ +/* +* /dev/random EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_DEVICE_H_ +#define BOTAN_ENTROPY_SRC_DEVICE_H_ + +#include <botan/entropy_src.h> +#include <vector> +#include <string> + +namespace Botan { + +/** +* Entropy source reading from kernel devices like /dev/random +*/ +class Device_EntropySource final : public Entropy_Source + { + public: + std::string name() const override { return "dev_random"; } + + size_t poll(RandomNumberGenerator& rng) override; + + explicit Device_EntropySource(const std::vector<std::string>& fsnames); + + ~Device_EntropySource(); + private: + std::vector<int> m_dev_fds; + int m_max_fd; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/entropy/dev_random/info.txt b/src/libs/3rdparty/botan/src/lib/entropy/dev_random/info.txt new file mode 100644 index 0000000000..3872411f30 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/dev_random/info.txt @@ -0,0 +1,11 @@ +<defines> +ENTROPY_SRC_DEV_RANDOM -> 20131128 +</defines> + +<header:internal> +dev_random.h +</header:internal> + +<os_features> +dev_random,posix1 +</os_features> diff --git a/src/libs/3rdparty/botan/src/lib/entropy/entropy_src.h b/src/libs/3rdparty/botan/src/lib/entropy/entropy_src.h new file mode 100644 index 0000000000..56e5bd53e5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/entropy_src.h @@ -0,0 +1,87 @@ +/* +* EntropySource +* (C) 2008,2009,2014,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_H_ +#define BOTAN_ENTROPY_H_ + +#include <botan/secmem.h> +#include <botan/rng.h> +#include <string> +#include <chrono> +#include <memory> +#include <vector> + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Abstract interface to a source of entropy +*/ +class BOTAN_PUBLIC_API(2,0) Entropy_Source + { + public: + /** + * Return a new entropy source of a particular type, or null + * Each entropy source may require substantial resources (eg, a file handle + * or socket instance), so try to share them among multiple RNGs, or just + * use the preconfigured global list accessed by Entropy_Sources::global_sources() + */ + static std::unique_ptr<Entropy_Source> create(const std::string& type); + + /** + * @return name identifying this entropy source + */ + virtual std::string name() const = 0; + + /** + * Perform an entropy gathering poll + * @param rng will be provided with entropy via calls to add_entropy + * @return conservative estimate of actual entropy added to rng during poll + */ + virtual size_t poll(RandomNumberGenerator& rng) = 0; + + Entropy_Source() = default; + Entropy_Source(const Entropy_Source& other) = delete; + Entropy_Source(Entropy_Source&& other) = delete; + Entropy_Source& operator=(const Entropy_Source& other) = delete; + + virtual ~Entropy_Source() = default; + }; + +class BOTAN_PUBLIC_API(2,0) Entropy_Sources final + { + public: + static Entropy_Sources& global_sources(); + + void add_source(std::unique_ptr<Entropy_Source> src); + + std::vector<std::string> enabled_sources() const; + + size_t poll(RandomNumberGenerator& rng, + size_t bits, + std::chrono::milliseconds timeout); + + /** + * Poll just a single named source. Ordinally only used for testing + */ + size_t poll_just(RandomNumberGenerator& rng, const std::string& src); + + Entropy_Sources() = default; + explicit Entropy_Sources(const std::vector<std::string>& sources); + + Entropy_Sources(const Entropy_Sources& other) = delete; + Entropy_Sources(Entropy_Sources&& other) = delete; + Entropy_Sources& operator=(const Entropy_Sources& other) = delete; + + private: + std::vector<std::unique_ptr<Entropy_Source>> m_srcs; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/entropy/entropy_srcs.cpp b/src/libs/3rdparty/botan/src/lib/entropy/entropy_srcs.cpp new file mode 100644 index 0000000000..c04b3b5b26 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/entropy_srcs.cpp @@ -0,0 +1,198 @@ +/* +* Entropy Source Polling +* (C) 2008-2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/entropy_src.h> +#include <botan/rng.h> + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include <botan/system_rng.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND) + #include <botan/internal/rdrand.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDSEED) + #include <botan/internal/rdseed.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) + #include <botan/internal/dev_random.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) + #include <botan/internal/es_win32.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) + #include <botan/internal/proc_walk.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DARWIN_SECRANDOM) + #include <botan/internal/darwin_secrandom.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY) + #include <botan/internal/getentropy.h> +#endif + +namespace Botan { + +#if defined(BOTAN_HAS_SYSTEM_RNG) + +namespace { + +class System_RNG_EntropySource final : public Entropy_Source + { + public: + size_t poll(RandomNumberGenerator& rng) override + { + const size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS; + rng.reseed_from_rng(system_rng(), poll_bits); + return poll_bits; + } + + std::string name() const override { return "system_rng"; } + }; + +} + +#endif + +std::unique_ptr<Entropy_Source> Entropy_Source::create(const std::string& name) + { +#if defined(BOTAN_HAS_SYSTEM_RNG) + if(name == "system_rng" || name == "win32_cryptoapi") + { + return std::unique_ptr<Entropy_Source>(new System_RNG_EntropySource); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND) + if(name == "rdrand") + { + return std::unique_ptr<Entropy_Source>(new Intel_Rdrand); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_RDSEED) + if(name == "rdseed") + { + return std::unique_ptr<Entropy_Source>(new Intel_Rdseed); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DARWIN_SECRANDOM) + if(name == "darwin_secrandom") + { + return std::unique_ptr<Entropy_Source>(new Darwin_SecRandom); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY) + if(name == "getentropy") + { + return std::unique_ptr<Entropy_Source>(new Getentropy); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM) + if(name == "dev_random") + { + return std::unique_ptr<Entropy_Source>(new Device_EntropySource(BOTAN_SYSTEM_RNG_POLL_DEVICES)); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) + if(name == "proc_walk") + { + const std::string root_dir = BOTAN_ENTROPY_PROC_FS_PATH; + if(!root_dir.empty()) + return std::unique_ptr<Entropy_Source>(new ProcWalking_EntropySource(root_dir)); + } +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) + if(name == "system_stats") + { + return std::unique_ptr<Entropy_Source>(new Win32_EntropySource); + } +#endif + + BOTAN_UNUSED(name); + return std::unique_ptr<Entropy_Source>(); + } + +void Entropy_Sources::add_source(std::unique_ptr<Entropy_Source> src) + { + if(src.get()) + { + m_srcs.push_back(std::move(src)); + } + } + +std::vector<std::string> Entropy_Sources::enabled_sources() const + { + std::vector<std::string> sources; + for(size_t i = 0; i != m_srcs.size(); ++i) + { + sources.push_back(m_srcs[i]->name()); + } + return sources; + } + +size_t Entropy_Sources::poll(RandomNumberGenerator& rng, + size_t poll_bits, + std::chrono::milliseconds timeout) + { + typedef std::chrono::system_clock clock; + + auto deadline = clock::now() + timeout; + + size_t bits_collected = 0; + + for(size_t i = 0; i != m_srcs.size(); ++i) + { + bits_collected += m_srcs[i]->poll(rng); + + if (bits_collected >= poll_bits || clock::now() > deadline) + break; + } + + return bits_collected; + } + +size_t Entropy_Sources::poll_just(RandomNumberGenerator& rng, const std::string& the_src) + { + for(size_t i = 0; i != m_srcs.size(); ++i) + { + if(m_srcs[i]->name() == the_src) + { + return m_srcs[i]->poll(rng); + } + } + + return 0; + } + +Entropy_Sources::Entropy_Sources(const std::vector<std::string>& sources) + { + for(auto&& src_name : sources) + { + add_source(Entropy_Source::create(src_name)); + } + } + +Entropy_Sources& Entropy_Sources::global_sources() + { + static Entropy_Sources global_entropy_sources(BOTAN_ENTROPY_DEFAULT_SOURCES); + + return global_entropy_sources; + } + +} + diff --git a/src/libs/3rdparty/botan/src/lib/entropy/getentropy/getentropy.cpp b/src/libs/3rdparty/botan/src/lib/entropy/getentropy/getentropy.cpp new file mode 100644 index 0000000000..15bd8abe87 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/getentropy/getentropy.cpp @@ -0,0 +1,35 @@ +/* +* System Call getentropy(2) +* (C) 2017 Alexander Bluhm (genua GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/getentropy.h> + +#if defined(BOTAN_TARGET_OS_IS_DARWIN) + #include <sys/random.h> +#else + #include <unistd.h> +#endif + +namespace Botan { + +/** +* Gather 256 bytes entropy from getentropy(2). Note that maximum +* buffer size is limited to 256 bytes. On OpenBSD this does neither +* block nor fail. +*/ +size_t Getentropy::poll(RandomNumberGenerator& rng) + { + secure_vector<uint8_t> buf(256); + + if(::getentropy(buf.data(), buf.size()) == 0) + { + rng.add_entropy(buf.data(), buf.size()); + return buf.size() * 8; + } + + return 0; + } +} diff --git a/src/libs/3rdparty/botan/src/lib/entropy/getentropy/getentropy.h b/src/libs/3rdparty/botan/src/lib/entropy/getentropy/getentropy.h new file mode 100644 index 0000000000..26783cf78a --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/getentropy/getentropy.h @@ -0,0 +1,28 @@ +/* +* Entropy Source Using OpenBSD getentropy(2) system call +* (C) 2017 Alexander Bluhm (genua GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_GETENTROPY_H_ +#define BOTAN_ENTROPY_SRC_GETENTROPY_H_ + +#include <botan/entropy_src.h> + +namespace Botan { + +/** +* Entropy source using the getentropy(2) system call first introduced in +* OpenBSD 5.6 and added to Solaris 11.3. +*/ +class Getentropy final : public Entropy_Source + { + public: + std::string name() const override { return "getentropy"; } + size_t poll(RandomNumberGenerator& rng) override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/entropy/getentropy/info.txt b/src/libs/3rdparty/botan/src/lib/entropy/getentropy/info.txt new file mode 100644 index 0000000000..886e57151f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/getentropy/info.txt @@ -0,0 +1,11 @@ +<defines> +ENTROPY_SRC_GETENTROPY -> 20170327 +</defines> + +<header:internal> +getentropy.h +</header:internal> + +<os_features> +getentropy +</os_features> diff --git a/src/libs/3rdparty/botan/src/lib/entropy/info.txt b/src/libs/3rdparty/botan/src/lib/entropy/info.txt new file mode 100644 index 0000000000..57f1930b99 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/info.txt @@ -0,0 +1,7 @@ +<defines> +ENTROPY_SOURCE -> 20151120 +</defines> + +<requires> +rng +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/entropy/proc_walk/info.txt b/src/libs/3rdparty/botan/src/lib/entropy/proc_walk/info.txt new file mode 100644 index 0000000000..2bba7e276b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/proc_walk/info.txt @@ -0,0 +1,11 @@ +<defines> +ENTROPY_SRC_PROC_WALKER -> 20131128 +</defines> + +<header:internal> +proc_walk.h +</header:internal> + +<os_features> +posix1,proc_fs +</os_features> diff --git a/src/libs/3rdparty/botan/src/lib/entropy/proc_walk/proc_walk.cpp b/src/libs/3rdparty/botan/src/lib/entropy/proc_walk/proc_walk.cpp new file mode 100644 index 0000000000..d780cbf739 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/proc_walk/proc_walk.cpp @@ -0,0 +1,154 @@ +/* +* Entropy source based on reading files in /proc on the assumption +* that a remote attacker will have difficulty guessing some of them. +* +* (C) 1999-2008,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/proc_walk.h> +#include <deque> + +#ifndef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309 +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <dirent.h> +#include <fcntl.h> + +namespace Botan { + +namespace { + +class Directory_Walker final : public File_Descriptor_Source + { + public: + explicit Directory_Walker(const std::string& root) : + m_cur_dir(std::make_pair<DIR*, std::string>(nullptr, "")) + { + if(DIR* root_dir = ::opendir(root.c_str())) + m_cur_dir = std::make_pair(root_dir, root); + } + + ~Directory_Walker() + { + if(m_cur_dir.first) + ::closedir(m_cur_dir.first); + } + + int next_fd() override; + private: + std::pair<struct dirent*, std::string> get_next_dirent(); + + std::pair<DIR*, std::string> m_cur_dir; + std::deque<std::string> m_dirlist; + }; + +std::pair<struct dirent*, std::string> Directory_Walker::get_next_dirent() + { + while(m_cur_dir.first) + { + if(struct dirent* dir = ::readdir(m_cur_dir.first)) + return std::make_pair(dir, m_cur_dir.second); + + ::closedir(m_cur_dir.first); + m_cur_dir = std::make_pair<DIR*, std::string>(nullptr, ""); + + while(!m_dirlist.empty() && !m_cur_dir.first) + { + const std::string next_dir_name = m_dirlist[0]; + m_dirlist.pop_front(); + + if(DIR* next_dir = ::opendir(next_dir_name.c_str())) + m_cur_dir = std::make_pair(next_dir, next_dir_name); + } + } + + return std::make_pair<struct dirent*, std::string>(nullptr, ""); // nothing left + } + +int Directory_Walker::next_fd() + { + while(true) + { + std::pair<struct dirent*, std::string> entry = get_next_dirent(); + + if(!entry.first) + break; // no more dirs + + const std::string filename = entry.first->d_name; + + if(filename == "." || filename == "..") + continue; + + const std::string full_path = entry.second + "/" + filename; + + struct stat stat_buf; + if(::lstat(full_path.c_str(), &stat_buf) == -1) + continue; + + if(S_ISDIR(stat_buf.st_mode)) + { + m_dirlist.push_back(full_path); + } + else if(S_ISREG(stat_buf.st_mode) && (stat_buf.st_mode & S_IROTH)) + { + int fd = ::open(full_path.c_str(), O_RDONLY | O_NOCTTY); + + if(fd >= 0) + return fd; + } + } + + return -1; + } + +} + +size_t ProcWalking_EntropySource::poll(RandomNumberGenerator& rng) + { + const size_t MAX_FILES_READ_PER_POLL = 2048; + + lock_guard_type<mutex_type> lock(m_mutex); + + if(!m_dir) + m_dir.reset(new Directory_Walker(m_path)); + + m_buf.resize(4096); + + size_t bits = 0; + + for(size_t i = 0; i != MAX_FILES_READ_PER_POLL; ++i) + { + int fd = m_dir->next_fd(); + + // If we've exhaused this walk of the directory, halt the poll + if(fd == -1) + { + m_dir.reset(); + break; + } + + ssize_t got = ::read(fd, m_buf.data(), m_buf.size()); + ::close(fd); + + if(got > 0) + { + rng.add_entropy(m_buf.data(), static_cast<size_t>(got)); + + // Conservative estimate of 4 bits per file + bits += 4; + } + + if(bits > 128) + break; + } + + return bits; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/entropy/proc_walk/proc_walk.h b/src/libs/3rdparty/botan/src/lib/entropy/proc_walk/proc_walk.h new file mode 100644 index 0000000000..4c5013d29c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/proc_walk/proc_walk.h @@ -0,0 +1,45 @@ +/* +* File Tree Walking EntropySource +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_PROC_WALK_H_ +#define BOTAN_ENTROPY_SRC_PROC_WALK_H_ + +#include <botan/entropy_src.h> +#include <botan/mutex.h> + +namespace Botan { + +class File_Descriptor_Source + { + public: + virtual int next_fd() = 0; + virtual ~File_Descriptor_Source() = default; + }; + +/** +* File Tree Walking Entropy Source +*/ +class ProcWalking_EntropySource final : public Entropy_Source + { + public: + std::string name() const override { return "proc_walk"; } + + size_t poll(RandomNumberGenerator& rng) override; + + explicit ProcWalking_EntropySource(const std::string& root_dir) : + m_path(root_dir), m_dir(nullptr) {} + + private: + const std::string m_path; + mutex_type m_mutex; + std::unique_ptr<File_Descriptor_Source> m_dir; + secure_vector<uint8_t> m_buf; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/entropy/rdrand/info.txt b/src/libs/3rdparty/botan/src/lib/entropy/rdrand/info.txt new file mode 100644 index 0000000000..6abe8765d3 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/rdrand/info.txt @@ -0,0 +1,11 @@ +<defines> +ENTROPY_SRC_RDRAND -> 20131128 +</defines> + +<requires> +rdrand_rng +</requires> + +<header:internal> +rdrand.h +</header:internal> diff --git a/src/libs/3rdparty/botan/src/lib/entropy/rdrand/rdrand.cpp b/src/libs/3rdparty/botan/src/lib/entropy/rdrand/rdrand.cpp new file mode 100644 index 0000000000..6a5b0f7c44 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/rdrand/rdrand.cpp @@ -0,0 +1,29 @@ +/* +* Entropy Source Using Intel's rdrand instruction +* (C) 2012,2015 Jack Lloyd +* (C) 2015 Daniel Neus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/rdrand.h> +#include <botan/rdrand_rng.h> +#include <botan/cpuid.h> + +namespace Botan { + +size_t Intel_Rdrand::poll(RandomNumberGenerator& rng) { + if(CPUID::has_rdrand() && BOTAN_ENTROPY_INTEL_RNG_POLLS > 0) + { + RDRAND_RNG rdrand_rng; + secure_vector<uint8_t> buf(4 * BOTAN_ENTROPY_INTEL_RNG_POLLS); + + rdrand_rng.randomize(buf.data(), buf.size()); + rng.add_entropy(buf.data(), buf.size()); + } + + // RDRAND is used but not trusted + return 0; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/entropy/rdrand/rdrand.h b/src/libs/3rdparty/botan/src/lib/entropy/rdrand/rdrand.h new file mode 100644 index 0000000000..6544fe57f9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/rdrand/rdrand.h @@ -0,0 +1,28 @@ +/* +* Entropy Source Using Intel's rdrand instruction +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_RDRAND_H_ +#define BOTAN_ENTROPY_SRC_RDRAND_H_ + +#include <botan/entropy_src.h> + +namespace Botan { + +/** +* Entropy source using the rdrand instruction first introduced on +* Intel's Ivy Bridge architecture. +*/ +class Intel_Rdrand final : public Entropy_Source + { + public: + std::string name() const override { return "rdrand"; } + size_t poll(RandomNumberGenerator& rng) override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/entropy/rdseed/info.txt b/src/libs/3rdparty/botan/src/lib/entropy/rdseed/info.txt new file mode 100644 index 0000000000..d4432e6c7f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/rdseed/info.txt @@ -0,0 +1,16 @@ +<defines> +ENTROPY_SRC_RDSEED -> 20151218 +</defines> + +need_isa rdseed + +<header:internal> +rdseed.h +</header:internal> + +<cc> +gcc +clang +icc +msvc +</cc> diff --git a/src/libs/3rdparty/botan/src/lib/entropy/rdseed/rdseed.cpp b/src/libs/3rdparty/botan/src/lib/entropy/rdseed/rdseed.cpp new file mode 100644 index 0000000000..fbb8f921e7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/rdseed/rdseed.cpp @@ -0,0 +1,48 @@ +/* +* Entropy Source Using Intel's rdseed instruction +* (C) 2015 Jack Lloyd, Daniel Neus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/rdseed.h> +#include <botan/cpuid.h> + +#if !defined(BOTAN_USE_GCC_INLINE_ASM) + #include <immintrin.h> +#endif + +namespace Botan { + +BOTAN_FUNC_ISA("rdseed") +size_t Intel_Rdseed::poll(RandomNumberGenerator& rng) { + if(CPUID::has_rdseed()) + { + for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p) + { + for(size_t i = 0; i != BOTAN_ENTROPY_RDSEED_RETRIES; ++i) + { + uint32_t r = 0; + +#if defined(BOTAN_USE_GCC_INLINE_ASM) + int cf = 0; + + // Encoding of rdseed %eax + asm(".byte 0x0F, 0xC7, 0xF8; adcl $0,%1" : + "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc"); +#else + int cf = _rdseed32_step(&r); +#endif + if(1 == cf) + { + rng.add_entropy_T(r); + break; + } + } + } + } + + return 0; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/entropy/rdseed/rdseed.h b/src/libs/3rdparty/botan/src/lib/entropy/rdseed/rdseed.h new file mode 100644 index 0000000000..da94bc0a10 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/rdseed/rdseed.h @@ -0,0 +1,28 @@ +/* +* Entropy Source Using Intel's rdseed instruction +* (C) 2015 Jack Lloyd, Daniel Neus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_RDSEED_H_ +#define BOTAN_ENTROPY_SRC_RDSEED_H_ + +#include <botan/entropy_src.h> + +namespace Botan { + +/** +* Entropy source using the rdseed instruction first introduced on +* Intel's Broadwell architecture. +*/ +class Intel_Rdseed final : public Entropy_Source + { + public: + std::string name() const override { return "rdseed"; } + size_t poll(RandomNumberGenerator& rng) override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/entropy/win32_stats/es_win32.cpp b/src/libs/3rdparty/botan/src/lib/entropy/win32_stats/es_win32.cpp new file mode 100644 index 0000000000..86d1f2cafb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/win32_stats/es_win32.cpp @@ -0,0 +1,121 @@ +/* +* Win32 EntropySource +* (C) 1999-2009,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/es_win32.h> + +#define NOMINMAX 1 +#define _WINSOCKAPI_ // stop windows.h including winsock.h +#include <windows.h> +#include <tlhelp32.h> + +namespace Botan { + +/** +* Win32 poll using stats functions including Tooltip32 +*/ +size_t Win32_EntropySource::poll(RandomNumberGenerator& rng) + { + const size_t POLL_TARGET = 128; + const size_t EST_ENTROPY_HEAP_INFO = 4; + const size_t EST_ENTROPY_THREAD_INFO = 2; + + /* + First query a bunch of basic statistical stuff + */ + rng.add_entropy_T(::GetTickCount()); + rng.add_entropy_T(::GetMessagePos()); + rng.add_entropy_T(::GetMessageTime()); + rng.add_entropy_T(::GetInputState()); + + rng.add_entropy_T(::GetCurrentProcessId()); + rng.add_entropy_T(::GetCurrentThreadId()); + + SYSTEM_INFO sys_info; + ::GetSystemInfo(&sys_info); + rng.add_entropy_T(sys_info); + + MEMORYSTATUSEX mem_info; + ::GlobalMemoryStatusEx(&mem_info); + rng.add_entropy_T(mem_info); + + POINT point; + ::GetCursorPos(&point); + rng.add_entropy_T(point); + + ::GetCaretPos(&point); + rng.add_entropy_T(point); + + /* + Now use the Tooltip library to iterate through various objects on + the system, including processes, threads, and heap objects. + */ + + HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); + size_t collected = 0; + +#define TOOLHELP32_ITER(DATA_TYPE, FUNC_FIRST, FUNC_NEXT) \ + if(collected < POLL_TARGET) \ + { \ + DATA_TYPE info; \ + info.dwSize = sizeof(DATA_TYPE); \ + if(FUNC_FIRST(snapshot, &info)) \ + { \ + do \ + { \ + rng.add_entropy_T(info); \ + collected += EST_ENTROPY_THREAD_INFO; \ + if(collected >= POLL_TARGET) \ + break; \ + } while(FUNC_NEXT(snapshot, &info)); \ + } \ + } + + TOOLHELP32_ITER(MODULEENTRY32, ::Module32First, ::Module32Next); + TOOLHELP32_ITER(PROCESSENTRY32, ::Process32First, ::Process32Next); + TOOLHELP32_ITER(THREADENTRY32, ::Thread32First, ::Thread32Next); + +#undef TOOLHELP32_ITER + + if(collected < POLL_TARGET) + { + HEAPLIST32 heap_list; + heap_list.dwSize = sizeof(HEAPLIST32); + + if(::Heap32ListFirst(snapshot, &heap_list)) + { + do + { + rng.add_entropy_T(heap_list); + + HEAPENTRY32 heap_entry; + heap_entry.dwSize = sizeof(HEAPENTRY32); + if(::Heap32First(&heap_entry, + heap_list.th32ProcessID, + heap_list.th32HeapID)) + { + do + { + rng.add_entropy_T(heap_entry); + collected += EST_ENTROPY_HEAP_INFO; + if(collected >= POLL_TARGET) + break; + } while(::Heap32Next(&heap_entry)); + } + + if(collected >= POLL_TARGET) + break; + + } while(::Heap32ListNext(snapshot, &heap_list)); + } + } + + ::CloseHandle(snapshot); + + return collected; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/entropy/win32_stats/es_win32.h b/src/libs/3rdparty/botan/src/lib/entropy/win32_stats/es_win32.h new file mode 100644 index 0000000000..2b11ee0801 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/win32_stats/es_win32.h @@ -0,0 +1,27 @@ +/* +* Win32 EntropySource +* (C) 1999-2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENTROPY_SRC_WIN32_H_ +#define BOTAN_ENTROPY_SRC_WIN32_H_ + +#include <botan/entropy_src.h> + +namespace Botan { + +/** +* Win32 Entropy Source +*/ +class Win32_EntropySource final : public Entropy_Source + { + public: + std::string name() const override { return "system_stats"; } + size_t poll(RandomNumberGenerator& rng) override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/entropy/win32_stats/info.txt b/src/libs/3rdparty/botan/src/lib/entropy/win32_stats/info.txt new file mode 100644 index 0000000000..3e3268183e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/entropy/win32_stats/info.txt @@ -0,0 +1,19 @@ +<defines> +ENTROPY_SRC_WIN32 -> 20131128 +</defines> + +<warning> +This module can cause false positives with antivirus systems +</warning> + +<header:internal> +es_win32.h +</header:internal> + +<os_features> +win32 +</os_features> + +<libs> +windows -> user32.lib +</libs> diff --git a/src/libs/3rdparty/botan/src/lib/filters/aead_filt.h b/src/libs/3rdparty/botan/src/lib/filters/aead_filt.h new file mode 100644 index 0000000000..f569423a69 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/aead_filt.h @@ -0,0 +1,40 @@ +/* +* Filter interface for AEAD Modes +* (C) 2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AEAD_FILTER_H_ +#define BOTAN_AEAD_FILTER_H_ + +#include <botan/cipher_filter.h> +#include <botan/aead.h> + +namespace Botan { + +/** +* Filter interface for AEAD Modes +*/ +class AEAD_Filter final : public Cipher_Mode_Filter + { + public: + AEAD_Filter(AEAD_Mode* aead) : Cipher_Mode_Filter(aead) {} + + /** + * Set associated data that is not included in the ciphertext but + * that should be authenticated. Must be called after set_key + * and before end_msg. + * + * @param ad the associated data + * @param ad_len length of add in bytes + */ + void set_associated_data(const uint8_t ad[], size_t ad_len) + { + dynamic_cast<AEAD_Mode&>(get_transform()).set_associated_data(ad, ad_len); + } + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/algo_filt.cpp b/src/libs/3rdparty/botan/src/lib/filters/algo_filt.cpp new file mode 100644 index 0000000000..c944b72e5b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/algo_filt.cpp @@ -0,0 +1,96 @@ +/* +* Filters +* (C) 1999-2007,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/filters.h> +#include <algorithm> + +namespace Botan { + +#if defined(BOTAN_HAS_STREAM_CIPHER) + +StreamCipher_Filter::StreamCipher_Filter(StreamCipher* cipher) : + m_buffer(BOTAN_DEFAULT_BUFFER_SIZE), + m_cipher(cipher) + { + } + +StreamCipher_Filter::StreamCipher_Filter(StreamCipher* cipher, const SymmetricKey& key) : + StreamCipher_Filter(cipher) + { + m_cipher->set_key(key); + } + +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name) : + m_buffer(BOTAN_DEFAULT_BUFFER_SIZE), + m_cipher(StreamCipher::create_or_throw(sc_name)) + { + } + +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name, const SymmetricKey& key) : + StreamCipher_Filter(sc_name) + { + m_cipher->set_key(key); + } + +void StreamCipher_Filter::write(const uint8_t input[], size_t length) + { + while(length) + { + size_t copied = std::min<size_t>(length, m_buffer.size()); + m_cipher->cipher(input, m_buffer.data(), copied); + send(m_buffer, copied); + input += copied; + length -= copied; + } + } + +#endif + +#if defined(BOTAN_HAS_HASH) + +Hash_Filter::Hash_Filter(const std::string& hash_name, size_t len) : + m_hash(HashFunction::create_or_throw(hash_name)), + m_out_len(len) + { + } + +void Hash_Filter::end_msg() + { + secure_vector<uint8_t> output = m_hash->final(); + if(m_out_len) + send(output, std::min<size_t>(m_out_len, output.size())); + else + send(output); + } +#endif + +#if defined(BOTAN_HAS_MAC) + +MAC_Filter::MAC_Filter(const std::string& mac_name, size_t len) : + m_mac(MessageAuthenticationCode::create_or_throw(mac_name)), + m_out_len(len) + { + } + +MAC_Filter::MAC_Filter(const std::string& mac_name, const SymmetricKey& key, size_t len) : + MAC_Filter(mac_name, len) + { + m_mac->set_key(key); + } + +void MAC_Filter::end_msg() + { + secure_vector<uint8_t> output = m_mac->final(); + if(m_out_len) + send(output, std::min<size_t>(m_out_len, output.size())); + else + send(output); + } + +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/basefilt.cpp b/src/libs/3rdparty/botan/src/lib/filters/basefilt.cpp new file mode 100644 index 0000000000..89026f6005 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/basefilt.cpp @@ -0,0 +1,70 @@ +/* +* Basic Filters +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/basefilt.h> +#include <botan/key_filt.h> + +namespace Botan { + +void Keyed_Filter::set_iv(const InitializationVector& iv) + { + if(iv.length() != 0) + throw Invalid_IV_Length(name(), iv.length()); + } + +/* +* Chain Constructor +*/ +Chain::Chain(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + if(f1) { attach(f1); incr_owns(); } + if(f2) { attach(f2); incr_owns(); } + if(f3) { attach(f3); incr_owns(); } + if(f4) { attach(f4); incr_owns(); } + } + +/* +* Chain Constructor +*/ +Chain::Chain(Filter* filters[], size_t count) + { + for(size_t j = 0; j != count; ++j) + if(filters[j]) + { + attach(filters[j]); + incr_owns(); + } + } + +std::string Chain::name() const + { + return "Chain"; + } + +/* +* Fork Constructor +*/ +Fork::Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + Filter* filters[4] = { f1, f2, f3, f4 }; + set_next(filters, 4); + } + +/* +* Fork Constructor +*/ +Fork::Fork(Filter* filters[], size_t count) + { + set_next(filters, count); + } + +std::string Fork::name() const + { + return "Fork"; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/basefilt.h b/src/libs/3rdparty/botan/src/lib/filters/basefilt.h new file mode 100644 index 0000000000..922d356693 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/basefilt.h @@ -0,0 +1,124 @@ +/* +* Basic Filters +* (C) 1999-2007 Jack Lloyd +* (C) 2013 Joel Low +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BASEFILT_H_ +#define BOTAN_BASEFILT_H_ + +#include <botan/filter.h> + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + #include <thread> +#endif + +namespace Botan { + +/** +* BitBucket is a filter which simply discards all inputs +*/ +class BOTAN_PUBLIC_API(2,0) BitBucket final : public Filter + { + public: + void write(const uint8_t[], size_t) override { /* discard */ } + + std::string name() const override { return "BitBucket"; } + }; + +/** +* This class represents Filter chains. A Filter chain is an ordered +* concatenation of Filters, the input to a Chain sequentially passes +* through all the Filters contained in the Chain. +*/ + +class BOTAN_PUBLIC_API(2,0) Chain final : public Fanout_Filter + { + public: + void write(const uint8_t input[], size_t length) override { send(input, length); } + + std::string name() const override; + + /** + * Construct a chain of up to four filters. The filters are set + * up in the same order as the arguments. + */ + Chain(Filter* = nullptr, Filter* = nullptr, + Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a chain from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Chain(Filter* filter_arr[], size_t length); + }; + +/** +* This class represents a fork filter, whose purpose is to fork the +* flow of data. It causes an input message to result in n messages at +* the end of the filter, where n is the number of forks. +*/ +class BOTAN_PUBLIC_API(2,0) Fork : public Fanout_Filter + { + public: + void write(const uint8_t input[], size_t length) override { send(input, length); } + void set_port(size_t n) { Fanout_Filter::set_port(n); } + + std::string name() const override; + + /** + * Construct a Fork filter with up to four forks. + */ + Fork(Filter*, Filter*, Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a Fork from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Fork(Filter* filter_arr[], size_t length); + }; + +#if defined(BOTAN_HAS_THREAD_UTILS) + +/** +* This class is a threaded version of the Fork filter. While this uses +* threads, the class itself is NOT thread-safe. This is meant as a drop- +* in replacement for Fork where performance gains are possible. +*/ +class BOTAN_PUBLIC_API(2,0) Threaded_Fork final : public Fork + { + public: + std::string name() const override; + + /** + * Construct a Threaded_Fork filter with up to four forks. + */ + Threaded_Fork(Filter*, Filter*, Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a Threaded_Fork from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Threaded_Fork(Filter* filter_arr[], size_t length); + + ~Threaded_Fork(); + + private: + void set_next(Filter* f[], size_t n); + void send(const uint8_t in[], size_t length) override; + void thread_delegate_work(const uint8_t input[], size_t length); + void thread_entry(Filter* filter); + + std::vector<std::shared_ptr<std::thread>> m_threads; + std::unique_ptr<struct Threaded_Fork_Data> m_thread_data; + }; +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/buf_filt.cpp b/src/libs/3rdparty/botan/src/lib/filters/buf_filt.cpp new file mode 100644 index 0000000000..8acc6c74f9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/buf_filt.cpp @@ -0,0 +1,103 @@ +/* +* Buffered Filter +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/buf_filt.h> +#include <botan/mem_ops.h> +#include <botan/internal/rounding.h> +#include <botan/exceptn.h> + +namespace Botan { + +/* +* Buffered_Filter Constructor +*/ +Buffered_Filter::Buffered_Filter(size_t b, size_t f) : + m_main_block_mod(b), m_final_minimum(f) + { + if(m_main_block_mod == 0) + throw Invalid_Argument("m_main_block_mod == 0"); + + if(m_final_minimum > m_main_block_mod) + throw Invalid_Argument("m_final_minimum > m_main_block_mod"); + + m_buffer.resize(2 * m_main_block_mod); + m_buffer_pos = 0; + } + +/* +* Buffer input into blocks, trying to minimize copying +*/ +void Buffered_Filter::write(const uint8_t input[], size_t input_size) + { + if(!input_size) + return; + + if(m_buffer_pos + input_size >= m_main_block_mod + m_final_minimum) + { + size_t to_copy = std::min<size_t>(m_buffer.size() - m_buffer_pos, input_size); + + copy_mem(&m_buffer[m_buffer_pos], input, to_copy); + m_buffer_pos += to_copy; + + input += to_copy; + input_size -= to_copy; + + size_t total_to_consume = + round_down(std::min(m_buffer_pos, + m_buffer_pos + input_size - m_final_minimum), + m_main_block_mod); + + buffered_block(m_buffer.data(), total_to_consume); + + m_buffer_pos -= total_to_consume; + + copy_mem(m_buffer.data(), m_buffer.data() + total_to_consume, m_buffer_pos); + } + + if(input_size >= m_final_minimum) + { + size_t full_blocks = (input_size - m_final_minimum) / m_main_block_mod; + size_t to_copy = full_blocks * m_main_block_mod; + + if(to_copy) + { + buffered_block(input, to_copy); + + input += to_copy; + input_size -= to_copy; + } + } + + copy_mem(&m_buffer[m_buffer_pos], input, input_size); + m_buffer_pos += input_size; + } + +/* +* Finish/flush operation +*/ +void Buffered_Filter::end_msg() + { + if(m_buffer_pos < m_final_minimum) + throw Exception("Buffered filter end_msg without enough input"); + + size_t spare_blocks = (m_buffer_pos - m_final_minimum) / m_main_block_mod; + + if(spare_blocks) + { + size_t spare_bytes = m_main_block_mod * spare_blocks; + buffered_block(m_buffer.data(), spare_bytes); + buffered_final(&m_buffer[spare_bytes], m_buffer_pos - spare_bytes); + } + else + { + buffered_final(m_buffer.data(), m_buffer_pos); + } + + m_buffer_pos = 0; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/buf_filt.h b/src/libs/3rdparty/botan/src/lib/filters/buf_filt.h new file mode 100644 index 0000000000..b4cd8e6809 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/buf_filt.h @@ -0,0 +1,93 @@ +/* +* Buffered Filter +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BUFFERED_FILTER_H_ +#define BOTAN_BUFFERED_FILTER_H_ + +#include <botan/secmem.h> + +namespace Botan { + +/** +* Filter mixin that breaks input into blocks, useful for +* cipher modes +*/ +class BOTAN_PUBLIC_API(2,0) Buffered_Filter + { + public: + /** + * Write bytes into the buffered filter, which will them emit them + * in calls to buffered_block in the subclass + * @param in the input bytes + * @param length of in in bytes + */ + void write(const uint8_t in[], size_t length); + + template<typename Alloc> + void write(const std::vector<uint8_t, Alloc>& in, size_t length) + { + write(in.data(), length); + } + + /** + * Finish a message, emitting to buffered_block and buffered_final + * Will throw an exception if less than final_minimum bytes were + * written into the filter. + */ + void end_msg(); + + /** + * Initialize a Buffered_Filter + * @param block_size the function buffered_block will be called + * with inputs which are a multiple of this size + * @param final_minimum the function buffered_final will be called + * with at least this many bytes. + */ + Buffered_Filter(size_t block_size, size_t final_minimum); + + virtual ~Buffered_Filter() = default; + protected: + /** + * The block processor, implemented by subclasses + * @param input some input bytes + * @param length the size of input, guaranteed to be a multiple + * of block_size + */ + virtual void buffered_block(const uint8_t input[], size_t length) = 0; + + /** + * The final block, implemented by subclasses + * @param input some input bytes + * @param length the size of input, guaranteed to be at least + * final_minimum bytes + */ + virtual void buffered_final(const uint8_t input[], size_t length) = 0; + + /** + * @return block size of inputs + */ + size_t buffered_block_size() const { return m_main_block_mod; } + + /** + * @return current position in the buffer + */ + size_t current_position() const { return m_buffer_pos; } + + /** + * Reset the buffer position + */ + void buffer_reset() { m_buffer_pos = 0; } + private: + size_t m_main_block_mod, m_final_minimum; + + secure_vector<uint8_t> m_buffer; + size_t m_buffer_pos; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.cpp b/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.cpp new file mode 100644 index 0000000000..a3e7bd1c39 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.cpp @@ -0,0 +1,103 @@ +/* +* Filter interface for Cipher_Modes +* (C) 2013,2014,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cipher_filter.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +namespace { + +size_t choose_update_size(size_t update_granularity) + { + const size_t target_size = 1024; + + if(update_granularity >= target_size) + return update_granularity; + + return round_up(target_size, update_granularity); + } + +} + +Cipher_Mode_Filter::Cipher_Mode_Filter(Cipher_Mode* mode) : + Buffered_Filter(choose_update_size(mode->update_granularity()), + mode->minimum_final_size()), + m_mode(mode), + m_nonce(mode->default_nonce_length()), + m_buffer(m_mode->update_granularity()) + { + } + +std::string Cipher_Mode_Filter::name() const + { + return m_mode->name(); + } + +void Cipher_Mode_Filter::set_iv(const InitializationVector& iv) + { + m_nonce = unlock(iv.bits_of()); + } + +void Cipher_Mode_Filter::set_key(const SymmetricKey& key) + { + m_mode->set_key(key); + } + +Key_Length_Specification Cipher_Mode_Filter::key_spec() const + { + return m_mode->key_spec(); + } + +bool Cipher_Mode_Filter::valid_iv_length(size_t length) const + { + return m_mode->valid_nonce_length(length); + } + +void Cipher_Mode_Filter::write(const uint8_t input[], size_t input_length) + { + Buffered_Filter::write(input, input_length); + } + +void Cipher_Mode_Filter::end_msg() + { + Buffered_Filter::end_msg(); + } + +void Cipher_Mode_Filter::start_msg() + { + if(m_nonce.empty() && !m_mode->valid_nonce_length(0)) + throw Invalid_State("Cipher " + m_mode->name() + " requires a fresh nonce for each message"); + + m_mode->start(m_nonce); + m_nonce.clear(); + } + +void Cipher_Mode_Filter::buffered_block(const uint8_t input[], size_t input_length) + { + while(input_length) + { + const size_t take = std::min(m_mode->update_granularity(), input_length); + + m_buffer.assign(input, input + take); + m_mode->update(m_buffer); + + send(m_buffer); + + input += take; + input_length -= take; + } + } + +void Cipher_Mode_Filter::buffered_final(const uint8_t input[], size_t input_length) + { + secure_vector<uint8_t> buf(input, input + input_length); + m_mode->finish(buf); + send(buf); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.h b/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.h new file mode 100644 index 0000000000..750385d152 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/cipher_filter.h @@ -0,0 +1,58 @@ +/* +* Filter interface for ciphers +* (C) 2013,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TRANSFORM_FILTER_H_ +#define BOTAN_TRANSFORM_FILTER_H_ + +#include <botan/cipher_mode.h> +#include <botan/key_filt.h> +#include <botan/buf_filt.h> + +namespace Botan { + +/** +* Filter interface for cipher modes +*/ +class BOTAN_PUBLIC_API(2,0) Cipher_Mode_Filter final : public Keyed_Filter, + private Buffered_Filter + { + public: + explicit Cipher_Mode_Filter(Cipher_Mode* t); + + explicit Cipher_Mode_Filter(std::unique_ptr<Cipher_Mode> t) : + Cipher_Mode_Filter(t.release()) {} + + void set_iv(const InitializationVector& iv) override; + + void set_key(const SymmetricKey& key) override; + + Key_Length_Specification key_spec() const override; + + bool valid_iv_length(size_t length) const override; + + std::string name() const override; + + private: + void write(const uint8_t input[], size_t input_length) override; + void start_msg() override; + void end_msg() override; + + void buffered_block(const uint8_t input[], size_t input_length) override; + void buffered_final(const uint8_t input[], size_t input_length) override; + + std::unique_ptr<Cipher_Mode> m_mode; + std::vector<uint8_t> m_nonce; + secure_vector<uint8_t> m_buffer; + }; + +// deprecated aliases, will be removed before 2.0 +typedef Cipher_Mode_Filter Transform_Filter; +typedef Transform_Filter Transformation_Filter; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/comp_filter.cpp b/src/libs/3rdparty/botan/src/lib/filters/comp_filter.cpp new file mode 100644 index 0000000000..2563a49077 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/comp_filter.cpp @@ -0,0 +1,122 @@ +/* +* Filter interface for compression +* (C) 2014,2015,2016 Jack Lloyd +* (C) 2015 Matej Kenda +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/comp_filter.h> +#include <botan/exceptn.h> + +#if defined(BOTAN_HAS_COMPRESSION) + #include <botan/compression.h> +#endif + +namespace Botan { + +#if defined(BOTAN_HAS_COMPRESSION) + +Compression_Filter::Compression_Filter(const std::string& type, size_t level, size_t bs) : + m_comp(make_compressor(type)), + m_buffersize(std::max<size_t>(bs, 256)), + m_level(level) + { + if(!m_comp) + { + throw Invalid_Argument("Compression type '" + type + "' not found"); + } + } + +Compression_Filter::~Compression_Filter() { /* for unique_ptr */ } + +std::string Compression_Filter::name() const + { + return m_comp->name(); + } + +void Compression_Filter::start_msg() + { + m_comp->start(m_level); + } + +void Compression_Filter::write(const uint8_t input[], size_t input_length) + { + while(input_length) + { + const size_t take = std::min(m_buffersize, input_length); + BOTAN_ASSERT(take > 0, "Consumed something"); + + m_buffer.assign(input, input + take); + m_comp->update(m_buffer); + + send(m_buffer); + + input += take; + input_length -= take; + } + } + +void Compression_Filter::flush() + { + m_buffer.clear(); + m_comp->update(m_buffer, 0, true); + send(m_buffer); + } + +void Compression_Filter::end_msg() + { + m_buffer.clear(); + m_comp->finish(m_buffer); + send(m_buffer); + } + +Decompression_Filter::Decompression_Filter(const std::string& type, size_t bs) : + m_comp(make_decompressor(type)), + m_buffersize(std::max<size_t>(bs, 256)) + { + if(!m_comp) + { + throw Invalid_Argument("Compression type '" + type + "' not found"); + } + } + +Decompression_Filter::~Decompression_Filter() { /* for unique_ptr */ } + +std::string Decompression_Filter::name() const + { + return m_comp->name(); + } + +void Decompression_Filter::start_msg() + { + m_comp->start(); + } + +void Decompression_Filter::write(const uint8_t input[], size_t input_length) + { + while(input_length) + { + const size_t take = std::min(m_buffersize, input_length); + BOTAN_ASSERT(take > 0, "Consumed something"); + + m_buffer.assign(input, input + take); + m_comp->update(m_buffer); + + send(m_buffer); + + input += take; + input_length -= take; + } + } + +void Decompression_Filter::end_msg() + { + m_buffer.clear(); + m_comp->finish(m_buffer); + send(m_buffer); + } + +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/comp_filter.h b/src/libs/3rdparty/botan/src/lib/filters/comp_filter.h new file mode 100644 index 0000000000..d9cc00b684 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/comp_filter.h @@ -0,0 +1,71 @@ +/* +* Filter interface for compression +* (C) 2014,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_COMPRESSION_FILTER_H_ +#define BOTAN_COMPRESSION_FILTER_H_ + +#include <botan/filter.h> + +namespace Botan { + +#if defined(BOTAN_HAS_COMPRESSION) + +class Compression_Algorithm; +class Decompression_Algorithm; + +/** +* Filter interface for compression +*/ +class BOTAN_PUBLIC_API(2,0) Compression_Filter final : public Filter + { + public: + void start_msg() override; + void write(const uint8_t input[], size_t input_length) override; + void end_msg() override; + + void flush(); + + std::string name() const override; + + Compression_Filter(const std::string& type, + size_t compression_level, + size_t buffer_size = 4096); + + ~Compression_Filter(); + private: + std::unique_ptr<Compression_Algorithm> m_comp; + size_t m_buffersize, m_level; + secure_vector<uint8_t> m_buffer; + }; + +/** +* Filter interface for decompression +*/ +class BOTAN_PUBLIC_API(2,0) Decompression_Filter final : public Filter + { + public: + void start_msg() override; + void write(const uint8_t input[], size_t input_length) override; + void end_msg() override; + + std::string name() const override; + + Decompression_Filter(const std::string& type, + size_t buffer_size = 4096); + + ~Decompression_Filter(); + private: + std::unique_ptr<Decompression_Algorithm> m_comp; + std::size_t m_buffersize; + secure_vector<uint8_t> m_buffer; + }; + +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/data_snk.cpp b/src/libs/3rdparty/botan/src/lib/filters/data_snk.cpp new file mode 100644 index 0000000000..9f0ddff96d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/data_snk.cpp @@ -0,0 +1,75 @@ +/* +* DataSink +* (C) 1999-2007 Jack Lloyd +* 2005 Matthew Gregan +* 2017 Philippe Lieser +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/data_snk.h> +#include <botan/exceptn.h> +#include <ostream> + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + #include <fstream> +#endif + +namespace Botan { + +/* +* Write to a stream +*/ +void DataSink_Stream::write(const uint8_t out[], size_t length) + { + m_sink.write(cast_uint8_ptr_to_char(out), length); + if(!m_sink.good()) + throw Stream_IO_Error("DataSink_Stream: Failure writing to " + + m_identifier); + } + +/* +* Flush the stream +*/ +void DataSink_Stream::end_msg() + { + m_sink.flush(); + } + +/* +* DataSink_Stream Constructor +*/ +DataSink_Stream::DataSink_Stream(std::ostream& out, + const std::string& name) : + m_identifier(name), + m_sink(out) + { + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +/* +* DataSink_Stream Constructor +*/ +DataSink_Stream::DataSink_Stream(const std::string& path, + bool use_binary) : + m_identifier(path), + m_sink_memory(new std::ofstream(path, use_binary ? std::ios::binary : std::ios::out)), + m_sink(*m_sink_memory) + { + if(!m_sink.good()) + { + throw Stream_IO_Error("DataSink_Stream: Failure opening " + path); + } + } +#endif + +/* +* DataSink_Stream Destructor +*/ +DataSink_Stream::~DataSink_Stream() + { + // for ~unique_ptr + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/data_snk.h b/src/libs/3rdparty/botan/src/lib/filters/data_snk.h new file mode 100644 index 0000000000..49484b1c1a --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/data_snk.h @@ -0,0 +1,76 @@ +/* +* DataSink +* (C) 1999-2007 Jack Lloyd +* 2017 Philippe Lieser +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DATA_SINK_H_ +#define BOTAN_DATA_SINK_H_ + +#include <botan/filter.h> +#include <memory> +#include <iosfwd> + +namespace Botan { + +/** +* This class represents abstract data sink objects. +*/ +class BOTAN_PUBLIC_API(2,0) DataSink : public Filter + { + public: + bool attachable() override { return false; } + DataSink() = default; + virtual ~DataSink() = default; + + DataSink& operator=(const DataSink&) = delete; + DataSink(const DataSink&) = delete; + }; + +/** +* This class represents a data sink which writes its output to a stream. +*/ +class BOTAN_PUBLIC_API(2,0) DataSink_Stream final : public DataSink + { + public: + /** + * Construct a DataSink_Stream from a stream. + * @param stream the stream to write to + * @param name identifier + */ + DataSink_Stream(std::ostream& stream, + const std::string& name = "<std::ostream>"); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + + /** + * Construct a DataSink_Stream from a filesystem path name. + * @param pathname the name of the file to open a stream to + * @param use_binary indicates whether to treat the file + * as a binary file or not + */ + DataSink_Stream(const std::string& pathname, + bool use_binary = false); +#endif + + std::string name() const override { return m_identifier; } + + void write(const uint8_t[], size_t) override; + + void end_msg() override; + + ~DataSink_Stream(); + + private: + const std::string m_identifier; + + // May be null, if m_sink was an external reference + std::unique_ptr<std::ostream> m_sink_memory; + std::ostream& m_sink; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/filter.cpp b/src/libs/3rdparty/botan/src/lib/filters/filter.cpp new file mode 100644 index 0000000000..6653fc7815 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/filter.cpp @@ -0,0 +1,129 @@ +/* +* Filter +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/filter.h> +#include <botan/exceptn.h> + +namespace Botan { + +/* +* Filter Constructor +*/ +Filter::Filter() + { + m_next.resize(1); + m_port_num = 0; + m_filter_owns = 0; + m_owned = false; + } + +/* +* Send data to all ports +*/ +void Filter::send(const uint8_t input[], size_t length) + { + if(!length) + return; + + bool nothing_attached = true; + for(size_t j = 0; j != total_ports(); ++j) + if(m_next[j]) + { + if(m_write_queue.size()) + m_next[j]->write(m_write_queue.data(), m_write_queue.size()); + m_next[j]->write(input, length); + nothing_attached = false; + } + + if(nothing_attached) + m_write_queue += std::make_pair(input, length); + else + m_write_queue.clear(); + } + +/* +* Start a new message +*/ +void Filter::new_msg() + { + start_msg(); + for(size_t j = 0; j != total_ports(); ++j) + if(m_next[j]) + m_next[j]->new_msg(); + } + +/* +* End the current message +*/ +void Filter::finish_msg() + { + end_msg(); + for(size_t j = 0; j != total_ports(); ++j) + if(m_next[j]) + m_next[j]->finish_msg(); + } + +/* +* Attach a filter to the current port +*/ +void Filter::attach(Filter* new_filter) + { + if(new_filter) + { + Filter* last = this; + while(last->get_next()) + last = last->get_next(); + last->m_next[last->current_port()] = new_filter; + } + } + +/* +* Set the active port on a filter +*/ +void Filter::set_port(size_t new_port) + { + if(new_port >= total_ports()) + throw Invalid_Argument("Filter: Invalid port number"); + m_port_num = new_port; + } + +/* +* Return the next Filter in the logical chain +*/ +Filter* Filter::get_next() const + { + if(m_port_num < m_next.size()) + return m_next[m_port_num]; + return nullptr; + } + +/* +* Set the next Filters +*/ +void Filter::set_next(Filter* filters[], size_t size) + { + m_next.clear(); + + m_port_num = 0; + m_filter_owns = 0; + + while(size && filters && (filters[size-1] == nullptr)) + --size; + + if(filters && size) + m_next.assign(filters, filters + size); + } + +/* +* Return the total number of ports +*/ +size_t Filter::total_ports() const + { + return m_next.size(); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/filter.h b/src/libs/3rdparty/botan/src/lib/filters/filter.h new file mode 100644 index 0000000000..a0857c589e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/filter.h @@ -0,0 +1,183 @@ +/* +* Filter +* (C) 1999-2007 Jack Lloyd +* (C) 2013 Joel Low +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FILTER_H_ +#define BOTAN_FILTER_H_ + +#include <botan/secmem.h> +#include <vector> +#include <string> + +namespace Botan { + +/** +* This class represents general abstract filter objects. +*/ +class BOTAN_PUBLIC_API(2,0) Filter + { + public: + /** + * @return descriptive name for this filter + */ + virtual std::string name() const = 0; + + /** + * Write a portion of a message to this filter. + * @param input the input as a byte array + * @param length the length of the byte array input + */ + virtual void write(const uint8_t input[], size_t length) = 0; + + /** + * Start a new message. Must be closed by end_msg() before another + * message can be started. + */ + virtual void start_msg() { /* default empty */ } + + /** + * Notify that the current message is finished; flush buffers and + * do end-of-message processing (if any). + */ + virtual void end_msg() { /* default empty */ } + + /** + * Check whether this filter is an attachable filter. + * @return true if this filter is attachable, false otherwise + */ + virtual bool attachable() { return true; } + + virtual ~Filter() = default; + protected: + /** + * @param in some input for the filter + * @param length the length of in + */ + virtual void send(const uint8_t in[], size_t length); + + /** + * @param in some input for the filter + */ + void send(uint8_t in) { send(&in, 1); } + + /** + * @param in some input for the filter + */ + void send(const secure_vector<uint8_t>& in) { send(in.data(), in.size()); } + + /** + * @param in some input for the filter + */ + void send(const std::vector<uint8_t>& in) { send(in.data(), in.size()); } + + /** + * @param in some input for the filter + * @param length the number of bytes of in to send + */ + void send(const secure_vector<uint8_t>& in, size_t length) + { + send(in.data(), length); + } + + /** + * @param in some input for the filter + * @param length the number of bytes of in to send + */ + void send(const std::vector<uint8_t>& in, size_t length) + { + send(in.data(), length); + } + + Filter(); + + Filter(const Filter&) = delete; + + Filter& operator=(const Filter&) = delete; + + private: + /** + * Start a new message in *this and all following filters. Only for + * internal use, not intended for use in client applications. + */ + void new_msg(); + + /** + * End a new message in *this and all following filters. Only for + * internal use, not intended for use in client applications. + */ + void finish_msg(); + + friend class Pipe; + friend class Fanout_Filter; + + size_t total_ports() const; + size_t current_port() const { return m_port_num; } + + /** + * Set the active port + * @param new_port the new value + */ + void set_port(size_t new_port); + + size_t owns() const { return m_filter_owns; } + + /** + * Attach another filter to this one + * @param f filter to attach + */ + void attach(Filter* f); + + /** + * @param filters the filters to set + * @param count number of items in filters + */ + void set_next(Filter* filters[], size_t count); + Filter* get_next() const; + + secure_vector<uint8_t> m_write_queue; + std::vector<Filter*> m_next; // not owned + size_t m_port_num, m_filter_owns; + + // true if filter belongs to a pipe --> prohibit filter sharing! + bool m_owned; + }; + +/** +* This is the abstract Fanout_Filter base class. +**/ +class BOTAN_PUBLIC_API(2,0) Fanout_Filter : public Filter + { + protected: + /** + * Increment the number of filters past us that we own + */ + void incr_owns() { ++m_filter_owns; } + + void set_port(size_t n) { Filter::set_port(n); } + + void set_next(Filter* f[], size_t n) { Filter::set_next(f, n); } + + void attach(Filter* f) { Filter::attach(f); } + + private: + friend class Threaded_Fork; + using Filter::m_write_queue; + using Filter::total_ports; + using Filter::m_next; + }; + +/** +* The type of checking to be performed by decoders: +* NONE - no checks, IGNORE_WS - perform checks, but ignore +* whitespaces, FULL_CHECK - perform checks, also complain +* about white spaces. +*/ +enum Decoder_Checking { NONE, IGNORE_WS, FULL_CHECK }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/filters.h b/src/libs/3rdparty/botan/src/lib/filters/filters.h new file mode 100644 index 0000000000..b4aee12078 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/filters.h @@ -0,0 +1,227 @@ +/* +* Filters +* (C) 1999-2007,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_FILTERS_H_ +#define BOTAN_FILTERS_H_ + +#include <botan/basefilt.h> +#include <botan/key_filt.h> +#include <botan/data_snk.h> +#include <botan/pipe.h> + +#if defined(BOTAN_HAS_STREAM_CIPHER) + #include <botan/stream_cipher.h> +#endif + +#if defined(BOTAN_HAS_HASH) + #include <botan/hash.h> +#endif + +#if defined(BOTAN_HAS_MAC) + #include <botan/mac.h> +#endif + +#if defined(BOTAN_HAS_CODEC_FILTERS) + #include <botan/b64_filt.h> + #include <botan/hex_filt.h> +#endif + +namespace Botan { + +#if defined(BOTAN_HAS_STREAM_CIPHER) + +/** +* Stream Cipher Filter +*/ +class BOTAN_PUBLIC_API(2,0) StreamCipher_Filter final : public Keyed_Filter + { + public: + + std::string name() const override { return m_cipher->name(); } + + /** + * Write input data + * @param input data + * @param input_len length of input in bytes + */ + void write(const uint8_t input[], size_t input_len) override; + + bool valid_iv_length(size_t iv_len) const override + { return m_cipher->valid_iv_length(iv_len); } + + /** + * Set the initialization vector for this filter. + * @param iv the initialization vector to set + */ + void set_iv(const InitializationVector& iv) override + { + m_cipher->set_iv(iv.begin(), iv.length()); + } + + /** + * Set the key of this filter. + * @param key the key to set + */ + void set_key(const SymmetricKey& key) override { m_cipher->set_key(key); } + + Key_Length_Specification key_spec() const override { return m_cipher->key_spec(); } + + /** + * Construct a stream cipher filter. + * @param cipher a cipher object to use + */ + explicit StreamCipher_Filter(StreamCipher* cipher); + + /** + * Construct a stream cipher filter. + * @param cipher a cipher object to use + * @param key the key to use inside this filter + */ + StreamCipher_Filter(StreamCipher* cipher, const SymmetricKey& key); + + /** + * Construct a stream cipher filter. + * @param cipher the name of the desired cipher + */ + explicit StreamCipher_Filter(const std::string& cipher); + + /** + * Construct a stream cipher filter. + * @param cipher the name of the desired cipher + * @param key the key to use inside this filter + */ + StreamCipher_Filter(const std::string& cipher, const SymmetricKey& key); + private: + secure_vector<uint8_t> m_buffer; + std::unique_ptr<StreamCipher> m_cipher; + }; +#endif + +#if defined(BOTAN_HAS_HASH) + +/** +* Hash Filter. +*/ +class BOTAN_PUBLIC_API(2,0) Hash_Filter final : public Filter + { + public: + void write(const uint8_t input[], size_t len) override { m_hash->update(input, len); } + void end_msg() override; + + std::string name() const override { return m_hash->name(); } + + /** + * Construct a hash filter. + * @param hash the hash function to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the hashfunction + * hash. Otherwise, specify a smaller value here so that the + * output of the hash algorithm will be cut off. + */ + Hash_Filter(HashFunction* hash, size_t len = 0) : + m_hash(hash), m_out_len(len) {} + + /** + * Construct a hash filter. + * @param request the name of the hash algorithm to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the hashfunction + * hash. Otherwise, specify a smaller value here so that the + * output of the hash algorithm will be cut off. + */ + Hash_Filter(const std::string& request, size_t len = 0); + + private: + std::unique_ptr<HashFunction> m_hash; + const size_t m_out_len; + }; +#endif + +#if defined(BOTAN_HAS_MAC) + +/** +* MessageAuthenticationCode Filter. +*/ +class BOTAN_PUBLIC_API(2,0) MAC_Filter final : public Keyed_Filter + { + public: + void write(const uint8_t input[], size_t len) override { m_mac->update(input, len); } + void end_msg() override; + + std::string name() const override { return m_mac->name(); } + + /** + * Set the key of this filter. + * @param key the key to set + */ + void set_key(const SymmetricKey& key) override { m_mac->set_key(key); } + + Key_Length_Specification key_spec() const override { return m_mac->key_spec(); } + + /** + * Construct a MAC filter. The MAC key will be left empty. + * @param mac the MAC to use + * @param out_len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(MessageAuthenticationCode* mac, + size_t out_len = 0) : + m_mac(mac), + m_out_len(out_len) + { + } + + /** + * Construct a MAC filter. + * @param mac the MAC to use + * @param key the MAC key to use + * @param out_len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(MessageAuthenticationCode* mac, + const SymmetricKey& key, + size_t out_len = 0) : + m_mac(mac), + m_out_len(out_len) + { + m_mac->set_key(key); + } + + /** + * Construct a MAC filter. The MAC key will be left empty. + * @param mac the name of the MAC to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(const std::string& mac, size_t len = 0); + + /** + * Construct a MAC filter. + * @param mac the name of the MAC to use + * @param key the MAC key to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(const std::string& mac, const SymmetricKey& key, + size_t len = 0); + private: + std::unique_ptr<MessageAuthenticationCode> m_mac; + const size_t m_out_len; + }; +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/info.txt b/src/libs/3rdparty/botan/src/lib/filters/info.txt new file mode 100644 index 0000000000..cfc1143536 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/info.txt @@ -0,0 +1,24 @@ +<defines> +FILTERS -> 20160415 +</defines> + +<header:public> +basefilt.h +buf_filt.h +data_snk.h +comp_filter.h +filter.h +filters.h +key_filt.h +pipe.h +secqueue.h +cipher_filter.h +</header:public> + +<header:internal> +out_buf.h +</header:internal> + +<requires> +modes +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/filters/key_filt.cpp b/src/libs/3rdparty/botan/src/lib/filters/key_filt.cpp new file mode 100644 index 0000000000..b87a8c87f3 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/key_filt.cpp @@ -0,0 +1,39 @@ +/* +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/key_filt.h> +#include <botan/cipher_filter.h> + +namespace Botan { + +Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir direction) + { + std::unique_ptr<Cipher_Mode> c(Cipher_Mode::create_or_throw(algo_spec, direction)); + return new Cipher_Mode_Filter(c.release()); + } + +Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + const InitializationVector& iv, + Cipher_Dir direction) + { + Keyed_Filter* cipher = get_cipher(algo_spec, key, direction); + if(iv.length()) + cipher->set_iv(iv); + return cipher; + } + +Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + Cipher_Dir direction) + { + Keyed_Filter* cipher = get_cipher(algo_spec, direction); + cipher->set_key(key); + return cipher; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/key_filt.h b/src/libs/3rdparty/botan/src/lib/filters/key_filt.h new file mode 100644 index 0000000000..67b689f998 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/key_filt.h @@ -0,0 +1,109 @@ +/* +* Keyed_Filter +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KEYED_FILTER_H_ +#define BOTAN_KEYED_FILTER_H_ + +#include <botan/symkey.h> +#include <botan/filter.h> +#include <botan/cipher_mode.h> + +namespace Botan { + +/** +* This class represents keyed filters, i.e. filters that have to be +* fed with a key in order to function. +*/ +class BOTAN_PUBLIC_API(2,0) Keyed_Filter : public Filter + { + public: + /** + * Set the key of this filter + * @param key the key to use + */ + virtual void set_key(const SymmetricKey& key) = 0; + + /** + * Set the initialization vector of this filter. Note: you should + * call set_iv() only after you have called set_key() + * @param iv the initialization vector to use + */ + virtual void set_iv(const InitializationVector& iv); + + /** + * Check whether a key length is valid for this filter + * @param length the key length to be checked for validity + * @return true if the key length is valid, false otherwise + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * Check whether an IV length is valid for this filter + * @param length the IV length to be checked for validity + * @return true if the IV length is valid, false otherwise + */ + virtual bool valid_iv_length(size_t length) const + { return (length == 0); } + }; + + + +/* +* Get a cipher object +*/ + +/** +* Factory method for general symmetric cipher filters. +* @param algo_spec the name of the desired cipher +* @param key the key to be used for encryption/decryption performed by +* the filter +* @param iv the initialization vector to be used +* @param direction determines whether the filter will be an encrypting +* or decrypting filter +* @return pointer to newly allocated encryption or decryption filter +*/ +BOTAN_PUBLIC_API(2,0) Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + const InitializationVector& iv, + Cipher_Dir direction); + +/** +* Factory method for general symmetric cipher filters. +* @param algo_spec the name of the desired cipher +* @param key the key to be used for encryption/decryption performed by +* the filter +* @param direction determines whether the filter will be an encrypting +* or decrypting filter +* @return pointer to the encryption or decryption filter +*/ +BOTAN_PUBLIC_API(2,0) Keyed_Filter* get_cipher(const std::string& algo_spec, + const SymmetricKey& key, + Cipher_Dir direction); + +/** +* Factory method for general symmetric cipher filters. No key will be +* set in the filter. +* +* @param algo_spec the name of the desired cipher +* @param direction determines whether the filter will be an encrypting or +* decrypting filter +* @return pointer to the encryption or decryption filter +*/ +BOTAN_PUBLIC_API(2,0) Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir direction); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/out_buf.cpp b/src/libs/3rdparty/botan/src/lib/filters/out_buf.cpp new file mode 100644 index 0000000000..645cc08236 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/out_buf.cpp @@ -0,0 +1,121 @@ +/* +* Pipe Output Buffer +* (C) 1999-2007,2011 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/out_buf.h> +#include <botan/secqueue.h> + +namespace Botan { + +/* +* Read data from a message +*/ +size_t Output_Buffers::read(uint8_t output[], size_t length, + Pipe::message_id msg) + { + SecureQueue* q = get(msg); + if(q) + return q->read(output, length); + return 0; + } + +/* +* Peek at data in a message +*/ +size_t Output_Buffers::peek(uint8_t output[], size_t length, + size_t stream_offset, + Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if(q) + return q->peek(output, length, stream_offset); + return 0; + } + +/* +* Check available bytes in a message +*/ +size_t Output_Buffers::remaining(Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if(q) + return q->size(); + return 0; + } + +/* +* Return the total bytes of a message that have already been read. +*/ +size_t Output_Buffers::get_bytes_read(Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if (q) + return q->get_bytes_read(); + return 0; + } + +/* +* Add a new output queue +*/ +void Output_Buffers::add(SecureQueue* queue) + { + BOTAN_ASSERT(queue, "queue was provided"); + + BOTAN_ASSERT(m_buffers.size() < m_buffers.max_size(), + "Room was available in container"); + + m_buffers.push_back(std::unique_ptr<SecureQueue>(queue)); + } + +/* +* Retire old output queues +*/ +void Output_Buffers::retire() + { + for(size_t i = 0; i != m_buffers.size(); ++i) + if(m_buffers[i] && m_buffers[i]->size() == 0) + { + m_buffers[i].reset(); + } + + while(m_buffers.size() && !m_buffers[0]) + { + m_buffers.pop_front(); + m_offset = m_offset + Pipe::message_id(1); + } + } + +/* +* Get a particular output queue +*/ +SecureQueue* Output_Buffers::get(Pipe::message_id msg) const + { + if(msg < m_offset) + return nullptr; + + BOTAN_ASSERT(msg < message_count(), "Message number is in range"); + + return m_buffers[msg-m_offset].get(); + } + +/* +* Return the total number of messages +*/ +Pipe::message_id Output_Buffers::message_count() const + { + return (m_offset + m_buffers.size()); + } + +/* +* Output_Buffers Constructor +*/ +Output_Buffers::Output_Buffers() + { + m_offset = 0; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/out_buf.h b/src/libs/3rdparty/botan/src/lib/filters/out_buf.h new file mode 100644 index 0000000000..d6efbdaf27 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/out_buf.h @@ -0,0 +1,44 @@ +/* +* Output Buffer +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OUTPUT_BUFFER_H_ +#define BOTAN_OUTPUT_BUFFER_H_ + +#include <botan/types.h> +#include <botan/pipe.h> +#include <deque> + +namespace Botan { + +/** +* Container of output buffers for Pipe +*/ +class Output_Buffers final + { + public: + size_t read(uint8_t[], size_t, Pipe::message_id); + size_t peek(uint8_t[], size_t, size_t, Pipe::message_id) const; + size_t get_bytes_read(Pipe::message_id) const; + size_t remaining(Pipe::message_id) const; + + void add(class SecureQueue*); + void retire(); + + Pipe::message_id message_count() const; + + Output_Buffers(); + private: + class SecureQueue* get(Pipe::message_id) const; + + std::deque<std::unique_ptr<SecureQueue>> m_buffers; + Pipe::message_id m_offset; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/pipe.cpp b/src/libs/3rdparty/botan/src/lib/filters/pipe.cpp new file mode 100644 index 0000000000..0bba81bf2d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/pipe.cpp @@ -0,0 +1,311 @@ +/* +* Pipe +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pipe.h> +#include <botan/internal/out_buf.h> +#include <botan/secqueue.h> + +namespace Botan { + +namespace { + +/* +* A Filter that does nothing +*/ +class Null_Filter final : public Filter + { + public: + void write(const uint8_t input[], size_t length) override + { send(input, length); } + + std::string name() const override { return "Null"; } + }; + +} + +/* +* Pipe Constructor +*/ +Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4) : + Pipe({f1,f2,f3,f4}) + { + } + +/* +* Pipe Constructor +*/ +Pipe::Pipe(std::initializer_list<Filter*> args) + { + m_outputs.reset(new Output_Buffers); + m_pipe = nullptr; + m_default_read = 0; + m_inside_msg = false; + + for(auto i = args.begin(); i != args.end(); ++i) + do_append(*i); + } + +/* +* Pipe Destructor +*/ +Pipe::~Pipe() + { + destruct(m_pipe); + } + +/* +* Reset the Pipe +*/ +void Pipe::reset() + { + destruct(m_pipe); + m_pipe = nullptr; + m_inside_msg = false; + } + +/* +* Destroy the Pipe +*/ +void Pipe::destruct(Filter* to_kill) + { + if(!to_kill || dynamic_cast<SecureQueue*>(to_kill)) + return; + for(size_t j = 0; j != to_kill->total_ports(); ++j) + destruct(to_kill->m_next[j]); + delete to_kill; + } + +/* +* Test if the Pipe has any data in it +*/ +bool Pipe::end_of_data() const + { + return (remaining() == 0); + } + +/* +* Set the default read message +*/ +void Pipe::set_default_msg(message_id msg) + { + if(msg >= message_count()) + throw Invalid_Argument("Pipe::set_default_msg: msg number is too high"); + m_default_read = msg; + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const uint8_t input[], size_t length) + { + start_msg(); + write(input, length); + end_msg(); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const secure_vector<uint8_t>& input) + { + process_msg(input.data(), input.size()); + } + +void Pipe::process_msg(const std::vector<uint8_t>& input) + { + process_msg(input.data(), input.size()); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const std::string& input) + { + process_msg(cast_char_ptr_to_uint8(input.data()), input.length()); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(DataSource& input) + { + start_msg(); + write(input); + end_msg(); + } + +/* +* Start a new message +*/ +void Pipe::start_msg() + { + if(m_inside_msg) + throw Invalid_State("Pipe::start_msg: Message was already started"); + if(m_pipe == nullptr) + m_pipe = new Null_Filter; + find_endpoints(m_pipe); + m_pipe->new_msg(); + m_inside_msg = true; + } + +/* +* End the current message +*/ +void Pipe::end_msg() + { + if(!m_inside_msg) + throw Invalid_State("Pipe::end_msg: Message was already ended"); + m_pipe->finish_msg(); + clear_endpoints(m_pipe); + if(dynamic_cast<Null_Filter*>(m_pipe)) + { + delete m_pipe; + m_pipe = nullptr; + } + m_inside_msg = false; + + m_outputs->retire(); + } + +/* +* Find the endpoints of the Pipe +*/ +void Pipe::find_endpoints(Filter* f) + { + for(size_t j = 0; j != f->total_ports(); ++j) + if(f->m_next[j] && !dynamic_cast<SecureQueue*>(f->m_next[j])) + find_endpoints(f->m_next[j]); + else + { + SecureQueue* q = new SecureQueue; + f->m_next[j] = q; + m_outputs->add(q); + } + } + +/* +* Remove the SecureQueues attached to the Filter +*/ +void Pipe::clear_endpoints(Filter* f) + { + if(!f) return; + for(size_t j = 0; j != f->total_ports(); ++j) + { + if(f->m_next[j] && dynamic_cast<SecureQueue*>(f->m_next[j])) + f->m_next[j] = nullptr; + clear_endpoints(f->m_next[j]); + } + } + +void Pipe::append(Filter* filter) + { + do_append(filter); + } + +void Pipe::append_filter(Filter* filter) + { + if(m_outputs->message_count() != 0) + throw Invalid_State("Cannot call Pipe::append_filter after start_msg"); + + do_append(filter); + } + +void Pipe::prepend(Filter* filter) + { + do_prepend(filter); + } + +void Pipe::prepend_filter(Filter* filter) + { + if(m_outputs->message_count() != 0) + throw Invalid_State("Cannot call Pipe::prepend_filter after start_msg"); + + do_prepend(filter); + } + +/* +* Append a Filter to the Pipe +*/ +void Pipe::do_append(Filter* filter) + { + if(!filter) + return; + if(dynamic_cast<SecureQueue*>(filter)) + throw Invalid_Argument("Pipe::append: SecureQueue cannot be used"); + if(filter->m_owned) + throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); + + if(m_inside_msg) + throw Invalid_State("Cannot append to a Pipe while it is processing"); + + filter->m_owned = true; + + if(!m_pipe) m_pipe = filter; + else m_pipe->attach(filter); + } + +/* +* Prepend a Filter to the Pipe +*/ +void Pipe::do_prepend(Filter* filter) + { + if(m_inside_msg) + throw Invalid_State("Cannot prepend to a Pipe while it is processing"); + if(!filter) + return; + if(dynamic_cast<SecureQueue*>(filter)) + throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used"); + if(filter->m_owned) + throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); + + filter->m_owned = true; + + if(m_pipe) filter->attach(m_pipe); + m_pipe = filter; + } + +/* +* Pop a Filter off the Pipe +*/ +void Pipe::pop() + { + if(m_inside_msg) + throw Invalid_State("Cannot pop off a Pipe while it is processing"); + + if(!m_pipe) + return; + + if(m_pipe->total_ports() > 1) + throw Invalid_State("Cannot pop off a Filter with multiple ports"); + + size_t to_remove = m_pipe->owns() + 1; + + while(to_remove--) + { + std::unique_ptr<Filter> to_destroy(m_pipe); + m_pipe = m_pipe->m_next[0]; + } + } + +/* +* Return the number of messages in this Pipe +*/ +Pipe::message_id Pipe::message_count() const + { + return m_outputs->message_count(); + } + +/* +* Static Member Variables +*/ +const Pipe::message_id Pipe::LAST_MESSAGE = + static_cast<Pipe::message_id>(-2); + +const Pipe::message_id Pipe::DEFAULT_MESSAGE = + static_cast<Pipe::message_id>(-1); + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/pipe.h b/src/libs/3rdparty/botan/src/lib/filters/pipe.h new file mode 100644 index 0000000000..03b5160835 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/pipe.h @@ -0,0 +1,379 @@ +/* +* Pipe +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PIPE_H_ +#define BOTAN_PIPE_H_ + +#include <botan/data_src.h> +#include <botan/exceptn.h> +#include <initializer_list> +#include <iosfwd> + +namespace Botan { + +class Filter; +class Output_Buffers; + +/** +* This class represents pipe objects. +* A set of filters can be placed into a pipe, and information flows +* through the pipe until it reaches the end, where the output is +* collected for retrieval. If you're familiar with the Unix shell +* environment, this design will sound quite familiar. +*/ +class BOTAN_PUBLIC_API(2,0) Pipe final : public DataSource + { + public: + /** + * An opaque type that identifies a message in this Pipe + */ + typedef size_t message_id; + + /** + * Exception if you use an invalid message as an argument to + * read, remaining, etc + */ + class BOTAN_PUBLIC_API(2,0) Invalid_Message_Number final : public Invalid_Argument + { + public: + /** + * @param where the error occurred + * @param msg the invalid message id that was used + */ + Invalid_Message_Number(const std::string& where, message_id msg) : + Invalid_Argument("Pipe::" + where + ": Invalid message number " + + std::to_string(msg)) + {} + }; + + /** + * A meta-id for whatever the last message is + */ + static const message_id LAST_MESSAGE; + + /** + * A meta-id for the default message (set with set_default_msg) + */ + static const message_id DEFAULT_MESSAGE; + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the byte array to write + * @param length the length of the byte array in + */ + void write(const uint8_t in[], size_t length); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the secure_vector containing the data to write + */ + void write(const secure_vector<uint8_t>& in) + { write(in.data(), in.size()); } + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the std::vector containing the data to write + */ + void write(const std::vector<uint8_t>& in) + { write(in.data(), in.size()); } + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the string containing the data to write + */ + void write(const std::string& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the DataSource to read the data from + */ + void write(DataSource& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in a single byte to be written + */ + void write(uint8_t in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the byte array containing the data to write + * @param length the length of the byte array to write + */ + void process_msg(const uint8_t in[], size_t length); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the secure_vector containing the data to write + */ + void process_msg(const secure_vector<uint8_t>& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the secure_vector containing the data to write + */ + void process_msg(const std::vector<uint8_t>& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the string containing the data to write + */ + void process_msg(const std::string& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the DataSource providing the data to write + */ + void process_msg(DataSource& in); + + /** + * Find out how many bytes are ready to read. + * @param msg the number identifying the message + * for which the information is desired + * @return number of bytes that can still be read + */ + size_t remaining(message_id msg = DEFAULT_MESSAGE) const BOTAN_WARN_UNUSED_RESULT; + + /** + * Read the default message from the pipe. Moves the internal + * offset so that every call to read will return a new portion of + * the message. + * + * @param output the byte array to write the read bytes to + * @param length the length of the byte array output + * @return number of bytes actually read into output + */ + size_t read(uint8_t output[], size_t length) override BOTAN_WARN_UNUSED_RESULT; + + /** + * Read a specified message from the pipe. Moves the internal + * offset so that every call to read will return a new portion of + * the message. + * @param output the byte array to write the read bytes to + * @param length the length of the byte array output + * @param msg the number identifying the message to read from + * @return number of bytes actually read into output + */ + size_t read(uint8_t output[], size_t length, message_id msg) BOTAN_WARN_UNUSED_RESULT; + + /** + * Read a single byte from the pipe. Moves the internal offset so + * that every call to read will return a new portion of the + * message. + * + * @param output the byte to write the result to + * @param msg the message to read from + * @return number of bytes actually read into output + */ + size_t read(uint8_t& output, message_id msg = DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT; + + /** + * Read the full contents of the pipe. + * @param msg the number identifying the message to read from + * @return secure_vector holding the contents of the pipe + */ + secure_vector<uint8_t> read_all(message_id msg = DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT; + + /** + * Read the full contents of the pipe. + * @param msg the number identifying the message to read from + * @return string holding the contents of the pipe + */ + std::string read_all_as_string(message_id msg = DEFAULT_MESSAGE) BOTAN_WARN_UNUSED_RESULT; + + /** + * Read from the default message but do not modify the internal + * offset. Consecutive calls to peek() will return portions of + * the message starting at the same position. + * @param output the byte array to write the peeked message part to + * @param length the length of the byte array output + * @param offset the offset from the current position in message + * @return number of bytes actually peeked and written into output + */ + size_t peek(uint8_t output[], size_t length, size_t offset) const override BOTAN_WARN_UNUSED_RESULT; + + /** Read from the specified message but do not modify the + * internal offset. Consecutive calls to peek() will return + * portions of the message starting at the same position. + * @param output the byte array to write the peeked message part to + * @param length the length of the byte array output + * @param offset the offset from the current position in message + * @param msg the number identifying the message to peek from + * @return number of bytes actually peeked and written into output + */ + size_t peek(uint8_t output[], size_t length, + size_t offset, message_id msg) const BOTAN_WARN_UNUSED_RESULT; + + /** Read a single byte from the specified message but do not + * modify the internal offset. Consecutive calls to peek() will + * return portions of the message starting at the same position. + * @param output the byte to write the peeked message byte to + * @param offset the offset from the current position in message + * @param msg the number identifying the message to peek from + * @return number of bytes actually peeked and written into output + */ + size_t peek(uint8_t& output, size_t offset, + message_id msg = DEFAULT_MESSAGE) const BOTAN_WARN_UNUSED_RESULT; + + /** + * @return the number of bytes read from the default message. + */ + size_t get_bytes_read() const override; + + /** + * @return the number of bytes read from the specified message. + */ + size_t get_bytes_read(message_id msg) const; + + bool check_available(size_t n) override; + bool check_available_msg(size_t n, message_id msg); + + /** + * @return currently set default message + */ + size_t default_msg() const { return m_default_read; } + + /** + * Set the default message + * @param msg the number identifying the message which is going to + * be the new default message + */ + void set_default_msg(message_id msg); + + /** + * Get the number of messages the are in this pipe. + * @return number of messages the are in this pipe + */ + message_id message_count() const; + + /** + * Test whether this pipe has any data that can be read from. + * @return true if there is more data to read, false otherwise + */ + bool end_of_data() const override; + + /** + * Start a new message in the pipe. A potential other message in this pipe + * must be closed with end_msg() before this function may be called. + */ + void start_msg(); + + /** + * End the current message. + */ + void end_msg(); + + /** + * Insert a new filter at the front of the pipe + * Deprecated because runtime modification of Pipes is deprecated. + * You can instead use prepend_filter which only works before the first + * message is processed. + * @param filt the new filter to insert + */ + BOTAN_DEPRECATED("Runtime modification of Pipe deprecated") + void prepend(Filter* filt); + + /** + * Insert a new filter at the back of the pipe + * Deprecated because runtime modification of Pipes is deprecated. + * You can instead use append_filter which only works before the first + * message is processed. + * @param filt the new filter to insert + */ + BOTAN_DEPRECATED("Runtime modification of Pipe deprecated") + void append(Filter* filt); + + /** + * Remove the first filter at the front of the pipe. + */ + BOTAN_DEPRECATED("Runtime modification of Pipe deprecated") + void pop(); + + /** + * Reset this pipe to an empty pipe. + */ + BOTAN_DEPRECATED("Runtime modification of Pipe deprecated") + void reset(); + + /** + * Append a new filter onto the filter sequence. This may only be + * called immediately after initial construction, before _any_ + * calls to start_msg have been made. + * + * This function (unlike append) is not deprecated, as it allows + * only modification of the pipe at initialization (before use) + * rather than after messages have been processed. + */ + void append_filter(Filter* filt); + + /** + * Prepend a new filter onto the filter sequence. This may only be + * called immediately after initial construction, before _any_ + * calls to start_msg have been made. + * + * This function (unlike prepend) is not deprecated, as it allows + * only modification of the pipe at initialization (before use) + * rather than after messages have been processed. + */ + void prepend_filter(Filter* filt); + + /** + * Construct a Pipe of up to four filters. The filters are set up + * in the same order as the arguments. + */ + Pipe(Filter* = nullptr, Filter* = nullptr, + Filter* = nullptr, Filter* = nullptr); + + /** + * Construct a Pipe from a list of filters + * @param filters the set of filters to use + */ + explicit Pipe(std::initializer_list<Filter*> filters); + + Pipe(const Pipe&) = delete; + Pipe& operator=(const Pipe&) = delete; + + ~Pipe(); + private: + void destruct(Filter*); + void do_append(Filter* filt); + void do_prepend(Filter* filt); + void find_endpoints(Filter*); + void clear_endpoints(Filter*); + + message_id get_message_no(const std::string&, message_id) const; + + Filter* m_pipe; + std::unique_ptr<Output_Buffers> m_outputs; + message_id m_default_read; + bool m_inside_msg; + }; + +/** +* Stream output operator; dumps the results from pipe's default +* message to the output stream. +* @param out an output stream +* @param pipe the pipe +*/ +BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream& out, Pipe& pipe); + +/** +* Stream input operator; dumps the remaining bytes of input +* to the (assumed open) pipe message. +* @param in the input stream +* @param pipe the pipe +*/ +BOTAN_PUBLIC_API(2,0) std::istream& operator>>(std::istream& in, Pipe& pipe); + +} + +#if defined(BOTAN_HAS_PIPE_UNIXFD_IO) + #include <botan/fd_unix.h> +#endif + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/pipe_io.cpp b/src/libs/3rdparty/botan/src/lib/filters/pipe_io.cpp new file mode 100644 index 0000000000..a909cba725 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/pipe_io.cpp @@ -0,0 +1,47 @@ +/* +* Pipe I/O +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pipe.h> +#include <istream> +#include <ostream> + +namespace Botan { + +/* +* Write data from a pipe into an ostream +*/ +std::ostream& operator<<(std::ostream& stream, Pipe& pipe) + { + secure_vector<uint8_t> buffer(BOTAN_DEFAULT_BUFFER_SIZE); + while(stream.good() && pipe.remaining()) + { + const size_t got = pipe.read(buffer.data(), buffer.size()); + stream.write(cast_uint8_ptr_to_char(buffer.data()), got); + } + if(!stream.good()) + throw Stream_IO_Error("Pipe output operator (iostream) has failed"); + return stream; + } + +/* +* Read data from an istream into a pipe +*/ +std::istream& operator>>(std::istream& stream, Pipe& pipe) + { + secure_vector<uint8_t> buffer(BOTAN_DEFAULT_BUFFER_SIZE); + while(stream.good()) + { + stream.read(cast_uint8_ptr_to_char(buffer.data()), buffer.size()); + const size_t got = static_cast<size_t>(stream.gcount()); + pipe.write(buffer.data(), got); + } + if(stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("Pipe input operator (iostream) has failed"); + return stream; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/pipe_rw.cpp b/src/libs/3rdparty/botan/src/lib/filters/pipe_rw.cpp new file mode 100644 index 0000000000..dc7b973727 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/pipe_rw.cpp @@ -0,0 +1,181 @@ +/* +* Pipe Reading/Writing +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pipe.h> +#include <botan/filter.h> +#include <botan/internal/out_buf.h> + +namespace Botan { + +/* +* Look up the canonical ID for a queue +*/ +Pipe::message_id Pipe::get_message_no(const std::string& func_name, + message_id msg) const + { + if(msg == DEFAULT_MESSAGE) + msg = default_msg(); + else if(msg == LAST_MESSAGE) + msg = message_count() - 1; + + if(msg >= message_count()) + throw Invalid_Message_Number(func_name, msg); + + return msg; + } + +/* +* Write into a Pipe +*/ +void Pipe::write(const uint8_t input[], size_t length) + { + if(!m_inside_msg) + throw Invalid_State("Cannot write to a Pipe while it is not processing"); + m_pipe->write(input, length); + } + +/* +* Write a string into a Pipe +*/ +void Pipe::write(const std::string& str) + { + write(cast_char_ptr_to_uint8(str.data()), str.size()); + } + +/* +* Write a single byte into a Pipe +*/ +void Pipe::write(uint8_t input) + { + write(&input, 1); + } + +/* +* Write the contents of a DataSource into a Pipe +*/ +void Pipe::write(DataSource& source) + { + secure_vector<uint8_t> buffer(BOTAN_DEFAULT_BUFFER_SIZE); + while(!source.end_of_data()) + { + size_t got = source.read(buffer.data(), buffer.size()); + write(buffer.data(), got); + } + } + +/* +* Read some data from the pipe +*/ +size_t Pipe::read(uint8_t output[], size_t length, message_id msg) + { + return m_outputs->read(output, length, get_message_no("read", msg)); + } + +/* +* Read some data from the pipe +*/ +size_t Pipe::read(uint8_t output[], size_t length) + { + return read(output, length, DEFAULT_MESSAGE); + } + +/* +* Read a single byte from the pipe +*/ +size_t Pipe::read(uint8_t& out, message_id msg) + { + return read(&out, 1, msg); + } + +/* +* Return all data in the pipe +*/ +secure_vector<uint8_t> Pipe::read_all(message_id msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + secure_vector<uint8_t> buffer(remaining(msg)); + size_t got = read(buffer.data(), buffer.size(), msg); + buffer.resize(got); + return buffer; + } + +/* +* Return all data in the pipe as a string +*/ +std::string Pipe::read_all_as_string(message_id msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + secure_vector<uint8_t> buffer(BOTAN_DEFAULT_BUFFER_SIZE); + std::string str; + str.reserve(remaining(msg)); + + while(true) + { + size_t got = read(buffer.data(), buffer.size(), msg); + if(got == 0) + break; + str.append(cast_uint8_ptr_to_char(buffer.data()), got); + } + + return str; + } + +/* +* Find out how many bytes are ready to read +*/ +size_t Pipe::remaining(message_id msg) const + { + return m_outputs->remaining(get_message_no("remaining", msg)); + } + +/* +* Peek at some data in the pipe +*/ +size_t Pipe::peek(uint8_t output[], size_t length, + size_t offset, message_id msg) const + { + return m_outputs->peek(output, length, offset, get_message_no("peek", msg)); + } + +/* +* Peek at some data in the pipe +*/ +size_t Pipe::peek(uint8_t output[], size_t length, size_t offset) const + { + return peek(output, length, offset, DEFAULT_MESSAGE); + } + +/* +* Peek at a byte in the pipe +*/ +size_t Pipe::peek(uint8_t& out, size_t offset, message_id msg) const + { + return peek(&out, 1, offset, msg); + } + +size_t Pipe::get_bytes_read() const + { + return m_outputs->get_bytes_read(default_msg()); + } + +size_t Pipe::get_bytes_read(message_id msg) const + { + return m_outputs->get_bytes_read(msg); + } + +bool Pipe::check_available(size_t n) + { + return (n <= remaining(default_msg())); + } + +bool Pipe::check_available_msg(size_t n, message_id msg) + { + return (n <= remaining(msg)); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/secqueue.cpp b/src/libs/3rdparty/botan/src/lib/filters/secqueue.cpp new file mode 100644 index 0000000000..1c8d281493 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/secqueue.cpp @@ -0,0 +1,232 @@ +/* +* SecureQueue +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/secqueue.h> +#include <algorithm> + +namespace Botan { + +/** +* A node in a SecureQueue +*/ +class SecureQueueNode final + { + public: + SecureQueueNode() : m_buffer(BOTAN_DEFAULT_BUFFER_SIZE) + { m_next = nullptr; m_start = m_end = 0; } + + ~SecureQueueNode() { m_next = nullptr; m_start = m_end = 0; } + + size_t write(const uint8_t input[], size_t length) + { + size_t copied = std::min<size_t>(length, m_buffer.size() - m_end); + copy_mem(m_buffer.data() + m_end, input, copied); + m_end += copied; + return copied; + } + + size_t read(uint8_t output[], size_t length) + { + size_t copied = std::min(length, m_end - m_start); + copy_mem(output, m_buffer.data() + m_start, copied); + m_start += copied; + return copied; + } + + size_t peek(uint8_t output[], size_t length, size_t offset = 0) + { + const size_t left = m_end - m_start; + if(offset >= left) return 0; + size_t copied = std::min(length, left - offset); + copy_mem(output, m_buffer.data() + m_start + offset, copied); + return copied; + } + + size_t size() const { return (m_end - m_start); } + private: + friend class SecureQueue; + SecureQueueNode* m_next; + secure_vector<uint8_t> m_buffer; + size_t m_start, m_end; + }; + +/* +* Create a SecureQueue +*/ +SecureQueue::SecureQueue() + { + m_bytes_read = 0; + set_next(nullptr, 0); + m_head = m_tail = new SecureQueueNode; + } + +/* +* Copy a SecureQueue +*/ +SecureQueue::SecureQueue(const SecureQueue& input) : + Fanout_Filter(), DataSource() + { + m_bytes_read = 0; + set_next(nullptr, 0); + + m_head = m_tail = new SecureQueueNode; + SecureQueueNode* temp = input.m_head; + while(temp) + { + write(&temp->m_buffer[temp->m_start], temp->m_end - temp->m_start); + temp = temp->m_next; + } + } + +/* +* Destroy this SecureQueue +*/ +void SecureQueue::destroy() + { + SecureQueueNode* temp = m_head; + while(temp) + { + SecureQueueNode* holder = temp->m_next; + delete temp; + temp = holder; + } + m_head = m_tail = nullptr; + } + +/* +* Copy a SecureQueue +*/ +SecureQueue& SecureQueue::operator=(const SecureQueue& input) + { + if(this == &input) + return *this; + + destroy(); + m_bytes_read = input.get_bytes_read(); + m_head = m_tail = new SecureQueueNode; + SecureQueueNode* temp = input.m_head; + while(temp) + { + write(&temp->m_buffer[temp->m_start], temp->m_end - temp->m_start); + temp = temp->m_next; + } + return (*this); + } + +/* +* Add some bytes to the queue +*/ +void SecureQueue::write(const uint8_t input[], size_t length) + { + if(!m_head) + m_head = m_tail = new SecureQueueNode; + while(length) + { + const size_t n = m_tail->write(input, length); + input += n; + length -= n; + if(length) + { + m_tail->m_next = new SecureQueueNode; + m_tail = m_tail->m_next; + } + } + } + +/* +* Read some bytes from the queue +*/ +size_t SecureQueue::read(uint8_t output[], size_t length) + { + size_t got = 0; + while(length && m_head) + { + const size_t n = m_head->read(output, length); + output += n; + got += n; + length -= n; + if(m_head->size() == 0) + { + SecureQueueNode* holder = m_head->m_next; + delete m_head; + m_head = holder; + } + } + m_bytes_read += got; + return got; + } + +/* +* Read data, but do not remove it from queue +*/ +size_t SecureQueue::peek(uint8_t output[], size_t length, size_t offset) const + { + SecureQueueNode* current = m_head; + + while(offset && current) + { + if(offset >= current->size()) + { + offset -= current->size(); + current = current->m_next; + } + else + break; + } + + size_t got = 0; + while(length && current) + { + const size_t n = current->peek(output, length, offset); + offset = 0; + output += n; + got += n; + length -= n; + current = current->m_next; + } + return got; + } + +/** +* Return how many bytes have been read so far. +*/ +size_t SecureQueue::get_bytes_read() const + { + return m_bytes_read; + } + +/* +* Return how many bytes the queue holds +*/ +size_t SecureQueue::size() const + { + SecureQueueNode* current = m_head; + size_t count = 0; + + while(current) + { + count += current->size(); + current = current->m_next; + } + return count; + } + +/* +* Test if the queue has any data in it +*/ +bool SecureQueue::end_of_data() const + { + return (size() == 0); + } + +bool SecureQueue::empty() const + { + return (size() == 0); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/filters/secqueue.h b/src/libs/3rdparty/botan/src/lib/filters/secqueue.h new file mode 100644 index 0000000000..00616f5cf5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/secqueue.h @@ -0,0 +1,72 @@ +/* +* SecureQueue +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SECURE_QUEUE_H_ +#define BOTAN_SECURE_QUEUE_H_ + +#include <botan/data_src.h> +#include <botan/filter.h> + +namespace Botan { + +/** +* A queue that knows how to zeroize itself +*/ +class BOTAN_PUBLIC_API(2,0) SecureQueue final : public Fanout_Filter, public DataSource + { + public: + std::string name() const override { return "Queue"; } + + void write(const uint8_t[], size_t) override; + + size_t read(uint8_t[], size_t) override; + size_t peek(uint8_t[], size_t, size_t = 0) const override; + size_t get_bytes_read() const override; + + bool end_of_data() const override; + + bool empty() const; + + bool check_available(size_t n) override { return n <= size(); } + + /** + * @return number of bytes available in the queue + */ + size_t size() const; + + bool attachable() override { return false; } + + /** + * SecureQueue assignment + * @param other the queue to copy + */ + SecureQueue& operator=(const SecureQueue& other); + + /** + * SecureQueue default constructor (creates empty queue) + */ + SecureQueue(); + + /** + * SecureQueue copy constructor + * @param other the queue to copy + */ + SecureQueue(const SecureQueue& other); + + ~SecureQueue() { destroy(); } + + private: + void destroy(); + size_t m_bytes_read; + class SecureQueueNode* m_head; + class SecureQueueNode* m_tail; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/filters/threaded_fork.cpp b/src/libs/3rdparty/botan/src/lib/filters/threaded_fork.cpp new file mode 100644 index 0000000000..35ea941095 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/filters/threaded_fork.cpp @@ -0,0 +1,153 @@ +/* +* Threaded Fork +* (C) 2013 Joel Low +* 2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/basefilt.h> + +#if defined(BOTAN_HAS_THREAD_UTILS) + +#include <botan/internal/semaphore.h> +#include <botan/internal/barrier.h> +#include <functional> + +namespace Botan { + +struct Threaded_Fork_Data + { + /* + * Semaphore for indicating that there is work to be done (or to + * quit) + */ + Semaphore m_input_ready_semaphore; + + /* + * Synchronises all threads to complete processing data in lock-step. + */ + Barrier m_input_complete_barrier; + + /* + * The work that needs to be done. This should be only when the threads + * are NOT running (i.e. before notifying the work condition, after + * the input_complete_barrier has reset.) + */ + const uint8_t* m_input = nullptr; + + /* + * The length of the work that needs to be done. + */ + size_t m_input_length = 0; + }; + +/* +* Threaded_Fork constructor +*/ +Threaded_Fork::Threaded_Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) : + Fork(nullptr, static_cast<size_t>(0)), + m_thread_data(new Threaded_Fork_Data) + { + Filter* filters[4] = { f1, f2, f3, f4 }; + set_next(filters, 4); + } + +/* +* Threaded_Fork constructor +*/ +Threaded_Fork::Threaded_Fork(Filter* filters[], size_t count) : + Fork(nullptr, static_cast<size_t>(0)), + m_thread_data(new Threaded_Fork_Data) + { + set_next(filters, count); + } + +Threaded_Fork::~Threaded_Fork() + { + m_thread_data->m_input = nullptr; + m_thread_data->m_input_length = 0; + + m_thread_data->m_input_ready_semaphore.release(m_threads.size()); + + for(auto& thread : m_threads) + thread->join(); + } + +std::string Threaded_Fork::name() const + { + return "Threaded Fork"; + } + +void Threaded_Fork::set_next(Filter* f[], size_t n) + { + Fork::set_next(f, n); + n = m_next.size(); + + if(n < m_threads.size()) + m_threads.resize(n); + else + { + m_threads.reserve(n); + for(size_t i = m_threads.size(); i != n; ++i) + { + m_threads.push_back( + std::shared_ptr<std::thread>( + new std::thread( + std::bind(&Threaded_Fork::thread_entry, this, m_next[i])))); + } + } + } + +void Threaded_Fork::send(const uint8_t input[], size_t length) + { + if(m_write_queue.size()) + thread_delegate_work(m_write_queue.data(), m_write_queue.size()); + thread_delegate_work(input, length); + + bool nothing_attached = true; + for(size_t j = 0; j != total_ports(); ++j) + if(m_next[j]) + nothing_attached = false; + + if(nothing_attached) + m_write_queue += std::make_pair(input, length); + else + m_write_queue.clear(); + } + +void Threaded_Fork::thread_delegate_work(const uint8_t input[], size_t length) + { + //Set the data to do. + m_thread_data->m_input = input; + m_thread_data->m_input_length = length; + + //Let the workers start processing. + m_thread_data->m_input_complete_barrier.wait(total_ports() + 1); + m_thread_data->m_input_ready_semaphore.release(total_ports()); + + //Wait for all the filters to finish processing. + m_thread_data->m_input_complete_barrier.sync(); + + //Reset the thread data + m_thread_data->m_input = nullptr; + m_thread_data->m_input_length = 0; + } + +void Threaded_Fork::thread_entry(Filter* filter) + { + while(true) + { + m_thread_data->m_input_ready_semaphore.acquire(); + + if(!m_thread_data->m_input) + break; + + filter->write(m_thread_data->m_input, m_thread_data->m_input_length); + m_thread_data->m_input_complete_barrier.sync(); + } + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/hash/hash.cpp b/src/libs/3rdparty/botan/src/lib/hash/hash.cpp new file mode 100644 index 0000000000..e30d000802 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/hash.cpp @@ -0,0 +1,361 @@ +/* +* Hash Functions +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/hash.h> +#include <botan/scan_name.h> +#include <botan/exceptn.h> + +#if defined(BOTAN_HAS_ADLER32) + #include <botan/adler32.h> +#endif + +#if defined(BOTAN_HAS_CRC24) + #include <botan/crc24.h> +#endif + +#if defined(BOTAN_HAS_CRC32) + #include <botan/crc32.h> +#endif + +#if defined(BOTAN_HAS_GOST_34_11) + #include <botan/gost_3411.h> +#endif + +#if defined(BOTAN_HAS_KECCAK) + #include <botan/keccak.h> +#endif + +#if defined(BOTAN_HAS_MD4) + #include <botan/md4.h> +#endif + +#if defined(BOTAN_HAS_MD5) + #include <botan/md5.h> +#endif + +#if defined(BOTAN_HAS_RIPEMD_160) + #include <botan/rmd160.h> +#endif + +#if defined(BOTAN_HAS_SHA1) + #include <botan/sha160.h> +#endif + +#if defined(BOTAN_HAS_SHA2_32) + #include <botan/sha2_32.h> +#endif + +#if defined(BOTAN_HAS_SHA2_64) + #include <botan/sha2_64.h> +#endif + +#if defined(BOTAN_HAS_SHA3) + #include <botan/sha3.h> +#endif + +#if defined(BOTAN_HAS_SHAKE) + #include <botan/shake.h> +#endif + +#if defined(BOTAN_HAS_SKEIN_512) + #include <botan/skein_512.h> +#endif + +#if defined(BOTAN_HAS_STREEBOG) + #include <botan/streebog.h> +#endif + +#if defined(BOTAN_HAS_SM3) + #include <botan/sm3.h> +#endif + +#if defined(BOTAN_HAS_TIGER) + #include <botan/tiger.h> +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) + #include <botan/whrlpool.h> +#endif + +#if defined(BOTAN_HAS_PARALLEL_HASH) + #include <botan/par_hash.h> +#endif + +#if defined(BOTAN_HAS_COMB4P) + #include <botan/comb4p.h> +#endif + +#if defined(BOTAN_HAS_BLAKE2B) + #include <botan/blake2b.h> +#endif + +#if defined(BOTAN_HAS_BEARSSL) + #include <botan/internal/bearssl.h> +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include <botan/internal/openssl.h> +#endif + +namespace Botan { + +std::unique_ptr<HashFunction> HashFunction::create(const std::string& algo_spec, + const std::string& provider) + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + if(auto hash = make_openssl_hash(algo_spec)) + return hash; + + if(!provider.empty()) + return nullptr; + } +#endif + +#if defined(BOTAN_HAS_BEARSSL) + if(provider.empty() || provider == "bearssl") + { + if(auto hash = make_bearssl_hash(algo_spec)) + return hash; + + if(!provider.empty()) + return nullptr; + } +#endif + + // TODO: CommonCrypto hashes + + if(provider.empty() == false && provider != "base") + return nullptr; // unknown provider + +#if defined(BOTAN_HAS_SHA1) + if(algo_spec == "SHA-160" || + algo_spec == "SHA-1" || + algo_spec == "SHA1") + { + return std::unique_ptr<HashFunction>(new SHA_160); + } +#endif + +#if defined(BOTAN_HAS_SHA2_32) + if(algo_spec == "SHA-224") + { + return std::unique_ptr<HashFunction>(new SHA_224); + } + + if(algo_spec == "SHA-256") + { + return std::unique_ptr<HashFunction>(new SHA_256); + } +#endif + +#if defined(BOTAN_HAS_SHA2_64) + if(algo_spec == "SHA-384") + { + return std::unique_ptr<HashFunction>(new SHA_384); + } + + if(algo_spec == "SHA-512") + { + return std::unique_ptr<HashFunction>(new SHA_512); + } + + if(algo_spec == "SHA-512-256") + { + return std::unique_ptr<HashFunction>(new SHA_512_256); + } +#endif + +#if defined(BOTAN_HAS_RIPEMD_160) + if(algo_spec == "RIPEMD-160") + { + return std::unique_ptr<HashFunction>(new RIPEMD_160); + } +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) + if(algo_spec == "Whirlpool") + { + return std::unique_ptr<HashFunction>(new Whirlpool); + } +#endif + +#if defined(BOTAN_HAS_MD5) + if(algo_spec == "MD5") + { + return std::unique_ptr<HashFunction>(new MD5); + } +#endif + +#if defined(BOTAN_HAS_MD4) + if(algo_spec == "MD4") + { + return std::unique_ptr<HashFunction>(new MD4); + } +#endif + +#if defined(BOTAN_HAS_GOST_34_11) + if(algo_spec == "GOST-R-34.11-94" || algo_spec == "GOST-34.11") + { + return std::unique_ptr<HashFunction>(new GOST_34_11); + } +#endif + +#if defined(BOTAN_HAS_ADLER32) + if(algo_spec == "Adler32") + { + return std::unique_ptr<HashFunction>(new Adler32); + } +#endif + +#if defined(BOTAN_HAS_CRC24) + if(algo_spec == "CRC24") + { + return std::unique_ptr<HashFunction>(new CRC24); + } +#endif + +#if defined(BOTAN_HAS_CRC32) + if(algo_spec == "CRC32") + { + return std::unique_ptr<HashFunction>(new CRC32); + } +#endif + + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_TIGER) + if(req.algo_name() == "Tiger") + { + return std::unique_ptr<HashFunction>( + new Tiger(req.arg_as_integer(0, 24), + req.arg_as_integer(1, 3))); + } +#endif + +#if defined(BOTAN_HAS_SKEIN_512) + if(req.algo_name() == "Skein-512") + { + return std::unique_ptr<HashFunction>( + new Skein_512(req.arg_as_integer(0, 512), req.arg(1, ""))); + } +#endif + +#if defined(BOTAN_HAS_BLAKE2B) + if(req.algo_name() == "Blake2b") + { + return std::unique_ptr<HashFunction>( + new Blake2b(req.arg_as_integer(0, 512))); + } +#endif + +#if defined(BOTAN_HAS_KECCAK) + if(req.algo_name() == "Keccak-1600") + { + return std::unique_ptr<HashFunction>( + new Keccak_1600(req.arg_as_integer(0, 512))); + } +#endif + +#if defined(BOTAN_HAS_SHA3) + if(req.algo_name() == "SHA-3") + { + return std::unique_ptr<HashFunction>( + new SHA_3(req.arg_as_integer(0, 512))); + } +#endif + +#if defined(BOTAN_HAS_SHAKE) + if(req.algo_name() == "SHAKE-128") + { + return std::unique_ptr<HashFunction>(new SHAKE_128(req.arg_as_integer(0, 128))); + } + if(req.algo_name() == "SHAKE-256") + { + return std::unique_ptr<HashFunction>(new SHAKE_256(req.arg_as_integer(0, 256))); + } +#endif + +#if defined(BOTAN_HAS_STREEBOG) + if(algo_spec == "Streebog-256") + { + return std::unique_ptr<HashFunction>(new Streebog_256); + } + if(algo_spec == "Streebog-512") + { + return std::unique_ptr<HashFunction>(new Streebog_512); + } +#endif + +#if defined(BOTAN_HAS_SM3) + if(algo_spec == "SM3") + { + return std::unique_ptr<HashFunction>(new SM3); + } +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) + if(req.algo_name() == "Whirlpool") + { + return std::unique_ptr<HashFunction>(new Whirlpool); + } +#endif + +#if defined(BOTAN_HAS_PARALLEL_HASH) + if(req.algo_name() == "Parallel") + { + std::vector<std::unique_ptr<HashFunction>> hashes; + + for(size_t i = 0; i != req.arg_count(); ++i) + { + auto h = HashFunction::create(req.arg(i)); + if(!h) + { + return nullptr; + } + hashes.push_back(std::move(h)); + } + + return std::unique_ptr<HashFunction>(new Parallel(hashes)); + } +#endif + +#if defined(BOTAN_HAS_COMB4P) + if(req.algo_name() == "Comb4P" && req.arg_count() == 2) + { + std::unique_ptr<HashFunction> h1(HashFunction::create(req.arg(0))); + std::unique_ptr<HashFunction> h2(HashFunction::create(req.arg(1))); + + if(h1 && h2) + return std::unique_ptr<HashFunction>(new Comb4P(h1.release(), h2.release())); + } +#endif + + + return nullptr; + } + +//static +std::unique_ptr<HashFunction> +HashFunction::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto hash = HashFunction::create(algo, provider)) + { + return hash; + } + throw Lookup_Error("Hash", algo, provider); + } + +std::vector<std::string> HashFunction::providers(const std::string& algo_spec) + { + return probe_providers_of<HashFunction>(algo_spec, {"base", "bearssl", "openssl"}); + } + +} + diff --git a/src/libs/3rdparty/botan/src/lib/hash/hash.h b/src/libs/3rdparty/botan/src/lib/hash/hash.h new file mode 100644 index 0000000000..8c6440e650 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/hash.h @@ -0,0 +1,91 @@ +/* +* Hash Function Base Class +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HASH_FUNCTION_BASE_CLASS_H_ +#define BOTAN_HASH_FUNCTION_BASE_CLASS_H_ + +#include <botan/buf_comp.h> +#include <string> +#include <memory> + +namespace Botan { + +/** +* This class represents hash function (message digest) objects +*/ +class BOTAN_PUBLIC_API(2,0) HashFunction : public Buffered_Computation + { + public: + /** + * Create an instance based on a name, or return null if the + * algo/provider combination cannot be found. If provider is + * empty then best available is chosen. + */ + static std::unique_ptr<HashFunction> + create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * Throws Lookup_Error if not found. + */ + static std::unique_ptr<HashFunction> + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + * @param algo_spec algorithm name + */ + static std::vector<std::string> providers(const std::string& algo_spec); + + /** + * @return new object representing the same algorithm as *this + */ + virtual HashFunction* clone() const = 0; + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + + virtual ~HashFunction() = default; + + /** + * Reset the state. + */ + virtual void clear() = 0; + + /** + * @return the hash function name + */ + virtual std::string name() const = 0; + + /** + * @return hash block size as defined for this algorithm + */ + virtual size_t hash_block_size() const { return 0; } + + /** + * Return a new hash object with the same state as *this. This + * allows computing the hash of several messages with a common + * prefix more efficiently than would otherwise be possible. + * + * This function should be called `clone` but that was already + * used for the case of returning an uninitialized object. + * @return new hash object + */ + virtual std::unique_ptr<HashFunction> copy_state() const = 0; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/hash/info.txt b/src/libs/3rdparty/botan/src/lib/hash/info.txt new file mode 100644 index 0000000000..8d38170589 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/info.txt @@ -0,0 +1,7 @@ +<defines> +HASH -> 20180112 +</defines> + +<header:public> +hash.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/hash/mdx_hash/info.txt b/src/libs/3rdparty/botan/src/lib/hash/mdx_hash/info.txt new file mode 100644 index 0000000000..6a509f1be9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/mdx_hash/info.txt @@ -0,0 +1,5 @@ +<defines> +MDX_HASH_FUNCTION -> 20131128 +</defines> + +load_on dep diff --git a/src/libs/3rdparty/botan/src/lib/hash/mdx_hash/mdx_hash.cpp b/src/libs/3rdparty/botan/src/lib/hash/mdx_hash/mdx_hash.cpp new file mode 100644 index 0000000000..7d163dbfb0 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/mdx_hash/mdx_hash.cpp @@ -0,0 +1,108 @@ +/* +* Merkle-Damgard Hash Function +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/mdx_hash.h> +#include <botan/exceptn.h> +#include <botan/loadstor.h> + +namespace Botan { + +/* +* MDx_HashFunction Constructor +*/ +MDx_HashFunction::MDx_HashFunction(size_t block_len, + bool byte_end, + bool bit_end, + size_t cnt_size) : + m_buffer(block_len), + m_count(0), + m_position(0), + BIG_BYTE_ENDIAN(byte_end), + BIG_BIT_ENDIAN(bit_end), + COUNT_SIZE(cnt_size) + { + } + +/* +* Clear memory of sensitive data +*/ +void MDx_HashFunction::clear() + { + zeroise(m_buffer); + m_count = m_position = 0; + } + +/* +* Update the hash +*/ +void MDx_HashFunction::add_data(const uint8_t input[], size_t length) + { + m_count += length; + + if(m_position) + { + buffer_insert(m_buffer, m_position, input, length); + + if(m_position + length >= m_buffer.size()) + { + compress_n(m_buffer.data(), 1); + input += (m_buffer.size() - m_position); + length -= (m_buffer.size() - m_position); + m_position = 0; + } + } + + const size_t full_blocks = length / m_buffer.size(); + const size_t remaining = length % m_buffer.size(); + + if(full_blocks) + compress_n(input, full_blocks); + + buffer_insert(m_buffer, m_position, input + full_blocks * m_buffer.size(), remaining); + m_position += remaining; + } + +/* +* Finalize a hash +*/ +void MDx_HashFunction::final_result(uint8_t output[]) + { + clear_mem(&m_buffer[m_position], m_buffer.size() - m_position); + m_buffer[m_position] = (BIG_BIT_ENDIAN ? 0x80 : 0x01); + + if(m_position >= m_buffer.size() - COUNT_SIZE) + { + compress_n(m_buffer.data(), 1); + zeroise(m_buffer); + } + + write_count(&m_buffer[m_buffer.size() - COUNT_SIZE]); + + compress_n(m_buffer.data(), 1); + copy_out(output); + clear(); + } + +/* +* Write the count bits to the buffer +*/ +void MDx_HashFunction::write_count(uint8_t out[]) + { + if(COUNT_SIZE < 8) + throw Invalid_State("MDx_HashFunction::write_count: COUNT_SIZE < 8"); + if(COUNT_SIZE >= output_length() || COUNT_SIZE >= hash_block_size()) + throw Invalid_Argument("MDx_HashFunction: COUNT_SIZE is too big"); + + const uint64_t bit_count = m_count * 8; + + if(BIG_BYTE_ENDIAN) + store_be(bit_count, out + COUNT_SIZE - 8); + else + store_le(bit_count, out + COUNT_SIZE - 8); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/hash/mdx_hash/mdx_hash.h b/src/libs/3rdparty/botan/src/lib/hash/mdx_hash/mdx_hash.h new file mode 100644 index 0000000000..f958e9fb75 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/mdx_hash/mdx_hash.h @@ -0,0 +1,68 @@ +/* +* MDx Hash Function +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MDX_BASE_H_ +#define BOTAN_MDX_BASE_H_ + +#include <botan/hash.h> + +namespace Botan { + +/** +* MDx Hash Function Base Class +*/ +class BOTAN_PUBLIC_API(2,0) MDx_HashFunction : public HashFunction + { + public: + /** + * @param block_length is the number of bytes per block + * @param big_byte_endian specifies if the hash uses big-endian bytes + * @param big_bit_endian specifies if the hash uses big-endian bits + * @param counter_size specifies the size of the counter var in bytes + */ + MDx_HashFunction(size_t block_length, + bool big_byte_endian, + bool big_bit_endian, + size_t counter_size = 8); + + size_t hash_block_size() const override final { return m_buffer.size(); } + protected: + void add_data(const uint8_t input[], size_t length) override final; + void final_result(uint8_t output[]) override final; + + /** + * Run the hash's compression function over a set of blocks + * @param blocks the input + * @param block_n the number of blocks + */ + virtual void compress_n(const uint8_t blocks[], size_t block_n) = 0; + + void clear() override; + + /** + * Copy the output to the buffer + * @param buffer to put the output into + */ + virtual void copy_out(uint8_t buffer[]) = 0; + + /** + * Write the count, if used, to this spot + * @param out where to write the counter to + */ + virtual void write_count(uint8_t out[]); + private: + secure_vector<uint8_t> m_buffer; + uint64_t m_count; + size_t m_position; + + const bool BIG_BYTE_ENDIAN, BIG_BIT_ENDIAN; + const size_t COUNT_SIZE; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha1/info.txt b/src/libs/3rdparty/botan/src/lib/hash/sha1/info.txt new file mode 100644 index 0000000000..6d326af1c9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha1/info.txt @@ -0,0 +1,7 @@ +<defines> +SHA1 -> 20131128 +</defines> + +<requires> +mdx_hash +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha1/sha160.cpp b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha160.cpp new file mode 100644 index 0000000000..8c12a4f042 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha160.cpp @@ -0,0 +1,188 @@ +/* +* SHA-160 +* (C) 1999-2008,2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sha160.h> +#include <botan/cpuid.h> + +namespace Botan { + +std::unique_ptr<HashFunction> SHA_160::copy_state() const + { + return std::unique_ptr<HashFunction>(new SHA_160(*this)); + } + +namespace SHA1_F { + +namespace { + +/* +* SHA-160 F1 Function +*/ +inline void F1(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (D ^ (B & (C ^ D))) + msg + 0x5A827999 + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F2 Function +*/ +inline void F2(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (B ^ C ^ D) + msg + 0x6ED9EBA1 + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F3 Function +*/ +inline void F3(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += ((B & C) | ((B | C) & D)) + msg + 0x8F1BBCDC + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F4 Function +*/ +inline void F4(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (B ^ C ^ D) + msg + 0xCA62C1D6 + rotl<5>(A); + B = rotl<30>(B); + } + +} + +} + +/* +* SHA-160 Compression Function +*/ +void SHA_160::compress_n(const uint8_t input[], size_t blocks) + { + using namespace SHA1_F; + +#if defined(BOTAN_HAS_SHA1_X86_SHA_NI) + if(CPUID::has_intel_sha()) + { + return sha1_compress_x86(m_digest, input, blocks); + } +#endif + +#if defined(BOTAN_HAS_SHA1_ARMV8) + if(CPUID::has_arm_sha1()) + { + return sha1_armv8_compress_n(m_digest, input, blocks); + } +#endif + +#if defined(BOTAN_HAS_SHA1_SSE2) + if(CPUID::has_sse2()) + { + return sse2_compress_n(m_digest, input, blocks); + } + +#endif + + uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], + D = m_digest[3], E = m_digest[4]; + + m_W.resize(80); + + for(size_t i = 0; i != blocks; ++i) + { + load_be(m_W.data(), input, 16); + + for(size_t j = 16; j != 80; j += 8) + { + m_W[j ] = rotl<1>(m_W[j-3] ^ m_W[j-8] ^ m_W[j-14] ^ m_W[j-16]); + m_W[j+1] = rotl<1>(m_W[j-2] ^ m_W[j-7] ^ m_W[j-13] ^ m_W[j-15]); + m_W[j+2] = rotl<1>(m_W[j-1] ^ m_W[j-6] ^ m_W[j-12] ^ m_W[j-14]); + m_W[j+3] = rotl<1>(m_W[j ] ^ m_W[j-5] ^ m_W[j-11] ^ m_W[j-13]); + m_W[j+4] = rotl<1>(m_W[j+1] ^ m_W[j-4] ^ m_W[j-10] ^ m_W[j-12]); + m_W[j+5] = rotl<1>(m_W[j+2] ^ m_W[j-3] ^ m_W[j- 9] ^ m_W[j-11]); + m_W[j+6] = rotl<1>(m_W[j+3] ^ m_W[j-2] ^ m_W[j- 8] ^ m_W[j-10]); + m_W[j+7] = rotl<1>(m_W[j+4] ^ m_W[j-1] ^ m_W[j- 7] ^ m_W[j- 9]); + } + + F1(A, B, C, D, E, m_W[ 0]); F1(E, A, B, C, D, m_W[ 1]); + F1(D, E, A, B, C, m_W[ 2]); F1(C, D, E, A, B, m_W[ 3]); + F1(B, C, D, E, A, m_W[ 4]); F1(A, B, C, D, E, m_W[ 5]); + F1(E, A, B, C, D, m_W[ 6]); F1(D, E, A, B, C, m_W[ 7]); + F1(C, D, E, A, B, m_W[ 8]); F1(B, C, D, E, A, m_W[ 9]); + F1(A, B, C, D, E, m_W[10]); F1(E, A, B, C, D, m_W[11]); + F1(D, E, A, B, C, m_W[12]); F1(C, D, E, A, B, m_W[13]); + F1(B, C, D, E, A, m_W[14]); F1(A, B, C, D, E, m_W[15]); + F1(E, A, B, C, D, m_W[16]); F1(D, E, A, B, C, m_W[17]); + F1(C, D, E, A, B, m_W[18]); F1(B, C, D, E, A, m_W[19]); + + F2(A, B, C, D, E, m_W[20]); F2(E, A, B, C, D, m_W[21]); + F2(D, E, A, B, C, m_W[22]); F2(C, D, E, A, B, m_W[23]); + F2(B, C, D, E, A, m_W[24]); F2(A, B, C, D, E, m_W[25]); + F2(E, A, B, C, D, m_W[26]); F2(D, E, A, B, C, m_W[27]); + F2(C, D, E, A, B, m_W[28]); F2(B, C, D, E, A, m_W[29]); + F2(A, B, C, D, E, m_W[30]); F2(E, A, B, C, D, m_W[31]); + F2(D, E, A, B, C, m_W[32]); F2(C, D, E, A, B, m_W[33]); + F2(B, C, D, E, A, m_W[34]); F2(A, B, C, D, E, m_W[35]); + F2(E, A, B, C, D, m_W[36]); F2(D, E, A, B, C, m_W[37]); + F2(C, D, E, A, B, m_W[38]); F2(B, C, D, E, A, m_W[39]); + + F3(A, B, C, D, E, m_W[40]); F3(E, A, B, C, D, m_W[41]); + F3(D, E, A, B, C, m_W[42]); F3(C, D, E, A, B, m_W[43]); + F3(B, C, D, E, A, m_W[44]); F3(A, B, C, D, E, m_W[45]); + F3(E, A, B, C, D, m_W[46]); F3(D, E, A, B, C, m_W[47]); + F3(C, D, E, A, B, m_W[48]); F3(B, C, D, E, A, m_W[49]); + F3(A, B, C, D, E, m_W[50]); F3(E, A, B, C, D, m_W[51]); + F3(D, E, A, B, C, m_W[52]); F3(C, D, E, A, B, m_W[53]); + F3(B, C, D, E, A, m_W[54]); F3(A, B, C, D, E, m_W[55]); + F3(E, A, B, C, D, m_W[56]); F3(D, E, A, B, C, m_W[57]); + F3(C, D, E, A, B, m_W[58]); F3(B, C, D, E, A, m_W[59]); + + F4(A, B, C, D, E, m_W[60]); F4(E, A, B, C, D, m_W[61]); + F4(D, E, A, B, C, m_W[62]); F4(C, D, E, A, B, m_W[63]); + F4(B, C, D, E, A, m_W[64]); F4(A, B, C, D, E, m_W[65]); + F4(E, A, B, C, D, m_W[66]); F4(D, E, A, B, C, m_W[67]); + F4(C, D, E, A, B, m_W[68]); F4(B, C, D, E, A, m_W[69]); + F4(A, B, C, D, E, m_W[70]); F4(E, A, B, C, D, m_W[71]); + F4(D, E, A, B, C, m_W[72]); F4(C, D, E, A, B, m_W[73]); + F4(B, C, D, E, A, m_W[74]); F4(A, B, C, D, E, m_W[75]); + F4(E, A, B, C, D, m_W[76]); F4(D, E, A, B, C, m_W[77]); + F4(C, D, E, A, B, m_W[78]); F4(B, C, D, E, A, m_W[79]); + + A = (m_digest[0] += A); + B = (m_digest[1] += B); + C = (m_digest[2] += C); + D = (m_digest[3] += D); + E = (m_digest[4] += E); + + input += hash_block_size(); + } + } + +/* +* Copy out the digest +*/ +void SHA_160::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_160::clear() + { + MDx_HashFunction::clear(); + zeroise(m_W); + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha1/sha160.h b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha160.h new file mode 100644 index 0000000000..9f7035ee63 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha160.h @@ -0,0 +1,73 @@ +/* +* SHA-160 +* (C) 1999-2007,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHA_160_H_ +#define BOTAN_SHA_160_H_ + +#include <botan/mdx_hash.h> + +namespace Botan { + +/** +* NIST's SHA-160 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_160 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-160"; } + size_t output_length() const override { return 20; } + HashFunction* clone() const override { return new SHA_160; } + std::unique_ptr<HashFunction> copy_state() const override; + + void clear() override; + + SHA_160() : MDx_HashFunction(64, true, true), m_digest(5) + { + clear(); + } + + private: + void compress_n(const uint8_t[], size_t blocks) override; + +#if defined(BOTAN_HAS_SHA1_ARMV8) + static void sha1_armv8_compress_n(secure_vector<uint32_t>& digest, + const uint8_t blocks[], + size_t block_count); +#endif + +#if defined(BOTAN_HAS_SHA1_SSE2) + static void sse2_compress_n(secure_vector<uint32_t>& digest, + const uint8_t blocks[], + size_t block_count); +#endif + +#if defined(BOTAN_HAS_SHA1_X86_SHA_NI) + // Using x86 SHA instructions in Intel Goldmont and Cannonlake + static void sha1_compress_x86(secure_vector<uint32_t>& digest, + const uint8_t blocks[], + size_t block_count); +#endif + + + void copy_out(uint8_t[]) override; + + /** + * The digest value + */ + secure_vector<uint32_t> m_digest; + + /** + * The message buffer + */ + secure_vector<uint32_t> m_W; + }; + +typedef SHA_160 SHA_1; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_armv8/info.txt b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_armv8/info.txt new file mode 100644 index 0000000000..405ac412c4 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_armv8/info.txt @@ -0,0 +1,10 @@ +<defines> +SHA1_ARMV8 -> 20170117 +</defines> + +need_isa armv8crypto + +<cc> +gcc:4.9 +clang:3.8 +</cc> diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_armv8/sha1_armv8.cpp b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_armv8/sha1_armv8.cpp new file mode 100644 index 0000000000..9da48c9fec --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_armv8/sha1_armv8.cpp @@ -0,0 +1,207 @@ +/* +* SHA-1 using CPU instructions in ARMv8 +* +* Contributed by Jeffrey Walton. Based on public domain code by +* Johannes Schneiders, Skip Hovsmith and Barry O'Rourke. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sha160.h> +#include <arm_neon.h> + +namespace Botan { + +/* +* SHA-1 using CPU instructions in ARMv8 +*/ +//static +#if defined(BOTAN_HAS_SHA1_ARMV8) +BOTAN_FUNC_ISA("+crypto") +void SHA_160::sha1_armv8_compress_n(secure_vector<uint32_t>& digest, const uint8_t input8[], size_t blocks) + { + uint32x4_t C0, C1, C2, C3; + uint32x4_t ABCD, ABCD_SAVED; + uint32_t E0, E0_SAVED, E1; + + // Load initial values + C0 = vdupq_n_u32(0x5A827999); + C1 = vdupq_n_u32(0x6ED9EBA1); + C2 = vdupq_n_u32(0x8F1BBCDC); + C3 = vdupq_n_u32(0xCA62C1D6); + + ABCD = vld1q_u32(&digest[0]); + E0 = digest[4]; + + // Intermediate void* cast due to https://llvm.org/bugs/show_bug.cgi?id=20670 + const uint32_t* input32 = reinterpret_cast<const uint32_t*>(reinterpret_cast<const void*>(input8)); + + while (blocks) + { + uint32x4_t MSG0, MSG1, MSG2, MSG3; + uint32x4_t TMP0, TMP1; + + // Save current hash + ABCD_SAVED = ABCD; + E0_SAVED = E0; + + MSG0 = vld1q_u32(input32 + 0); + MSG1 = vld1q_u32(input32 + 4); + MSG2 = vld1q_u32(input32 + 8); + MSG3 = vld1q_u32(input32 + 12); + + MSG0 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG0))); + MSG1 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG1))); + MSG2 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG2))); + MSG3 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG3))); + + TMP0 = vaddq_u32(MSG0, C0); + TMP1 = vaddq_u32(MSG1, C0); + + // Rounds 0-3 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C0); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 4-7 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C0); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 8-11 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C0); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 12-15 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C1); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 16-19 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1cq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C1); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 20-23 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C1); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 24-27 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C1); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 28-31 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C1); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 32-35 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C2); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 36-39 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C2); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 40-43 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C2); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 44-47 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C2); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 48-51 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C2); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 52-55 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C3); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + MSG1 = vsha1su0q_u32(MSG1, MSG2, MSG3); + + // Rounds 56-59 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1mq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG0, C3); + MSG1 = vsha1su1q_u32(MSG1, MSG0); + MSG2 = vsha1su0q_u32(MSG2, MSG3, MSG0); + + // Rounds 60-63 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG1, C3); + MSG2 = vsha1su1q_u32(MSG2, MSG1); + MSG3 = vsha1su0q_u32(MSG3, MSG0, MSG1); + + // Rounds 64-67 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + TMP0 = vaddq_u32(MSG2, C3); + MSG3 = vsha1su1q_u32(MSG3, MSG2); + MSG0 = vsha1su0q_u32(MSG0, MSG1, MSG2); + + // Rounds 68-71 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + TMP1 = vaddq_u32(MSG3, C3); + MSG0 = vsha1su1q_u32(MSG0, MSG3); + + // Rounds 72-75 + E1 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E0, TMP0); + + // Rounds 76-79 + E0 = vsha1h_u32(vgetq_lane_u32(ABCD, 0)); + ABCD = vsha1pq_u32(ABCD, E1, TMP1); + + // Add state back + E0 += E0_SAVED; + ABCD = vaddq_u32(ABCD_SAVED, ABCD); + + input32 += 64/4; + blocks--; + } + + // Save digest + vst1q_u32(&digest[0], ABCD); + digest[4] = E0; + } +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_sse2/info.txt b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_sse2/info.txt new file mode 100644 index 0000000000..272bf5e8d4 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_sse2/info.txt @@ -0,0 +1,5 @@ +<defines> +SHA1_SSE2 -> 20160803 +</defines> + +need_isa sse2 diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_sse2/sha1_sse2.cpp b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_sse2/sha1_sse2.cpp new file mode 100644 index 0000000000..88e5a0d2c7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_sse2/sha1_sse2.cpp @@ -0,0 +1,335 @@ +/* +* SHA-1 using SSE2 +* Based on public domain code by Dean Gaudet +* (http://arctic.org/~dean/crypto/sha1.html) +* (C) 2009-2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sha160.h> +#include <emmintrin.h> + +namespace Botan { + +namespace SHA1_SSE2_F { + +namespace { + +/* +* First 16 bytes just need byte swapping. Preparing just means +* adding in the round constants. +*/ + +#define prep00_15(P, W) \ + do { \ + W = _mm_shufflehi_epi16(W, _MM_SHUFFLE(2, 3, 0, 1)); \ + W = _mm_shufflelo_epi16(W, _MM_SHUFFLE(2, 3, 0, 1)); \ + W = _mm_or_si128(_mm_slli_epi16(W, 8), \ + _mm_srli_epi16(W, 8)); \ + P.u128 = _mm_add_epi32(W, K00_19); \ + } while(0) + +/* +For each multiple of 4, t, we want to calculate this: + +W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); +W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1); +W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1); +W[t+3] = rol(W[t] ^ W[t-5] ^ W[t-11] ^ W[t-13], 1); + +we'll actually calculate this: + +W[t+0] = rol(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1); +W[t+1] = rol(W[t-2] ^ W[t-7] ^ W[t-13] ^ W[t-15], 1); +W[t+2] = rol(W[t-1] ^ W[t-6] ^ W[t-12] ^ W[t-14], 1); +W[t+3] = rol( 0 ^ W[t-5] ^ W[t-11] ^ W[t-13], 1); +W[t+3] ^= rol(W[t+0], 1); + +the parameters are: + +W0 = &W[t-16]; +W1 = &W[t-12]; +W2 = &W[t- 8]; +W3 = &W[t- 4]; + +and on output: +prepared = W0 + K +W0 = W[t]..W[t+3] +*/ + +/* note that there is a step here where i want to do a rol by 1, which +* normally would look like this: +* +* r1 = psrld r0,$31 +* r0 = pslld r0,$1 +* r0 = por r0,r1 +* +* but instead i do this: +* +* r1 = pcmpltd r0,zero +* r0 = paddd r0,r0 +* r0 = psub r0,r1 +* +* because pcmpltd and paddd are available in both MMX units on +* efficeon, pentium-m, and opteron but shifts are available in +* only one unit. +*/ +#define prep(prep, XW0, XW1, XW2, XW3, K) \ + do { \ + __m128i r0, r1, r2, r3; \ + \ + /* load W[t-4] 16-byte aligned, and shift */ \ + r3 = _mm_srli_si128((XW3), 4); \ + r0 = (XW0); \ + /* get high 64-bits of XW0 into low 64-bits */ \ + r1 = _mm_shuffle_epi32((XW0), _MM_SHUFFLE(1,0,3,2)); \ + /* load high 64-bits of r1 */ \ + r1 = _mm_unpacklo_epi64(r1, (XW1)); \ + r2 = (XW2); \ + \ + r0 = _mm_xor_si128(r1, r0); \ + r2 = _mm_xor_si128(r3, r2); \ + r0 = _mm_xor_si128(r2, r0); \ + /* unrotated W[t]..W[t+2] in r0 ... still need W[t+3] */ \ + \ + r2 = _mm_slli_si128(r0, 12); \ + r1 = _mm_cmplt_epi32(r0, _mm_setzero_si128()); \ + r0 = _mm_add_epi32(r0, r0); /* shift left by 1 */ \ + r0 = _mm_sub_epi32(r0, r1); /* r0 has W[t]..W[t+2] */ \ + \ + r3 = _mm_srli_epi32(r2, 30); \ + r2 = _mm_slli_epi32(r2, 2); \ + \ + r0 = _mm_xor_si128(r0, r3); \ + r0 = _mm_xor_si128(r0, r2); /* r0 now has W[t+3] */ \ + \ + (XW0) = r0; \ + (prep).u128 = _mm_add_epi32(r0, K); \ + } while(0) + +/* +* SHA-160 F1 Function +*/ +inline void F1(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (D ^ (B & (C ^ D))) + msg + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F2 Function +*/ +inline void F2(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (B ^ C ^ D) + msg + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F3 Function +*/ +inline void F3(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += ((B & C) | ((B | C) & D)) + msg + rotl<5>(A); + B = rotl<30>(B); + } + +/* +* SHA-160 F4 Function +*/ +inline void F4(uint32_t A, uint32_t& B, uint32_t C, uint32_t D, uint32_t& E, uint32_t msg) + { + E += (B ^ C ^ D) + msg + rotl<5>(A); + B = rotl<30>(B); + } + +} + +} + +/* +* SHA-160 Compression Function using SSE for message expansion +*/ +//static +BOTAN_FUNC_ISA("sse2") +void SHA_160::sse2_compress_n(secure_vector<uint32_t>& digest, const uint8_t input[], size_t blocks) + { + using namespace SHA1_SSE2_F; + + const __m128i K00_19 = _mm_set1_epi32(0x5A827999); + const __m128i K20_39 = _mm_set1_epi32(0x6ED9EBA1); + const __m128i K40_59 = _mm_set1_epi32(0x8F1BBCDC); + const __m128i K60_79 = _mm_set1_epi32(0xCA62C1D6); + + uint32_t A = digest[0], + B = digest[1], + C = digest[2], + D = digest[3], + E = digest[4]; + + const __m128i* input_mm = reinterpret_cast<const __m128i*>(input); + + for(size_t i = 0; i != blocks; ++i) + { + union v4si { + uint32_t u32[4]; + __m128i u128; + }; + + v4si P0, P1, P2, P3; + + __m128i W0 = _mm_loadu_si128(&input_mm[0]); + prep00_15(P0, W0); + + __m128i W1 = _mm_loadu_si128(&input_mm[1]); + prep00_15(P1, W1); + + __m128i W2 = _mm_loadu_si128(&input_mm[2]); + prep00_15(P2, W2); + + __m128i W3 = _mm_loadu_si128(&input_mm[3]); + prep00_15(P3, W3); + + /* + Using SSE4; slower on Core2 and Nehalem + #define GET_P_32(P, i) _mm_extract_epi32(P.u128, i) + + Much slower on all tested platforms + #define GET_P_32(P,i) _mm_cvtsi128_si32(_mm_srli_si128(P.u128, i*4)) + */ + +#define GET_P_32(P, i) P.u32[i] + + F1(A, B, C, D, E, GET_P_32(P0, 0)); + F1(E, A, B, C, D, GET_P_32(P0, 1)); + F1(D, E, A, B, C, GET_P_32(P0, 2)); + F1(C, D, E, A, B, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K00_19); + + F1(B, C, D, E, A, GET_P_32(P1, 0)); + F1(A, B, C, D, E, GET_P_32(P1, 1)); + F1(E, A, B, C, D, GET_P_32(P1, 2)); + F1(D, E, A, B, C, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K20_39); + + F1(C, D, E, A, B, GET_P_32(P2, 0)); + F1(B, C, D, E, A, GET_P_32(P2, 1)); + F1(A, B, C, D, E, GET_P_32(P2, 2)); + F1(E, A, B, C, D, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K20_39); + + F1(D, E, A, B, C, GET_P_32(P3, 0)); + F1(C, D, E, A, B, GET_P_32(P3, 1)); + F1(B, C, D, E, A, GET_P_32(P3, 2)); + F1(A, B, C, D, E, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K20_39); + + F1(E, A, B, C, D, GET_P_32(P0, 0)); + F1(D, E, A, B, C, GET_P_32(P0, 1)); + F1(C, D, E, A, B, GET_P_32(P0, 2)); + F1(B, C, D, E, A, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K20_39); + + F2(A, B, C, D, E, GET_P_32(P1, 0)); + F2(E, A, B, C, D, GET_P_32(P1, 1)); + F2(D, E, A, B, C, GET_P_32(P1, 2)); + F2(C, D, E, A, B, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K20_39); + + F2(B, C, D, E, A, GET_P_32(P2, 0)); + F2(A, B, C, D, E, GET_P_32(P2, 1)); + F2(E, A, B, C, D, GET_P_32(P2, 2)); + F2(D, E, A, B, C, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K40_59); + + F2(C, D, E, A, B, GET_P_32(P3, 0)); + F2(B, C, D, E, A, GET_P_32(P3, 1)); + F2(A, B, C, D, E, GET_P_32(P3, 2)); + F2(E, A, B, C, D, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K40_59); + + F2(D, E, A, B, C, GET_P_32(P0, 0)); + F2(C, D, E, A, B, GET_P_32(P0, 1)); + F2(B, C, D, E, A, GET_P_32(P0, 2)); + F2(A, B, C, D, E, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K40_59); + + F2(E, A, B, C, D, GET_P_32(P1, 0)); + F2(D, E, A, B, C, GET_P_32(P1, 1)); + F2(C, D, E, A, B, GET_P_32(P1, 2)); + F2(B, C, D, E, A, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K40_59); + + F3(A, B, C, D, E, GET_P_32(P2, 0)); + F3(E, A, B, C, D, GET_P_32(P2, 1)); + F3(D, E, A, B, C, GET_P_32(P2, 2)); + F3(C, D, E, A, B, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K40_59); + + F3(B, C, D, E, A, GET_P_32(P3, 0)); + F3(A, B, C, D, E, GET_P_32(P3, 1)); + F3(E, A, B, C, D, GET_P_32(P3, 2)); + F3(D, E, A, B, C, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K60_79); + + F3(C, D, E, A, B, GET_P_32(P0, 0)); + F3(B, C, D, E, A, GET_P_32(P0, 1)); + F3(A, B, C, D, E, GET_P_32(P0, 2)); + F3(E, A, B, C, D, GET_P_32(P0, 3)); + prep(P0, W0, W1, W2, W3, K60_79); + + F3(D, E, A, B, C, GET_P_32(P1, 0)); + F3(C, D, E, A, B, GET_P_32(P1, 1)); + F3(B, C, D, E, A, GET_P_32(P1, 2)); + F3(A, B, C, D, E, GET_P_32(P1, 3)); + prep(P1, W1, W2, W3, W0, K60_79); + + F3(E, A, B, C, D, GET_P_32(P2, 0)); + F3(D, E, A, B, C, GET_P_32(P2, 1)); + F3(C, D, E, A, B, GET_P_32(P2, 2)); + F3(B, C, D, E, A, GET_P_32(P2, 3)); + prep(P2, W2, W3, W0, W1, K60_79); + + F4(A, B, C, D, E, GET_P_32(P3, 0)); + F4(E, A, B, C, D, GET_P_32(P3, 1)); + F4(D, E, A, B, C, GET_P_32(P3, 2)); + F4(C, D, E, A, B, GET_P_32(P3, 3)); + prep(P3, W3, W0, W1, W2, K60_79); + + F4(B, C, D, E, A, GET_P_32(P0, 0)); + F4(A, B, C, D, E, GET_P_32(P0, 1)); + F4(E, A, B, C, D, GET_P_32(P0, 2)); + F4(D, E, A, B, C, GET_P_32(P0, 3)); + + F4(C, D, E, A, B, GET_P_32(P1, 0)); + F4(B, C, D, E, A, GET_P_32(P1, 1)); + F4(A, B, C, D, E, GET_P_32(P1, 2)); + F4(E, A, B, C, D, GET_P_32(P1, 3)); + + F4(D, E, A, B, C, GET_P_32(P2, 0)); + F4(C, D, E, A, B, GET_P_32(P2, 1)); + F4(B, C, D, E, A, GET_P_32(P2, 2)); + F4(A, B, C, D, E, GET_P_32(P2, 3)); + + F4(E, A, B, C, D, GET_P_32(P3, 0)); + F4(D, E, A, B, C, GET_P_32(P3, 1)); + F4(C, D, E, A, B, GET_P_32(P3, 2)); + F4(B, C, D, E, A, GET_P_32(P3, 3)); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + + input_mm += (64 / 16); + } + +#undef GET_P_32 + } + +#undef prep00_15 +#undef prep + +} diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_x86/info.txt b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_x86/info.txt new file mode 100644 index 0000000000..cfa1750c23 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_x86/info.txt @@ -0,0 +1,11 @@ +<defines> +SHA1_X86_SHA_NI -> 20170518 +</defines> + +need_isa sha,ssse3,sse41 + +<cc> +clang:3.9 +gcc:5.0 +msvc:19.0 # MSVS 2015 +</cc> diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_x86/sha1_x86.cpp b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_x86/sha1_x86.cpp new file mode 100644 index 0000000000..76feebcea1 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha1/sha1_x86/sha1_x86.cpp @@ -0,0 +1,216 @@ +/* +* SHA-1 using Intel SHA intrinsic +* +* Based on public domain code by Sean Gulley +* (https://github.com/mitls/hacl-star/tree/master/experimental/hash) +* Adapted to Botan by Jeffrey Walton. +* +* Further changes +* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sha160.h> +#include <immintrin.h> + +namespace Botan { + +#if defined(BOTAN_HAS_SHA1_X86_SHA_NI) +BOTAN_FUNC_ISA("sha,ssse3,sse4.1") +void SHA_160::sha1_compress_x86(secure_vector<uint32_t>& digest, + const uint8_t input[], + size_t blocks) + { + const __m128i MASK = _mm_set_epi64x(0x0001020304050607ULL, 0x08090a0b0c0d0e0fULL); + const __m128i* input_mm = reinterpret_cast<const __m128i*>(input); + + uint32_t* state = digest.data(); + + // Load initial values + __m128i ABCD = _mm_loadu_si128(reinterpret_cast<__m128i*>(state)); + __m128i E0 = _mm_set_epi32(state[4], 0, 0, 0); + ABCD = _mm_shuffle_epi32(ABCD, 0x1B); + + while (blocks) + { + // Save current hash + const __m128i ABCD_SAVE = ABCD; + const __m128i E0_SAVE = E0; + + __m128i MSG0, MSG1, MSG2, MSG3; + __m128i E1; + + // Rounds 0-3 + MSG0 = _mm_loadu_si128(input_mm+0); + MSG0 = _mm_shuffle_epi8(MSG0, MASK); + E0 = _mm_add_epi32(E0, MSG0); + E1 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + + // Rounds 4-7 + MSG1 = _mm_loadu_si128(input_mm+1); + MSG1 = _mm_shuffle_epi8(MSG1, MASK); + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + + // Rounds 8-11 + MSG2 = _mm_loadu_si128(input_mm+2); + MSG2 = _mm_shuffle_epi8(MSG2, MASK); + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 12-15 + MSG3 = _mm_loadu_si128(input_mm+3); + MSG3 = _mm_shuffle_epi8(MSG3, MASK); + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 16-19 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 20-23 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 24-27 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 28-31 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 32-35 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 36-39 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 40-43 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 44-47 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 48-51 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 52-55 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2); + MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 56-59 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); + MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); + MSG0 = _mm_xor_si128(MSG0, MSG2); + + // Rounds 60-63 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); + MSG1 = _mm_xor_si128(MSG1, MSG3); + + // Rounds 64-67 + E0 = _mm_sha1nexte_epu32(E0, MSG0); + E1 = ABCD; + MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3); + MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); + MSG2 = _mm_xor_si128(MSG2, MSG0); + + // Rounds 68-71 + E1 = _mm_sha1nexte_epu32(E1, MSG1); + E0 = ABCD; + MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + MSG3 = _mm_xor_si128(MSG3, MSG1); + + // Rounds 72-75 + E0 = _mm_sha1nexte_epu32(E0, MSG2); + E1 = ABCD; + MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); + ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3); + + // Rounds 76-79 + E1 = _mm_sha1nexte_epu32(E1, MSG3); + E0 = ABCD; + ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); + + // Add values back to state + E0 = _mm_sha1nexte_epu32(E0, E0_SAVE); + ABCD = _mm_add_epi32(ABCD, ABCD_SAVE); + + input_mm += 4; + blocks--; + } + + // Save state + ABCD = _mm_shuffle_epi32(ABCD, 0x1B); + _mm_storeu_si128(reinterpret_cast<__m128i*>(state), ABCD); + state[4] = _mm_extract_epi32(E0, 3); + } +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_32/info.txt b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/info.txt new file mode 100644 index 0000000000..7992eff261 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/info.txt @@ -0,0 +1,7 @@ +<defines> +SHA2_32 -> 20131128 +</defines> + +<requires> +mdx_hash +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32.cpp b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32.cpp new file mode 100644 index 0000000000..99cc2a6ffb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32.cpp @@ -0,0 +1,236 @@ +/* +* SHA-{224,256} +* (C) 1999-2010,2017 Jack Lloyd +* 2007 FlexSecure GmbH +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sha2_32.h> +#include <botan/cpuid.h> + +namespace Botan { + +std::unique_ptr<HashFunction> SHA_224::copy_state() const + { + return std::unique_ptr<HashFunction>(new SHA_224(*this)); + } + +std::unique_ptr<HashFunction> SHA_256::copy_state() const + { + return std::unique_ptr<HashFunction>(new SHA_256(*this)); + } + +/* +* SHA-256 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. +*/ +#define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) do { \ + uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A); \ + uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E); \ + uint32_t M2_sigma = rotr<17>(M2) ^ rotr<19>(M2) ^ (M2 >> 10); \ + uint32_t M4_sigma = rotr<7>(M4) ^ rotr<18>(M4) ^ (M4 >> 3); \ + H += magic + E_rho + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += A_rho + ((A & B) | ((A | B) & C)); \ + M1 += M2_sigma + M3 + M4_sigma; \ + } while(0); + +/* +* SHA-224 / SHA-256 compression function +*/ +void SHA_256::compress_digest(secure_vector<uint32_t>& digest, + const uint8_t input[], size_t blocks) + { +#if defined(BOTAN_HAS_SHA2_32_X86) + if(CPUID::has_intel_sha()) + { + return SHA_256::compress_digest_x86(digest, input, blocks); + } +#endif + +#if defined(BOTAN_HAS_SHA2_32_X86_BMI2) + if(CPUID::has_bmi2()) + { + return SHA_256::compress_digest_x86_bmi2(digest, input, blocks); + } +#endif + +#if defined(BOTAN_HAS_SHA2_32_ARMV8) + if(CPUID::has_arm_sha2()) + { + return SHA_256::compress_digest_armv8(digest, input, blocks); + } +#endif + + uint32_t A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t W00 = load_be<uint32_t>(input, 0); + uint32_t W01 = load_be<uint32_t>(input, 1); + uint32_t W02 = load_be<uint32_t>(input, 2); + uint32_t W03 = load_be<uint32_t>(input, 3); + uint32_t W04 = load_be<uint32_t>(input, 4); + uint32_t W05 = load_be<uint32_t>(input, 5); + uint32_t W06 = load_be<uint32_t>(input, 6); + uint32_t W07 = load_be<uint32_t>(input, 7); + uint32_t W08 = load_be<uint32_t>(input, 8); + uint32_t W09 = load_be<uint32_t>(input, 9); + uint32_t W10 = load_be<uint32_t>(input, 10); + uint32_t W11 = load_be<uint32_t>(input, 11); + uint32_t W12 = load_be<uint32_t>(input, 12); + uint32_t W13 = load_be<uint32_t>(input, 13); + uint32_t W14 = load_be<uint32_t>(input, 14); + uint32_t W15 = load_be<uint32_t>(input, 15); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x71374491); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCF); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25B); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B01); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C1); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC6); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DC); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C8); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF3); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x14292967); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A85); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B2138); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D13); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A7354); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C85); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A1); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664B); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD6990624); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E3585); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA070); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C08); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774C); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4A); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC70208); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEB); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 64; + } + } + +/* +* SHA-224 compression function +*/ +void SHA_224::compress_n(const uint8_t input[], size_t blocks) + { + SHA_256::compress_digest(m_digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_224::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_224::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0xC1059ED8; + m_digest[1] = 0x367CD507; + m_digest[2] = 0x3070DD17; + m_digest[3] = 0xF70E5939; + m_digest[4] = 0xFFC00B31; + m_digest[5] = 0x68581511; + m_digest[6] = 0x64F98FA7; + m_digest[7] = 0xBEFA4FA4; + } + +/* +* SHA-256 compression function +*/ +void SHA_256::compress_n(const uint8_t input[], size_t blocks) + { + SHA_256::compress_digest(m_digest, input, blocks); + } + +/* +* Copy out the digest +*/ +void SHA_256::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +/* +* Clear memory of sensitive data +*/ +void SHA_256::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0x6A09E667; + m_digest[1] = 0xBB67AE85; + m_digest[2] = 0x3C6EF372; + m_digest[3] = 0xA54FF53A; + m_digest[4] = 0x510E527F; + m_digest[5] = 0x9B05688C; + m_digest[6] = 0x1F83D9AB; + m_digest[7] = 0x5BE0CD19; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32.h b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32.h new file mode 100644 index 0000000000..bc883f77ac --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32.h @@ -0,0 +1,89 @@ +/* +* SHA-{224,256} +* (C) 1999-2011 Jack Lloyd +* 2007 FlexSecure GmbH +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHA_224_256_H_ +#define BOTAN_SHA_224_256_H_ + +#include <botan/mdx_hash.h> + +namespace Botan { + +/** +* SHA-224 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_224 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-224"; } + size_t output_length() const override { return 28; } + HashFunction* clone() const override { return new SHA_224; } + std::unique_ptr<HashFunction> copy_state() const override; + + void clear() override; + + SHA_224() : MDx_HashFunction(64, true, true), m_digest(8) + { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + secure_vector<uint32_t> m_digest; + }; + +/** +* SHA-256 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_256 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-256"; } + size_t output_length() const override { return 32; } + HashFunction* clone() const override { return new SHA_256; } + std::unique_ptr<HashFunction> copy_state() const override; + + void clear() override; + + SHA_256() : MDx_HashFunction(64, true, true), m_digest(8) + { clear(); } + + /* + * Perform a SHA-256 compression. For internal use + */ + static void compress_digest(secure_vector<uint32_t>& digest, + const uint8_t input[], + size_t blocks); + + private: + +#if defined(BOTAN_HAS_SHA2_32_ARMV8) + static void compress_digest_armv8(secure_vector<uint32_t>& digest, + const uint8_t input[], + size_t blocks); +#endif + +#if defined(BOTAN_HAS_SHA2_32_X86_BMI2) + static void compress_digest_x86_bmi2(secure_vector<uint32_t>& digest, + const uint8_t input[], + size_t blocks); +#endif + +#if defined(BOTAN_HAS_SHA2_32_X86) + static void compress_digest_x86(secure_vector<uint32_t>& digest, + const uint8_t input[], + size_t blocks); +#endif + + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + secure_vector<uint32_t> m_digest; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_armv8/info.txt b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_armv8/info.txt new file mode 100644 index 0000000000..74d3fe4abc --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_armv8/info.txt @@ -0,0 +1,10 @@ +<defines> +SHA2_32_ARMV8 -> 20170117 +</defines> + +need_isa armv8crypto + +<cc> +gcc:4.9 +clang:3.8 +</cc> diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_armv8/sha2_32_armv8.cpp b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_armv8/sha2_32_armv8.cpp new file mode 100644 index 0000000000..1574a32738 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_armv8/sha2_32_armv8.cpp @@ -0,0 +1,204 @@ +/* +* SHA-256 using CPU instructions in ARMv8 +* +* Contributed by Jeffrey Walton. Based on public domain code by +* Johannes Schneiders, Skip Hovsmith and Barry O'Rourke. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sha2_32.h> +#include <arm_neon.h> + +namespace Botan { + +/* +* SHA-256 using CPU instructions in ARMv8 +*/ +//static +#if defined(BOTAN_HAS_SHA2_32_ARMV8) +BOTAN_FUNC_ISA("+crypto") +void SHA_256::compress_digest_armv8(secure_vector<uint32_t>& digest, const uint8_t input8[], size_t blocks) + { + static const uint32_t K[] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, + }; + + uint32x4_t STATE0, STATE1, ABEF_SAVE, CDGH_SAVE; + uint32x4_t MSG0, MSG1, MSG2, MSG3; + uint32x4_t TMP0, TMP1, TMP2; + + // Load initial values + STATE0 = vld1q_u32(&digest[0]); + STATE1 = vld1q_u32(&digest[4]); + + // Intermediate void* cast due to https://llvm.org/bugs/show_bug.cgi?id=20670 + const uint32_t* input32 = reinterpret_cast<const uint32_t*>(reinterpret_cast<const void*>(input8)); + + while (blocks) + { + // Save current state + ABEF_SAVE = STATE0; + CDGH_SAVE = STATE1; + + MSG0 = vld1q_u32(input32 + 0); + MSG1 = vld1q_u32(input32 + 4); + MSG2 = vld1q_u32(input32 + 8); + MSG3 = vld1q_u32(input32 + 12); + + MSG0 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG0))); + MSG1 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG1))); + MSG2 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG2))); + MSG3 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(MSG3))); + + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0x00])); + + // Rounds 0-3 + MSG0 = vsha256su0q_u32(MSG0, MSG1); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&K[0x04])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 4-7 + MSG1 = vsha256su0q_u32(MSG1, MSG2); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[0x08])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 8-11 + MSG2 = vsha256su0q_u32(MSG2, MSG3); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&K[0x0c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 12-15 + MSG3 = vsha256su0q_u32(MSG3, MSG0); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0x10])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 16-19 + MSG0 = vsha256su0q_u32(MSG0, MSG1); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&K[0x14])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 20-23 + MSG1 = vsha256su0q_u32(MSG1, MSG2); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[0x18])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 24-27 + MSG2 = vsha256su0q_u32(MSG2, MSG3); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&K[0x1c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 28-31 + MSG3 = vsha256su0q_u32(MSG3, MSG0); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0x20])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 32-35 + MSG0 = vsha256su0q_u32(MSG0, MSG1); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&K[0x24])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 36-39 + MSG1 = vsha256su0q_u32(MSG1, MSG2); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[0x28])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 40-43 + MSG2 = vsha256su0q_u32(MSG2, MSG3); + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&K[0x2c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 44-47 + MSG3 = vsha256su0q_u32(MSG3, MSG0); + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0x30])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 48-51 + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG1, vld1q_u32(&K[0x34])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + + // Rounds 52-55 + TMP2 = STATE0; + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[0x38])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + + // Rounds 56-59 + TMP2 = STATE0; + TMP1 = vaddq_u32(MSG3, vld1q_u32(&K[0x3c])); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + + // Rounds 60-63 + TMP2 = STATE0; + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP1); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP1); + + // Add back to state + STATE0 = vaddq_u32(STATE0, ABEF_SAVE); + STATE1 = vaddq_u32(STATE1, CDGH_SAVE); + + input32 += 64/4; + blocks--; + } + + // Save state + vst1q_u32(&digest[0], STATE0); + vst1q_u32(&digest[4], STATE1); + } +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_bmi2/info.txt b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_bmi2/info.txt new file mode 100644 index 0000000000..dc73497163 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_bmi2/info.txt @@ -0,0 +1,10 @@ +<defines> +SHA2_32_X86_BMI2 -> 20180526 +</defines> + +need_isa bmi2 + +<cc> +gcc +clang +</cc> diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_bmi2/sha2_32_bmi2.cpp b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_bmi2/sha2_32_bmi2.cpp new file mode 100644 index 0000000000..12ceb11c49 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_bmi2/sha2_32_bmi2.cpp @@ -0,0 +1,139 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sha2_32.h> +#include <botan/rotate.h> + +namespace Botan { + +/* +Your eyes do not decieve you; this is currently just a copy of the +baseline SHA-256 implementation. Because we compile it with BMI2 +flags, GCC and Clang use the BMI2 instructions without further help. + +Likely instruction scheduling could be improved by using inline asm. +*/ + +#define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) do { \ + uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A); \ + uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E); \ + uint32_t M2_sigma = rotr<17>(M2) ^ rotr<19>(M2) ^ (M2 >> 10); \ + uint32_t M4_sigma = rotr<7>(M4) ^ rotr<18>(M4) ^ (M4 >> 3); \ + H += magic + E_rho + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += A_rho + ((A & B) | ((A | B) & C)); \ + M1 += M2_sigma + M3 + M4_sigma; \ + } while(0); + +void SHA_256::compress_digest_x86_bmi2(secure_vector<uint32_t>& digest, + const uint8_t input[], + size_t blocks) + { + uint32_t A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + uint32_t W00 = load_be<uint32_t>(input, 0); + uint32_t W01 = load_be<uint32_t>(input, 1); + uint32_t W02 = load_be<uint32_t>(input, 2); + uint32_t W03 = load_be<uint32_t>(input, 3); + uint32_t W04 = load_be<uint32_t>(input, 4); + uint32_t W05 = load_be<uint32_t>(input, 5); + uint32_t W06 = load_be<uint32_t>(input, 6); + uint32_t W07 = load_be<uint32_t>(input, 7); + uint32_t W08 = load_be<uint32_t>(input, 8); + uint32_t W09 = load_be<uint32_t>(input, 9); + uint32_t W10 = load_be<uint32_t>(input, 10); + uint32_t W11 = load_be<uint32_t>(input, 11); + uint32_t W12 = load_be<uint32_t>(input, 12); + uint32_t W13 = load_be<uint32_t>(input, 13); + uint32_t W14 = load_be<uint32_t>(input, 14); + uint32_t W15 = load_be<uint32_t>(input, 15); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x71374491); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCF); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25B); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B01); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C1); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC6); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DC); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C8); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF3); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x14292967); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A85); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B2138); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D13); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A7354); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C85); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A1); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664B); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD6990624); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E3585); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA070); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C08); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774C); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4A); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC70208); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEB); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 64; + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_x86/info.txt b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_x86/info.txt new file mode 100644 index 0000000000..4a0b25910e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_x86/info.txt @@ -0,0 +1,11 @@ +<defines> +SHA2_32_X86 -> 20170518 +</defines> + +need_isa sha,ssse3,sse41 + +<cc> +gcc:5.0 +clang:3.9 +msvc:19.0 # MSVS 2015 +</cc> diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_x86/sha2_32_x86.cpp b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_x86/sha2_32_x86.cpp new file mode 100644 index 0000000000..a4bd9b72db --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_32/sha2_32_x86/sha2_32_x86.cpp @@ -0,0 +1,215 @@ +/* +* Support for SHA-256 x86 instrinsic +* Based on public domain code by Sean Gulley +* (https://github.com/mitls/hacl-star/tree/master/experimental/hash) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sha2_32.h> +#include <immintrin.h> + +namespace Botan { + +// called from sha2_32.cpp +#if defined(BOTAN_HAS_SHA2_32_X86) +BOTAN_FUNC_ISA("sha,sse4.1,ssse3") +void SHA_256::compress_digest_x86(secure_vector<uint32_t>& digest, const uint8_t input[], size_t blocks) + { + __m128i STATE0, STATE1; + __m128i MSG, TMP, MASK; + __m128i TMSG0, TMSG1, TMSG2, TMSG3; + __m128i ABEF_SAVE, CDGH_SAVE; + + uint32_t* state = &digest[0]; + + const __m128i* input_mm = reinterpret_cast<const __m128i*>(input); + + // Load initial values + TMP = _mm_loadu_si128(reinterpret_cast<__m128i*>(&state[0])); + STATE1 = _mm_loadu_si128(reinterpret_cast<__m128i*>(&state[4])); + MASK = _mm_set_epi64x(0x0c0d0e0f08090a0bULL, 0x0405060700010203ULL); + + TMP = _mm_shuffle_epi32(TMP, 0xB1); // CDAB + STATE1 = _mm_shuffle_epi32(STATE1, 0x1B); // EFGH + STATE0 = _mm_alignr_epi8(TMP, STATE1, 8); // ABEF + STATE1 = _mm_blend_epi16(STATE1, TMP, 0xF0); // CDGH + + while (blocks) + { + // Save current hash + ABEF_SAVE = STATE0; + CDGH_SAVE = STATE1; + + // Rounds 0-3 + MSG = _mm_loadu_si128(input_mm); + TMSG0 = _mm_shuffle_epi8(MSG, MASK); + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(0xE9B5DBA5B5C0FBCFULL, 0x71374491428A2F98ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Rounds 4-7 + TMSG1 = _mm_loadu_si128(input_mm + 1); + TMSG1 = _mm_shuffle_epi8(TMSG1, MASK); + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(0xAB1C5ED5923F82A4ULL, 0x59F111F13956C25BULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG0 = _mm_sha256msg1_epu32(TMSG0, TMSG1); + + // Rounds 8-11 + TMSG2 = _mm_loadu_si128(input_mm + 2); + TMSG2 = _mm_shuffle_epi8(TMSG2, MASK); + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(0x550C7DC3243185BEULL, 0x12835B01D807AA98ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG1 = _mm_sha256msg1_epu32(TMSG1, TMSG2); + + // Rounds 12-15 + TMSG3 = _mm_loadu_si128(input_mm + 3); + TMSG3 = _mm_shuffle_epi8(TMSG3, MASK); + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(0xC19BF1749BDC06A7ULL, 0x80DEB1FE72BE5D74ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG3, TMSG2, 4); + TMSG0 = _mm_add_epi32(TMSG0, TMP); + TMSG0 = _mm_sha256msg2_epu32(TMSG0, TMSG3); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG2 = _mm_sha256msg1_epu32(TMSG2, TMSG3); + + // Rounds 16-19 + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(0x240CA1CC0FC19DC6ULL, 0xEFBE4786E49B69C1ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG0, TMSG3, 4); + TMSG1 = _mm_add_epi32(TMSG1, TMP); + TMSG1 = _mm_sha256msg2_epu32(TMSG1, TMSG0); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG3 = _mm_sha256msg1_epu32(TMSG3, TMSG0); + + // Rounds 20-23 + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(0x76F988DA5CB0A9DCULL, 0x4A7484AA2DE92C6FULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG1, TMSG0, 4); + TMSG2 = _mm_add_epi32(TMSG2, TMP); + TMSG2 = _mm_sha256msg2_epu32(TMSG2, TMSG1); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG0 = _mm_sha256msg1_epu32(TMSG0, TMSG1); + + // Rounds 24-27 + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(0xBF597FC7B00327C8ULL, 0xA831C66D983E5152ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG2, TMSG1, 4); + TMSG3 = _mm_add_epi32(TMSG3, TMP); + TMSG3 = _mm_sha256msg2_epu32(TMSG3, TMSG2); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG1 = _mm_sha256msg1_epu32(TMSG1, TMSG2); + + // Rounds 28-31 + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(0x1429296706CA6351ULL, 0xD5A79147C6E00BF3ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG3, TMSG2, 4); + TMSG0 = _mm_add_epi32(TMSG0, TMP); + TMSG0 = _mm_sha256msg2_epu32(TMSG0, TMSG3); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG2 = _mm_sha256msg1_epu32(TMSG2, TMSG3); + + // Rounds 32-35 + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(0x53380D134D2C6DFCULL, 0x2E1B213827B70A85ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG0, TMSG3, 4); + TMSG1 = _mm_add_epi32(TMSG1, TMP); + TMSG1 = _mm_sha256msg2_epu32(TMSG1, TMSG0); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG3 = _mm_sha256msg1_epu32(TMSG3, TMSG0); + + // Rounds 36-39 + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(0x92722C8581C2C92EULL, 0x766A0ABB650A7354ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG1, TMSG0, 4); + TMSG2 = _mm_add_epi32(TMSG2, TMP); + TMSG2 = _mm_sha256msg2_epu32(TMSG2, TMSG1); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG0 = _mm_sha256msg1_epu32(TMSG0, TMSG1); + + // Rounds 40-43 + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(0xC76C51A3C24B8B70ULL, 0xA81A664BA2BFE8A1ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG2, TMSG1, 4); + TMSG3 = _mm_add_epi32(TMSG3, TMP); + TMSG3 = _mm_sha256msg2_epu32(TMSG3, TMSG2); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG1 = _mm_sha256msg1_epu32(TMSG1, TMSG2); + + // Rounds 44-47 + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(0x106AA070F40E3585ULL, 0xD6990624D192E819ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG3, TMSG2, 4); + TMSG0 = _mm_add_epi32(TMSG0, TMP); + TMSG0 = _mm_sha256msg2_epu32(TMSG0, TMSG3); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG2 = _mm_sha256msg1_epu32(TMSG2, TMSG3); + + // Rounds 48-51 + MSG = _mm_add_epi32(TMSG0, _mm_set_epi64x(0x34B0BCB52748774CULL, 0x1E376C0819A4C116ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG0, TMSG3, 4); + TMSG1 = _mm_add_epi32(TMSG1, TMP); + TMSG1 = _mm_sha256msg2_epu32(TMSG1, TMSG0); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + TMSG3 = _mm_sha256msg1_epu32(TMSG3, TMSG0); + + // Rounds 52-55 + MSG = _mm_add_epi32(TMSG1, _mm_set_epi64x(0x682E6FF35B9CCA4FULL, 0x4ED8AA4A391C0CB3ULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG1, TMSG0, 4); + TMSG2 = _mm_add_epi32(TMSG2, TMP); + TMSG2 = _mm_sha256msg2_epu32(TMSG2, TMSG1); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Rounds 56-59 + MSG = _mm_add_epi32(TMSG2, _mm_set_epi64x(0x8CC7020884C87814ULL, 0x78A5636F748F82EEULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + TMP = _mm_alignr_epi8(TMSG2, TMSG1, 4); + TMSG3 = _mm_add_epi32(TMSG3, TMP); + TMSG3 = _mm_sha256msg2_epu32(TMSG3, TMSG2); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Rounds 60-63 + MSG = _mm_add_epi32(TMSG3, _mm_set_epi64x(0xC67178F2BEF9A3F7ULL, 0xA4506CEB90BEFFFAULL)); + STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); + MSG = _mm_shuffle_epi32(MSG, 0x0E); + STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); + + // Add values back to state + STATE0 = _mm_add_epi32(STATE0, ABEF_SAVE); + STATE1 = _mm_add_epi32(STATE1, CDGH_SAVE); + + input_mm += 4; + blocks--; + } + + TMP = _mm_shuffle_epi32(STATE0, 0x1B); // FEBA + STATE1 = _mm_shuffle_epi32(STATE1, 0xB1); // DCHG + STATE0 = _mm_blend_epi16(TMP, STATE1, 0xF0); // DCBA + STATE1 = _mm_alignr_epi8(STATE1, TMP, 8); // ABEF + + // Save state + _mm_storeu_si128(reinterpret_cast<__m128i*>(&state[0]), STATE0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(&state[4]), STATE1); + } +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_64/info.txt b/src/libs/3rdparty/botan/src/lib/hash/sha2_64/info.txt new file mode 100644 index 0000000000..6fb415a6bb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_64/info.txt @@ -0,0 +1,7 @@ +<defines> +SHA2_64 -> 20131128 +</defines> + +<requires> +mdx_hash +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_64/sha2_64.cpp b/src/libs/3rdparty/botan/src/lib/hash/sha2_64/sha2_64.cpp new file mode 100644 index 0000000000..45992e9968 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_64/sha2_64.cpp @@ -0,0 +1,241 @@ +/* +* SHA-{384,512} +* (C) 1999-2011,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sha2_64.h> + +namespace Botan { + +std::unique_ptr<HashFunction> SHA_384::copy_state() const + { + return std::unique_ptr<HashFunction>(new SHA_384(*this)); + } + +std::unique_ptr<HashFunction> SHA_512::copy_state() const + { + return std::unique_ptr<HashFunction>(new SHA_512(*this)); + } + +std::unique_ptr<HashFunction> SHA_512_256::copy_state() const + { + return std::unique_ptr<HashFunction>(new SHA_512_256(*this)); + } + +namespace { + +/* +* SHA-512 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. +*/ +#define SHA2_64_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) \ + do { \ + const uint64_t E_rho = rotr<14>(E) ^ rotr<18>(E) ^ rotr<41>(E); \ + const uint64_t A_rho = rotr<28>(A) ^ rotr<34>(A) ^ rotr<39>(A); \ + const uint64_t M2_sigma = rotr<19>(M2) ^ rotr<61>(M2) ^ (M2 >> 6); \ + const uint64_t M4_sigma = rotr<1>(M4) ^ rotr<8>(M4) ^ (M4 >> 7); \ + H += magic + E_rho + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += A_rho + ((A & B) | ((A | B) & C)); \ + M1 += M2_sigma + M3 + M4_sigma; \ + } while(0); + +/* +* SHA-{384,512} Compression Function +*/ +void SHA64_compress(secure_vector<uint64_t>& digest, + const uint8_t input[], size_t blocks) + { + uint64_t A = digest[0], B = digest[1], C = digest[2], + D = digest[3], E = digest[4], F = digest[5], + G = digest[6], H = digest[7]; + + for(size_t i = 0; i != blocks; ++i) + { + uint64_t W00 = load_be<uint64_t>(input, 0); + uint64_t W01 = load_be<uint64_t>(input, 1); + uint64_t W02 = load_be<uint64_t>(input, 2); + uint64_t W03 = load_be<uint64_t>(input, 3); + uint64_t W04 = load_be<uint64_t>(input, 4); + uint64_t W05 = load_be<uint64_t>(input, 5); + uint64_t W06 = load_be<uint64_t>(input, 6); + uint64_t W07 = load_be<uint64_t>(input, 7); + uint64_t W08 = load_be<uint64_t>(input, 8); + uint64_t W09 = load_be<uint64_t>(input, 9); + uint64_t W10 = load_be<uint64_t>(input, 10); + uint64_t W11 = load_be<uint64_t>(input, 11); + uint64_t W12 = load_be<uint64_t>(input, 12); + uint64_t W13 = load_be<uint64_t>(input, 13); + uint64_t W14 = load_be<uint64_t>(input, 14); + uint64_t W15 = load_be<uint64_t>(input, 15); + + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98D728AE22); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x7137449123EF65CD); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCFEC4D3B2F); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA58189DBBC); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25BF348B538); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1B605D019); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4AF194F9B); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5DA6D8118); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98A3030242); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B0145706FBE); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE4EE4B28C); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3D5FFB4E2); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74F27B896F); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE3B1696B1); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A725C71235); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174CF692694); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C19EF14AD2); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786384F25E3); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC68B8CD5B5); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC77AC9C65); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F592B0275); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA6EA6E483); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DCBD41FBD4); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA831153B5); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152EE66DFAB); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D2DB43210); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C898FB213F); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7BEEF0EE4); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF33DA88FC2); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147930AA725); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351E003826F); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x142929670A0E6E70); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A8546D22FFC); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B21385C26C926); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC5AC42AED); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D139D95B3DF); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A73548BAF63DE); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB3C77B2A8); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E47EDAEE6); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C851482353B); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A14CF10364); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664BBC423001); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70D0F89791); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A30654BE30); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819D6EF5218); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD69906245565A910); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E35855771202A); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA07032BBD1B8); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116B8D2D0C8); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C085141AB53); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774CDF8EEB99); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5E19B48A8); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3C5C95A63); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4AE3418ACB); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F7763E373); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3D6B2B8A3); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE5DEFB2FC); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F43172F60); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814A1F0AB72); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC702081A6439EC); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA23631E28); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEBDE82BDE9); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7B2C67915); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2E372532B); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xCA273ECEEA26619C); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xD186B8C721C0C207); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xEADA7DD6CDE0EB1E); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xF57D4F7FEE6ED178); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x06F067AA72176FBA); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x0A637DC5A2C898A6); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x113F9804BEF90DAE); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x1B710B35131C471B); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x28DB77F523047D84); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x32CAAB7B40C72493); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x3C9EBE0A15C9BEBC); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x431D67C49C100D4C); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x4CC5D4BECB3E42B6); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x597F299CFC657E2A); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x5FCB6FAB3AD6FAEC); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x6C44198C4A475817); + + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); + F = (digest[5] += F); + G = (digest[6] += G); + H = (digest[7] += H); + + input += 128; + } + } + +} + +void SHA_512_256::compress_n(const uint8_t input[], size_t blocks) + { + SHA64_compress(m_digest, input, blocks); + } + +void SHA_384::compress_n(const uint8_t input[], size_t blocks) + { + SHA64_compress(m_digest, input, blocks); + } + +void SHA_512::compress_n(const uint8_t input[], size_t blocks) + { + SHA64_compress(m_digest, input, blocks); + } + +void SHA_512_256::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +void SHA_384::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +void SHA_512::copy_out(uint8_t output[]) + { + copy_out_vec_be(output, output_length(), m_digest); + } + +void SHA_512_256::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0x22312194FC2BF72C; + m_digest[1] = 0x9F555FA3C84C64C2; + m_digest[2] = 0x2393B86B6F53B151; + m_digest[3] = 0x963877195940EABD; + m_digest[4] = 0x96283EE2A88EFFE3; + m_digest[5] = 0xBE5E1E2553863992; + m_digest[6] = 0x2B0199FC2C85B8AA; + m_digest[7] = 0x0EB72DDC81C52CA2; + } + +void SHA_384::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0xCBBB9D5DC1059ED8; + m_digest[1] = 0x629A292A367CD507; + m_digest[2] = 0x9159015A3070DD17; + m_digest[3] = 0x152FECD8F70E5939; + m_digest[4] = 0x67332667FFC00B31; + m_digest[5] = 0x8EB44A8768581511; + m_digest[6] = 0xDB0C2E0D64F98FA7; + m_digest[7] = 0x47B5481DBEFA4FA4; + } + +void SHA_512::clear() + { + MDx_HashFunction::clear(); + m_digest[0] = 0x6A09E667F3BCC908; + m_digest[1] = 0xBB67AE8584CAA73B; + m_digest[2] = 0x3C6EF372FE94F82B; + m_digest[3] = 0xA54FF53A5F1D36F1; + m_digest[4] = 0x510E527FADE682D1; + m_digest[5] = 0x9B05688C2B3E6C1F; + m_digest[6] = 0x1F83D9ABFB41BD6B; + m_digest[7] = 0x5BE0CD19137E2179; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/hash/sha2_64/sha2_64.h b/src/libs/3rdparty/botan/src/lib/hash/sha2_64/sha2_64.h new file mode 100644 index 0000000000..cbe1ad70bb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/hash/sha2_64/sha2_64.h @@ -0,0 +1,82 @@ +/* +* SHA-{384,512} +* (C) 1999-2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SHA_64BIT_H_ +#define BOTAN_SHA_64BIT_H_ + +#include <botan/mdx_hash.h> + +namespace Botan { + +/** +* SHA-384 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_384 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-384"; } + size_t output_length() const override { return 48; } + HashFunction* clone() const override { return new SHA_384; } + std::unique_ptr<HashFunction> copy_state() const override; + + void clear() override; + + SHA_384() : MDx_HashFunction(128, true, true, 16), m_digest(8) + { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + secure_vector<uint64_t> m_digest; + }; + +/** +* SHA-512 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_512 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-512"; } + size_t output_length() const override { return 64; } + HashFunction* clone() const override { return new SHA_512; } + std::unique_ptr<HashFunction> copy_state() const override; + + void clear() override; + + SHA_512() : MDx_HashFunction(128, true, true, 16), m_digest(8) + { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + secure_vector<uint64_t> m_digest; + }; + +/** +* SHA-512/256 +*/ +class BOTAN_PUBLIC_API(2,0) SHA_512_256 final : public MDx_HashFunction + { + public: + std::string name() const override { return "SHA-512-256"; } + size_t output_length() const override { return 32; } + HashFunction* clone() const override { return new SHA_512_256; } + std::unique_ptr<HashFunction> copy_state() const override; + + void clear() override; + + SHA_512_256() : MDx_HashFunction(128, true, true, 16), m_digest(8) { clear(); } + private: + void compress_n(const uint8_t[], size_t blocks) override; + void copy_out(uint8_t[]) override; + + secure_vector<uint64_t> m_digest; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/kdf/info.txt b/src/libs/3rdparty/botan/src/lib/kdf/info.txt new file mode 100644 index 0000000000..81567300f5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/kdf/info.txt @@ -0,0 +1,12 @@ +<defines> +KDF_BASE -> 20131128 +</defines> + +<requires> +mac +hash +</requires> + +<header:public> +kdf.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/kdf/kdf.cpp b/src/libs/3rdparty/botan/src/lib/kdf/kdf.cpp new file mode 100644 index 0000000000..fbe24462ad --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/kdf/kdf.cpp @@ -0,0 +1,251 @@ +/* +* KDF Retrieval +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/kdf.h> +#include <botan/mac.h> +#include <botan/hash.h> +#include <botan/scan_name.h> +#include <botan/exceptn.h> + +#if defined(BOTAN_HAS_HKDF) +#include <botan/hkdf.h> +#endif + +#if defined(BOTAN_HAS_KDF1) +#include <botan/kdf1.h> +#endif + +#if defined(BOTAN_HAS_KDF2) +#include <botan/kdf2.h> +#endif + +#if defined(BOTAN_HAS_KDF1_18033) +#include <botan/kdf1_iso18033.h> +#endif + +#if defined(BOTAN_HAS_TLS_V10_PRF) || defined(BOTAN_HAS_TLS_V12_PRF) +#include <botan/prf_tls.h> +#endif + +#if defined(BOTAN_HAS_X942_PRF) +#include <botan/prf_x942.h> +#endif + +#if defined(BOTAN_HAS_SP800_108) +#include <botan/sp800_108.h> +#endif + +#if defined(BOTAN_HAS_SP800_56A) +#include <botan/sp800_56a.h> +#endif + +#if defined(BOTAN_HAS_SP800_56C) +#include <botan/sp800_56c.h> +#endif + +namespace Botan { + +namespace { + +template<typename KDF_Type> +std::unique_ptr<KDF> +kdf_create_mac_or_hash(const std::string& nm) + { + if(auto mac = MessageAuthenticationCode::create(nm)) + return std::unique_ptr<KDF>(new KDF_Type(mac.release())); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + nm + ")")) + return std::unique_ptr<KDF>(new KDF_Type(mac.release())); + + return nullptr; + } + +} + +std::unique_ptr<KDF> KDF::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_HKDF) + if(req.algo_name() == "HKDF" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash<HKDF>(req.arg(0)); + } + } + + if(req.algo_name() == "HKDF-Extract" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash<HKDF_Extract>(req.arg(0)); + } + } + + if(req.algo_name() == "HKDF-Expand" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash<HKDF_Expand>(req.arg(0)); + } + } +#endif + +#if defined(BOTAN_HAS_KDF2) + if(req.algo_name() == "KDF2" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr<KDF>(new KDF2(hash.release())); + } + } +#endif + +#if defined(BOTAN_HAS_KDF1_18033) + if(req.algo_name() == "KDF1-18033" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr<KDF>(new KDF1_18033(hash.release())); + } + } +#endif + +#if defined(BOTAN_HAS_KDF1) + if(req.algo_name() == "KDF1" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr<KDF>(new KDF1(hash.release())); + } + } +#endif + +#if defined(BOTAN_HAS_TLS_V10_PRF) + if(req.algo_name() == "TLS-PRF" && req.arg_count() == 0) + { + if(provider.empty() || provider == "base") + { + return std::unique_ptr<KDF>(new TLS_PRF); + } + } +#endif + +#if defined(BOTAN_HAS_TLS_V12_PRF) + if(req.algo_name() == "TLS-12-PRF" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash<TLS_12_PRF>(req.arg(0)); + } + } +#endif + +#if defined(BOTAN_HAS_X942_PRF) + if(req.algo_name() == "X9.42-PRF" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return std::unique_ptr<KDF>(new X942_PRF(req.arg(0))); + } + } +#endif + +#if defined(BOTAN_HAS_SP800_108) + if(req.algo_name() == "SP800-108-Counter" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash<SP800_108_Counter>(req.arg(0)); + } + } + + if(req.algo_name() == "SP800-108-Feedback" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash<SP800_108_Feedback>(req.arg(0)); + } + } + + if(req.algo_name() == "SP800-108-Pipeline" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + return kdf_create_mac_or_hash<SP800_108_Pipeline>(req.arg(0)); + } + } +#endif + +#if defined(BOTAN_HAS_SP800_56A) + if(req.algo_name() == "SP800-56A" && req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr<KDF>(new SP800_56A_Hash(hash.release())); + if(auto mac = MessageAuthenticationCode::create(req.arg(0))) + return std::unique_ptr<KDF>(new SP800_56A_HMAC(mac.release())); + } +#endif + +#if defined(BOTAN_HAS_SP800_56C) + if(req.algo_name() == "SP800-56C" && req.arg_count() == 1) + { + std::unique_ptr<KDF> exp(kdf_create_mac_or_hash<SP800_108_Feedback>(req.arg(0))); + if(exp) + { + if(auto mac = MessageAuthenticationCode::create(req.arg(0))) + return std::unique_ptr<KDF>(new SP800_56C(mac.release(), exp.release())); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + req.arg(0) + ")")) + return std::unique_ptr<KDF>(new SP800_56C(mac.release(), exp.release())); + } + } +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +//static +std::unique_ptr<KDF> +KDF::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto kdf = KDF::create(algo, provider)) + { + return kdf; + } + throw Lookup_Error("KDF", algo, provider); + } + +std::vector<std::string> KDF::providers(const std::string& algo_spec) + { + return probe_providers_of<KDF>(algo_spec, { "base" }); + } + +KDF* get_kdf(const std::string& algo_spec) + { + SCAN_Name request(algo_spec); + + if(request.algo_name() == "Raw") + return nullptr; // No KDF + + //return KDF::create_or_throw(algo_spec).release(); + auto kdf = KDF::create(algo_spec); + if(!kdf) + throw Algorithm_Not_Found(algo_spec); + return kdf.release(); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/kdf/kdf.h b/src/libs/3rdparty/botan/src/lib/kdf/kdf.h new file mode 100644 index 0000000000..dd4cfedf6d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/kdf/kdf.h @@ -0,0 +1,196 @@ +/* +* Key Derivation Function interfaces +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KDF_BASE_H_ +#define BOTAN_KDF_BASE_H_ + +#include <botan/secmem.h> +#include <botan/types.h> +#include <string> + +namespace Botan { + +/** +* Key Derivation Function +*/ +class BOTAN_PUBLIC_API(2,0) KDF + { + public: + virtual ~KDF() = default; + + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to choose + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr<KDF> + create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name, or throw if the + * algo/provider combination cannot be found. If provider is + * empty then best available is chosen. + */ + static std::unique_ptr<KDF> + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + */ + static std::vector<std::string> providers(const std::string& algo_spec); + + /** + * @return KDF name + */ + virtual std::string name() const = 0; + + /** + * Derive a key + * @param key buffer holding the derived key, must be of length key_len + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + * @param salt_len size of salt in bytes + * @param label purpose for the derived keying material + * @param label_len size of label in bytes + * @return the derived key + */ + virtual size_t kdf(uint8_t key[], size_t key_len, + const uint8_t secret[], size_t secret_len, + const uint8_t salt[], size_t salt_len, + const uint8_t label[], size_t label_len) const = 0; + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + * @param salt_len size of salt in bytes + * @param label purpose for the derived keying material + * @param label_len size of label in bytes + * @return the derived key + */ + secure_vector<uint8_t> derive_key(size_t key_len, + const uint8_t secret[], + size_t secret_len, + const uint8_t salt[], + size_t salt_len, + const uint8_t label[] = nullptr, + size_t label_len = 0) const + { + secure_vector<uint8_t> key(key_len); + key.resize(kdf(key.data(), key.size(), secret, secret_len, salt, salt_len, label, label_len)); + return key; + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + * @param label purpose for the derived keying material + * @return the derived key + */ + secure_vector<uint8_t> derive_key(size_t key_len, + const secure_vector<uint8_t>& secret, + const std::string& salt = "", + const std::string& label = "") const + { + return derive_key(key_len, secret.data(), secret.size(), + cast_char_ptr_to_uint8(salt.data()), + salt.length(), + cast_char_ptr_to_uint8(label.data()), + label.length()); + + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + * @param label purpose for the derived keying material + * @return the derived key + */ + template<typename Alloc, typename Alloc2, typename Alloc3> + secure_vector<uint8_t> derive_key(size_t key_len, + const std::vector<uint8_t, Alloc>& secret, + const std::vector<uint8_t, Alloc2>& salt, + const std::vector<uint8_t, Alloc3>& label) const + { + return derive_key(key_len, + secret.data(), secret.size(), + salt.data(), salt.size(), + label.data(), label.size()); + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param salt a diversifier + * @param salt_len size of salt in bytes + * @param label purpose for the derived keying material + * @return the derived key + */ + secure_vector<uint8_t> derive_key(size_t key_len, + const secure_vector<uint8_t>& secret, + const uint8_t salt[], + size_t salt_len, + const std::string& label = "") const + { + return derive_key(key_len, + secret.data(), secret.size(), + salt, salt_len, + cast_char_ptr_to_uint8(label.data()), + label.size()); + } + + /** + * Derive a key + * @param key_len the desired output length in bytes + * @param secret the secret input + * @param secret_len size of secret in bytes + * @param salt a diversifier + * @param label purpose for the derived keying material + * @return the derived key + */ + secure_vector<uint8_t> derive_key(size_t key_len, + const uint8_t secret[], + size_t secret_len, + const std::string& salt = "", + const std::string& label = "") const + { + return derive_key(key_len, secret, secret_len, + cast_char_ptr_to_uint8(salt.data()), + salt.length(), + cast_char_ptr_to_uint8(label.data()), + label.length()); + } + + /** + * @return new object representing the same algorithm as *this + */ + virtual KDF* clone() const = 0; + }; + +/** +* Factory method for KDF (key derivation function) +* @param algo_spec the name of the KDF to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_PUBLIC_API(2,0) KDF* get_kdf(const std::string& algo_spec); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/mac/hmac/hmac.cpp b/src/libs/3rdparty/botan/src/lib/mac/hmac/hmac.cpp new file mode 100644 index 0000000000..72c617c5b4 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/mac/hmac/hmac.cpp @@ -0,0 +1,107 @@ +/* +* HMAC +* (C) 1999-2007,2014 Jack Lloyd +* 2007 Yves Jerschow +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/hmac.h> + +namespace Botan { + +/* +* Update a HMAC Calculation +*/ +void HMAC::add_data(const uint8_t input[], size_t length) + { + verify_key_set(m_ikey.empty() == false); + m_hash->update(input, length); + } + +/* +* Finalize a HMAC Calculation +*/ +void HMAC::final_result(uint8_t mac[]) + { + verify_key_set(m_okey.empty() == false); + m_hash->final(mac); + m_hash->update(m_okey); + m_hash->update(mac, output_length()); + m_hash->final(mac); + m_hash->update(m_ikey); + } + +Key_Length_Specification HMAC::key_spec() const + { + // Support very long lengths for things like PBKDF2 and the TLS PRF + return Key_Length_Specification(0, 4096); + } + +/* +* HMAC Key Schedule +*/ +void HMAC::key_schedule(const uint8_t key[], size_t length) + { + m_hash->clear(); + + m_ikey.resize(m_hash->hash_block_size()); + m_okey.resize(m_hash->hash_block_size()); + + const uint8_t ipad = 0x36; + const uint8_t opad = 0x5C; + + std::fill(m_ikey.begin(), m_ikey.end(), ipad); + std::fill(m_okey.begin(), m_okey.end(), opad); + + if(length > m_hash->hash_block_size()) + { + secure_vector<uint8_t> hmac_key = m_hash->process(key, length); + xor_buf(m_ikey, hmac_key, hmac_key.size()); + xor_buf(m_okey, hmac_key, hmac_key.size()); + } + else + { + xor_buf(m_ikey, key, length); + xor_buf(m_okey, key, length); + } + + m_hash->update(m_ikey); + } + +/* +* Clear memory of sensitive data +*/ +void HMAC::clear() + { + m_hash->clear(); + zap(m_ikey); + zap(m_okey); + } + +/* +* Return the name of this type +*/ +std::string HMAC::name() const + { + return "HMAC(" + m_hash->name() + ")"; + } + +/* +* Return a clone of this object +*/ +MessageAuthenticationCode* HMAC::clone() const + { + return new HMAC(m_hash->clone()); + } + +/* +* HMAC Constructor +*/ +HMAC::HMAC(HashFunction* hash) : m_hash(hash) + { + BOTAN_ARG_CHECK(m_hash->hash_block_size() > 0, + "HMAC is not compatible with this hash function"); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/mac/hmac/hmac.h b/src/libs/3rdparty/botan/src/lib/mac/hmac/hmac.h new file mode 100644 index 0000000000..8001594324 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/mac/hmac/hmac.h @@ -0,0 +1,48 @@ +/* +* HMAC +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HMAC_H_ +#define BOTAN_HMAC_H_ + +#include <botan/mac.h> +#include <botan/hash.h> + +namespace Botan { + +/** +* HMAC +*/ +class BOTAN_PUBLIC_API(2,0) HMAC final : public MessageAuthenticationCode + { + public: + void clear() override; + std::string name() const override; + MessageAuthenticationCode* clone() const override; + + size_t output_length() const override { return m_hash->output_length(); } + + Key_Length_Specification key_spec() const override; + + /** + * @param hash the hash to use for HMACing + */ + explicit HMAC(HashFunction* hash); + + HMAC(const HMAC&) = delete; + HMAC& operator=(const HMAC&) = delete; + private: + void add_data(const uint8_t[], size_t) override; + void final_result(uint8_t[]) override; + void key_schedule(const uint8_t[], size_t) override; + + std::unique_ptr<HashFunction> m_hash; + secure_vector<uint8_t> m_ikey, m_okey; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/mac/hmac/info.txt b/src/libs/3rdparty/botan/src/lib/mac/hmac/info.txt new file mode 100644 index 0000000000..50dc665dc9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/mac/hmac/info.txt @@ -0,0 +1,7 @@ +<defines> +HMAC -> 20131128 +</defines> + +<requires> +hash +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/mac/info.txt b/src/libs/3rdparty/botan/src/lib/mac/info.txt new file mode 100644 index 0000000000..7aef92b879 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/mac/info.txt @@ -0,0 +1,7 @@ +<defines> +MAC -> 20150626 +</defines> + +<header:public> +mac.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/mac/mac.cpp b/src/libs/3rdparty/botan/src/lib/mac/mac.cpp new file mode 100644 index 0000000000..4c3fc5230e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/mac/mac.cpp @@ -0,0 +1,171 @@ +/* +* Message Authentication Code base class +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/mac.h> +#include <botan/exceptn.h> +#include <botan/scan_name.h> +#include <botan/mem_ops.h> + +#if defined(BOTAN_HAS_CBC_MAC) + #include <botan/cbc_mac.h> +#endif + +#if defined(BOTAN_HAS_CMAC) + #include <botan/cmac.h> +#endif + +#if defined(BOTAN_HAS_GMAC) + #include <botan/gmac.h> + #include <botan/block_cipher.h> +#endif + +#if defined(BOTAN_HAS_HMAC) + #include <botan/hmac.h> + #include <botan/hash.h> +#endif + +#if defined(BOTAN_HAS_POLY1305) + #include <botan/poly1305.h> +#endif + +#if defined(BOTAN_HAS_SIPHASH) + #include <botan/siphash.h> +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + #include <botan/x919_mac.h> +#endif + +namespace Botan { + +std::unique_ptr<MessageAuthenticationCode> +MessageAuthenticationCode::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_GMAC) + if(req.algo_name() == "GMAC" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto bc = BlockCipher::create(req.arg(0))) + return std::unique_ptr<MessageAuthenticationCode>(new GMAC(bc.release())); + } + } +#endif + +#if defined(BOTAN_HAS_HMAC) + if(req.algo_name() == "HMAC" && req.arg_count() == 1) + { + // TODO OpenSSL + if(provider.empty() || provider == "base") + { + if(auto h = HashFunction::create(req.arg(0))) + return std::unique_ptr<MessageAuthenticationCode>(new HMAC(h.release())); + } + } +#endif + +#if defined(BOTAN_HAS_POLY1305) + if(req.algo_name() == "Poly1305" && req.arg_count() == 0) + { + if(provider.empty() || provider == "base") + return std::unique_ptr<MessageAuthenticationCode>(new Poly1305); + } +#endif + +#if defined(BOTAN_HAS_SIPHASH) + if(req.algo_name() == "SipHash") + { + if(provider.empty() || provider == "base") + { + return std::unique_ptr<MessageAuthenticationCode>( + new SipHash(req.arg_as_integer(0, 2), req.arg_as_integer(1, 4))); + } + } +#endif + +#if defined(BOTAN_HAS_CMAC) + if((req.algo_name() == "CMAC" || req.algo_name() == "OMAC") && req.arg_count() == 1) + { + // TODO: OpenSSL CMAC + if(provider.empty() || provider == "base") + { + if(auto bc = BlockCipher::create(req.arg(0))) + return std::unique_ptr<MessageAuthenticationCode>(new CMAC(bc.release())); + } + } +#endif + + +#if defined(BOTAN_HAS_CBC_MAC) + if(req.algo_name() == "CBC-MAC" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto bc = BlockCipher::create(req.arg(0))) + return std::unique_ptr<MessageAuthenticationCode>(new CBC_MAC(bc.release())); + } + } +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + if(req.algo_name() == "X9.19-MAC") + { + if(provider.empty() || provider == "base") + { + return std::unique_ptr<MessageAuthenticationCode>(new ANSI_X919_MAC); + } + } +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +std::vector<std::string> +MessageAuthenticationCode::providers(const std::string& algo_spec) + { + return probe_providers_of<MessageAuthenticationCode>(algo_spec, {"base", "openssl"}); + } + +//static +std::unique_ptr<MessageAuthenticationCode> +MessageAuthenticationCode::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto mac = MessageAuthenticationCode::create(algo, provider)) + { + return mac; + } + throw Lookup_Error("MAC", algo, provider); + } + +void MessageAuthenticationCode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + BOTAN_UNUSED(nonce); + if(nonce_len > 0) + throw Invalid_IV_Length(name(), nonce_len); + } + +/* +* Default (deterministic) MAC verification operation +*/ +bool MessageAuthenticationCode::verify_mac(const uint8_t mac[], size_t length) + { + secure_vector<uint8_t> our_mac = final(); + + if(our_mac.size() != length) + return false; + + return constant_time_compare(our_mac.data(), mac, length); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/mac/mac.h b/src/libs/3rdparty/botan/src/lib/mac/mac.h new file mode 100644 index 0000000000..de30b7dbb2 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/mac/mac.h @@ -0,0 +1,143 @@ +/* +* Base class for message authentiction codes +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MESSAGE_AUTH_CODE_BASE_H_ +#define BOTAN_MESSAGE_AUTH_CODE_BASE_H_ + +#include <botan/buf_comp.h> +#include <botan/sym_algo.h> +#include <string> +#include <memory> + +namespace Botan { + +/** +* This class represents Message Authentication Code (MAC) objects. +*/ +class BOTAN_PUBLIC_API(2,0) MessageAuthenticationCode : public Buffered_Computation, + public SymmetricAlgorithm + { + public: + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr<MessageAuthenticationCode> + create(const std::string& algo_spec, + const std::string& provider = ""); + + /* + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * Throws a Lookup_Error if algo/provider combination cannot be found + */ + static std::unique_ptr<MessageAuthenticationCode> + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + */ + static std::vector<std::string> providers(const std::string& algo_spec); + + virtual ~MessageAuthenticationCode() = default; + + /** + * Prepare for processing a message under the specified nonce + * + * Most MACs neither require nor support a nonce; for these algorithms + * calling `start_msg` is optional and calling it with anything other than + * an empty string is an error. One MAC which *requires* a per-message + * nonce be specified is GMAC. + * + * @param nonce the message nonce bytes + * @param nonce_len the size of len in bytes + * Default implementation simply rejects all non-empty nonces + * since most hash/MAC algorithms do not support randomization + */ + virtual void start_msg(const uint8_t nonce[], size_t nonce_len); + + /** + * Begin processing a message with a nonce + * + * @param nonce the per message nonce + */ + template<typename Alloc> + void start(const std::vector<uint8_t, Alloc>& nonce) + { + start_msg(nonce.data(), nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + * @param nonce_len length of nonce + */ + void start(const uint8_t nonce[], size_t nonce_len) + { + start_msg(nonce, nonce_len); + } + + /** + * Begin processing a message. + */ + void start() + { + return start_msg(nullptr, 0); + } + + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @param length the length of param in + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const uint8_t in[], size_t length); + + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const std::vector<uint8_t>& in) + { + return verify_mac(in.data(), in.size()); + } + + /** + * Verify a MAC. + * @param in the MAC to verify as a byte array + * @return true if the MAC is valid, false otherwise + */ + virtual bool verify_mac(const secure_vector<uint8_t>& in) + { + return verify_mac(in.data(), in.size()); + } + + /** + * Get a new object representing the same algorithm as *this + */ + virtual MessageAuthenticationCode* clone() const = 0; + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + + }; + +typedef MessageAuthenticationCode MAC; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/bigint/big_code.cpp b/src/libs/3rdparty/botan/src/lib/math/bigint/big_code.cpp new file mode 100644 index 0000000000..c428199659 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/bigint/big_code.cpp @@ -0,0 +1,166 @@ +/* +* BigInt Encoding/Decoding +* (C) 1999-2010,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/bigint.h> +#include <botan/divide.h> +#include <botan/charset.h> +#include <botan/hex.h> + +namespace Botan { + +/* +* Encode a BigInt +*/ +void BigInt::encode(uint8_t output[], const BigInt& n, Base base) + { + if(base == Binary) + { + n.binary_encode(output); + } + else if(base == Hexadecimal) + { + secure_vector<uint8_t> binary(n.encoded_size(Binary)); + n.binary_encode(binary.data()); + + hex_encode(cast_uint8_ptr_to_char(output), + binary.data(), binary.size()); + } + else if(base == Decimal) + { + BigInt copy = n; + BigInt remainder; + copy.set_sign(Positive); + const size_t output_size = n.encoded_size(Decimal); + for(size_t j = 0; j != output_size; ++j) + { + divide(copy, 10, copy, remainder); + output[output_size - 1 - j] = + Charset::digit2char(static_cast<uint8_t>(remainder.word_at(0))); + if(copy.is_zero()) + break; + } + } + else + throw Invalid_Argument("Unknown BigInt encoding method"); + } + +/* +* Encode a BigInt +*/ +std::vector<uint8_t> BigInt::encode(const BigInt& n, Base base) + { + std::vector<uint8_t> output(n.encoded_size(base)); + encode(output.data(), n, base); + if(base != Binary) + for(size_t j = 0; j != output.size(); ++j) + if(output[j] == 0) + output[j] = '0'; + return output; + } + +/* +* Encode a BigInt +*/ +secure_vector<uint8_t> BigInt::encode_locked(const BigInt& n, Base base) + { + secure_vector<uint8_t> output(n.encoded_size(base)); + encode(output.data(), n, base); + if(base != Binary) + for(size_t j = 0; j != output.size(); ++j) + if(output[j] == 0) + output[j] = '0'; + return output; + } + +/* +* Encode a BigInt, with leading 0s if needed +*/ +secure_vector<uint8_t> BigInt::encode_1363(const BigInt& n, size_t bytes) + { + secure_vector<uint8_t> output(bytes); + BigInt::encode_1363(output.data(), output.size(), n); + return output; + } + +//static +void BigInt::encode_1363(uint8_t output[], size_t bytes, const BigInt& n) + { + const size_t n_bytes = n.bytes(); + if(n_bytes > bytes) + throw Encoding_Error("encode_1363: n is too large to encode properly"); + + const size_t leading_0s = bytes - n_bytes; + encode(&output[leading_0s], n, Binary); + } + +/* +* Encode two BigInt, with leading 0s if needed, and concatenate +*/ +secure_vector<uint8_t> BigInt::encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes) + { + secure_vector<uint8_t> output(2 * bytes); + BigInt::encode_1363(output.data(), bytes, n1); + BigInt::encode_1363(output.data() + bytes, bytes, n2); + return output; + } + +/* +* Decode a BigInt +*/ +BigInt BigInt::decode(const uint8_t buf[], size_t length, Base base) + { + BigInt r; + if(base == Binary) + r.binary_decode(buf, length); + else if(base == Hexadecimal) + { + secure_vector<uint8_t> binary; + + if(length % 2) + { + // Handle lack of leading 0 + const char buf0_with_leading_0[2] = + { '0', static_cast<char>(buf[0]) }; + + binary = hex_decode_locked(buf0_with_leading_0, 2); + + binary += hex_decode_locked(cast_uint8_ptr_to_char(&buf[1]), + length - 1, + false); + } + else + binary = hex_decode_locked(cast_uint8_ptr_to_char(buf), + length, false); + + r.binary_decode(binary.data(), binary.size()); + } + else if(base == Decimal) + { + for(size_t i = 0; i != length; ++i) + { + if(Charset::is_space(buf[i])) + continue; + + if(!Charset::is_digit(buf[i])) + throw Invalid_Argument("BigInt::decode: " + "Invalid character in decimal input"); + + const uint8_t x = Charset::char2digit(buf[i]); + + if(x >= 10) + throw Invalid_Argument("BigInt: Invalid decimal string"); + + r *= 10; + r += x; + } + } + else + throw Invalid_Argument("Unknown BigInt decoding method"); + return r; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/bigint/big_io.cpp b/src/libs/3rdparty/botan/src/lib/math/bigint/big_io.cpp new file mode 100644 index 0000000000..803e1cc4ae --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/bigint/big_io.cpp @@ -0,0 +1,56 @@ +/* +* BigInt Input/Output +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/bigint.h> +#include <istream> +#include <ostream> + +namespace Botan { + +/* +* Write the BigInt into a stream +*/ +std::ostream& operator<<(std::ostream& stream, const BigInt& n) + { + BigInt::Base base = BigInt::Decimal; + if(stream.flags() & std::ios::hex) + base = BigInt::Hexadecimal; + else if(stream.flags() & std::ios::oct) + throw Exception("Octal output of BigInt not supported"); + + if(n == 0) + stream.write("0", 1); + else + { + if(n < 0) + stream.write("-", 1); + const std::vector<uint8_t> buffer = BigInt::encode(n, base); + size_t skip = 0; + while(skip < buffer.size() && buffer[skip] == '0') + ++skip; + stream.write(cast_uint8_ptr_to_char(buffer.data()) + skip, + buffer.size() - skip); + } + if(!stream.good()) + throw Stream_IO_Error("BigInt output operator has failed"); + return stream; + } + +/* +* Read the BigInt from a stream +*/ +std::istream& operator>>(std::istream& stream, BigInt& n) + { + std::string str; + std::getline(stream, str); + if(stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("BigInt input operator has failed"); + n = BigInt(str); + return stream; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/bigint/big_ops2.cpp b/src/libs/3rdparty/botan/src/lib/math/bigint/big_ops2.cpp new file mode 100644 index 0000000000..bd107f33ad --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/bigint/big_ops2.cpp @@ -0,0 +1,382 @@ +/* +* (C) 1999-2007,2018 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/bigint.h> +#include <botan/internal/mp_core.h> +#include <botan/internal/bit_ops.h> +#include <algorithm> + +namespace Botan { + +BigInt& BigInt::add(const word y[], size_t y_sw, Sign y_sign) + { + const size_t x_sw = sig_words(); + + if(sign() == y_sign) + { + const size_t reg_size = std::max(x_sw, y_sw) + 1; + + if(m_reg.size() < reg_size) + grow_to(reg_size); + + bigint_add2(mutable_data(), reg_size - 1, y, y_sw); + } + else + { + const int32_t relative_size = bigint_cmp(data(), x_sw, y, y_sw); + + if(relative_size < 0) + { + const size_t reg_size = std::max(x_sw, y_sw); + grow_to(reg_size); + bigint_sub2_rev(mutable_data(), y, y_sw); + set_sign(y_sign); + } + else if(relative_size == 0) + { + zeroise(m_reg); + set_sign(Positive); + } + else if(relative_size > 0) + { + bigint_sub2(mutable_data(), x_sw, y, y_sw); + } + } + + return (*this); + } + +BigInt& BigInt::operator+=(const BigInt& y) + { + return add(y.data(), y.sig_words(), y.sign()); + } + +BigInt& BigInt::operator+=(word y) + { + return add(&y, 1, Positive); + } + +BigInt& BigInt::sub(const word y[], size_t y_sw, Sign y_sign) + { + const size_t x_sw = sig_words(); + + int32_t relative_size = bigint_cmp(data(), x_sw, y, y_sw); + + const size_t reg_size = std::max(x_sw, y_sw) + 1; + grow_to(reg_size); + + if(relative_size < 0) + { + if(sign() == y_sign) + bigint_sub2_rev(mutable_data(), y, y_sw); + else + bigint_add2(mutable_data(), reg_size - 1, y, y_sw); + + set_sign(y_sign == Positive ? Negative : Positive); + } + else if(relative_size == 0) + { + if(sign() == y_sign) + { + clear(); + set_sign(Positive); + } + else + bigint_shl1(mutable_data(), x_sw, 0, 1); + } + else if(relative_size > 0) + { + if(sign() == y_sign) + bigint_sub2(mutable_data(), x_sw, y, y_sw); + else + bigint_add2(mutable_data(), reg_size - 1, y, y_sw); + } + + return (*this); + } + +BigInt& BigInt::operator-=(const BigInt& y) + { + return sub(y.data(), y.sig_words(), y.sign()); + } + +BigInt& BigInt::operator-=(word y) + { + return sub(&y, 1, Positive); + } + +BigInt& BigInt::mod_add(const BigInt& s, const BigInt& mod, secure_vector<word>& ws) + { + if(this->is_negative() || s.is_negative() || mod.is_negative()) + throw Invalid_Argument("BigInt::mod_add expects all arguments are positive"); + + // TODO add optimized version of this + *this += s; + this->reduce_below(mod, ws); + + return (*this); + } + +BigInt& BigInt::mod_sub(const BigInt& s, const BigInt& mod, secure_vector<word>& ws) + { + if(this->is_negative() || s.is_negative() || mod.is_negative()) + throw Invalid_Argument("BigInt::mod_sub expects all arguments are positive"); + + const size_t t_sw = sig_words(); + const size_t s_sw = s.sig_words(); + const size_t mod_sw = mod.sig_words(); + + if(t_sw > mod_sw || s_sw > mod_sw) + throw Invalid_Argument("BigInt::mod_sub args larger than modulus"); + + BOTAN_DEBUG_ASSERT(*this < mod); + BOTAN_DEBUG_ASSERT(s < mod); + + int32_t relative_size = bigint_cmp(data(), t_sw, s.data(), s_sw); + + if(relative_size >= 0) + { + // this >= s in which case just subtract + bigint_sub2(mutable_data(), t_sw, s.data(), s_sw); + } + else + { + // Otherwise we must sub s and then add p (or add (p - s) as here) + + if(ws.size() < mod_sw) + ws.resize(mod_sw); + + word borrow = bigint_sub3(ws.data(), mod.data(), mod_sw, s.data(), s_sw); + BOTAN_ASSERT_NOMSG(borrow == 0); + + if(m_reg.size() < mod_sw) + grow_to(mod_sw); + + word carry = bigint_add2_nc(mutable_data(), m_reg.size(), ws.data(), mod_sw); + BOTAN_ASSERT_NOMSG(carry == 0); + } + + return (*this); + } + +BigInt& BigInt::rev_sub(const word y[], size_t y_sw, secure_vector<word>& ws) + { + /* + *this = BigInt(y, y_sw) - *this; + return *this; + */ + if(this->sign() != BigInt::Positive) + throw Invalid_State("BigInt::sub_rev requires this is positive"); + + const size_t x_sw = this->sig_words(); + + const int32_t relative_size = bigint_cmp(y, y_sw, this->data(), x_sw); + + ws.resize(std::max(y_sw, x_sw) + 1); + clear_mem(ws.data(), ws.size()); + + if(relative_size < 0) + { + bigint_sub3(ws.data(), this->data(), x_sw, y, y_sw); + this->flip_sign(); + } + else if(relative_size == 0) + { + ws.clear(); + } + else if(relative_size > 0) + { + bigint_sub3(ws.data(), y, y_sw, this->data(), x_sw); + } + + m_reg.swap(ws); + + return (*this); + } + +/* +* Multiplication Operator +*/ +BigInt& BigInt::operator*=(const BigInt& y) + { + secure_vector<word> ws; + return this->mul(y, ws); + } + +BigInt& BigInt::mul(const BigInt& y, secure_vector<word>& ws) + { + const size_t x_sw = sig_words(); + const size_t y_sw = y.sig_words(); + set_sign((sign() == y.sign()) ? Positive : Negative); + + if(x_sw == 0 || y_sw == 0) + { + clear(); + set_sign(Positive); + } + else if(x_sw == 1 && y_sw) + { + grow_to(y_sw + 1); + bigint_linmul3(mutable_data(), y.data(), y_sw, word_at(0)); + } + else if(y_sw == 1 && x_sw) + { + grow_to(x_sw + 1); + bigint_linmul2(mutable_data(), x_sw, y.word_at(0)); + } + else + { + const size_t new_size = x_sw + y_sw + 1; + ws.resize(new_size); + secure_vector<word> z_reg(new_size); + + bigint_mul(z_reg.data(), z_reg.size(), + data(), size(), x_sw, + y.data(), y.size(), y_sw, + ws.data(), ws.size()); + + z_reg.swap(m_reg); + } + + return (*this); + } + +BigInt& BigInt::square(secure_vector<word>& ws) + { + const size_t sw = sig_words(); + + secure_vector<word> z(2*sw); + ws.resize(z.size()); + + bigint_sqr(z.data(), z.size(), + data(), size(), sw, + ws.data(), ws.size()); + + swap_reg(z); + set_sign(BigInt::Positive); + + return (*this); + } + +BigInt& BigInt::operator*=(word y) + { + if(y == 0) + { + clear(); + set_sign(Positive); + } + + const size_t x_sw = sig_words(); + + if(size() < x_sw + 1) + grow_to(x_sw + 1); + bigint_linmul2(mutable_data(), x_sw, y); + + return (*this); + } + +/* +* Division Operator +*/ +BigInt& BigInt::operator/=(const BigInt& y) + { + if(y.sig_words() == 1 && is_power_of_2(y.word_at(0))) + (*this) >>= (y.bits() - 1); + else + (*this) = (*this) / y; + return (*this); + } + +/* +* Modulo Operator +*/ +BigInt& BigInt::operator%=(const BigInt& mod) + { + return (*this = (*this) % mod); + } + +/* +* Modulo Operator +*/ +word BigInt::operator%=(word mod) + { + if(mod == 0) + throw BigInt::DivideByZero(); + + if(is_power_of_2(mod)) + { + word result = (word_at(0) & (mod - 1)); + clear(); + grow_to(2); + m_reg[0] = result; + return result; + } + + word remainder = 0; + + for(size_t j = sig_words(); j > 0; --j) + remainder = bigint_modop(remainder, word_at(j-1), mod); + clear(); + grow_to(2); + + if(remainder && sign() == BigInt::Negative) + m_reg[0] = mod - remainder; + else + m_reg[0] = remainder; + + set_sign(BigInt::Positive); + + return word_at(0); + } + +/* +* Left Shift Operator +*/ +BigInt& BigInt::operator<<=(size_t shift) + { + if(shift) + { + const size_t shift_words = shift / BOTAN_MP_WORD_BITS, + shift_bits = shift % BOTAN_MP_WORD_BITS, + words = sig_words(); + + /* + * FIXME - if shift_words == 0 && the top shift_bits of the top word + * are zero then we know that no additional word is needed and can + * skip the allocation. + */ + const size_t needed_size = words + shift_words + (shift_bits ? 1 : 0); + + if(m_reg.size() < needed_size) + grow_to(needed_size); + + bigint_shl1(mutable_data(), words, shift_words, shift_bits); + } + + return (*this); + } + +/* +* Right Shift Operator +*/ +BigInt& BigInt::operator>>=(size_t shift) + { + if(shift) + { + const size_t shift_words = shift / BOTAN_MP_WORD_BITS, + shift_bits = shift % BOTAN_MP_WORD_BITS; + + bigint_shr1(mutable_data(), sig_words(), shift_words, shift_bits); + + if(is_zero()) + set_sign(Positive); + } + + return (*this); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/bigint/big_ops3.cpp b/src/libs/3rdparty/botan/src/lib/math/bigint/big_ops3.cpp new file mode 100644 index 0000000000..492a69ad05 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/bigint/big_ops3.cpp @@ -0,0 +1,219 @@ +/* +* BigInt Binary Operators +* (C) 1999-2007 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/bigint.h> +#include <botan/divide.h> +#include <botan/internal/mp_core.h> +#include <botan/internal/bit_ops.h> +#include <algorithm> + +namespace Botan { + +namespace { + +BigInt bigint_add(const BigInt& x, const word y[], size_t y_sw, BigInt::Sign y_sign) + { + const size_t x_sw = x.sig_words(); + + BigInt z(x.sign(), std::max(x_sw, y_sw) + 1); + + if(x.sign() == y_sign) + bigint_add3(z.mutable_data(), x.data(), x_sw, y, y_sw); + else + { + int32_t relative_size = bigint_cmp(x.data(), x_sw, y, y_sw); + + if(relative_size < 0) + { + bigint_sub3(z.mutable_data(), y, y_sw, x.data(), x_sw); + z.set_sign(y_sign); + } + else if(relative_size == 0) + z.set_sign(BigInt::Positive); + else if(relative_size > 0) + bigint_sub3(z.mutable_data(), x.data(), x_sw, y, y_sw); + } + + return z; + } + +BigInt bigint_sub(const BigInt& x, const word y[], size_t y_sw, BigInt::Sign y_sign) + { + const size_t x_sw = x.sig_words(); + + int32_t relative_size = bigint_cmp(x.data(), x_sw, y, y_sw); + + BigInt z(BigInt::Positive, std::max(x_sw, y_sw) + 1); + + if(relative_size < 0) + { + if(x.sign() == y_sign) + bigint_sub3(z.mutable_data(), y, y_sw, x.data(), x_sw); + else + bigint_add3(z.mutable_data(), x.data(), x_sw, y, y_sw); + z.set_sign(y_sign == BigInt::Positive ? BigInt::Negative : BigInt::Positive); + } + else if(relative_size == 0) + { + if(x.sign() != y_sign) + bigint_shl2(z.mutable_data(), x.data(), x_sw, 0, 1); + z.set_sign(y_sign == BigInt::Positive ? BigInt::Negative : BigInt::Positive); + } + else if(relative_size > 0) + { + if(x.sign() == y_sign) + bigint_sub3(z.mutable_data(), x.data(), x_sw, y, y_sw); + else + bigint_add3(z.mutable_data(), x.data(), x_sw, y, y_sw); + z.set_sign(x.sign()); + } + return z; + } + +} + +BigInt operator+(const BigInt& x, const BigInt& y) + { + return bigint_add(x, y.data(), y.sig_words(), y.sign()); + } + +BigInt operator+(const BigInt& x, word y) + { + return bigint_add(x, &y, 1, BigInt::Positive); + } + +BigInt operator-(const BigInt& x, const BigInt& y) + { + return bigint_sub(x, y.data(), y.sig_words(), y.sign()); + } + +BigInt operator-(const BigInt& x, word y) + { + return bigint_sub(x, &y, 1, BigInt::Positive); + } + +/* +* Multiplication Operator +*/ +BigInt operator*(const BigInt& x, const BigInt& y) + { + const size_t x_sw = x.sig_words(), y_sw = y.sig_words(); + + BigInt z(BigInt::Positive, x.size() + y.size()); + + if(x_sw == 1 && y_sw) + bigint_linmul3(z.mutable_data(), y.data(), y_sw, x.word_at(0)); + else if(y_sw == 1 && x_sw) + bigint_linmul3(z.mutable_data(), x.data(), x_sw, y.word_at(0)); + else if(x_sw && y_sw) + { + secure_vector<word> workspace(z.size()); + + bigint_mul(z.mutable_data(), z.size(), + x.data(), x.size(), x_sw, + y.data(), y.size(), y_sw, + workspace.data(), workspace.size()); + } + + if(x_sw && y_sw && x.sign() != y.sign()) + z.flip_sign(); + return z; + } + +/* +* Division Operator +*/ +BigInt operator/(const BigInt& x, const BigInt& y) + { + if(y.sig_words() == 1 && is_power_of_2(y.word_at(0))) + return (x >> (y.bits() - 1)); + + BigInt q, r; + divide(x, y, q, r); + return q; + } + +/* +* Modulo Operator +*/ +BigInt operator%(const BigInt& n, const BigInt& mod) + { + if(mod.is_zero()) + throw BigInt::DivideByZero(); + if(mod.is_negative()) + throw Invalid_Argument("BigInt::operator%: modulus must be > 0"); + if(n.is_positive() && mod.is_positive() && n < mod) + return n; + + BigInt q, r; + divide(n, mod, q, r); + return r; + } + +/* +* Modulo Operator +*/ +word operator%(const BigInt& n, word mod) + { + if(mod == 0) + throw BigInt::DivideByZero(); + + if(mod == 1) + return 0; + + if(is_power_of_2(mod)) + return (n.word_at(0) & (mod - 1)); + + word remainder = 0; + + for(size_t j = n.sig_words(); j > 0; --j) + remainder = bigint_modop(remainder, n.word_at(j-1), mod); + + if(remainder && n.sign() == BigInt::Negative) + return mod - remainder; + return remainder; + } + +/* +* Left Shift Operator +*/ +BigInt operator<<(const BigInt& x, size_t shift) + { + if(shift == 0) + return x; + + const size_t shift_words = shift / BOTAN_MP_WORD_BITS, + shift_bits = shift % BOTAN_MP_WORD_BITS; + + const size_t x_sw = x.sig_words(); + + BigInt y(x.sign(), x_sw + shift_words + (shift_bits ? 1 : 0)); + bigint_shl2(y.mutable_data(), x.data(), x_sw, shift_words, shift_bits); + return y; + } + +/* +* Right Shift Operator +*/ +BigInt operator>>(const BigInt& x, size_t shift) + { + if(shift == 0) + return x; + if(x.bits() <= shift) + return 0; + + const size_t shift_words = shift / BOTAN_MP_WORD_BITS, + shift_bits = shift % BOTAN_MP_WORD_BITS, + x_sw = x.sig_words(); + + BigInt y(x.sign(), x_sw - shift_words); + bigint_shr2(y.mutable_data(), x.data(), x_sw, shift_words, shift_bits); + return y; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/bigint/big_rand.cpp b/src/libs/3rdparty/botan/src/lib/math/bigint/big_rand.cpp new file mode 100644 index 0000000000..dd4cb5eaba --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/bigint/big_rand.cpp @@ -0,0 +1,64 @@ +/* +* BigInt Random Generation +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/bigint.h> +#include <botan/rng.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +/* +* Randomize this number +*/ +void BigInt::randomize(RandomNumberGenerator& rng, + size_t bitsize, bool set_high_bit) + { + set_sign(Positive); + + if(bitsize == 0) + { + clear(); + } + else + { + secure_vector<uint8_t> array = rng.random_vec(round_up(bitsize, 8) / 8); + + // Always cut unwanted bits + if(bitsize % 8) + array[0] &= 0xFF >> (8 - (bitsize % 8)); + + // Set the highest bit if wanted + if (set_high_bit) + array[0] |= 0x80 >> ((bitsize % 8) ? (8 - bitsize % 8) : 0); + + binary_decode(array); + } + } + +/* +* Generate a random integer within given range +*/ +BigInt BigInt::random_integer(RandomNumberGenerator& rng, + const BigInt& min, const BigInt& max) + { + if(min.is_negative() || max.is_negative() || max <= min) + throw Invalid_Argument("BigInt::random_integer invalid range"); + + BigInt r; + + const size_t bits = max.bits(); + + do + { + r.randomize(rng, bits, false); + } + while(r < min || r >= max); + + return r; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/bigint/bigint.cpp b/src/libs/3rdparty/botan/src/lib/math/bigint/bigint.cpp new file mode 100644 index 0000000000..495907d1ab --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/bigint/bigint.cpp @@ -0,0 +1,381 @@ +/* +* BigInt Base +* (C) 1999-2011,2012,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/bigint.h> +#include <botan/internal/mp_core.h> +#include <botan/internal/rounding.h> +#include <botan/internal/bit_ops.h> +#include <botan/internal/ct_utils.h> + +namespace Botan { + +BigInt::BigInt(const word words[], size_t length) + { + m_reg.assign(words, words + length); + } + +/* +* Construct a BigInt from a regular number +*/ +BigInt::BigInt(uint64_t n) + { + if(n == 0) + return; + + const size_t limbs_needed = sizeof(uint64_t) / sizeof(word); + + m_reg.resize(limbs_needed); + for(size_t i = 0; i != limbs_needed; ++i) + m_reg[i] = ((n >> (i*BOTAN_MP_WORD_BITS)) & MP_WORD_MASK); + } + +/* +* Construct a BigInt of the specified size +*/ +BigInt::BigInt(Sign s, size_t size) + { + m_reg.resize(round_up(size, 8)); + m_signedness = s; + } + +/* +* Copy constructor +*/ +BigInt::BigInt(const BigInt& other) + { + m_reg = other.m_reg; + m_signedness = other.m_signedness; + } + +/* +* Construct a BigInt from a string +*/ +BigInt::BigInt(const std::string& str) + { + Base base = Decimal; + size_t markers = 0; + bool negative = false; + + if(str.length() > 0 && str[0] == '-') + { + markers += 1; + negative = true; + } + + if(str.length() > markers + 2 && str[markers ] == '0' && + str[markers + 1] == 'x') + { + markers += 2; + base = Hexadecimal; + } + + *this = decode(cast_char_ptr_to_uint8(str.data()) + markers, + str.length() - markers, base); + + if(negative) set_sign(Negative); + else set_sign(Positive); + } + +BigInt::BigInt(const uint8_t input[], size_t length) + { + binary_decode(input, length); + } + +/* +* Construct a BigInt from an encoded BigInt +*/ +BigInt::BigInt(const uint8_t input[], size_t length, Base base) + { + *this = decode(input, length, base); + } + +BigInt::BigInt(const uint8_t buf[], size_t length, size_t max_bits) + { + const size_t max_bytes = std::min(length, (max_bits + 7) / 8); + *this = decode(buf, max_bytes); + + const size_t b = this->bits(); + if(b > max_bits) + { + *this >>= (b - max_bits); + } + } + +/* +* Construct a BigInt from an encoded BigInt +*/ +BigInt::BigInt(RandomNumberGenerator& rng, size_t bits, bool set_high_bit) + { + randomize(rng, bits, set_high_bit); + } + +int32_t BigInt::cmp_word(word other) const + { + if(is_negative()) + return -1; // other is positive ... + + const size_t sw = this->sig_words(); + if(sw > 1) + return 1; // must be larger since other is just one word ... + + return bigint_cmp(this->data(), sw, &other, 1); + } + +/* +* Comparison Function +*/ +int32_t BigInt::cmp(const BigInt& other, bool check_signs) const + { + if(check_signs) + { + if(other.is_positive() && this->is_negative()) + return -1; + + if(other.is_negative() && this->is_positive()) + return 1; + + if(other.is_negative() && this->is_negative()) + return (-bigint_cmp(this->data(), this->sig_words(), + other.data(), other.sig_words())); + } + + return bigint_cmp(this->data(), this->sig_words(), + other.data(), other.sig_words()); + } + +void BigInt::encode_words(word out[], size_t size) const + { + const size_t words = sig_words(); + + if(words > size) + throw Encoding_Error("BigInt::encode_words value too large to encode"); + + clear_mem(out, size); + copy_mem(out, data(), words); + } + +/* +* Return bits {offset...offset+length} +*/ +uint32_t BigInt::get_substring(size_t offset, size_t length) const + { + if(length > 32) + throw Invalid_Argument("BigInt::get_substring: Substring size " + std::to_string(length) + " too big"); + + uint64_t piece = 0; + for(size_t i = 0; i != 8; ++i) + { + const uint8_t part = byte_at((offset / 8) + (7-i)); + piece = (piece << 8) | part; + } + + const uint64_t mask = (static_cast<uint64_t>(1) << length) - 1; + const size_t shift = (offset % 8); + + return static_cast<uint32_t>((piece >> shift) & mask); + } + +/* +* Convert this number to a uint32_t, if possible +*/ +uint32_t BigInt::to_u32bit() const + { + if(is_negative()) + throw Encoding_Error("BigInt::to_u32bit: Number is negative"); + if(bits() > 32) + throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert"); + + uint32_t out = 0; + for(size_t i = 0; i != 4; ++i) + out = (out << 8) | byte_at(3-i); + return out; + } + +/* +* Set bit number n +*/ +void BigInt::set_bit(size_t n) + { + const size_t which = n / BOTAN_MP_WORD_BITS; + const word mask = static_cast<word>(1) << (n % BOTAN_MP_WORD_BITS); + if(which >= size()) grow_to(which + 1); + m_reg[which] |= mask; + } + +/* +* Clear bit number n +*/ +void BigInt::clear_bit(size_t n) + { + const size_t which = n / BOTAN_MP_WORD_BITS; + const word mask = static_cast<word>(1) << (n % BOTAN_MP_WORD_BITS); + if(which < size()) + m_reg[which] &= ~mask; + } + +size_t BigInt::bytes() const + { + return round_up(bits(), 8) / 8; + } + +/* +* Count how many bits are being used +*/ +size_t BigInt::bits() const + { + const size_t words = sig_words(); + + if(words == 0) + return 0; + + const size_t full_words = words - 1; + return (full_words * BOTAN_MP_WORD_BITS + high_bit(word_at(full_words))); + } + +/* +* Calcluate the size in a certain base +*/ +size_t BigInt::encoded_size(Base base) const + { + static const double LOG_2_BASE_10 = 0.30102999566; + + if(base == Binary) + return bytes(); + else if(base == Hexadecimal) + return 2*bytes(); + else if(base == Decimal) + return static_cast<size_t>((bits() * LOG_2_BASE_10) + 1); + else + throw Invalid_Argument("Unknown base for BigInt encoding"); + } + +/* +* Return the negation of this number +*/ +BigInt BigInt::operator-() const + { + BigInt x = (*this); + x.flip_sign(); + return x; + } + +void BigInt::reduce_below(const BigInt& p, secure_vector<word>& ws) + { + if(p.is_negative()) + throw Invalid_Argument("BigInt::reduce_below mod must be positive"); + + const size_t p_words = p.sig_words(); + + if(size() < p_words + 1) + grow_to(p_words + 1); + + if(ws.size() < p_words + 1) + ws.resize(p_words + 1); + + clear_mem(ws.data(), ws.size()); + + for(;;) + { + word borrow = bigint_sub3(ws.data(), data(), p_words + 1, p.data(), p_words); + + if(borrow) + break; + + m_reg.swap(ws); + } + } + +/* +* Return the absolute value of this number +*/ +BigInt BigInt::abs() const + { + BigInt x = (*this); + x.set_sign(Positive); + return x; + } + +void BigInt::grow_to(size_t n) + { + if(n > size()) + { + if(n <= m_reg.capacity()) + m_reg.resize(m_reg.capacity()); + else + m_reg.resize(round_up(n, 8)); + } + } + +/* +* Encode this number into bytes +*/ +void BigInt::binary_encode(uint8_t output[]) const + { + const size_t sig_bytes = bytes(); + for(size_t i = 0; i != sig_bytes; ++i) + output[sig_bytes-i-1] = byte_at(i); + } + +/* +* Set this number to the value in buf +*/ +void BigInt::binary_decode(const uint8_t buf[], size_t length) + { + const size_t WORD_BYTES = sizeof(word); + + clear(); + m_reg.resize(round_up((length / WORD_BYTES) + 1, 8)); + + for(size_t i = 0; i != length / WORD_BYTES; ++i) + { + const size_t top = length - WORD_BYTES*i; + for(size_t j = WORD_BYTES; j > 0; --j) + m_reg[i] = (m_reg[i] << 8) | buf[top - j]; + } + + for(size_t i = 0; i != length % WORD_BYTES; ++i) + m_reg[length / WORD_BYTES] = (m_reg[length / WORD_BYTES] << 8) | buf[i]; + } + +#if defined(BOTAN_HAS_VALGRIND) +void BigInt::const_time_poison() const + { + CT::poison(m_reg.data(), m_reg.size()); + } + +void BigInt::const_time_unpoison() const + { + CT::unpoison(m_reg.data(), m_reg.size()); + } +#endif + +void BigInt::const_time_lookup(secure_vector<word>& output, + const std::vector<BigInt>& vec, + size_t idx) + { + const size_t words = output.size(); + + clear_mem(output.data(), output.size()); + + CT::poison(&idx, sizeof(idx)); + + for(size_t i = 0; i != vec.size(); ++i) + { + BOTAN_ASSERT(vec[i].size() >= words, + "Word size as expected in const_time_lookup"); + + const word mask = CT::is_equal(i, idx); + + for(size_t w = 0; w != words; ++w) + output[w] |= CT::select<word>(mask, vec[i].word_at(w), 0); + } + + CT::unpoison(idx); + CT::unpoison(output.data(), output.size()); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/bigint/bigint.h b/src/libs/3rdparty/botan/src/lib/math/bigint/bigint.h new file mode 100644 index 0000000000..4a07723b77 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/bigint/bigint.h @@ -0,0 +1,806 @@ +/* +* BigInt +* (C) 1999-2008,2012 Jack Lloyd +* 2007 FlexSecure +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BIGINT_H_ +#define BOTAN_BIGINT_H_ + +#include <botan/types.h> +#include <botan/secmem.h> +#include <botan/exceptn.h> +#include <botan/loadstor.h> +#include <iosfwd> + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Arbitrary precision integer +*/ +class BOTAN_PUBLIC_API(2,0) BigInt final + { + public: + /** + * Base enumerator for encoding and decoding + */ + enum Base { Decimal = 10, Hexadecimal = 16, Binary = 256 }; + + /** + * Sign symbol definitions for positive and negative numbers + */ + enum Sign { Negative = 0, Positive = 1 }; + + /** + * DivideByZero Exception + */ + class BOTAN_PUBLIC_API(2,0) DivideByZero final : public Exception + { + public: + DivideByZero() : Exception("BigInt divide by zero") {} + }; + + /** + * Create empty BigInt + */ + BigInt() = default; + + /** + * Create BigInt from 64 bit integer + * @param n initial value of this BigInt + */ + BigInt(uint64_t n); + + /** + * Copy Constructor + * @param other the BigInt to copy + */ + BigInt(const BigInt& other); + + /** + * Create BigInt from a string. If the string starts with 0x the + * rest of the string will be interpreted as hexadecimal digits. + * Otherwise, it will be interpreted as a decimal number. + * + * @param str the string to parse for an integer value + */ + explicit BigInt(const std::string& str); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the byte array holding the value + * @param length size of buf + */ + BigInt(const uint8_t buf[], size_t length); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the byte array holding the value + * @param length size of buf + * @param base is the number base of the integer in buf + */ + BigInt(const uint8_t buf[], size_t length, Base base); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the byte array holding the value + * @param length size of buf + * @param max_bits if the resulting integer is more than max_bits, + * it will be shifted so it is at most max_bits in length. + */ + BigInt(const uint8_t buf[], size_t length, size_t max_bits); + + /** + * Create a BigInt from an array of words + * @param words the words + * @param length number of words + */ + BigInt(const word words[], size_t length); + + /** + * \brief Create a random BigInt of the specified size + * + * @param rng random number generator + * @param bits size in bits + * @param set_high_bit if true, the highest bit is always set + * + * @see randomize + */ + BigInt(RandomNumberGenerator& rng, size_t bits, bool set_high_bit = true); + + /** + * Create BigInt of specified size, all zeros + * @param sign the sign + * @param n size of the internal register in words + */ + BigInt(Sign sign, size_t n); + + /** + * Move constructor + */ + BigInt(BigInt&& other) + { + this->swap(other); + } + + /** + * Move assignment + */ + BigInt& operator=(BigInt&& other) + { + if(this != &other) + this->swap(other); + + return (*this); + } + + /** + * Copy assignment + */ + BigInt& operator=(const BigInt&) = default; + + /** + * Swap this value with another + * @param other BigInt to swap values with + */ + void swap(BigInt& other) + { + m_reg.swap(other.m_reg); + std::swap(m_signedness, other.m_signedness); + } + + void swap_reg(secure_vector<word>& reg) + { + m_reg.swap(reg); + } + + /** + * += operator + * @param y the BigInt to add to this + */ + BigInt& operator+=(const BigInt& y); + + /** + * += operator + * @param y the word to add to this + */ + BigInt& operator+=(word y); + + /** + * -= operator + * @param y the BigInt to subtract from this + */ + BigInt& operator-=(const BigInt& y); + + /** + * -= operator + * @param y the word to subtract from this + */ + BigInt& operator-=(word y); + + /** + * *= operator + * @param y the BigInt to multiply with this + */ + BigInt& operator*=(const BigInt& y); + + /** + * *= operator + * @param y the word to multiply with this + */ + BigInt& operator*=(word y); + + /** + * /= operator + * @param y the BigInt to divide this by + */ + BigInt& operator/=(const BigInt& y); + + /** + * Modulo operator + * @param y the modulus to reduce this by + */ + BigInt& operator%=(const BigInt& y); + + /** + * Modulo operator + * @param y the modulus (word) to reduce this by + */ + word operator%=(word y); + + /** + * Left shift operator + * @param shift the number of bits to shift this left by + */ + BigInt& operator<<=(size_t shift); + + /** + * Right shift operator + * @param shift the number of bits to shift this right by + */ + BigInt& operator>>=(size_t shift); + + /** + * Increment operator + */ + BigInt& operator++() { return (*this += 1); } + + /** + * Decrement operator + */ + BigInt& operator--() { return (*this -= 1); } + + /** + * Postfix increment operator + */ + BigInt operator++(int) { BigInt x = (*this); ++(*this); return x; } + + /** + * Postfix decrement operator + */ + BigInt operator--(int) { BigInt x = (*this); --(*this); return x; } + + /** + * Unary negation operator + * @return negative this + */ + BigInt operator-() const; + + /** + * ! operator + * @return true iff this is zero, otherwise false + */ + bool operator !() const { return (!is_nonzero()); } + + BigInt& add(const word y[], size_t y_words, Sign sign); + BigInt& sub(const word y[], size_t y_words, Sign sign); + + /** + * Multiply this with y + * @param y the BigInt to multiply with this + * @param ws a temp workspace + */ + BigInt& mul(const BigInt& y, secure_vector<word>& ws); + + /** + * Square value of *this + * @param ws a temp workspace + */ + BigInt& square(secure_vector<word>& ws); + + /** + * Set *this to y - *this + * @param y the BigInt to subtract from as a sequence of words + * @param y_size length of y in words + * @param ws a temp workspace + */ + BigInt& rev_sub(const word y[], size_t y_size, secure_vector<word>& ws); + + /** + * Set *this to (*this + y) % mod + * This function assumes *this is >= 0 && < mod + * @param y the BigInt to add - assumed y >= 0 and y < mod + * @param mod the positive modulus + * @param ws a temp workspace + */ + BigInt& mod_add(const BigInt& y, const BigInt& mod, secure_vector<word>& ws); + + /** + * Set *this to (*this - y) % mod + * This function assumes *this is >= 0 && < mod + * @param y the BigInt to subtract - assumed y >= 0 and y < mod + * @param mod the positive modulus + * @param ws a temp workspace + */ + BigInt& mod_sub(const BigInt& y, const BigInt& mod, secure_vector<word>& ws); + + /** + * Return *this below mod + * + * Assumes that *this is (if anything) only slightly larger than + * mod and performs repeated subtractions. It should not be used if + * *this is much larger than mod, instead of modulo operator. + */ + void reduce_below(const BigInt& mod, secure_vector<word> &ws); + + /** + * Zeroize the BigInt. The size of the underlying register is not + * modified. + */ + void clear() { zeroise(m_reg); } + + /** + * Compare this to another BigInt + * @param n the BigInt value to compare with + * @param check_signs include sign in comparison? + * @result if (this<n) return -1, if (this>n) return 1, if both + * values are identical return 0 [like Perl's <=> operator] + */ + int32_t cmp(const BigInt& n, bool check_signs = true) const; + + /** + * Compare this to an integer + * @param n the value to compare with + * @result if (this<n) return -1, if (this>n) return 1, if both + * values are identical return 0 [like Perl's <=> operator] + */ + int32_t cmp_word(word n) const; + + /** + * Test if the integer has an even value + * @result true if the integer is even, false otherwise + */ + bool is_even() const { return (get_bit(0) == 0); } + + /** + * Test if the integer has an odd value + * @result true if the integer is odd, false otherwise + */ + bool is_odd() const { return (get_bit(0) == 1); } + + /** + * Test if the integer is not zero + * @result true if the integer is non-zero, false otherwise + */ + bool is_nonzero() const { return (!is_zero()); } + + /** + * Test if the integer is zero + * @result true if the integer is zero, false otherwise + */ + bool is_zero() const + { + const size_t sw = sig_words(); + + for(size_t i = 0; i != sw; ++i) + if(m_reg[i]) + return false; + return true; + } + + /** + * Set bit at specified position + * @param n bit position to set + */ + void set_bit(size_t n); + + /** + * Clear bit at specified position + * @param n bit position to clear + */ + void clear_bit(size_t n); + + /** + * Clear all but the lowest n bits + * @param n amount of bits to keep + */ + void mask_bits(size_t n) + { + if(n == 0) { clear(); return; } + + const size_t top_word = n / BOTAN_MP_WORD_BITS; + const word mask = (static_cast<word>(1) << (n % BOTAN_MP_WORD_BITS)) - 1; + + if(top_word < size()) + { + const size_t len = size() - (top_word + 1); + if (len > 0) + { + clear_mem(&m_reg[top_word+1], len); + } + m_reg[top_word] &= mask; + } + } + + /** + * Return bit value at specified position + * @param n the bit offset to test + * @result true, if the bit at position n is set, false otherwise + */ + bool get_bit(size_t n) const + { + return ((word_at(n / BOTAN_MP_WORD_BITS) >> (n % BOTAN_MP_WORD_BITS)) & 1); + } + + /** + * Return (a maximum of) 32 bits of the complete value + * @param offset the offset to start extracting + * @param length amount of bits to extract (starting at offset) + * @result the integer extracted from the register starting at + * offset with specified length + */ + uint32_t get_substring(size_t offset, size_t length) const; + + /** + * Convert this value into a uint32_t, if it is in the range + * [0 ... 2**32-1], or otherwise throw an exception. + * @result the value as a uint32_t if conversion is possible + */ + uint32_t to_u32bit() const; + + /** + * @param n the offset to get a byte from + * @result byte at offset n + */ + uint8_t byte_at(size_t n) const + { + return get_byte(sizeof(word) - (n % sizeof(word)) - 1, + word_at(n / sizeof(word))); + } + + /** + * Return the word at a specified position of the internal register + * @param n position in the register + * @return value at position n + */ + word word_at(size_t n) const + { return ((n < size()) ? m_reg[n] : 0); } + + void set_word_at(size_t i, word w) + { + if(i >= m_reg.size()) + grow_to(i + 1); + m_reg[i] = w; + } + + void set_words(const word w[], size_t len) + { + m_reg.resize(len); + copy_mem(mutable_data(), w, len); + } + + /** + * Tests if the sign of the integer is negative + * @result true, iff the integer has a negative sign + */ + bool is_negative() const { return (sign() == Negative); } + + /** + * Tests if the sign of the integer is positive + * @result true, iff the integer has a positive sign + */ + bool is_positive() const { return (sign() == Positive); } + + /** + * Return the sign of the integer + * @result the sign of the integer + */ + Sign sign() const { return (m_signedness); } + + /** + * @result the opposite sign of the represented integer value + */ + Sign reverse_sign() const + { + if(sign() == Positive) + return Negative; + return Positive; + } + + /** + * Flip the sign of this BigInt + */ + void flip_sign() + { + set_sign(reverse_sign()); + } + + /** + * Set sign of the integer + * @param sign new Sign to set + */ + void set_sign(Sign sign) + { + if(is_zero()) + m_signedness = Positive; + else + m_signedness = sign; + } + + /** + * @result absolute (positive) value of this + */ + BigInt abs() const; + + /** + * Give size of internal register + * @result size of internal register in words + */ + size_t size() const { return m_reg.size(); } + + /** + * Return how many words we need to hold this value + * @result significant words of the represented integer value + */ + size_t sig_words() const + { + const word* x = m_reg.data(); + size_t sig = m_reg.size(); + + while(sig && (x[sig-1] == 0)) + sig--; + return sig; + } + + /** + * Give byte length of the integer + * @result byte length of the represented integer value + */ + size_t bytes() const; + + /** + * Get the bit length of the integer + * @result bit length of the represented integer value + */ + size_t bits() const; + + /** + * Return a mutable pointer to the register + * @result a pointer to the start of the internal register + */ + word* mutable_data() { return m_reg.data(); } + + /** + * Return a const pointer to the register + * @result a pointer to the start of the internal register + */ + const word* data() const { return m_reg.data(); } + + secure_vector<word>& get_word_vector() { return m_reg; } + const secure_vector<word>& get_word_vector() const { return m_reg; } + + /** + * Increase internal register buffer to at least n words + * @param n new size of register + */ + void grow_to(size_t n); + + /** + * Resize the vector to the minimum word size to hold the integer, or + * min_size words, whichever is larger + */ + void shrink_to_fit(size_t min_size = 0) + { + const size_t words = std::max(min_size, sig_words()); + m_reg.resize(words); + } + + /** + * Fill BigInt with a random number with size of bitsize + * + * If \p set_high_bit is true, the highest bit will be set, which causes + * the entropy to be \a bits-1. Otherwise the highest bit is randomly chosen + * by the rng, causing the entropy to be \a bits. + * + * @param rng the random number generator to use + * @param bitsize number of bits the created random value should have + * @param set_high_bit if true, the highest bit is always set + */ + void randomize(RandomNumberGenerator& rng, size_t bitsize, bool set_high_bit = true); + + /** + * Store BigInt-value in a given byte array + * @param buf destination byte array for the integer value + */ + void binary_encode(uint8_t buf[]) const; + + /** + * Read integer value from a byte array with given size + * @param buf byte array buffer containing the integer + * @param length size of buf + */ + void binary_decode(const uint8_t buf[], size_t length); + + /** + * Read integer value from a byte array (secure_vector<uint8_t>) + * @param buf the array to load from + */ + void binary_decode(const secure_vector<uint8_t>& buf) + { + binary_decode(buf.data(), buf.size()); + } + + /** + * @param base the base to measure the size for + * @return size of this integer in base base + */ + size_t encoded_size(Base base = Binary) const; + + /** + * Place the value into out, zero-padding up to size words + * Throw if *this cannot be represented in size words + */ + void encode_words(word out[], size_t size) const; + +#if defined(BOTAN_HAS_VALGRIND) + void const_time_poison() const; + void const_time_unpoison() const; +#else + void const_time_poison() const {} + void const_time_unpoison() const {} +#endif + + /** + * @param rng a random number generator + * @param min the minimum value (must be non-negative) + * @param max the maximum value (must be non-negative and > min) + * @return random integer in [min,max) + */ + static BigInt random_integer(RandomNumberGenerator& rng, + const BigInt& min, + const BigInt& max); + + /** + * Create a power of two + * @param n the power of two to create + * @return bigint representing 2^n + */ + static BigInt power_of_2(size_t n) + { + BigInt b; + b.set_bit(n); + return b; + } + + /** + * Encode the integer value from a BigInt to a std::vector of bytes + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + * @result secure_vector of bytes containing the integer with given base + */ + static std::vector<uint8_t> encode(const BigInt& n, Base base = Binary); + + /** + * Encode the integer value from a BigInt to a secure_vector of bytes + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + * @result secure_vector of bytes containing the integer with given base + */ + static secure_vector<uint8_t> encode_locked(const BigInt& n, + Base base = Binary); + + /** + * Encode the integer value from a BigInt to a byte array + * @param buf destination byte array for the encoded integer + * value with given base + * @param n the BigInt to use as integer source + * @param base number-base of resulting byte array representation + */ + static void encode(uint8_t buf[], const BigInt& n, Base base = Binary); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param length size of buf + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const uint8_t buf[], size_t length, + Base base = Binary); + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const secure_vector<uint8_t>& buf, + Base base = Binary) + { + return BigInt::decode(buf.data(), buf.size(), base); + } + + /** + * Create a BigInt from an integer in a byte array + * @param buf the binary value to load + * @param base number-base of the integer in buf + * @result BigInt representing the integer in the byte array + */ + static BigInt decode(const std::vector<uint8_t>& buf, + Base base = Binary) + { + return BigInt::decode(buf.data(), buf.size(), base); + } + + /** + * Encode a BigInt to a byte array according to IEEE 1363 + * @param n the BigInt to encode + * @param bytes the length of the resulting secure_vector<uint8_t> + * @result a secure_vector<uint8_t> containing the encoded BigInt + */ + static secure_vector<uint8_t> encode_1363(const BigInt& n, size_t bytes); + + static void encode_1363(uint8_t out[], size_t bytes, const BigInt& n); + + /** + * Encode two BigInt to a byte array according to IEEE 1363 + * @param n1 the first BigInt to encode + * @param n2 the second BigInt to encode + * @param bytes the length of the encoding of each single BigInt + * @result a secure_vector<uint8_t> containing the concatenation of the two encoded BigInt + */ + static secure_vector<uint8_t> encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes); + + /** + * Set output = vec[idx].m_reg in constant time + * All words of vec must have the same size + */ + static void const_time_lookup( + secure_vector<word>& output, + const std::vector<BigInt>& vec, + size_t idx); + + private: + secure_vector<word> m_reg; + Sign m_signedness = Positive; + }; + +/* +* Arithmetic Operators +*/ +BigInt BOTAN_PUBLIC_API(2,0) operator+(const BigInt& x, const BigInt& y); +BigInt BOTAN_PUBLIC_API(2,7) operator+(const BigInt& x, word y); +inline BigInt operator+(word x, const BigInt& y) { return y + x; } + +BigInt BOTAN_PUBLIC_API(2,0) operator-(const BigInt& x, const BigInt& y); +BigInt BOTAN_PUBLIC_API(2,7) operator-(const BigInt& x, word y); + +BigInt BOTAN_PUBLIC_API(2,0) operator*(const BigInt& x, const BigInt& y); +BigInt BOTAN_PUBLIC_API(2,0) operator/(const BigInt& x, const BigInt& d); +BigInt BOTAN_PUBLIC_API(2,0) operator%(const BigInt& x, const BigInt& m); +word BOTAN_PUBLIC_API(2,0) operator%(const BigInt& x, word m); +BigInt BOTAN_PUBLIC_API(2,0) operator<<(const BigInt& x, size_t n); +BigInt BOTAN_PUBLIC_API(2,0) operator>>(const BigInt& x, size_t n); + +/* +* Comparison Operators +*/ +inline bool operator==(const BigInt& a, const BigInt& b) + { return (a.cmp(b) == 0); } +inline bool operator!=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) != 0); } +inline bool operator<=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) <= 0); } +inline bool operator>=(const BigInt& a, const BigInt& b) + { return (a.cmp(b) >= 0); } +inline bool operator<(const BigInt& a, const BigInt& b) + { return (a.cmp(b) < 0); } +inline bool operator>(const BigInt& a, const BigInt& b) + { return (a.cmp(b) > 0); } + +inline bool operator==(const BigInt& a, word b) + { return (a.cmp_word(b) == 0); } +inline bool operator!=(const BigInt& a, word b) + { return (a.cmp_word(b) != 0); } +inline bool operator<=(const BigInt& a, word b) + { return (a.cmp_word(b) <= 0); } +inline bool operator>=(const BigInt& a, word b) + { return (a.cmp_word(b) >= 0); } +inline bool operator<(const BigInt& a, word b) + { return (a.cmp_word(b) < 0); } +inline bool operator>(const BigInt& a, word b) + { return (a.cmp_word(b) > 0); } + +/* +* I/O Operators +*/ +BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream&, const BigInt&); +BOTAN_PUBLIC_API(2,0) std::istream& operator>>(std::istream&, BigInt&); + +} + +namespace std { + +template<> +inline void swap<Botan::BigInt>(Botan::BigInt& x, Botan::BigInt& y) + { + x.swap(y); + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/bigint/divide.cpp b/src/libs/3rdparty/botan/src/lib/math/bigint/divide.cpp new file mode 100644 index 0000000000..63326d6552 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/bigint/divide.cpp @@ -0,0 +1,140 @@ +/* +* Division Algorithm +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/divide.h> +#include <botan/internal/mp_core.h> +#include <botan/internal/mp_madd.h> + +namespace Botan { + +namespace { + +/* +* Handle signed operands, if necessary +*/ +void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r) + { + if(x.sign() == BigInt::Negative) + { + q.flip_sign(); + if(r.is_nonzero()) { --q; r = y.abs() - r; } + } + if(y.sign() == BigInt::Negative) + q.flip_sign(); + } + +bool division_check(word q, word y2, word y1, + word x3, word x2, word x1) + { + // Compute (y3,y2,y1) = (y2,y1) * q + + word y3 = 0; + y1 = word_madd2(q, y1, &y3); + y2 = word_madd2(q, y2, &y3); + + // Return (y3,y2,y1) >? (x3,x2,x1) + + if(y3 > x3) return true; + if(y3 < x3) return false; + + if(y2 > x2) return true; + if(y2 < x2) return false; + + if(y1 > x1) return true; + if(y1 < x1) return false; + + return false; + } + +} + +/* +* Solve x = q * y + r +*/ +void divide(const BigInt& x, const BigInt& y_arg, BigInt& q, BigInt& r) + { + if(y_arg.is_zero()) + throw BigInt::DivideByZero(); + + BigInt y = y_arg; + const size_t y_words = y.sig_words(); + + r = x; + q = 0; + + r.set_sign(BigInt::Positive); + y.set_sign(BigInt::Positive); + + int32_t compare = r.cmp(y); + + if(compare == 0) + { + q = 1; + r = 0; + } + else if(compare > 0) + { + size_t shifts = 0; + word y_top = y.word_at(y.sig_words()-1); + while(y_top < MP_WORD_TOP_BIT) { y_top <<= 1; ++shifts; } + y <<= shifts; + r <<= shifts; + + const size_t n = r.sig_words() - 1, t = y_words - 1; + + if(n < t) + throw Internal_Error("BigInt division word sizes"); + + q.grow_to(n - t + 1); + + word* q_words = q.mutable_data(); + + if(n <= t) + { + while(r > y) { r -= y; ++q; } + r >>= shifts; + sign_fixup(x, y_arg, q, r); + return; + } + + BigInt temp = y << (BOTAN_MP_WORD_BITS * (n-t)); + + while(r >= temp) { r -= temp; q_words[n-t] += 1; } + + for(size_t j = n; j != t; --j) + { + const word x_j0 = r.word_at(j); + const word x_j1 = r.word_at(j-1); + const word y_t = y.word_at(t); + + if(x_j0 == y_t) + q_words[j-t-1] = MP_WORD_MAX; + else + q_words[j-t-1] = bigint_divop(x_j0, x_j1, y_t); + + while(division_check(q_words[j-t-1], + y_t, y.word_at(t-1), + x_j0, x_j1, r.word_at(j-2))) + { + q_words[j-t-1] -= 1; + } + + r -= (q_words[j-t-1] * y) << (BOTAN_MP_WORD_BITS * (j-t-1)); + + if(r.is_negative()) + { + r += y << (BOTAN_MP_WORD_BITS * (j-t-1)); + q_words[j-t-1] -= 1; + } + } + r >>= shifts; + } + + sign_fixup(x, y_arg, q, r); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/bigint/divide.h b/src/libs/3rdparty/botan/src/lib/math/bigint/divide.h new file mode 100644 index 0000000000..03e5ff7c14 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/bigint/divide.h @@ -0,0 +1,29 @@ +/* +* Division +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DIVISON_ALGORITHM_H_ +#define BOTAN_DIVISON_ALGORITHM_H_ + +#include <botan/bigint.h> + +namespace Botan { + +/** +* BigInt Division +* @param x an integer +* @param y a non-zero integer +* @param q will be set to x / y +* @param r will be set to x % y +*/ +void BOTAN_PUBLIC_API(2,0) divide(const BigInt& x, + const BigInt& y, + BigInt& q, + BigInt& r); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/bigint/info.txt b/src/libs/3rdparty/botan/src/lib/math/bigint/info.txt new file mode 100644 index 0000000000..e84061bb6d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/bigint/info.txt @@ -0,0 +1,16 @@ +<defines> +BIGINT -> 20131128 +</defines> + +load_on auto + +<header:public> +bigint.h +divide.h +</header:public> + +<requires> +mp +hex +rng +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/math/mp/info.txt b/src/libs/3rdparty/botan/src/lib/math/mp/info.txt new file mode 100644 index 0000000000..cee4325ed8 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/mp/info.txt @@ -0,0 +1,10 @@ +<defines> +BIGINT_MP -> 20151225 +</defines> + +<header:internal> +mp_core.h +mp_madd.h +mp_asmi.h +mp_monty.h +</header:internal> diff --git a/src/libs/3rdparty/botan/src/lib/math/mp/mp_asmi.h b/src/libs/3rdparty/botan/src/lib/math/mp/mp_asmi.h new file mode 100644 index 0000000000..1b332811f8 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/mp/mp_asmi.h @@ -0,0 +1,875 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2010 Jack Lloyd +* 2006 Luca Piccarreta +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MP_ASM_INTERNAL_H_ +#define BOTAN_MP_ASM_INTERNAL_H_ + +#include <botan/internal/mp_madd.h> + +namespace Botan { + +#if defined(BOTAN_MP_USE_X86_32_ASM) + +#define ADDSUB2_OP(OPERATION, INDEX) \ + ASM("movl 4*" #INDEX "(%[y]), %[carry]") \ + ASM(OPERATION " %[carry], 4*" #INDEX "(%[x])") \ + +#define ADDSUB3_OP(OPERATION, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]), %[carry]") \ + ASM(OPERATION " 4*" #INDEX "(%[y]), %[carry]") \ + ASM("movl %[carry], 4*" #INDEX "(%[z])") \ + +#define LINMUL_OP(WRITE_TO, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]),%%eax") \ + ASM("mull %[y]") \ + ASM("addl %[carry],%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("movl %%edx,%[carry]") \ + ASM("movl %%eax, 4*" #INDEX "(%[" WRITE_TO "])") + +#define MULADD_OP(IGNORED, INDEX) \ + ASM("movl 4*" #INDEX "(%[x]),%%eax") \ + ASM("mull %[y]") \ + ASM("addl %[carry],%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("addl 4*" #INDEX "(%[z]),%%eax") \ + ASM("adcl $0,%%edx") \ + ASM("movl %%edx,%[carry]") \ + ASM("movl %%eax, 4*" #INDEX " (%[z])") + +#define ADD_OR_SUBTRACT(CORE_CODE) \ + ASM("rorl %[carry]") \ + CORE_CODE \ + ASM("sbbl %[carry],%[carry]") \ + ASM("negl %[carry]") + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + +#define ADDSUB2_OP(OPERATION, INDEX) \ + ASM("movq 8*" #INDEX "(%[y]), %[carry]") \ + ASM(OPERATION " %[carry], 8*" #INDEX "(%[x])") \ + +#define ADDSUB3_OP(OPERATION, INDEX) \ + ASM("movq 8*" #INDEX "(%[x]), %[carry]") \ + ASM(OPERATION " 8*" #INDEX "(%[y]), %[carry]") \ + ASM("movq %[carry], 8*" #INDEX "(%[z])") \ + +#define LINMUL_OP(WRITE_TO, INDEX) \ + ASM("movq 8*" #INDEX "(%[x]),%%rax") \ + ASM("mulq %[y]") \ + ASM("addq %[carry],%%rax") \ + ASM("adcq $0,%%rdx") \ + ASM("movq %%rdx,%[carry]") \ + ASM("movq %%rax, 8*" #INDEX "(%[" WRITE_TO "])") + +#define MULADD_OP(IGNORED, INDEX) \ + ASM("movq 8*" #INDEX "(%[x]),%%rax") \ + ASM("mulq %[y]") \ + ASM("addq %[carry],%%rax") \ + ASM("adcq $0,%%rdx") \ + ASM("addq 8*" #INDEX "(%[z]),%%rax") \ + ASM("adcq $0,%%rdx") \ + ASM("movq %%rdx,%[carry]") \ + ASM("movq %%rax, 8*" #INDEX " (%[z])") + +#define ADD_OR_SUBTRACT(CORE_CODE) \ + ASM("rorq %[carry]") \ + CORE_CODE \ + ASM("sbbq %[carry],%[carry]") \ + ASM("negq %[carry]") + +#endif + +#if defined(ADD_OR_SUBTRACT) + +#define ASM(x) x "\n\t" + +#define DO_8_TIMES(MACRO, ARG) \ + MACRO(ARG, 0) \ + MACRO(ARG, 1) \ + MACRO(ARG, 2) \ + MACRO(ARG, 3) \ + MACRO(ARG, 4) \ + MACRO(ARG, 5) \ + MACRO(ARG, 6) \ + MACRO(ARG, 7) + +#endif + +/* +* Word Addition +*/ +inline word word_add(word x, word y, word* carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(ASM("adcl %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(ASM("adcq %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + +#else + word z = x + y; + word c1 = (z < x); + z += *carry; + *carry = c1 | (z < *carry); + return z; +#endif + } + +/* +* Eight Word Block Addition, Two Argument +*/ +inline word word8_add2(word x[8], const word y[8], word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM) + + __asm { + mov edx,[x] + mov esi,[y] + xor eax,eax + sub eax,[carry] //force CF=1 iff *carry==1 + mov eax,[esi] + adc [edx],eax + mov eax,[esi+4] + adc [edx+4],eax + mov eax,[esi+8] + adc [edx+8],eax + mov eax,[esi+12] + adc [edx+12],eax + mov eax,[esi+16] + adc [edx+16],eax + mov eax,[esi+20] + adc [edx+20],eax + mov eax,[esi+24] + adc [edx+24],eax + mov eax,[esi+28] + adc [edx+28],eax + sbb eax,eax + neg eax + } + +#else + x[0] = word_add(x[0], y[0], &carry); + x[1] = word_add(x[1], y[1], &carry); + x[2] = word_add(x[2], y[2], &carry); + x[3] = word_add(x[3], y[3], &carry); + x[4] = word_add(x[4], y[4], &carry); + x[5] = word_add(x[5], y[5], &carry); + x[6] = word_add(x[6], y[6], &carry); + x[7] = word_add(x[7], y[7], &carry); + return carry; +#endif + } + +/* +* Eight Word Block Addition, Three Argument +*/ +inline word word8_add3(word z[8], const word x[8], + const word y[8], word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM) + + __asm { + mov edi,[x] + mov esi,[y] + mov ebx,[z] + xor eax,eax + sub eax,[carry] //force CF=1 iff *carry==1 + mov eax,[edi] + adc eax,[esi] + mov [ebx],eax + + mov eax,[edi+4] + adc eax,[esi+4] + mov [ebx+4],eax + + mov eax,[edi+8] + adc eax,[esi+8] + mov [ebx+8],eax + + mov eax,[edi+12] + adc eax,[esi+12] + mov [ebx+12],eax + + mov eax,[edi+16] + adc eax,[esi+16] + mov [ebx+16],eax + + mov eax,[edi+20] + adc eax,[esi+20] + mov [ebx+20],eax + + mov eax,[edi+24] + adc eax,[esi+24] + mov [ebx+24],eax + + mov eax,[edi+28] + adc eax,[esi+28] + mov [ebx+28],eax + + sbb eax,eax + neg eax + } + +#else + z[0] = word_add(x[0], y[0], &carry); + z[1] = word_add(x[1], y[1], &carry); + z[2] = word_add(x[2], y[2], &carry); + z[3] = word_add(x[3], y[3], &carry); + z[4] = word_add(x[4], y[4], &carry); + z[5] = word_add(x[5], y[5], &carry); + z[6] = word_add(x[6], y[6], &carry); + z[7] = word_add(x[7], y[7], &carry); + return carry; +#endif + } + +/* +* Word Subtraction +*/ +inline word word_sub(word x, word y, word* carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(ASM("sbbl %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(ASM("sbbq %[y],%[x]")) + : [x]"=r"(x), [carry]"=r"(*carry) + : "0"(x), [y]"rm"(y), "1"(*carry) + : "cc"); + return x; + +#else + word t0 = x - y; + word c1 = (t0 > x); + word z = t0 - *carry; + *carry = c1 | (z > t0); + return z; +#endif + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2(word x[8], const word y[8], word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM) + + __asm { + mov edi,[x] + mov esi,[y] + xor eax,eax + sub eax,[carry] //force CF=1 iff *carry==1 + mov eax,[edi] + sbb eax,[esi] + mov [edi],eax + mov eax,[edi+4] + sbb eax,[esi+4] + mov [edi+4],eax + mov eax,[edi+8] + sbb eax,[esi+8] + mov [edi+8],eax + mov eax,[edi+12] + sbb eax,[esi+12] + mov [edi+12],eax + mov eax,[edi+16] + sbb eax,[esi+16] + mov [edi+16],eax + mov eax,[edi+20] + sbb eax,[esi+20] + mov [edi+20],eax + mov eax,[edi+24] + sbb eax,[esi+24] + mov [edi+24],eax + mov eax,[edi+28] + sbb eax,[esi+28] + mov [edi+28],eax + sbb eax,eax + neg eax + } + +#else + x[0] = word_sub(x[0], y[0], &carry); + x[1] = word_sub(x[1], y[1], &carry); + x[2] = word_sub(x[2], y[2], &carry); + x[3] = word_sub(x[3], y[3], &carry); + x[4] = word_sub(x[4], y[4], &carry); + x[5] = word_sub(x[5], y[5], &carry); + x[6] = word_sub(x[6], y[6], &carry); + x[7] = word_sub(x[7], y[7], &carry); + return carry; +#endif + } + +/* +* Eight Word Block Subtraction, Two Argument +*/ +inline word word8_sub2_rev(word x[8], const word y[8], word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq")) + : [carry]"=r"(carry) + : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry) + : "cc", "memory"); + return carry; + +#else + x[0] = word_sub(y[0], x[0], &carry); + x[1] = word_sub(y[1], x[1], &carry); + x[2] = word_sub(y[2], x[2], &carry); + x[3] = word_sub(y[3], x[3], &carry); + x[4] = word_sub(y[4], x[4], &carry); + x[5] = word_sub(y[5], x[5], &carry); + x[6] = word_sub(y[6], x[6], &carry); + x[7] = word_sub(y[7], x[7], &carry); + return carry; +#endif + } + +/* +* Eight Word Block Subtraction, Three Argument +*/ +inline word word8_sub3(word z[8], const word x[8], + const word y[8], word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq")) + : [carry]"=r"(carry) + : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry) + : "cc", "memory"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM) + + __asm { + mov edi,[x] + mov esi,[y] + xor eax,eax + sub eax,[carry] //force CF=1 iff *carry==1 + mov ebx,[z] + mov eax,[edi] + sbb eax,[esi] + mov [ebx],eax + mov eax,[edi+4] + sbb eax,[esi+4] + mov [ebx+4],eax + mov eax,[edi+8] + sbb eax,[esi+8] + mov [ebx+8],eax + mov eax,[edi+12] + sbb eax,[esi+12] + mov [ebx+12],eax + mov eax,[edi+16] + sbb eax,[esi+16] + mov [ebx+16],eax + mov eax,[edi+20] + sbb eax,[esi+20] + mov [ebx+20],eax + mov eax,[edi+24] + sbb eax,[esi+24] + mov [ebx+24],eax + mov eax,[edi+28] + sbb eax,[esi+28] + mov [ebx+28],eax + sbb eax,eax + neg eax + } + +#else + z[0] = word_sub(x[0], y[0], &carry); + z[1] = word_sub(x[1], y[1], &carry); + z[2] = word_sub(x[2], y[2], &carry); + z[3] = word_sub(x[3], y[3], &carry); + z[4] = word_sub(x[4], y[4], &carry); + z[5] = word_sub(x[5], y[5], &carry); + z[6] = word_sub(x[6], y[6], &carry); + z[7] = word_sub(x[7], y[7], &carry); + return carry; +#endif + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul2(word x[8], word y, word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + DO_8_TIMES(LINMUL_OP, "x") + : [carry]"=r"(carry) + : [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + DO_8_TIMES(LINMUL_OP, "x") + : [carry]"=r"(carry) + : [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%rax", "%rdx"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM) + + __asm { + mov esi,[x] + mov eax,[esi] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,[carry] //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi],eax //load a + + mov eax,[esi+4] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+4],eax //load a + + mov eax,[esi+8] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+8],eax //load a + + mov eax,[esi+12] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+12],eax //load a + + mov eax,[esi+16] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+16],eax //load a + + mov eax,[esi+20] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+20],eax //load a + + mov eax,[esi+24] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [esi+24],eax //load a + + mov eax,[esi+28] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov [esi+28],eax //load a + + mov eax,edx //store carry + } + +#else + x[0] = word_madd2(x[0], y, &carry); + x[1] = word_madd2(x[1], y, &carry); + x[2] = word_madd2(x[2], y, &carry); + x[3] = word_madd2(x[3], y, &carry); + x[4] = word_madd2(x[4], y, &carry); + x[5] = word_madd2(x[5], y, &carry); + x[6] = word_madd2(x[6], y, &carry); + x[7] = word_madd2(x[7], y, &carry); + return carry; +#endif + } + +/* +* Eight Word Block Linear Multiplication +*/ +inline word word8_linmul3(word z[8], const word x[8], word y, word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + DO_8_TIMES(LINMUL_OP, "z") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + asm( + DO_8_TIMES(LINMUL_OP, "z") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%rax", "%rdx"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM) + + __asm { + mov edi,[z] + mov esi,[x] + mov eax,[esi] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,[carry] //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi],eax //load a + + mov eax,[esi+4] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+4],eax //load a + + mov eax,[esi+8] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+8],eax //load a + + mov eax,[esi+12] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+12],eax //load a + + mov eax,[esi+16] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+16],eax //load a + + mov eax,[esi+20] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+20],eax //load a + + mov eax,[esi+24] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov ecx,edx //store carry + mov [edi+24],eax //load a + + mov eax,[esi+28] //load a + mul [y] //edx(hi):eax(lo)=a*b + add eax,ecx //sum lo carry + adc edx,0 //sum hi carry + mov [edi+28],eax //load a + mov eax,edx //store carry + } + +#else + z[0] = word_madd2(x[0], y, &carry); + z[1] = word_madd2(x[1], y, &carry); + z[2] = word_madd2(x[2], y, &carry); + z[3] = word_madd2(x[3], y, &carry); + z[4] = word_madd2(x[4], y, &carry); + z[5] = word_madd2(x[5], y, &carry); + z[6] = word_madd2(x[6], y, &carry); + z[7] = word_madd2(x[7], y, &carry); + return carry; +#endif + } + +/* +* Eight Word Block Multiply/Add +*/ +inline word word8_madd3(word z[8], const word x[8], word y, word carry) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + DO_8_TIMES(MULADD_OP, "") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%eax", "%edx"); + return carry; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + DO_8_TIMES(MULADD_OP, "") + : [carry]"=r"(carry) + : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry) + : "cc", "%rax", "%rdx"); + return carry; + +#else + z[0] = word_madd3(x[0], y, z[0], &carry); + z[1] = word_madd3(x[1], y, z[1], &carry); + z[2] = word_madd3(x[2], y, z[2], &carry); + z[3] = word_madd3(x[3], y, z[3], &carry); + z[4] = word_madd3(x[4], y, z[4], &carry); + z[5] = word_madd3(x[5], y, z[5], &carry); + z[6] = word_madd3(x[6], y, z[6], &carry); + z[7] = word_madd3(x[7], y, z[7], &carry); + return carry; +#endif + } + +/* +* Multiply-Add Accumulator +* (w2,w1,w0) += x * y +*/ +inline void word3_muladd(word* w2, word* w1, word* w0, word x, word y) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + word z0 = 0, z1 = 0; + + asm ("mull %[y]" + : "=a"(z0),"=d"(z1) + : "a"(x), [y]"rm"(y) + : "cc"); + + asm(ASM("addl %[z0],%[w0]") + ASM("adcl %[z1],%[w1]") + ASM("adcl $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + word z0 = 0, z1 = 0; + + asm ("mulq %[y]" + : "=a"(z0),"=d"(z1) + : "a"(x), [y]"rm"(y) + : "cc"); + + asm(ASM("addq %[z0],%[w0]") + ASM("adcq %[z1],%[w1]") + ASM("adcq $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#else + word carry = *w0; + *w0 = word_madd2(x, y, &carry); + *w1 += carry; + *w2 += (*w1 < carry); +#endif + } + +/* +* 3-word addition +* (w2,w1,w0) += x +*/ +inline void word3_add(word* w2, word* w1, word* w0, word x) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ASM("addl %[x],%[w0]") + ASM("adcl $0,%[w1]") + ASM("adcl $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [x]"r"(x), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + asm( + ASM("addq %[x],%[w0]") + ASM("adcq $0,%[w1]") + ASM("adcq $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [x]"r"(x), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#else + *w0 += x; + word c1 = (*w0 < x); + *w1 += c1; + word c2 = (*w1 < c1); + *w2 += c2; +#endif + } + +/* +* Multiply-Add Accumulator +* (w2,w1,w0) += 2 * x * y +*/ +inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + + word z0 = 0, z1 = 0; + + asm ("mull %[y]" + : "=a"(z0),"=d"(z1) + : "a"(x), [y]"rm"(y) + : "cc"); + + asm( + ASM("addl %[z0],%[w0]") + ASM("adcl %[z1],%[w1]") + ASM("adcl $0,%[w2]") + + ASM("addl %[z0],%[w0]") + ASM("adcl %[z1],%[w1]") + ASM("adcl $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + + word z0 = 0, z1 = 0; + + asm ("mulq %[y]" + : "=a"(z0),"=d"(z1) + : "a"(x), [y]"rm"(y) + : "cc"); + + asm( + ASM("addq %[z0],%[w0]") + ASM("adcq %[z1],%[w1]") + ASM("adcq $0,%[w2]") + + ASM("addq %[z0],%[w0]") + ASM("adcq %[z1],%[w1]") + ASM("adcq $0,%[w2]") + + : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2) + : [z0]"r"(z0), [z1]"r"(z1), "0"(*w0), "1"(*w1), "2"(*w2) + : "cc"); + +#else + word carry = 0; + x = word_madd2(x, y, &carry); + y = carry; + + word top = (y >> (BOTAN_MP_WORD_BITS-1)); + y <<= 1; + y |= (x >> (BOTAN_MP_WORD_BITS-1)); + x <<= 1; + + carry = 0; + *w0 = word_add(*w0, x, &carry); + *w1 = word_add(*w1, y, &carry); + *w2 = word_add(*w2, top, &carry); +#endif + } + +#if defined(ASM) + #undef ASM + #undef DO_8_TIMES + #undef ADD_OR_SUBTRACT + #undef ADDSUB2_OP + #undef ADDSUB3_OP + #undef LINMUL_OP + #undef MULADD_OP +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/mp/mp_comba.cpp b/src/libs/3rdparty/botan/src/lib/math/mp/mp_comba.cpp new file mode 100644 index 0000000000..ec527224c8 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/mp/mp_comba.cpp @@ -0,0 +1,2211 @@ +/* +* Comba Multiplication and Squaring +* +* This file was automatically generated by ./src/scripts/comba.py on 2018-05-08 +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/mp_core.h> +#include <botan/internal/mp_asmi.h> + +namespace Botan { + +/* +* Comba 4x4 Squaring +*/ +void bigint_comba_sqr4(word z[8], const word x[4]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; + z[ 7] = w1; + } + +/* +* Comba 4x4 Multiplication +*/ +void bigint_comba_mul4(word z[8], const word x[4], const word y[4]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + z[ 6] = w0; + z[ 7] = w1; + } + +/* +* Comba 6x6 Squaring +*/ +void bigint_comba_sqr6(word z[12], const word x[6]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; + z[11] = w2; + } + +/* +* Comba 6x6 Multiplication +*/ +void bigint_comba_mul6(word z[12], const word x[6], const word y[6]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + z[10] = w1; + z[11] = w2; + } + +/* +* Comba 8x8 Squaring +*/ +void bigint_comba_sqr8(word z[16], const word x[8]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; + z[15] = w0; + } + +/* +* Comba 8x8 Multiplication +*/ +void bigint_comba_mul8(word z[16], const word x[8], const word y[8]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + z[14] = w2; + z[15] = w0; + } + +/* +* Comba 9x9 Squaring +*/ +void bigint_comba_sqr9(word z[18], const word x[9]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); + word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); + z[15] = w0; w0 = 0; + + word3_muladd (&w0, &w2, &w1, x[ 8], x[ 8]); + z[16] = w1; + z[17] = w2; + } + +/* +* Comba 9x9 Multiplication +*/ +void bigint_comba_mul9(word z[18], const word x[9], const word y[9]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); + z[14] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); + z[15] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); + z[16] = w1; + z[17] = w2; + } + +/* +* Comba 16x16 Squaring +*/ +void bigint_comba_sqr16(word z[32], const word x[16]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); + word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); + z[15] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[ 9]); + word3_muladd (&w0, &w2, &w1, x[ 8], x[ 8]); + z[16] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[ 9]); + z[17] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[10]); + word3_muladd (&w2, &w1, &w0, x[ 9], x[ 9]); + z[18] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[10]); + z[19] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[11]); + word3_muladd (&w1, &w0, &w2, x[10], x[10]); + z[20] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[11]); + z[21] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[12]); + word3_muladd (&w0, &w2, &w1, x[11], x[11]); + z[22] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[12]); + z[23] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[13]); + word3_muladd (&w2, &w1, &w0, x[12], x[12]); + z[24] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[10], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[11], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[13]); + z[25] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[11], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[12], x[14]); + word3_muladd (&w1, &w0, &w2, x[13], x[13]); + z[26] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[12], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[13], x[14]); + z[27] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[13], x[15]); + word3_muladd (&w0, &w2, &w1, x[14], x[14]); + z[28] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[14], x[15]); + z[29] = w2; w2 = 0; + + word3_muladd (&w2, &w1, &w0, x[15], x[15]); + z[30] = w0; + z[31] = w1; + } + +/* +* Comba 16x16 Multiplication +*/ +void bigint_comba_mul16(word z[32], const word x[16], const word y[16]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 0]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 0]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 0]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 0]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 0]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 0]); + z[14] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 0]); + z[15] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 1], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 1]); + z[16] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 2], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 2]); + z[17] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 3], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 3]); + z[18] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 4], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[10]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 4]); + z[19] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 5], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[11]); + word3_muladd(&w1, &w0, &w2, x[10], y[10]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 5]); + z[20] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 6], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[12]); + word3_muladd(&w2, &w1, &w0, x[10], y[11]); + word3_muladd(&w2, &w1, &w0, x[11], y[10]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 6]); + z[21] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 7], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[13]); + word3_muladd(&w0, &w2, &w1, x[10], y[12]); + word3_muladd(&w0, &w2, &w1, x[11], y[11]); + word3_muladd(&w0, &w2, &w1, x[12], y[10]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 7]); + z[22] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 8], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[14]); + word3_muladd(&w1, &w0, &w2, x[10], y[13]); + word3_muladd(&w1, &w0, &w2, x[11], y[12]); + word3_muladd(&w1, &w0, &w2, x[12], y[11]); + word3_muladd(&w1, &w0, &w2, x[13], y[10]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 8]); + z[23] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 9], y[15]); + word3_muladd(&w2, &w1, &w0, x[10], y[14]); + word3_muladd(&w2, &w1, &w0, x[11], y[13]); + word3_muladd(&w2, &w1, &w0, x[12], y[12]); + word3_muladd(&w2, &w1, &w0, x[13], y[11]); + word3_muladd(&w2, &w1, &w0, x[14], y[10]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 9]); + z[24] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[10], y[15]); + word3_muladd(&w0, &w2, &w1, x[11], y[14]); + word3_muladd(&w0, &w2, &w1, x[12], y[13]); + word3_muladd(&w0, &w2, &w1, x[13], y[12]); + word3_muladd(&w0, &w2, &w1, x[14], y[11]); + word3_muladd(&w0, &w2, &w1, x[15], y[10]); + z[25] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[11], y[15]); + word3_muladd(&w1, &w0, &w2, x[12], y[14]); + word3_muladd(&w1, &w0, &w2, x[13], y[13]); + word3_muladd(&w1, &w0, &w2, x[14], y[12]); + word3_muladd(&w1, &w0, &w2, x[15], y[11]); + z[26] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[12], y[15]); + word3_muladd(&w2, &w1, &w0, x[13], y[14]); + word3_muladd(&w2, &w1, &w0, x[14], y[13]); + word3_muladd(&w2, &w1, &w0, x[15], y[12]); + z[27] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[13], y[15]); + word3_muladd(&w0, &w2, &w1, x[14], y[14]); + word3_muladd(&w0, &w2, &w1, x[15], y[13]); + z[28] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[14], y[15]); + word3_muladd(&w1, &w0, &w2, x[15], y[14]); + z[29] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[15], y[15]); + z[30] = w0; + z[31] = w1; + } + +/* +* Comba 24x24 Squaring +*/ +void bigint_comba_sqr24(word z[48], const word x[24]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd (&w2, &w1, &w0, x[ 0], x[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 1]); + z[ 1] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 2]); + word3_muladd (&w1, &w0, &w2, x[ 1], x[ 1]); + z[ 2] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 3]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 2]); + z[ 3] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 4]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 3]); + word3_muladd (&w0, &w2, &w1, x[ 2], x[ 2]); + z[ 4] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 5]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 4]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 3]); + z[ 5] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 5]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 4]); + word3_muladd (&w2, &w1, &w0, x[ 3], x[ 3]); + z[ 6] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 6]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 5]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 4]); + z[ 7] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 6]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 5]); + word3_muladd (&w1, &w0, &w2, x[ 4], x[ 4]); + z[ 8] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[ 7]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 6]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 5]); + z[ 9] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[ 7]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 6]); + word3_muladd (&w0, &w2, &w1, x[ 5], x[ 5]); + z[10] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[ 8]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[ 7]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 6]); + z[11] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[ 8]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[ 7]); + word3_muladd (&w2, &w1, &w0, x[ 6], x[ 6]); + z[12] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[ 9]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[ 8]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[ 7]); + z[13] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[ 9]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[ 8]); + word3_muladd (&w1, &w0, &w2, x[ 7], x[ 7]); + z[14] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[10]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[ 9]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[ 8]); + z[15] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[16]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[10]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[ 9]); + word3_muladd (&w0, &w2, &w1, x[ 8], x[ 8]); + z[16] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[17]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[16]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[11]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[10]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[ 9]); + z[17] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[17]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[16]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[11]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[10]); + word3_muladd (&w2, &w1, &w0, x[ 9], x[ 9]); + z[18] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[18]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[17]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[16]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[12]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[11]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[10]); + z[19] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[18]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[17]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[16]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[12]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[11]); + word3_muladd (&w1, &w0, &w2, x[10], x[10]); + z[20] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 0], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[19]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[17]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[16]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[13]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[12]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[11]); + z[21] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 0], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[ 1], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[18]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[17]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[16]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[13]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[12]); + word3_muladd (&w0, &w2, &w1, x[11], x[11]); + z[22] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 0], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[ 1], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[ 2], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[18]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[17]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[16]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[14]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[13]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[12]); + z[23] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 1], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[ 2], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[ 3], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[19]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[17]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[16]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[14]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[13]); + word3_muladd (&w2, &w1, &w0, x[12], x[12]); + z[24] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 2], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[ 3], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[ 4], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[18]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[17]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[16]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[15]); + word3_muladd_2(&w0, &w2, &w1, x[11], x[14]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[13]); + z[25] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 3], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[ 4], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[ 5], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[18]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[17]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[16]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[15]); + word3_muladd_2(&w1, &w0, &w2, x[12], x[14]); + word3_muladd (&w1, &w0, &w2, x[13], x[13]); + z[26] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 4], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[ 5], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[ 6], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[19]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[17]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[16]); + word3_muladd_2(&w2, &w1, &w0, x[12], x[15]); + word3_muladd_2(&w2, &w1, &w0, x[13], x[14]); + z[27] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 5], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[ 6], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[ 7], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[18]); + word3_muladd_2(&w0, &w2, &w1, x[11], x[17]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[16]); + word3_muladd_2(&w0, &w2, &w1, x[13], x[15]); + word3_muladd (&w0, &w2, &w1, x[14], x[14]); + z[28] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 6], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[ 7], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[ 8], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[18]); + word3_muladd_2(&w1, &w0, &w2, x[12], x[17]); + word3_muladd_2(&w1, &w0, &w2, x[13], x[16]); + word3_muladd_2(&w1, &w0, &w2, x[14], x[15]); + z[29] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[ 7], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[ 8], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[ 9], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[10], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[19]); + word3_muladd_2(&w2, &w1, &w0, x[12], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[13], x[17]); + word3_muladd_2(&w2, &w1, &w0, x[14], x[16]); + word3_muladd (&w2, &w1, &w0, x[15], x[15]); + z[30] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[ 8], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[ 9], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[10], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[11], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[13], x[18]); + word3_muladd_2(&w0, &w2, &w1, x[14], x[17]); + word3_muladd_2(&w0, &w2, &w1, x[15], x[16]); + z[31] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[ 9], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[10], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[11], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[12], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[13], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[14], x[18]); + word3_muladd_2(&w1, &w0, &w2, x[15], x[17]); + word3_muladd (&w1, &w0, &w2, x[16], x[16]); + z[32] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[10], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[11], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[12], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[13], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[14], x[19]); + word3_muladd_2(&w2, &w1, &w0, x[15], x[18]); + word3_muladd_2(&w2, &w1, &w0, x[16], x[17]); + z[33] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[11], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[12], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[13], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[14], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[15], x[19]); + word3_muladd_2(&w0, &w2, &w1, x[16], x[18]); + word3_muladd (&w0, &w2, &w1, x[17], x[17]); + z[34] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[12], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[13], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[14], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[15], x[20]); + word3_muladd_2(&w1, &w0, &w2, x[16], x[19]); + word3_muladd_2(&w1, &w0, &w2, x[17], x[18]); + z[35] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[13], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[14], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[15], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[16], x[20]); + word3_muladd_2(&w2, &w1, &w0, x[17], x[19]); + word3_muladd (&w2, &w1, &w0, x[18], x[18]); + z[36] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[14], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[15], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[16], x[21]); + word3_muladd_2(&w0, &w2, &w1, x[17], x[20]); + word3_muladd_2(&w0, &w2, &w1, x[18], x[19]); + z[37] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[15], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[16], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[17], x[21]); + word3_muladd_2(&w1, &w0, &w2, x[18], x[20]); + word3_muladd (&w1, &w0, &w2, x[19], x[19]); + z[38] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[16], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[17], x[22]); + word3_muladd_2(&w2, &w1, &w0, x[18], x[21]); + word3_muladd_2(&w2, &w1, &w0, x[19], x[20]); + z[39] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[17], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[18], x[22]); + word3_muladd_2(&w0, &w2, &w1, x[19], x[21]); + word3_muladd (&w0, &w2, &w1, x[20], x[20]); + z[40] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[18], x[23]); + word3_muladd_2(&w1, &w0, &w2, x[19], x[22]); + word3_muladd_2(&w1, &w0, &w2, x[20], x[21]); + z[41] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[19], x[23]); + word3_muladd_2(&w2, &w1, &w0, x[20], x[22]); + word3_muladd (&w2, &w1, &w0, x[21], x[21]); + z[42] = w0; w0 = 0; + + word3_muladd_2(&w0, &w2, &w1, x[20], x[23]); + word3_muladd_2(&w0, &w2, &w1, x[21], x[22]); + z[43] = w1; w1 = 0; + + word3_muladd_2(&w1, &w0, &w2, x[21], x[23]); + word3_muladd (&w1, &w0, &w2, x[22], x[22]); + z[44] = w2; w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[22], x[23]); + z[45] = w0; w0 = 0; + + word3_muladd (&w0, &w2, &w1, x[23], x[23]); + z[46] = w1; + z[47] = w2; + } + +/* +* Comba 24x24 Multiplication +*/ +void bigint_comba_mul24(word z[48], const word x[24], const word y[24]) + { + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 0]); + z[ 0] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 0]); + z[ 1] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 0]); + z[ 2] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 0]); + z[ 3] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 0]); + z[ 4] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 0]); + z[ 5] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 0]); + z[ 6] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 0]); + z[ 7] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 0]); + z[ 8] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 0]); + z[ 9] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 0]); + z[10] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 0]); + z[11] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 0]); + z[12] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 0]); + z[13] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 0]); + z[14] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 0]); + z[15] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[16]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[10]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[16], y[ 0]); + z[16] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[17]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[16]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[11]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[10]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[10], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[16], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[17], y[ 0]); + z[17] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[18]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[17]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[16]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[12]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[11]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[10]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[10], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[11], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[16], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[17], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[18], y[ 0]); + z[18] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[19]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[18]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[17]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[16]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[13]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[12]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[11]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[10]); + word3_muladd(&w0, &w2, &w1, x[10], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[11], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[12], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[16], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[17], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[18], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[19], y[ 0]); + z[19] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[20]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[19]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[18]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[17]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[16]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[14]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[13]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[12]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[11]); + word3_muladd(&w1, &w0, &w2, x[10], y[10]); + word3_muladd(&w1, &w0, &w2, x[11], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[12], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[13], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[16], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[17], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[18], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[19], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[20], y[ 0]); + z[20] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 0], y[21]); + word3_muladd(&w2, &w1, &w0, x[ 1], y[20]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[19]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[18]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[17]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[16]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[15]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[14]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[13]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[12]); + word3_muladd(&w2, &w1, &w0, x[10], y[11]); + word3_muladd(&w2, &w1, &w0, x[11], y[10]); + word3_muladd(&w2, &w1, &w0, x[12], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[13], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[14], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[16], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[17], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[18], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[19], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[20], y[ 1]); + word3_muladd(&w2, &w1, &w0, x[21], y[ 0]); + z[21] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 0], y[22]); + word3_muladd(&w0, &w2, &w1, x[ 1], y[21]); + word3_muladd(&w0, &w2, &w1, x[ 2], y[20]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[19]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[18]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[17]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[16]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[15]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[14]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[13]); + word3_muladd(&w0, &w2, &w1, x[10], y[12]); + word3_muladd(&w0, &w2, &w1, x[11], y[11]); + word3_muladd(&w0, &w2, &w1, x[12], y[10]); + word3_muladd(&w0, &w2, &w1, x[13], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[14], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[15], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[16], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[17], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[18], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[19], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[20], y[ 2]); + word3_muladd(&w0, &w2, &w1, x[21], y[ 1]); + word3_muladd(&w0, &w2, &w1, x[22], y[ 0]); + z[22] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 0], y[23]); + word3_muladd(&w1, &w0, &w2, x[ 1], y[22]); + word3_muladd(&w1, &w0, &w2, x[ 2], y[21]); + word3_muladd(&w1, &w0, &w2, x[ 3], y[20]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[19]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[18]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[17]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[16]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[15]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[14]); + word3_muladd(&w1, &w0, &w2, x[10], y[13]); + word3_muladd(&w1, &w0, &w2, x[11], y[12]); + word3_muladd(&w1, &w0, &w2, x[12], y[11]); + word3_muladd(&w1, &w0, &w2, x[13], y[10]); + word3_muladd(&w1, &w0, &w2, x[14], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[15], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[16], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[17], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[18], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[19], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[20], y[ 3]); + word3_muladd(&w1, &w0, &w2, x[21], y[ 2]); + word3_muladd(&w1, &w0, &w2, x[22], y[ 1]); + word3_muladd(&w1, &w0, &w2, x[23], y[ 0]); + z[23] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 1], y[23]); + word3_muladd(&w2, &w1, &w0, x[ 2], y[22]); + word3_muladd(&w2, &w1, &w0, x[ 3], y[21]); + word3_muladd(&w2, &w1, &w0, x[ 4], y[20]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[19]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[18]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[17]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[16]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[15]); + word3_muladd(&w2, &w1, &w0, x[10], y[14]); + word3_muladd(&w2, &w1, &w0, x[11], y[13]); + word3_muladd(&w2, &w1, &w0, x[12], y[12]); + word3_muladd(&w2, &w1, &w0, x[13], y[11]); + word3_muladd(&w2, &w1, &w0, x[14], y[10]); + word3_muladd(&w2, &w1, &w0, x[15], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[16], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[17], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[18], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[19], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[20], y[ 4]); + word3_muladd(&w2, &w1, &w0, x[21], y[ 3]); + word3_muladd(&w2, &w1, &w0, x[22], y[ 2]); + word3_muladd(&w2, &w1, &w0, x[23], y[ 1]); + z[24] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 2], y[23]); + word3_muladd(&w0, &w2, &w1, x[ 3], y[22]); + word3_muladd(&w0, &w2, &w1, x[ 4], y[21]); + word3_muladd(&w0, &w2, &w1, x[ 5], y[20]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[19]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[18]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[17]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[16]); + word3_muladd(&w0, &w2, &w1, x[10], y[15]); + word3_muladd(&w0, &w2, &w1, x[11], y[14]); + word3_muladd(&w0, &w2, &w1, x[12], y[13]); + word3_muladd(&w0, &w2, &w1, x[13], y[12]); + word3_muladd(&w0, &w2, &w1, x[14], y[11]); + word3_muladd(&w0, &w2, &w1, x[15], y[10]); + word3_muladd(&w0, &w2, &w1, x[16], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[17], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[18], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[19], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[20], y[ 5]); + word3_muladd(&w0, &w2, &w1, x[21], y[ 4]); + word3_muladd(&w0, &w2, &w1, x[22], y[ 3]); + word3_muladd(&w0, &w2, &w1, x[23], y[ 2]); + z[25] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 3], y[23]); + word3_muladd(&w1, &w0, &w2, x[ 4], y[22]); + word3_muladd(&w1, &w0, &w2, x[ 5], y[21]); + word3_muladd(&w1, &w0, &w2, x[ 6], y[20]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[19]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[18]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[17]); + word3_muladd(&w1, &w0, &w2, x[10], y[16]); + word3_muladd(&w1, &w0, &w2, x[11], y[15]); + word3_muladd(&w1, &w0, &w2, x[12], y[14]); + word3_muladd(&w1, &w0, &w2, x[13], y[13]); + word3_muladd(&w1, &w0, &w2, x[14], y[12]); + word3_muladd(&w1, &w0, &w2, x[15], y[11]); + word3_muladd(&w1, &w0, &w2, x[16], y[10]); + word3_muladd(&w1, &w0, &w2, x[17], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[18], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[19], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[20], y[ 6]); + word3_muladd(&w1, &w0, &w2, x[21], y[ 5]); + word3_muladd(&w1, &w0, &w2, x[22], y[ 4]); + word3_muladd(&w1, &w0, &w2, x[23], y[ 3]); + z[26] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 4], y[23]); + word3_muladd(&w2, &w1, &w0, x[ 5], y[22]); + word3_muladd(&w2, &w1, &w0, x[ 6], y[21]); + word3_muladd(&w2, &w1, &w0, x[ 7], y[20]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[19]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[18]); + word3_muladd(&w2, &w1, &w0, x[10], y[17]); + word3_muladd(&w2, &w1, &w0, x[11], y[16]); + word3_muladd(&w2, &w1, &w0, x[12], y[15]); + word3_muladd(&w2, &w1, &w0, x[13], y[14]); + word3_muladd(&w2, &w1, &w0, x[14], y[13]); + word3_muladd(&w2, &w1, &w0, x[15], y[12]); + word3_muladd(&w2, &w1, &w0, x[16], y[11]); + word3_muladd(&w2, &w1, &w0, x[17], y[10]); + word3_muladd(&w2, &w1, &w0, x[18], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[19], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[20], y[ 7]); + word3_muladd(&w2, &w1, &w0, x[21], y[ 6]); + word3_muladd(&w2, &w1, &w0, x[22], y[ 5]); + word3_muladd(&w2, &w1, &w0, x[23], y[ 4]); + z[27] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 5], y[23]); + word3_muladd(&w0, &w2, &w1, x[ 6], y[22]); + word3_muladd(&w0, &w2, &w1, x[ 7], y[21]); + word3_muladd(&w0, &w2, &w1, x[ 8], y[20]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[19]); + word3_muladd(&w0, &w2, &w1, x[10], y[18]); + word3_muladd(&w0, &w2, &w1, x[11], y[17]); + word3_muladd(&w0, &w2, &w1, x[12], y[16]); + word3_muladd(&w0, &w2, &w1, x[13], y[15]); + word3_muladd(&w0, &w2, &w1, x[14], y[14]); + word3_muladd(&w0, &w2, &w1, x[15], y[13]); + word3_muladd(&w0, &w2, &w1, x[16], y[12]); + word3_muladd(&w0, &w2, &w1, x[17], y[11]); + word3_muladd(&w0, &w2, &w1, x[18], y[10]); + word3_muladd(&w0, &w2, &w1, x[19], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[20], y[ 8]); + word3_muladd(&w0, &w2, &w1, x[21], y[ 7]); + word3_muladd(&w0, &w2, &w1, x[22], y[ 6]); + word3_muladd(&w0, &w2, &w1, x[23], y[ 5]); + z[28] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 6], y[23]); + word3_muladd(&w1, &w0, &w2, x[ 7], y[22]); + word3_muladd(&w1, &w0, &w2, x[ 8], y[21]); + word3_muladd(&w1, &w0, &w2, x[ 9], y[20]); + word3_muladd(&w1, &w0, &w2, x[10], y[19]); + word3_muladd(&w1, &w0, &w2, x[11], y[18]); + word3_muladd(&w1, &w0, &w2, x[12], y[17]); + word3_muladd(&w1, &w0, &w2, x[13], y[16]); + word3_muladd(&w1, &w0, &w2, x[14], y[15]); + word3_muladd(&w1, &w0, &w2, x[15], y[14]); + word3_muladd(&w1, &w0, &w2, x[16], y[13]); + word3_muladd(&w1, &w0, &w2, x[17], y[12]); + word3_muladd(&w1, &w0, &w2, x[18], y[11]); + word3_muladd(&w1, &w0, &w2, x[19], y[10]); + word3_muladd(&w1, &w0, &w2, x[20], y[ 9]); + word3_muladd(&w1, &w0, &w2, x[21], y[ 8]); + word3_muladd(&w1, &w0, &w2, x[22], y[ 7]); + word3_muladd(&w1, &w0, &w2, x[23], y[ 6]); + z[29] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[ 7], y[23]); + word3_muladd(&w2, &w1, &w0, x[ 8], y[22]); + word3_muladd(&w2, &w1, &w0, x[ 9], y[21]); + word3_muladd(&w2, &w1, &w0, x[10], y[20]); + word3_muladd(&w2, &w1, &w0, x[11], y[19]); + word3_muladd(&w2, &w1, &w0, x[12], y[18]); + word3_muladd(&w2, &w1, &w0, x[13], y[17]); + word3_muladd(&w2, &w1, &w0, x[14], y[16]); + word3_muladd(&w2, &w1, &w0, x[15], y[15]); + word3_muladd(&w2, &w1, &w0, x[16], y[14]); + word3_muladd(&w2, &w1, &w0, x[17], y[13]); + word3_muladd(&w2, &w1, &w0, x[18], y[12]); + word3_muladd(&w2, &w1, &w0, x[19], y[11]); + word3_muladd(&w2, &w1, &w0, x[20], y[10]); + word3_muladd(&w2, &w1, &w0, x[21], y[ 9]); + word3_muladd(&w2, &w1, &w0, x[22], y[ 8]); + word3_muladd(&w2, &w1, &w0, x[23], y[ 7]); + z[30] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[ 8], y[23]); + word3_muladd(&w0, &w2, &w1, x[ 9], y[22]); + word3_muladd(&w0, &w2, &w1, x[10], y[21]); + word3_muladd(&w0, &w2, &w1, x[11], y[20]); + word3_muladd(&w0, &w2, &w1, x[12], y[19]); + word3_muladd(&w0, &w2, &w1, x[13], y[18]); + word3_muladd(&w0, &w2, &w1, x[14], y[17]); + word3_muladd(&w0, &w2, &w1, x[15], y[16]); + word3_muladd(&w0, &w2, &w1, x[16], y[15]); + word3_muladd(&w0, &w2, &w1, x[17], y[14]); + word3_muladd(&w0, &w2, &w1, x[18], y[13]); + word3_muladd(&w0, &w2, &w1, x[19], y[12]); + word3_muladd(&w0, &w2, &w1, x[20], y[11]); + word3_muladd(&w0, &w2, &w1, x[21], y[10]); + word3_muladd(&w0, &w2, &w1, x[22], y[ 9]); + word3_muladd(&w0, &w2, &w1, x[23], y[ 8]); + z[31] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[ 9], y[23]); + word3_muladd(&w1, &w0, &w2, x[10], y[22]); + word3_muladd(&w1, &w0, &w2, x[11], y[21]); + word3_muladd(&w1, &w0, &w2, x[12], y[20]); + word3_muladd(&w1, &w0, &w2, x[13], y[19]); + word3_muladd(&w1, &w0, &w2, x[14], y[18]); + word3_muladd(&w1, &w0, &w2, x[15], y[17]); + word3_muladd(&w1, &w0, &w2, x[16], y[16]); + word3_muladd(&w1, &w0, &w2, x[17], y[15]); + word3_muladd(&w1, &w0, &w2, x[18], y[14]); + word3_muladd(&w1, &w0, &w2, x[19], y[13]); + word3_muladd(&w1, &w0, &w2, x[20], y[12]); + word3_muladd(&w1, &w0, &w2, x[21], y[11]); + word3_muladd(&w1, &w0, &w2, x[22], y[10]); + word3_muladd(&w1, &w0, &w2, x[23], y[ 9]); + z[32] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[10], y[23]); + word3_muladd(&w2, &w1, &w0, x[11], y[22]); + word3_muladd(&w2, &w1, &w0, x[12], y[21]); + word3_muladd(&w2, &w1, &w0, x[13], y[20]); + word3_muladd(&w2, &w1, &w0, x[14], y[19]); + word3_muladd(&w2, &w1, &w0, x[15], y[18]); + word3_muladd(&w2, &w1, &w0, x[16], y[17]); + word3_muladd(&w2, &w1, &w0, x[17], y[16]); + word3_muladd(&w2, &w1, &w0, x[18], y[15]); + word3_muladd(&w2, &w1, &w0, x[19], y[14]); + word3_muladd(&w2, &w1, &w0, x[20], y[13]); + word3_muladd(&w2, &w1, &w0, x[21], y[12]); + word3_muladd(&w2, &w1, &w0, x[22], y[11]); + word3_muladd(&w2, &w1, &w0, x[23], y[10]); + z[33] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[11], y[23]); + word3_muladd(&w0, &w2, &w1, x[12], y[22]); + word3_muladd(&w0, &w2, &w1, x[13], y[21]); + word3_muladd(&w0, &w2, &w1, x[14], y[20]); + word3_muladd(&w0, &w2, &w1, x[15], y[19]); + word3_muladd(&w0, &w2, &w1, x[16], y[18]); + word3_muladd(&w0, &w2, &w1, x[17], y[17]); + word3_muladd(&w0, &w2, &w1, x[18], y[16]); + word3_muladd(&w0, &w2, &w1, x[19], y[15]); + word3_muladd(&w0, &w2, &w1, x[20], y[14]); + word3_muladd(&w0, &w2, &w1, x[21], y[13]); + word3_muladd(&w0, &w2, &w1, x[22], y[12]); + word3_muladd(&w0, &w2, &w1, x[23], y[11]); + z[34] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[12], y[23]); + word3_muladd(&w1, &w0, &w2, x[13], y[22]); + word3_muladd(&w1, &w0, &w2, x[14], y[21]); + word3_muladd(&w1, &w0, &w2, x[15], y[20]); + word3_muladd(&w1, &w0, &w2, x[16], y[19]); + word3_muladd(&w1, &w0, &w2, x[17], y[18]); + word3_muladd(&w1, &w0, &w2, x[18], y[17]); + word3_muladd(&w1, &w0, &w2, x[19], y[16]); + word3_muladd(&w1, &w0, &w2, x[20], y[15]); + word3_muladd(&w1, &w0, &w2, x[21], y[14]); + word3_muladd(&w1, &w0, &w2, x[22], y[13]); + word3_muladd(&w1, &w0, &w2, x[23], y[12]); + z[35] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[13], y[23]); + word3_muladd(&w2, &w1, &w0, x[14], y[22]); + word3_muladd(&w2, &w1, &w0, x[15], y[21]); + word3_muladd(&w2, &w1, &w0, x[16], y[20]); + word3_muladd(&w2, &w1, &w0, x[17], y[19]); + word3_muladd(&w2, &w1, &w0, x[18], y[18]); + word3_muladd(&w2, &w1, &w0, x[19], y[17]); + word3_muladd(&w2, &w1, &w0, x[20], y[16]); + word3_muladd(&w2, &w1, &w0, x[21], y[15]); + word3_muladd(&w2, &w1, &w0, x[22], y[14]); + word3_muladd(&w2, &w1, &w0, x[23], y[13]); + z[36] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[14], y[23]); + word3_muladd(&w0, &w2, &w1, x[15], y[22]); + word3_muladd(&w0, &w2, &w1, x[16], y[21]); + word3_muladd(&w0, &w2, &w1, x[17], y[20]); + word3_muladd(&w0, &w2, &w1, x[18], y[19]); + word3_muladd(&w0, &w2, &w1, x[19], y[18]); + word3_muladd(&w0, &w2, &w1, x[20], y[17]); + word3_muladd(&w0, &w2, &w1, x[21], y[16]); + word3_muladd(&w0, &w2, &w1, x[22], y[15]); + word3_muladd(&w0, &w2, &w1, x[23], y[14]); + z[37] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[15], y[23]); + word3_muladd(&w1, &w0, &w2, x[16], y[22]); + word3_muladd(&w1, &w0, &w2, x[17], y[21]); + word3_muladd(&w1, &w0, &w2, x[18], y[20]); + word3_muladd(&w1, &w0, &w2, x[19], y[19]); + word3_muladd(&w1, &w0, &w2, x[20], y[18]); + word3_muladd(&w1, &w0, &w2, x[21], y[17]); + word3_muladd(&w1, &w0, &w2, x[22], y[16]); + word3_muladd(&w1, &w0, &w2, x[23], y[15]); + z[38] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[16], y[23]); + word3_muladd(&w2, &w1, &w0, x[17], y[22]); + word3_muladd(&w2, &w1, &w0, x[18], y[21]); + word3_muladd(&w2, &w1, &w0, x[19], y[20]); + word3_muladd(&w2, &w1, &w0, x[20], y[19]); + word3_muladd(&w2, &w1, &w0, x[21], y[18]); + word3_muladd(&w2, &w1, &w0, x[22], y[17]); + word3_muladd(&w2, &w1, &w0, x[23], y[16]); + z[39] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[17], y[23]); + word3_muladd(&w0, &w2, &w1, x[18], y[22]); + word3_muladd(&w0, &w2, &w1, x[19], y[21]); + word3_muladd(&w0, &w2, &w1, x[20], y[20]); + word3_muladd(&w0, &w2, &w1, x[21], y[19]); + word3_muladd(&w0, &w2, &w1, x[22], y[18]); + word3_muladd(&w0, &w2, &w1, x[23], y[17]); + z[40] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[18], y[23]); + word3_muladd(&w1, &w0, &w2, x[19], y[22]); + word3_muladd(&w1, &w0, &w2, x[20], y[21]); + word3_muladd(&w1, &w0, &w2, x[21], y[20]); + word3_muladd(&w1, &w0, &w2, x[22], y[19]); + word3_muladd(&w1, &w0, &w2, x[23], y[18]); + z[41] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[19], y[23]); + word3_muladd(&w2, &w1, &w0, x[20], y[22]); + word3_muladd(&w2, &w1, &w0, x[21], y[21]); + word3_muladd(&w2, &w1, &w0, x[22], y[20]); + word3_muladd(&w2, &w1, &w0, x[23], y[19]); + z[42] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[20], y[23]); + word3_muladd(&w0, &w2, &w1, x[21], y[22]); + word3_muladd(&w0, &w2, &w1, x[22], y[21]); + word3_muladd(&w0, &w2, &w1, x[23], y[20]); + z[43] = w1; w1 = 0; + + word3_muladd(&w1, &w0, &w2, x[21], y[23]); + word3_muladd(&w1, &w0, &w2, x[22], y[22]); + word3_muladd(&w1, &w0, &w2, x[23], y[21]); + z[44] = w2; w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[22], y[23]); + word3_muladd(&w2, &w1, &w0, x[23], y[22]); + z[45] = w0; w0 = 0; + + word3_muladd(&w0, &w2, &w1, x[23], y[23]); + z[46] = w1; + z[47] = w2; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/mp/mp_core.cpp b/src/libs/3rdparty/botan/src/lib/math/mp/mp_core.cpp new file mode 100644 index 0000000000..2ae65e508f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/mp/mp_core.cpp @@ -0,0 +1,527 @@ +/* +* MPI Add, Subtract, Word Multiply +* (C) 1999-2010,2016 Jack Lloyd +* 2006 Luca Piccarreta +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/mp_core.h> +#include <botan/internal/mp_asmi.h> +#include <botan/internal/ct_utils.h> +#include <botan/exceptn.h> +#include <botan/mem_ops.h> + +namespace Botan { + +/* +* If cond == 0, does nothing. +* If cond > 0, swaps x[0:size] with y[0:size] +* Runs in constant time +*/ +void bigint_cnd_swap(word cnd, word x[], word y[], size_t size) + { + const word mask = CT::expand_mask(cnd); + + for(size_t i = 0; i != size; ++i) + { + const word a = x[i]; + const word b = y[i]; + x[i] = CT::select(mask, b, a); + y[i] = CT::select(mask, a, b); + } + } + +/* +* If cond > 0 adds x[0:size] to y[0:size] and returns carry +* Runs in constant time +*/ +word bigint_cnd_add(word cnd, word x[], const word y[], size_t size) + { + const word mask = CT::expand_mask(cnd); + + word carry = 0; + + const size_t blocks = size - (size % 8); + word z[8] = { 0 }; + + for(size_t i = 0; i != blocks; i += 8) + { + carry = word8_add3(z, x + i, y + i, carry); + + for(size_t j = 0; j != 8; ++j) + x[i+j] = CT::select(mask, z[j], x[i+j]); + } + + for(size_t i = blocks; i != size; ++i) + { + z[0] = word_add(x[i], y[i], &carry); + x[i] = CT::select(mask, z[0], x[i]); + } + + return carry & mask; + } + +/* +* If cond > 0 subs x[0:size] to y[0:size] and returns borrow +* Runs in constant time +*/ +word bigint_cnd_sub(word cnd, word x[], const word y[], size_t size) + { + const word mask = CT::expand_mask(cnd); + + word carry = 0; + + const size_t blocks = size - (size % 8); + word z[8] = { 0 }; + + for(size_t i = 0; i != blocks; i += 8) + { + carry = word8_sub3(z, x + i, y + i, carry); + + for(size_t j = 0; j != 8; ++j) + x[i+j] = CT::select(mask, z[j], x[i+j]); + } + + for(size_t i = blocks; i != size; ++i) + { + z[0] = word_sub(x[i], y[i], &carry); + x[i] = CT::select(mask, z[0], x[i]); + } + + return carry & mask; + } + +void bigint_cnd_addsub(word mask, word x[], const word y[], size_t size) + { + const size_t blocks = size - (size % 8); + + word carry = 0; + word borrow = 0; + + word t0[8] = { 0 }; + word t1[8] = { 0 }; + + for(size_t i = 0; i != blocks; i += 8) + { + carry = word8_add3(t0, x + i, y + i, carry); + borrow = word8_sub3(t1, x + i, y + i, borrow); + + for(size_t j = 0; j != 8; ++j) + x[i+j] = CT::select(mask, t0[j], t1[j]); + } + + for(size_t i = blocks; i != size; ++i) + { + const word a = word_add(x[i], y[i], &carry); + const word s = word_sub(x[i], y[i], &borrow); + + x[i] = CT::select(mask, a, s); + } + } + +void bigint_cnd_abs(word cnd, word x[], size_t size) + { + const word mask = CT::expand_mask(cnd); + + word carry = mask & 1; + for(size_t i = 0; i != size; ++i) + { + const word z = word_add(~x[i], 0, &carry); + x[i] = CT::select(mask, z, x[i]); + } + } + +/* +* Two Operand Addition, No Carry +*/ +word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size) + { + word carry = 0; + + BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_add2(x + i, y + i, carry); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_add(x[i], y[i], &carry); + + for(size_t i = y_size; i != x_size; ++i) + x[i] = word_add(x[i], 0, &carry); + + return carry; + } + +/* +* Three Operand Addition, No Carry +*/ +word bigint_add3_nc(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + if(x_size < y_size) + { return bigint_add3_nc(z, y, y_size, x, x_size); } + + word carry = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_add3(z + i, x + i, y + i, carry); + + for(size_t i = blocks; i != y_size; ++i) + z[i] = word_add(x[i], y[i], &carry); + + for(size_t i = y_size; i != x_size; ++i) + z[i] = word_add(x[i], 0, &carry); + + return carry; + } + +/* +* Two Operand Addition +*/ +void bigint_add2(word x[], size_t x_size, const word y[], size_t y_size) + { + x[x_size] += bigint_add2_nc(x, x_size, y, y_size); + } + +/* +* Three Operand Addition +*/ +void bigint_add3(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + z[x_size > y_size ? x_size : y_size] += + bigint_add3_nc(z, x, x_size, y, y_size); + } + +/* +* Two Operand Subtraction +*/ +word bigint_sub2(word x[], size_t x_size, const word y[], size_t y_size) + { + word borrow = 0; + + BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub2(x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_sub(x[i], y[i], &borrow); + + for(size_t i = y_size; i != x_size; ++i) + x[i] = word_sub(x[i], 0, &borrow); + + return borrow; + } + +/* +* Two Operand Subtraction x = y - x +*/ +void bigint_sub2_rev(word x[], const word y[], size_t y_size) + { + word borrow = 0; + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub2_rev(x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + x[i] = word_sub(y[i], x[i], &borrow); + + BOTAN_ASSERT(!borrow, "y must be greater than x"); + } + +word bigint_sub_abs(word z[], + const word x[], const word y[], size_t N, + word ws[]) + { + // Subtract in both direction then conditional copy out the result + + word* ws0 = ws; + word* ws1 = ws + N; + + word borrow0 = 0; + word borrow1 = 0; + + const size_t blocks = N - (N % 8); + + for(size_t i = 0; i != blocks; i += 8) + { + borrow0 = word8_sub3(ws0 + i, x + i, y + i, borrow0); + borrow1 = word8_sub3(ws1 + i, y + i, x + i, borrow1); + } + + for(size_t i = blocks; i != N; ++i) + { + ws0[i] = word_sub(x[i], y[i], &borrow0); + ws1[i] = word_sub(y[i], x[i], &borrow1); + } + + word mask = CT::conditional_copy_mem(borrow1, z, ws0, ws1, N); + + return CT::select<word>(mask, 0, 1); + } + +/* +* Three Operand Subtraction +*/ +word bigint_sub3(word z[], const word x[], size_t x_size, + const word y[], size_t y_size) + { + word borrow = 0; + + BOTAN_ASSERT(x_size >= y_size, "Expected sizes"); + + const size_t blocks = y_size - (y_size % 8); + + for(size_t i = 0; i != blocks; i += 8) + borrow = word8_sub3(z + i, x + i, y + i, borrow); + + for(size_t i = blocks; i != y_size; ++i) + z[i] = word_sub(x[i], y[i], &borrow); + + for(size_t i = y_size; i != x_size; ++i) + z[i] = word_sub(x[i], 0, &borrow); + + return borrow; + } + +/* +* Two Operand Linear Multiply +*/ +void bigint_linmul2(word x[], size_t x_size, word y) + { + const size_t blocks = x_size - (x_size % 8); + + word carry = 0; + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_linmul2(x + i, y, carry); + + for(size_t i = blocks; i != x_size; ++i) + x[i] = word_madd2(x[i], y, &carry); + + x[x_size] = carry; + } + +/* +* Three Operand Linear Multiply +*/ +void bigint_linmul3(word z[], const word x[], size_t x_size, word y) + { + const size_t blocks = x_size - (x_size % 8); + + word carry = 0; + + for(size_t i = 0; i != blocks; i += 8) + carry = word8_linmul3(z + i, x + i, y, carry); + + for(size_t i = blocks; i != x_size; ++i) + z[i] = word_madd2(x[i], y, &carry); + + z[x_size] = carry; + } + +/* +* Single Operand Left Shift +*/ +void bigint_shl1(word x[], size_t x_size, size_t word_shift, size_t bit_shift) + { + if(word_shift) + { + copy_mem(x + word_shift, x, x_size); + clear_mem(x, word_shift); + } + + if(bit_shift) + { + word carry = 0; + for(size_t j = word_shift; j != x_size + word_shift + 1; ++j) + { + word temp = x[j]; + x[j] = (temp << bit_shift) | carry; + carry = (temp >> (BOTAN_MP_WORD_BITS - bit_shift)); + } + } + } + +/* +* Single Operand Right Shift +*/ +void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift) + { + if(x_size < word_shift) + { + clear_mem(x, x_size); + return; + } + + if(word_shift) + { + copy_mem(x, x + word_shift, x_size - word_shift); + clear_mem(x + x_size - word_shift, word_shift); + } + + if(bit_shift) + { + word carry = 0; + + size_t top = x_size - word_shift; + + while(top >= 4) + { + word w = x[top-1]; + x[top-1] = (w >> bit_shift) | carry; + carry = (w << (BOTAN_MP_WORD_BITS - bit_shift)); + + w = x[top-2]; + x[top-2] = (w >> bit_shift) | carry; + carry = (w << (BOTAN_MP_WORD_BITS - bit_shift)); + + w = x[top-3]; + x[top-3] = (w >> bit_shift) | carry; + carry = (w << (BOTAN_MP_WORD_BITS - bit_shift)); + + w = x[top-4]; + x[top-4] = (w >> bit_shift) | carry; + carry = (w << (BOTAN_MP_WORD_BITS - bit_shift)); + + top -= 4; + } + + while(top) + { + word w = x[top-1]; + x[top-1] = (w >> bit_shift) | carry; + carry = (w << (BOTAN_MP_WORD_BITS - bit_shift)); + + top--; + } + } + } + +/* +* Two Operand Left Shift +*/ +void bigint_shl2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift) + { + for(size_t j = 0; j != x_size; ++j) + y[j + word_shift] = x[j]; + if(bit_shift) + { + word carry = 0; + for(size_t j = word_shift; j != x_size + word_shift + 1; ++j) + { + word w = y[j]; + y[j] = (w << bit_shift) | carry; + carry = (w >> (BOTAN_MP_WORD_BITS - bit_shift)); + } + } + } + +/* +* Two Operand Right Shift +*/ +void bigint_shr2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift) + { + if(x_size < word_shift) return; + + for(size_t j = 0; j != x_size - word_shift; ++j) + y[j] = x[j + word_shift]; + if(bit_shift) + { + word carry = 0; + for(size_t j = x_size - word_shift; j > 0; --j) + { + word w = y[j-1]; + y[j-1] = (w >> bit_shift) | carry; + carry = (w << (BOTAN_MP_WORD_BITS - bit_shift)); + } + } + } + +/* +* Compare two MP integers +*/ +int32_t bigint_cmp(const word x[], size_t x_size, + const word y[], size_t y_size) + { + if(x_size < y_size) { return (-bigint_cmp(y, y_size, x, x_size)); } + + while(x_size > y_size) + { + if(x[x_size-1]) + return 1; + x_size--; + } + + for(size_t i = x_size; i > 0; --i) + { + if(x[i-1] > y[i-1]) + return 1; + if(x[i-1] < y[i-1]) + return -1; + } + + return 0; + } + +/* +* Do a 2-word/1-word Division +*/ +word bigint_divop(word n1, word n0, word d) + { + if(d == 0) + throw Invalid_Argument("bigint_divop divide by zero"); + +#if defined(BOTAN_HAS_MP_DWORD) + return ((static_cast<dword>(n1) << BOTAN_MP_WORD_BITS) | n0) / d; +#else + + word high = n1 % d, quotient = 0; + + for(size_t i = 0; i != BOTAN_MP_WORD_BITS; ++i) + { + word high_top_bit = (high & MP_WORD_TOP_BIT); + + high <<= 1; + high |= (n0 >> (BOTAN_MP_WORD_BITS-1-i)) & 1; + quotient <<= 1; + + if(high_top_bit || high >= d) + { + high -= d; + quotient |= 1; + } + } + + return quotient; +#endif + } + +/* +* Do a 2-word/1-word Modulo +*/ +word bigint_modop(word n1, word n0, word d) + { +#if defined(BOTAN_HAS_MP_DWORD) + return ((static_cast<dword>(n1) << BOTAN_MP_WORD_BITS) | n0) % d; +#else + word z = bigint_divop(n1, n0, d); + word dummy = 0; + z = word_madd2(z, d, &dummy); + return (n0-z); +#endif + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/mp/mp_core.h b/src/libs/3rdparty/botan/src/lib/math/mp/mp_core.h new file mode 100644 index 0000000000..9430c3753f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/mp/mp_core.h @@ -0,0 +1,209 @@ +/* +* MPI Algorithms +* (C) 1999-2010 Jack Lloyd +* 2006 Luca Piccarreta +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MP_CORE_OPS_H_ +#define BOTAN_MP_CORE_OPS_H_ + +#include <botan/types.h> + +namespace Botan { + +const word MP_WORD_MASK = ~static_cast<word>(0); +const word MP_WORD_TOP_BIT = static_cast<word>(1) << (8*sizeof(word) - 1); +const word MP_WORD_MAX = MP_WORD_MASK; + +/* +* If cond == 0, does nothing. +* If cond > 0, swaps x[0:size] with y[0:size] +* Runs in constant time +*/ +BOTAN_TEST_API +void bigint_cnd_swap(word cnd, word x[], word y[], size_t size); + +/* +* If cond > 0 adds x[0:size] and y[0:size] and returns carry +* Runs in constant time +*/ +BOTAN_TEST_API +word bigint_cnd_add(word cnd, word x[], const word y[], size_t size); + +/* +* If cond > 0 subtracts x[0:size] and y[0:size] and returns borrow +* Runs in constant time +*/ +BOTAN_TEST_API +word bigint_cnd_sub(word cnd, word x[], const word y[], size_t size); + +/* +* Equivalent to +* bigint_cnd_add( mask, x, y, size); +* bigint_cnd_sub(~mask, x, y, size); +* +* Mask must be either 0 or all 1 bits +*/ +void bigint_cnd_addsub(word mask, word x[], const word y[], size_t size); + +/* +* 2s complement absolute value +* If cond > 0 sets x to ~x + 1 +* Runs in constant time +*/ +BOTAN_TEST_API +void bigint_cnd_abs(word cnd, word x[], size_t size); + +/** +* Two operand addition +* @param x the first operand (and output) +* @param x_size size of x +* @param y the second operand +* @param y_size size of y (must be >= x_size) +*/ +void bigint_add2(word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Three operand addition +*/ +void bigint_add3(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Two operand addition with carry out +*/ +word bigint_add2_nc(word x[], size_t x_size, const word y[], size_t y_size); + +/** +* Three operand addition with carry out +*/ +word bigint_add3_nc(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Two operand subtraction +*/ +word bigint_sub2(word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Two operand subtraction, x = y - x; assumes y >= x +*/ +void bigint_sub2_rev(word x[], const word y[], size_t y_size); + +/** +* Three operand subtraction +*/ +word bigint_sub3(word z[], + const word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Return abs(x-y), ie if x >= y, then compute z = x - y +* Otherwise compute z = y - x +* No borrow is possible since the result is always >= 0 +* +* Returns 1 if x >= y or 0 if x < y +* @param z output array of at least N words +* @param x input array of N words +* @param y input array of N words +* @param N length of x and y +* @param ws array of at least 2*N words +*/ +word bigint_sub_abs(word z[], + const word x[], const word y[], size_t N, + word ws[]); + +/* +* Shift Operations +*/ +void bigint_shl1(word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +void bigint_shr1(word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +void bigint_shl2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +void bigint_shr2(word y[], const word x[], size_t x_size, + size_t word_shift, size_t bit_shift); + +/* +* Linear Multiply +*/ +void bigint_linmul2(word x[], size_t x_size, word y); +void bigint_linmul3(word z[], const word x[], size_t x_size, word y); + +/** +* Montgomery Reduction +* @param z integer to reduce, of size exactly 2*(p_size+1). + Output is in the first p_size+1 words, higher + words are set to zero. +* @param p modulus +* @param p_size size of p +* @param p_dash Montgomery value +* @param workspace array of at least 2*(p_size+1) words +* @param ws_size size of workspace in words +*/ +void bigint_monty_redc(word z[], + const word p[], size_t p_size, + word p_dash, + word workspace[], + size_t ws_size); + +/** +* Compare x and y returning early +*/ +int32_t bigint_cmp(const word x[], size_t x_size, + const word y[], size_t y_size); + +/** +* Compute ((n1<<bits) + n0) / d +*/ +word bigint_divop(word n1, word n0, word d); + +/** +* Compute ((n1<<bits) + n0) % d +*/ +word bigint_modop(word n1, word n0, word d); + +/* +* Comba Multiplication / Squaring +*/ +void bigint_comba_mul4(word z[8], const word x[4], const word y[4]); +void bigint_comba_mul6(word z[12], const word x[6], const word y[6]); +void bigint_comba_mul8(word z[16], const word x[8], const word y[8]); +void bigint_comba_mul9(word z[18], const word x[9], const word y[9]); +void bigint_comba_mul16(word z[32], const word x[16], const word y[16]); +void bigint_comba_mul24(word z[48], const word x[24], const word y[24]); + +void bigint_comba_sqr4(word out[8], const word in[4]); +void bigint_comba_sqr6(word out[12], const word in[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]); +void bigint_comba_sqr24(word out[48], const word in[24]); + +/* +* High Level Multiplication/Squaring Interfaces +*/ + +void bigint_mul(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw, + word workspace[], size_t ws_size); + +void bigint_sqr(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + word workspace[], size_t ws_size); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/mp/mp_karat.cpp b/src/libs/3rdparty/botan/src/lib/math/mp/mp_karat.cpp new file mode 100644 index 0000000000..69e2ae6656 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/mp/mp_karat.cpp @@ -0,0 +1,403 @@ +/* +* Multiplication and Squaring +* (C) 1999-2010,2018 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/mp_core.h> +#include <botan/internal/mp_asmi.h> +#include <botan/internal/ct_utils.h> +#include <botan/mem_ops.h> +#include <botan/exceptn.h> + +namespace Botan { + +namespace { + +const size_t KARATSUBA_MULTIPLY_THRESHOLD = 32; +const size_t KARATSUBA_SQUARE_THRESHOLD = 32; + +/* +* Simple O(N^2) Multiplication +*/ +void basecase_mul(word z[], size_t z_size, + const word x[], size_t x_size, + const word y[], size_t y_size) + { + if(z_size < x_size + y_size) + throw Invalid_Argument("basecase_mul z_size too small"); + + const size_t x_size_8 = x_size - (x_size % 8); + + clear_mem(z, z_size); + + for(size_t i = 0; i != y_size; ++i) + { + const word y_i = y[i]; + + word carry = 0; + + for(size_t j = 0; j != x_size_8; j += 8) + carry = word8_madd3(z + i + j, x + j, y_i, carry); + + for(size_t j = x_size_8; j != x_size; ++j) + z[i+j] = word_madd3(x[j], y_i, z[i+j], &carry); + + z[x_size+i] = carry; + } + } + +void basecase_sqr(word z[], size_t z_size, + const word x[], size_t x_size) + { + if(z_size < 2*x_size) + throw Invalid_Argument("basecase_sqr z_size too small"); + + const size_t x_size_8 = x_size - (x_size % 8); + + clear_mem(z, z_size); + + for(size_t i = 0; i != x_size; ++i) + { + const word x_i = x[i]; + + word carry = 0; + + for(size_t j = 0; j != x_size_8; j += 8) + carry = word8_madd3(z + i + j, x + j, x_i, carry); + + for(size_t j = x_size_8; j != x_size; ++j) + z[i+j] = word_madd3(x[j], x_i, z[i+j], &carry); + + z[x_size+i] = carry; + } + } + +/* +* Karatsuba Multiplication Operation +*/ +void karatsuba_mul(word z[], const word x[], const word y[], size_t N, + word workspace[]) + { + if(N < KARATSUBA_MULTIPLY_THRESHOLD || N % 2) + { + if(N == 6) + return bigint_comba_mul6(z, x, y); + else if(N == 8) + return bigint_comba_mul8(z, x, y); + else if(N == 9) + return bigint_comba_mul9(z, x, y); + else if(N == 16) + return bigint_comba_mul16(z, x, y); + else if(N == 24) + return bigint_comba_mul24(z, x, y); + else + return basecase_mul(z, 2*N, x, N, y, N); + } + + const size_t N2 = N / 2; + + const word* x0 = x; + const word* x1 = x + N2; + const word* y0 = y; + const word* y1 = y + N2; + word* z0 = z; + word* z1 = z + N; + + word* ws0 = workspace; + word* ws1 = workspace + N; + + clear_mem(workspace, 2*N); + + /* + * If either of cmp0 or cmp1 is zero then z0 or z1 resp is zero here, + * resulting in a no-op - z0*z1 will be equal to zero so we don't need to do + * anything, clear_mem above already set the correct result. + * + * However we ignore the result of the comparisons and always perform the + * subtractions and recursively multiply to avoid the timing channel. + */ + + // First compute (X_lo - X_hi)*(Y_hi - Y_lo) + const word cmp0 = bigint_sub_abs(z0, x0, x1, N2, workspace); + const word cmp1 = bigint_sub_abs(z1, y1, y0, N2, workspace); + + karatsuba_mul(ws0, z0, z1, N2, ws1); + + // Compute X_lo * Y_lo + karatsuba_mul(z0, x0, y0, N2, ws1); + + // Compute X_hi * Y_hi + karatsuba_mul(z1, x1, y1, N2, ws1); + + const word ws_carry = bigint_add3_nc(ws1, z0, N, z1, N); + word z_carry = bigint_add2_nc(z + N2, N, ws1, N); + + z_carry += bigint_add2_nc(z + N + N2, N2, &ws_carry, 1); + bigint_add2_nc(z + N + N2, N2, &z_carry, 1); + + clear_mem(workspace + N, N2); + + const word neg_mask = CT::is_equal<word>(cmp0, cmp1); + + bigint_cnd_addsub(neg_mask, z + N2, workspace, 2*N-N2); + } + +/* +* Karatsuba Squaring Operation +*/ +void karatsuba_sqr(word z[], const word x[], size_t N, word workspace[]) + { + if(N < KARATSUBA_SQUARE_THRESHOLD || N % 2) + { + if(N == 6) + return bigint_comba_sqr6(z, x); + else if(N == 8) + return bigint_comba_sqr8(z, x); + else if(N == 9) + return bigint_comba_sqr9(z, x); + else if(N == 16) + return bigint_comba_sqr16(z, x); + else if(N == 24) + return bigint_comba_sqr24(z, x); + else + return basecase_sqr(z, 2*N, x, N); + } + + const size_t N2 = N / 2; + + const word* x0 = x; + const word* x1 = x + N2; + word* z0 = z; + word* z1 = z + N; + + word* ws0 = workspace; + word* ws1 = workspace + N; + + clear_mem(workspace, 2*N); + + // See comment in karatsuba_mul + bigint_sub_abs(z0, x0, x1, N2, workspace); + karatsuba_sqr(ws0, z0, N2, ws1); + + karatsuba_sqr(z0, x0, N2, ws1); + karatsuba_sqr(z1, x1, N2, ws1); + + const word ws_carry = bigint_add3_nc(ws1, z0, N, z1, N); + word z_carry = bigint_add2_nc(z + N2, N, ws1, N); + + z_carry += bigint_add2_nc(z + N + N2, N2, &ws_carry, 1); + bigint_add2_nc(z + N + N2, N2, &z_carry, 1); + + /* + * This is only actually required if cmp (result of bigint_sub_abs) is != 0, + * however if cmp==0 then ws0[0:N] == 0 and avoiding the jump hides a + * timing channel. + */ + bigint_sub2(z + N2, 2*N-N2, ws0, N); + } + +/* +* Pick a good size for the Karatsuba multiply +*/ +size_t karatsuba_size(size_t z_size, + size_t x_size, size_t x_sw, + size_t y_size, size_t y_sw) + { + if(x_sw > x_size || x_sw > y_size || y_sw > x_size || y_sw > y_size) + return 0; + + if(((x_size == x_sw) && (x_size % 2)) || + ((y_size == y_sw) && (y_size % 2))) + return 0; + + const size_t start = (x_sw > y_sw) ? x_sw : y_sw; + const size_t end = (x_size < y_size) ? x_size : y_size; + + if(start == end) + { + if(start % 2) + return 0; + return start; + } + + for(size_t j = start; j <= end; ++j) + { + if(j % 2) + continue; + + if(2*j > z_size) + return 0; + + if(x_sw <= j && j <= x_size && y_sw <= j && j <= y_size) + { + if(j % 4 == 2 && + (j+2) <= x_size && (j+2) <= y_size && 2*(j+2) <= z_size) + return j+2; + return j; + } + } + + return 0; + } + +/* +* Pick a good size for the Karatsuba squaring +*/ +size_t karatsuba_size(size_t z_size, size_t x_size, size_t x_sw) + { + if(x_sw == x_size) + { + if(x_sw % 2) + return 0; + return x_sw; + } + + for(size_t j = x_sw; j <= x_size; ++j) + { + if(j % 2) + continue; + + if(2*j > z_size) + return 0; + + if(j % 4 == 2 && (j+2) <= x_size && 2*(j+2) <= z_size) + return j+2; + return j; + } + + return 0; + } + +template<size_t SZ> +inline bool sized_for_comba_mul(size_t x_sw, size_t x_size, + size_t y_sw, size_t y_size, + size_t z_size) + { + return (x_sw <= SZ && x_size >= SZ && + y_sw <= SZ && y_size >= SZ && + z_size >= 2*SZ); + } + +template<size_t SZ> +inline bool sized_for_comba_sqr(size_t x_sw, size_t x_size, + size_t z_size) + { + return (x_sw <= SZ && x_size >= SZ && z_size >= 2*SZ); + } + +} + +void bigint_mul(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw, + word workspace[], size_t ws_size) + { + clear_mem(z, z_size); + + if(x_sw == 1) + { + bigint_linmul3(z, y, y_sw, x[0]); + } + else if(y_sw == 1) + { + bigint_linmul3(z, x, x_sw, y[0]); + } + else if(sized_for_comba_mul<4>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul4(z, x, y); + } + else if(sized_for_comba_mul<6>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul6(z, x, y); + } + else if(sized_for_comba_mul<8>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul8(z, x, y); + } + else if(sized_for_comba_mul<9>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul9(z, x, y); + } + else if(sized_for_comba_mul<16>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul16(z, x, y); + } + else if(sized_for_comba_mul<24>(x_sw, x_size, y_sw, y_size, z_size)) + { + bigint_comba_mul24(z, x, y); + } + else if(x_sw < KARATSUBA_MULTIPLY_THRESHOLD || + y_sw < KARATSUBA_MULTIPLY_THRESHOLD || + !workspace) + { + basecase_mul(z, z_size, x, x_sw, y, y_sw); + } + else + { + const size_t N = karatsuba_size(z_size, x_size, x_sw, y_size, y_sw); + + if(N && z_size >= 2*N && ws_size >= 2*N) + karatsuba_mul(z, x, y, N, workspace); + else + basecase_mul(z, z_size, x, x_sw, y, y_sw); + } + } + +/* +* Squaring Algorithm Dispatcher +*/ +void bigint_sqr(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + word workspace[], size_t ws_size) + { + clear_mem(z, z_size); + + BOTAN_ASSERT(z_size/2 >= x_sw, "Output size is sufficient"); + + if(x_sw == 1) + { + bigint_linmul3(z, x, x_sw, x[0]); + } + else if(sized_for_comba_sqr<4>(x_sw, x_size, z_size)) + { + bigint_comba_sqr4(z, x); + } + else if(sized_for_comba_sqr<6>(x_sw, x_size, z_size)) + { + bigint_comba_sqr6(z, x); + } + else if(sized_for_comba_sqr<8>(x_sw, x_size, z_size)) + { + bigint_comba_sqr8(z, x); + } + else if(sized_for_comba_sqr<9>(x_sw, x_size, z_size)) + { + bigint_comba_sqr9(z, x); + } + else if(sized_for_comba_sqr<16>(x_sw, x_size, z_size)) + { + bigint_comba_sqr16(z, x); + } + else if(sized_for_comba_sqr<24>(x_sw, x_size, z_size)) + { + bigint_comba_sqr24(z, x); + } + else if(x_size < KARATSUBA_SQUARE_THRESHOLD || !workspace) + { + basecase_sqr(z, z_size, x, x_sw); + } + else + { + const size_t N = karatsuba_size(z_size, x_size, x_sw); + + if(N && z_size >= 2*N && ws_size >= 2*N) + karatsuba_sqr(z, x, N, workspace); + else + basecase_sqr(z, z_size, x, x_sw); + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/mp/mp_madd.h b/src/libs/3rdparty/botan/src/lib/math/mp/mp_madd.h new file mode 100644 index 0000000000..4807fcd040 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/mp/mp_madd.h @@ -0,0 +1,165 @@ +/* +* Lowest Level MPI Algorithms +* (C) 1999-2008,2013 Jack Lloyd +* 2006 Luca Piccarreta +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MP_WORD_MULADD_H_ +#define BOTAN_MP_WORD_MULADD_H_ + +#include <botan/types.h> +#include <botan/mul128.h> + +namespace Botan { + +#if (BOTAN_MP_WORD_BITS == 8) + typedef uint16_t dword; + #define BOTAN_HAS_MP_DWORD +#elif (BOTAN_MP_WORD_BITS == 16) + typedef uint32_t dword; + #define BOTAN_HAS_MP_DWORD +#elif (BOTAN_MP_WORD_BITS == 32) + typedef uint64_t dword; + #define BOTAN_HAS_MP_DWORD +#elif (BOTAN_MP_WORD_BITS == 64) + #if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) + typedef uint128_t dword; + #define BOTAN_HAS_MP_DWORD + #else + // No native 128 bit integer type; use mul64x64_128 instead + #endif + +#else + #error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 +#endif + +#if defined(BOTAN_TARGET_ARCH_IS_X86_32) && (BOTAN_MP_WORD_BITS == 32) + + #if defined(BOTAN_USE_GCC_INLINE_ASM) + #define BOTAN_MP_USE_X86_32_ASM + #define ASM(x) x "\n\t" + #elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) + #define BOTAN_MP_USE_X86_32_MSVC_ASM + #endif + +#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && (BOTAN_MP_WORD_BITS == 64) && (BOTAN_USE_GCC_INLINE_ASM) + #define BOTAN_MP_USE_X86_64_ASM + #define ASM(x) x "\n\t" +#endif + +#if defined(BOTAN_MP_USE_X86_32_ASM) || defined(BOTAN_MP_USE_X86_64_ASM) + #define ASM(x) x "\n\t" +#endif + +/* +* Word Multiply/Add +*/ +inline word word_madd2(word a, word b, word* c) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ASM("mull %[b]") + ASM("addl %[c],%[a]") + ASM("adcl $0,%[carry]") + + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c) + : "0"(a), "1"(b), [c]"g"(*c) : "cc"); + + return a; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + asm( + ASM("mulq %[b]") + ASM("addq %[c],%[a]") + ASM("adcq $0,%[carry]") + + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c) + : "0"(a), "1"(b), [c]"g"(*c) : "cc"); + + return a; + +#elif defined(BOTAN_HAS_MP_DWORD) + const dword s = static_cast<dword>(a) * b + *c; + *c = static_cast<word>(s >> BOTAN_MP_WORD_BITS); + return static_cast<word>(s); +#else + static_assert(BOTAN_MP_WORD_BITS == 64, "Unexpected word size"); + + word hi = 0, lo = 0; + + mul64x64_128(a, b, &lo, &hi); + + lo += *c; + hi += (lo < *c); // carry? + + *c = hi; + return lo; +#endif + } + +/* +* Word Multiply/Add +*/ +inline word word_madd3(word a, word b, word c, word* d) + { +#if defined(BOTAN_MP_USE_X86_32_ASM) + asm( + ASM("mull %[b]") + + ASM("addl %[c],%[a]") + ASM("adcl $0,%[carry]") + + ASM("addl %[d],%[a]") + ASM("adcl $0,%[carry]") + + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d) + : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc"); + + return a; + +#elif defined(BOTAN_MP_USE_X86_64_ASM) + asm( + ASM("mulq %[b]") + + ASM("addq %[c],%[a]") + ASM("adcq $0,%[carry]") + + ASM("addq %[d],%[a]") + ASM("adcq $0,%[carry]") + + : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d) + : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc"); + + return a; + +#elif defined(BOTAN_HAS_MP_DWORD) + const dword s = static_cast<dword>(a) * b + c + *d; + *d = static_cast<word>(s >> BOTAN_MP_WORD_BITS); + return static_cast<word>(s); +#else + static_assert(BOTAN_MP_WORD_BITS == 64, "Unexpected word size"); + + word hi = 0, lo = 0; + + mul64x64_128(a, b, &lo, &hi); + + lo += c; + hi += (lo < c); // carry? + + lo += *d; + hi += (lo < *d); // carry? + + *d = hi; + return lo; +#endif + } + +#if defined(ASM) + #undef ASM +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/mp/mp_monty.cpp b/src/libs/3rdparty/botan/src/lib/math/mp/mp_monty.cpp new file mode 100644 index 0000000000..e5dda705ce --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/mp/mp_monty.cpp @@ -0,0 +1,135 @@ +/* +* Montgomery Reduction +* (C) 1999-2011 Jack Lloyd +* 2006 Luca Piccarreta +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/mp_core.h> +#include <botan/internal/mp_monty.h> +#include <botan/internal/mp_madd.h> +#include <botan/internal/mp_asmi.h> +#include <botan/internal/ct_utils.h> +#include <botan/mem_ops.h> +#include <botan/exceptn.h> + +namespace Botan { + +namespace { + +/* +* Montgomery reduction - product scanning form +* +* https://www.iacr.org/archive/ches2005/006.pdf +* https://eprint.iacr.org/2013/882.pdf +* https://www.microsoft.com/en-us/research/wp-content/uploads/1996/01/j37acmon.pdf +*/ +void bigint_monty_redc_generic(word z[], size_t z_size, + const word p[], size_t p_size, word p_dash, + word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + + w0 = z[0]; + + ws[0] = w0 * p_dash; + + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + + w0 = w1; + w1 = w2; + w2 = 0; + + for(size_t i = 1; i != p_size; ++i) + { + for(size_t j = 0; j < i; ++j) + { + word3_muladd(&w2, &w1, &w0, ws[j], p[i-j]); + } + + word3_add(&w2, &w1, &w0, z[i]); + + ws[i] = w0 * p_dash; + + word3_muladd(&w2, &w1, &w0, ws[i], p[0]); + + w0 = w1; + w1 = w2; + w2 = 0; + } + + for(size_t i = 0; i != p_size; ++i) + { + for(size_t j = i + 1; j != p_size; ++j) + { + word3_muladd(&w2, &w1, &w0, ws[j], p[p_size + i-j]); + } + + word3_add(&w2, &w1, &w0, z[p_size+i]); + + ws[i] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + } + + word3_add(&w2, &w1, &w0, z[z_size-1]); + + ws[p_size] = w0; + ws[p_size+1] = w1; + + /* + * The result might need to be reduced mod p. To avoid a timing + * channel, always perform the subtraction. If in the compution + * of x - p a borrow is required then x was already < p. + * + * x starts at ws[0] and is p_size+1 bytes long. + * x - p starts at ws[p_size+1] and is also p_size+1 bytes log + * + * Select which address to copy from indexing off of the final + * borrow. + */ + + // word borrow = bigint_sub3(ws + p_size + 1, ws, p_size + 1, p, p_size); + word borrow = 0; + for(size_t i = 0; i != p_size; ++i) + ws[p_size + 1 + i] = word_sub(ws[i], p[i], &borrow); + ws[2*p_size+1] = word_sub(ws[p_size], 0, &borrow); + + CT::conditional_copy_mem(borrow, z, ws, ws + (p_size + 1), (p_size + 1)); + clear_mem(z + p_size, z_size - p_size - 2); + + // This check comes after we've used it but that's ok here + CT::unpoison(&borrow, 1); + BOTAN_ASSERT(borrow == 0 || borrow == 1, "Expected borrow"); + } + +} + +void bigint_monty_redc(word z[], + const word p[], size_t p_size, word p_dash, + word ws[], size_t ws_size) + { + const size_t z_size = 2*(p_size+1); + + BOTAN_ARG_CHECK(ws_size >= z_size, "workspace too small"); + + if(p_size == 4) + bigint_monty_redc_4(z, p, p_dash, ws); + else if(p_size == 6) + bigint_monty_redc_6(z, p, p_dash, ws); + else if(p_size == 8) + bigint_monty_redc_8(z, p, p_dash, ws); + else if(p_size == 16) + bigint_monty_redc_16(z, p, p_dash, ws); + else if(p_size == 24) + bigint_monty_redc_24(z, p, p_dash, ws); + else if(p_size == 32) + bigint_monty_redc_32(z, p, p_dash, ws); + else + bigint_monty_redc_generic(z, z_size, p, p_size, p_dash, ws); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/mp/mp_monty.h b/src/libs/3rdparty/botan/src/lib/math/mp/mp_monty.h new file mode 100644 index 0000000000..7462272d5c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/mp/mp_monty.h @@ -0,0 +1,31 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MP_MONTY_H_ +#define BOTAN_MP_MONTY_H_ + +#include <botan/types.h> + +namespace Botan { + +/* +* Each of these functions makes the following assumptions: +* +* z_size >= 2*(p_size + 1) +* ws_size >= z_size +*/ + +void bigint_monty_redc_4(word z[], const word p[], word p_dash, word ws[]); +void bigint_monty_redc_6(word z[], const word p[], word p_dash, word ws[]); +void bigint_monty_redc_8(word z[], const word p[], word p_dash, word ws[]); +void bigint_monty_redc_16(word z[], const word p[], word p_dash, word ws[]); +void bigint_monty_redc_24(word z[], const word p[], word p_dash, word ws[]); +void bigint_monty_redc_32(word z[], const word p[], word p_dash, word ws[]); + + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/mp/mp_monty_n.cpp b/src/libs/3rdparty/botan/src/lib/math/mp/mp_monty_n.cpp new file mode 100644 index 0000000000..0331d4a073 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/mp/mp_monty_n.cpp @@ -0,0 +1,2614 @@ +/* +* This file was automatically generated by ./src/scripts/monty.py on 2018-06-11 +* All manual changes will be lost. Edit the script instead. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/mp_monty.h> +#include <botan/internal/mp_core.h> +#include <botan/internal/mp_asmi.h> +#include <botan/internal/ct_utils.h> + +namespace Botan { + +void bigint_monty_redc_4(word z[], const word p[4], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_add(&w2, &w1, &w0, z[5]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_add(&w2, &w1, &w0, z[6]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[7]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[9]); + ws[4] = w0; + ws[5] = w1; + word borrow = 0; + ws[5] = word_sub(ws[0], p[0], &borrow); + ws[6] = word_sub(ws[1], p[1], &borrow); + ws[7] = word_sub(ws[2], p[2], &borrow); + ws[8] = word_sub(ws[3], p[3], &borrow); + ws[9] = word_sub(ws[4], 0, &borrow); + CT::conditional_copy_mem(borrow, z, ws, ws + 5, 5); + clear_mem(z + 4, 2*(4+1) - 4); + } + +void bigint_monty_redc_6(word z[], const word p[6], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[4]); + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[4] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[4], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[5]); + word3_muladd(&w2, &w1, &w0, ws[1], p[4]); + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_muladd(&w2, &w1, &w0, ws[4], p[1]); + word3_add(&w2, &w1, &w0, z[5]); + ws[5] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[5], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[5]); + word3_muladd(&w2, &w1, &w0, ws[2], p[4]); + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_muladd(&w2, &w1, &w0, ws[4], p[2]); + word3_muladd(&w2, &w1, &w0, ws[5], p[1]); + word3_add(&w2, &w1, &w0, z[6]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[5]); + word3_muladd(&w2, &w1, &w0, ws[3], p[4]); + word3_muladd(&w2, &w1, &w0, ws[4], p[3]); + word3_muladd(&w2, &w1, &w0, ws[5], p[2]); + word3_add(&w2, &w1, &w0, z[7]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[5]); + word3_muladd(&w2, &w1, &w0, ws[4], p[4]); + word3_muladd(&w2, &w1, &w0, ws[5], p[3]); + word3_add(&w2, &w1, &w0, z[8]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[4], p[5]); + word3_muladd(&w2, &w1, &w0, ws[5], p[4]); + word3_add(&w2, &w1, &w0, z[9]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[5], p[5]); + word3_add(&w2, &w1, &w0, z[10]); + ws[4] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[11]); + ws[5] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[13]); + ws[6] = w0; + ws[7] = w1; + word borrow = 0; + ws[7] = word_sub(ws[0], p[0], &borrow); + ws[8] = word_sub(ws[1], p[1], &borrow); + ws[9] = word_sub(ws[2], p[2], &borrow); + ws[10] = word_sub(ws[3], p[3], &borrow); + ws[11] = word_sub(ws[4], p[4], &borrow); + ws[12] = word_sub(ws[5], p[5], &borrow); + ws[13] = word_sub(ws[6], 0, &borrow); + CT::conditional_copy_mem(borrow, z, ws, ws + 7, 7); + clear_mem(z + 6, 2*(6+1) - 6); + } + +void bigint_monty_redc_8(word z[], const word p[8], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[4]); + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[4] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[4], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[5]); + word3_muladd(&w2, &w1, &w0, ws[1], p[4]); + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_muladd(&w2, &w1, &w0, ws[4], p[1]); + word3_add(&w2, &w1, &w0, z[5]); + ws[5] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[5], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[6]); + word3_muladd(&w2, &w1, &w0, ws[1], p[5]); + word3_muladd(&w2, &w1, &w0, ws[2], p[4]); + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_muladd(&w2, &w1, &w0, ws[4], p[2]); + word3_muladd(&w2, &w1, &w0, ws[5], p[1]); + word3_add(&w2, &w1, &w0, z[6]); + ws[6] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[6], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[7]); + word3_muladd(&w2, &w1, &w0, ws[1], p[6]); + word3_muladd(&w2, &w1, &w0, ws[2], p[5]); + word3_muladd(&w2, &w1, &w0, ws[3], p[4]); + word3_muladd(&w2, &w1, &w0, ws[4], p[3]); + word3_muladd(&w2, &w1, &w0, ws[5], p[2]); + word3_muladd(&w2, &w1, &w0, ws[6], p[1]); + word3_add(&w2, &w1, &w0, z[7]); + ws[7] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[7], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[7]); + word3_muladd(&w2, &w1, &w0, ws[2], p[6]); + word3_muladd(&w2, &w1, &w0, ws[3], p[5]); + word3_muladd(&w2, &w1, &w0, ws[4], p[4]); + word3_muladd(&w2, &w1, &w0, ws[5], p[3]); + word3_muladd(&w2, &w1, &w0, ws[6], p[2]); + word3_muladd(&w2, &w1, &w0, ws[7], p[1]); + word3_add(&w2, &w1, &w0, z[8]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[7]); + word3_muladd(&w2, &w1, &w0, ws[3], p[6]); + word3_muladd(&w2, &w1, &w0, ws[4], p[5]); + word3_muladd(&w2, &w1, &w0, ws[5], p[4]); + word3_muladd(&w2, &w1, &w0, ws[6], p[3]); + word3_muladd(&w2, &w1, &w0, ws[7], p[2]); + word3_add(&w2, &w1, &w0, z[9]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[7]); + word3_muladd(&w2, &w1, &w0, ws[4], p[6]); + word3_muladd(&w2, &w1, &w0, ws[5], p[5]); + word3_muladd(&w2, &w1, &w0, ws[6], p[4]); + word3_muladd(&w2, &w1, &w0, ws[7], p[3]); + word3_add(&w2, &w1, &w0, z[10]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[4], p[7]); + word3_muladd(&w2, &w1, &w0, ws[5], p[6]); + word3_muladd(&w2, &w1, &w0, ws[6], p[5]); + word3_muladd(&w2, &w1, &w0, ws[7], p[4]); + word3_add(&w2, &w1, &w0, z[11]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[5], p[7]); + word3_muladd(&w2, &w1, &w0, ws[6], p[6]); + word3_muladd(&w2, &w1, &w0, ws[7], p[5]); + word3_add(&w2, &w1, &w0, z[12]); + ws[4] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[6], p[7]); + word3_muladd(&w2, &w1, &w0, ws[7], p[6]); + word3_add(&w2, &w1, &w0, z[13]); + ws[5] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[7], p[7]); + word3_add(&w2, &w1, &w0, z[14]); + ws[6] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[15]); + ws[7] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[17]); + ws[8] = w0; + ws[9] = w1; + word borrow = 0; + ws[9] = word_sub(ws[0], p[0], &borrow); + ws[10] = word_sub(ws[1], p[1], &borrow); + ws[11] = word_sub(ws[2], p[2], &borrow); + ws[12] = word_sub(ws[3], p[3], &borrow); + ws[13] = word_sub(ws[4], p[4], &borrow); + ws[14] = word_sub(ws[5], p[5], &borrow); + ws[15] = word_sub(ws[6], p[6], &borrow); + ws[16] = word_sub(ws[7], p[7], &borrow); + ws[17] = word_sub(ws[8], 0, &borrow); + CT::conditional_copy_mem(borrow, z, ws, ws + 9, 9); + clear_mem(z + 8, 2*(8+1) - 8); + } + +void bigint_monty_redc_16(word z[], const word p[16], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[4]); + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[4] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[4], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[5]); + word3_muladd(&w2, &w1, &w0, ws[1], p[4]); + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_muladd(&w2, &w1, &w0, ws[4], p[1]); + word3_add(&w2, &w1, &w0, z[5]); + ws[5] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[5], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[6]); + word3_muladd(&w2, &w1, &w0, ws[1], p[5]); + word3_muladd(&w2, &w1, &w0, ws[2], p[4]); + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_muladd(&w2, &w1, &w0, ws[4], p[2]); + word3_muladd(&w2, &w1, &w0, ws[5], p[1]); + word3_add(&w2, &w1, &w0, z[6]); + ws[6] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[6], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[7]); + word3_muladd(&w2, &w1, &w0, ws[1], p[6]); + word3_muladd(&w2, &w1, &w0, ws[2], p[5]); + word3_muladd(&w2, &w1, &w0, ws[3], p[4]); + word3_muladd(&w2, &w1, &w0, ws[4], p[3]); + word3_muladd(&w2, &w1, &w0, ws[5], p[2]); + word3_muladd(&w2, &w1, &w0, ws[6], p[1]); + word3_add(&w2, &w1, &w0, z[7]); + ws[7] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[7], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[8]); + word3_muladd(&w2, &w1, &w0, ws[1], p[7]); + word3_muladd(&w2, &w1, &w0, ws[2], p[6]); + word3_muladd(&w2, &w1, &w0, ws[3], p[5]); + word3_muladd(&w2, &w1, &w0, ws[4], p[4]); + word3_muladd(&w2, &w1, &w0, ws[5], p[3]); + word3_muladd(&w2, &w1, &w0, ws[6], p[2]); + word3_muladd(&w2, &w1, &w0, ws[7], p[1]); + word3_add(&w2, &w1, &w0, z[8]); + ws[8] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[8], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[9]); + word3_muladd(&w2, &w1, &w0, ws[1], p[8]); + word3_muladd(&w2, &w1, &w0, ws[2], p[7]); + word3_muladd(&w2, &w1, &w0, ws[3], p[6]); + word3_muladd(&w2, &w1, &w0, ws[4], p[5]); + word3_muladd(&w2, &w1, &w0, ws[5], p[4]); + word3_muladd(&w2, &w1, &w0, ws[6], p[3]); + word3_muladd(&w2, &w1, &w0, ws[7], p[2]); + word3_muladd(&w2, &w1, &w0, ws[8], p[1]); + word3_add(&w2, &w1, &w0, z[9]); + ws[9] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[9], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[10]); + word3_muladd(&w2, &w1, &w0, ws[1], p[9]); + word3_muladd(&w2, &w1, &w0, ws[2], p[8]); + word3_muladd(&w2, &w1, &w0, ws[3], p[7]); + word3_muladd(&w2, &w1, &w0, ws[4], p[6]); + word3_muladd(&w2, &w1, &w0, ws[5], p[5]); + word3_muladd(&w2, &w1, &w0, ws[6], p[4]); + word3_muladd(&w2, &w1, &w0, ws[7], p[3]); + word3_muladd(&w2, &w1, &w0, ws[8], p[2]); + word3_muladd(&w2, &w1, &w0, ws[9], p[1]); + word3_add(&w2, &w1, &w0, z[10]); + ws[10] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[10], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[11]); + word3_muladd(&w2, &w1, &w0, ws[1], p[10]); + word3_muladd(&w2, &w1, &w0, ws[2], p[9]); + word3_muladd(&w2, &w1, &w0, ws[3], p[8]); + word3_muladd(&w2, &w1, &w0, ws[4], p[7]); + word3_muladd(&w2, &w1, &w0, ws[5], p[6]); + word3_muladd(&w2, &w1, &w0, ws[6], p[5]); + word3_muladd(&w2, &w1, &w0, ws[7], p[4]); + word3_muladd(&w2, &w1, &w0, ws[8], p[3]); + word3_muladd(&w2, &w1, &w0, ws[9], p[2]); + word3_muladd(&w2, &w1, &w0, ws[10], p[1]); + word3_add(&w2, &w1, &w0, z[11]); + ws[11] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[11], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[12]); + word3_muladd(&w2, &w1, &w0, ws[1], p[11]); + word3_muladd(&w2, &w1, &w0, ws[2], p[10]); + word3_muladd(&w2, &w1, &w0, ws[3], p[9]); + word3_muladd(&w2, &w1, &w0, ws[4], p[8]); + word3_muladd(&w2, &w1, &w0, ws[5], p[7]); + word3_muladd(&w2, &w1, &w0, ws[6], p[6]); + word3_muladd(&w2, &w1, &w0, ws[7], p[5]); + word3_muladd(&w2, &w1, &w0, ws[8], p[4]); + word3_muladd(&w2, &w1, &w0, ws[9], p[3]); + word3_muladd(&w2, &w1, &w0, ws[10], p[2]); + word3_muladd(&w2, &w1, &w0, ws[11], p[1]); + word3_add(&w2, &w1, &w0, z[12]); + ws[12] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[12], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[13]); + word3_muladd(&w2, &w1, &w0, ws[1], p[12]); + word3_muladd(&w2, &w1, &w0, ws[2], p[11]); + word3_muladd(&w2, &w1, &w0, ws[3], p[10]); + word3_muladd(&w2, &w1, &w0, ws[4], p[9]); + word3_muladd(&w2, &w1, &w0, ws[5], p[8]); + word3_muladd(&w2, &w1, &w0, ws[6], p[7]); + word3_muladd(&w2, &w1, &w0, ws[7], p[6]); + word3_muladd(&w2, &w1, &w0, ws[8], p[5]); + word3_muladd(&w2, &w1, &w0, ws[9], p[4]); + word3_muladd(&w2, &w1, &w0, ws[10], p[3]); + word3_muladd(&w2, &w1, &w0, ws[11], p[2]); + word3_muladd(&w2, &w1, &w0, ws[12], p[1]); + word3_add(&w2, &w1, &w0, z[13]); + ws[13] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[13], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[14]); + word3_muladd(&w2, &w1, &w0, ws[1], p[13]); + word3_muladd(&w2, &w1, &w0, ws[2], p[12]); + word3_muladd(&w2, &w1, &w0, ws[3], p[11]); + word3_muladd(&w2, &w1, &w0, ws[4], p[10]); + word3_muladd(&w2, &w1, &w0, ws[5], p[9]); + word3_muladd(&w2, &w1, &w0, ws[6], p[8]); + word3_muladd(&w2, &w1, &w0, ws[7], p[7]); + word3_muladd(&w2, &w1, &w0, ws[8], p[6]); + word3_muladd(&w2, &w1, &w0, ws[9], p[5]); + word3_muladd(&w2, &w1, &w0, ws[10], p[4]); + word3_muladd(&w2, &w1, &w0, ws[11], p[3]); + word3_muladd(&w2, &w1, &w0, ws[12], p[2]); + word3_muladd(&w2, &w1, &w0, ws[13], p[1]); + word3_add(&w2, &w1, &w0, z[14]); + ws[14] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[14], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[15]); + word3_muladd(&w2, &w1, &w0, ws[1], p[14]); + word3_muladd(&w2, &w1, &w0, ws[2], p[13]); + word3_muladd(&w2, &w1, &w0, ws[3], p[12]); + word3_muladd(&w2, &w1, &w0, ws[4], p[11]); + word3_muladd(&w2, &w1, &w0, ws[5], p[10]); + word3_muladd(&w2, &w1, &w0, ws[6], p[9]); + word3_muladd(&w2, &w1, &w0, ws[7], p[8]); + word3_muladd(&w2, &w1, &w0, ws[8], p[7]); + word3_muladd(&w2, &w1, &w0, ws[9], p[6]); + word3_muladd(&w2, &w1, &w0, ws[10], p[5]); + word3_muladd(&w2, &w1, &w0, ws[11], p[4]); + word3_muladd(&w2, &w1, &w0, ws[12], p[3]); + word3_muladd(&w2, &w1, &w0, ws[13], p[2]); + word3_muladd(&w2, &w1, &w0, ws[14], p[1]); + word3_add(&w2, &w1, &w0, z[15]); + ws[15] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[15], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[15]); + word3_muladd(&w2, &w1, &w0, ws[2], p[14]); + word3_muladd(&w2, &w1, &w0, ws[3], p[13]); + word3_muladd(&w2, &w1, &w0, ws[4], p[12]); + word3_muladd(&w2, &w1, &w0, ws[5], p[11]); + word3_muladd(&w2, &w1, &w0, ws[6], p[10]); + word3_muladd(&w2, &w1, &w0, ws[7], p[9]); + word3_muladd(&w2, &w1, &w0, ws[8], p[8]); + word3_muladd(&w2, &w1, &w0, ws[9], p[7]); + word3_muladd(&w2, &w1, &w0, ws[10], p[6]); + word3_muladd(&w2, &w1, &w0, ws[11], p[5]); + word3_muladd(&w2, &w1, &w0, ws[12], p[4]); + word3_muladd(&w2, &w1, &w0, ws[13], p[3]); + word3_muladd(&w2, &w1, &w0, ws[14], p[2]); + word3_muladd(&w2, &w1, &w0, ws[15], p[1]); + word3_add(&w2, &w1, &w0, z[16]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[15]); + word3_muladd(&w2, &w1, &w0, ws[3], p[14]); + word3_muladd(&w2, &w1, &w0, ws[4], p[13]); + word3_muladd(&w2, &w1, &w0, ws[5], p[12]); + word3_muladd(&w2, &w1, &w0, ws[6], p[11]); + word3_muladd(&w2, &w1, &w0, ws[7], p[10]); + word3_muladd(&w2, &w1, &w0, ws[8], p[9]); + word3_muladd(&w2, &w1, &w0, ws[9], p[8]); + word3_muladd(&w2, &w1, &w0, ws[10], p[7]); + word3_muladd(&w2, &w1, &w0, ws[11], p[6]); + word3_muladd(&w2, &w1, &w0, ws[12], p[5]); + word3_muladd(&w2, &w1, &w0, ws[13], p[4]); + word3_muladd(&w2, &w1, &w0, ws[14], p[3]); + word3_muladd(&w2, &w1, &w0, ws[15], p[2]); + word3_add(&w2, &w1, &w0, z[17]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[15]); + word3_muladd(&w2, &w1, &w0, ws[4], p[14]); + word3_muladd(&w2, &w1, &w0, ws[5], p[13]); + word3_muladd(&w2, &w1, &w0, ws[6], p[12]); + word3_muladd(&w2, &w1, &w0, ws[7], p[11]); + word3_muladd(&w2, &w1, &w0, ws[8], p[10]); + word3_muladd(&w2, &w1, &w0, ws[9], p[9]); + word3_muladd(&w2, &w1, &w0, ws[10], p[8]); + word3_muladd(&w2, &w1, &w0, ws[11], p[7]); + word3_muladd(&w2, &w1, &w0, ws[12], p[6]); + word3_muladd(&w2, &w1, &w0, ws[13], p[5]); + word3_muladd(&w2, &w1, &w0, ws[14], p[4]); + word3_muladd(&w2, &w1, &w0, ws[15], p[3]); + word3_add(&w2, &w1, &w0, z[18]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[4], p[15]); + word3_muladd(&w2, &w1, &w0, ws[5], p[14]); + word3_muladd(&w2, &w1, &w0, ws[6], p[13]); + word3_muladd(&w2, &w1, &w0, ws[7], p[12]); + word3_muladd(&w2, &w1, &w0, ws[8], p[11]); + word3_muladd(&w2, &w1, &w0, ws[9], p[10]); + word3_muladd(&w2, &w1, &w0, ws[10], p[9]); + word3_muladd(&w2, &w1, &w0, ws[11], p[8]); + word3_muladd(&w2, &w1, &w0, ws[12], p[7]); + word3_muladd(&w2, &w1, &w0, ws[13], p[6]); + word3_muladd(&w2, &w1, &w0, ws[14], p[5]); + word3_muladd(&w2, &w1, &w0, ws[15], p[4]); + word3_add(&w2, &w1, &w0, z[19]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[5], p[15]); + word3_muladd(&w2, &w1, &w0, ws[6], p[14]); + word3_muladd(&w2, &w1, &w0, ws[7], p[13]); + word3_muladd(&w2, &w1, &w0, ws[8], p[12]); + word3_muladd(&w2, &w1, &w0, ws[9], p[11]); + word3_muladd(&w2, &w1, &w0, ws[10], p[10]); + word3_muladd(&w2, &w1, &w0, ws[11], p[9]); + word3_muladd(&w2, &w1, &w0, ws[12], p[8]); + word3_muladd(&w2, &w1, &w0, ws[13], p[7]); + word3_muladd(&w2, &w1, &w0, ws[14], p[6]); + word3_muladd(&w2, &w1, &w0, ws[15], p[5]); + word3_add(&w2, &w1, &w0, z[20]); + ws[4] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[6], p[15]); + word3_muladd(&w2, &w1, &w0, ws[7], p[14]); + word3_muladd(&w2, &w1, &w0, ws[8], p[13]); + word3_muladd(&w2, &w1, &w0, ws[9], p[12]); + word3_muladd(&w2, &w1, &w0, ws[10], p[11]); + word3_muladd(&w2, &w1, &w0, ws[11], p[10]); + word3_muladd(&w2, &w1, &w0, ws[12], p[9]); + word3_muladd(&w2, &w1, &w0, ws[13], p[8]); + word3_muladd(&w2, &w1, &w0, ws[14], p[7]); + word3_muladd(&w2, &w1, &w0, ws[15], p[6]); + word3_add(&w2, &w1, &w0, z[21]); + ws[5] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[7], p[15]); + word3_muladd(&w2, &w1, &w0, ws[8], p[14]); + word3_muladd(&w2, &w1, &w0, ws[9], p[13]); + word3_muladd(&w2, &w1, &w0, ws[10], p[12]); + word3_muladd(&w2, &w1, &w0, ws[11], p[11]); + word3_muladd(&w2, &w1, &w0, ws[12], p[10]); + word3_muladd(&w2, &w1, &w0, ws[13], p[9]); + word3_muladd(&w2, &w1, &w0, ws[14], p[8]); + word3_muladd(&w2, &w1, &w0, ws[15], p[7]); + word3_add(&w2, &w1, &w0, z[22]); + ws[6] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[8], p[15]); + word3_muladd(&w2, &w1, &w0, ws[9], p[14]); + word3_muladd(&w2, &w1, &w0, ws[10], p[13]); + word3_muladd(&w2, &w1, &w0, ws[11], p[12]); + word3_muladd(&w2, &w1, &w0, ws[12], p[11]); + word3_muladd(&w2, &w1, &w0, ws[13], p[10]); + word3_muladd(&w2, &w1, &w0, ws[14], p[9]); + word3_muladd(&w2, &w1, &w0, ws[15], p[8]); + word3_add(&w2, &w1, &w0, z[23]); + ws[7] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[9], p[15]); + word3_muladd(&w2, &w1, &w0, ws[10], p[14]); + word3_muladd(&w2, &w1, &w0, ws[11], p[13]); + word3_muladd(&w2, &w1, &w0, ws[12], p[12]); + word3_muladd(&w2, &w1, &w0, ws[13], p[11]); + word3_muladd(&w2, &w1, &w0, ws[14], p[10]); + word3_muladd(&w2, &w1, &w0, ws[15], p[9]); + word3_add(&w2, &w1, &w0, z[24]); + ws[8] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[10], p[15]); + word3_muladd(&w2, &w1, &w0, ws[11], p[14]); + word3_muladd(&w2, &w1, &w0, ws[12], p[13]); + word3_muladd(&w2, &w1, &w0, ws[13], p[12]); + word3_muladd(&w2, &w1, &w0, ws[14], p[11]); + word3_muladd(&w2, &w1, &w0, ws[15], p[10]); + word3_add(&w2, &w1, &w0, z[25]); + ws[9] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[11], p[15]); + word3_muladd(&w2, &w1, &w0, ws[12], p[14]); + word3_muladd(&w2, &w1, &w0, ws[13], p[13]); + word3_muladd(&w2, &w1, &w0, ws[14], p[12]); + word3_muladd(&w2, &w1, &w0, ws[15], p[11]); + word3_add(&w2, &w1, &w0, z[26]); + ws[10] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[12], p[15]); + word3_muladd(&w2, &w1, &w0, ws[13], p[14]); + word3_muladd(&w2, &w1, &w0, ws[14], p[13]); + word3_muladd(&w2, &w1, &w0, ws[15], p[12]); + word3_add(&w2, &w1, &w0, z[27]); + ws[11] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[13], p[15]); + word3_muladd(&w2, &w1, &w0, ws[14], p[14]); + word3_muladd(&w2, &w1, &w0, ws[15], p[13]); + word3_add(&w2, &w1, &w0, z[28]); + ws[12] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[14], p[15]); + word3_muladd(&w2, &w1, &w0, ws[15], p[14]); + word3_add(&w2, &w1, &w0, z[29]); + ws[13] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[15], p[15]); + word3_add(&w2, &w1, &w0, z[30]); + ws[14] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[31]); + ws[15] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[33]); + ws[16] = w0; + ws[17] = w1; + word borrow = bigint_sub3(ws + 16 + 1, ws, 16 + 1, p, 16); + CT::conditional_copy_mem(borrow, z, ws, ws + 17, 17); + clear_mem(z + 16, 2*(16+1) - 16); + } + +void bigint_monty_redc_24(word z[], const word p[24], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[4]); + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[4] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[4], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[5]); + word3_muladd(&w2, &w1, &w0, ws[1], p[4]); + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_muladd(&w2, &w1, &w0, ws[4], p[1]); + word3_add(&w2, &w1, &w0, z[5]); + ws[5] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[5], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[6]); + word3_muladd(&w2, &w1, &w0, ws[1], p[5]); + word3_muladd(&w2, &w1, &w0, ws[2], p[4]); + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_muladd(&w2, &w1, &w0, ws[4], p[2]); + word3_muladd(&w2, &w1, &w0, ws[5], p[1]); + word3_add(&w2, &w1, &w0, z[6]); + ws[6] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[6], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[7]); + word3_muladd(&w2, &w1, &w0, ws[1], p[6]); + word3_muladd(&w2, &w1, &w0, ws[2], p[5]); + word3_muladd(&w2, &w1, &w0, ws[3], p[4]); + word3_muladd(&w2, &w1, &w0, ws[4], p[3]); + word3_muladd(&w2, &w1, &w0, ws[5], p[2]); + word3_muladd(&w2, &w1, &w0, ws[6], p[1]); + word3_add(&w2, &w1, &w0, z[7]); + ws[7] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[7], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[8]); + word3_muladd(&w2, &w1, &w0, ws[1], p[7]); + word3_muladd(&w2, &w1, &w0, ws[2], p[6]); + word3_muladd(&w2, &w1, &w0, ws[3], p[5]); + word3_muladd(&w2, &w1, &w0, ws[4], p[4]); + word3_muladd(&w2, &w1, &w0, ws[5], p[3]); + word3_muladd(&w2, &w1, &w0, ws[6], p[2]); + word3_muladd(&w2, &w1, &w0, ws[7], p[1]); + word3_add(&w2, &w1, &w0, z[8]); + ws[8] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[8], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[9]); + word3_muladd(&w2, &w1, &w0, ws[1], p[8]); + word3_muladd(&w2, &w1, &w0, ws[2], p[7]); + word3_muladd(&w2, &w1, &w0, ws[3], p[6]); + word3_muladd(&w2, &w1, &w0, ws[4], p[5]); + word3_muladd(&w2, &w1, &w0, ws[5], p[4]); + word3_muladd(&w2, &w1, &w0, ws[6], p[3]); + word3_muladd(&w2, &w1, &w0, ws[7], p[2]); + word3_muladd(&w2, &w1, &w0, ws[8], p[1]); + word3_add(&w2, &w1, &w0, z[9]); + ws[9] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[9], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[10]); + word3_muladd(&w2, &w1, &w0, ws[1], p[9]); + word3_muladd(&w2, &w1, &w0, ws[2], p[8]); + word3_muladd(&w2, &w1, &w0, ws[3], p[7]); + word3_muladd(&w2, &w1, &w0, ws[4], p[6]); + word3_muladd(&w2, &w1, &w0, ws[5], p[5]); + word3_muladd(&w2, &w1, &w0, ws[6], p[4]); + word3_muladd(&w2, &w1, &w0, ws[7], p[3]); + word3_muladd(&w2, &w1, &w0, ws[8], p[2]); + word3_muladd(&w2, &w1, &w0, ws[9], p[1]); + word3_add(&w2, &w1, &w0, z[10]); + ws[10] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[10], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[11]); + word3_muladd(&w2, &w1, &w0, ws[1], p[10]); + word3_muladd(&w2, &w1, &w0, ws[2], p[9]); + word3_muladd(&w2, &w1, &w0, ws[3], p[8]); + word3_muladd(&w2, &w1, &w0, ws[4], p[7]); + word3_muladd(&w2, &w1, &w0, ws[5], p[6]); + word3_muladd(&w2, &w1, &w0, ws[6], p[5]); + word3_muladd(&w2, &w1, &w0, ws[7], p[4]); + word3_muladd(&w2, &w1, &w0, ws[8], p[3]); + word3_muladd(&w2, &w1, &w0, ws[9], p[2]); + word3_muladd(&w2, &w1, &w0, ws[10], p[1]); + word3_add(&w2, &w1, &w0, z[11]); + ws[11] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[11], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[12]); + word3_muladd(&w2, &w1, &w0, ws[1], p[11]); + word3_muladd(&w2, &w1, &w0, ws[2], p[10]); + word3_muladd(&w2, &w1, &w0, ws[3], p[9]); + word3_muladd(&w2, &w1, &w0, ws[4], p[8]); + word3_muladd(&w2, &w1, &w0, ws[5], p[7]); + word3_muladd(&w2, &w1, &w0, ws[6], p[6]); + word3_muladd(&w2, &w1, &w0, ws[7], p[5]); + word3_muladd(&w2, &w1, &w0, ws[8], p[4]); + word3_muladd(&w2, &w1, &w0, ws[9], p[3]); + word3_muladd(&w2, &w1, &w0, ws[10], p[2]); + word3_muladd(&w2, &w1, &w0, ws[11], p[1]); + word3_add(&w2, &w1, &w0, z[12]); + ws[12] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[12], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[13]); + word3_muladd(&w2, &w1, &w0, ws[1], p[12]); + word3_muladd(&w2, &w1, &w0, ws[2], p[11]); + word3_muladd(&w2, &w1, &w0, ws[3], p[10]); + word3_muladd(&w2, &w1, &w0, ws[4], p[9]); + word3_muladd(&w2, &w1, &w0, ws[5], p[8]); + word3_muladd(&w2, &w1, &w0, ws[6], p[7]); + word3_muladd(&w2, &w1, &w0, ws[7], p[6]); + word3_muladd(&w2, &w1, &w0, ws[8], p[5]); + word3_muladd(&w2, &w1, &w0, ws[9], p[4]); + word3_muladd(&w2, &w1, &w0, ws[10], p[3]); + word3_muladd(&w2, &w1, &w0, ws[11], p[2]); + word3_muladd(&w2, &w1, &w0, ws[12], p[1]); + word3_add(&w2, &w1, &w0, z[13]); + ws[13] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[13], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[14]); + word3_muladd(&w2, &w1, &w0, ws[1], p[13]); + word3_muladd(&w2, &w1, &w0, ws[2], p[12]); + word3_muladd(&w2, &w1, &w0, ws[3], p[11]); + word3_muladd(&w2, &w1, &w0, ws[4], p[10]); + word3_muladd(&w2, &w1, &w0, ws[5], p[9]); + word3_muladd(&w2, &w1, &w0, ws[6], p[8]); + word3_muladd(&w2, &w1, &w0, ws[7], p[7]); + word3_muladd(&w2, &w1, &w0, ws[8], p[6]); + word3_muladd(&w2, &w1, &w0, ws[9], p[5]); + word3_muladd(&w2, &w1, &w0, ws[10], p[4]); + word3_muladd(&w2, &w1, &w0, ws[11], p[3]); + word3_muladd(&w2, &w1, &w0, ws[12], p[2]); + word3_muladd(&w2, &w1, &w0, ws[13], p[1]); + word3_add(&w2, &w1, &w0, z[14]); + ws[14] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[14], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[15]); + word3_muladd(&w2, &w1, &w0, ws[1], p[14]); + word3_muladd(&w2, &w1, &w0, ws[2], p[13]); + word3_muladd(&w2, &w1, &w0, ws[3], p[12]); + word3_muladd(&w2, &w1, &w0, ws[4], p[11]); + word3_muladd(&w2, &w1, &w0, ws[5], p[10]); + word3_muladd(&w2, &w1, &w0, ws[6], p[9]); + word3_muladd(&w2, &w1, &w0, ws[7], p[8]); + word3_muladd(&w2, &w1, &w0, ws[8], p[7]); + word3_muladd(&w2, &w1, &w0, ws[9], p[6]); + word3_muladd(&w2, &w1, &w0, ws[10], p[5]); + word3_muladd(&w2, &w1, &w0, ws[11], p[4]); + word3_muladd(&w2, &w1, &w0, ws[12], p[3]); + word3_muladd(&w2, &w1, &w0, ws[13], p[2]); + word3_muladd(&w2, &w1, &w0, ws[14], p[1]); + word3_add(&w2, &w1, &w0, z[15]); + ws[15] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[15], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[16]); + word3_muladd(&w2, &w1, &w0, ws[1], p[15]); + word3_muladd(&w2, &w1, &w0, ws[2], p[14]); + word3_muladd(&w2, &w1, &w0, ws[3], p[13]); + word3_muladd(&w2, &w1, &w0, ws[4], p[12]); + word3_muladd(&w2, &w1, &w0, ws[5], p[11]); + word3_muladd(&w2, &w1, &w0, ws[6], p[10]); + word3_muladd(&w2, &w1, &w0, ws[7], p[9]); + word3_muladd(&w2, &w1, &w0, ws[8], p[8]); + word3_muladd(&w2, &w1, &w0, ws[9], p[7]); + word3_muladd(&w2, &w1, &w0, ws[10], p[6]); + word3_muladd(&w2, &w1, &w0, ws[11], p[5]); + word3_muladd(&w2, &w1, &w0, ws[12], p[4]); + word3_muladd(&w2, &w1, &w0, ws[13], p[3]); + word3_muladd(&w2, &w1, &w0, ws[14], p[2]); + word3_muladd(&w2, &w1, &w0, ws[15], p[1]); + word3_add(&w2, &w1, &w0, z[16]); + ws[16] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[16], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[17]); + word3_muladd(&w2, &w1, &w0, ws[1], p[16]); + word3_muladd(&w2, &w1, &w0, ws[2], p[15]); + word3_muladd(&w2, &w1, &w0, ws[3], p[14]); + word3_muladd(&w2, &w1, &w0, ws[4], p[13]); + word3_muladd(&w2, &w1, &w0, ws[5], p[12]); + word3_muladd(&w2, &w1, &w0, ws[6], p[11]); + word3_muladd(&w2, &w1, &w0, ws[7], p[10]); + word3_muladd(&w2, &w1, &w0, ws[8], p[9]); + word3_muladd(&w2, &w1, &w0, ws[9], p[8]); + word3_muladd(&w2, &w1, &w0, ws[10], p[7]); + word3_muladd(&w2, &w1, &w0, ws[11], p[6]); + word3_muladd(&w2, &w1, &w0, ws[12], p[5]); + word3_muladd(&w2, &w1, &w0, ws[13], p[4]); + word3_muladd(&w2, &w1, &w0, ws[14], p[3]); + word3_muladd(&w2, &w1, &w0, ws[15], p[2]); + word3_muladd(&w2, &w1, &w0, ws[16], p[1]); + word3_add(&w2, &w1, &w0, z[17]); + ws[17] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[17], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[18]); + word3_muladd(&w2, &w1, &w0, ws[1], p[17]); + word3_muladd(&w2, &w1, &w0, ws[2], p[16]); + word3_muladd(&w2, &w1, &w0, ws[3], p[15]); + word3_muladd(&w2, &w1, &w0, ws[4], p[14]); + word3_muladd(&w2, &w1, &w0, ws[5], p[13]); + word3_muladd(&w2, &w1, &w0, ws[6], p[12]); + word3_muladd(&w2, &w1, &w0, ws[7], p[11]); + word3_muladd(&w2, &w1, &w0, ws[8], p[10]); + word3_muladd(&w2, &w1, &w0, ws[9], p[9]); + word3_muladd(&w2, &w1, &w0, ws[10], p[8]); + word3_muladd(&w2, &w1, &w0, ws[11], p[7]); + word3_muladd(&w2, &w1, &w0, ws[12], p[6]); + word3_muladd(&w2, &w1, &w0, ws[13], p[5]); + word3_muladd(&w2, &w1, &w0, ws[14], p[4]); + word3_muladd(&w2, &w1, &w0, ws[15], p[3]); + word3_muladd(&w2, &w1, &w0, ws[16], p[2]); + word3_muladd(&w2, &w1, &w0, ws[17], p[1]); + word3_add(&w2, &w1, &w0, z[18]); + ws[18] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[18], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[19]); + word3_muladd(&w2, &w1, &w0, ws[1], p[18]); + word3_muladd(&w2, &w1, &w0, ws[2], p[17]); + word3_muladd(&w2, &w1, &w0, ws[3], p[16]); + word3_muladd(&w2, &w1, &w0, ws[4], p[15]); + word3_muladd(&w2, &w1, &w0, ws[5], p[14]); + word3_muladd(&w2, &w1, &w0, ws[6], p[13]); + word3_muladd(&w2, &w1, &w0, ws[7], p[12]); + word3_muladd(&w2, &w1, &w0, ws[8], p[11]); + word3_muladd(&w2, &w1, &w0, ws[9], p[10]); + word3_muladd(&w2, &w1, &w0, ws[10], p[9]); + word3_muladd(&w2, &w1, &w0, ws[11], p[8]); + word3_muladd(&w2, &w1, &w0, ws[12], p[7]); + word3_muladd(&w2, &w1, &w0, ws[13], p[6]); + word3_muladd(&w2, &w1, &w0, ws[14], p[5]); + word3_muladd(&w2, &w1, &w0, ws[15], p[4]); + word3_muladd(&w2, &w1, &w0, ws[16], p[3]); + word3_muladd(&w2, &w1, &w0, ws[17], p[2]); + word3_muladd(&w2, &w1, &w0, ws[18], p[1]); + word3_add(&w2, &w1, &w0, z[19]); + ws[19] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[19], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[20]); + word3_muladd(&w2, &w1, &w0, ws[1], p[19]); + word3_muladd(&w2, &w1, &w0, ws[2], p[18]); + word3_muladd(&w2, &w1, &w0, ws[3], p[17]); + word3_muladd(&w2, &w1, &w0, ws[4], p[16]); + word3_muladd(&w2, &w1, &w0, ws[5], p[15]); + word3_muladd(&w2, &w1, &w0, ws[6], p[14]); + word3_muladd(&w2, &w1, &w0, ws[7], p[13]); + word3_muladd(&w2, &w1, &w0, ws[8], p[12]); + word3_muladd(&w2, &w1, &w0, ws[9], p[11]); + word3_muladd(&w2, &w1, &w0, ws[10], p[10]); + word3_muladd(&w2, &w1, &w0, ws[11], p[9]); + word3_muladd(&w2, &w1, &w0, ws[12], p[8]); + word3_muladd(&w2, &w1, &w0, ws[13], p[7]); + word3_muladd(&w2, &w1, &w0, ws[14], p[6]); + word3_muladd(&w2, &w1, &w0, ws[15], p[5]); + word3_muladd(&w2, &w1, &w0, ws[16], p[4]); + word3_muladd(&w2, &w1, &w0, ws[17], p[3]); + word3_muladd(&w2, &w1, &w0, ws[18], p[2]); + word3_muladd(&w2, &w1, &w0, ws[19], p[1]); + word3_add(&w2, &w1, &w0, z[20]); + ws[20] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[20], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[21]); + word3_muladd(&w2, &w1, &w0, ws[1], p[20]); + word3_muladd(&w2, &w1, &w0, ws[2], p[19]); + word3_muladd(&w2, &w1, &w0, ws[3], p[18]); + word3_muladd(&w2, &w1, &w0, ws[4], p[17]); + word3_muladd(&w2, &w1, &w0, ws[5], p[16]); + word3_muladd(&w2, &w1, &w0, ws[6], p[15]); + word3_muladd(&w2, &w1, &w0, ws[7], p[14]); + word3_muladd(&w2, &w1, &w0, ws[8], p[13]); + word3_muladd(&w2, &w1, &w0, ws[9], p[12]); + word3_muladd(&w2, &w1, &w0, ws[10], p[11]); + word3_muladd(&w2, &w1, &w0, ws[11], p[10]); + word3_muladd(&w2, &w1, &w0, ws[12], p[9]); + word3_muladd(&w2, &w1, &w0, ws[13], p[8]); + word3_muladd(&w2, &w1, &w0, ws[14], p[7]); + word3_muladd(&w2, &w1, &w0, ws[15], p[6]); + word3_muladd(&w2, &w1, &w0, ws[16], p[5]); + word3_muladd(&w2, &w1, &w0, ws[17], p[4]); + word3_muladd(&w2, &w1, &w0, ws[18], p[3]); + word3_muladd(&w2, &w1, &w0, ws[19], p[2]); + word3_muladd(&w2, &w1, &w0, ws[20], p[1]); + word3_add(&w2, &w1, &w0, z[21]); + ws[21] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[21], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[22]); + word3_muladd(&w2, &w1, &w0, ws[1], p[21]); + word3_muladd(&w2, &w1, &w0, ws[2], p[20]); + word3_muladd(&w2, &w1, &w0, ws[3], p[19]); + word3_muladd(&w2, &w1, &w0, ws[4], p[18]); + word3_muladd(&w2, &w1, &w0, ws[5], p[17]); + word3_muladd(&w2, &w1, &w0, ws[6], p[16]); + word3_muladd(&w2, &w1, &w0, ws[7], p[15]); + word3_muladd(&w2, &w1, &w0, ws[8], p[14]); + word3_muladd(&w2, &w1, &w0, ws[9], p[13]); + word3_muladd(&w2, &w1, &w0, ws[10], p[12]); + word3_muladd(&w2, &w1, &w0, ws[11], p[11]); + word3_muladd(&w2, &w1, &w0, ws[12], p[10]); + word3_muladd(&w2, &w1, &w0, ws[13], p[9]); + word3_muladd(&w2, &w1, &w0, ws[14], p[8]); + word3_muladd(&w2, &w1, &w0, ws[15], p[7]); + word3_muladd(&w2, &w1, &w0, ws[16], p[6]); + word3_muladd(&w2, &w1, &w0, ws[17], p[5]); + word3_muladd(&w2, &w1, &w0, ws[18], p[4]); + word3_muladd(&w2, &w1, &w0, ws[19], p[3]); + word3_muladd(&w2, &w1, &w0, ws[20], p[2]); + word3_muladd(&w2, &w1, &w0, ws[21], p[1]); + word3_add(&w2, &w1, &w0, z[22]); + ws[22] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[22], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[23]); + word3_muladd(&w2, &w1, &w0, ws[1], p[22]); + word3_muladd(&w2, &w1, &w0, ws[2], p[21]); + word3_muladd(&w2, &w1, &w0, ws[3], p[20]); + word3_muladd(&w2, &w1, &w0, ws[4], p[19]); + word3_muladd(&w2, &w1, &w0, ws[5], p[18]); + word3_muladd(&w2, &w1, &w0, ws[6], p[17]); + word3_muladd(&w2, &w1, &w0, ws[7], p[16]); + word3_muladd(&w2, &w1, &w0, ws[8], p[15]); + word3_muladd(&w2, &w1, &w0, ws[9], p[14]); + word3_muladd(&w2, &w1, &w0, ws[10], p[13]); + word3_muladd(&w2, &w1, &w0, ws[11], p[12]); + word3_muladd(&w2, &w1, &w0, ws[12], p[11]); + word3_muladd(&w2, &w1, &w0, ws[13], p[10]); + word3_muladd(&w2, &w1, &w0, ws[14], p[9]); + word3_muladd(&w2, &w1, &w0, ws[15], p[8]); + word3_muladd(&w2, &w1, &w0, ws[16], p[7]); + word3_muladd(&w2, &w1, &w0, ws[17], p[6]); + word3_muladd(&w2, &w1, &w0, ws[18], p[5]); + word3_muladd(&w2, &w1, &w0, ws[19], p[4]); + word3_muladd(&w2, &w1, &w0, ws[20], p[3]); + word3_muladd(&w2, &w1, &w0, ws[21], p[2]); + word3_muladd(&w2, &w1, &w0, ws[22], p[1]); + word3_add(&w2, &w1, &w0, z[23]); + ws[23] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[23], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[23]); + word3_muladd(&w2, &w1, &w0, ws[2], p[22]); + word3_muladd(&w2, &w1, &w0, ws[3], p[21]); + word3_muladd(&w2, &w1, &w0, ws[4], p[20]); + word3_muladd(&w2, &w1, &w0, ws[5], p[19]); + word3_muladd(&w2, &w1, &w0, ws[6], p[18]); + word3_muladd(&w2, &w1, &w0, ws[7], p[17]); + word3_muladd(&w2, &w1, &w0, ws[8], p[16]); + word3_muladd(&w2, &w1, &w0, ws[9], p[15]); + word3_muladd(&w2, &w1, &w0, ws[10], p[14]); + word3_muladd(&w2, &w1, &w0, ws[11], p[13]); + word3_muladd(&w2, &w1, &w0, ws[12], p[12]); + word3_muladd(&w2, &w1, &w0, ws[13], p[11]); + word3_muladd(&w2, &w1, &w0, ws[14], p[10]); + word3_muladd(&w2, &w1, &w0, ws[15], p[9]); + word3_muladd(&w2, &w1, &w0, ws[16], p[8]); + word3_muladd(&w2, &w1, &w0, ws[17], p[7]); + word3_muladd(&w2, &w1, &w0, ws[18], p[6]); + word3_muladd(&w2, &w1, &w0, ws[19], p[5]); + word3_muladd(&w2, &w1, &w0, ws[20], p[4]); + word3_muladd(&w2, &w1, &w0, ws[21], p[3]); + word3_muladd(&w2, &w1, &w0, ws[22], p[2]); + word3_muladd(&w2, &w1, &w0, ws[23], p[1]); + word3_add(&w2, &w1, &w0, z[24]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[23]); + word3_muladd(&w2, &w1, &w0, ws[3], p[22]); + word3_muladd(&w2, &w1, &w0, ws[4], p[21]); + word3_muladd(&w2, &w1, &w0, ws[5], p[20]); + word3_muladd(&w2, &w1, &w0, ws[6], p[19]); + word3_muladd(&w2, &w1, &w0, ws[7], p[18]); + word3_muladd(&w2, &w1, &w0, ws[8], p[17]); + word3_muladd(&w2, &w1, &w0, ws[9], p[16]); + word3_muladd(&w2, &w1, &w0, ws[10], p[15]); + word3_muladd(&w2, &w1, &w0, ws[11], p[14]); + word3_muladd(&w2, &w1, &w0, ws[12], p[13]); + word3_muladd(&w2, &w1, &w0, ws[13], p[12]); + word3_muladd(&w2, &w1, &w0, ws[14], p[11]); + word3_muladd(&w2, &w1, &w0, ws[15], p[10]); + word3_muladd(&w2, &w1, &w0, ws[16], p[9]); + word3_muladd(&w2, &w1, &w0, ws[17], p[8]); + word3_muladd(&w2, &w1, &w0, ws[18], p[7]); + word3_muladd(&w2, &w1, &w0, ws[19], p[6]); + word3_muladd(&w2, &w1, &w0, ws[20], p[5]); + word3_muladd(&w2, &w1, &w0, ws[21], p[4]); + word3_muladd(&w2, &w1, &w0, ws[22], p[3]); + word3_muladd(&w2, &w1, &w0, ws[23], p[2]); + word3_add(&w2, &w1, &w0, z[25]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[23]); + word3_muladd(&w2, &w1, &w0, ws[4], p[22]); + word3_muladd(&w2, &w1, &w0, ws[5], p[21]); + word3_muladd(&w2, &w1, &w0, ws[6], p[20]); + word3_muladd(&w2, &w1, &w0, ws[7], p[19]); + word3_muladd(&w2, &w1, &w0, ws[8], p[18]); + word3_muladd(&w2, &w1, &w0, ws[9], p[17]); + word3_muladd(&w2, &w1, &w0, ws[10], p[16]); + word3_muladd(&w2, &w1, &w0, ws[11], p[15]); + word3_muladd(&w2, &w1, &w0, ws[12], p[14]); + word3_muladd(&w2, &w1, &w0, ws[13], p[13]); + word3_muladd(&w2, &w1, &w0, ws[14], p[12]); + word3_muladd(&w2, &w1, &w0, ws[15], p[11]); + word3_muladd(&w2, &w1, &w0, ws[16], p[10]); + word3_muladd(&w2, &w1, &w0, ws[17], p[9]); + word3_muladd(&w2, &w1, &w0, ws[18], p[8]); + word3_muladd(&w2, &w1, &w0, ws[19], p[7]); + word3_muladd(&w2, &w1, &w0, ws[20], p[6]); + word3_muladd(&w2, &w1, &w0, ws[21], p[5]); + word3_muladd(&w2, &w1, &w0, ws[22], p[4]); + word3_muladd(&w2, &w1, &w0, ws[23], p[3]); + word3_add(&w2, &w1, &w0, z[26]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[4], p[23]); + word3_muladd(&w2, &w1, &w0, ws[5], p[22]); + word3_muladd(&w2, &w1, &w0, ws[6], p[21]); + word3_muladd(&w2, &w1, &w0, ws[7], p[20]); + word3_muladd(&w2, &w1, &w0, ws[8], p[19]); + word3_muladd(&w2, &w1, &w0, ws[9], p[18]); + word3_muladd(&w2, &w1, &w0, ws[10], p[17]); + word3_muladd(&w2, &w1, &w0, ws[11], p[16]); + word3_muladd(&w2, &w1, &w0, ws[12], p[15]); + word3_muladd(&w2, &w1, &w0, ws[13], p[14]); + word3_muladd(&w2, &w1, &w0, ws[14], p[13]); + word3_muladd(&w2, &w1, &w0, ws[15], p[12]); + word3_muladd(&w2, &w1, &w0, ws[16], p[11]); + word3_muladd(&w2, &w1, &w0, ws[17], p[10]); + word3_muladd(&w2, &w1, &w0, ws[18], p[9]); + word3_muladd(&w2, &w1, &w0, ws[19], p[8]); + word3_muladd(&w2, &w1, &w0, ws[20], p[7]); + word3_muladd(&w2, &w1, &w0, ws[21], p[6]); + word3_muladd(&w2, &w1, &w0, ws[22], p[5]); + word3_muladd(&w2, &w1, &w0, ws[23], p[4]); + word3_add(&w2, &w1, &w0, z[27]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[5], p[23]); + word3_muladd(&w2, &w1, &w0, ws[6], p[22]); + word3_muladd(&w2, &w1, &w0, ws[7], p[21]); + word3_muladd(&w2, &w1, &w0, ws[8], p[20]); + word3_muladd(&w2, &w1, &w0, ws[9], p[19]); + word3_muladd(&w2, &w1, &w0, ws[10], p[18]); + word3_muladd(&w2, &w1, &w0, ws[11], p[17]); + word3_muladd(&w2, &w1, &w0, ws[12], p[16]); + word3_muladd(&w2, &w1, &w0, ws[13], p[15]); + word3_muladd(&w2, &w1, &w0, ws[14], p[14]); + word3_muladd(&w2, &w1, &w0, ws[15], p[13]); + word3_muladd(&w2, &w1, &w0, ws[16], p[12]); + word3_muladd(&w2, &w1, &w0, ws[17], p[11]); + word3_muladd(&w2, &w1, &w0, ws[18], p[10]); + word3_muladd(&w2, &w1, &w0, ws[19], p[9]); + word3_muladd(&w2, &w1, &w0, ws[20], p[8]); + word3_muladd(&w2, &w1, &w0, ws[21], p[7]); + word3_muladd(&w2, &w1, &w0, ws[22], p[6]); + word3_muladd(&w2, &w1, &w0, ws[23], p[5]); + word3_add(&w2, &w1, &w0, z[28]); + ws[4] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[6], p[23]); + word3_muladd(&w2, &w1, &w0, ws[7], p[22]); + word3_muladd(&w2, &w1, &w0, ws[8], p[21]); + word3_muladd(&w2, &w1, &w0, ws[9], p[20]); + word3_muladd(&w2, &w1, &w0, ws[10], p[19]); + word3_muladd(&w2, &w1, &w0, ws[11], p[18]); + word3_muladd(&w2, &w1, &w0, ws[12], p[17]); + word3_muladd(&w2, &w1, &w0, ws[13], p[16]); + word3_muladd(&w2, &w1, &w0, ws[14], p[15]); + word3_muladd(&w2, &w1, &w0, ws[15], p[14]); + word3_muladd(&w2, &w1, &w0, ws[16], p[13]); + word3_muladd(&w2, &w1, &w0, ws[17], p[12]); + word3_muladd(&w2, &w1, &w0, ws[18], p[11]); + word3_muladd(&w2, &w1, &w0, ws[19], p[10]); + word3_muladd(&w2, &w1, &w0, ws[20], p[9]); + word3_muladd(&w2, &w1, &w0, ws[21], p[8]); + word3_muladd(&w2, &w1, &w0, ws[22], p[7]); + word3_muladd(&w2, &w1, &w0, ws[23], p[6]); + word3_add(&w2, &w1, &w0, z[29]); + ws[5] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[7], p[23]); + word3_muladd(&w2, &w1, &w0, ws[8], p[22]); + word3_muladd(&w2, &w1, &w0, ws[9], p[21]); + word3_muladd(&w2, &w1, &w0, ws[10], p[20]); + word3_muladd(&w2, &w1, &w0, ws[11], p[19]); + word3_muladd(&w2, &w1, &w0, ws[12], p[18]); + word3_muladd(&w2, &w1, &w0, ws[13], p[17]); + word3_muladd(&w2, &w1, &w0, ws[14], p[16]); + word3_muladd(&w2, &w1, &w0, ws[15], p[15]); + word3_muladd(&w2, &w1, &w0, ws[16], p[14]); + word3_muladd(&w2, &w1, &w0, ws[17], p[13]); + word3_muladd(&w2, &w1, &w0, ws[18], p[12]); + word3_muladd(&w2, &w1, &w0, ws[19], p[11]); + word3_muladd(&w2, &w1, &w0, ws[20], p[10]); + word3_muladd(&w2, &w1, &w0, ws[21], p[9]); + word3_muladd(&w2, &w1, &w0, ws[22], p[8]); + word3_muladd(&w2, &w1, &w0, ws[23], p[7]); + word3_add(&w2, &w1, &w0, z[30]); + ws[6] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[8], p[23]); + word3_muladd(&w2, &w1, &w0, ws[9], p[22]); + word3_muladd(&w2, &w1, &w0, ws[10], p[21]); + word3_muladd(&w2, &w1, &w0, ws[11], p[20]); + word3_muladd(&w2, &w1, &w0, ws[12], p[19]); + word3_muladd(&w2, &w1, &w0, ws[13], p[18]); + word3_muladd(&w2, &w1, &w0, ws[14], p[17]); + word3_muladd(&w2, &w1, &w0, ws[15], p[16]); + word3_muladd(&w2, &w1, &w0, ws[16], p[15]); + word3_muladd(&w2, &w1, &w0, ws[17], p[14]); + word3_muladd(&w2, &w1, &w0, ws[18], p[13]); + word3_muladd(&w2, &w1, &w0, ws[19], p[12]); + word3_muladd(&w2, &w1, &w0, ws[20], p[11]); + word3_muladd(&w2, &w1, &w0, ws[21], p[10]); + word3_muladd(&w2, &w1, &w0, ws[22], p[9]); + word3_muladd(&w2, &w1, &w0, ws[23], p[8]); + word3_add(&w2, &w1, &w0, z[31]); + ws[7] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[9], p[23]); + word3_muladd(&w2, &w1, &w0, ws[10], p[22]); + word3_muladd(&w2, &w1, &w0, ws[11], p[21]); + word3_muladd(&w2, &w1, &w0, ws[12], p[20]); + word3_muladd(&w2, &w1, &w0, ws[13], p[19]); + word3_muladd(&w2, &w1, &w0, ws[14], p[18]); + word3_muladd(&w2, &w1, &w0, ws[15], p[17]); + word3_muladd(&w2, &w1, &w0, ws[16], p[16]); + word3_muladd(&w2, &w1, &w0, ws[17], p[15]); + word3_muladd(&w2, &w1, &w0, ws[18], p[14]); + word3_muladd(&w2, &w1, &w0, ws[19], p[13]); + word3_muladd(&w2, &w1, &w0, ws[20], p[12]); + word3_muladd(&w2, &w1, &w0, ws[21], p[11]); + word3_muladd(&w2, &w1, &w0, ws[22], p[10]); + word3_muladd(&w2, &w1, &w0, ws[23], p[9]); + word3_add(&w2, &w1, &w0, z[32]); + ws[8] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[10], p[23]); + word3_muladd(&w2, &w1, &w0, ws[11], p[22]); + word3_muladd(&w2, &w1, &w0, ws[12], p[21]); + word3_muladd(&w2, &w1, &w0, ws[13], p[20]); + word3_muladd(&w2, &w1, &w0, ws[14], p[19]); + word3_muladd(&w2, &w1, &w0, ws[15], p[18]); + word3_muladd(&w2, &w1, &w0, ws[16], p[17]); + word3_muladd(&w2, &w1, &w0, ws[17], p[16]); + word3_muladd(&w2, &w1, &w0, ws[18], p[15]); + word3_muladd(&w2, &w1, &w0, ws[19], p[14]); + word3_muladd(&w2, &w1, &w0, ws[20], p[13]); + word3_muladd(&w2, &w1, &w0, ws[21], p[12]); + word3_muladd(&w2, &w1, &w0, ws[22], p[11]); + word3_muladd(&w2, &w1, &w0, ws[23], p[10]); + word3_add(&w2, &w1, &w0, z[33]); + ws[9] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[11], p[23]); + word3_muladd(&w2, &w1, &w0, ws[12], p[22]); + word3_muladd(&w2, &w1, &w0, ws[13], p[21]); + word3_muladd(&w2, &w1, &w0, ws[14], p[20]); + word3_muladd(&w2, &w1, &w0, ws[15], p[19]); + word3_muladd(&w2, &w1, &w0, ws[16], p[18]); + word3_muladd(&w2, &w1, &w0, ws[17], p[17]); + word3_muladd(&w2, &w1, &w0, ws[18], p[16]); + word3_muladd(&w2, &w1, &w0, ws[19], p[15]); + word3_muladd(&w2, &w1, &w0, ws[20], p[14]); + word3_muladd(&w2, &w1, &w0, ws[21], p[13]); + word3_muladd(&w2, &w1, &w0, ws[22], p[12]); + word3_muladd(&w2, &w1, &w0, ws[23], p[11]); + word3_add(&w2, &w1, &w0, z[34]); + ws[10] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[12], p[23]); + word3_muladd(&w2, &w1, &w0, ws[13], p[22]); + word3_muladd(&w2, &w1, &w0, ws[14], p[21]); + word3_muladd(&w2, &w1, &w0, ws[15], p[20]); + word3_muladd(&w2, &w1, &w0, ws[16], p[19]); + word3_muladd(&w2, &w1, &w0, ws[17], p[18]); + word3_muladd(&w2, &w1, &w0, ws[18], p[17]); + word3_muladd(&w2, &w1, &w0, ws[19], p[16]); + word3_muladd(&w2, &w1, &w0, ws[20], p[15]); + word3_muladd(&w2, &w1, &w0, ws[21], p[14]); + word3_muladd(&w2, &w1, &w0, ws[22], p[13]); + word3_muladd(&w2, &w1, &w0, ws[23], p[12]); + word3_add(&w2, &w1, &w0, z[35]); + ws[11] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[13], p[23]); + word3_muladd(&w2, &w1, &w0, ws[14], p[22]); + word3_muladd(&w2, &w1, &w0, ws[15], p[21]); + word3_muladd(&w2, &w1, &w0, ws[16], p[20]); + word3_muladd(&w2, &w1, &w0, ws[17], p[19]); + word3_muladd(&w2, &w1, &w0, ws[18], p[18]); + word3_muladd(&w2, &w1, &w0, ws[19], p[17]); + word3_muladd(&w2, &w1, &w0, ws[20], p[16]); + word3_muladd(&w2, &w1, &w0, ws[21], p[15]); + word3_muladd(&w2, &w1, &w0, ws[22], p[14]); + word3_muladd(&w2, &w1, &w0, ws[23], p[13]); + word3_add(&w2, &w1, &w0, z[36]); + ws[12] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[14], p[23]); + word3_muladd(&w2, &w1, &w0, ws[15], p[22]); + word3_muladd(&w2, &w1, &w0, ws[16], p[21]); + word3_muladd(&w2, &w1, &w0, ws[17], p[20]); + word3_muladd(&w2, &w1, &w0, ws[18], p[19]); + word3_muladd(&w2, &w1, &w0, ws[19], p[18]); + word3_muladd(&w2, &w1, &w0, ws[20], p[17]); + word3_muladd(&w2, &w1, &w0, ws[21], p[16]); + word3_muladd(&w2, &w1, &w0, ws[22], p[15]); + word3_muladd(&w2, &w1, &w0, ws[23], p[14]); + word3_add(&w2, &w1, &w0, z[37]); + ws[13] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[15], p[23]); + word3_muladd(&w2, &w1, &w0, ws[16], p[22]); + word3_muladd(&w2, &w1, &w0, ws[17], p[21]); + word3_muladd(&w2, &w1, &w0, ws[18], p[20]); + word3_muladd(&w2, &w1, &w0, ws[19], p[19]); + word3_muladd(&w2, &w1, &w0, ws[20], p[18]); + word3_muladd(&w2, &w1, &w0, ws[21], p[17]); + word3_muladd(&w2, &w1, &w0, ws[22], p[16]); + word3_muladd(&w2, &w1, &w0, ws[23], p[15]); + word3_add(&w2, &w1, &w0, z[38]); + ws[14] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[16], p[23]); + word3_muladd(&w2, &w1, &w0, ws[17], p[22]); + word3_muladd(&w2, &w1, &w0, ws[18], p[21]); + word3_muladd(&w2, &w1, &w0, ws[19], p[20]); + word3_muladd(&w2, &w1, &w0, ws[20], p[19]); + word3_muladd(&w2, &w1, &w0, ws[21], p[18]); + word3_muladd(&w2, &w1, &w0, ws[22], p[17]); + word3_muladd(&w2, &w1, &w0, ws[23], p[16]); + word3_add(&w2, &w1, &w0, z[39]); + ws[15] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[17], p[23]); + word3_muladd(&w2, &w1, &w0, ws[18], p[22]); + word3_muladd(&w2, &w1, &w0, ws[19], p[21]); + word3_muladd(&w2, &w1, &w0, ws[20], p[20]); + word3_muladd(&w2, &w1, &w0, ws[21], p[19]); + word3_muladd(&w2, &w1, &w0, ws[22], p[18]); + word3_muladd(&w2, &w1, &w0, ws[23], p[17]); + word3_add(&w2, &w1, &w0, z[40]); + ws[16] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[18], p[23]); + word3_muladd(&w2, &w1, &w0, ws[19], p[22]); + word3_muladd(&w2, &w1, &w0, ws[20], p[21]); + word3_muladd(&w2, &w1, &w0, ws[21], p[20]); + word3_muladd(&w2, &w1, &w0, ws[22], p[19]); + word3_muladd(&w2, &w1, &w0, ws[23], p[18]); + word3_add(&w2, &w1, &w0, z[41]); + ws[17] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[19], p[23]); + word3_muladd(&w2, &w1, &w0, ws[20], p[22]); + word3_muladd(&w2, &w1, &w0, ws[21], p[21]); + word3_muladd(&w2, &w1, &w0, ws[22], p[20]); + word3_muladd(&w2, &w1, &w0, ws[23], p[19]); + word3_add(&w2, &w1, &w0, z[42]); + ws[18] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[20], p[23]); + word3_muladd(&w2, &w1, &w0, ws[21], p[22]); + word3_muladd(&w2, &w1, &w0, ws[22], p[21]); + word3_muladd(&w2, &w1, &w0, ws[23], p[20]); + word3_add(&w2, &w1, &w0, z[43]); + ws[19] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[21], p[23]); + word3_muladd(&w2, &w1, &w0, ws[22], p[22]); + word3_muladd(&w2, &w1, &w0, ws[23], p[21]); + word3_add(&w2, &w1, &w0, z[44]); + ws[20] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[22], p[23]); + word3_muladd(&w2, &w1, &w0, ws[23], p[22]); + word3_add(&w2, &w1, &w0, z[45]); + ws[21] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[23], p[23]); + word3_add(&w2, &w1, &w0, z[46]); + ws[22] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[47]); + ws[23] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[49]); + ws[24] = w0; + ws[25] = w1; + word borrow = bigint_sub3(ws + 24 + 1, ws, 24 + 1, p, 24); + CT::conditional_copy_mem(borrow, z, ws, ws + 25, 25); + clear_mem(z + 24, 2*(24+1) - 24); + } + +void bigint_monty_redc_32(word z[], const word p[32], word p_dash, word ws[]) + { + word w2 = 0, w1 = 0, w0 = 0; + w0 = z[0]; + ws[0] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[0], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[1]); + word3_add(&w2, &w1, &w0, z[1]); + ws[1] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[1], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[2]); + word3_muladd(&w2, &w1, &w0, ws[1], p[1]); + word3_add(&w2, &w1, &w0, z[2]); + ws[2] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[2], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[3]); + word3_muladd(&w2, &w1, &w0, ws[1], p[2]); + word3_muladd(&w2, &w1, &w0, ws[2], p[1]); + word3_add(&w2, &w1, &w0, z[3]); + ws[3] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[3], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[4]); + word3_muladd(&w2, &w1, &w0, ws[1], p[3]); + word3_muladd(&w2, &w1, &w0, ws[2], p[2]); + word3_muladd(&w2, &w1, &w0, ws[3], p[1]); + word3_add(&w2, &w1, &w0, z[4]); + ws[4] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[4], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[5]); + word3_muladd(&w2, &w1, &w0, ws[1], p[4]); + word3_muladd(&w2, &w1, &w0, ws[2], p[3]); + word3_muladd(&w2, &w1, &w0, ws[3], p[2]); + word3_muladd(&w2, &w1, &w0, ws[4], p[1]); + word3_add(&w2, &w1, &w0, z[5]); + ws[5] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[5], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[6]); + word3_muladd(&w2, &w1, &w0, ws[1], p[5]); + word3_muladd(&w2, &w1, &w0, ws[2], p[4]); + word3_muladd(&w2, &w1, &w0, ws[3], p[3]); + word3_muladd(&w2, &w1, &w0, ws[4], p[2]); + word3_muladd(&w2, &w1, &w0, ws[5], p[1]); + word3_add(&w2, &w1, &w0, z[6]); + ws[6] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[6], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[7]); + word3_muladd(&w2, &w1, &w0, ws[1], p[6]); + word3_muladd(&w2, &w1, &w0, ws[2], p[5]); + word3_muladd(&w2, &w1, &w0, ws[3], p[4]); + word3_muladd(&w2, &w1, &w0, ws[4], p[3]); + word3_muladd(&w2, &w1, &w0, ws[5], p[2]); + word3_muladd(&w2, &w1, &w0, ws[6], p[1]); + word3_add(&w2, &w1, &w0, z[7]); + ws[7] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[7], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[8]); + word3_muladd(&w2, &w1, &w0, ws[1], p[7]); + word3_muladd(&w2, &w1, &w0, ws[2], p[6]); + word3_muladd(&w2, &w1, &w0, ws[3], p[5]); + word3_muladd(&w2, &w1, &w0, ws[4], p[4]); + word3_muladd(&w2, &w1, &w0, ws[5], p[3]); + word3_muladd(&w2, &w1, &w0, ws[6], p[2]); + word3_muladd(&w2, &w1, &w0, ws[7], p[1]); + word3_add(&w2, &w1, &w0, z[8]); + ws[8] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[8], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[9]); + word3_muladd(&w2, &w1, &w0, ws[1], p[8]); + word3_muladd(&w2, &w1, &w0, ws[2], p[7]); + word3_muladd(&w2, &w1, &w0, ws[3], p[6]); + word3_muladd(&w2, &w1, &w0, ws[4], p[5]); + word3_muladd(&w2, &w1, &w0, ws[5], p[4]); + word3_muladd(&w2, &w1, &w0, ws[6], p[3]); + word3_muladd(&w2, &w1, &w0, ws[7], p[2]); + word3_muladd(&w2, &w1, &w0, ws[8], p[1]); + word3_add(&w2, &w1, &w0, z[9]); + ws[9] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[9], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[10]); + word3_muladd(&w2, &w1, &w0, ws[1], p[9]); + word3_muladd(&w2, &w1, &w0, ws[2], p[8]); + word3_muladd(&w2, &w1, &w0, ws[3], p[7]); + word3_muladd(&w2, &w1, &w0, ws[4], p[6]); + word3_muladd(&w2, &w1, &w0, ws[5], p[5]); + word3_muladd(&w2, &w1, &w0, ws[6], p[4]); + word3_muladd(&w2, &w1, &w0, ws[7], p[3]); + word3_muladd(&w2, &w1, &w0, ws[8], p[2]); + word3_muladd(&w2, &w1, &w0, ws[9], p[1]); + word3_add(&w2, &w1, &w0, z[10]); + ws[10] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[10], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[11]); + word3_muladd(&w2, &w1, &w0, ws[1], p[10]); + word3_muladd(&w2, &w1, &w0, ws[2], p[9]); + word3_muladd(&w2, &w1, &w0, ws[3], p[8]); + word3_muladd(&w2, &w1, &w0, ws[4], p[7]); + word3_muladd(&w2, &w1, &w0, ws[5], p[6]); + word3_muladd(&w2, &w1, &w0, ws[6], p[5]); + word3_muladd(&w2, &w1, &w0, ws[7], p[4]); + word3_muladd(&w2, &w1, &w0, ws[8], p[3]); + word3_muladd(&w2, &w1, &w0, ws[9], p[2]); + word3_muladd(&w2, &w1, &w0, ws[10], p[1]); + word3_add(&w2, &w1, &w0, z[11]); + ws[11] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[11], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[12]); + word3_muladd(&w2, &w1, &w0, ws[1], p[11]); + word3_muladd(&w2, &w1, &w0, ws[2], p[10]); + word3_muladd(&w2, &w1, &w0, ws[3], p[9]); + word3_muladd(&w2, &w1, &w0, ws[4], p[8]); + word3_muladd(&w2, &w1, &w0, ws[5], p[7]); + word3_muladd(&w2, &w1, &w0, ws[6], p[6]); + word3_muladd(&w2, &w1, &w0, ws[7], p[5]); + word3_muladd(&w2, &w1, &w0, ws[8], p[4]); + word3_muladd(&w2, &w1, &w0, ws[9], p[3]); + word3_muladd(&w2, &w1, &w0, ws[10], p[2]); + word3_muladd(&w2, &w1, &w0, ws[11], p[1]); + word3_add(&w2, &w1, &w0, z[12]); + ws[12] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[12], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[13]); + word3_muladd(&w2, &w1, &w0, ws[1], p[12]); + word3_muladd(&w2, &w1, &w0, ws[2], p[11]); + word3_muladd(&w2, &w1, &w0, ws[3], p[10]); + word3_muladd(&w2, &w1, &w0, ws[4], p[9]); + word3_muladd(&w2, &w1, &w0, ws[5], p[8]); + word3_muladd(&w2, &w1, &w0, ws[6], p[7]); + word3_muladd(&w2, &w1, &w0, ws[7], p[6]); + word3_muladd(&w2, &w1, &w0, ws[8], p[5]); + word3_muladd(&w2, &w1, &w0, ws[9], p[4]); + word3_muladd(&w2, &w1, &w0, ws[10], p[3]); + word3_muladd(&w2, &w1, &w0, ws[11], p[2]); + word3_muladd(&w2, &w1, &w0, ws[12], p[1]); + word3_add(&w2, &w1, &w0, z[13]); + ws[13] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[13], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[14]); + word3_muladd(&w2, &w1, &w0, ws[1], p[13]); + word3_muladd(&w2, &w1, &w0, ws[2], p[12]); + word3_muladd(&w2, &w1, &w0, ws[3], p[11]); + word3_muladd(&w2, &w1, &w0, ws[4], p[10]); + word3_muladd(&w2, &w1, &w0, ws[5], p[9]); + word3_muladd(&w2, &w1, &w0, ws[6], p[8]); + word3_muladd(&w2, &w1, &w0, ws[7], p[7]); + word3_muladd(&w2, &w1, &w0, ws[8], p[6]); + word3_muladd(&w2, &w1, &w0, ws[9], p[5]); + word3_muladd(&w2, &w1, &w0, ws[10], p[4]); + word3_muladd(&w2, &w1, &w0, ws[11], p[3]); + word3_muladd(&w2, &w1, &w0, ws[12], p[2]); + word3_muladd(&w2, &w1, &w0, ws[13], p[1]); + word3_add(&w2, &w1, &w0, z[14]); + ws[14] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[14], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[15]); + word3_muladd(&w2, &w1, &w0, ws[1], p[14]); + word3_muladd(&w2, &w1, &w0, ws[2], p[13]); + word3_muladd(&w2, &w1, &w0, ws[3], p[12]); + word3_muladd(&w2, &w1, &w0, ws[4], p[11]); + word3_muladd(&w2, &w1, &w0, ws[5], p[10]); + word3_muladd(&w2, &w1, &w0, ws[6], p[9]); + word3_muladd(&w2, &w1, &w0, ws[7], p[8]); + word3_muladd(&w2, &w1, &w0, ws[8], p[7]); + word3_muladd(&w2, &w1, &w0, ws[9], p[6]); + word3_muladd(&w2, &w1, &w0, ws[10], p[5]); + word3_muladd(&w2, &w1, &w0, ws[11], p[4]); + word3_muladd(&w2, &w1, &w0, ws[12], p[3]); + word3_muladd(&w2, &w1, &w0, ws[13], p[2]); + word3_muladd(&w2, &w1, &w0, ws[14], p[1]); + word3_add(&w2, &w1, &w0, z[15]); + ws[15] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[15], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[16]); + word3_muladd(&w2, &w1, &w0, ws[1], p[15]); + word3_muladd(&w2, &w1, &w0, ws[2], p[14]); + word3_muladd(&w2, &w1, &w0, ws[3], p[13]); + word3_muladd(&w2, &w1, &w0, ws[4], p[12]); + word3_muladd(&w2, &w1, &w0, ws[5], p[11]); + word3_muladd(&w2, &w1, &w0, ws[6], p[10]); + word3_muladd(&w2, &w1, &w0, ws[7], p[9]); + word3_muladd(&w2, &w1, &w0, ws[8], p[8]); + word3_muladd(&w2, &w1, &w0, ws[9], p[7]); + word3_muladd(&w2, &w1, &w0, ws[10], p[6]); + word3_muladd(&w2, &w1, &w0, ws[11], p[5]); + word3_muladd(&w2, &w1, &w0, ws[12], p[4]); + word3_muladd(&w2, &w1, &w0, ws[13], p[3]); + word3_muladd(&w2, &w1, &w0, ws[14], p[2]); + word3_muladd(&w2, &w1, &w0, ws[15], p[1]); + word3_add(&w2, &w1, &w0, z[16]); + ws[16] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[16], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[17]); + word3_muladd(&w2, &w1, &w0, ws[1], p[16]); + word3_muladd(&w2, &w1, &w0, ws[2], p[15]); + word3_muladd(&w2, &w1, &w0, ws[3], p[14]); + word3_muladd(&w2, &w1, &w0, ws[4], p[13]); + word3_muladd(&w2, &w1, &w0, ws[5], p[12]); + word3_muladd(&w2, &w1, &w0, ws[6], p[11]); + word3_muladd(&w2, &w1, &w0, ws[7], p[10]); + word3_muladd(&w2, &w1, &w0, ws[8], p[9]); + word3_muladd(&w2, &w1, &w0, ws[9], p[8]); + word3_muladd(&w2, &w1, &w0, ws[10], p[7]); + word3_muladd(&w2, &w1, &w0, ws[11], p[6]); + word3_muladd(&w2, &w1, &w0, ws[12], p[5]); + word3_muladd(&w2, &w1, &w0, ws[13], p[4]); + word3_muladd(&w2, &w1, &w0, ws[14], p[3]); + word3_muladd(&w2, &w1, &w0, ws[15], p[2]); + word3_muladd(&w2, &w1, &w0, ws[16], p[1]); + word3_add(&w2, &w1, &w0, z[17]); + ws[17] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[17], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[18]); + word3_muladd(&w2, &w1, &w0, ws[1], p[17]); + word3_muladd(&w2, &w1, &w0, ws[2], p[16]); + word3_muladd(&w2, &w1, &w0, ws[3], p[15]); + word3_muladd(&w2, &w1, &w0, ws[4], p[14]); + word3_muladd(&w2, &w1, &w0, ws[5], p[13]); + word3_muladd(&w2, &w1, &w0, ws[6], p[12]); + word3_muladd(&w2, &w1, &w0, ws[7], p[11]); + word3_muladd(&w2, &w1, &w0, ws[8], p[10]); + word3_muladd(&w2, &w1, &w0, ws[9], p[9]); + word3_muladd(&w2, &w1, &w0, ws[10], p[8]); + word3_muladd(&w2, &w1, &w0, ws[11], p[7]); + word3_muladd(&w2, &w1, &w0, ws[12], p[6]); + word3_muladd(&w2, &w1, &w0, ws[13], p[5]); + word3_muladd(&w2, &w1, &w0, ws[14], p[4]); + word3_muladd(&w2, &w1, &w0, ws[15], p[3]); + word3_muladd(&w2, &w1, &w0, ws[16], p[2]); + word3_muladd(&w2, &w1, &w0, ws[17], p[1]); + word3_add(&w2, &w1, &w0, z[18]); + ws[18] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[18], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[19]); + word3_muladd(&w2, &w1, &w0, ws[1], p[18]); + word3_muladd(&w2, &w1, &w0, ws[2], p[17]); + word3_muladd(&w2, &w1, &w0, ws[3], p[16]); + word3_muladd(&w2, &w1, &w0, ws[4], p[15]); + word3_muladd(&w2, &w1, &w0, ws[5], p[14]); + word3_muladd(&w2, &w1, &w0, ws[6], p[13]); + word3_muladd(&w2, &w1, &w0, ws[7], p[12]); + word3_muladd(&w2, &w1, &w0, ws[8], p[11]); + word3_muladd(&w2, &w1, &w0, ws[9], p[10]); + word3_muladd(&w2, &w1, &w0, ws[10], p[9]); + word3_muladd(&w2, &w1, &w0, ws[11], p[8]); + word3_muladd(&w2, &w1, &w0, ws[12], p[7]); + word3_muladd(&w2, &w1, &w0, ws[13], p[6]); + word3_muladd(&w2, &w1, &w0, ws[14], p[5]); + word3_muladd(&w2, &w1, &w0, ws[15], p[4]); + word3_muladd(&w2, &w1, &w0, ws[16], p[3]); + word3_muladd(&w2, &w1, &w0, ws[17], p[2]); + word3_muladd(&w2, &w1, &w0, ws[18], p[1]); + word3_add(&w2, &w1, &w0, z[19]); + ws[19] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[19], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[20]); + word3_muladd(&w2, &w1, &w0, ws[1], p[19]); + word3_muladd(&w2, &w1, &w0, ws[2], p[18]); + word3_muladd(&w2, &w1, &w0, ws[3], p[17]); + word3_muladd(&w2, &w1, &w0, ws[4], p[16]); + word3_muladd(&w2, &w1, &w0, ws[5], p[15]); + word3_muladd(&w2, &w1, &w0, ws[6], p[14]); + word3_muladd(&w2, &w1, &w0, ws[7], p[13]); + word3_muladd(&w2, &w1, &w0, ws[8], p[12]); + word3_muladd(&w2, &w1, &w0, ws[9], p[11]); + word3_muladd(&w2, &w1, &w0, ws[10], p[10]); + word3_muladd(&w2, &w1, &w0, ws[11], p[9]); + word3_muladd(&w2, &w1, &w0, ws[12], p[8]); + word3_muladd(&w2, &w1, &w0, ws[13], p[7]); + word3_muladd(&w2, &w1, &w0, ws[14], p[6]); + word3_muladd(&w2, &w1, &w0, ws[15], p[5]); + word3_muladd(&w2, &w1, &w0, ws[16], p[4]); + word3_muladd(&w2, &w1, &w0, ws[17], p[3]); + word3_muladd(&w2, &w1, &w0, ws[18], p[2]); + word3_muladd(&w2, &w1, &w0, ws[19], p[1]); + word3_add(&w2, &w1, &w0, z[20]); + ws[20] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[20], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[21]); + word3_muladd(&w2, &w1, &w0, ws[1], p[20]); + word3_muladd(&w2, &w1, &w0, ws[2], p[19]); + word3_muladd(&w2, &w1, &w0, ws[3], p[18]); + word3_muladd(&w2, &w1, &w0, ws[4], p[17]); + word3_muladd(&w2, &w1, &w0, ws[5], p[16]); + word3_muladd(&w2, &w1, &w0, ws[6], p[15]); + word3_muladd(&w2, &w1, &w0, ws[7], p[14]); + word3_muladd(&w2, &w1, &w0, ws[8], p[13]); + word3_muladd(&w2, &w1, &w0, ws[9], p[12]); + word3_muladd(&w2, &w1, &w0, ws[10], p[11]); + word3_muladd(&w2, &w1, &w0, ws[11], p[10]); + word3_muladd(&w2, &w1, &w0, ws[12], p[9]); + word3_muladd(&w2, &w1, &w0, ws[13], p[8]); + word3_muladd(&w2, &w1, &w0, ws[14], p[7]); + word3_muladd(&w2, &w1, &w0, ws[15], p[6]); + word3_muladd(&w2, &w1, &w0, ws[16], p[5]); + word3_muladd(&w2, &w1, &w0, ws[17], p[4]); + word3_muladd(&w2, &w1, &w0, ws[18], p[3]); + word3_muladd(&w2, &w1, &w0, ws[19], p[2]); + word3_muladd(&w2, &w1, &w0, ws[20], p[1]); + word3_add(&w2, &w1, &w0, z[21]); + ws[21] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[21], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[22]); + word3_muladd(&w2, &w1, &w0, ws[1], p[21]); + word3_muladd(&w2, &w1, &w0, ws[2], p[20]); + word3_muladd(&w2, &w1, &w0, ws[3], p[19]); + word3_muladd(&w2, &w1, &w0, ws[4], p[18]); + word3_muladd(&w2, &w1, &w0, ws[5], p[17]); + word3_muladd(&w2, &w1, &w0, ws[6], p[16]); + word3_muladd(&w2, &w1, &w0, ws[7], p[15]); + word3_muladd(&w2, &w1, &w0, ws[8], p[14]); + word3_muladd(&w2, &w1, &w0, ws[9], p[13]); + word3_muladd(&w2, &w1, &w0, ws[10], p[12]); + word3_muladd(&w2, &w1, &w0, ws[11], p[11]); + word3_muladd(&w2, &w1, &w0, ws[12], p[10]); + word3_muladd(&w2, &w1, &w0, ws[13], p[9]); + word3_muladd(&w2, &w1, &w0, ws[14], p[8]); + word3_muladd(&w2, &w1, &w0, ws[15], p[7]); + word3_muladd(&w2, &w1, &w0, ws[16], p[6]); + word3_muladd(&w2, &w1, &w0, ws[17], p[5]); + word3_muladd(&w2, &w1, &w0, ws[18], p[4]); + word3_muladd(&w2, &w1, &w0, ws[19], p[3]); + word3_muladd(&w2, &w1, &w0, ws[20], p[2]); + word3_muladd(&w2, &w1, &w0, ws[21], p[1]); + word3_add(&w2, &w1, &w0, z[22]); + ws[22] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[22], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[23]); + word3_muladd(&w2, &w1, &w0, ws[1], p[22]); + word3_muladd(&w2, &w1, &w0, ws[2], p[21]); + word3_muladd(&w2, &w1, &w0, ws[3], p[20]); + word3_muladd(&w2, &w1, &w0, ws[4], p[19]); + word3_muladd(&w2, &w1, &w0, ws[5], p[18]); + word3_muladd(&w2, &w1, &w0, ws[6], p[17]); + word3_muladd(&w2, &w1, &w0, ws[7], p[16]); + word3_muladd(&w2, &w1, &w0, ws[8], p[15]); + word3_muladd(&w2, &w1, &w0, ws[9], p[14]); + word3_muladd(&w2, &w1, &w0, ws[10], p[13]); + word3_muladd(&w2, &w1, &w0, ws[11], p[12]); + word3_muladd(&w2, &w1, &w0, ws[12], p[11]); + word3_muladd(&w2, &w1, &w0, ws[13], p[10]); + word3_muladd(&w2, &w1, &w0, ws[14], p[9]); + word3_muladd(&w2, &w1, &w0, ws[15], p[8]); + word3_muladd(&w2, &w1, &w0, ws[16], p[7]); + word3_muladd(&w2, &w1, &w0, ws[17], p[6]); + word3_muladd(&w2, &w1, &w0, ws[18], p[5]); + word3_muladd(&w2, &w1, &w0, ws[19], p[4]); + word3_muladd(&w2, &w1, &w0, ws[20], p[3]); + word3_muladd(&w2, &w1, &w0, ws[21], p[2]); + word3_muladd(&w2, &w1, &w0, ws[22], p[1]); + word3_add(&w2, &w1, &w0, z[23]); + ws[23] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[23], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[24]); + word3_muladd(&w2, &w1, &w0, ws[1], p[23]); + word3_muladd(&w2, &w1, &w0, ws[2], p[22]); + word3_muladd(&w2, &w1, &w0, ws[3], p[21]); + word3_muladd(&w2, &w1, &w0, ws[4], p[20]); + word3_muladd(&w2, &w1, &w0, ws[5], p[19]); + word3_muladd(&w2, &w1, &w0, ws[6], p[18]); + word3_muladd(&w2, &w1, &w0, ws[7], p[17]); + word3_muladd(&w2, &w1, &w0, ws[8], p[16]); + word3_muladd(&w2, &w1, &w0, ws[9], p[15]); + word3_muladd(&w2, &w1, &w0, ws[10], p[14]); + word3_muladd(&w2, &w1, &w0, ws[11], p[13]); + word3_muladd(&w2, &w1, &w0, ws[12], p[12]); + word3_muladd(&w2, &w1, &w0, ws[13], p[11]); + word3_muladd(&w2, &w1, &w0, ws[14], p[10]); + word3_muladd(&w2, &w1, &w0, ws[15], p[9]); + word3_muladd(&w2, &w1, &w0, ws[16], p[8]); + word3_muladd(&w2, &w1, &w0, ws[17], p[7]); + word3_muladd(&w2, &w1, &w0, ws[18], p[6]); + word3_muladd(&w2, &w1, &w0, ws[19], p[5]); + word3_muladd(&w2, &w1, &w0, ws[20], p[4]); + word3_muladd(&w2, &w1, &w0, ws[21], p[3]); + word3_muladd(&w2, &w1, &w0, ws[22], p[2]); + word3_muladd(&w2, &w1, &w0, ws[23], p[1]); + word3_add(&w2, &w1, &w0, z[24]); + ws[24] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[24], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[25]); + word3_muladd(&w2, &w1, &w0, ws[1], p[24]); + word3_muladd(&w2, &w1, &w0, ws[2], p[23]); + word3_muladd(&w2, &w1, &w0, ws[3], p[22]); + word3_muladd(&w2, &w1, &w0, ws[4], p[21]); + word3_muladd(&w2, &w1, &w0, ws[5], p[20]); + word3_muladd(&w2, &w1, &w0, ws[6], p[19]); + word3_muladd(&w2, &w1, &w0, ws[7], p[18]); + word3_muladd(&w2, &w1, &w0, ws[8], p[17]); + word3_muladd(&w2, &w1, &w0, ws[9], p[16]); + word3_muladd(&w2, &w1, &w0, ws[10], p[15]); + word3_muladd(&w2, &w1, &w0, ws[11], p[14]); + word3_muladd(&w2, &w1, &w0, ws[12], p[13]); + word3_muladd(&w2, &w1, &w0, ws[13], p[12]); + word3_muladd(&w2, &w1, &w0, ws[14], p[11]); + word3_muladd(&w2, &w1, &w0, ws[15], p[10]); + word3_muladd(&w2, &w1, &w0, ws[16], p[9]); + word3_muladd(&w2, &w1, &w0, ws[17], p[8]); + word3_muladd(&w2, &w1, &w0, ws[18], p[7]); + word3_muladd(&w2, &w1, &w0, ws[19], p[6]); + word3_muladd(&w2, &w1, &w0, ws[20], p[5]); + word3_muladd(&w2, &w1, &w0, ws[21], p[4]); + word3_muladd(&w2, &w1, &w0, ws[22], p[3]); + word3_muladd(&w2, &w1, &w0, ws[23], p[2]); + word3_muladd(&w2, &w1, &w0, ws[24], p[1]); + word3_add(&w2, &w1, &w0, z[25]); + ws[25] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[25], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[26]); + word3_muladd(&w2, &w1, &w0, ws[1], p[25]); + word3_muladd(&w2, &w1, &w0, ws[2], p[24]); + word3_muladd(&w2, &w1, &w0, ws[3], p[23]); + word3_muladd(&w2, &w1, &w0, ws[4], p[22]); + word3_muladd(&w2, &w1, &w0, ws[5], p[21]); + word3_muladd(&w2, &w1, &w0, ws[6], p[20]); + word3_muladd(&w2, &w1, &w0, ws[7], p[19]); + word3_muladd(&w2, &w1, &w0, ws[8], p[18]); + word3_muladd(&w2, &w1, &w0, ws[9], p[17]); + word3_muladd(&w2, &w1, &w0, ws[10], p[16]); + word3_muladd(&w2, &w1, &w0, ws[11], p[15]); + word3_muladd(&w2, &w1, &w0, ws[12], p[14]); + word3_muladd(&w2, &w1, &w0, ws[13], p[13]); + word3_muladd(&w2, &w1, &w0, ws[14], p[12]); + word3_muladd(&w2, &w1, &w0, ws[15], p[11]); + word3_muladd(&w2, &w1, &w0, ws[16], p[10]); + word3_muladd(&w2, &w1, &w0, ws[17], p[9]); + word3_muladd(&w2, &w1, &w0, ws[18], p[8]); + word3_muladd(&w2, &w1, &w0, ws[19], p[7]); + word3_muladd(&w2, &w1, &w0, ws[20], p[6]); + word3_muladd(&w2, &w1, &w0, ws[21], p[5]); + word3_muladd(&w2, &w1, &w0, ws[22], p[4]); + word3_muladd(&w2, &w1, &w0, ws[23], p[3]); + word3_muladd(&w2, &w1, &w0, ws[24], p[2]); + word3_muladd(&w2, &w1, &w0, ws[25], p[1]); + word3_add(&w2, &w1, &w0, z[26]); + ws[26] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[26], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[27]); + word3_muladd(&w2, &w1, &w0, ws[1], p[26]); + word3_muladd(&w2, &w1, &w0, ws[2], p[25]); + word3_muladd(&w2, &w1, &w0, ws[3], p[24]); + word3_muladd(&w2, &w1, &w0, ws[4], p[23]); + word3_muladd(&w2, &w1, &w0, ws[5], p[22]); + word3_muladd(&w2, &w1, &w0, ws[6], p[21]); + word3_muladd(&w2, &w1, &w0, ws[7], p[20]); + word3_muladd(&w2, &w1, &w0, ws[8], p[19]); + word3_muladd(&w2, &w1, &w0, ws[9], p[18]); + word3_muladd(&w2, &w1, &w0, ws[10], p[17]); + word3_muladd(&w2, &w1, &w0, ws[11], p[16]); + word3_muladd(&w2, &w1, &w0, ws[12], p[15]); + word3_muladd(&w2, &w1, &w0, ws[13], p[14]); + word3_muladd(&w2, &w1, &w0, ws[14], p[13]); + word3_muladd(&w2, &w1, &w0, ws[15], p[12]); + word3_muladd(&w2, &w1, &w0, ws[16], p[11]); + word3_muladd(&w2, &w1, &w0, ws[17], p[10]); + word3_muladd(&w2, &w1, &w0, ws[18], p[9]); + word3_muladd(&w2, &w1, &w0, ws[19], p[8]); + word3_muladd(&w2, &w1, &w0, ws[20], p[7]); + word3_muladd(&w2, &w1, &w0, ws[21], p[6]); + word3_muladd(&w2, &w1, &w0, ws[22], p[5]); + word3_muladd(&w2, &w1, &w0, ws[23], p[4]); + word3_muladd(&w2, &w1, &w0, ws[24], p[3]); + word3_muladd(&w2, &w1, &w0, ws[25], p[2]); + word3_muladd(&w2, &w1, &w0, ws[26], p[1]); + word3_add(&w2, &w1, &w0, z[27]); + ws[27] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[27], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[28]); + word3_muladd(&w2, &w1, &w0, ws[1], p[27]); + word3_muladd(&w2, &w1, &w0, ws[2], p[26]); + word3_muladd(&w2, &w1, &w0, ws[3], p[25]); + word3_muladd(&w2, &w1, &w0, ws[4], p[24]); + word3_muladd(&w2, &w1, &w0, ws[5], p[23]); + word3_muladd(&w2, &w1, &w0, ws[6], p[22]); + word3_muladd(&w2, &w1, &w0, ws[7], p[21]); + word3_muladd(&w2, &w1, &w0, ws[8], p[20]); + word3_muladd(&w2, &w1, &w0, ws[9], p[19]); + word3_muladd(&w2, &w1, &w0, ws[10], p[18]); + word3_muladd(&w2, &w1, &w0, ws[11], p[17]); + word3_muladd(&w2, &w1, &w0, ws[12], p[16]); + word3_muladd(&w2, &w1, &w0, ws[13], p[15]); + word3_muladd(&w2, &w1, &w0, ws[14], p[14]); + word3_muladd(&w2, &w1, &w0, ws[15], p[13]); + word3_muladd(&w2, &w1, &w0, ws[16], p[12]); + word3_muladd(&w2, &w1, &w0, ws[17], p[11]); + word3_muladd(&w2, &w1, &w0, ws[18], p[10]); + word3_muladd(&w2, &w1, &w0, ws[19], p[9]); + word3_muladd(&w2, &w1, &w0, ws[20], p[8]); + word3_muladd(&w2, &w1, &w0, ws[21], p[7]); + word3_muladd(&w2, &w1, &w0, ws[22], p[6]); + word3_muladd(&w2, &w1, &w0, ws[23], p[5]); + word3_muladd(&w2, &w1, &w0, ws[24], p[4]); + word3_muladd(&w2, &w1, &w0, ws[25], p[3]); + word3_muladd(&w2, &w1, &w0, ws[26], p[2]); + word3_muladd(&w2, &w1, &w0, ws[27], p[1]); + word3_add(&w2, &w1, &w0, z[28]); + ws[28] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[28], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[29]); + word3_muladd(&w2, &w1, &w0, ws[1], p[28]); + word3_muladd(&w2, &w1, &w0, ws[2], p[27]); + word3_muladd(&w2, &w1, &w0, ws[3], p[26]); + word3_muladd(&w2, &w1, &w0, ws[4], p[25]); + word3_muladd(&w2, &w1, &w0, ws[5], p[24]); + word3_muladd(&w2, &w1, &w0, ws[6], p[23]); + word3_muladd(&w2, &w1, &w0, ws[7], p[22]); + word3_muladd(&w2, &w1, &w0, ws[8], p[21]); + word3_muladd(&w2, &w1, &w0, ws[9], p[20]); + word3_muladd(&w2, &w1, &w0, ws[10], p[19]); + word3_muladd(&w2, &w1, &w0, ws[11], p[18]); + word3_muladd(&w2, &w1, &w0, ws[12], p[17]); + word3_muladd(&w2, &w1, &w0, ws[13], p[16]); + word3_muladd(&w2, &w1, &w0, ws[14], p[15]); + word3_muladd(&w2, &w1, &w0, ws[15], p[14]); + word3_muladd(&w2, &w1, &w0, ws[16], p[13]); + word3_muladd(&w2, &w1, &w0, ws[17], p[12]); + word3_muladd(&w2, &w1, &w0, ws[18], p[11]); + word3_muladd(&w2, &w1, &w0, ws[19], p[10]); + word3_muladd(&w2, &w1, &w0, ws[20], p[9]); + word3_muladd(&w2, &w1, &w0, ws[21], p[8]); + word3_muladd(&w2, &w1, &w0, ws[22], p[7]); + word3_muladd(&w2, &w1, &w0, ws[23], p[6]); + word3_muladd(&w2, &w1, &w0, ws[24], p[5]); + word3_muladd(&w2, &w1, &w0, ws[25], p[4]); + word3_muladd(&w2, &w1, &w0, ws[26], p[3]); + word3_muladd(&w2, &w1, &w0, ws[27], p[2]); + word3_muladd(&w2, &w1, &w0, ws[28], p[1]); + word3_add(&w2, &w1, &w0, z[29]); + ws[29] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[29], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[30]); + word3_muladd(&w2, &w1, &w0, ws[1], p[29]); + word3_muladd(&w2, &w1, &w0, ws[2], p[28]); + word3_muladd(&w2, &w1, &w0, ws[3], p[27]); + word3_muladd(&w2, &w1, &w0, ws[4], p[26]); + word3_muladd(&w2, &w1, &w0, ws[5], p[25]); + word3_muladd(&w2, &w1, &w0, ws[6], p[24]); + word3_muladd(&w2, &w1, &w0, ws[7], p[23]); + word3_muladd(&w2, &w1, &w0, ws[8], p[22]); + word3_muladd(&w2, &w1, &w0, ws[9], p[21]); + word3_muladd(&w2, &w1, &w0, ws[10], p[20]); + word3_muladd(&w2, &w1, &w0, ws[11], p[19]); + word3_muladd(&w2, &w1, &w0, ws[12], p[18]); + word3_muladd(&w2, &w1, &w0, ws[13], p[17]); + word3_muladd(&w2, &w1, &w0, ws[14], p[16]); + word3_muladd(&w2, &w1, &w0, ws[15], p[15]); + word3_muladd(&w2, &w1, &w0, ws[16], p[14]); + word3_muladd(&w2, &w1, &w0, ws[17], p[13]); + word3_muladd(&w2, &w1, &w0, ws[18], p[12]); + word3_muladd(&w2, &w1, &w0, ws[19], p[11]); + word3_muladd(&w2, &w1, &w0, ws[20], p[10]); + word3_muladd(&w2, &w1, &w0, ws[21], p[9]); + word3_muladd(&w2, &w1, &w0, ws[22], p[8]); + word3_muladd(&w2, &w1, &w0, ws[23], p[7]); + word3_muladd(&w2, &w1, &w0, ws[24], p[6]); + word3_muladd(&w2, &w1, &w0, ws[25], p[5]); + word3_muladd(&w2, &w1, &w0, ws[26], p[4]); + word3_muladd(&w2, &w1, &w0, ws[27], p[3]); + word3_muladd(&w2, &w1, &w0, ws[28], p[2]); + word3_muladd(&w2, &w1, &w0, ws[29], p[1]); + word3_add(&w2, &w1, &w0, z[30]); + ws[30] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[30], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[0], p[31]); + word3_muladd(&w2, &w1, &w0, ws[1], p[30]); + word3_muladd(&w2, &w1, &w0, ws[2], p[29]); + word3_muladd(&w2, &w1, &w0, ws[3], p[28]); + word3_muladd(&w2, &w1, &w0, ws[4], p[27]); + word3_muladd(&w2, &w1, &w0, ws[5], p[26]); + word3_muladd(&w2, &w1, &w0, ws[6], p[25]); + word3_muladd(&w2, &w1, &w0, ws[7], p[24]); + word3_muladd(&w2, &w1, &w0, ws[8], p[23]); + word3_muladd(&w2, &w1, &w0, ws[9], p[22]); + word3_muladd(&w2, &w1, &w0, ws[10], p[21]); + word3_muladd(&w2, &w1, &w0, ws[11], p[20]); + word3_muladd(&w2, &w1, &w0, ws[12], p[19]); + word3_muladd(&w2, &w1, &w0, ws[13], p[18]); + word3_muladd(&w2, &w1, &w0, ws[14], p[17]); + word3_muladd(&w2, &w1, &w0, ws[15], p[16]); + word3_muladd(&w2, &w1, &w0, ws[16], p[15]); + word3_muladd(&w2, &w1, &w0, ws[17], p[14]); + word3_muladd(&w2, &w1, &w0, ws[18], p[13]); + word3_muladd(&w2, &w1, &w0, ws[19], p[12]); + word3_muladd(&w2, &w1, &w0, ws[20], p[11]); + word3_muladd(&w2, &w1, &w0, ws[21], p[10]); + word3_muladd(&w2, &w1, &w0, ws[22], p[9]); + word3_muladd(&w2, &w1, &w0, ws[23], p[8]); + word3_muladd(&w2, &w1, &w0, ws[24], p[7]); + word3_muladd(&w2, &w1, &w0, ws[25], p[6]); + word3_muladd(&w2, &w1, &w0, ws[26], p[5]); + word3_muladd(&w2, &w1, &w0, ws[27], p[4]); + word3_muladd(&w2, &w1, &w0, ws[28], p[3]); + word3_muladd(&w2, &w1, &w0, ws[29], p[2]); + word3_muladd(&w2, &w1, &w0, ws[30], p[1]); + word3_add(&w2, &w1, &w0, z[31]); + ws[31] = w0 * p_dash; + word3_muladd(&w2, &w1, &w0, ws[31], p[0]); + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[1], p[31]); + word3_muladd(&w2, &w1, &w0, ws[2], p[30]); + word3_muladd(&w2, &w1, &w0, ws[3], p[29]); + word3_muladd(&w2, &w1, &w0, ws[4], p[28]); + word3_muladd(&w2, &w1, &w0, ws[5], p[27]); + word3_muladd(&w2, &w1, &w0, ws[6], p[26]); + word3_muladd(&w2, &w1, &w0, ws[7], p[25]); + word3_muladd(&w2, &w1, &w0, ws[8], p[24]); + word3_muladd(&w2, &w1, &w0, ws[9], p[23]); + word3_muladd(&w2, &w1, &w0, ws[10], p[22]); + word3_muladd(&w2, &w1, &w0, ws[11], p[21]); + word3_muladd(&w2, &w1, &w0, ws[12], p[20]); + word3_muladd(&w2, &w1, &w0, ws[13], p[19]); + word3_muladd(&w2, &w1, &w0, ws[14], p[18]); + word3_muladd(&w2, &w1, &w0, ws[15], p[17]); + word3_muladd(&w2, &w1, &w0, ws[16], p[16]); + word3_muladd(&w2, &w1, &w0, ws[17], p[15]); + word3_muladd(&w2, &w1, &w0, ws[18], p[14]); + word3_muladd(&w2, &w1, &w0, ws[19], p[13]); + word3_muladd(&w2, &w1, &w0, ws[20], p[12]); + word3_muladd(&w2, &w1, &w0, ws[21], p[11]); + word3_muladd(&w2, &w1, &w0, ws[22], p[10]); + word3_muladd(&w2, &w1, &w0, ws[23], p[9]); + word3_muladd(&w2, &w1, &w0, ws[24], p[8]); + word3_muladd(&w2, &w1, &w0, ws[25], p[7]); + word3_muladd(&w2, &w1, &w0, ws[26], p[6]); + word3_muladd(&w2, &w1, &w0, ws[27], p[5]); + word3_muladd(&w2, &w1, &w0, ws[28], p[4]); + word3_muladd(&w2, &w1, &w0, ws[29], p[3]); + word3_muladd(&w2, &w1, &w0, ws[30], p[2]); + word3_muladd(&w2, &w1, &w0, ws[31], p[1]); + word3_add(&w2, &w1, &w0, z[32]); + ws[0] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[2], p[31]); + word3_muladd(&w2, &w1, &w0, ws[3], p[30]); + word3_muladd(&w2, &w1, &w0, ws[4], p[29]); + word3_muladd(&w2, &w1, &w0, ws[5], p[28]); + word3_muladd(&w2, &w1, &w0, ws[6], p[27]); + word3_muladd(&w2, &w1, &w0, ws[7], p[26]); + word3_muladd(&w2, &w1, &w0, ws[8], p[25]); + word3_muladd(&w2, &w1, &w0, ws[9], p[24]); + word3_muladd(&w2, &w1, &w0, ws[10], p[23]); + word3_muladd(&w2, &w1, &w0, ws[11], p[22]); + word3_muladd(&w2, &w1, &w0, ws[12], p[21]); + word3_muladd(&w2, &w1, &w0, ws[13], p[20]); + word3_muladd(&w2, &w1, &w0, ws[14], p[19]); + word3_muladd(&w2, &w1, &w0, ws[15], p[18]); + word3_muladd(&w2, &w1, &w0, ws[16], p[17]); + word3_muladd(&w2, &w1, &w0, ws[17], p[16]); + word3_muladd(&w2, &w1, &w0, ws[18], p[15]); + word3_muladd(&w2, &w1, &w0, ws[19], p[14]); + word3_muladd(&w2, &w1, &w0, ws[20], p[13]); + word3_muladd(&w2, &w1, &w0, ws[21], p[12]); + word3_muladd(&w2, &w1, &w0, ws[22], p[11]); + word3_muladd(&w2, &w1, &w0, ws[23], p[10]); + word3_muladd(&w2, &w1, &w0, ws[24], p[9]); + word3_muladd(&w2, &w1, &w0, ws[25], p[8]); + word3_muladd(&w2, &w1, &w0, ws[26], p[7]); + word3_muladd(&w2, &w1, &w0, ws[27], p[6]); + word3_muladd(&w2, &w1, &w0, ws[28], p[5]); + word3_muladd(&w2, &w1, &w0, ws[29], p[4]); + word3_muladd(&w2, &w1, &w0, ws[30], p[3]); + word3_muladd(&w2, &w1, &w0, ws[31], p[2]); + word3_add(&w2, &w1, &w0, z[33]); + ws[1] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[3], p[31]); + word3_muladd(&w2, &w1, &w0, ws[4], p[30]); + word3_muladd(&w2, &w1, &w0, ws[5], p[29]); + word3_muladd(&w2, &w1, &w0, ws[6], p[28]); + word3_muladd(&w2, &w1, &w0, ws[7], p[27]); + word3_muladd(&w2, &w1, &w0, ws[8], p[26]); + word3_muladd(&w2, &w1, &w0, ws[9], p[25]); + word3_muladd(&w2, &w1, &w0, ws[10], p[24]); + word3_muladd(&w2, &w1, &w0, ws[11], p[23]); + word3_muladd(&w2, &w1, &w0, ws[12], p[22]); + word3_muladd(&w2, &w1, &w0, ws[13], p[21]); + word3_muladd(&w2, &w1, &w0, ws[14], p[20]); + word3_muladd(&w2, &w1, &w0, ws[15], p[19]); + word3_muladd(&w2, &w1, &w0, ws[16], p[18]); + word3_muladd(&w2, &w1, &w0, ws[17], p[17]); + word3_muladd(&w2, &w1, &w0, ws[18], p[16]); + word3_muladd(&w2, &w1, &w0, ws[19], p[15]); + word3_muladd(&w2, &w1, &w0, ws[20], p[14]); + word3_muladd(&w2, &w1, &w0, ws[21], p[13]); + word3_muladd(&w2, &w1, &w0, ws[22], p[12]); + word3_muladd(&w2, &w1, &w0, ws[23], p[11]); + word3_muladd(&w2, &w1, &w0, ws[24], p[10]); + word3_muladd(&w2, &w1, &w0, ws[25], p[9]); + word3_muladd(&w2, &w1, &w0, ws[26], p[8]); + word3_muladd(&w2, &w1, &w0, ws[27], p[7]); + word3_muladd(&w2, &w1, &w0, ws[28], p[6]); + word3_muladd(&w2, &w1, &w0, ws[29], p[5]); + word3_muladd(&w2, &w1, &w0, ws[30], p[4]); + word3_muladd(&w2, &w1, &w0, ws[31], p[3]); + word3_add(&w2, &w1, &w0, z[34]); + ws[2] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[4], p[31]); + word3_muladd(&w2, &w1, &w0, ws[5], p[30]); + word3_muladd(&w2, &w1, &w0, ws[6], p[29]); + word3_muladd(&w2, &w1, &w0, ws[7], p[28]); + word3_muladd(&w2, &w1, &w0, ws[8], p[27]); + word3_muladd(&w2, &w1, &w0, ws[9], p[26]); + word3_muladd(&w2, &w1, &w0, ws[10], p[25]); + word3_muladd(&w2, &w1, &w0, ws[11], p[24]); + word3_muladd(&w2, &w1, &w0, ws[12], p[23]); + word3_muladd(&w2, &w1, &w0, ws[13], p[22]); + word3_muladd(&w2, &w1, &w0, ws[14], p[21]); + word3_muladd(&w2, &w1, &w0, ws[15], p[20]); + word3_muladd(&w2, &w1, &w0, ws[16], p[19]); + word3_muladd(&w2, &w1, &w0, ws[17], p[18]); + word3_muladd(&w2, &w1, &w0, ws[18], p[17]); + word3_muladd(&w2, &w1, &w0, ws[19], p[16]); + word3_muladd(&w2, &w1, &w0, ws[20], p[15]); + word3_muladd(&w2, &w1, &w0, ws[21], p[14]); + word3_muladd(&w2, &w1, &w0, ws[22], p[13]); + word3_muladd(&w2, &w1, &w0, ws[23], p[12]); + word3_muladd(&w2, &w1, &w0, ws[24], p[11]); + word3_muladd(&w2, &w1, &w0, ws[25], p[10]); + word3_muladd(&w2, &w1, &w0, ws[26], p[9]); + word3_muladd(&w2, &w1, &w0, ws[27], p[8]); + word3_muladd(&w2, &w1, &w0, ws[28], p[7]); + word3_muladd(&w2, &w1, &w0, ws[29], p[6]); + word3_muladd(&w2, &w1, &w0, ws[30], p[5]); + word3_muladd(&w2, &w1, &w0, ws[31], p[4]); + word3_add(&w2, &w1, &w0, z[35]); + ws[3] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[5], p[31]); + word3_muladd(&w2, &w1, &w0, ws[6], p[30]); + word3_muladd(&w2, &w1, &w0, ws[7], p[29]); + word3_muladd(&w2, &w1, &w0, ws[8], p[28]); + word3_muladd(&w2, &w1, &w0, ws[9], p[27]); + word3_muladd(&w2, &w1, &w0, ws[10], p[26]); + word3_muladd(&w2, &w1, &w0, ws[11], p[25]); + word3_muladd(&w2, &w1, &w0, ws[12], p[24]); + word3_muladd(&w2, &w1, &w0, ws[13], p[23]); + word3_muladd(&w2, &w1, &w0, ws[14], p[22]); + word3_muladd(&w2, &w1, &w0, ws[15], p[21]); + word3_muladd(&w2, &w1, &w0, ws[16], p[20]); + word3_muladd(&w2, &w1, &w0, ws[17], p[19]); + word3_muladd(&w2, &w1, &w0, ws[18], p[18]); + word3_muladd(&w2, &w1, &w0, ws[19], p[17]); + word3_muladd(&w2, &w1, &w0, ws[20], p[16]); + word3_muladd(&w2, &w1, &w0, ws[21], p[15]); + word3_muladd(&w2, &w1, &w0, ws[22], p[14]); + word3_muladd(&w2, &w1, &w0, ws[23], p[13]); + word3_muladd(&w2, &w1, &w0, ws[24], p[12]); + word3_muladd(&w2, &w1, &w0, ws[25], p[11]); + word3_muladd(&w2, &w1, &w0, ws[26], p[10]); + word3_muladd(&w2, &w1, &w0, ws[27], p[9]); + word3_muladd(&w2, &w1, &w0, ws[28], p[8]); + word3_muladd(&w2, &w1, &w0, ws[29], p[7]); + word3_muladd(&w2, &w1, &w0, ws[30], p[6]); + word3_muladd(&w2, &w1, &w0, ws[31], p[5]); + word3_add(&w2, &w1, &w0, z[36]); + ws[4] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[6], p[31]); + word3_muladd(&w2, &w1, &w0, ws[7], p[30]); + word3_muladd(&w2, &w1, &w0, ws[8], p[29]); + word3_muladd(&w2, &w1, &w0, ws[9], p[28]); + word3_muladd(&w2, &w1, &w0, ws[10], p[27]); + word3_muladd(&w2, &w1, &w0, ws[11], p[26]); + word3_muladd(&w2, &w1, &w0, ws[12], p[25]); + word3_muladd(&w2, &w1, &w0, ws[13], p[24]); + word3_muladd(&w2, &w1, &w0, ws[14], p[23]); + word3_muladd(&w2, &w1, &w0, ws[15], p[22]); + word3_muladd(&w2, &w1, &w0, ws[16], p[21]); + word3_muladd(&w2, &w1, &w0, ws[17], p[20]); + word3_muladd(&w2, &w1, &w0, ws[18], p[19]); + word3_muladd(&w2, &w1, &w0, ws[19], p[18]); + word3_muladd(&w2, &w1, &w0, ws[20], p[17]); + word3_muladd(&w2, &w1, &w0, ws[21], p[16]); + word3_muladd(&w2, &w1, &w0, ws[22], p[15]); + word3_muladd(&w2, &w1, &w0, ws[23], p[14]); + word3_muladd(&w2, &w1, &w0, ws[24], p[13]); + word3_muladd(&w2, &w1, &w0, ws[25], p[12]); + word3_muladd(&w2, &w1, &w0, ws[26], p[11]); + word3_muladd(&w2, &w1, &w0, ws[27], p[10]); + word3_muladd(&w2, &w1, &w0, ws[28], p[9]); + word3_muladd(&w2, &w1, &w0, ws[29], p[8]); + word3_muladd(&w2, &w1, &w0, ws[30], p[7]); + word3_muladd(&w2, &w1, &w0, ws[31], p[6]); + word3_add(&w2, &w1, &w0, z[37]); + ws[5] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[7], p[31]); + word3_muladd(&w2, &w1, &w0, ws[8], p[30]); + word3_muladd(&w2, &w1, &w0, ws[9], p[29]); + word3_muladd(&w2, &w1, &w0, ws[10], p[28]); + word3_muladd(&w2, &w1, &w0, ws[11], p[27]); + word3_muladd(&w2, &w1, &w0, ws[12], p[26]); + word3_muladd(&w2, &w1, &w0, ws[13], p[25]); + word3_muladd(&w2, &w1, &w0, ws[14], p[24]); + word3_muladd(&w2, &w1, &w0, ws[15], p[23]); + word3_muladd(&w2, &w1, &w0, ws[16], p[22]); + word3_muladd(&w2, &w1, &w0, ws[17], p[21]); + word3_muladd(&w2, &w1, &w0, ws[18], p[20]); + word3_muladd(&w2, &w1, &w0, ws[19], p[19]); + word3_muladd(&w2, &w1, &w0, ws[20], p[18]); + word3_muladd(&w2, &w1, &w0, ws[21], p[17]); + word3_muladd(&w2, &w1, &w0, ws[22], p[16]); + word3_muladd(&w2, &w1, &w0, ws[23], p[15]); + word3_muladd(&w2, &w1, &w0, ws[24], p[14]); + word3_muladd(&w2, &w1, &w0, ws[25], p[13]); + word3_muladd(&w2, &w1, &w0, ws[26], p[12]); + word3_muladd(&w2, &w1, &w0, ws[27], p[11]); + word3_muladd(&w2, &w1, &w0, ws[28], p[10]); + word3_muladd(&w2, &w1, &w0, ws[29], p[9]); + word3_muladd(&w2, &w1, &w0, ws[30], p[8]); + word3_muladd(&w2, &w1, &w0, ws[31], p[7]); + word3_add(&w2, &w1, &w0, z[38]); + ws[6] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[8], p[31]); + word3_muladd(&w2, &w1, &w0, ws[9], p[30]); + word3_muladd(&w2, &w1, &w0, ws[10], p[29]); + word3_muladd(&w2, &w1, &w0, ws[11], p[28]); + word3_muladd(&w2, &w1, &w0, ws[12], p[27]); + word3_muladd(&w2, &w1, &w0, ws[13], p[26]); + word3_muladd(&w2, &w1, &w0, ws[14], p[25]); + word3_muladd(&w2, &w1, &w0, ws[15], p[24]); + word3_muladd(&w2, &w1, &w0, ws[16], p[23]); + word3_muladd(&w2, &w1, &w0, ws[17], p[22]); + word3_muladd(&w2, &w1, &w0, ws[18], p[21]); + word3_muladd(&w2, &w1, &w0, ws[19], p[20]); + word3_muladd(&w2, &w1, &w0, ws[20], p[19]); + word3_muladd(&w2, &w1, &w0, ws[21], p[18]); + word3_muladd(&w2, &w1, &w0, ws[22], p[17]); + word3_muladd(&w2, &w1, &w0, ws[23], p[16]); + word3_muladd(&w2, &w1, &w0, ws[24], p[15]); + word3_muladd(&w2, &w1, &w0, ws[25], p[14]); + word3_muladd(&w2, &w1, &w0, ws[26], p[13]); + word3_muladd(&w2, &w1, &w0, ws[27], p[12]); + word3_muladd(&w2, &w1, &w0, ws[28], p[11]); + word3_muladd(&w2, &w1, &w0, ws[29], p[10]); + word3_muladd(&w2, &w1, &w0, ws[30], p[9]); + word3_muladd(&w2, &w1, &w0, ws[31], p[8]); + word3_add(&w2, &w1, &w0, z[39]); + ws[7] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[9], p[31]); + word3_muladd(&w2, &w1, &w0, ws[10], p[30]); + word3_muladd(&w2, &w1, &w0, ws[11], p[29]); + word3_muladd(&w2, &w1, &w0, ws[12], p[28]); + word3_muladd(&w2, &w1, &w0, ws[13], p[27]); + word3_muladd(&w2, &w1, &w0, ws[14], p[26]); + word3_muladd(&w2, &w1, &w0, ws[15], p[25]); + word3_muladd(&w2, &w1, &w0, ws[16], p[24]); + word3_muladd(&w2, &w1, &w0, ws[17], p[23]); + word3_muladd(&w2, &w1, &w0, ws[18], p[22]); + word3_muladd(&w2, &w1, &w0, ws[19], p[21]); + word3_muladd(&w2, &w1, &w0, ws[20], p[20]); + word3_muladd(&w2, &w1, &w0, ws[21], p[19]); + word3_muladd(&w2, &w1, &w0, ws[22], p[18]); + word3_muladd(&w2, &w1, &w0, ws[23], p[17]); + word3_muladd(&w2, &w1, &w0, ws[24], p[16]); + word3_muladd(&w2, &w1, &w0, ws[25], p[15]); + word3_muladd(&w2, &w1, &w0, ws[26], p[14]); + word3_muladd(&w2, &w1, &w0, ws[27], p[13]); + word3_muladd(&w2, &w1, &w0, ws[28], p[12]); + word3_muladd(&w2, &w1, &w0, ws[29], p[11]); + word3_muladd(&w2, &w1, &w0, ws[30], p[10]); + word3_muladd(&w2, &w1, &w0, ws[31], p[9]); + word3_add(&w2, &w1, &w0, z[40]); + ws[8] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[10], p[31]); + word3_muladd(&w2, &w1, &w0, ws[11], p[30]); + word3_muladd(&w2, &w1, &w0, ws[12], p[29]); + word3_muladd(&w2, &w1, &w0, ws[13], p[28]); + word3_muladd(&w2, &w1, &w0, ws[14], p[27]); + word3_muladd(&w2, &w1, &w0, ws[15], p[26]); + word3_muladd(&w2, &w1, &w0, ws[16], p[25]); + word3_muladd(&w2, &w1, &w0, ws[17], p[24]); + word3_muladd(&w2, &w1, &w0, ws[18], p[23]); + word3_muladd(&w2, &w1, &w0, ws[19], p[22]); + word3_muladd(&w2, &w1, &w0, ws[20], p[21]); + word3_muladd(&w2, &w1, &w0, ws[21], p[20]); + word3_muladd(&w2, &w1, &w0, ws[22], p[19]); + word3_muladd(&w2, &w1, &w0, ws[23], p[18]); + word3_muladd(&w2, &w1, &w0, ws[24], p[17]); + word3_muladd(&w2, &w1, &w0, ws[25], p[16]); + word3_muladd(&w2, &w1, &w0, ws[26], p[15]); + word3_muladd(&w2, &w1, &w0, ws[27], p[14]); + word3_muladd(&w2, &w1, &w0, ws[28], p[13]); + word3_muladd(&w2, &w1, &w0, ws[29], p[12]); + word3_muladd(&w2, &w1, &w0, ws[30], p[11]); + word3_muladd(&w2, &w1, &w0, ws[31], p[10]); + word3_add(&w2, &w1, &w0, z[41]); + ws[9] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[11], p[31]); + word3_muladd(&w2, &w1, &w0, ws[12], p[30]); + word3_muladd(&w2, &w1, &w0, ws[13], p[29]); + word3_muladd(&w2, &w1, &w0, ws[14], p[28]); + word3_muladd(&w2, &w1, &w0, ws[15], p[27]); + word3_muladd(&w2, &w1, &w0, ws[16], p[26]); + word3_muladd(&w2, &w1, &w0, ws[17], p[25]); + word3_muladd(&w2, &w1, &w0, ws[18], p[24]); + word3_muladd(&w2, &w1, &w0, ws[19], p[23]); + word3_muladd(&w2, &w1, &w0, ws[20], p[22]); + word3_muladd(&w2, &w1, &w0, ws[21], p[21]); + word3_muladd(&w2, &w1, &w0, ws[22], p[20]); + word3_muladd(&w2, &w1, &w0, ws[23], p[19]); + word3_muladd(&w2, &w1, &w0, ws[24], p[18]); + word3_muladd(&w2, &w1, &w0, ws[25], p[17]); + word3_muladd(&w2, &w1, &w0, ws[26], p[16]); + word3_muladd(&w2, &w1, &w0, ws[27], p[15]); + word3_muladd(&w2, &w1, &w0, ws[28], p[14]); + word3_muladd(&w2, &w1, &w0, ws[29], p[13]); + word3_muladd(&w2, &w1, &w0, ws[30], p[12]); + word3_muladd(&w2, &w1, &w0, ws[31], p[11]); + word3_add(&w2, &w1, &w0, z[42]); + ws[10] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[12], p[31]); + word3_muladd(&w2, &w1, &w0, ws[13], p[30]); + word3_muladd(&w2, &w1, &w0, ws[14], p[29]); + word3_muladd(&w2, &w1, &w0, ws[15], p[28]); + word3_muladd(&w2, &w1, &w0, ws[16], p[27]); + word3_muladd(&w2, &w1, &w0, ws[17], p[26]); + word3_muladd(&w2, &w1, &w0, ws[18], p[25]); + word3_muladd(&w2, &w1, &w0, ws[19], p[24]); + word3_muladd(&w2, &w1, &w0, ws[20], p[23]); + word3_muladd(&w2, &w1, &w0, ws[21], p[22]); + word3_muladd(&w2, &w1, &w0, ws[22], p[21]); + word3_muladd(&w2, &w1, &w0, ws[23], p[20]); + word3_muladd(&w2, &w1, &w0, ws[24], p[19]); + word3_muladd(&w2, &w1, &w0, ws[25], p[18]); + word3_muladd(&w2, &w1, &w0, ws[26], p[17]); + word3_muladd(&w2, &w1, &w0, ws[27], p[16]); + word3_muladd(&w2, &w1, &w0, ws[28], p[15]); + word3_muladd(&w2, &w1, &w0, ws[29], p[14]); + word3_muladd(&w2, &w1, &w0, ws[30], p[13]); + word3_muladd(&w2, &w1, &w0, ws[31], p[12]); + word3_add(&w2, &w1, &w0, z[43]); + ws[11] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[13], p[31]); + word3_muladd(&w2, &w1, &w0, ws[14], p[30]); + word3_muladd(&w2, &w1, &w0, ws[15], p[29]); + word3_muladd(&w2, &w1, &w0, ws[16], p[28]); + word3_muladd(&w2, &w1, &w0, ws[17], p[27]); + word3_muladd(&w2, &w1, &w0, ws[18], p[26]); + word3_muladd(&w2, &w1, &w0, ws[19], p[25]); + word3_muladd(&w2, &w1, &w0, ws[20], p[24]); + word3_muladd(&w2, &w1, &w0, ws[21], p[23]); + word3_muladd(&w2, &w1, &w0, ws[22], p[22]); + word3_muladd(&w2, &w1, &w0, ws[23], p[21]); + word3_muladd(&w2, &w1, &w0, ws[24], p[20]); + word3_muladd(&w2, &w1, &w0, ws[25], p[19]); + word3_muladd(&w2, &w1, &w0, ws[26], p[18]); + word3_muladd(&w2, &w1, &w0, ws[27], p[17]); + word3_muladd(&w2, &w1, &w0, ws[28], p[16]); + word3_muladd(&w2, &w1, &w0, ws[29], p[15]); + word3_muladd(&w2, &w1, &w0, ws[30], p[14]); + word3_muladd(&w2, &w1, &w0, ws[31], p[13]); + word3_add(&w2, &w1, &w0, z[44]); + ws[12] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[14], p[31]); + word3_muladd(&w2, &w1, &w0, ws[15], p[30]); + word3_muladd(&w2, &w1, &w0, ws[16], p[29]); + word3_muladd(&w2, &w1, &w0, ws[17], p[28]); + word3_muladd(&w2, &w1, &w0, ws[18], p[27]); + word3_muladd(&w2, &w1, &w0, ws[19], p[26]); + word3_muladd(&w2, &w1, &w0, ws[20], p[25]); + word3_muladd(&w2, &w1, &w0, ws[21], p[24]); + word3_muladd(&w2, &w1, &w0, ws[22], p[23]); + word3_muladd(&w2, &w1, &w0, ws[23], p[22]); + word3_muladd(&w2, &w1, &w0, ws[24], p[21]); + word3_muladd(&w2, &w1, &w0, ws[25], p[20]); + word3_muladd(&w2, &w1, &w0, ws[26], p[19]); + word3_muladd(&w2, &w1, &w0, ws[27], p[18]); + word3_muladd(&w2, &w1, &w0, ws[28], p[17]); + word3_muladd(&w2, &w1, &w0, ws[29], p[16]); + word3_muladd(&w2, &w1, &w0, ws[30], p[15]); + word3_muladd(&w2, &w1, &w0, ws[31], p[14]); + word3_add(&w2, &w1, &w0, z[45]); + ws[13] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[15], p[31]); + word3_muladd(&w2, &w1, &w0, ws[16], p[30]); + word3_muladd(&w2, &w1, &w0, ws[17], p[29]); + word3_muladd(&w2, &w1, &w0, ws[18], p[28]); + word3_muladd(&w2, &w1, &w0, ws[19], p[27]); + word3_muladd(&w2, &w1, &w0, ws[20], p[26]); + word3_muladd(&w2, &w1, &w0, ws[21], p[25]); + word3_muladd(&w2, &w1, &w0, ws[22], p[24]); + word3_muladd(&w2, &w1, &w0, ws[23], p[23]); + word3_muladd(&w2, &w1, &w0, ws[24], p[22]); + word3_muladd(&w2, &w1, &w0, ws[25], p[21]); + word3_muladd(&w2, &w1, &w0, ws[26], p[20]); + word3_muladd(&w2, &w1, &w0, ws[27], p[19]); + word3_muladd(&w2, &w1, &w0, ws[28], p[18]); + word3_muladd(&w2, &w1, &w0, ws[29], p[17]); + word3_muladd(&w2, &w1, &w0, ws[30], p[16]); + word3_muladd(&w2, &w1, &w0, ws[31], p[15]); + word3_add(&w2, &w1, &w0, z[46]); + ws[14] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[16], p[31]); + word3_muladd(&w2, &w1, &w0, ws[17], p[30]); + word3_muladd(&w2, &w1, &w0, ws[18], p[29]); + word3_muladd(&w2, &w1, &w0, ws[19], p[28]); + word3_muladd(&w2, &w1, &w0, ws[20], p[27]); + word3_muladd(&w2, &w1, &w0, ws[21], p[26]); + word3_muladd(&w2, &w1, &w0, ws[22], p[25]); + word3_muladd(&w2, &w1, &w0, ws[23], p[24]); + word3_muladd(&w2, &w1, &w0, ws[24], p[23]); + word3_muladd(&w2, &w1, &w0, ws[25], p[22]); + word3_muladd(&w2, &w1, &w0, ws[26], p[21]); + word3_muladd(&w2, &w1, &w0, ws[27], p[20]); + word3_muladd(&w2, &w1, &w0, ws[28], p[19]); + word3_muladd(&w2, &w1, &w0, ws[29], p[18]); + word3_muladd(&w2, &w1, &w0, ws[30], p[17]); + word3_muladd(&w2, &w1, &w0, ws[31], p[16]); + word3_add(&w2, &w1, &w0, z[47]); + ws[15] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[17], p[31]); + word3_muladd(&w2, &w1, &w0, ws[18], p[30]); + word3_muladd(&w2, &w1, &w0, ws[19], p[29]); + word3_muladd(&w2, &w1, &w0, ws[20], p[28]); + word3_muladd(&w2, &w1, &w0, ws[21], p[27]); + word3_muladd(&w2, &w1, &w0, ws[22], p[26]); + word3_muladd(&w2, &w1, &w0, ws[23], p[25]); + word3_muladd(&w2, &w1, &w0, ws[24], p[24]); + word3_muladd(&w2, &w1, &w0, ws[25], p[23]); + word3_muladd(&w2, &w1, &w0, ws[26], p[22]); + word3_muladd(&w2, &w1, &w0, ws[27], p[21]); + word3_muladd(&w2, &w1, &w0, ws[28], p[20]); + word3_muladd(&w2, &w1, &w0, ws[29], p[19]); + word3_muladd(&w2, &w1, &w0, ws[30], p[18]); + word3_muladd(&w2, &w1, &w0, ws[31], p[17]); + word3_add(&w2, &w1, &w0, z[48]); + ws[16] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[18], p[31]); + word3_muladd(&w2, &w1, &w0, ws[19], p[30]); + word3_muladd(&w2, &w1, &w0, ws[20], p[29]); + word3_muladd(&w2, &w1, &w0, ws[21], p[28]); + word3_muladd(&w2, &w1, &w0, ws[22], p[27]); + word3_muladd(&w2, &w1, &w0, ws[23], p[26]); + word3_muladd(&w2, &w1, &w0, ws[24], p[25]); + word3_muladd(&w2, &w1, &w0, ws[25], p[24]); + word3_muladd(&w2, &w1, &w0, ws[26], p[23]); + word3_muladd(&w2, &w1, &w0, ws[27], p[22]); + word3_muladd(&w2, &w1, &w0, ws[28], p[21]); + word3_muladd(&w2, &w1, &w0, ws[29], p[20]); + word3_muladd(&w2, &w1, &w0, ws[30], p[19]); + word3_muladd(&w2, &w1, &w0, ws[31], p[18]); + word3_add(&w2, &w1, &w0, z[49]); + ws[17] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[19], p[31]); + word3_muladd(&w2, &w1, &w0, ws[20], p[30]); + word3_muladd(&w2, &w1, &w0, ws[21], p[29]); + word3_muladd(&w2, &w1, &w0, ws[22], p[28]); + word3_muladd(&w2, &w1, &w0, ws[23], p[27]); + word3_muladd(&w2, &w1, &w0, ws[24], p[26]); + word3_muladd(&w2, &w1, &w0, ws[25], p[25]); + word3_muladd(&w2, &w1, &w0, ws[26], p[24]); + word3_muladd(&w2, &w1, &w0, ws[27], p[23]); + word3_muladd(&w2, &w1, &w0, ws[28], p[22]); + word3_muladd(&w2, &w1, &w0, ws[29], p[21]); + word3_muladd(&w2, &w1, &w0, ws[30], p[20]); + word3_muladd(&w2, &w1, &w0, ws[31], p[19]); + word3_add(&w2, &w1, &w0, z[50]); + ws[18] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[20], p[31]); + word3_muladd(&w2, &w1, &w0, ws[21], p[30]); + word3_muladd(&w2, &w1, &w0, ws[22], p[29]); + word3_muladd(&w2, &w1, &w0, ws[23], p[28]); + word3_muladd(&w2, &w1, &w0, ws[24], p[27]); + word3_muladd(&w2, &w1, &w0, ws[25], p[26]); + word3_muladd(&w2, &w1, &w0, ws[26], p[25]); + word3_muladd(&w2, &w1, &w0, ws[27], p[24]); + word3_muladd(&w2, &w1, &w0, ws[28], p[23]); + word3_muladd(&w2, &w1, &w0, ws[29], p[22]); + word3_muladd(&w2, &w1, &w0, ws[30], p[21]); + word3_muladd(&w2, &w1, &w0, ws[31], p[20]); + word3_add(&w2, &w1, &w0, z[51]); + ws[19] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[21], p[31]); + word3_muladd(&w2, &w1, &w0, ws[22], p[30]); + word3_muladd(&w2, &w1, &w0, ws[23], p[29]); + word3_muladd(&w2, &w1, &w0, ws[24], p[28]); + word3_muladd(&w2, &w1, &w0, ws[25], p[27]); + word3_muladd(&w2, &w1, &w0, ws[26], p[26]); + word3_muladd(&w2, &w1, &w0, ws[27], p[25]); + word3_muladd(&w2, &w1, &w0, ws[28], p[24]); + word3_muladd(&w2, &w1, &w0, ws[29], p[23]); + word3_muladd(&w2, &w1, &w0, ws[30], p[22]); + word3_muladd(&w2, &w1, &w0, ws[31], p[21]); + word3_add(&w2, &w1, &w0, z[52]); + ws[20] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[22], p[31]); + word3_muladd(&w2, &w1, &w0, ws[23], p[30]); + word3_muladd(&w2, &w1, &w0, ws[24], p[29]); + word3_muladd(&w2, &w1, &w0, ws[25], p[28]); + word3_muladd(&w2, &w1, &w0, ws[26], p[27]); + word3_muladd(&w2, &w1, &w0, ws[27], p[26]); + word3_muladd(&w2, &w1, &w0, ws[28], p[25]); + word3_muladd(&w2, &w1, &w0, ws[29], p[24]); + word3_muladd(&w2, &w1, &w0, ws[30], p[23]); + word3_muladd(&w2, &w1, &w0, ws[31], p[22]); + word3_add(&w2, &w1, &w0, z[53]); + ws[21] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[23], p[31]); + word3_muladd(&w2, &w1, &w0, ws[24], p[30]); + word3_muladd(&w2, &w1, &w0, ws[25], p[29]); + word3_muladd(&w2, &w1, &w0, ws[26], p[28]); + word3_muladd(&w2, &w1, &w0, ws[27], p[27]); + word3_muladd(&w2, &w1, &w0, ws[28], p[26]); + word3_muladd(&w2, &w1, &w0, ws[29], p[25]); + word3_muladd(&w2, &w1, &w0, ws[30], p[24]); + word3_muladd(&w2, &w1, &w0, ws[31], p[23]); + word3_add(&w2, &w1, &w0, z[54]); + ws[22] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[24], p[31]); + word3_muladd(&w2, &w1, &w0, ws[25], p[30]); + word3_muladd(&w2, &w1, &w0, ws[26], p[29]); + word3_muladd(&w2, &w1, &w0, ws[27], p[28]); + word3_muladd(&w2, &w1, &w0, ws[28], p[27]); + word3_muladd(&w2, &w1, &w0, ws[29], p[26]); + word3_muladd(&w2, &w1, &w0, ws[30], p[25]); + word3_muladd(&w2, &w1, &w0, ws[31], p[24]); + word3_add(&w2, &w1, &w0, z[55]); + ws[23] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[25], p[31]); + word3_muladd(&w2, &w1, &w0, ws[26], p[30]); + word3_muladd(&w2, &w1, &w0, ws[27], p[29]); + word3_muladd(&w2, &w1, &w0, ws[28], p[28]); + word3_muladd(&w2, &w1, &w0, ws[29], p[27]); + word3_muladd(&w2, &w1, &w0, ws[30], p[26]); + word3_muladd(&w2, &w1, &w0, ws[31], p[25]); + word3_add(&w2, &w1, &w0, z[56]); + ws[24] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[26], p[31]); + word3_muladd(&w2, &w1, &w0, ws[27], p[30]); + word3_muladd(&w2, &w1, &w0, ws[28], p[29]); + word3_muladd(&w2, &w1, &w0, ws[29], p[28]); + word3_muladd(&w2, &w1, &w0, ws[30], p[27]); + word3_muladd(&w2, &w1, &w0, ws[31], p[26]); + word3_add(&w2, &w1, &w0, z[57]); + ws[25] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[27], p[31]); + word3_muladd(&w2, &w1, &w0, ws[28], p[30]); + word3_muladd(&w2, &w1, &w0, ws[29], p[29]); + word3_muladd(&w2, &w1, &w0, ws[30], p[28]); + word3_muladd(&w2, &w1, &w0, ws[31], p[27]); + word3_add(&w2, &w1, &w0, z[58]); + ws[26] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[28], p[31]); + word3_muladd(&w2, &w1, &w0, ws[29], p[30]); + word3_muladd(&w2, &w1, &w0, ws[30], p[29]); + word3_muladd(&w2, &w1, &w0, ws[31], p[28]); + word3_add(&w2, &w1, &w0, z[59]); + ws[27] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[29], p[31]); + word3_muladd(&w2, &w1, &w0, ws[30], p[30]); + word3_muladd(&w2, &w1, &w0, ws[31], p[29]); + word3_add(&w2, &w1, &w0, z[60]); + ws[28] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[30], p[31]); + word3_muladd(&w2, &w1, &w0, ws[31], p[30]); + word3_add(&w2, &w1, &w0, z[61]); + ws[29] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_muladd(&w2, &w1, &w0, ws[31], p[31]); + word3_add(&w2, &w1, &w0, z[62]); + ws[30] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[63]); + ws[31] = w0; + w0 = w1; w1 = w2; w2 = 0; + word3_add(&w2, &w1, &w0, z[65]); + ws[32] = w0; + ws[33] = w1; + word borrow = bigint_sub3(ws + 32 + 1, ws, 32 + 1, p, 32); + CT::conditional_copy_mem(borrow, z, ws, ws + 33, 33); + clear_mem(z + 32, 2*(32+1) - 32); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/curve_nistp.h b/src/libs/3rdparty/botan/src/lib/math/numbertheory/curve_nistp.h new file mode 100644 index 0000000000..c9936a338b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/curve_nistp.h @@ -0,0 +1,46 @@ +/* +* 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_NIST_PRIMES_H_ +#define BOTAN_NIST_PRIMES_H_ + +#include <botan/bigint.h> + +namespace Botan { + +/** +* 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. +*/ +BOTAN_PUBLIC_API(2,0) const BigInt& prime_p521(); +BOTAN_PUBLIC_API(2,0) void redc_p521(BigInt& x, secure_vector<word>& ws); + +#if (BOTAN_MP_WORD_BITS == 32) || (BOTAN_MP_WORD_BITS == 64) + +#define BOTAN_HAS_NIST_PRIME_REDUCERS_W32 + +BOTAN_PUBLIC_API(2,0) const BigInt& prime_p384(); +BOTAN_PUBLIC_API(2,0) void redc_p384(BigInt& x, secure_vector<word>& ws); + +BOTAN_PUBLIC_API(2,0) const BigInt& prime_p256(); +BOTAN_PUBLIC_API(2,0) void redc_p256(BigInt& x, secure_vector<word>& ws); + +BOTAN_PUBLIC_API(2,0) const BigInt& prime_p224(); +BOTAN_PUBLIC_API(2,0) void redc_p224(BigInt& x, secure_vector<word>& ws); + +BOTAN_PUBLIC_API(2,0) const BigInt& prime_p192(); +BOTAN_PUBLIC_API(2,0) void redc_p192(BigInt& x, secure_vector<word>& ws); + +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/def_powm.h b/src/libs/3rdparty/botan/src/lib/math/numbertheory/def_powm.h new file mode 100644 index 0000000000..6b1f33835f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/def_powm.h @@ -0,0 +1,68 @@ +/* +* Modular Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DEFAULT_MODEXP_H_ +#define BOTAN_DEFAULT_MODEXP_H_ + +#include <botan/pow_mod.h> +#include <botan/reducer.h> +#include <vector> + +namespace Botan { + +/** +* Fixed Window Exponentiator +*/ +class Fixed_Window_Exponentiator final : public Modular_Exponentiator + { + public: + void set_exponent(const BigInt&) override; + void set_base(const BigInt&) override; + BigInt execute() const override; + + Modular_Exponentiator* copy() const override + { return new Fixed_Window_Exponentiator(*this); } + + Fixed_Window_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); + private: + Modular_Reducer m_reducer; + BigInt m_exp; + size_t m_window_bits; + std::vector<BigInt> m_g; + Power_Mod::Usage_Hints m_hints; + }; + +class Montgomery_Params; +class Montgomery_Exponentation_State; + +/** +* Montgomery Exponentiator +*/ +class Montgomery_Exponentiator final : public Modular_Exponentiator + { + public: + void set_exponent(const BigInt&) override; + void set_base(const BigInt&) override; + BigInt execute() const override; + + Modular_Exponentiator* copy() const override + { return new Montgomery_Exponentiator(*this); } + + Montgomery_Exponentiator(const BigInt&, Power_Mod::Usage_Hints); + private: + BigInt m_p; + Modular_Reducer m_mod_p; + std::shared_ptr<const Montgomery_Params> m_monty_params; + std::shared_ptr<const Montgomery_Exponentation_State> m_monty; + + BigInt m_e; + Power_Mod::Usage_Hints m_hints; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/dsa_gen.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/dsa_gen.cpp new file mode 100644 index 0000000000..a5efbc2662 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/dsa_gen.cpp @@ -0,0 +1,136 @@ +/* +* DSA Parameter Generation +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/numthry.h> +#include <botan/hash.h> +#include <botan/reducer.h> +#include <botan/rng.h> + +namespace Botan { + +namespace { + +/* +* Check if this size is allowed by FIPS 186-3 +*/ +bool fips186_3_valid_size(size_t pbits, size_t qbits) + { + if(qbits == 160) + return (pbits == 1024); + + if(qbits == 224) + return (pbits == 2048); + + if(qbits == 256) + return (pbits == 2048 || pbits == 3072); + + return false; + } + +} + +/* +* Attempt DSA prime generation with given seed +*/ +bool generate_dsa_primes(RandomNumberGenerator& rng, + BigInt& p, BigInt& q, + size_t pbits, size_t qbits, + const std::vector<uint8_t>& seed_c, + size_t offset) + { + if(!fips186_3_valid_size(pbits, qbits)) + throw Invalid_Argument( + "FIPS 186-3 does not allow DSA domain parameters of " + + std::to_string(pbits) + "/" + std::to_string(qbits) + " bits long"); + + if(seed_c.size() * 8 < qbits) + throw Invalid_Argument( + "Generating a DSA parameter set with a " + std::to_string(qbits) + + " bit long q requires a seed at least as many bits long"); + + const std::string hash_name = "SHA-" + std::to_string(qbits); + std::unique_ptr<HashFunction> hash(HashFunction::create_or_throw(hash_name)); + + const size_t HASH_SIZE = hash->output_length(); + + class Seed final + { + public: + explicit Seed(const std::vector<uint8_t>& s) : m_seed(s) {} + + const std::vector<uint8_t>& value() const { return m_seed; } + + Seed& operator++() + { + for(size_t j = m_seed.size(); j > 0; --j) + if(++m_seed[j-1]) + break; + return (*this); + } + private: + std::vector<uint8_t> m_seed; + }; + + Seed seed(seed_c); + + q.binary_decode(hash->process(seed.value())); + q.set_bit(qbits-1); + q.set_bit(0); + + if(!is_prime(q, rng, 128, true)) + return false; + + const size_t n = (pbits-1) / (HASH_SIZE * 8), + b = (pbits-1) % (HASH_SIZE * 8); + + BigInt X; + std::vector<uint8_t> V(HASH_SIZE * (n+1)); + + Modular_Reducer mod_2q(2*q); + + for(size_t j = 0; j != 4*pbits; ++j) + { + for(size_t k = 0; k <= n; ++k) + { + ++seed; + hash->update(seed.value()); + hash->final(&V[HASH_SIZE * (n-k)]); + } + + if(j >= offset) + { + X.binary_decode(&V[HASH_SIZE - 1 - b/8], + V.size() - (HASH_SIZE - 1 - b/8)); + X.set_bit(pbits-1); + + p = X - (mod_2q.reduce(X) - 1); + + if(p.bits() == pbits && is_prime(p, rng, 128, true)) + return true; + } + } + return false; + } + +/* +* Generate DSA Primes +*/ +std::vector<uint8_t> generate_dsa_primes(RandomNumberGenerator& rng, + BigInt& p, BigInt& q, + size_t pbits, size_t qbits) + { + while(true) + { + std::vector<uint8_t> seed(qbits / 8); + rng.randomize(seed.data(), seed.size()); + + if(generate_dsa_primes(rng, p, q, pbits, qbits, seed)) + return seed; + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/info.txt b/src/libs/3rdparty/botan/src/lib/math/numbertheory/info.txt new file mode 100644 index 0000000000..8da52f9f43 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/info.txt @@ -0,0 +1,24 @@ +<defines> +NUMBERTHEORY -> 20131128 +</defines> + +load_on auto + +<header:public> +curve_nistp.h +numthry.h +pow_mod.h +reducer.h +monty.h +</header:public> + +<header:internal> +def_powm.h +monty_exp.h +</header:internal> + +<requires> +bigint +hash +rng +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/jacobi.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/jacobi.cpp new file mode 100644 index 0000000000..d3e8d75572 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/jacobi.cpp @@ -0,0 +1,53 @@ +/* +* Jacobi Function +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/numthry.h> + +namespace Botan { + +/* +* Calculate the Jacobi symbol +*/ +int32_t jacobi(const BigInt& a, const BigInt& n) + { + if(a.is_negative()) + throw Invalid_Argument("jacobi: first argument must be non-negative"); + if(n.is_even() || n < 2) + throw Invalid_Argument("jacobi: second argument must be odd and > 1"); + + BigInt x = a, y = n; + int32_t J = 1; + + while(y > 1) + { + x %= y; + if(x > y / 2) + { + x = y - x; + if(y % 4 == 3) + J = -J; + } + if(x.is_zero()) + return 0; + + size_t shifts = low_zero_bits(x); + x >>= shifts; + if(shifts % 2) + { + word y_mod_8 = y % 8; + if(y_mod_8 == 3 || y_mod_8 == 5) + J = -J; + } + + if(x % 4 == 3 && y % 4 == 3) + J = -J; + std::swap(x, y); + } + return J; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/make_prm.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/make_prm.cpp new file mode 100644 index 0000000000..1979fa5502 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/make_prm.cpp @@ -0,0 +1,285 @@ +/* +* Prime Generation +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/numthry.h> +#include <botan/rng.h> +#include <botan/internal/bit_ops.h> +#include <algorithm> + +namespace Botan { + +namespace { + +class Prime_Sieve + { + public: + Prime_Sieve(const BigInt& init_value) : m_sieve(PRIME_TABLE_SIZE) + { + for(size_t i = 0; i != m_sieve.size(); ++i) + m_sieve[i] = static_cast<uint16_t>(init_value % PRIMES[i]); + } + + void step(word increment) + { + for(size_t i = 0; i != m_sieve.size(); ++i) + { + m_sieve[i] = (m_sieve[i] + increment) % PRIMES[i]; + } + } + + bool passes(bool check_2p1 = false) const + { + for(size_t i = 0; i != m_sieve.size(); ++i) + { + /* + In this case, p is a multiple of PRIMES[i] + */ + if(m_sieve[i] == 0) + return false; + + if(check_2p1) + { + /* + In this case, 2*p+1 will be a multiple of PRIMES[i] + + So if potentially generating a safe prime, we want to + avoid this value because 2*p+1 will certainly not be prime. + + See "Safe Prime Generation with a Combined Sieve" M. Wiener + https://eprint.iacr.org/2003/186.pdf + */ + if(m_sieve[i] == (PRIMES[i] - 1) / 2) + return false; + } + } + + return true; + } + + private: + std::vector<uint16_t> m_sieve; + }; + +} + + +/* +* Generate a random prime +*/ +BigInt random_prime(RandomNumberGenerator& rng, + size_t bits, const BigInt& coprime, + size_t equiv, size_t modulo, + size_t prob) + { + if(coprime.is_negative()) + { + throw Invalid_Argument("random_prime: coprime must be >= 0"); + } + if(modulo == 0) + { + throw Invalid_Argument("random_prime: Invalid modulo value"); + } + + equiv %= modulo; + + if(equiv == 0) + throw Invalid_Argument("random_prime Invalid value for equiv/modulo"); + + // Handle small values: + if(bits <= 1) + { + throw Invalid_Argument("random_prime: Can't make a prime of " + + std::to_string(bits) + " bits"); + } + else if(bits == 2) + { + return ((rng.next_byte() % 2) ? 2 : 3); + } + else if(bits == 3) + { + return ((rng.next_byte() % 2) ? 5 : 7); + } + else if(bits == 4) + { + return ((rng.next_byte() % 2) ? 11 : 13); + } + else if(bits <= 16) + { + for(;;) + { + size_t idx = make_uint16(rng.next_byte(), rng.next_byte()) % PRIME_TABLE_SIZE; + uint16_t small_prime = PRIMES[idx]; + + if(high_bit(small_prime) == bits) + return small_prime; + } + } + + const size_t MAX_ATTEMPTS = 32*1024; + + while(true) + { + BigInt p(rng, bits); + + // Force lowest and two top bits on + p.set_bit(bits - 1); + p.set_bit(bits - 2); + p.set_bit(0); + + // Force p to be equal to equiv mod modulo + p += (modulo - (p % modulo)) + equiv; + + Prime_Sieve sieve(p); + + size_t counter = 0; + while(true) + { + ++counter; + + if(counter > MAX_ATTEMPTS) + { + break; // don't try forever, choose a new starting point + } + + p += modulo; + + sieve.step(modulo); + + if(sieve.passes(true) == false) + continue; + + if(coprime > 1) + { + /* + * Check if gcd(p - 1, coprime) != 1 by computing the inverse. The + * gcd algorithm is not constant time, but modular inverse is (for + * odd modulus anyway). This avoids a side channel attack against RSA + * key generation, though RSA keygen should be using generate_rsa_prime. + */ + if(inverse_mod(p - 1, coprime).is_zero()) + continue; + } + + if(p.bits() > bits) + break; + + if(is_prime(p, rng, prob, true)) + return p; + } + } + } + +BigInt generate_rsa_prime(RandomNumberGenerator& keygen_rng, + RandomNumberGenerator& prime_test_rng, + size_t bits, + const BigInt& coprime, + size_t prob) + { + if(bits < 512) + throw Invalid_Argument("generate_rsa_prime bits too small"); + + /* + * The restriction on coprime <= 64 bits is arbitrary but generally speaking + * very large RSA public exponents are a bad idea both for performance and due + * to attacks on small d. + */ + if(coprime <= 1 || coprime.is_even() || coprime.bits() > 64) + throw Invalid_Argument("generate_rsa_prime coprime must be small odd positive integer"); + + const size_t MAX_ATTEMPTS = 32*1024; + + while(true) + { + BigInt p(keygen_rng, bits); + + // Force lowest and two top bits on + p.set_bit(bits - 1); + p.set_bit(bits - 2); + p.set_bit(0); + + Prime_Sieve sieve(p); + + const word step = 2; + + size_t counter = 0; + while(true) + { + ++counter; + + if(counter > MAX_ATTEMPTS) + { + break; // don't try forever, choose a new starting point + } + + p += step; + + sieve.step(step); + + if(sieve.passes() == false) + continue; + + /* + * Check if p - 1 and coprime are relatively prime by computing the inverse. + * + * We avoid gcd here because that algorithm is not constant time. + * Modular inverse is (for odd modulus anyway). + * + * We earlier verified that coprime argument is odd. Thus the factors of 2 + * in (p - 1) cannot possibly be factors in coprime, so remove them from p - 1. + * Using an odd modulus allows the const time algorithm to be used. + * + * This assumes coprime < p - 1 which is always true for RSA. + */ + BigInt p1 = p - 1; + p1 >>= low_zero_bits(p1); + if(inverse_mod(coprime, p1).is_zero()) + { + BOTAN_DEBUG_ASSERT(gcd(p1, coprime) > 1); + continue; + } + + BOTAN_DEBUG_ASSERT(gcd(p1, coprime) == 1); + + if(p.bits() > bits) + break; + + if(is_prime(p, prime_test_rng, prob, true)) + return p; + } + } + } + +/* +* Generate a random safe prime +*/ +BigInt random_safe_prime(RandomNumberGenerator& rng, size_t bits) + { + if(bits <= 64) + throw Invalid_Argument("random_safe_prime: Can't make a prime of " + + std::to_string(bits) + " bits"); + + BigInt q, p; + for(;;) + { + /* + Generate q == 2 (mod 3) + + Otherwise [q == 1 (mod 3) case], 2*q+1 == 3 (mod 3) and not prime. + */ + q = random_prime(rng, bits - 1, 0, 2, 3, 8); + p = (q << 1) + 1; + + if(is_prime(p, rng, 128, true)) + { + // We did only a weak check before, go back and verify q before returning + if(is_prime(q, rng, 128, true)) + return p; + } + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty.cpp new file mode 100644 index 0000000000..b91560fd58 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty.cpp @@ -0,0 +1,449 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/monty.h> +#include <botan/reducer.h> +#include <botan/internal/mp_core.h> + +namespace Botan { + +Montgomery_Params::Montgomery_Params(const BigInt& p, + const Modular_Reducer& mod_p) + { + if(p.is_negative() || p.is_even()) + throw Invalid_Argument("Montgomery_Params invalid modulus"); + + m_p = p; + m_p_words = m_p.sig_words(); + m_p_dash = monty_inverse(m_p.word_at(0)); + + const BigInt r = BigInt::power_of_2(m_p_words * BOTAN_MP_WORD_BITS); + + m_r1 = mod_p.reduce(r); + m_r2 = mod_p.square(m_r1); + m_r3 = mod_p.multiply(m_r1, m_r2); + } + +Montgomery_Params::Montgomery_Params(const BigInt& p) + { + + if(p.is_negative() || p.is_even()) + throw Invalid_Argument("Montgomery_Params invalid modulus"); + + m_p = p; + m_p_words = m_p.sig_words(); + m_p_dash = monty_inverse(m_p.word_at(0)); + + const BigInt r = BigInt::power_of_2(m_p_words * BOTAN_MP_WORD_BITS); + + Modular_Reducer mod_p(p); + + m_r1 = mod_p.reduce(r); + m_r2 = mod_p.square(m_r1); + m_r3 = mod_p.multiply(m_r1, m_r2); + } + +BigInt Montgomery_Params::inv_mod_p(const BigInt& x) const + { + return ct_inverse_mod_odd_modulus(x, p()); + } + +BigInt Montgomery_Params::redc(const BigInt& x, secure_vector<word>& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < output_size) + ws.resize(output_size); + + BigInt z = x; + z.grow_to(output_size); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + + return z; + } + +BigInt Montgomery_Params::mul(const BigInt& x, const BigInt& y, + secure_vector<word>& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < output_size) + ws.resize(output_size); + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words); + + BigInt z(BigInt::Positive, output_size); + bigint_mul(z.mutable_data(), z.size(), + x.data(), x.size(), std::min(m_p_words, x.size()), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + + return z; + } + +BigInt Montgomery_Params::mul(const BigInt& x, + const secure_vector<word>& y, + secure_vector<word>& ws) const + { + const size_t output_size = 2*m_p_words + 2; + if(ws.size() < output_size) + ws.resize(output_size); + BigInt z(BigInt::Positive, output_size); + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + + bigint_mul(z.mutable_data(), z.size(), + x.data(), x.size(), std::min(m_p_words, x.size()), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + + return z; + } + +void Montgomery_Params::mul_by(BigInt& x, + const secure_vector<word>& y, + secure_vector<word>& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < 2*output_size) + ws.resize(2*output_size); + + word* z_data = &ws[0]; + word* ws_data = &ws[output_size]; + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + + bigint_mul(z_data, output_size, + x.data(), x.size(), std::min(m_p_words, x.size()), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws_data, output_size); + + bigint_monty_redc(z_data, + m_p.data(), m_p_words, m_p_dash, + ws_data, output_size); + + if(x.size() < output_size) + x.grow_to(output_size); + copy_mem(x.mutable_data(), z_data, output_size); + } + +void Montgomery_Params::mul_by(BigInt& x, + const BigInt& y, + secure_vector<word>& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < 2*output_size) + ws.resize(2*output_size); + + word* z_data = &ws[0]; + word* ws_data = &ws[output_size]; + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + + bigint_mul(z_data, output_size, + x.data(), x.size(), std::min(m_p_words, x.size()), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws_data, output_size); + + bigint_monty_redc(z_data, + m_p.data(), m_p_words, m_p_dash, + ws_data, output_size); + + if(x.size() < output_size) + x.grow_to(output_size); + copy_mem(x.mutable_data(), z_data, output_size); + } + +BigInt Montgomery_Params::sqr(const BigInt& x, secure_vector<word>& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < output_size) + ws.resize(output_size); + + BigInt z(BigInt::Positive, output_size); + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + + bigint_sqr(z.mutable_data(), z.size(), + x.data(), x.size(), std::min(m_p_words, x.size()), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + + return z; + } + +void Montgomery_Params::square_this(BigInt& x, + secure_vector<word>& ws) const + { + const size_t output_size = 2*m_p_words + 2; + + if(ws.size() < 2*output_size) + ws.resize(2*output_size); + + word* z_data = &ws[0]; + word* ws_data = &ws[output_size]; + + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + + bigint_sqr(z_data, output_size, + x.data(), x.size(), std::min(m_p_words, x.size()), + ws_data, output_size); + + bigint_monty_redc(z_data, + m_p.data(), m_p_words, m_p_dash, + ws_data, output_size); + + if(x.size() < output_size) + x.grow_to(output_size); + copy_mem(x.mutable_data(), z_data, output_size); + } + +Montgomery_Int::Montgomery_Int(const std::shared_ptr<const Montgomery_Params> params, + const BigInt& v, + bool redc_needed) : + m_params(params) + { + if(redc_needed == false) + { + m_v = v; + } + else + { + secure_vector<word> ws; + m_v = m_params->mul(v % m_params->p(), m_params->R2(), ws); + } + } + +Montgomery_Int::Montgomery_Int(std::shared_ptr<const Montgomery_Params> params, + const uint8_t bits[], size_t len, + bool redc_needed) : + m_params(params), + m_v(bits, len) + { + if(redc_needed) + { + secure_vector<word> ws; + m_v = m_params->mul(m_v % m_params->p(), m_params->R2(), ws); + } + } + +Montgomery_Int::Montgomery_Int(std::shared_ptr<const Montgomery_Params> params, + const word words[], size_t len, + bool redc_needed) : + m_params(params), + m_v(words, len) + { + if(redc_needed) + { + secure_vector<word> ws; + m_v = m_params->mul(m_v % m_params->p(), m_params->R2(), ws); + } + } + +void Montgomery_Int::fix_size() + { + const size_t p_words = m_params->p_words(); + + if(m_v.sig_words() > p_words) + throw Internal_Error("Montgomery_Int::fix_size v too large"); + + secure_vector<word>& w = m_v.get_word_vector(); + + if(w.size() != p_words) + { + w.resize(p_words); + w.shrink_to_fit(); + } + } + +bool Montgomery_Int::operator==(const Montgomery_Int& other) const + { + return m_v == other.m_v && m_params->p() == other.m_params->p(); + } + +std::vector<uint8_t> Montgomery_Int::serialize() const + { + std::vector<uint8_t> v(size()); + BigInt::encode_1363(v.data(), v.size(), value()); + return v; + } + +size_t Montgomery_Int::size() const + { + return m_params->p().bytes(); + } + +bool Montgomery_Int::is_one() const + { + return m_v == m_params->R1(); + } + +bool Montgomery_Int::is_zero() const + { + return m_v.is_zero(); + } + +BigInt Montgomery_Int::value() const + { + secure_vector<word> ws; + return m_params->redc(m_v, ws); + } + +Montgomery_Int Montgomery_Int::operator+(const Montgomery_Int& other) const + { + BigInt z = m_v + other.m_v; + secure_vector<word> ws; + z.reduce_below(m_params->p(), ws); + return Montgomery_Int(m_params, z, false); + } + +Montgomery_Int Montgomery_Int::operator-(const Montgomery_Int& other) const + { + BigInt z = m_v - other.m_v; + if(z.is_negative()) + z += m_params->p(); + return Montgomery_Int(m_params, z, false); + } + +Montgomery_Int& Montgomery_Int::operator+=(const Montgomery_Int& other) + { + secure_vector<word> ws; + return this->add(other, ws); + } + +Montgomery_Int& Montgomery_Int::add(const Montgomery_Int& other, secure_vector<word>& ws) + { + m_v.mod_add(other.m_v, m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::operator-=(const Montgomery_Int& other) + { + secure_vector<word> ws; + return this->sub(other, ws); + } + +Montgomery_Int& Montgomery_Int::sub(const Montgomery_Int& other, secure_vector<word>& ws) + { + m_v.mod_sub(other.m_v, m_params->p(), ws); + return (*this); + } + +Montgomery_Int Montgomery_Int::operator*(const Montgomery_Int& other) const + { + secure_vector<word> ws; + return Montgomery_Int(m_params, m_params->mul(m_v, other.m_v, ws), false); + } + +Montgomery_Int Montgomery_Int::mul(const Montgomery_Int& other, + secure_vector<word>& ws) const + { + return Montgomery_Int(m_params, m_params->mul(m_v, other.m_v, ws), false); + } + +Montgomery_Int& Montgomery_Int::mul_by(const Montgomery_Int& other, + secure_vector<word>& ws) + { + m_params->mul_by(m_v, other.m_v, ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by(const secure_vector<word>& other, + secure_vector<word>& ws) + { + m_params->mul_by(m_v, other, ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::operator*=(const Montgomery_Int& other) + { + secure_vector<word> ws; + return mul_by(other, ws); + } + +Montgomery_Int& Montgomery_Int::operator*=(const secure_vector<word>& other) + { + secure_vector<word> ws; + return mul_by(other, ws); + } + +Montgomery_Int& Montgomery_Int::square_this_n_times(secure_vector<word>& ws, size_t n) + { + for(size_t i = 0; i != n; ++i) + m_params->square_this(m_v, ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::square_this(secure_vector<word>& ws) + { + m_params->square_this(m_v, ws); + return (*this); + } + +Montgomery_Int Montgomery_Int::square(secure_vector<word>& ws) const + { + return Montgomery_Int(m_params, m_params->sqr(m_v, ws), false); + } + +Montgomery_Int Montgomery_Int::multiplicative_inverse() const + { + secure_vector<word> ws; + const BigInt iv = m_params->mul(m_params->inv_mod_p(m_v), m_params->R3(), ws); + return Montgomery_Int(m_params, iv, false); + } + +Montgomery_Int Montgomery_Int::additive_inverse() const + { + return Montgomery_Int(m_params, m_params->p()) - (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_2(secure_vector<word>& ws) + { + m_v <<= 1; + m_v.reduce_below(m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_3(secure_vector<word>& ws) + { + m_v *= 3; + m_v.reduce_below(m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_4(secure_vector<word>& ws) + { + m_v <<= 2; + m_v.reduce_below(m_params->p(), ws); + return (*this); + } + +Montgomery_Int& Montgomery_Int::mul_by_8(secure_vector<word>& ws) + { + m_v <<= 3; + m_v.reduce_below(m_params->p(), ws); + return (*this); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty.h b/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty.h new file mode 100644 index 0000000000..e5ab2f9ada --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty.h @@ -0,0 +1,190 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MONTY_INT_H_ +#define BOTAN_MONTY_INT_H_ + +#include <botan/bigint.h> + +namespace Botan { + +class Modular_Reducer; + +class Montgomery_Params; + +/** +* The Montgomery representation of an integer +*/ +class BOTAN_UNSTABLE_API Montgomery_Int final + { + public: + /** + * Create a zero-initialized Montgomery_Int + */ + Montgomery_Int(std::shared_ptr<const Montgomery_Params> params) : m_params(params) {} + + /** + * Create a Montgomery_Int + */ + Montgomery_Int(std::shared_ptr<const Montgomery_Params> params, + const BigInt& v, + bool redc_needed = true); + + /** + * Create a Montgomery_Int + */ + Montgomery_Int(std::shared_ptr<const Montgomery_Params> params, + const uint8_t bits[], size_t len, + bool redc_needed = true); + + /** + * Create a Montgomery_Int + */ + Montgomery_Int(std::shared_ptr<const Montgomery_Params> params, + const word words[], size_t len, + bool redc_needed = true); + + bool operator==(const Montgomery_Int& other) const; + bool operator!=(const Montgomery_Int& other) const { return (m_v != other.m_v); } + + std::vector<uint8_t> serialize() const; + + size_t size() const; + bool is_one() const; + bool is_zero() const; + + void fix_size(); + + /** + * Return the value to normal mod-p space + */ + BigInt value() const; + + /** + * Return the Montgomery representation + */ + const BigInt& repr() const { return m_v; } + + Montgomery_Int operator+(const Montgomery_Int& other) const; + + Montgomery_Int operator-(const Montgomery_Int& other) const; + + Montgomery_Int& operator+=(const Montgomery_Int& other); + + Montgomery_Int& operator-=(const Montgomery_Int& other); + + Montgomery_Int operator*(const Montgomery_Int& other) const; + + Montgomery_Int& operator*=(const Montgomery_Int& other); + + Montgomery_Int& operator*=(const secure_vector<word>& other); + + Montgomery_Int& add(const Montgomery_Int& other, + secure_vector<word>& ws); + + Montgomery_Int& sub(const Montgomery_Int& other, + secure_vector<word>& ws); + + Montgomery_Int mul(const Montgomery_Int& other, + secure_vector<word>& ws) const; + + Montgomery_Int& mul_by(const Montgomery_Int& other, + secure_vector<word>& ws); + + Montgomery_Int& mul_by(const secure_vector<word>& other, + secure_vector<word>& ws); + + Montgomery_Int square(secure_vector<word>& ws) const; + + Montgomery_Int& square_this(secure_vector<word>& ws); + + Montgomery_Int& square_this_n_times(secure_vector<word>& ws, size_t n); + + Montgomery_Int multiplicative_inverse() const; + + Montgomery_Int additive_inverse() const; + + Montgomery_Int& mul_by_2(secure_vector<word>& ws); + + Montgomery_Int& mul_by_3(secure_vector<word>& ws); + + Montgomery_Int& mul_by_4(secure_vector<word>& ws); + + Montgomery_Int& mul_by_8(secure_vector<word>& ws); + + void const_time_poison() const { m_v.const_time_poison(); } + void const_time_unpoison() const { return m_v.const_time_unpoison(); } + + private: + std::shared_ptr<const Montgomery_Params> m_params; + BigInt m_v; + }; + +/** +* Parameters for Montgomery Reduction +*/ +class BOTAN_UNSTABLE_API Montgomery_Params final + { + public: + /** + * Initialize a set of Montgomery reduction parameters. These values + * can be shared by all values in a specific Montgomery domain. + */ + Montgomery_Params(const BigInt& p, const Modular_Reducer& mod_p); + + /** + * Initialize a set of Montgomery reduction parameters. These values + * can be shared by all values in a specific Montgomery domain. + */ + Montgomery_Params(const BigInt& p); + + const BigInt& p() const { return m_p; } + const BigInt& R1() const { return m_r1; } + const BigInt& R2() const { return m_r2; } + const BigInt& R3() const { return m_r3; } + + word p_dash() const { return m_p_dash; } + + size_t p_words() const { return m_p_words; } + + BigInt redc(const BigInt& x, + secure_vector<word>& ws) const; + + BigInt mul(const BigInt& x, + const BigInt& y, + secure_vector<word>& ws) const; + + BigInt mul(const BigInt& x, + const secure_vector<word>& y, + secure_vector<word>& ws) const; + + void mul_by(BigInt& x, + const secure_vector<word>& y, + secure_vector<word>& ws) const; + + void mul_by(BigInt& x, const BigInt& y, + secure_vector<word>& ws) const; + + BigInt sqr(const BigInt& x, + secure_vector<word>& ws) const; + + void square_this(BigInt& x, + secure_vector<word>& ws) const; + + BigInt inv_mod_p(const BigInt& x) const; + + private: + BigInt m_p; + BigInt m_r1; + BigInt m_r2; + BigInt m_r3; + word m_p_dash; + size_t m_p_words; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty_exp.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty_exp.cpp new file mode 100644 index 0000000000..5674920915 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty_exp.cpp @@ -0,0 +1,248 @@ +/* +* Montgomery Exponentiation +* (C) 1999-2010,2012,2018 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/monty_exp.h> +#include <botan/internal/ct_utils.h> +#include <botan/internal/rounding.h> +#include <botan/numthry.h> +#include <botan/reducer.h> +#include <botan/monty.h> + +namespace Botan { + +class Montgomery_Exponentation_State + { + public: + Montgomery_Exponentation_State(std::shared_ptr<const Montgomery_Params> params, + const BigInt& g, + size_t window_bits, + bool const_time); + + BigInt exponentiation(const BigInt& k, size_t max_k_bits) const; + + BigInt exponentiation_vartime(const BigInt& k) const; + private: + std::shared_ptr<const Montgomery_Params> m_params; + std::vector<Montgomery_Int> m_g; + size_t m_window_bits; + bool m_const_time; + }; + +Montgomery_Exponentation_State::Montgomery_Exponentation_State(std::shared_ptr<const Montgomery_Params> params, + const BigInt& g, + size_t window_bits, + bool const_time) : + m_params(params), + m_window_bits(window_bits == 0 ? 4 : window_bits), + m_const_time(const_time) + { + if(m_window_bits < 1 || m_window_bits > 12) // really even 8 is too large ... + throw Invalid_Argument("Invalid window bits for Montgomery exponentiation"); + + const size_t window_size = (1U << m_window_bits); + + m_g.reserve(window_size); + + m_g.push_back(Montgomery_Int(m_params, m_params->R1(), false)); + + m_g.push_back(Montgomery_Int(m_params, g)); + + const Montgomery_Int& monty_g = m_g[1]; + + for(size_t i = 2; i != window_size; ++i) + { + m_g.push_back(monty_g * m_g[i - 1]); + } + + // Resize each element to exactly p words + for(size_t i = 0; i != window_size; ++i) + { + m_g[i].fix_size(); + if(const_time) + m_g[i].const_time_poison(); + } + } + +namespace { + +void const_time_lookup(secure_vector<word>& output, + const std::vector<Montgomery_Int>& g, + size_t nibble) + { + const size_t words = output.size(); + + clear_mem(output.data(), output.size()); + + for(size_t i = 0; i != g.size(); ++i) + { + const secure_vector<word>& vec = g[i].repr().get_word_vector(); + + BOTAN_ASSERT(vec.size() >= words, + "Word size as expected in const_time_lookup"); + + const word mask = CT::is_equal<word>(i, nibble); + + for(size_t w = 0; w != words; ++w) + output[w] |= (mask & vec[w]); + } + } + +} + +BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size_t max_k_bits) const + { + BOTAN_DEBUG_ASSERT(scalar.bits() <= max_k_bits); + // TODO add a const-time implementation of above assert and use it in release builds + + const size_t exp_nibbles = (max_k_bits + m_window_bits - 1) / m_window_bits; + + if(exp_nibbles == 0) + return 1; + + secure_vector<word> e_bits(m_params->p_words()); + secure_vector<word> ws; + + const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits)); + Montgomery_Int x(m_params, e_bits.data(), e_bits.size(), false); + + for(size_t i = exp_nibbles - 1; i > 0; --i) + { + x.square_this_n_times(ws, m_window_bits); + const_time_lookup(e_bits, m_g, scalar.get_substring(m_window_bits*(i-1), m_window_bits)); + x.mul_by(e_bits, ws); + } + + x.const_time_unpoison(); + return x.value(); + } + +BigInt Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scalar) const + { + BOTAN_ASSERT_NOMSG(m_const_time == false); + + const size_t exp_nibbles = (scalar.bits() + m_window_bits - 1) / m_window_bits; + + secure_vector<word> ws; + + if(exp_nibbles == 0) + return 1; + + Montgomery_Int x = m_g[scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits)]; + + for(size_t i = exp_nibbles - 1; i > 0; --i) + { + x.square_this_n_times(ws, m_window_bits); + + const uint32_t nibble = scalar.get_substring(m_window_bits*(i-1), m_window_bits); + if(nibble > 0) + x.mul_by(m_g[nibble], ws); + } + + x.const_time_unpoison(); + return x.value(); + } + +std::shared_ptr<const Montgomery_Exponentation_State> +monty_precompute(std::shared_ptr<const Montgomery_Params> params, + const BigInt& g, + size_t window_bits, + bool const_time) + { + return std::make_shared<const Montgomery_Exponentation_State>(params, g, window_bits, const_time); + } + +BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state, + const BigInt& k, size_t max_k_bits) + { + return precomputed_state.exponentiation(k, max_k_bits); + } + +BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state, + const BigInt& k) + { + return precomputed_state.exponentiation_vartime(k); + } + +BigInt monty_multi_exp(std::shared_ptr<const Montgomery_Params> params_p, + const BigInt& x_bn, + const BigInt& z1, + const BigInt& y_bn, + const BigInt& z2) + { + if(z1.is_negative() || z2.is_negative()) + throw Invalid_Argument("multi_exponentiate exponents must be positive"); + + const size_t z_bits = round_up(std::max(z1.bits(), z2.bits()), 2); + + secure_vector<word> ws; + + const Montgomery_Int one(params_p, params_p->R1(), false); + //const Montgomery_Int one(params_p, 1); + + const Montgomery_Int x1(params_p, x_bn); + const Montgomery_Int x2 = x1.square(ws); + const Montgomery_Int x3 = x2.mul(x1, ws); + + const Montgomery_Int y1(params_p, y_bn); + const Montgomery_Int y2 = y1.square(ws); + const Montgomery_Int y3 = y2.mul(y1, ws); + + const Montgomery_Int y1x1 = y1.mul(x1, ws); + const Montgomery_Int y1x2 = y1.mul(x2, ws); + const Montgomery_Int y1x3 = y1.mul(x3, ws); + + const Montgomery_Int y2x1 = y2.mul(x1, ws); + const Montgomery_Int y2x2 = y2.mul(x2, ws); + const Montgomery_Int y2x3 = y2.mul(x3, ws); + + const Montgomery_Int y3x1 = y3.mul(x1, ws); + const Montgomery_Int y3x2 = y3.mul(x2, ws); + const Montgomery_Int y3x3 = y3.mul(x3, ws); + + const Montgomery_Int* M[16] = { + &one, + &x1, // 0001 + &x2, // 0010 + &x3, // 0011 + &y1, // 0100 + &y1x1, + &y1x2, + &y1x3, + &y2, // 1000 + &y2x1, + &y2x2, + &y2x3, + &y3, // 1100 + &y3x1, + &y3x2, + &y3x3 + }; + + Montgomery_Int H = one; + + for(size_t i = 0; i != z_bits; i += 2) + { + if(i > 0) + { + H.square_this(ws); + H.square_this(ws); + } + + const uint8_t z1_b = z1.get_substring(z_bits - i - 2, 2); + const uint8_t z2_b = z2.get_substring(z_bits - i - 2, 2); + + const uint8_t z12 = (4*z2_b) + z1_b; + + H.mul_by(*M[z12], ws); + } + + return H.value(); + } + +} + diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty_exp.h b/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty_exp.h new file mode 100644 index 0000000000..632d7f7d6e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/monty_exp.h @@ -0,0 +1,54 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MONTY_EXP_H_ +#define BOTAN_MONTY_EXP_H_ + +#include <memory> + +namespace Botan { + +class BigInt; +class Modular_Reducer; + +class Montgomery_Params; + +class Montgomery_Exponentation_State; + +/* +* Precompute for calculating values g^x mod p +*/ +std::shared_ptr<const Montgomery_Exponentation_State> +monty_precompute(std::shared_ptr<const Montgomery_Params> params_p, + const BigInt& g, + size_t window_bits, + bool const_time = true); + +/* +* Return g^k mod p +*/ +BigInt monty_execute(const Montgomery_Exponentation_State& precomputed_state, + const BigInt& k, size_t max_k_bits); + +/* +* Return g^k mod p taking variable time depending on k +* @warning only use this if k is public +*/ +BigInt monty_execute_vartime(const Montgomery_Exponentation_State& precomputed_state, + const BigInt& k); + +/** +* Return (x^z1 * y^z2) % p +*/ +BigInt monty_multi_exp(std::shared_ptr<const Montgomery_Params> params_p, + const BigInt& x, + const BigInt& z1, + const BigInt& y, + const BigInt& z2); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/mp_numth.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/mp_numth.cpp new file mode 100644 index 0000000000..eef6419965 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/mp_numth.cpp @@ -0,0 +1,84 @@ +/* +* Fused and Important MP Algorithms +* (C) 1999-2007 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/numthry.h> +#include <botan/internal/mp_core.h> +#include <botan/internal/rounding.h> +#include <algorithm> + +namespace Botan { + +/* +* Square a BigInt +*/ +BigInt square(const BigInt& x) + { + BigInt z = x; + secure_vector<word> ws; + z.square(ws); + return z; + } + +/* +* Multiply-Add Operation +*/ +BigInt mul_add(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(c.is_negative()) + throw Invalid_Argument("mul_add: Third argument must be > 0"); + + BigInt::Sign sign = BigInt::Positive; + if(a.sign() != b.sign()) + sign = BigInt::Negative; + + const size_t a_sw = a.sig_words(); + const size_t b_sw = b.sig_words(); + const size_t c_sw = c.sig_words(); + + BigInt r(sign, std::max(a_sw + b_sw, c_sw) + 1); + secure_vector<word> workspace(r.size()); + + bigint_mul(r.mutable_data(), r.size(), + a.data(), a.size(), a_sw, + b.data(), b.size(), b_sw, + workspace.data(), workspace.size()); + + const size_t r_size = std::max(r.sig_words(), c_sw); + bigint_add2(r.mutable_data(), r_size, c.data(), c_sw); + return r; + } + +/* +* Subtract-Multiply Operation +*/ +BigInt sub_mul(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(a.is_negative() || b.is_negative()) + throw Invalid_Argument("sub_mul: First two arguments must be >= 0"); + + BigInt r = a; + r -= b; + r *= c; + return r; + } + +/* +* Multiply-Subtract Operation +*/ +BigInt mul_sub(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(c.is_negative() || c.is_zero()) + throw Invalid_Argument("mul_sub: Third argument must be > 0"); + + BigInt r = a; + r *= b; + r -= c; + return r; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/nistp_redc.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/nistp_redc.cpp new file mode 100644 index 0000000000..b74a2f9c6b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/nistp_redc.cpp @@ -0,0 +1,623 @@ +/* +* NIST prime reductions +* (C) 2014,2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/curve_nistp.h> +#include <botan/internal/mp_core.h> +#include <botan/internal/mp_asmi.h> + +namespace Botan { + +const BigInt& prime_p521() + { + static const BigInt p521("0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + + return p521; + } + +void redc_p521(BigInt& x, secure_vector<word>& ws) + { + const size_t p_full_words = 521 / BOTAN_MP_WORD_BITS; + const size_t p_top_bits = 521 % BOTAN_MP_WORD_BITS; + const size_t p_words = p_full_words + 1; + + const size_t x_sw = x.sig_words(); + + if(x_sw < p_words) + return; // already smaller + + if(ws.size() < p_words + 1) + ws.resize(p_words + 1); + + clear_mem(ws.data(), ws.size()); + bigint_shr2(ws.data(), x.data(), x_sw, p_full_words, p_top_bits); + + x.mask_bits(521); + + // Word-level carry will be zero + word carry = bigint_add3_nc(x.mutable_data(), x.data(), p_words, ws.data(), p_words); + BOTAN_ASSERT_EQUAL(carry, 0, "Final carry in P-521 reduction"); + + // Now find the actual carry in bit 522 + const uint8_t bit_522_set = x.word_at(p_full_words) >> (p_top_bits); + +#if (BOTAN_MP_WORD_BITS == 64) + static const word p521_words[9] = { + 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, + 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, + 0x1FF }; +#endif + + /* + * If bit 522 is set then we overflowed and must reduce. Otherwise, if the + * top bit is set, it is possible we have x == 2**521 - 1 so check for that. + */ + if(bit_522_set) + { +#if (BOTAN_MP_WORD_BITS == 64) + bigint_sub2(x.mutable_data(), x.size(), p521_words, 9); +#else + x -= prime_p521(); +#endif + } + else if(x.word_at(p_full_words) >> (p_top_bits - 1)) + { + /* + * Otherwise we must reduce if p is exactly 2^512-1 + */ + + word possibly_521 = MP_WORD_MAX; + for(size_t i = 0; i != p_full_words; ++i) + possibly_521 &= x.word_at(i); + + if(possibly_521 == MP_WORD_MAX) + x.reduce_below(prime_p521(), ws); + } + } + +#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32) + +namespace { + +/** +* Treating this MPI as a sequence of 32-bit words in big-endian +* order, return word i (or 0 if out of range) +*/ +inline uint32_t get_uint32_t(const BigInt& x, size_t i) + { +#if (BOTAN_MP_WORD_BITS == 32) + return x.word_at(i); +#elif (BOTAN_MP_WORD_BITS == 64) + return static_cast<uint32_t>(x.word_at(i/2) >> ((i % 2)*32)); +#else + #error "Not implemented" +#endif + } + +inline void set_words(BigInt& x, size_t i, uint32_t R0, uint32_t R1) + { +#if (BOTAN_MP_WORD_BITS == 32) + x.set_word_at(i, R0); + x.set_word_at(i+1, R1); +#elif (BOTAN_MP_WORD_BITS == 64) + x.set_word_at(i/2, (static_cast<uint64_t>(R1) << 32) | R0); +#else + #error "Not implemented" +#endif + } + +} + +const BigInt& prime_p192() + { + static const BigInt p192("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"); + return p192; + } + +void redc_p192(BigInt& x, secure_vector<word>& ws) + { + BOTAN_UNUSED(ws); + + static const size_t p192_limbs = 192 / BOTAN_MP_WORD_BITS; + + const uint64_t X00 = get_uint32_t(x, 0); + const uint64_t X01 = get_uint32_t(x, 1); + const uint64_t X02 = get_uint32_t(x, 2); + const uint64_t X03 = get_uint32_t(x, 3); + const uint64_t X04 = get_uint32_t(x, 4); + const uint64_t X05 = get_uint32_t(x, 5); + const uint64_t X06 = get_uint32_t(x, 6); + const uint64_t X07 = get_uint32_t(x, 7); + const uint64_t X08 = get_uint32_t(x, 8); + const uint64_t X09 = get_uint32_t(x, 9); + const uint64_t X10 = get_uint32_t(x, 10); + const uint64_t X11 = get_uint32_t(x, 11); + + const uint64_t S0 = X00 + X06 + X10; + const uint64_t S1 = X01 + X07 + X11; + const uint64_t S2 = X02 + X06 + X08 + X10; + const uint64_t S3 = X03 + X07 + X09 + X11; + const uint64_t S4 = X04 + X08 + X10; + const uint64_t S5 = X05 + X09 + X11; + + x.mask_bits(192); + + uint64_t S = 0; + uint32_t R0 = 0, R1 = 0; + + S += S0; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S1; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 0, R0, R1); + + S += S2; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S3; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 2, R0, R1); + + S += S4; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S5; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 4, R0, R1); + + // No underflow possible + + BOTAN_ASSERT(S <= 2, "Expected overflow in P-192 reduce"); + + /* + This is a table of (i*P-192) % 2**192 for i in 1...3 + */ + static const word p192_mults[3][p192_limbs] = { +#if (BOTAN_MP_WORD_BITS == 64) + {0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF}, + {0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFF}, + {0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFFFFFF}, +#else + {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, +#endif + }; + + if(S == 0 && x.word_at(p192_limbs-1) < p192_mults[0][p192_limbs-1]) + { + return; + } + + word borrow = bigint_sub2(x.mutable_data(), x.size(), p192_mults[S], p192_limbs); + + BOTAN_ASSERT(borrow == 0 || borrow == 1, "Expected borrow during P-192 reduction"); + + if(borrow) + { + bigint_add2(x.mutable_data(), x.size() - 1, p192_mults[0], p192_limbs); + } + } + +const BigInt& prime_p224() + { + static const BigInt p224("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"); + return p224; + } + +void redc_p224(BigInt& x, secure_vector<word>& ws) + { + static const size_t p224_limbs = (BOTAN_MP_WORD_BITS == 32) ? 7 : 4; + + BOTAN_UNUSED(ws); + + const int64_t X00 = get_uint32_t(x, 0); + const int64_t X01 = get_uint32_t(x, 1); + const int64_t X02 = get_uint32_t(x, 2); + const int64_t X03 = get_uint32_t(x, 3); + const int64_t X04 = get_uint32_t(x, 4); + const int64_t X05 = get_uint32_t(x, 5); + const int64_t X06 = get_uint32_t(x, 6); + const int64_t X07 = get_uint32_t(x, 7); + const int64_t X08 = get_uint32_t(x, 8); + const int64_t X09 = get_uint32_t(x, 9); + const int64_t X10 = get_uint32_t(x, 10); + const int64_t X11 = get_uint32_t(x, 11); + const int64_t X12 = get_uint32_t(x, 12); + const int64_t X13 = get_uint32_t(x, 13); + + // One full copy of P224 is added, so the result is always positive + + const int64_t S0 = 0x00000001 + X00 - X07 - X11; + const int64_t S1 = 0x00000000 + X01 - X08 - X12; + const int64_t S2 = 0x00000000 + X02 - X09 - X13; + const int64_t S3 = 0xFFFFFFFF + X03 + X07 + X11 - X10; + const int64_t S4 = 0xFFFFFFFF + X04 + X08 + X12 - X11; + const int64_t S5 = 0xFFFFFFFF + X05 + X09 + X13 - X12; + const int64_t S6 = 0xFFFFFFFF + X06 + X10 - X13; + + x.mask_bits(224); + x.shrink_to_fit(p224_limbs + 1); + + int64_t S = 0; + uint32_t R0 = 0, R1 = 0; + + S += S0; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S1; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 0, R0, R1); + + S += S2; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S3; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 2, R0, R1); + + S += S4; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S5; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 4, R0, R1); + + S += S6; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 6, R0, 0); + + BOTAN_ASSERT(S >= 0 && S <= 2, "Expected overflow in P-224 reduce"); + + static const word p224_mults[3][p224_limbs] = { +#if (BOTAN_MP_WORD_BITS == 64) + {0x0000000000000001, 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF}, + {0x0000000000000002, 0xFFFFFFFE00000000, 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF}, + {0x0000000000000003, 0xFFFFFFFD00000000, 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF}, +#else + {0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0x00000002, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0x00000003, 0x00000000, 0x00000000, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#endif + + }; + + if(S == 0 && x.word_at(p224_limbs-1) < p224_mults[0][p224_limbs-1]) + { + return; + } + + word borrow = bigint_sub2(x.mutable_data(), x.size(), p224_mults[S], p224_limbs); + + BOTAN_ASSERT(borrow == 0 || borrow == 1, "Expected borrow during P-224 reduction"); + + if(borrow) + { + bigint_add2(x.mutable_data(), x.size() - 1, p224_mults[0], p224_limbs); + } + } + +const BigInt& prime_p256() + { + static const BigInt p256("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"); + return p256; + } + +void redc_p256(BigInt& x, secure_vector<word>& ws) + { + static const size_t p256_limbs = (BOTAN_MP_WORD_BITS == 32) ? 8 : 4; + + BOTAN_UNUSED(ws); + + const int64_t X00 = get_uint32_t(x, 0); + const int64_t X01 = get_uint32_t(x, 1); + const int64_t X02 = get_uint32_t(x, 2); + const int64_t X03 = get_uint32_t(x, 3); + const int64_t X04 = get_uint32_t(x, 4); + const int64_t X05 = get_uint32_t(x, 5); + const int64_t X06 = get_uint32_t(x, 6); + const int64_t X07 = get_uint32_t(x, 7); + const int64_t X08 = get_uint32_t(x, 8); + const int64_t X09 = get_uint32_t(x, 9); + const int64_t X10 = get_uint32_t(x, 10); + const int64_t X11 = get_uint32_t(x, 11); + const int64_t X12 = get_uint32_t(x, 12); + const int64_t X13 = get_uint32_t(x, 13); + const int64_t X14 = get_uint32_t(x, 14); + const int64_t X15 = get_uint32_t(x, 15); + + // Adds 6 * P-256 to prevent underflow + const int64_t S0 = 0xFFFFFFFA + X00 + X08 + X09 - X11 - X12 - X13 - X14; + const int64_t S1 = 0xFFFFFFFF + X01 + X09 + X10 - X12 - X13 - X14 - X15; + const int64_t S2 = 0xFFFFFFFF + X02 + X10 + X11 - X13 - X14 - X15; + const int64_t S3 = 0x00000005 + X03 + (X11 + X12)*2 + X13 - X15 - X08 - X09; + const int64_t S4 = 0x00000000 + X04 + (X12 + X13)*2 + X14 - X09 - X10; + const int64_t S5 = 0x00000000 + X05 + (X13 + X14)*2 + X15 - X10 - X11; + const int64_t S6 = 0x00000006 + X06 + X13 + X14*3 + X15*2 - X08 - X09; + const int64_t S7 = 0xFFFFFFFA + X07 + X15*3 + X08 - X10 - X11 - X12 - X13; + + x.mask_bits(256); + x.shrink_to_fit(p256_limbs + 1); + + int64_t S = 0; + + uint32_t R0 = 0, R1 = 0; + + S += S0; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S1; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 0, R0, R1); + + S += S2; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S3; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 2, R0, R1); + + S += S4; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S5; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 4, R0, R1); + + S += S6; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S7; + R1 = static_cast<uint32_t>(S); + S >>= 32; + set_words(x, 6, R0, R1); + + S += 5; // the top digits of 6*P-256 + + BOTAN_ASSERT(S >= 0 && S <= 10, "Expected overflow"); + + /* + This is a table of (i*P-256) % 2**256 for i in 1...10 + */ + static const word p256_mults[11][p256_limbs] = { +#if (BOTAN_MP_WORD_BITS == 64) + {0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFF, 0x0000000000000000, 0xFFFFFFFF00000001}, + {0xFFFFFFFFFFFFFFFE, 0x00000001FFFFFFFF, 0x0000000000000000, 0xFFFFFFFE00000002}, + {0xFFFFFFFFFFFFFFFD, 0x00000002FFFFFFFF, 0x0000000000000000, 0xFFFFFFFD00000003}, + {0xFFFFFFFFFFFFFFFC, 0x00000003FFFFFFFF, 0x0000000000000000, 0xFFFFFFFC00000004}, + {0xFFFFFFFFFFFFFFFB, 0x00000004FFFFFFFF, 0x0000000000000000, 0xFFFFFFFB00000005}, + {0xFFFFFFFFFFFFFFFA, 0x00000005FFFFFFFF, 0x0000000000000000, 0xFFFFFFFA00000006}, + {0xFFFFFFFFFFFFFFF9, 0x00000006FFFFFFFF, 0x0000000000000000, 0xFFFFFFF900000007}, + {0xFFFFFFFFFFFFFFF8, 0x00000007FFFFFFFF, 0x0000000000000000, 0xFFFFFFF800000008}, + {0xFFFFFFFFFFFFFFF7, 0x00000008FFFFFFFF, 0x0000000000000000, 0xFFFFFFF700000009}, + {0xFFFFFFFFFFFFFFF6, 0x00000009FFFFFFFF, 0x0000000000000000, 0xFFFFFFF60000000A}, + {0xFFFFFFFFFFFFFFF5, 0x0000000AFFFFFFFF, 0x0000000000000000, 0xFFFFFFF50000000B}, +#else + {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF}, + {0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000000, 0x00000000, 0x00000002, 0xFFFFFFFE}, + {0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000002, 0x00000000, 0x00000000, 0x00000003, 0xFFFFFFFD}, + {0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000003, 0x00000000, 0x00000000, 0x00000004, 0xFFFFFFFC}, + {0xFFFFFFFB, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000004, 0x00000000, 0x00000000, 0x00000005, 0xFFFFFFFB}, + {0xFFFFFFFA, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000005, 0x00000000, 0x00000000, 0x00000006, 0xFFFFFFFA}, + {0xFFFFFFF9, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000006, 0x00000000, 0x00000000, 0x00000007, 0xFFFFFFF9}, + {0xFFFFFFF8, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000, 0x00000000, 0x00000008, 0xFFFFFFF8}, + {0xFFFFFFF7, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000008, 0x00000000, 0x00000000, 0x00000009, 0xFFFFFFF7}, + {0xFFFFFFF6, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000009, 0x00000000, 0x00000000, 0x0000000A, 0xFFFFFFF6}, + {0xFFFFFFF5, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000000A, 0x00000000, 0x00000000, 0x0000000B, 0xFFFFFFF5}, +#endif + }; + + if(S == 0 && x.word_at(p256_limbs-1) < p256_mults[0][p256_limbs-1]) + { + return; + } + + word borrow = bigint_sub2(x.mutable_data(), x.size(), p256_mults[S], p256_limbs); + + BOTAN_ASSERT(borrow == 0 || borrow == 1, "Expected borrow during P-256 reduction"); + + if(borrow) + { + bigint_add2(x.mutable_data(), x.size() - 1, p256_mults[0], p256_limbs); + } + } + +const BigInt& prime_p384() + { + static const BigInt p384("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"); + return p384; + } + +void redc_p384(BigInt& x, secure_vector<word>& ws) + { + BOTAN_UNUSED(ws); + + static const size_t p384_limbs = (BOTAN_MP_WORD_BITS == 32) ? 12 : 6; + + const int64_t X00 = get_uint32_t(x, 0); + const int64_t X01 = get_uint32_t(x, 1); + const int64_t X02 = get_uint32_t(x, 2); + const int64_t X03 = get_uint32_t(x, 3); + const int64_t X04 = get_uint32_t(x, 4); + const int64_t X05 = get_uint32_t(x, 5); + const int64_t X06 = get_uint32_t(x, 6); + const int64_t X07 = get_uint32_t(x, 7); + const int64_t X08 = get_uint32_t(x, 8); + const int64_t X09 = get_uint32_t(x, 9); + const int64_t X10 = get_uint32_t(x, 10); + const int64_t X11 = get_uint32_t(x, 11); + const int64_t X12 = get_uint32_t(x, 12); + const int64_t X13 = get_uint32_t(x, 13); + const int64_t X14 = get_uint32_t(x, 14); + const int64_t X15 = get_uint32_t(x, 15); + const int64_t X16 = get_uint32_t(x, 16); + const int64_t X17 = get_uint32_t(x, 17); + const int64_t X18 = get_uint32_t(x, 18); + const int64_t X19 = get_uint32_t(x, 19); + const int64_t X20 = get_uint32_t(x, 20); + const int64_t X21 = get_uint32_t(x, 21); + const int64_t X22 = get_uint32_t(x, 22); + const int64_t X23 = get_uint32_t(x, 23); + + // One copy of P-384 is added to prevent underflow + const int64_t S0 = 0xFFFFFFFF + X00 + X12 + X20 + X21 - X23; + const int64_t S1 = 0x00000000 + X01 + X13 + X22 + X23 - X12 - X20; + const int64_t S2 = 0x00000000 + X02 + X14 + X23 - X13 - X21; + const int64_t S3 = 0xFFFFFFFF + X03 + X12 + X15 + X20 + X21 - X14 - X22 - X23; + const int64_t S4 = 0xFFFFFFFE + X04 + X12 + X13 + X16 + X20 + X21*2 + X22 - X15 - X23*2; + const int64_t S5 = 0xFFFFFFFF + X05 + X13 + X14 + X17 + X21 + X22*2 + X23 - X16; + const int64_t S6 = 0xFFFFFFFF + X06 + X14 + X15 + X18 + X22 + X23*2 - X17; + const int64_t S7 = 0xFFFFFFFF + X07 + X15 + X16 + X19 + X23 - X18; + const int64_t S8 = 0xFFFFFFFF + X08 + X16 + X17 + X20 - X19; + const int64_t S9 = 0xFFFFFFFF + X09 + X17 + X18 + X21 - X20; + const int64_t SA = 0xFFFFFFFF + X10 + X18 + X19 + X22 - X21; + const int64_t SB = 0xFFFFFFFF + X11 + X19 + X20 + X23 - X22; + + x.mask_bits(384); + x.shrink_to_fit(p384_limbs + 1); + + int64_t S = 0; + + uint32_t R0 = 0, R1 = 0; + + S += S0; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S1; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 0, R0, R1); + + S += S2; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S3; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 2, R0, R1); + + S += S4; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S5; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 4, R0, R1); + + S += S6; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S7; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 6, R0, R1); + + S += S8; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += S9; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 8, R0, R1); + + S += SA; + R0 = static_cast<uint32_t>(S); + S >>= 32; + + S += SB; + R1 = static_cast<uint32_t>(S); + S >>= 32; + + set_words(x, 10, R0, R1); + + BOTAN_ASSERT(S >= 0 && S <= 4, "Expected overflow in P-384 reduction"); + + /* + This is a table of (i*P-384) % 2**384 for i in 1...4 + */ + static const word p384_mults[5][p384_limbs] = { +#if (BOTAN_MP_WORD_BITS == 64) + {0x00000000FFFFFFFF, 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x00000001FFFFFFFE, 0xFFFFFFFE00000000, 0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x00000002FFFFFFFD, 0xFFFFFFFD00000000, 0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x00000003FFFFFFFC, 0xFFFFFFFC00000000, 0xFFFFFFFFFFFFFFFB, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + {0x00000004FFFFFFFB, 0xFFFFFFFB00000000, 0xFFFFFFFFFFFFFFFA, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}, + +#else + {0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFE, 0x00000001, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFD, 0x00000002, 0x00000000, 0xFFFFFFFD, 0xFFFFFFFC, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFC, 0x00000003, 0x00000000, 0xFFFFFFFC, 0xFFFFFFFB, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFB, 0x00000004, 0x00000000, 0xFFFFFFFB, 0xFFFFFFFA, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, +#endif + }; + + if(S == 0 && x.word_at(p384_limbs-1) < p384_mults[0][p384_limbs-1]) + { + return; + } + + word borrow = bigint_sub2(x.mutable_data(), x.size(), p384_mults[S], p384_limbs); + + BOTAN_ASSERT(borrow == 0 || borrow == 1, "Expected borrow during P-384 reduction"); + + if(borrow) + { + bigint_add2(x.mutable_data(), x.size() - 1, p384_mults[0], p384_limbs); + } + } + +#endif + + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/numthry.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/numthry.cpp new file mode 100644 index 0000000000..a312ba3a1c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/numthry.cpp @@ -0,0 +1,566 @@ +/* +* Number Theory Functions +* (C) 1999-2011,2016,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/numthry.h> +#include <botan/pow_mod.h> +#include <botan/reducer.h> +#include <botan/monty.h> +#include <botan/rng.h> +#include <botan/internal/bit_ops.h> +#include <botan/internal/mp_core.h> +#include <botan/internal/ct_utils.h> +#include <botan/internal/monty_exp.h> +#include <algorithm> + +namespace Botan { + +/* +* Return the number of 0 bits at the end of n +*/ +size_t low_zero_bits(const BigInt& n) + { + size_t low_zero = 0; + + if(n.is_positive() && n.is_nonzero()) + { + for(size_t i = 0; i != n.size(); ++i) + { + const word x = n.word_at(i); + + if(x) + { + low_zero += ctz(x); + break; + } + else + low_zero += BOTAN_MP_WORD_BITS; + } + } + + return low_zero; + } + +/* +* Calculate the GCD +*/ +BigInt gcd(const BigInt& a, const BigInt& b) + { + if(a.is_zero() || b.is_zero()) + return 0; + if(a == 1 || b == 1) + return 1; + + BigInt X[2] = { a, b }; + X[0].set_sign(BigInt::Positive); + X[1].set_sign(BigInt::Positive); + + const size_t shift = std::min(low_zero_bits(X[0]), low_zero_bits(X[1])); + + X[0] >>= shift; + X[1] >>= shift; + + while(X[0].is_nonzero()) + { + X[0] >>= low_zero_bits(X[0]); + X[1] >>= low_zero_bits(X[1]); + + const uint8_t sel = static_cast<uint8_t>(X[0] >= X[1]); + + X[sel^1] -= X[sel]; + X[sel^1] >>= 1; + } + + return (X[1] << shift); + } + +/* +* Calculate the LCM +*/ +BigInt lcm(const BigInt& a, const BigInt& b) + { + return ((a * b) / gcd(a, b)); + } + +/* +Sets result to a^-1 * 2^k mod a +with n <= k <= 2n +Returns k + +"The Montgomery Modular Inverse - Revisited" Çetin Koç, E. Savas +https://citeseerx.ist.psu.edu/viewdoc/citations?doi=10.1.1.75.8377 + +A const time implementation of this algorithm is described in +"Constant Time Modular Inversion" Joppe W. Bos +http://www.joppebos.com/files/CTInversion.pdf +*/ +size_t almost_montgomery_inverse(BigInt& result, + const BigInt& a, + const BigInt& p) + { + size_t k = 0; + + BigInt u = p, v = a, r = 0, s = 1; + + while(v > 0) + { + if(u.is_even()) + { + u >>= 1; + s <<= 1; + } + else if(v.is_even()) + { + v >>= 1; + r <<= 1; + } + else if(u > v) + { + u -= v; + u >>= 1; + r += s; + s <<= 1; + } + else + { + v -= u; + v >>= 1; + s += r; + r <<= 1; + } + + ++k; + } + + if(r >= p) + { + r -= p; + } + + result = p - r; + + return k; + } + +BigInt normalized_montgomery_inverse(const BigInt& a, const BigInt& p) + { + BigInt r; + size_t k = almost_montgomery_inverse(r, a, p); + + for(size_t i = 0; i != k; ++i) + { + if(r.is_odd()) + r += p; + r >>= 1; + } + + return r; + } + +BigInt ct_inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod) + { + if(n.is_negative() || mod.is_negative()) + throw Invalid_Argument("ct_inverse_mod_odd_modulus: arguments must be non-negative"); + if(mod < 3 || mod.is_even()) + throw Invalid_Argument("Bad modulus to ct_inverse_mod_odd_modulus"); + if(n >= mod) + throw Invalid_Argument("ct_inverse_mod_odd_modulus n >= mod not supported"); + + /* + This uses a modular inversion algorithm designed by Niels Möller + and implemented in Nettle. The same algorithm was later also + adapted to GMP in mpn_sec_invert. + + It can be easily implemented in a way that does not depend on + secret branches or memory lookups, providing resistance against + some forms of side channel attack. + + There is also a description of the algorithm in Appendix 5 of "Fast + Software Polynomial Multiplication on ARM Processors using the NEON Engine" + by Danilo Câmara, Conrado P. L. Gouvêa, Julio López, and Ricardo + Dahab in LNCS 8182 + https://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf + + Thanks to Niels for creating the algorithm, explaining some things + about it, and the reference to the paper. + */ + + // todo allow this to be pre-calculated and passed in as arg + BigInt mp1o2 = (mod + 1) >> 1; + + const size_t mod_words = mod.sig_words(); + BOTAN_ASSERT(mod_words > 0, "Not empty"); + + BigInt a = n; + BigInt b = mod; + BigInt u = 1, v = 0; + + a.grow_to(mod_words); + u.grow_to(mod_words); + v.grow_to(mod_words); + mp1o2.grow_to(mod_words); + + secure_vector<word>& a_w = a.get_word_vector(); + secure_vector<word>& b_w = b.get_word_vector(); + secure_vector<word>& u_w = u.get_word_vector(); + secure_vector<word>& v_w = v.get_word_vector(); + + CT::poison(a_w.data(), a_w.size()); + CT::poison(b_w.data(), b_w.size()); + CT::poison(u_w.data(), u_w.size()); + CT::poison(v_w.data(), v_w.size()); + + // Only n.bits() + mod.bits() iterations are required, but avoid leaking the size of n + size_t bits = 2 * mod.bits(); + + while(bits--) + { + /* + const word odd = a.is_odd(); + a -= odd * b; + const word underflow = a.is_negative(); + b += a * underflow; + a.set_sign(BigInt::Positive); + + a >>= 1; + + if(underflow) + { + std::swap(u, v); + } + + u -= odd * v; + u += u.is_negative() * mod; + + const word odd_u = u.is_odd(); + + u >>= 1; + u += mp1o2 * odd_u; + */ + + const word odd_a = a_w[0] & 1; + + //if(odd_a) a -= b + word underflow = bigint_cnd_sub(odd_a, a_w.data(), b_w.data(), mod_words); + + //if(underflow) { b -= a; a = abs(a); swap(u, v); } + bigint_cnd_add(underflow, b_w.data(), a_w.data(), mod_words); + bigint_cnd_abs(underflow, a_w.data(), mod_words); + bigint_cnd_swap(underflow, u_w.data(), v_w.data(), mod_words); + + // a >>= 1 + bigint_shr1(a_w.data(), mod_words, 0, 1); + + //if(odd_a) u -= v; + word borrow = bigint_cnd_sub(odd_a, u_w.data(), v_w.data(), mod_words); + + // if(borrow) u += p + bigint_cnd_add(borrow, u_w.data(), mod.data(), mod_words); + + const word odd_u = u_w[0] & 1; + + // u >>= 1 + bigint_shr1(u_w.data(), mod_words, 0, 1); + + //if(odd_u) u += mp1o2; + bigint_cnd_add(odd_u, u_w.data(), mp1o2.data(), mod_words); + } + + CT::unpoison(a_w.data(), a_w.size()); + CT::unpoison(b_w.data(), b_w.size()); + CT::unpoison(u_w.data(), u_w.size()); + CT::unpoison(v_w.data(), v_w.size()); + + BOTAN_ASSERT(a.is_zero(), "A is zero"); + + if(b != 1) + return 0; + + return v; + } + +/* +* Find the Modular Inverse +*/ +BigInt inverse_mod(const BigInt& n, const BigInt& mod) + { + if(mod.is_zero()) + throw BigInt::DivideByZero(); + if(mod.is_negative() || n.is_negative()) + throw Invalid_Argument("inverse_mod: arguments must be non-negative"); + + if(n.is_zero() || (n.is_even() && mod.is_even())) + return 0; // fast fail checks + + if(mod.is_odd() && n < mod) + return ct_inverse_mod_odd_modulus(n, mod); + + return inverse_euclid(n, mod); + } + +BigInt inverse_euclid(const BigInt& n, const BigInt& mod) + { + if(mod.is_zero()) + throw BigInt::DivideByZero(); + if(mod.is_negative() || n.is_negative()) + throw Invalid_Argument("inverse_mod: arguments must be non-negative"); + + if(n.is_zero() || (n.is_even() && mod.is_even())) + return 0; // fast fail checks + + BigInt u = mod, v = n; + BigInt A = 1, B = 0, C = 0, D = 1; + + while(u.is_nonzero()) + { + const size_t u_zero_bits = low_zero_bits(u); + u >>= u_zero_bits; + for(size_t i = 0; i != u_zero_bits; ++i) + { + if(A.is_odd() || B.is_odd()) + { A += n; B -= mod; } + A >>= 1; B >>= 1; + } + + const size_t v_zero_bits = low_zero_bits(v); + v >>= v_zero_bits; + for(size_t i = 0; i != v_zero_bits; ++i) + { + if(C.is_odd() || D.is_odd()) + { C += n; D -= mod; } + C >>= 1; D >>= 1; + } + + if(u >= v) { u -= v; A -= C; B -= D; } + else { v -= u; C -= A; D -= B; } + } + + if(v != 1) + return 0; // no modular inverse + + while(D.is_negative()) D += mod; + while(D >= mod) D -= mod; + + return D; + } + +word monty_inverse(word input) + { + if(input == 0) + throw Exception("monty_inverse: divide by zero"); + + word b = input; + word x2 = 1, x1 = 0, y2 = 0, y1 = 1; + + // First iteration, a = n+1 + word q = bigint_divop(1, 0, b); + word r = (MP_WORD_MAX - q*b) + 1; + word x = x2 - q*x1; + word y = y2 - q*y1; + + word a = b; + b = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + + while(b > 0) + { + q = a / b; + r = a - q*b; + x = x2 - q*x1; + y = y2 - q*y1; + + a = b; + b = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + + const word check = y2 * input; + BOTAN_ASSERT_EQUAL(check, 1, "monty_inverse result is inverse of input"); + + // Now invert in addition space + y2 = (MP_WORD_MAX - y2) + 1; + + return y2; + } + +/* +* Modular Exponentiation +*/ +BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod) + { + if(mod.is_negative() || mod == 1) + { + return 0; + } + + if(base.is_zero() || mod.is_zero()) + { + if(exp.is_zero()) + return 1; + return 0; + } + + Power_Mod pow_mod(mod); + + /* + * Calling set_base before set_exponent means we end up using a + * minimal window. This makes sense given that here we know that any + * precomputation is wasted. + */ + + if(base.is_negative()) + { + pow_mod.set_base(-base); + pow_mod.set_exponent(exp); + if(exp.is_even()) + return pow_mod.execute(); + else + return (mod - pow_mod.execute()); + } + else + { + pow_mod.set_base(base); + pow_mod.set_exponent(exp); + return pow_mod.execute(); + } + } + +namespace { + +bool mr_witness(BigInt&& y, + const Modular_Reducer& reducer_n, + const BigInt& n_minus_1, size_t s) + { + if(y == 1 || y == n_minus_1) + return false; + + for(size_t i = 1; i != s; ++i) + { + y = reducer_n.square(y); + + if(y == 1) // found a non-trivial square root + return true; + + /* + -1 is the trivial square root of unity, so ``a`` is not a + witness for this number - give up + */ + if(y == n_minus_1) + return false; + } + + return true; // is a witness + } + +size_t mr_test_iterations(size_t n_bits, size_t prob, bool random) + { + const size_t base = (prob + 2) / 2; // worst case 4^-t error rate + + /* + * If the candidate prime was maliciously constructed, we can't rely + * on arguments based on p being random. + */ + if(random == false) + return base; + + /* + * For randomly chosen numbers we can use the estimates from + * http://www.math.dartmouth.edu/~carlp/PDF/paper88.pdf + * + * These values are derived from the inequality for p(k,t) given on + * the second page. + */ + if(prob <= 128) + { + if(n_bits >= 1536) + return 4; // < 2^-133 + if(n_bits >= 1024) + return 6; // < 2^-133 + if(n_bits >= 512) + return 12; // < 2^-129 + if(n_bits >= 256) + return 29; // < 2^-128 + } + + /* + If the user desires a smaller error probability than we have + precomputed error estimates for, just fall back to using the worst + case error rate. + */ + return base; + } + +} + +/* +* Test for primality using Miller-Rabin +*/ +bool is_prime(const BigInt& n, RandomNumberGenerator& rng, + size_t prob, bool is_random) + { + if(n == 2) + return true; + if(n <= 1 || n.is_even()) + return false; + + // Fast path testing for small numbers (<= 65521) + if(n <= PRIMES[PRIME_TABLE_SIZE-1]) + { + const uint16_t num = static_cast<uint16_t>(n.word_at(0)); + + return std::binary_search(PRIMES, PRIMES + PRIME_TABLE_SIZE, num); + } + + const size_t test_iterations = + mr_test_iterations(n.bits(), prob, is_random && rng.is_seeded()); + + const BigInt n_minus_1 = n - 1; + const size_t s = low_zero_bits(n_minus_1); + const BigInt nm1_s = n_minus_1 >> s; + const size_t n_bits = n.bits(); + + const Modular_Reducer mod_n(n); + auto monty_n = std::make_shared<Montgomery_Params>(n, mod_n); + + const size_t powm_window = 4; + + for(size_t i = 0; i != test_iterations; ++i) + { + BigInt a; + + if(rng.is_seeded()) + { + a = BigInt::random_integer(rng, 2, n_minus_1); + } + else + { + /* + * If passed a null RNG just use 2,3,5, ... as bases + * + * This is not ideal but in certain circumstances we need to + * test for primality but have no RNG available. + */ + a = PRIMES[i]; + } + + auto powm_a_n = monty_precompute(monty_n, a, powm_window); + + BigInt y = monty_execute(*powm_a_n, nm1_s, n_bits); + + if(mr_witness(std::move(y), mod_n, n_minus_1, s)) + return false; + } + + return true; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/numthry.h b/src/libs/3rdparty/botan/src/lib/math/numbertheory/numthry.h new file mode 100644 index 0000000000..7097979bd7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/numthry.h @@ -0,0 +1,278 @@ +/* +* Number Theory Functions +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_NUMBER_THEORY_H_ +#define BOTAN_NUMBER_THEORY_H_ + +#include <botan/bigint.h> + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Fused multiply-add +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a*b)+c +*/ +BigInt BOTAN_PUBLIC_API(2,0) mul_add(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** +* Fused subtract-multiply +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a-b)*c +*/ +BigInt BOTAN_PUBLIC_API(2,0) sub_mul(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** +* Fused multiply-subtract +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a*b)-c +*/ +BigInt BOTAN_PUBLIC_API(2,0) mul_sub(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** +* Return the absolute value +* @param n an integer +* @return absolute value of n +*/ +inline BigInt abs(const BigInt& n) { return n.abs(); } + +/** +* Compute the greatest common divisor +* @param x a positive integer +* @param y a positive integer +* @return gcd(x,y) +*/ +BigInt BOTAN_PUBLIC_API(2,0) gcd(const BigInt& x, const BigInt& y); + +/** +* Least common multiple +* @param x a positive integer +* @param y a positive integer +* @return z, smallest integer such that z % x == 0 and z % y == 0 +*/ +BigInt BOTAN_PUBLIC_API(2,0) lcm(const BigInt& x, const BigInt& y); + +/** +* @param x an integer +* @return (x*x) +*/ +BigInt BOTAN_PUBLIC_API(2,0) square(const BigInt& x); + +/** +* Modular inversion +* @param x a positive integer +* @param modulus a positive integer +* @return y st (x*y) % modulus == 1 or 0 if no such value +* Not const time +*/ +BigInt BOTAN_PUBLIC_API(2,0) inverse_mod(const BigInt& x, + const BigInt& modulus); + +/** +* Modular inversion using extended binary Euclidian algorithm +* @param x a positive integer +* @param modulus a positive integer +* @return y st (x*y) % modulus == 1 or 0 if no such value +* Not const time +*/ +BigInt BOTAN_PUBLIC_API(2,5) inverse_euclid(const BigInt& x, + const BigInt& modulus); + +/** +* Const time modular inversion +* Requires the modulus be odd +*/ +BigInt BOTAN_PUBLIC_API(2,0) ct_inverse_mod_odd_modulus(const BigInt& n, const BigInt& mod); + +/** +* Return a^-1 * 2^k mod b +* Returns k, between n and 2n +* Not const time +*/ +size_t BOTAN_PUBLIC_API(2,0) almost_montgomery_inverse(BigInt& result, + const BigInt& a, + const BigInt& b); + +/** +* Call almost_montgomery_inverse and correct the result to a^-1 mod b +*/ +BigInt BOTAN_PUBLIC_API(2,0) normalized_montgomery_inverse(const BigInt& a, const BigInt& b); + + +/** +* Compute the Jacobi symbol. If n is prime, this is equivalent +* to the Legendre symbol. +* @see http://mathworld.wolfram.com/JacobiSymbol.html +* +* @param a is a non-negative integer +* @param n is an odd integer > 1 +* @return (n / m) +*/ +int32_t BOTAN_PUBLIC_API(2,0) jacobi(const BigInt& a, + const BigInt& n); + +/** +* Modular exponentation +* @param b an integer base +* @param x a positive exponent +* @param m a positive modulus +* @return (b^x) % m +*/ +BigInt BOTAN_PUBLIC_API(2,0) power_mod(const BigInt& b, + const BigInt& x, + const BigInt& m); + +/** +* Compute the square root of x modulo a prime using the +* Shanks-Tonnelli algorithm +* +* @param x the input +* @param p the prime +* @return y such that (y*y)%p == x, or -1 if no such integer +*/ +BigInt BOTAN_PUBLIC_API(2,0) ressol(const BigInt& x, const BigInt& p); + +/* +* Compute -input^-1 mod 2^MP_WORD_BITS. Returns zero if input +* is even. If input is odd, input and 2^n are relatively prime +* and an inverse exists. +*/ +word BOTAN_PUBLIC_API(2,0) monty_inverse(word input); + +/** +* @param x a positive integer +* @return count of the zero bits in x, or, equivalently, the largest +* value of n such that 2^n divides x evenly. Returns zero if +* n is less than or equal to zero. +*/ +size_t BOTAN_PUBLIC_API(2,0) low_zero_bits(const BigInt& x); + +/** +* Check for primality +* @param n a positive integer to test for primality +* @param rng a random number generator +* @param prob chance of false positive is bounded by 1/2**prob +* @param is_random true if n was randomly chosen by us +* @return true if all primality tests passed, otherwise false +*/ +bool BOTAN_PUBLIC_API(2,0) is_prime(const BigInt& n, + RandomNumberGenerator& rng, + size_t prob = 56, + bool is_random = false); + +inline bool quick_check_prime(const BigInt& n, RandomNumberGenerator& rng) + { return is_prime(n, rng, 32); } + +inline bool check_prime(const BigInt& n, RandomNumberGenerator& rng) + { return is_prime(n, rng, 56); } + +inline bool verify_prime(const BigInt& n, RandomNumberGenerator& rng) + { return is_prime(n, rng, 80); } + + +/** +* Randomly generate a prime suitable for discrete logarithm parameters +* @param rng a random number generator +* @param bits how large the resulting prime should be in bits +* @param coprime a positive integer that (prime - 1) should be coprime to +* @param equiv a non-negative number that the result should be + equivalent to modulo equiv_mod +* @param equiv_mod the modulus equiv should be checked against +* @param prob use test so false positive is bounded by 1/2**prob +* @return random prime with the specified criteria +*/ +BigInt BOTAN_PUBLIC_API(2,0) random_prime(RandomNumberGenerator& rng, + size_t bits, + const BigInt& coprime = 0, + size_t equiv = 1, + size_t equiv_mod = 2, + size_t prob = 128); + +/** +* Generate a prime suitable for RSA p/q +* @param keygen_rng a random number generator +* @param prime_test_rng a random number generator +* @param bits how large the resulting prime should be in bits (must be >= 512) +* @param coprime a positive integer that (prime - 1) should be coprime to +* @param prob use test so false positive is bounded by 1/2**prob +* @return random prime with the specified criteria +*/ +BigInt BOTAN_PUBLIC_API(2,7) generate_rsa_prime(RandomNumberGenerator& keygen_rng, + RandomNumberGenerator& prime_test_rng, + size_t bits, + const BigInt& coprime, + size_t prob = 128); + +/** +* Return a 'safe' prime, of the form p=2*q+1 with q prime +* @param rng a random number generator +* @param bits is how long the resulting prime should be +* @return prime randomly chosen from safe primes of length bits +*/ +BigInt BOTAN_PUBLIC_API(2,0) random_safe_prime(RandomNumberGenerator& rng, + size_t bits); + +/** +* Generate DSA parameters using the FIPS 186 kosherizer +* @param rng a random number generator +* @param p_out where the prime p will be stored +* @param q_out where the prime q will be stored +* @param pbits how long p will be in bits +* @param qbits how long q will be in bits +* @return random seed used to generate this parameter set +*/ +std::vector<uint8_t> BOTAN_PUBLIC_API(2,0) +generate_dsa_primes(RandomNumberGenerator& rng, + BigInt& p_out, BigInt& q_out, + size_t pbits, size_t qbits); + +/** +* Generate DSA parameters using the FIPS 186 kosherizer +* @param rng a random number generator +* @param p_out where the prime p will be stored +* @param q_out where the prime q will be stored +* @param pbits how long p will be in bits +* @param qbits how long q will be in bits +* @param seed the seed used to generate the parameters +* @param offset optional offset from seed to start searching at +* @return true if seed generated a valid DSA parameter set, otherwise + false. p_out and q_out are only valid if true was returned. +*/ +bool BOTAN_PUBLIC_API(2,0) +generate_dsa_primes(RandomNumberGenerator& rng, + BigInt& p_out, BigInt& q_out, + size_t pbits, size_t qbits, + const std::vector<uint8_t>& seed, + size_t offset = 0); + +/** +* The size of the PRIMES[] array +*/ +const size_t PRIME_TABLE_SIZE = 6541; + +/** +* A const array of all primes less than 65535 +*/ +extern const uint16_t BOTAN_PUBLIC_API(2,0) PRIMES[]; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/pow_mod.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/pow_mod.cpp new file mode 100644 index 0000000000..00917a5f91 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/pow_mod.cpp @@ -0,0 +1,196 @@ +/* +* Modular Exponentiation Proxy +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pow_mod.h> +#include <botan/internal/def_powm.h> + +namespace Botan { + +/* +* Power_Mod Constructor +*/ +Power_Mod::Power_Mod(const BigInt& n, Usage_Hints hints, bool disable_monty) + { + set_modulus(n, hints, disable_monty); + } + +/* +* Power_Mod Copy Constructor +*/ +Power_Mod::Power_Mod(const Power_Mod& other) + { + if(other.m_core.get()) + m_core.reset(other.m_core->copy()); + } + +/* +* Power_Mod Assignment Operator +*/ +Power_Mod& Power_Mod::operator=(const Power_Mod& other) + { + if(this != &other) + { + if(other.m_core) + m_core.reset(other.m_core->copy()); + else + m_core.reset(); + } + return (*this); + } + +/* +* Set the modulus +*/ +void Power_Mod::set_modulus(const BigInt& n, Usage_Hints hints, bool disable_monty) const + { + // Allow set_modulus(0) to mean "drop old state" + + m_core.reset(); + + if(n != 0) + { + if(n.is_odd() && disable_monty == false) + m_core.reset(new Montgomery_Exponentiator(n, hints)); + else + m_core.reset(new Fixed_Window_Exponentiator(n, hints)); + } + } + +/* +* Set the base +*/ +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(!m_core) + throw Internal_Error("Power_Mod::set_base: m_core was NULL"); + m_core->set_base(b); + } + +/* +* Set the exponent +*/ +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(!m_core) + throw Internal_Error("Power_Mod::set_exponent: m_core was NULL"); + m_core->set_exponent(e); + } + +/* +* Compute the result +*/ +BigInt Power_Mod::execute() const + { + if(!m_core) + throw Internal_Error("Power_Mod::execute: m_core was NULL"); + return m_core->execute(); + } + +/* +* Try to choose a good window size +*/ +size_t Power_Mod::window_bits(size_t exp_bits, size_t, + Power_Mod::Usage_Hints hints) + { + static const size_t wsize[][2] = { + { 1434, 7 }, + { 539, 6 }, + { 197, 4 }, + { 70, 3 }, + { 17, 2 }, + { 0, 0 } + }; + + size_t window_bits = 1; + + if(exp_bits) + { + for(size_t j = 0; wsize[j][0]; ++j) + { + if(exp_bits >= wsize[j][0]) + { + window_bits += wsize[j][1]; + break; + } + } + } + + if(hints & Power_Mod::BASE_IS_FIXED) + window_bits += 2; + if(hints & Power_Mod::EXP_IS_LARGE) + ++window_bits; + + return window_bits; + } + +namespace { + +/* +* Choose potentially useful hints +*/ +Power_Mod::Usage_Hints choose_base_hints(const BigInt& b, const BigInt& n) + { + if(b == 2) + return Power_Mod::Usage_Hints(Power_Mod::BASE_IS_2 | + Power_Mod::BASE_IS_SMALL); + + const size_t b_bits = b.bits(); + const size_t n_bits = n.bits(); + + if(b_bits < n_bits / 32) + return Power_Mod::BASE_IS_SMALL; + if(b_bits > n_bits / 4) + return Power_Mod::BASE_IS_LARGE; + + return Power_Mod::NO_HINTS; + } + +/* +* Choose potentially useful hints +*/ +Power_Mod::Usage_Hints choose_exp_hints(const BigInt& e, const BigInt& n) + { + const size_t e_bits = e.bits(); + const size_t n_bits = n.bits(); + + if(e_bits < n_bits / 32) + return Power_Mod::BASE_IS_SMALL; + if(e_bits > n_bits / 4) + return Power_Mod::BASE_IS_LARGE; + return Power_Mod::NO_HINTS; + } + +} + +/* +* Fixed_Exponent_Power_Mod Constructor +*/ +Fixed_Exponent_Power_Mod::Fixed_Exponent_Power_Mod(const BigInt& e, + const BigInt& n, + Usage_Hints hints) : + Power_Mod(n, Usage_Hints(hints | EXP_IS_FIXED | choose_exp_hints(e, n))) + { + set_exponent(e); + } + +/* +* Fixed_Base_Power_Mod Constructor +*/ +Fixed_Base_Power_Mod::Fixed_Base_Power_Mod(const BigInt& b, const BigInt& n, + Usage_Hints hints) : + Power_Mod(n, Usage_Hints(hints | BASE_IS_FIXED | choose_base_hints(b, n))) + { + set_base(b); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/pow_mod.h b/src/libs/3rdparty/botan/src/lib/math/numbertheory/pow_mod.h new file mode 100644 index 0000000000..077f4ccf72 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/pow_mod.h @@ -0,0 +1,135 @@ +/* +* Modular Exponentiator +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_POWER_MOD_H_ +#define BOTAN_POWER_MOD_H_ + +#include <botan/bigint.h> + +namespace Botan { + +/** +* Modular Exponentiator Interface +*/ +class BOTAN_PUBLIC_API(2,0) Modular_Exponentiator + { + public: + virtual void set_base(const BigInt&) = 0; + virtual void set_exponent(const BigInt&) = 0; + virtual BigInt execute() const = 0; + virtual Modular_Exponentiator* copy() const = 0; + + Modular_Exponentiator() = default; + Modular_Exponentiator(const Modular_Exponentiator&) = default; + Modular_Exponentiator & operator=(const Modular_Exponentiator&) = default; + virtual ~Modular_Exponentiator() = default; + }; + +/** +* Modular Exponentiator Proxy +*/ +class BOTAN_PUBLIC_API(2,0) Power_Mod + { + public: + + enum Usage_Hints { + NO_HINTS = 0x0000, + + BASE_IS_FIXED = 0x0001, + BASE_IS_SMALL = 0x0002, + BASE_IS_LARGE = 0x0004, + BASE_IS_2 = 0x0008, + + EXP_IS_FIXED = 0x0100, + EXP_IS_SMALL = 0x0200, + EXP_IS_LARGE = 0x0400 + }; + + /* + * Try to choose a good window size + */ + static size_t window_bits(size_t exp_bits, size_t base_bits, + Power_Mod::Usage_Hints hints); + + /** + * @param modulus the modulus + * @param hints Passed to set_modulus if modulus > 0 + * @param disable_montgomery_arith Disables use of Montgomery + * representation. Likely only useful for testing. + */ + void set_modulus(const BigInt& modulus, + Usage_Hints hints = NO_HINTS, + bool disable_montgomery_arith = false) const; + + /** + * Set the base + */ + void set_base(const BigInt& base) const; + + /** + * Set the exponent + */ + void set_exponent(const BigInt& exponent) const; + + /** + * All three of the above functions must have already been called. + * @return result of g^x%p + */ + BigInt execute() const; + + Power_Mod& operator=(const Power_Mod&); + + /** + * @param modulus Optionally call set_modulus + * @param hints Passed to set_modulus if modulus > 0 + * @param disable_montgomery_arith Disables use of Montgomery + * representation. Likely only useful for testing. + */ + Power_Mod(const BigInt& modulus = 0, + Usage_Hints hints = NO_HINTS, + bool disable_montgomery_arith = false); + Power_Mod(const Power_Mod&); + virtual ~Power_Mod() = default; + private: + mutable std::unique_ptr<Modular_Exponentiator> m_core; + }; + +/** +* Fixed Exponent Modular Exponentiator Proxy +*/ +class BOTAN_PUBLIC_API(2,0) Fixed_Exponent_Power_Mod final : public Power_Mod + { + public: + BigInt operator()(const BigInt& b) const + { set_base(b); return execute(); } + + Fixed_Exponent_Power_Mod() = default; + + Fixed_Exponent_Power_Mod(const BigInt& exponent, + const BigInt& modulus, + Usage_Hints hints = NO_HINTS); + }; + +/** +* Fixed Base Modular Exponentiator Proxy +*/ +class BOTAN_PUBLIC_API(2,0) Fixed_Base_Power_Mod final : public Power_Mod + { + public: + BigInt operator()(const BigInt& e) const + { set_exponent(e); return execute(); } + + Fixed_Base_Power_Mod() = default; + + Fixed_Base_Power_Mod(const BigInt& base, + const BigInt& modulus, + Usage_Hints hints = NO_HINTS); + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/powm_fw.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/powm_fw.cpp new file mode 100644 index 0000000000..85a0364b5a --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/powm_fw.cpp @@ -0,0 +1,65 @@ +/* +* Fixed Window Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/def_powm.h> +#include <vector> + +namespace Botan { + +/* +* Set the exponent +*/ +void Fixed_Window_Exponentiator::set_exponent(const BigInt& e) + { + m_exp = e; + } + +/* +* Set the base +*/ +void Fixed_Window_Exponentiator::set_base(const BigInt& base) + { + m_window_bits = Power_Mod::window_bits(m_exp.bits(), base.bits(), m_hints); + + m_g.resize(1U << m_window_bits); + m_g[0] = 1; + m_g[1] = base; + + for(size_t i = 2; i != m_g.size(); ++i) + m_g[i] = m_reducer.multiply(m_g[i-1], m_g[1]); + } + +/* +* Compute the result +*/ +BigInt Fixed_Window_Exponentiator::execute() const + { + const size_t exp_nibbles = (m_exp.bits() + m_window_bits - 1) / m_window_bits; + + BigInt x = 1; + + for(size_t i = exp_nibbles; i > 0; --i) + { + for(size_t j = 0; j != m_window_bits; ++j) + x = m_reducer.square(x); + + const uint32_t nibble = m_exp.get_substring(m_window_bits*(i-1), m_window_bits); + + x = m_reducer.multiply(x, m_g[nibble]); + } + return x; + } + +/* +* Fixed_Window_Exponentiator Constructor +*/ +Fixed_Window_Exponentiator::Fixed_Window_Exponentiator(const BigInt& n, + Power_Mod::Usage_Hints hints) + : m_reducer{Modular_Reducer(n)}, m_exp{}, m_window_bits{}, m_g{}, m_hints{hints} + {} + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/powm_mnt.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/powm_mnt.cpp new file mode 100644 index 0000000000..8cb3f6a08e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/powm_mnt.cpp @@ -0,0 +1,46 @@ +/* +* Montgomery Exponentiation +* (C) 1999-2010,2012,2018 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/def_powm.h> +#include <botan/numthry.h> +#include <botan/monty.h> +#include <botan/internal/monty_exp.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +void Montgomery_Exponentiator::set_exponent(const BigInt& exp) + { + m_e = exp; + } + +void Montgomery_Exponentiator::set_base(const BigInt& base) + { + size_t window_bits = Power_Mod::window_bits(m_e.bits(), base.bits(), m_hints); + m_monty = monty_precompute(m_monty_params, base, window_bits); + } + +BigInt Montgomery_Exponentiator::execute() const + { + /* + This leaks size of e via loop iterations, not possible to fix without + breaking this API. Round up to avoid leaking fine details. + */ + return monty_execute(*m_monty, m_e, round_up(m_e.bits(), 8)); + } + +Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod, + Power_Mod::Usage_Hints hints) : + m_p(mod), + m_mod_p(mod), + m_monty_params(std::make_shared<Montgomery_Params>(m_p, m_mod_p)), + m_hints(hints) + { + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/primes.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/primes.cpp new file mode 100644 index 0000000000..4a3eb46f2c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/primes.cpp @@ -0,0 +1,609 @@ +/* +* Small Primes Table +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/numthry.h> + +namespace Botan { + +const uint16_t PRIMES[PRIME_TABLE_SIZE+1] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, + 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, + 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, + 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, + 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, + 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, + 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, + 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, + 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, + 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, + 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, + 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, + 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, + 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, + 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, + 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, + 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, + 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, + 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, + 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, + 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, + 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, + 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, + 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, + 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, + 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, + 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, + 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, + 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, + 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, + 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, + 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, + 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, + 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, + 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, + 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, + 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, + 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, + 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, + 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, + 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, + 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, + 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, + 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, + 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, + 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, + 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, + 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, + 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, + 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, + 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, + 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, + 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, + 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, + 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, + 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, + 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, + 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, + 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, + 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, + 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, + 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, + 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, + 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, + 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, + 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, + 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, + 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, + 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, + 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, + 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, + 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, + 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, + 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, + 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, + 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, + 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, + 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, + 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, + 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, + 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, + 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, + 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, + 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, + 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, + 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, + 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, + 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, + 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, + 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, + 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, + 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, + 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, + 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, + 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, + 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, + 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, + 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, + 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, + 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, + 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, + 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, +10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, +10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, +10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, +10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, +10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, +10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, +10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, +10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, +10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, +10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, +11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, +11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, +11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, +11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, +11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, +11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, +11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, +11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, +11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, +12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, +12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, +12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, +12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, +12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, +12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, +12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, +12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, +12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, +12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, +13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, +13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, +13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, +13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, +13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, +13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, +13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, +13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, +13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, +13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, +14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, +14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, +14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, +14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, +14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, +14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, +14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, +14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, +14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, +15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, +15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, +15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, +15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, +15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, +15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, +15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, +15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, +15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, +15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, +16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, +16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, +16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, +16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547, +16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, +16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, +16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, +16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, +16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, +17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, +17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, +17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 17417, +17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, +17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, +17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737, +17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851, +17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, +17959, 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, +18059, 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, +18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, 18251, +18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, +18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, +18451, 18457, 18461, 18481, 18493, 18503, 18517, 18521, 18523, 18539, 18541, +18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, 18701, +18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, +18839, 18859, 18869, 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, +18979, 19001, 19009, 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, +19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, +19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, +19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, 19427, +19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, 19483, 19489, +19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, +19603, 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, +19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, +19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, +19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, +20051, 20063, 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, +20147, 20149, 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, +20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, +20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, +20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, +20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, 20707, 20717, 20719, +20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, +20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, +20947, 20959, 20963, 20981, 20983, 21001, 21011, 21013, 21017, 21019, 21023, +21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, 21139, 21143, 21149, +21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, +21269, 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, +21383, 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, +21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, 21569, +21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, +21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, +21787, 21799, 21803, 21817, 21821, 21839, 21841, 21851, 21859, 21863, 21871, +21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, 22003, +22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, +22093, 22109, 22111, 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, +22189, 22193, 22229, 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, +22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, +22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, +22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, 22651, +22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, 22739, 22741, +22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, +22871, 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, +23003, 23011, 23017, 23021, 23027, 23029, 23039, 23041, 23053, 23057, 23059, +23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, 23167, 23173, +23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, +23297, 23311, 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, +23431, 23447, 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, +23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, +23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, +23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, +23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, 23911, 23917, 23929, +23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, +24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, +24121, 24133, 24137, 24151, 24169, 24179, 24181, 24197, 24203, 24223, 24229, +24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, 24371, 24373, 24379, +24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, +24509, 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, +24659, 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, +24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, 24889, +24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, +25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, +25127, 25147, 25153, 25163, 25169, 25171, 25183, 25189, 25219, 25229, 25237, +25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, 25343, +25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, +25457, 25463, 25469, 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, +25589, 25601, 25603, 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, +25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, +25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, +25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, 26003, +26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, 26113, 26119, +26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, +26249, 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, +26347, 26357, 26371, 26387, 26393, 26399, 26407, 26417, 26423, 26431, 26437, +26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, 26561, 26573, +26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, +26699, 26701, 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, +26783, 26801, 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, +26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, +26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, +27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, +27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, 27337, 27361, 27367, +27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, +27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, +27647, 27653, 27673, 27689, 27691, 27697, 27701, 27733, 27737, 27739, 27743, +27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, 27799, 27803, 27809, +27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, +27943, 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, +28051, 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, +28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, 28289, +28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, +28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, +28541, 28547, 28549, 28559, 28571, 28573, 28579, 28591, 28597, 28603, 28607, +28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, 28687, +28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, +28807, 28813, 28817, 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, +28921, 28927, 28933, 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, +29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, +29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, +29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, 29383, +29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, 29453, 29473, +29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, +29611, 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, +29753, 29759, 29761, 29789, 29803, 29819, 29833, 29837, 29851, 29863, 29867, +29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, 29989, 30011, +30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, +30119, 30133, 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, +30223, 30241, 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, +30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, +30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, +30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, +30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829, +30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, +30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, +31063, 31069, 31079, 31081, 31091, 31121, 31123, 31139, 31147, 31151, 31153, +31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, 31231, 31237, 31247, +31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, +31337, 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, +31511, 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, +31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, 31723, +31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, +31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, +32009, 32027, 32029, 32051, 32057, 32059, 32063, 32069, 32077, 32083, 32089, +32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, 32203, +32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, +32323, 32327, 32341, 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, +32411, 32413, 32423, 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, +32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, +32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, +32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, 32833, +32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, 32941, 32957, +32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, +33053, 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, +33179, 33181, 33191, 33199, 33203, 33211, 33223, 33247, 33287, 33289, 33301, +33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, 33377, 33391, +33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, +33521, 33529, 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, +33601, 33613, 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, +33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, +33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, +33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, +34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, 34159, 34171, 34183, +34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, +34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, +34403, 34421, 34429, 34439, 34457, 34469, 34471, 34483, 34487, 34499, 34501, +34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, 34591, 34603, 34607, +34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, +34729, 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, +34847, 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, +34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, 35089, +35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, +35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, +35327, 35339, 35353, 35363, 35381, 35393, 35401, 35407, 35419, 35423, 35437, +35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, 35537, +35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, +35731, 35747, 35753, 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, +35839, 35851, 35863, 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, +35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, +36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, +36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, 36293, +36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, 36389, 36433, +36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, +36541, 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, +36643, 36653, 36671, 36677, 36683, 36691, 36697, 36709, 36713, 36721, 36739, +36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, 36821, 36833, +36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, +36931, 36943, 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, +37049, 37057, 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, +37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, +37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, +37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, +37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, 37579, 37589, 37591, +37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, +37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, +37879, 37889, 37897, 37907, 37951, 37957, 37963, 37967, 37987, 37991, 37993, +37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, 38119, 38149, 38153, +38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, +38273, 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, +38371, 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, +38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, 38651, +38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, +38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, +38861, 38867, 38873, 38891, 38903, 38917, 38921, 38923, 38933, 38953, 38959, +38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, 39097, +39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, +39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, +39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, +39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, +39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, +39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779, +39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869, +39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, +40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, +40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231, +40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387, +40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, +40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, +40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, +40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, +40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, +41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, +41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203, +41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, +41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, +41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549, +41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, 41627, 41641, 41647, +41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, +41777, 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, +41897, 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, +41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, 42083, +42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, +42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, +42323, 42331, 42337, 42349, 42359, 42373, 42379, 42391, 42397, 42403, 42407, +42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, 42487, +42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, +42643, 42649, 42667, 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, +42727, 42737, 42743, 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, +42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, +42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, +43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, 43201, +43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, 43321, 43331, +43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, +43499, 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, +43613, 43627, 43633, 43649, 43651, 43661, 43669, 43691, 43711, 43717, 43721, +43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, 43853, 43867, +43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, +43991, 43997, 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, +44089, 44101, 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, +44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, +44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, +44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, +44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, 44647, 44651, 44657, +44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, +44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, +44909, 44917, 44927, 44939, 44953, 44959, 44963, 44971, 44983, 44987, 45007, +45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, 45131, 45137, 45139, +45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, +45293, 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, +45403, 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, +45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, 45659, +45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, +45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, +45893, 45943, 45949, 45953, 45959, 45971, 45979, 45989, 46021, 46027, 46049, +46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, 46153, +46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, +46279, 46301, 46307, 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, +46439, 46441, 46447, 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, +46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, +46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, +46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, 46853, +46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, 46997, 47017, +47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, +47143, 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, +47287, 47293, 47297, 47303, 47309, 47317, 47339, 47351, 47353, 47363, 47381, +47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, 47497, 47501, +47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, +47609, 47623, 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, +47713, 47717, 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, +47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, +47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, +48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, +48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, 48311, 48313, 48337, +48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, +48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, +48563, 48571, 48589, 48593, 48611, 48619, 48623, 48647, 48649, 48661, 48673, +48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, 48779, 48781, 48787, +48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, +48889, 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, +49033, 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, +49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, 49223, +49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, +49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, +49477, 49481, 49499, 49523, 49529, 49531, 49537, 49547, 49549, 49559, 49597, +49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, 49711, +49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, +49823, 49831, 49843, 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, +49939, 49943, 49957, 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, +50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, +50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, +50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, 50383, +50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, 50513, 50527, +50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, +50651, 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, +50821, 50833, 50839, 50849, 50857, 50867, 50873, 50891, 50893, 50909, 50923, +50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, 51043, 51047, +51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, +51197, 51199, 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, +51307, 51329, 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, +51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, +51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, +51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, +51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, 51817, 51827, 51829, +51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, +51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, +52069, 52081, 52103, 52121, 52127, 52147, 52153, 52163, 52177, 52181, 52183, +52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, 52289, 52291, 52301, +52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, +52489, 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, +52579, 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, +52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, 52817, +52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, +52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, +53077, 53087, 53089, 53093, 53101, 53113, 53117, 53129, 53147, 53149, 53161, +53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, 53279, +53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, +53411, 53419, 53437, 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, +53569, 53591, 53593, 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, +53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, +53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, +53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, 54001, +54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, 54133, 54139, +54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, +54311, 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, +54409, 54413, 54419, 54421, 54437, 54443, 54449, 54469, 54493, 54497, 54499, +54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, 54581, 54583, +54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, +54721, 54727, 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, +54869, 54877, 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, +54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, +55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, +55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, +55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, 55469, 55487, 55501, +55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, +55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, +55721, 55733, 55763, 55787, 55793, 55799, 55807, 55813, 55817, 55819, 55823, +55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, 55903, 55921, 55927, +55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, +56081, 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, +56179, 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, +56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, 56437, +56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, +56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, +56659, 56663, 56671, 56681, 56687, 56701, 56711, 56713, 56731, 56737, 56747, +56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, 56857, +56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, +56957, 56963, 56983, 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, +57077, 57089, 57097, 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, +57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, +57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, +57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, 57557, +57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, 57667, 57679, +57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, +57787, 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, +57899, 57901, 57917, 57923, 57943, 57947, 57973, 57977, 57991, 58013, 58027, +58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, 58111, 58129, +58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, +58229, 58231, 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, +58369, 58379, 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, +58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, +58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, +58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, +58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, 58979, 58991, 58997, +59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, +59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, +59207, 59209, 59219, 59221, 59233, 59239, 59243, 59263, 59273, 59281, 59333, +59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, 59399, 59407, 59417, +59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, +59539, 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, +59659, 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, +59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, 59921, +59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, +60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, +60161, 60167, 60169, 60209, 60217, 60223, 60251, 60257, 60259, 60271, 60289, +60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, 60427, +60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, +60607, 60611, 60617, 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, +60689, 60703, 60719, 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, +60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, +60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, +61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, 61211, +61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, 61339, 61343, +61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, +61483, 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, +61583, 61603, 61609, 61613, 61627, 61631, 61637, 61643, 61651, 61657, 61667, +61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, 61781, 61813, +61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, +61967, 61979, 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, +62057, 62071, 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, +62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, +62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, +62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, +62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, 62659, 62683, 62687, +62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, +62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, +62971, 62981, 62983, 62987, 62989, 63029, 63031, 63059, 63067, 63073, 63079, +63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, 63199, 63211, 63241, +63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, +63361, 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, +63463, 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, +63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, 63649, +63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, +63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, +63853, 63857, 63863, 63901, 63907, 63913, 63929, 63949, 63977, 63997, 64007, +64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, 64151, +64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, +64283, 64301, 64303, 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, +64439, 64451, 64453, 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, +64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, +64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, +64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, 64951, +64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, 65071, 65089, +65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, +65179, 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, +65323, 65327, 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423, +65437, 65447, 65449, 65479, 65497, 65519, 65521, 0 }; + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/reducer.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/reducer.cpp new file mode 100644 index 0000000000..98cf698ed7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/reducer.cpp @@ -0,0 +1,90 @@ +/* +* Modular Reducer +* (C) 1999-2011,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/reducer.h> +#include <botan/internal/ct_utils.h> + +namespace Botan { + +/* +* Modular_Reducer Constructor +*/ +Modular_Reducer::Modular_Reducer(const BigInt& mod) + { + if(mod < 0) + throw Invalid_Argument("Modular_Reducer: modulus must be positive"); + + // Left uninitialized if mod == 0 + m_mod_words = 0; + + if(mod > 0) + { + m_modulus = mod; + m_mod_words = m_modulus.sig_words(); + + m_modulus_2 = Botan::square(m_modulus); + + m_mu = BigInt::power_of_2(2 * BOTAN_MP_WORD_BITS * m_mod_words) / m_modulus; + } + } + +/* +* Barrett Reduction +*/ +BigInt Modular_Reducer::reduce(const BigInt& x) const + { + if(m_mod_words == 0) + throw Invalid_State("Modular_Reducer: Never initalized"); + + const size_t x_sw = x.sig_words(); + + if(x_sw >= (2*m_mod_words - 1) && x.cmp(m_modulus_2, false) >= 0) + { + // too big, fall back to normal division + return (x % m_modulus); + } + + secure_vector<word> ws; + + BigInt t1 = x; + t1.set_sign(BigInt::Positive); + t1 >>= (BOTAN_MP_WORD_BITS * (m_mod_words - 1)); + + t1.mul(m_mu, ws); + t1 >>= (BOTAN_MP_WORD_BITS * (m_mod_words + 1)); + + // TODO add masked mul to avoid computing high bits + t1.mul(m_modulus, ws); + t1.mask_bits(BOTAN_MP_WORD_BITS * (m_mod_words + 1)); + + t1.rev_sub(x.data(), std::min(x_sw, m_mod_words + 1), ws); + + /* + * If t1 < 0 then we must add b^(k+1) where b = 2^w. To avoid a + * side channel perform the addition unconditionally, with ws set + * to either b^(k+1) or else 0. + */ + const word t1_neg = t1.is_negative(); + + if(ws.size() < m_mod_words + 2) + ws.resize(m_mod_words + 2); + clear_mem(ws.data(), ws.size()); + ws[m_mod_words + 1] = t1_neg; + + t1.add(ws.data(), m_mod_words + 2, BigInt::Positive); + + t1.reduce_below(m_modulus, ws); + + if(x.is_negative() && t1.is_nonzero()) + { + t1.rev_sub(m_modulus.data(), m_modulus.size(), ws); + } + + return t1; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/reducer.h b/src/libs/3rdparty/botan/src/lib/math/numbertheory/reducer.h new file mode 100644 index 0000000000..c66c220342 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/reducer.h @@ -0,0 +1,61 @@ +/* +* Modular Reducer +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MODULAR_REDUCER_H_ +#define BOTAN_MODULAR_REDUCER_H_ + +#include <botan/numthry.h> + +namespace Botan { + +/** +* Modular Reducer (using Barrett's technique) +*/ +class BOTAN_PUBLIC_API(2,0) Modular_Reducer + { + public: + const BigInt& get_modulus() const { return m_modulus; } + + BigInt reduce(const BigInt& x) const; + + /** + * Multiply mod p + * @param x the first operand + * @param y the second operand + * @return (x * y) % p + */ + BigInt multiply(const BigInt& x, const BigInt& y) const + { return reduce(x * y); } + + /** + * Square mod p + * @param x the value to square + * @return (x * x) % p + */ + BigInt square(const BigInt& x) const + { return reduce(Botan::square(x)); } + + /** + * Cube mod p + * @param x the value to cube + * @return (x * x * x) % p + */ + BigInt cube(const BigInt& x) const + { return multiply(x, this->square(x)); } + + bool initialized() const { return (m_mod_words != 0); } + + Modular_Reducer() { m_mod_words = 0; } + explicit Modular_Reducer(const BigInt& mod); + private: + BigInt m_modulus, m_modulus_2, m_mu; + size_t m_mod_words; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/math/numbertheory/ressol.cpp b/src/libs/3rdparty/botan/src/lib/math/numbertheory/ressol.cpp new file mode 100644 index 0000000000..9d11ebbc42 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/math/numbertheory/ressol.cpp @@ -0,0 +1,87 @@ +/* +* Shanks-Tonnelli (RESSOL) +* (C) 2007-2008 Falko Strenzke, FlexSecure GmbH +* (C) 2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/numthry.h> +#include <botan/reducer.h> + +namespace Botan { + +/* +* Shanks-Tonnelli algorithm +*/ +BigInt ressol(const BigInt& a, const BigInt& p) + { + if(a == 0) + return 0; + else if(a < 0) + throw Invalid_Argument("ressol: value to solve for must be positive"); + else if(a >= p) + throw Invalid_Argument("ressol: value to solve for must be less than p"); + + if(p == 2) + return a; + else if(p <= 1) + throw Invalid_Argument("ressol: prime must be > 1 a"); + else if(p.is_even()) + throw Invalid_Argument("ressol: invalid prime"); + + if(jacobi(a, p) != 1) // not a quadratic residue + return -BigInt(1); + + if(p % 4 == 3) + return power_mod(a, ((p+1) >> 2), p); + + size_t s = low_zero_bits(p - 1); + BigInt q = p >> s; + + q -= 1; + q >>= 1; + + Modular_Reducer mod_p(p); + + BigInt r = power_mod(a, q, p); + BigInt n = mod_p.multiply(a, mod_p.square(r)); + r = mod_p.multiply(r, a); + + if(n == 1) + return r; + + // find random non quadratic residue z + BigInt z = 2; + while(jacobi(z, p) == 1) // while z quadratic residue + ++z; + + BigInt c = power_mod(z, (q << 1) + 1, p); + + while(n > 1) + { + q = n; + + size_t i = 0; + while(q != 1) + { + q = mod_p.square(q); + ++i; + + if(i >= s) + { + return -BigInt(1); + } + } + + c = power_mod(c, BigInt::power_of_2(s-i-1), p); + r = mod_p.multiply(r, c); + c = mod_p.square(c); + n = mod_p.multiply(n, c); + s = i; + } + + return r; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.cpp b/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.cpp new file mode 100644 index 0000000000..c67664a6e7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.cpp @@ -0,0 +1,312 @@ +/* +* CBC Mode +* (C) 1999-2007,2013,2017 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cbc.h> +#include <botan/mode_pad.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +CBC_Mode::CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + m_cipher(cipher), + m_padding(padding), + m_state(m_cipher->block_size()) + { + if(m_padding && !m_padding->valid_blocksize(cipher->block_size())) + throw Invalid_Argument("Padding " + m_padding->name() + + " cannot be used with " + + cipher->name() + "/CBC"); + } + +void CBC_Mode::clear() + { + m_cipher->clear(); + reset(); + } + +void CBC_Mode::reset() + { + zeroise(m_state); + } + +std::string CBC_Mode::name() const + { + if(m_padding) + return cipher().name() + "/CBC/" + padding().name(); + else + return cipher().name() + "/CBC/CTS"; + } + +size_t CBC_Mode::update_granularity() const + { + return cipher().parallel_bytes(); + } + +Key_Length_Specification CBC_Mode::key_spec() const + { + return cipher().key_spec(); + } + +size_t CBC_Mode::default_nonce_length() const + { + return block_size(); + } + +bool CBC_Mode::valid_nonce_length(size_t n) const + { + return (n == 0 || n == block_size()); + } + +void CBC_Mode::key_schedule(const uint8_t key[], size_t length) + { + m_cipher->set_key(key, length); + } + +void CBC_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + /* + * A nonce of zero length means carry the last ciphertext value over + * as the new IV, as unfortunately some protocols require this. If + * this is the first message then we use an IV of all zeros. + */ + if(nonce_len) + m_state.assign(nonce, nonce + nonce_len); + } + +size_t CBC_Encryption::minimum_final_size() const + { + return 0; + } + +size_t CBC_Encryption::output_length(size_t input_length) const + { + if(input_length == 0) + return block_size(); + else + return round_up(input_length, block_size()); + } + +size_t CBC_Encryption::process(uint8_t buf[], size_t sz) + { + const size_t BS = block_size(); + + BOTAN_ASSERT(sz % BS == 0, "CBC input is full blocks"); + const size_t blocks = sz / BS; + + if(blocks > 0) + { + xor_buf(&buf[0], state_ptr(), BS); + cipher().encrypt(&buf[0]); + + for(size_t i = 1; i != blocks; ++i) + { + xor_buf(&buf[BS*i], &buf[BS*(i-1)], BS); + cipher().encrypt(&buf[BS*i]); + } + + state().assign(&buf[BS*(blocks-1)], &buf[BS*blocks]); + } + + return sz; + } + +void CBC_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + + const size_t BS = block_size(); + + const size_t bytes_in_final_block = (buffer.size()-offset) % BS; + + padding().add_padding(buffer, bytes_in_final_block, BS); + + if((buffer.size()-offset) % BS) + throw Exception("Did not pad to full block size in " + name()); + + update(buffer, offset); + } + +bool CTS_Encryption::valid_nonce_length(size_t n) const + { + return (n == block_size()); + } + +size_t CTS_Encryption::minimum_final_size() const + { + return block_size() + 1; + } + +size_t CTS_Encryption::output_length(size_t input_length) const + { + return input_length; // no ciphertext expansion in CTS + } + +void CTS_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + uint8_t* buf = buffer.data() + offset; + const size_t sz = buffer.size() - offset; + + const size_t BS = block_size(); + + if(sz < BS + 1) + throw Encoding_Error(name() + ": insufficient data to encrypt"); + + if(sz % BS == 0) + { + update(buffer, offset); + + // swap last two blocks + for(size_t i = 0; i != BS; ++i) + std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); + } + else + { + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + xor_buf(last.data(), state_ptr(), BS); + cipher().encrypt(last.data()); + + for(size_t i = 0; i != final_bytes - BS; ++i) + { + last[i] ^= last[i + BS]; + last[i + BS] ^= last[i]; + } + + cipher().encrypt(last.data()); + + buffer += last; + } + } + +size_t CBC_Decryption::output_length(size_t input_length) const + { + return input_length; // precise for CTS, worst case otherwise + } + +size_t CBC_Decryption::minimum_final_size() const + { + return block_size(); + } + +size_t CBC_Decryption::process(uint8_t buf[], size_t sz) + { + const size_t BS = block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + while(blocks) + { + const size_t to_proc = std::min(BS * blocks, m_tempbuf.size()); + + cipher().decrypt_n(buf, m_tempbuf.data(), to_proc / BS); + + xor_buf(m_tempbuf.data(), state_ptr(), BS); + xor_buf(&m_tempbuf[BS], buf, to_proc - BS); + copy_mem(state_ptr(), buf + (to_proc - BS), BS); + + copy_mem(buf, m_tempbuf.data(), to_proc); + + buf += to_proc; + blocks -= to_proc / BS; + } + + return sz; + } + +void CBC_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + + const size_t BS = block_size(); + + if(sz == 0 || sz % BS) + throw Decoding_Error(name() + ": Ciphertext not a multiple of block size"); + + update(buffer, offset); + + const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.size()-BS], BS); + buffer.resize(buffer.size() - pad_bytes); // remove padding + if(pad_bytes == 0 && padding().name() != "NoPadding") + { + throw Decoding_Error(name()); + } + } + +void CBC_Decryption::reset() + { + zeroise(state()); + zeroise(m_tempbuf); + } + +bool CTS_Decryption::valid_nonce_length(size_t n) const + { + return (n == block_size()); + } + +size_t CTS_Decryption::minimum_final_size() const + { + return block_size() + 1; + } + +void CTS_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + const size_t BS = block_size(); + + if(sz < BS + 1) + throw Encoding_Error(name() + ": insufficient data to decrypt"); + + if(sz % BS == 0) + { + // swap last two blocks + + for(size_t i = 0; i != BS; ++i) + std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); + + update(buffer, offset); + } + else + { + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + cipher().decrypt(last.data()); + + xor_buf(last.data(), &last[BS], final_bytes - BS); + + for(size_t i = 0; i != final_bytes - BS; ++i) + std::swap(last[i], last[i + BS]); + + cipher().decrypt(last.data()); + xor_buf(last.data(), state_ptr(), BS); + + buffer += last; + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.h b/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.h new file mode 100644 index 0000000000..65b6395115 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.h @@ -0,0 +1,154 @@ +/* +* CBC mode +* (C) 1999-2007,2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MODE_CBC_H_ +#define BOTAN_MODE_CBC_H_ + +#include <botan/cipher_mode.h> +#include <botan/block_cipher.h> +#include <botan/mode_pad.h> + +namespace Botan { + +/** +* CBC Mode +*/ +class BOTAN_PUBLIC_API(2,0) CBC_Mode : public Cipher_Mode + { + public: + std::string name() const override; + + size_t update_granularity() const override; + + Key_Length_Specification key_spec() const override; + + size_t default_nonce_length() const override; + + bool valid_nonce_length(size_t n) const override; + + void clear() override; + + void reset() override; + + protected: + CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding); + + const BlockCipher& cipher() const { return *m_cipher; } + + const BlockCipherModePaddingMethod& padding() const + { + BOTAN_ASSERT_NONNULL(m_padding); + return *m_padding; + } + + secure_vector<uint8_t>& state() { return m_state; } + + size_t block_size() const { return m_state.size(); } + + uint8_t* state_ptr() { return m_state.data(); } + + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + + void key_schedule(const uint8_t key[], size_t length) override; + + std::unique_ptr<BlockCipher> m_cipher; + std::unique_ptr<BlockCipherModePaddingMethod> m_padding; + secure_vector<uint8_t> m_state; + }; + +/** +* CBC Encryption +*/ +class BOTAN_PUBLIC_API(2,0) CBC_Encryption : public CBC_Mode + { + public: + /** + * @param cipher block cipher to use + * @param padding padding method to use + */ + CBC_Encryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + CBC_Mode(cipher, padding) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override; + }; + +/** +* CBC Encryption with ciphertext stealing (CBC-CS3 variant) +*/ +class BOTAN_PUBLIC_API(2,0) CTS_Encryption final : public CBC_Encryption + { + public: + /** + * @param cipher block cipher to use + */ + explicit CTS_Encryption(BlockCipher* cipher) : CBC_Encryption(cipher, nullptr) {} + + size_t output_length(size_t input_length) const override; + + void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) override; + + size_t minimum_final_size() const override; + + bool valid_nonce_length(size_t n) const override; + }; + +/** +* CBC Decryption +*/ +class BOTAN_PUBLIC_API(2,0) CBC_Decryption : public CBC_Mode + { + public: + /** + * @param cipher block cipher to use + * @param padding padding method to use + */ + CBC_Decryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + CBC_Mode(cipher, padding), m_tempbuf(update_granularity()) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override; + + void reset() override; + + private: + secure_vector<uint8_t> m_tempbuf; + }; + +/** +* CBC Decryption with ciphertext stealing (CBC-CS3 variant) +*/ +class BOTAN_PUBLIC_API(2,0) CTS_Decryption final : public CBC_Decryption + { + public: + /** + * @param cipher block cipher to use + */ + explicit CTS_Decryption(BlockCipher* cipher) : CBC_Decryption(cipher, nullptr) {} + + void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) override; + + size_t minimum_final_size() const override; + + bool valid_nonce_length(size_t n) const override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/modes/cbc/info.txt b/src/libs/3rdparty/botan/src/lib/modes/cbc/info.txt new file mode 100644 index 0000000000..778ba1e252 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/cbc/info.txt @@ -0,0 +1,8 @@ +<defines> +MODE_CBC -> 20131128 +</defines> + +<requires> +block +mode_pad +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.cpp b/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.cpp new file mode 100644 index 0000000000..00d7a4db08 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.cpp @@ -0,0 +1,188 @@ +/* +* Cipher Modes +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cipher_mode.h> +#include <botan/stream_mode.h> +#include <botan/scan_name.h> +#include <botan/parsing.h> +#include <sstream> + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + #include <botan/block_cipher.h> +#endif + +#if defined(BOTAN_HAS_AEAD_MODES) + #include <botan/aead.h> +#endif + +#if defined(BOTAN_HAS_MODE_CBC) + #include <botan/cbc.h> +#endif + +#if defined(BOTAN_HAS_MODE_CFB) + #include <botan/cfb.h> +#endif + +#if defined(BOTAN_HAS_MODE_XTS) + #include <botan/xts.h> +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include <botan/internal/openssl.h> +#endif + +namespace Botan { + +std::unique_ptr<Cipher_Mode> Cipher_Mode::create_or_throw(const std::string& algo, + Cipher_Dir direction, + const std::string& provider) + { + if(auto mode = Cipher_Mode::create(algo, direction, provider)) + return mode; + + throw Lookup_Error("Cipher mode", algo, provider); + } + +std::unique_ptr<Cipher_Mode> Cipher_Mode::create(const std::string& algo, + Cipher_Dir direction, + const std::string& provider) + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + std::unique_ptr<Cipher_Mode> openssl_cipher(make_openssl_cipher_mode(algo, direction)); + + if(openssl_cipher) + return openssl_cipher; + + if(!provider.empty()) + return std::unique_ptr<Cipher_Mode>(); + } +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + if(auto sc = StreamCipher::create(algo)) + { + return std::unique_ptr<Cipher_Mode>(new Stream_Cipher_Mode(sc.release())); + } +#endif + +#if defined(BOTAN_HAS_AEAD_MODES) + if(auto aead = AEAD_Mode::create(algo, direction)) + { + return std::unique_ptr<Cipher_Mode>(aead.release()); + } +#endif + + if(algo.find('/') != std::string::npos) + { + const std::vector<std::string> algo_parts = split_on(algo, '/'); + const std::string cipher_name = algo_parts[0]; + const std::vector<std::string> mode_info = parse_algorithm_name(algo_parts[1]); + + if(mode_info.empty()) + return std::unique_ptr<Cipher_Mode>(); + + std::ostringstream alg_args; + + alg_args << '(' << cipher_name; + for(size_t i = 1; i < mode_info.size(); ++i) + alg_args << ',' << mode_info[i]; + for(size_t i = 2; i < algo_parts.size(); ++i) + alg_args << ',' << algo_parts[i]; + alg_args << ')'; + + const std::string mode_name = mode_info[0] + alg_args.str(); + return Cipher_Mode::create(mode_name, direction, provider); + } + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + + SCAN_Name spec(algo); + + if(spec.arg_count() == 0) + { + return std::unique_ptr<Cipher_Mode>(); + } + + std::unique_ptr<BlockCipher> bc(BlockCipher::create(spec.arg(0), provider)); + + if(!bc) + { + return std::unique_ptr<Cipher_Mode>(); + } + +#if defined(BOTAN_HAS_MODE_CBC) + if(spec.algo_name() == "CBC") + { + const std::string padding = spec.arg(1, "PKCS7"); + + if(padding == "CTS") + { + if(direction == ENCRYPTION) + return std::unique_ptr<Cipher_Mode>(new CTS_Encryption(bc.release())); + else + return std::unique_ptr<Cipher_Mode>(new CTS_Decryption(bc.release())); + } + else + { + std::unique_ptr<BlockCipherModePaddingMethod> pad(get_bc_pad(padding)); + + if(pad) + { + if(direction == ENCRYPTION) + return std::unique_ptr<Cipher_Mode>(new CBC_Encryption(bc.release(), pad.release())); + else + return std::unique_ptr<Cipher_Mode>(new CBC_Decryption(bc.release(), pad.release())); + } + } + } +#endif + +#if defined(BOTAN_HAS_MODE_XTS) + if(spec.algo_name() == "XTS") + { + if(direction == ENCRYPTION) + return std::unique_ptr<Cipher_Mode>(new XTS_Encryption(bc.release())); + else + return std::unique_ptr<Cipher_Mode>(new XTS_Decryption(bc.release())); + } +#endif + +#if defined(BOTAN_HAS_MODE_CFB) + if(spec.algo_name() == "CFB") + { + const size_t feedback_bits = spec.arg_as_integer(1, 8*bc->block_size()); + if(direction == ENCRYPTION) + return std::unique_ptr<Cipher_Mode>(new CFB_Encryption(bc.release(), feedback_bits)); + else + return std::unique_ptr<Cipher_Mode>(new CFB_Decryption(bc.release(), feedback_bits)); + } +#endif + +#endif + + return std::unique_ptr<Cipher_Mode>(); + } + +//static +std::vector<std::string> Cipher_Mode::providers(const std::string& algo_spec) + { + const std::vector<std::string>& possible = { "base", "openssl" }; + std::vector<std::string> providers; + for(auto&& prov : possible) + { + std::unique_ptr<Cipher_Mode> mode = Cipher_Mode::create(algo_spec, ENCRYPTION, prov); + if(mode) + { + providers.push_back(prov); // available + } + } + return providers; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.h b/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.h new file mode 100644 index 0000000000..f67e737a43 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.h @@ -0,0 +1,257 @@ +/* +* Cipher Modes +* (C) 2013,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CIPHER_MODE_H_ +#define BOTAN_CIPHER_MODE_H_ + +#include <botan/secmem.h> +#include <botan/key_spec.h> +#include <botan/exceptn.h> +#include <botan/symkey.h> +#include <string> +#include <vector> + +namespace Botan { + +/** +* The two possible directions for cipher filters, determining whether they +* actually perform encryption or decryption. +*/ +enum Cipher_Dir : int { ENCRYPTION, DECRYPTION }; + +/** +* Interface for cipher modes +*/ +class BOTAN_PUBLIC_API(2,0) Cipher_Mode + { + public: + virtual ~Cipher_Mode() = default; + + /** + * @return list of available providers for this algorithm, empty if not available + * @param algo_spec algorithm name + */ + static std::vector<std::string> providers(const std::string& algo_spec); + + /** + * Create an AEAD mode + * @param algo the algorithm to create + * @param direction specify if this should be an encryption or decryption AEAD + * @param provider optional specification for provider to use + * @return an AEAD mode or a null pointer if not available + */ + static std::unique_ptr<Cipher_Mode> create(const std::string& algo, + Cipher_Dir direction, + const std::string& provider = ""); + + /** + * Create an AEAD mode, or throw + * @param algo the algorithm to create + * @param direction specify if this should be an encryption or decryption AEAD + * @param provider optional specification for provider to use + * @return an AEAD mode, or throw an exception + */ + static std::unique_ptr<Cipher_Mode> create_or_throw(const std::string& algo, + Cipher_Dir direction, + const std::string& provider = ""); + + /* + * Prepare for processing a message under the specified nonce + */ + virtual void start_msg(const uint8_t nonce[], size_t nonce_len) = 0; + + /** + * Begin processing a message. + * @param nonce the per message nonce + */ + template<typename Alloc> + void start(const std::vector<uint8_t, Alloc>& nonce) + { + start_msg(nonce.data(), nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + * @param nonce_len length of nonce + */ + void start(const uint8_t nonce[], size_t nonce_len) + { + start_msg(nonce, nonce_len); + } + + /** + * Begin processing a message. + */ + void start() + { + return start_msg(nullptr, 0); + } + + /** + * Process message blocks + * + * Input must be a multiple of update_granularity + * + * Processes msg in place and returns bytes written. Normally + * this will be either msg_len (indicating the entire message was + * processed) or for certain AEAD modes zero (indicating that the + * mode requires the entire message be processed in one pass). + * + * @param msg the message to be processed + * @param msg_len length of the message in bytes + */ + virtual size_t process(uint8_t msg[], size_t msg_len) = 0; + + /** + * Process some data. Input must be in size update_granularity() uint8_t blocks. + * @param buffer in/out parameter which will possibly be resized + * @param offset an offset into blocks to begin processing + */ + void update(secure_vector<uint8_t>& buffer, size_t offset = 0) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset ok"); + uint8_t* buf = buffer.data() + offset; + const size_t buf_size = buffer.size() - offset; + + const size_t written = process(buf, buf_size); + buffer.resize(offset + written); + } + + /** + * Complete processing of a message. + * + * @param final_block in/out parameter which must be at least + * minimum_final_size() bytes, and will be set to any final output + * @param offset an offset into final_block to begin processing + */ + virtual void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) = 0; + + /** + * Returns the size of the output if this transform is used to process a + * message with input_length bytes. Will throw if unable to give a precise + * answer. + */ + virtual size_t output_length(size_t input_length) const = 0; + + /** + * @return size of required blocks to update + */ + virtual size_t update_granularity() const = 0; + + /** + * @return required minimium size to finalize() - may be any + * length larger than this. + */ + virtual size_t minimum_final_size() const = 0; + + /** + * @return the default size for a nonce + */ + virtual size_t default_nonce_length() const = 0; + + /** + * @return true iff nonce_len is a valid length for the nonce + */ + virtual bool valid_nonce_length(size_t nonce_len) const = 0; + + virtual std::string name() const = 0; + + /** + * Zeroise all state + * See also reset_msg() + */ + virtual void clear() = 0; + + /** + * Resets just the message specific state and allows encrypting again under the existing key + */ + virtual void reset() = 0; + + /** + * @return true iff this mode provides authentication as well as + * confidentiality. + */ + virtual bool authenticated() const { return false; } + + /** + * @return the size of the authentication tag used (in bytes) + */ + virtual size_t tag_size() const { return 0; } + + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * Check whether a given key length is valid for this algorithm. + * @param length the key length to be checked. + * @return true if the key length is valid. + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + /** + * Set the symmetric key of this transform + * @param key contains the key material + */ + template<typename Alloc> + void set_key(const std::vector<uint8_t, Alloc>& key) + { + set_key(key.data(), key.size()); + } + + /** + * Set the symmetric key of this transform + * @param key contains the key material + */ + void set_key(const SymmetricKey& key) + { + set_key(key.begin(), key.length()); + } + + /** + * Set the symmetric key of this transform + * @param key contains the key material + * @param length in bytes of key param + */ + void set_key(const uint8_t key[], size_t length) + { + if(!valid_keylength(length)) + throw Invalid_Key_Length(name(), length); + key_schedule(key, length); + } + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + + private: + virtual void key_schedule(const uint8_t key[], size_t length) = 0; + }; + +/** +* Get a cipher mode by name (eg "AES-128/CBC" or "Serpent/XTS") +* @param algo_spec cipher name +* @param direction ENCRYPTION or DECRYPTION +* @param provider provider implementation to choose +*/ +inline Cipher_Mode* get_cipher_mode(const std::string& algo_spec, + Cipher_Dir direction, + const std::string& provider = "") + { + return Cipher_Mode::create(algo_spec, direction, provider).release(); + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/modes/info.txt b/src/libs/3rdparty/botan/src/lib/modes/info.txt new file mode 100644 index 0000000000..4c19db04ca --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/info.txt @@ -0,0 +1,9 @@ +<defines> +MODES -> 20150626 +CIPHER_MODES -> 20180124 +</defines> + +<header:public> +cipher_mode.h +stream_mode.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/modes/mode_pad/info.txt b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/info.txt new file mode 100644 index 0000000000..12b6e5b3a9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/info.txt @@ -0,0 +1,3 @@ +<defines> +CIPHER_MODE_PADDING -> 20131128 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.cpp b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.cpp new file mode 100644 index 0000000000..f93b2dcccc --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.cpp @@ -0,0 +1,196 @@ +/* +* CBC Padding Methods +* (C) 1999-2007,2013 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/mode_pad.h> +#include <botan/exceptn.h> +#include <botan/internal/ct_utils.h> + +namespace Botan { + +/** +* Get a block cipher padding method by name +*/ +BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec) + { + if(algo_spec == "NoPadding") + return new Null_Padding; + + if(algo_spec == "PKCS7") + return new PKCS7_Padding; + + if(algo_spec == "OneAndZeros") + return new OneAndZeros_Padding; + + if(algo_spec == "X9.23") + return new ANSI_X923_Padding; + + if(algo_spec == "ESP") + return new ESP_Padding; + + return nullptr; + } + +/* +* Pad with PKCS #7 Method +*/ +void PKCS7_Padding::add_padding(secure_vector<uint8_t>& buffer, + size_t last_byte_pos, + size_t block_size) const + { + const uint8_t pad_value = static_cast<uint8_t>(block_size - last_byte_pos); + + for(size_t i = 0; i != pad_value; ++i) + buffer.push_back(pad_value); + } + +/* +* Unpad with PKCS #7 Method +*/ +size_t PKCS7_Padding::unpad(const uint8_t block[], size_t size) const + { + CT::poison(block,size); + size_t bad_input = 0; + const uint8_t last_byte = block[size-1]; + + bad_input |= CT::expand_mask<size_t>(last_byte > size); + + size_t pad_pos = size - last_byte; + size_t i = size - 2; + while(i) + { + bad_input |= (~CT::is_equal(block[i],last_byte)) & CT::expand_mask<uint8_t>(i >= pad_pos); + --i; + } + + CT::conditional_copy_mem(bad_input,&pad_pos,&size,&pad_pos,1); + CT::unpoison(block,size); + CT::unpoison(pad_pos); + return pad_pos; + } + +/* +* Pad with ANSI X9.23 Method +*/ +void ANSI_X923_Padding::add_padding(secure_vector<uint8_t>& buffer, + size_t last_byte_pos, + size_t block_size) const + { + const uint8_t pad_value = static_cast<uint8_t>(block_size - last_byte_pos); + + for(size_t i = last_byte_pos; i < block_size-1; ++i) + { + buffer.push_back(0); + } + buffer.push_back(pad_value); + } + +/* +* Unpad with ANSI X9.23 Method +*/ +size_t ANSI_X923_Padding::unpad(const uint8_t block[], size_t size) const + { + CT::poison(block,size); + size_t bad_input = 0; + const size_t last_byte = block[size-1]; + + bad_input |= CT::expand_mask<size_t>(last_byte > size); + + size_t pad_pos = size - last_byte; + size_t i = size - 2; + while(i) + { + bad_input |= (~CT::is_zero(block[i])) & CT::expand_mask<uint8_t>(i >= pad_pos); + --i; + } + CT::conditional_copy_mem(bad_input,&pad_pos,&size,&pad_pos,1); + CT::unpoison(block,size); + CT::unpoison(pad_pos); + return pad_pos; + } + +/* +* Pad with One and Zeros Method +*/ +void OneAndZeros_Padding::add_padding(secure_vector<uint8_t>& buffer, + size_t last_byte_pos, + size_t block_size) const + { + buffer.push_back(0x80); + + for(size_t i = last_byte_pos + 1; i % block_size; ++i) + buffer.push_back(0x00); + } + +/* +* Unpad with One and Zeros Method +*/ +size_t OneAndZeros_Padding::unpad(const uint8_t block[], size_t size) const + { + CT::poison(block, size); + uint8_t bad_input = 0; + uint8_t seen_one = 0; + size_t pad_pos = size - 1; + size_t i = size; + + while(i) + { + seen_one |= CT::is_equal<uint8_t>(block[i-1],0x80); + pad_pos -= CT::select<uint8_t>(~seen_one, 1, 0); + bad_input |= ~CT::is_zero<uint8_t>(block[i-1]) & ~seen_one; + i--; + } + bad_input |= ~seen_one; + + CT::conditional_copy_mem(size_t(bad_input),&pad_pos,&size,&pad_pos,1); + CT::unpoison(block, size); + CT::unpoison(pad_pos); + + return pad_pos; + } + +/* +* Pad with ESP Padding Method +*/ +void ESP_Padding::add_padding(secure_vector<uint8_t>& buffer, + size_t last_byte_pos, + size_t block_size) const + { + uint8_t pad_value = 0x01; + + for(size_t i = last_byte_pos; i < block_size; ++i) + { + buffer.push_back(pad_value++); + } + } + +/* +* Unpad with ESP Padding Method +*/ +size_t ESP_Padding::unpad(const uint8_t block[], size_t size) const + { + CT::poison(block,size); + + const size_t last_byte = block[size-1]; + size_t bad_input = 0; + bad_input |= CT::expand_mask<size_t>(last_byte > size); + + size_t pad_pos = size - last_byte; + size_t i = size - 1; + while(i) + { + bad_input |= ~CT::is_equal<uint8_t>(size_t(block[i-1]),size_t(block[i])-1) & CT::expand_mask<uint8_t>(i > pad_pos); + --i; + } + CT::conditional_copy_mem(bad_input,&pad_pos,&size,&pad_pos,1); + CT::unpoison(block, size); + CT::unpoison(pad_pos); + return pad_pos; + } + + +} diff --git a/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.h b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.h new file mode 100644 index 0000000000..cc196d251b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.h @@ -0,0 +1,159 @@ +/* +* CBC Padding Methods +* (C) 1999-2008,2013 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MODE_PADDING_H_ +#define BOTAN_MODE_PADDING_H_ + +#include <botan/secmem.h> +#include <string> + +namespace Botan { + +/** +* Block Cipher Mode Padding Method +* This class is pretty limited, it cannot deal well with +* randomized padding methods, or any padding method that +* wants to add more than one block. For instance, it should +* be possible to define cipher text stealing mode as simply +* a padding mode for CBC, which happens to consume the last +* two block (and requires use of the block cipher). +*/ +class BOTAN_PUBLIC_API(2,0) BlockCipherModePaddingMethod + { + public: + /** + * Add padding bytes to buffer. + * @param buffer data to pad + * @param final_block_bytes size of the final block in bytes + * @param block_size size of each block in bytes + */ + virtual void add_padding(secure_vector<uint8_t>& buffer, + size_t final_block_bytes, + size_t block_size) const = 0; + + /** + * Remove padding bytes from block + * @param block the last block + * @param size the size of the block in bytes + * @return number of padding bytes + */ + virtual size_t unpad(const uint8_t block[], + size_t size) const = 0; + + /** + * @param block_size of the cipher + * @return valid block size for this padding mode + */ + virtual bool valid_blocksize(size_t block_size) const = 0; + + /** + * @return name of the mode + */ + virtual std::string name() const = 0; + + /** + * virtual destructor + */ + virtual ~BlockCipherModePaddingMethod() = default; + }; + +/** +* PKCS#7 Padding +*/ +class BOTAN_PUBLIC_API(2,0) PKCS7_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector<uint8_t>& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 0 && bs < 256); } + + std::string name() const override { return "PKCS7"; } + }; + +/** +* ANSI X9.23 Padding +*/ +class BOTAN_PUBLIC_API(2,0) ANSI_X923_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector<uint8_t>& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 0 && bs < 256); } + + std::string name() const override { return "X9.23"; } + }; + +/** +* One And Zeros Padding (ISO/IEC 9797-1, padding method 2) +*/ +class BOTAN_PUBLIC_API(2,0) OneAndZeros_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector<uint8_t>& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 0); } + + std::string name() const override { return "OneAndZeros"; } + }; + +/** +* ESP Padding (RFC 4304) +*/ +class BOTAN_PUBLIC_API(2,0) ESP_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector<uint8_t>& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 0); } + + std::string name() const override { return "ESP"; } + }; + +/** +* Null Padding +*/ +class BOTAN_PUBLIC_API(2,0) Null_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector<uint8_t>&, size_t, size_t) const override + { + /* no padding */ + } + + size_t unpad(const uint8_t[], size_t size) const override { return size; } + + bool valid_blocksize(size_t) const override { return true; } + + std::string name() const override { return "NoPadding"; } + }; + +/** +* Get a block cipher padding mode by name (eg "NoPadding" or "PKCS7") +* @param algo_spec block cipher padding mode name +*/ +BOTAN_PUBLIC_API(2,0) BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/modes/stream_mode.h b/src/libs/3rdparty/botan/src/lib/modes/stream_mode.h new file mode 100644 index 0000000000..3bce01731a --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/stream_mode.h @@ -0,0 +1,82 @@ +/* +* (C) 2015 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STREAM_MODE_H_ +#define BOTAN_STREAM_MODE_H_ + +#include <botan/cipher_mode.h> + +#if defined(BOTAN_HAS_STREAM_CIPHER) + #include <botan/stream_cipher.h> +#endif + +namespace Botan { + +#if defined(BOTAN_HAS_STREAM_CIPHER) + +class BOTAN_PUBLIC_API(2,0) Stream_Cipher_Mode final : public Cipher_Mode + { + public: + /** + * @param cipher underyling stream cipher + */ + explicit Stream_Cipher_Mode(StreamCipher* cipher) : m_cipher(cipher) {} + + size_t process(uint8_t buf[], size_t sz) override + { + m_cipher->cipher1(buf, sz); + return sz; + } + + void finish(secure_vector<uint8_t>& buf, size_t offset) override + { return update(buf, offset); } + + size_t output_length(size_t input_length) const override { return input_length; } + + size_t update_granularity() const override { return 1; } + + size_t minimum_final_size() const override { return 0; } + + size_t default_nonce_length() const override { return 0; } + + bool valid_nonce_length(size_t nonce_len) const override + { return m_cipher->valid_iv_length(nonce_len); } + + Key_Length_Specification key_spec() const override { return m_cipher->key_spec(); } + + std::string name() const override { return m_cipher->name(); } + + void clear() override + { + m_cipher->clear(); + reset(); + } + + void reset() override { /* no msg state */ } + + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override + { + if(nonce_len > 0) + { + m_cipher->set_iv(nonce, nonce_len); + } + } + + void key_schedule(const uint8_t key[], size_t length) override + { + m_cipher->set_key(key, length); + } + + std::unique_ptr<StreamCipher> m_cipher; + }; + +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pbkdf/info.txt b/src/libs/3rdparty/botan/src/lib/pbkdf/info.txt new file mode 100644 index 0000000000..48c6b56e66 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pbkdf/info.txt @@ -0,0 +1,12 @@ +<defines> +PBKDF -> 20150626 +</defines> + +<requires> +mac +hash +</requires> + +<header:public> +pbkdf.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf.cpp b/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf.cpp new file mode 100644 index 0000000000..73b482725c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf.cpp @@ -0,0 +1,133 @@ +/* +* PBKDF +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pbkdf.h> +#include <botan/exceptn.h> +#include <botan/scan_name.h> + +#if defined(BOTAN_HAS_PBKDF1) +#include <botan/pbkdf1.h> +#endif + +#if defined(BOTAN_HAS_PBKDF2) +#include <botan/pbkdf2.h> +#endif + +#if defined(BOTAN_HAS_PGP_S2K) +#include <botan/pgp_s2k.h> +#endif + +namespace Botan { + +std::unique_ptr<PBKDF> PBKDF::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_PBKDF2) + if(req.algo_name() == "PBKDF2") + { + // TODO OpenSSL + + if(provider.empty() || provider == "base") + { + if(auto mac = MessageAuthenticationCode::create(req.arg(0))) + return std::unique_ptr<PBKDF>(new PKCS5_PBKDF2(mac.release())); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + req.arg(0) + ")")) + return std::unique_ptr<PBKDF>(new PKCS5_PBKDF2(mac.release())); + } + + return nullptr; + } +#endif + +#if defined(BOTAN_HAS_PBKDF1) + if(req.algo_name() == "PBKDF1" && req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr<PBKDF>(new PKCS5_PBKDF1(hash.release())); + + } +#endif + +#if defined(BOTAN_HAS_PGP_S2K) + if(req.algo_name() == "OpenPGP-S2K" && req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + return std::unique_ptr<PBKDF>(new OpenPGP_S2K(hash.release())); + } +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +//static +std::unique_ptr<PBKDF> +PBKDF::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto pbkdf = PBKDF::create(algo, provider)) + { + return pbkdf; + } + throw Lookup_Error("PBKDF", algo, provider); + } + +std::vector<std::string> PBKDF::providers(const std::string& algo_spec) + { + return probe_providers_of<PBKDF>(algo_spec, { "base", "openssl" }); + } + +void PBKDF::pbkdf_timed(uint8_t out[], size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const + { + iterations = pbkdf(out, out_len, passphrase, salt, salt_len, 0, msec); + } + +void PBKDF::pbkdf_iterations(uint8_t out[], size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations) const + { + if(iterations == 0) + throw Invalid_Argument(name() + ": Invalid iteration count"); + + const size_t iterations_run = pbkdf(out, out_len, passphrase, + salt, salt_len, iterations, + std::chrono::milliseconds(0)); + BOTAN_ASSERT_EQUAL(iterations, iterations_run, "Expected PBKDF iterations"); + } + +secure_vector<uint8_t> PBKDF::pbkdf_iterations(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations) const + { + secure_vector<uint8_t> out(out_len); + pbkdf_iterations(out.data(), out_len, passphrase, salt, salt_len, iterations); + return out; + } + +secure_vector<uint8_t> PBKDF::pbkdf_timed(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const + { + secure_vector<uint8_t> out(out_len); + pbkdf_timed(out.data(), out_len, passphrase, salt, salt_len, msec, iterations); + return out; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf.h b/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf.h new file mode 100644 index 0000000000..7d3bceffcf --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf.h @@ -0,0 +1,243 @@ +/* +* PBKDF +* (C) 1999-2007,2012,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PBKDF_H_ +#define BOTAN_PBKDF_H_ + +#include <botan/symkey.h> +#include <chrono> + +namespace Botan { + +/** +* Base class for PBKDF (password based key derivation function) +* implementations. Converts a password into a key using a salt +* and iterated hashing to make brute force attacks harder. +*/ +class BOTAN_PUBLIC_API(2,0) PBKDF + { + public: + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to choose + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr<PBKDF> create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name, or throw if the + * algo/provider combination cannot be found. If provider is + * empty then best available is chosen. + */ + static std::unique_ptr<PBKDF> + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + */ + static std::vector<std::string> providers(const std::string& algo_spec); + + /** + * @return new instance of this same algorithm + */ + virtual PBKDF* clone() const = 0; + + /** + * @return name of this PBKDF + */ + virtual std::string name() const = 0; + + virtual ~PBKDF() = default; + + /** + * Derive a key from a passphrase for a number of iterations + * specified by either iterations or if iterations == 0 then + * running until msec time has elapsed. + * + * @param out buffer to store the derived key, must be of out_len bytes + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + * @param msec if iterations is zero, then instead the PBKDF is + * run until msec milliseconds has passed. + * @return the number of iterations performed + */ + virtual size_t pbkdf(uint8_t out[], size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const = 0; + + /** + * Derive a key from a passphrase for a number of iterations. + * + * @param out buffer to store the derived key, must be of out_len bytes + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + */ + void pbkdf_iterations(uint8_t out[], size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations) const; + + /** + * Derive a key from a passphrase, running until msec time has elapsed. + * + * @param out buffer to store the derived key, must be of out_len bytes + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param msec if iterations is zero, then instead the PBKDF is + * run until msec milliseconds has passed. + * @param iterations set to the number iterations executed + */ + void pbkdf_timed(uint8_t out[], size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const; + + /** + * Derive a key from a passphrase for a number of iterations. + * + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + * @return the derived key + */ + secure_vector<uint8_t> pbkdf_iterations(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations) const; + + /** + * Derive a key from a passphrase, running until msec time has elapsed. + * + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param msec if iterations is zero, then instead the PBKDF is + * run until msec milliseconds has passed. + * @param iterations set to the number iterations executed + * @return the derived key + */ + secure_vector<uint8_t> pbkdf_timed(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const; + + // Following kept for compat with 1.10: + + /** + * Derive a key from a passphrase + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) + */ + OctetString derive_key(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations) const + { + return pbkdf_iterations(out_len, passphrase, salt, salt_len, iterations); + } + + /** + * Derive a key from a passphrase + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param iterations the number of iterations to use (use 10K or more) + */ + template<typename Alloc> + OctetString derive_key(size_t out_len, + const std::string& passphrase, + const std::vector<uint8_t, Alloc>& salt, + size_t iterations) const + { + return pbkdf_iterations(out_len, passphrase, salt.data(), salt.size(), iterations); + } + + /** + * Derive a key from a passphrase + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param salt_len length of salt in bytes + * @param msec is how long to run the PBKDF + * @param iterations is set to the number of iterations used + */ + OctetString derive_key(size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + std::chrono::milliseconds msec, + size_t& iterations) const + { + return pbkdf_timed(out_len, passphrase, salt, salt_len, msec, iterations); + } + + /** + * Derive a key from a passphrase using a certain amount of time + * @param out_len the desired length of the key to produce + * @param passphrase the password to derive the key from + * @param salt a randomly chosen salt + * @param msec is how long to run the PBKDF + * @param iterations is set to the number of iterations used + */ + template<typename Alloc> + OctetString derive_key(size_t out_len, + const std::string& passphrase, + const std::vector<uint8_t, Alloc>& salt, + std::chrono::milliseconds msec, + size_t& iterations) const + { + return pbkdf_timed(out_len, passphrase, salt.data(), salt.size(), msec, iterations); + } + }; + +/* +* Compatability typedef +*/ +typedef PBKDF S2K; + +/** +* Password based key derivation function factory method +* @param algo_spec the name of the desired PBKDF algorithm +* @param provider the provider to use +* @return pointer to newly allocated object of that type +*/ +inline PBKDF* get_pbkdf(const std::string& algo_spec, + const std::string& provider = "") + { + return PBKDF::create_or_throw(algo_spec, provider).release(); + } + +inline PBKDF* get_s2k(const std::string& algo_spec) + { + return get_pbkdf(algo_spec); + } + + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf2/info.txt b/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf2/info.txt new file mode 100644 index 0000000000..bc5c2e4916 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf2/info.txt @@ -0,0 +1,7 @@ +<defines> +PBKDF2 -> 20131128 +</defines> + +<requires> +hmac +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf2/pbkdf2.cpp b/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf2/pbkdf2.cpp new file mode 100644 index 0000000000..cc2982f6e9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf2/pbkdf2.cpp @@ -0,0 +1,118 @@ +/* +* PBKDF2 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pbkdf2.h> +#include <botan/exceptn.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +size_t +pbkdf2(MessageAuthenticationCode& prf, + uint8_t out[], + size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) + { + clear_mem(out, out_len); + + if(out_len == 0) + return 0; + + try + { + prf.set_key(cast_char_ptr_to_uint8(passphrase.data()), passphrase.size()); + } + catch(Invalid_Key_Length&) + { + throw Exception("PBKDF2 with " + prf.name() + + " cannot accept passphrases of length " + + std::to_string(passphrase.size())); + } + + const size_t prf_sz = prf.output_length(); + secure_vector<uint8_t> U(prf_sz); + + const size_t blocks_needed = round_up(out_len, prf_sz) / prf_sz; + + std::chrono::microseconds usec_per_block = + std::chrono::duration_cast<std::chrono::microseconds>(msec) / blocks_needed; + + uint32_t counter = 1; + while(out_len) + { + const size_t prf_output = std::min<size_t>(prf_sz, out_len); + + prf.update(salt, salt_len); + prf.update_be(counter++); + prf.final(U.data()); + + xor_buf(out, U.data(), prf_output); + + if(iterations == 0) + { + /* + If no iterations set, run the first block to calibrate based + on how long hashing takes on whatever machine we're running on. + */ + + const auto start = std::chrono::high_resolution_clock::now(); + + iterations = 1; // the first iteration we did above + + while(true) + { + prf.update(U); + prf.final(U.data()); + xor_buf(out, U.data(), prf_output); + iterations++; + + /* + Only break on relatively 'even' iterations. For one it + avoids confusion, and likely some broken implementations + break on getting completely randomly distributed values + */ + if(iterations % 10000 == 0) + { + auto time_taken = std::chrono::high_resolution_clock::now() - start; + auto usec_taken = std::chrono::duration_cast<std::chrono::microseconds>(time_taken); + if(usec_taken > usec_per_block) + break; + } + } + } + else + { + for(size_t i = 1; i != iterations; ++i) + { + prf.update(U); + prf.final(U.data()); + xor_buf(out, U.data(), prf_output); + } + } + + out_len -= prf_output; + out += prf_output; + } + + return iterations; + } + +size_t +PKCS5_PBKDF2::pbkdf(uint8_t key[], size_t key_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const + { + return pbkdf2(*m_mac.get(), key, key_len, passphrase, salt, salt_len, iterations, msec); + } + + +} diff --git a/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf2/pbkdf2.h b/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf2/pbkdf2.h new file mode 100644 index 0000000000..ea357cac0b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pbkdf/pbkdf2/pbkdf2.h @@ -0,0 +1,57 @@ +/* +* PBKDF2 +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PBKDF2_H_ +#define BOTAN_PBKDF2_H_ + +#include <botan/pbkdf.h> +#include <botan/mac.h> + +namespace Botan { + +BOTAN_PUBLIC_API(2,0) size_t pbkdf2(MessageAuthenticationCode& prf, + uint8_t out[], + size_t out_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec); + +/** +* PKCS #5 PBKDF2 +*/ +class BOTAN_PUBLIC_API(2,0) PKCS5_PBKDF2 final : public PBKDF + { + public: + std::string name() const override + { + return "PBKDF2(" + m_mac->name() + ")"; + } + + PBKDF* clone() const override + { + return new PKCS5_PBKDF2(m_mac->clone()); + } + + size_t pbkdf(uint8_t output_buf[], size_t output_len, + const std::string& passphrase, + const uint8_t salt[], size_t salt_len, + size_t iterations, + std::chrono::milliseconds msec) const override; + + /** + * Create a PKCS #5 instance using the specified message auth code + * @param mac_fn the MAC object to use as PRF + */ + explicit PKCS5_PBKDF2(MessageAuthenticationCode* mac_fn) : m_mac(mac_fn) {} + private: + std::unique_ptr<MessageAuthenticationCode> m_mac; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/eme.cpp b/src/libs/3rdparty/botan/src/lib/pk_pad/eme.cpp new file mode 100644 index 0000000000..5164157f76 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/eme.cpp @@ -0,0 +1,94 @@ +/* +* EME Base Class +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/eme.h> +#include <botan/scan_name.h> +#include <botan/exceptn.h> +#include <botan/parsing.h> + +#if defined(BOTAN_HAS_EME_OAEP) +#include <botan/oaep.h> +#endif + +#if defined(BOTAN_HAS_EME_PKCS1v15) +#include <botan/eme_pkcs.h> +#endif + +#if defined(BOTAN_HAS_EME_RAW) +#include <botan/eme_raw.h> +#endif + +namespace Botan { + +EME* get_eme(const std::string& algo_spec) + { +#if defined(BOTAN_HAS_EME_RAW) + if(algo_spec == "Raw") + return new EME_Raw; +#endif + +#if defined(BOTAN_HAS_EME_PKCS1v15) + if(algo_spec == "PKCS1v15" || algo_spec == "EME-PKCS1-v1_5") + return new EME_PKCS1v15; +#endif + +#if defined(BOTAN_HAS_EME_OAEP) + SCAN_Name req(algo_spec); + + if(req.algo_name() == "OAEP" || + req.algo_name() == "EME-OAEP" || + req.algo_name() == "EME1") + { + if(req.arg_count() == 1 || + ((req.arg_count() == 2 || req.arg_count() == 3) && req.arg(1) == "MGF1")) + { + if(auto hash = HashFunction::create(req.arg(0))) + return new OAEP(hash.release(), req.arg(2, "")); + } + else if(req.arg_count() == 2 || req.arg_count() == 3) + { + auto mgf_params = parse_algorithm_name(req.arg(1)); + + if(mgf_params.size() == 2 && mgf_params[0] == "MGF1") + { + auto hash = HashFunction::create(req.arg(0)); + auto mgf1_hash = HashFunction::create(mgf_params[1]); + + if(hash && mgf1_hash) + { + return new OAEP(hash.release(), mgf1_hash.release(), req.arg(2, "")); + } + } + } + } +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +/* +* Encode a message +*/ +secure_vector<uint8_t> EME::encode(const uint8_t msg[], size_t msg_len, + size_t key_bits, + RandomNumberGenerator& rng) const + { + return pad(msg, msg_len, key_bits, rng); + } + +/* +* Encode a message +*/ +secure_vector<uint8_t> EME::encode(const secure_vector<uint8_t>& msg, + size_t key_bits, + RandomNumberGenerator& rng) const + { + return pad(msg.data(), msg.size(), key_bits, rng); + } + + +} diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/eme.h b/src/libs/3rdparty/botan/src/lib/pk_pad/eme.h new file mode 100644 index 0000000000..26523bc881 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/eme.h @@ -0,0 +1,91 @@ +/* +* EME Classes +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PUBKEY_EME_ENCRYPTION_PAD_H_ +#define BOTAN_PUBKEY_EME_ENCRYPTION_PAD_H_ + +#include <botan/secmem.h> + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Encoding Method for Encryption +*/ +class BOTAN_PUBLIC_API(2,0) EME + { + public: + virtual ~EME() = default; + + /** + * Return the maximum input size in bytes we can support + * @param keybits the size of the key in bits + * @return upper bound of input in bytes + */ + virtual size_t maximum_input_size(size_t keybits) const = 0; + + /** + * Encode an input + * @param in the plaintext + * @param in_length length of plaintext in bytes + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + secure_vector<uint8_t> encode(const uint8_t in[], + size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const; + + /** + * Encode an input + * @param in the plaintext + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + secure_vector<uint8_t> encode(const secure_vector<uint8_t>& in, + size_t key_length, + RandomNumberGenerator& rng) const; + + /** + * Decode an input + * @param valid_mask written to specifies if output is valid + * @param in the encoded plaintext + * @param in_len length of encoded plaintext in bytes + * @return bytes of out[] written to along with + * validity mask (0xFF if valid, else 0x00) + */ + virtual secure_vector<uint8_t> unpad(uint8_t& valid_mask, + const uint8_t in[], + size_t in_len) const = 0; + + /** + * Encode an input + * @param in the plaintext + * @param in_length length of plaintext in bytes + * @param key_length length of the key in bits + * @param rng a random number generator + * @return encoded plaintext + */ + virtual secure_vector<uint8_t> pad(const uint8_t in[], + size_t in_length, + size_t key_length, + RandomNumberGenerator& rng) const = 0; + }; + +/** +* Factory method for EME (message-encoding methods for encryption) objects +* @param algo_spec the name of the EME to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_PUBLIC_API(2,0) EME* get_eme(const std::string& algo_spec); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa.cpp b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa.cpp new file mode 100644 index 0000000000..126e1421df --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa.cpp @@ -0,0 +1,183 @@ +/* +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/emsa.h> +#include <botan/hash.h> +#include <botan/scan_name.h> +#include <botan/exceptn.h> + +#if defined(BOTAN_HAS_EMSA1) + #include <botan/emsa1.h> +#endif + +#if defined(BOTAN_HAS_EMSA_X931) + #include <botan/emsa_x931.h> +#endif + +#if defined(BOTAN_HAS_EMSA_PKCS1) + #include <botan/emsa_pkcs1.h> +#endif + +#if defined(BOTAN_HAS_EMSA_PSSR) + #include <botan/pssr.h> +#endif + +#if defined(BOTAN_HAS_EMSA_RAW) + #include <botan/emsa_raw.h> +#endif + +#if defined(BOTAN_HAS_ISO_9796) + #include <botan/iso9796.h> +#endif + +namespace Botan { + +AlgorithmIdentifier EMSA::config_for_x509(const Private_Key&, + const std::string&) const + { + throw Not_Implemented("Encoding " + name() + " not supported for signing X509 objects"); + } + +EMSA* get_emsa(const std::string& algo_spec) + { + SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_EMSA1) + if(req.algo_name() == "EMSA1" && req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + return new EMSA1(hash.release()); + } +#endif + +#if defined(BOTAN_HAS_EMSA_PKCS1) + if(req.algo_name() == "EMSA_PKCS1" || + req.algo_name() == "EMSA-PKCS1-v1_5" || + req.algo_name() == "EMSA3") + { + if(req.arg_count() == 2 && req.arg(0) == "Raw") + { + return new EMSA_PKCS1v15_Raw(req.arg(1)); + } + else if(req.arg_count() == 1) + { + if(req.arg(0) == "Raw") + { + return new EMSA_PKCS1v15_Raw; + } + else + { + if(auto hash = HashFunction::create(req.arg(0))) + { + return new EMSA_PKCS1v15(hash.release()); + } + } + } + } +#endif + +#if defined(BOTAN_HAS_EMSA_PSSR) + if(req.algo_name() == "PSSR" || + req.algo_name() == "EMSA-PSS" || + req.algo_name() == "PSS-MGF1" || + req.algo_name() == "EMSA4" || + req.algo_name() == "PSSR_Raw") + { + if(req.arg_count_between(1, 3)) + { + if(req.arg(1, "MGF1") != "MGF1") + return nullptr; // not supported + + if(auto h = HashFunction::create(req.arg(0))) + { + const size_t salt_size = req.arg_as_integer(2, h->output_length()); + + if(req.algo_name() == "PSSR_Raw") + return new PSSR_Raw(h.release(), salt_size); + else + return new PSSR(h.release(), salt_size); + } + } + } +#endif + +#if defined(BOTAN_HAS_ISO_9796) + if(req.algo_name() == "ISO_9796_DS2") + { + if(req.arg_count_between(1, 3)) + { + if(auto h = HashFunction::create(req.arg(0))) + { + const size_t salt_size = req.arg_as_integer(2, h->output_length()); + const bool implicit = req.arg(1, "exp") == "imp"; + return new ISO_9796_DS2(h.release(), implicit, salt_size); + } + } + } + //ISO-9796-2 DS 3 is deterministic and DS2 without a salt + if(req.algo_name() == "ISO_9796_DS3") + { + if(req.arg_count_between(1, 2)) + { + if(auto h = HashFunction::create(req.arg(0))) + { + const bool implicit = req.arg(1, "exp") == "imp"; + return new ISO_9796_DS3(h.release(), implicit); + } + } + } +#endif + +#if defined(BOTAN_HAS_EMSA_X931) + if(req.algo_name() == "EMSA_X931" || + req.algo_name() == "EMSA2" || + req.algo_name() == "X9.31") + { + if(req.arg_count() == 1) + { + if(auto hash = HashFunction::create(req.arg(0))) + { + return new EMSA_X931(hash.release()); + } + } + } +#endif + +#if defined(BOTAN_HAS_EMSA_RAW) + if(req.algo_name() == "Raw") + { + if(req.arg_count() == 0) + { + return new EMSA_Raw; + } + else + { + auto hash = HashFunction::create(req.arg(0)); + if(hash) + return new EMSA_Raw(hash->output_length()); + } + } +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +std::string hash_for_emsa(const std::string& algo_spec) + { + SCAN_Name emsa_name(algo_spec); + + if(emsa_name.arg_count() > 0) + { + const std::string pos_hash = emsa_name.arg(0); + return pos_hash; + } + + return "SHA-512"; // safe default if nothing we understand + } + +} + + diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa.h b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa.h new file mode 100644 index 0000000000..fe0785294f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa.h @@ -0,0 +1,104 @@ +/* +* EMSA Classes +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PUBKEY_EMSA_H_ +#define BOTAN_PUBKEY_EMSA_H_ + +#include <botan/secmem.h> +#include <botan/alg_id.h> + +namespace Botan { + +class Private_Key; +class RandomNumberGenerator; + +/** +* EMSA, from IEEE 1363s Encoding Method for Signatures, Appendix +* +* Any way of encoding/padding signatures +*/ +class BOTAN_PUBLIC_API(2,0) EMSA + { + public: + virtual ~EMSA() = default; + + /** + * Add more data to the signature computation + * @param input some data + * @param length length of input in bytes + */ + virtual void update(const uint8_t input[], size_t length) = 0; + + /** + * @return raw hash + */ + virtual secure_vector<uint8_t> raw_data() = 0; + + /** + * Return the encoding of a message + * @param msg the result of raw_data() + * @param output_bits the desired output bit size + * @param rng a random number generator + * @return encoded signature + */ + virtual secure_vector<uint8_t> encoding_of(const secure_vector<uint8_t>& msg, + size_t output_bits, + RandomNumberGenerator& rng) = 0; + + /** + * Verify the encoding + * @param coded the received (coded) message representative + * @param raw the computed (local, uncoded) message representative + * @param key_bits the size of the key in bits + * @return true if coded is a valid encoding of raw, otherwise false + */ + virtual bool verify(const secure_vector<uint8_t>& coded, + const secure_vector<uint8_t>& raw, + size_t key_bits) = 0; + + /** + * Prepare sig_algo for use in choose_sig_format for x509 certs + * + * @param key used for checking compatibility with the encoding scheme + * @param cert_hash_name is checked to equal the hash for the encoding + * @return algorithm identifier to signatures created using this key, + * padding method and hash. + */ + virtual AlgorithmIdentifier config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const; + + /** + * @return a new object representing the same encoding method as *this + */ + virtual EMSA* clone() = 0; + + /** + * @return the SCAN name of the encoding/padding scheme + */ + virtual std::string name() const = 0; + }; + +/** +* Factory method for EMSA (message-encoding methods for signatures +* with appendix) objects +* @param algo_spec the name of the EMSA to create +* @return pointer to newly allocated object of that type +*/ +BOTAN_PUBLIC_API(2,0) EMSA* get_emsa(const std::string& algo_spec); + +/** +* Returns the hash function used in the given EMSA scheme +* If the hash function is not specified or not understood, +* returns "SHA-512" +* @param algo_spec the name of the EMSA +* @return hash function used in the given EMSA scheme +*/ +BOTAN_PUBLIC_API(2,0) std::string hash_for_emsa(const std::string& algo_spec); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa1/emsa1.cpp b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa1/emsa1.cpp new file mode 100644 index 0000000000..66d8ec8520 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa1/emsa1.cpp @@ -0,0 +1,133 @@ +/* +* EMSA1 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/emsa1.h> +#include <botan/exceptn.h> +#include <botan/oids.h> +#include <botan/pk_keys.h> +#include <botan/internal/padding.h> + +namespace Botan { + +namespace { + +secure_vector<uint8_t> emsa1_encoding(const secure_vector<uint8_t>& msg, + size_t output_bits) + { + if(8*msg.size() <= output_bits) + return msg; + + size_t shift = 8*msg.size() - output_bits; + + size_t byte_shift = shift / 8, bit_shift = shift % 8; + secure_vector<uint8_t> digest(msg.size() - byte_shift); + + for(size_t j = 0; j != msg.size() - byte_shift; ++j) + digest[j] = msg[j]; + + if(bit_shift) + { + uint8_t carry = 0; + for(size_t j = 0; j != digest.size(); ++j) + { + uint8_t temp = digest[j]; + digest[j] = (temp >> bit_shift) | carry; + carry = (temp << (8 - bit_shift)); + } + } + return digest; + } + +} + +std::string EMSA1::name() const + { + return "EMSA1(" + m_hash->name() + ")"; + } + +EMSA* EMSA1::clone() + { + return new EMSA1(m_hash->clone()); + } + +void EMSA1::update(const uint8_t input[], size_t length) + { + m_hash->update(input, length); + } + +secure_vector<uint8_t> EMSA1::raw_data() + { + return m_hash->final(); + } + +secure_vector<uint8_t> EMSA1::encoding_of(const secure_vector<uint8_t>& msg, + size_t output_bits, + RandomNumberGenerator&) + { + if(msg.size() != hash_output_length()) + throw Encoding_Error("EMSA1::encoding_of: Invalid size for input"); + return emsa1_encoding(msg, output_bits); + } + +bool EMSA1::verify(const secure_vector<uint8_t>& input, + const secure_vector<uint8_t>& raw, + size_t key_bits) + { + if(raw.size() != m_hash->output_length()) + return false; + + // Call emsa1_encoding to handle any required bit shifting + const secure_vector<uint8_t> our_coding = emsa1_encoding(raw, key_bits); + + if(our_coding.size() < input.size()) + return false; + + const size_t offset = our_coding.size() - input.size(); // must be >= 0 per check above + + // If our encoding is longer, all the bytes in it must be zero + for(size_t i = 0; i != offset; ++i) + if(our_coding[i] != 0) + return false; + + return constant_time_compare(input.data(), &our_coding[offset], input.size()); + } + +AlgorithmIdentifier EMSA1::config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const + { + if(cert_hash_name != m_hash->name()) + throw Invalid_Argument("Hash function from opts and hash_fn argument" + " need to be identical"); + // check that the signature algorithm and the padding scheme fit + if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA1")) + { + throw Invalid_Argument("Encoding scheme with canonical name EMSA1" + " not supported for signature algorithm " + key.algo_name()); + } + + AlgorithmIdentifier sig_algo; + sig_algo.oid = OIDS::lookup( key.algo_name() + "/" + name() ); + + std::string algo_name = key.algo_name(); + if(algo_name == "DSA" || + algo_name == "ECDSA" || + algo_name == "ECGDSA" || + algo_name == "ECKCDSA" || + algo_name == "GOST-34.10") + { + // for DSA, ECDSA, GOST parameters "SHALL" be empty + sig_algo.parameters = {}; + } + else + { + sig_algo.parameters = key.algorithm_identifier().parameters; + } + + return sig_algo; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa1/emsa1.h b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa1/emsa1.h new file mode 100644 index 0000000000..7b4d027da5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa1/emsa1.h @@ -0,0 +1,53 @@ +/* +* EMSA1 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_EMSA1_H_ +#define BOTAN_EMSA1_H_ + +#include <botan/emsa.h> +#include <botan/hash.h> + +namespace Botan { + +/** +* EMSA1 from IEEE 1363 +* Essentially, sign the hash directly +*/ +class BOTAN_PUBLIC_API(2,0) EMSA1 final : public EMSA + { + public: + /** + * @param hash the hash function to use + */ + explicit EMSA1(HashFunction* hash) : m_hash(hash) {} + + EMSA* clone() override; + + std::string name() const override; + + AlgorithmIdentifier config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const override; + private: + size_t hash_output_length() const { return m_hash->output_length(); } + + void update(const uint8_t[], size_t) override; + secure_vector<uint8_t> raw_data() override; + + secure_vector<uint8_t> encoding_of(const secure_vector<uint8_t>& msg, + size_t output_bits, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector<uint8_t>& coded, + const secure_vector<uint8_t>& raw, + size_t key_bits) override; + + std::unique_ptr<HashFunction> m_hash; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa1/info.txt b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa1/info.txt new file mode 100644 index 0000000000..5b5bf1f6b0 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa1/info.txt @@ -0,0 +1,3 @@ +<defines> +EMSA1 -> 20131128 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp new file mode 100644 index 0000000000..ddc1e6b279 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.cpp @@ -0,0 +1,170 @@ +/* +* PKCS #1 v1.5 signature padding +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/emsa_pkcs1.h> +#include <botan/hash_id.h> +#include <botan/exceptn.h> +#include <botan/oids.h> +#include <botan/pk_keys.h> +#include <botan/internal/padding.h> + +namespace Botan { + +namespace { + +secure_vector<uint8_t> emsa3_encoding(const secure_vector<uint8_t>& msg, + size_t output_bits, + const uint8_t hash_id[], + size_t hash_id_length) + { + size_t output_length = output_bits / 8; + if(output_length < hash_id_length + msg.size() + 10) + throw Encoding_Error("emsa3_encoding: Output length is too small"); + + secure_vector<uint8_t> T(output_length); + const size_t P_LENGTH = output_length - msg.size() - hash_id_length - 2; + + T[0] = 0x01; + set_mem(&T[1], P_LENGTH, 0xFF); + T[P_LENGTH+1] = 0x00; + + if(hash_id_length > 0) + { + BOTAN_ASSERT_NONNULL(hash_id); + buffer_insert(T, P_LENGTH+2, hash_id, hash_id_length); + } + + buffer_insert(T, output_length-msg.size(), msg.data(), msg.size()); + return T; + } + +} + +void EMSA_PKCS1v15::update(const uint8_t input[], size_t length) + { + m_hash->update(input, length); + } + +secure_vector<uint8_t> EMSA_PKCS1v15::raw_data() + { + return m_hash->final(); + } + +secure_vector<uint8_t> +EMSA_PKCS1v15::encoding_of(const secure_vector<uint8_t>& msg, + size_t output_bits, + RandomNumberGenerator&) + { + if(msg.size() != m_hash->output_length()) + throw Encoding_Error("EMSA_PKCS1v15::encoding_of: Bad input length"); + + return emsa3_encoding(msg, output_bits, + m_hash_id.data(), m_hash_id.size()); + } + +bool EMSA_PKCS1v15::verify(const secure_vector<uint8_t>& coded, + const secure_vector<uint8_t>& raw, + size_t key_bits) + { + if(raw.size() != m_hash->output_length()) + return false; + + try + { + return (coded == emsa3_encoding(raw, key_bits, + m_hash_id.data(), m_hash_id.size())); + } + catch(...) + { + return false; + } + } + +AlgorithmIdentifier EMSA_PKCS1v15::config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const + { + if(cert_hash_name != m_hash->name()) + throw Invalid_Argument("Hash function from opts and hash_fn argument" + " need to be identical"); + // check that the signature algorithm and the padding scheme fit + if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA3")) + { + throw Invalid_Argument("Encoding scheme with canonical name EMSA3" + " not supported for signature algorithm " + key.algo_name()); + } + + + AlgorithmIdentifier sig_algo; + sig_algo.oid = OIDS::lookup( key.algo_name() + "/" + name() ); + // for RSA PKCSv1.5 parameters "SHALL" be NULL as configured by + // RSA_PublicKey::algorithm_identifier() + sig_algo.parameters = key.algorithm_identifier().parameters; + return sig_algo; + } + +EMSA_PKCS1v15::EMSA_PKCS1v15(HashFunction* hash) : m_hash(hash) + { + m_hash_id = pkcs_hash_id(m_hash->name()); + } + +EMSA_PKCS1v15_Raw::EMSA_PKCS1v15_Raw(const std::string& hash_algo) + { + if(!hash_algo.empty()) + { + m_hash_id = pkcs_hash_id(hash_algo); + std::unique_ptr<HashFunction> hash(HashFunction::create_or_throw(hash_algo)); + m_hash_name = hash->name(); + m_hash_output_len = hash->output_length(); + } + else + { + m_hash_output_len = 0; + } + } + +void EMSA_PKCS1v15_Raw::update(const uint8_t input[], size_t length) + { + m_message += std::make_pair(input, length); + } + +secure_vector<uint8_t> EMSA_PKCS1v15_Raw::raw_data() + { + secure_vector<uint8_t> ret; + std::swap(ret, m_message); + + if(m_hash_output_len > 0 && ret.size() != m_hash_output_len) + throw Encoding_Error("EMSA_PKCS1v15_Raw::encoding_of: Bad input length"); + + return ret; + } + +secure_vector<uint8_t> +EMSA_PKCS1v15_Raw::encoding_of(const secure_vector<uint8_t>& msg, + size_t output_bits, + RandomNumberGenerator&) + { + return emsa3_encoding(msg, output_bits, m_hash_id.data(), m_hash_id.size()); + } + +bool EMSA_PKCS1v15_Raw::verify(const secure_vector<uint8_t>& coded, + const secure_vector<uint8_t>& raw, + size_t key_bits) + { + if(m_hash_output_len > 0 && raw.size() != m_hash_output_len) + return false; + + try + { + return (coded == emsa3_encoding(raw, key_bits, m_hash_id.data(), m_hash_id.size())); + } + catch(...) + { + return false; + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h new file mode 100644 index 0000000000..31032320e6 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h @@ -0,0 +1,92 @@ +/* +* PKCS #1 v1.5 signature padding +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_EMSA_PKCS1_H_ +#define BOTAN_EMSA_PKCS1_H_ + +#include <botan/emsa.h> +#include <botan/hash.h> + +namespace Botan { + +/** +* PKCS #1 v1.5 signature padding +* aka PKCS #1 block type 1 +* aka EMSA3 from IEEE 1363 +*/ +class BOTAN_PUBLIC_API(2,0) EMSA_PKCS1v15 final : public EMSA + { + public: + /** + * @param hash the hash function to use + */ + explicit EMSA_PKCS1v15(HashFunction* hash); + + EMSA* clone() override { return new EMSA_PKCS1v15(m_hash->clone()); } + + void update(const uint8_t[], size_t) override; + + secure_vector<uint8_t> raw_data() override; + + secure_vector<uint8_t> encoding_of(const secure_vector<uint8_t>&, size_t, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector<uint8_t>&, const secure_vector<uint8_t>&, + size_t) override; + + std::string name() const override + { return "EMSA3(" + m_hash->name() + ")"; } + + AlgorithmIdentifier config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const override; + private: + std::unique_ptr<HashFunction> m_hash; + std::vector<uint8_t> m_hash_id; + }; + +/** +* EMSA_PKCS1v15_Raw which is EMSA_PKCS1v15 without a hash or digest id +* (which according to QCA docs is "identical to PKCS#11's CKM_RSA_PKCS +* mechanism", something I have not confirmed) +*/ +class BOTAN_PUBLIC_API(2,0) EMSA_PKCS1v15_Raw final : public EMSA + { + public: + EMSA* clone() override { return new EMSA_PKCS1v15_Raw(); } + + void update(const uint8_t[], size_t) override; + + secure_vector<uint8_t> raw_data() override; + + secure_vector<uint8_t> encoding_of(const secure_vector<uint8_t>&, size_t, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector<uint8_t>&, const secure_vector<uint8_t>&, + size_t) override; + + /** + * @param hash_algo if non-empty, the digest id for that hash is + * included in the signature. + */ + EMSA_PKCS1v15_Raw(const std::string& hash_algo = ""); + + std::string name() const override + { + if(m_hash_name.empty()) return "EMSA3(Raw)"; + else return "EMSA3(Raw," + m_hash_name + ")"; + } + + private: + size_t m_hash_output_len = 0; + std::string m_hash_name; + std::vector<uint8_t> m_hash_id; + secure_vector<uint8_t> m_message; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pkcs1/info.txt b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pkcs1/info.txt new file mode 100644 index 0000000000..b70f4e2445 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pkcs1/info.txt @@ -0,0 +1,7 @@ +<defines> +EMSA_PKCS1 -> 20140118 +</defines> + +<requires> +hash_id +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pssr/info.txt b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pssr/info.txt new file mode 100644 index 0000000000..f514936c37 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pssr/info.txt @@ -0,0 +1,7 @@ +<defines> +EMSA_PSSR -> 20131128 +</defines> + +<requires> +mgf1 +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pssr/pssr.cpp b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pssr/pssr.cpp new file mode 100644 index 0000000000..97b229be35 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pssr/pssr.cpp @@ -0,0 +1,258 @@ +/* +* PSSR +* (C) 1999-2007,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pssr.h> +#include <botan/exceptn.h> +#include <botan/rng.h> +#include <botan/mgf1.h> +#include <botan/internal/bit_ops.h> +#include <botan/oids.h> +#include <botan/der_enc.h> +#include <botan/pk_keys.h> +#include <botan/internal/padding.h> + +namespace Botan { + +namespace { + +/* +* PSSR Encode Operation +*/ +secure_vector<uint8_t> pss_encode(HashFunction& hash, + const secure_vector<uint8_t>& msg, + const secure_vector<uint8_t>& salt, + size_t output_bits) + { + const size_t HASH_SIZE = hash.output_length(); + const size_t SALT_SIZE = salt.size(); + + if(msg.size() != HASH_SIZE) + throw Encoding_Error("Cannot encode PSS string, input length invalid for hash"); + if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9) + throw Encoding_Error("Cannot encode PSS string, output length too small"); + + const size_t output_length = (output_bits + 7) / 8; + + for(size_t i = 0; i != 8; ++i) + hash.update(0); + hash.update(msg); + hash.update(salt); + secure_vector<uint8_t> H = hash.final(); + + secure_vector<uint8_t> EM(output_length); + + EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01; + buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt); + mgf1_mask(hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - 1); + EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits); + buffer_insert(EM, output_length - 1 - HASH_SIZE, H); + EM[output_length-1] = 0xBC; + return EM; + } + +bool pss_verify(HashFunction& hash, + const secure_vector<uint8_t>& const_coded, + const secure_vector<uint8_t>& raw, + size_t key_bits) + { + const size_t HASH_SIZE = hash.output_length(); + const size_t KEY_BYTES = (key_bits + 7) / 8; + + if(key_bits < 8*HASH_SIZE + 9) + return false; + + if(raw.size() != HASH_SIZE) + return false; + + if(const_coded.size() > KEY_BYTES || const_coded.size() <= 1) + return false; + + if(const_coded[const_coded.size()-1] != 0xBC) + return false; + + secure_vector<uint8_t> coded = const_coded; + if(coded.size() < KEY_BYTES) + { + secure_vector<uint8_t> temp(KEY_BYTES); + buffer_insert(temp, KEY_BYTES - coded.size(), coded); + coded = temp; + } + + const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits; + if(TOP_BITS > 8 - high_bit(coded[0])) + return false; + + uint8_t* DB = coded.data(); + const size_t DB_size = coded.size() - HASH_SIZE - 1; + + const uint8_t* H = &coded[DB_size]; + const size_t H_size = HASH_SIZE; + + mgf1_mask(hash, H, H_size, DB, DB_size); + DB[0] &= 0xFF >> TOP_BITS; + + size_t salt_offset = 0; + for(size_t j = 0; j != DB_size; ++j) + { + if(DB[j] == 0x01) + { salt_offset = j + 1; break; } + if(DB[j]) + return false; + } + if(salt_offset == 0) + return false; + + const size_t salt_size = DB_size - salt_offset; + + for(size_t j = 0; j != 8; ++j) + hash.update(0); + hash.update(raw); + hash.update(&DB[salt_offset], salt_size); + + secure_vector<uint8_t> H2 = hash.final(); + + return constant_time_compare(H, H2.data(), HASH_SIZE); + } + +} + +PSSR::PSSR(HashFunction* h) : + m_hash(h), m_SALT_SIZE(m_hash->output_length()) + { + } + +PSSR::PSSR(HashFunction* h, size_t salt_size) : + m_hash(h), m_SALT_SIZE(salt_size) + { + } + +/* +* PSSR Update Operation +*/ +void PSSR::update(const uint8_t input[], size_t length) + { + m_hash->update(input, length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector<uint8_t> PSSR::raw_data() + { + return m_hash->final(); + } + +secure_vector<uint8_t> PSSR::encoding_of(const secure_vector<uint8_t>& msg, + size_t output_bits, + RandomNumberGenerator& rng) + { + secure_vector<uint8_t> salt = rng.random_vec(m_SALT_SIZE); + return pss_encode(*m_hash, msg, salt, output_bits); + } + +/* +* PSSR Decode/Verify Operation +*/ +bool PSSR::verify(const secure_vector<uint8_t>& coded, + const secure_vector<uint8_t>& raw, + size_t key_bits) + { + return pss_verify(*m_hash, coded, raw, key_bits); + } + +std::string PSSR::name() const + { + return "EMSA4(" + m_hash->name() + ",MGF1," + std::to_string(m_SALT_SIZE) + ")"; + } + +AlgorithmIdentifier PSSR::config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const + { + if(cert_hash_name != m_hash->name()) + throw Invalid_Argument("Hash function from opts and hash_fn argument" + " need to be identical"); + // check that the signature algorithm and the padding scheme fit + if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA4")) + { + throw Invalid_Argument("Encoding scheme with canonical name EMSA4" + " not supported for signature algorithm " + key.algo_name()); + } + + AlgorithmIdentifier sig_algo; + // hardcoded as RSA is the only valid algorithm for EMSA4 at the moment + sig_algo.oid = OIDS::lookup( "RSA/EMSA4" ); + + const AlgorithmIdentifier hash_id(cert_hash_name, AlgorithmIdentifier::USE_NULL_PARAM); + const AlgorithmIdentifier mgf_id("MGF1", hash_id.BER_encode()); + + DER_Encoder(sig_algo.parameters) + .start_cons(SEQUENCE) + .start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).encode(hash_id).end_cons() + .start_cons(ASN1_Tag(1), CONTEXT_SPECIFIC).encode(mgf_id).end_cons() + .start_cons(ASN1_Tag(2), CONTEXT_SPECIFIC).encode(m_SALT_SIZE).end_cons() + .start_cons(ASN1_Tag(3), CONTEXT_SPECIFIC).encode(size_t(1)).end_cons() // trailer field + .end_cons(); + + return sig_algo; + } + +PSSR_Raw::PSSR_Raw(HashFunction* h) : + m_hash(h), m_SALT_SIZE(m_hash->output_length()) + { + } + +PSSR_Raw::PSSR_Raw(HashFunction* h, size_t salt_size) : + m_hash(h), m_SALT_SIZE(salt_size) + { + } + +/* +* PSSR_Raw Update Operation +*/ +void PSSR_Raw::update(const uint8_t input[], size_t length) + { + m_msg.insert(m_msg.end(), input, input + length); + } + +/* +* Return the raw (unencoded) data +*/ +secure_vector<uint8_t> PSSR_Raw::raw_data() + { + secure_vector<uint8_t> ret; + std::swap(ret, m_msg); + + if(ret.size() != m_hash->output_length()) + throw Encoding_Error("PSSR_Raw Bad input length, did not match hash"); + + return ret; + } + +secure_vector<uint8_t> PSSR_Raw::encoding_of(const secure_vector<uint8_t>& msg, + size_t output_bits, + RandomNumberGenerator& rng) + { + secure_vector<uint8_t> salt = rng.random_vec(m_SALT_SIZE); + return pss_encode(*m_hash, msg, salt, output_bits); + } + +/* +* PSSR_Raw Decode/Verify Operation +*/ +bool PSSR_Raw::verify(const secure_vector<uint8_t>& coded, + const secure_vector<uint8_t>& raw, + size_t key_bits) + { + return pss_verify(*m_hash, coded, raw, key_bits); + } + +std::string PSSR_Raw::name() const + { + return "PSSR_Raw(" + m_hash->name() + ",MGF1," + std::to_string(m_SALT_SIZE) + ")"; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pssr/pssr.h b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pssr/pssr.h new file mode 100644 index 0000000000..3b902dd6a8 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/emsa_pssr/pssr.h @@ -0,0 +1,99 @@ +/* +* PSSR +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PSSR_H_ +#define BOTAN_PSSR_H_ + +#include <botan/emsa.h> +#include <botan/hash.h> + +namespace Botan { + +/** +* PSSR (called EMSA4 in IEEE 1363 and in old versions of the library) +*/ +class BOTAN_PUBLIC_API(2,0) PSSR final : public EMSA + { + public: + + /** + * @param hash the hash function to use + */ + explicit PSSR(HashFunction* hash); + + /** + * @param hash the hash function to use + * @param salt_size the size of the salt to use in bytes + */ + PSSR(HashFunction* hash, size_t salt_size); + + EMSA* clone() override { return new PSSR(m_hash->clone(), m_SALT_SIZE); } + + std::string name() const override; + + AlgorithmIdentifier config_for_x509(const Private_Key& key, + const std::string& cert_hash_name) const override; + private: + void update(const uint8_t input[], size_t length) override; + + secure_vector<uint8_t> raw_data() override; + + secure_vector<uint8_t> encoding_of(const secure_vector<uint8_t>& msg, + size_t output_bits, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector<uint8_t>& coded, + const secure_vector<uint8_t>& raw, + size_t key_bits) override; + + std::unique_ptr<HashFunction> m_hash; + size_t m_SALT_SIZE; + }; + +/** +* PSSR_Raw +* This accepts a pre-hashed buffer +*/ +class BOTAN_PUBLIC_API(2,3) PSSR_Raw final : public EMSA + { + public: + + /** + * @param hash the hash function to use + */ + explicit PSSR_Raw(HashFunction* hash); + + /** + * @param hash the hash function to use + * @param salt_size the size of the salt to use in bytes + */ + PSSR_Raw(HashFunction* hash, size_t salt_size); + + EMSA* clone() override { return new PSSR_Raw(m_hash->clone(), m_SALT_SIZE); } + + std::string name() const override; + private: + void update(const uint8_t input[], size_t length) override; + + secure_vector<uint8_t> raw_data() override; + + secure_vector<uint8_t> encoding_of(const secure_vector<uint8_t>& msg, + size_t output_bits, + RandomNumberGenerator& rng) override; + + bool verify(const secure_vector<uint8_t>& coded, + const secure_vector<uint8_t>& raw, + size_t key_bits) override; + + std::unique_ptr<HashFunction> m_hash; + size_t m_SALT_SIZE; + secure_vector<uint8_t> m_msg; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/hash_id/hash_id.cpp b/src/libs/3rdparty/botan/src/lib/pk_pad/hash_id/hash_id.cpp new file mode 100644 index 0000000000..ec317f9692 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/hash_id/hash_id.cpp @@ -0,0 +1,163 @@ +/* +* Hash Function Identification +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/hash_id.h> +#include <botan/exceptn.h> + +namespace Botan { + +namespace { + +const uint8_t MD5_PKCS_ID[] = { +0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, +0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; + +const uint8_t RIPEMD_160_PKCS_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, +0x01, 0x05, 0x00, 0x04, 0x14 }; + +const uint8_t SHA_160_PKCS_ID[] = { +0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, +0x1A, 0x05, 0x00, 0x04, 0x14 }; + +const uint8_t SHA_224_PKCS_ID[] = { +0x30, 0x2D, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C }; + +const uint8_t SHA_256_PKCS_ID[] = { +0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; + +const uint8_t SHA_384_PKCS_ID[] = { +0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30 }; + +const uint8_t SHA_512_PKCS_ID[] = { +0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 }; + +const uint8_t SHA_512_256_PKCS_ID[] = { +0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, +0x65, 0x03, 0x04, 0x02, 0x06, 0x05, 0x00, 0x04, 0x20 }; + +const uint8_t SHA3_224_PKCS_ID[] = { +0x30, 0x2D, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, +0x03, 0x04, 0x02, 0x07, 0x05, 0x00, 0x04, 0x1C }; + +const uint8_t SHA3_256_PKCS_ID[] = { +0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, +0x03, 0x04, 0x02, 0x08, 0x05, 0x00, 0x04, 0x20 }; + +const uint8_t SHA3_384_PKCS_ID[] = { +0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, +0x03, 0x04, 0x02, 0x09, 0x05, 0x00, 0x04, 0x30 }; + +const uint8_t SHA3_512_PKCS_ID[] = { +0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, +0x03, 0x04, 0x02, 0x0A, 0x05, 0x00, 0x04, 0x40 }; + +const uint8_t SM3_PKCS_ID[] = { +0x30, 0x30, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x81, 0x1C, 0xCF, +0x55, 0x01, 0x83, 0x11, 0x05, 0x00, 0x04, 0x20, +}; + +const uint8_t TIGER_PKCS_ID[] = { +0x30, 0x29, 0x30, 0x0D, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, +0x01, 0xDA, 0x47, 0x0C, 0x02, 0x05, 0x00, 0x04, 0x18 }; + +} + +/* +* HashID as specified by PKCS +*/ +std::vector<uint8_t> pkcs_hash_id(const std::string& name) + { + // Special case for SSL/TLS RSA signatures + if(name == "Parallel(MD5,SHA-160)") + return std::vector<uint8_t>(); + + // If you add a value to this function, also update test_hash_id.cpp + + if(name == "MD5") + return std::vector<uint8_t>(MD5_PKCS_ID, + MD5_PKCS_ID + sizeof(MD5_PKCS_ID)); + + if(name == "RIPEMD-160") + return std::vector<uint8_t>(RIPEMD_160_PKCS_ID, + RIPEMD_160_PKCS_ID + sizeof(RIPEMD_160_PKCS_ID)); + + if(name == "SHA-160" || name == "SHA-1" || name == "SHA1") + return std::vector<uint8_t>(SHA_160_PKCS_ID, + SHA_160_PKCS_ID + sizeof(SHA_160_PKCS_ID)); + + if(name == "SHA-224") + return std::vector<uint8_t>(SHA_224_PKCS_ID, + SHA_224_PKCS_ID + sizeof(SHA_224_PKCS_ID)); + + if(name == "SHA-256") + return std::vector<uint8_t>(SHA_256_PKCS_ID, + SHA_256_PKCS_ID + sizeof(SHA_256_PKCS_ID)); + + if(name == "SHA-384") + return std::vector<uint8_t>(SHA_384_PKCS_ID, + SHA_384_PKCS_ID + sizeof(SHA_384_PKCS_ID)); + + if(name == "SHA-512") + return std::vector<uint8_t>(SHA_512_PKCS_ID, + SHA_512_PKCS_ID + sizeof(SHA_512_PKCS_ID)); + + if(name == "SHA-512-256") + return std::vector<uint8_t>(SHA_512_256_PKCS_ID, + SHA_512_256_PKCS_ID + sizeof(SHA_512_256_PKCS_ID)); + + if(name == "SHA-3(224)") + return std::vector<uint8_t>(SHA3_224_PKCS_ID, + SHA3_224_PKCS_ID + sizeof(SHA3_224_PKCS_ID)); + + if(name == "SHA-3(256)") + return std::vector<uint8_t>(SHA3_256_PKCS_ID, + SHA3_256_PKCS_ID + sizeof(SHA3_256_PKCS_ID)); + + if(name == "SHA-3(384)") + return std::vector<uint8_t>(SHA3_384_PKCS_ID, + SHA3_384_PKCS_ID + sizeof(SHA3_384_PKCS_ID)); + + if(name == "SHA-3(512)") + return std::vector<uint8_t>(SHA3_512_PKCS_ID, + SHA3_512_PKCS_ID + sizeof(SHA3_512_PKCS_ID)); + + if(name == "SM3") + return std::vector<uint8_t>(SM3_PKCS_ID, SM3_PKCS_ID + sizeof(SM3_PKCS_ID)); + + if(name == "Tiger(24,3)") + return std::vector<uint8_t>(TIGER_PKCS_ID, + TIGER_PKCS_ID + sizeof(TIGER_PKCS_ID)); + + throw Invalid_Argument("No PKCS #1 identifier for " + name); + } + +/* +* HashID as specified by IEEE 1363/X9.31 +*/ +uint8_t ieee1363_hash_id(const std::string& name) + { + if(name == "SHA-160" || name == "SHA-1" || name == "SHA1") + return 0x33; + + if(name == "SHA-224") return 0x38; + if(name == "SHA-256") return 0x34; + if(name == "SHA-384") return 0x36; + if(name == "SHA-512") return 0x35; + + if(name == "RIPEMD-160") return 0x31; + + if(name == "Whirlpool") return 0x37; + + return 0; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/hash_id/hash_id.h b/src/libs/3rdparty/botan/src/lib/pk_pad/hash_id/hash_id.h new file mode 100644 index 0000000000..75c86c0c65 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/hash_id/hash_id.h @@ -0,0 +1,34 @@ +/* +* Hash Function Identification +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HASHID_H_ +#define BOTAN_HASHID_H_ + +#include <botan/secmem.h> +#include <string> + +namespace Botan { + +/** +* Return the PKCS #1 hash identifier +* @see RFC 3447 section 9.2 +* @param hash_name the name of the hash function +* @return uint8_t sequence identifying the hash +* @throw Invalid_Argument if the hash has no known PKCS #1 hash id +*/ +BOTAN_PUBLIC_API(2,0) std::vector<uint8_t> pkcs_hash_id(const std::string& hash_name); + +/** +* Return the IEEE 1363 hash identifier +* @param hash_name the name of the hash function +* @return uint8_t code identifying the hash, or 0 if not known +*/ +BOTAN_PUBLIC_API(2,0) uint8_t ieee1363_hash_id(const std::string& hash_name); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/hash_id/info.txt b/src/libs/3rdparty/botan/src/lib/pk_pad/hash_id/info.txt new file mode 100644 index 0000000000..8cd930a9fe --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/hash_id/info.txt @@ -0,0 +1,3 @@ +<defines> +HASH_ID -> 20131128 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/info.txt b/src/libs/3rdparty/botan/src/lib/pk_pad/info.txt new file mode 100644 index 0000000000..afadf56554 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/info.txt @@ -0,0 +1,20 @@ +<defines> +PK_PADDING -> 20131128 +</defines> + +load_on auto + +<requires> +asn1 +rng +pubkey +</requires> + +<header:internal> +padding.h +</header:internal> + +<header:public> +eme.h +emsa.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/mgf1/info.txt b/src/libs/3rdparty/botan/src/lib/pk_pad/mgf1/info.txt new file mode 100644 index 0000000000..f17c72fda4 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/mgf1/info.txt @@ -0,0 +1,3 @@ +<defines> +MGF1 -> 20140118 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/mgf1/mgf1.cpp b/src/libs/3rdparty/botan/src/lib/pk_pad/mgf1/mgf1.cpp new file mode 100644 index 0000000000..dbfac5110d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/mgf1/mgf1.cpp @@ -0,0 +1,35 @@ +/* +* MGF1 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/mgf1.h> +#include <botan/hash.h> +#include <algorithm> + +namespace Botan { + +void mgf1_mask(HashFunction& hash, + const uint8_t in[], size_t in_len, + uint8_t out[], size_t out_len) + { + uint32_t counter = 0; + + while(out_len) + { + hash.update(in, in_len); + hash.update_be(counter); + secure_vector<uint8_t> buffer = hash.final(); + + size_t xored = std::min<size_t>(buffer.size(), out_len); + xor_buf(out, buffer.data(), xored); + out += xored; + out_len -= xored; + + ++counter; + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/mgf1/mgf1.h b/src/libs/3rdparty/botan/src/lib/pk_pad/mgf1/mgf1.h new file mode 100644 index 0000000000..9eb652a825 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/mgf1/mgf1.h @@ -0,0 +1,31 @@ +/* +* MGF1 +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MGF1_H_ +#define BOTAN_MGF1_H_ + +#include <botan/types.h> + +namespace Botan { + +class HashFunction; + +/** +* MGF1 from PKCS #1 v2.0 +* @param hash hash function to use +* @param in input buffer +* @param in_len size of the input buffer in bytes +* @param out output buffer +* @param out_len size of the output buffer in bytes +*/ +void BOTAN_PUBLIC_API(2,0) mgf1_mask(HashFunction& hash, + const uint8_t in[], size_t in_len, + uint8_t out[], size_t out_len); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/padding.cpp b/src/libs/3rdparty/botan/src/lib/pk_pad/padding.cpp new file mode 100644 index 0000000000..134bb41017 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/padding.cpp @@ -0,0 +1,42 @@ +/* +* Sets of allowed padding schemes for public key types +* +* This file was automatically generated by ./src/scripts/oids.py on 2017-12-20 +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/padding.h> +#include <map> +#include <vector> +#include <string> +#include <algorithm> + +namespace Botan { + +const std::map<const std::string, std::vector<std::string>> allowed_signature_paddings = + { + { "DSA", {"EMSA1"} }, + { "ECDSA", {"EMSA1"} }, + { "ECGDSA", {"EMSA1"} }, + { "ECKCDSA", {"EMSA1"} }, + { "GOST-34.10", {"EMSA1"} }, + { "RSA", {"EMSA4", "EMSA3"} }, + }; + +const std::vector<std::string> get_sig_paddings(const std::string algo) + { + if(allowed_signature_paddings.count(algo) > 0) + return allowed_signature_paddings.at(algo); + return {}; + } + +bool sig_algo_and_pad_ok(const std::string algo, const std::string padding) + { + std::vector<std::string> pads = get_sig_paddings(algo); + return std::find(pads.begin(), pads.end(), padding) != pads.end(); + } +} diff --git a/src/libs/3rdparty/botan/src/lib/pk_pad/padding.h b/src/libs/3rdparty/botan/src/lib/pk_pad/padding.h new file mode 100644 index 0000000000..ed05ec3819 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pk_pad/padding.h @@ -0,0 +1,36 @@ +/* +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PADDING_H_ +#define BOTAN_PADDING_H_ + +#include <botan/build.h> +#include <string> +#include <vector> + +namespace Botan { + +/** +* Returns the allowed padding schemes when using the given +* algorithm (key type) for creating digital signatures. +* +* @param algo the algorithm for which to look up supported padding schemes +* @return a vector of supported padding schemes +*/ +BOTAN_TEST_API const std::vector<std::string> get_sig_paddings(const std::string algo); + +/** +* Returns true iff the given padding scheme is valid for the given +* signature algorithm (key type). +* +* @param algo the signature algorithm to be used +* @param padding the padding scheme to be used +*/ +bool sig_algo_and_pad_ok(const std::string algo, const std::string padding); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/blinding.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/blinding.cpp new file mode 100644 index 0000000000..ecd420780c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/blinding.cpp @@ -0,0 +1,66 @@ +/* +* Blinding for public key operations +* (C) 1999-2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/blinding.h> + +namespace Botan { + +Blinder::Blinder(const BigInt& modulus, + RandomNumberGenerator& rng, + std::function<BigInt (const BigInt&)> fwd, + std::function<BigInt (const BigInt&)> inv) : + m_reducer(modulus), + m_rng(rng), + m_fwd_fn(fwd), + m_inv_fn(inv), + m_modulus_bits(modulus.bits()), + m_e{}, + m_d{}, + m_counter{} + { + const BigInt k = blinding_nonce(); + m_e = m_fwd_fn(k); + m_d = m_inv_fn(k); + } + +BigInt Blinder::blinding_nonce() const + { + return BigInt(m_rng, m_modulus_bits - 1); + } + +BigInt Blinder::blind(const BigInt& i) const + { + if(!m_reducer.initialized()) + throw Exception("Blinder not initialized, cannot blind"); + + ++m_counter; + + if((BOTAN_BLINDING_REINIT_INTERVAL > 0) && (m_counter > BOTAN_BLINDING_REINIT_INTERVAL)) + { + const BigInt k = blinding_nonce(); + m_e = m_fwd_fn(k); + m_d = m_inv_fn(k); + m_counter = 0; + } + else + { + m_e = m_reducer.square(m_e); + m_d = m_reducer.square(m_d); + } + + return m_reducer.multiply(i, m_e); + } + +BigInt Blinder::unblind(const BigInt& i) const + { + if(!m_reducer.initialized()) + throw Exception("Blinder not initialized, cannot unblind"); + + return m_reducer.multiply(i, m_d); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/blinding.h b/src/libs/3rdparty/botan/src/lib/pubkey/blinding.h new file mode 100644 index 0000000000..1bdd235f0f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/blinding.h @@ -0,0 +1,78 @@ +/* +* Blinding for public key operations +* (C) 1999-2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BLINDER_H_ +#define BOTAN_BLINDER_H_ + +#include <botan/bigint.h> +#include <botan/reducer.h> +#include <functional> + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Blinding Function Object. +*/ +class BOTAN_PUBLIC_API(2,0) Blinder final + { + public: + /** + * Blind a value. + * The blinding nonce k is freshly generated after + * BOTAN_BLINDING_REINIT_INTERVAL calls to blind(). + * BOTAN_BLINDING_REINIT_INTERVAL = 0 means a fresh + * nonce is only generated once. On every other call, + * an updated nonce is used for blinding: k' = k*k mod n. + * @param x value to blind + * @return blinded value + */ + BigInt blind(const BigInt& x) const; + + /** + * Unblind a value. + * @param x value to unblind + * @return unblinded value + */ + BigInt unblind(const BigInt& x) const; + + /** + * @param modulus the modulus + * @param rng the RNG to use for generating the nonce + * @param fwd_func a function that calculates the modular + * exponentiation of the public exponent and the given value (the nonce) + * @param inv_func a function that calculates the modular inverse + * of the given value (the nonce) + */ + Blinder(const BigInt& modulus, + RandomNumberGenerator& rng, + std::function<BigInt (const BigInt&)> fwd_func, + std::function<BigInt (const BigInt&)> inv_func); + + Blinder(const Blinder&) = delete; + + Blinder& operator=(const Blinder&) = delete; + + RandomNumberGenerator& rng() const { return m_rng; } + + private: + BigInt blinding_nonce() const; + + Modular_Reducer m_reducer; + RandomNumberGenerator& m_rng; + std::function<BigInt (const BigInt&)> m_fwd_fn; + std::function<BigInt (const BigInt&)> m_inv_fn; + size_t m_modulus_bits = 0; + + mutable BigInt m_e, m_d; + mutable size_t m_counter = 0; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dh/dh.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/dh/dh.cpp new file mode 100644 index 0000000000..ae6e9c589b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dh/dh.cpp @@ -0,0 +1,130 @@ +/* +* Diffie-Hellman +* (C) 1999-2007,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/dh.h> +#include <botan/internal/pk_ops_impl.h> +#include <botan/pow_mod.h> +#include <botan/blinding.h> + +namespace Botan { + +/* +* DH_PublicKey Constructor +*/ +DH_PublicKey::DH_PublicKey(const DL_Group& grp, const BigInt& y1) + { + m_group = grp; + m_y = y1; + } + +/* +* Return the public value for key agreement +*/ +std::vector<uint8_t> DH_PublicKey::public_value() const + { + return unlock(BigInt::encode_1363(m_y, group_p().bytes())); + } + +/* +* Create a DH private key +*/ +DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + m_group = grp; + + if(x_arg == 0) + { + const size_t exp_bits = grp.exponent_bits(); + m_x.randomize(rng, exp_bits); + m_y = m_group.power_g_p(m_x, exp_bits); + } + else + { + m_x = x_arg; + + if(m_y == 0) + m_y = m_group.power_g_p(m_x, grp.p_bits()); + } + } + +/* +* Load a DH private key +*/ +DH_PrivateKey::DH_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42) + { + if(m_y.is_zero()) + { + m_y = m_group.power_g_p(m_x, m_group.p_bits()); + } + } + +/* +* Return the public value for key agreement +*/ +std::vector<uint8_t> DH_PrivateKey::public_value() const + { + return DH_PublicKey::public_value(); + } + +namespace { + +/** +* DH operation +*/ +class DH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF + { + public: + + DH_KA_Operation(const DH_PrivateKey& key, const std::string& kdf, RandomNumberGenerator& rng) : + PK_Ops::Key_Agreement_with_KDF(kdf), + m_p(key.group_p()), + m_powermod_x_p(key.get_x(), m_p), + m_blinder(m_p, + rng, + [](const BigInt& k) { return k; }, + [this](const BigInt& k) { return m_powermod_x_p(inverse_mod(k, m_p)); }) + {} + + secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override; + private: + const BigInt& m_p; + + Fixed_Exponent_Power_Mod m_powermod_x_p; + Blinder m_blinder; + }; + +secure_vector<uint8_t> DH_KA_Operation::raw_agree(const uint8_t w[], size_t w_len) + { + BigInt v = BigInt::decode(w, w_len); + + if(v <= 1 || v >= m_p - 1) + throw Invalid_Argument("DH agreement - invalid key provided"); + + v = m_blinder.blind(v); + v = m_powermod_x_p(v); + v = m_blinder.unblind(v); + + return BigInt::encode_1363(v, m_p.bytes()); + } + +} + +std::unique_ptr<PK_Ops::Key_Agreement> +DH_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Key_Agreement>(new DH_KA_Operation(*this, params, rng)); + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dh/dh.h b/src/libs/3rdparty/botan/src/lib/pubkey/dh/dh.h new file mode 100644 index 0000000000..e3aa0d2c5b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dh/dh.h @@ -0,0 +1,81 @@ +/* +* Diffie-Hellman +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DIFFIE_HELLMAN_H_ +#define BOTAN_DIFFIE_HELLMAN_H_ + +#include <botan/dl_algo.h> + +namespace Botan { + +/** +* This class represents Diffie-Hellman public keys. +*/ +class BOTAN_PUBLIC_API(2,0) DH_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const override { return "DH"; } + + std::vector<uint8_t> public_value() const; + + DL_Group::Format group_format() const override { return DL_Group::ANSI_X9_42; } + + /** + * Create a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + DH_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_42) {} + + /** + * Construct a public key with the specified parameters. + * @param grp the DL group to use in the key + * @param y the public value y + */ + DH_PublicKey(const DL_Group& grp, const BigInt& y); + protected: + DH_PublicKey() = default; + }; + +/** +* This class represents Diffie-Hellman private keys. +*/ +class BOTAN_PUBLIC_API(2,0) DH_PrivateKey final : public DH_PublicKey, + public PK_Key_Agreement_Key, + public virtual DL_Scheme_PrivateKey + { + public: + std::vector<uint8_t> public_value() const override; + + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits PKCS #8 structure + */ + DH_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits); + + /** + * Create a private key. + * @param rng random number generator to use + * @param grp the group to be used in the key + * @param x the key's secret value (or if zero, generate a new key) + */ + DH_PrivateKey(RandomNumberGenerator& rng, const DL_Group& grp, + const BigInt& x = 0); + + std::unique_ptr<PK_Ops::Key_Agreement> + create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dh/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/dh/info.txt new file mode 100644 index 0000000000..1b9ba24948 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dh/info.txt @@ -0,0 +1,13 @@ +<defines> +DIFFIE_HELLMAN -> 20131128 +</defines> + +<header:public> +dh.h +</header:public> + +<requires> +dl_algo +dl_group +numbertheory +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dl_algo/dl_algo.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/dl_algo/dl_algo.cpp new file mode 100644 index 0000000000..15b0b175e4 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dl_algo/dl_algo.cpp @@ -0,0 +1,84 @@ +/* +* DL Scheme +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/dl_algo.h> +#include <botan/numthry.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> + +namespace Botan { + +size_t DL_Scheme_PublicKey::key_length() const + { + return m_group.p_bits(); + } + +size_t DL_Scheme_PublicKey::estimated_strength() const + { + return m_group.estimated_strength(); + } + +AlgorithmIdentifier DL_Scheme_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), + m_group.DER_encode(group_format())); + } + +std::vector<uint8_t> DL_Scheme_PublicKey::public_key_bits() const + { + std::vector<uint8_t> output; + DER_Encoder(output).encode(m_y); + return output; + } + +DL_Scheme_PublicKey::DL_Scheme_PublicKey(const DL_Group& group, const BigInt& y) : + m_y(y), + m_group(group) + { + } + +DL_Scheme_PublicKey::DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits, + DL_Group::Format format) : + m_group(alg_id.get_parameters(), format) + { + BER_Decoder(key_bits).decode(m_y); + } + +secure_vector<uint8_t> DL_Scheme_PrivateKey::private_key_bits() const + { + return DER_Encoder().encode(m_x).get_contents(); + } + +DL_Scheme_PrivateKey::DL_Scheme_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits, + DL_Group::Format format) + { + m_group.BER_decode(alg_id.get_parameters(), format); + + BER_Decoder(key_bits).decode(m_x); + } + +/* +* Check Public DL Parameters +*/ +bool DL_Scheme_PublicKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + return m_group.verify_group(rng, strong) && m_group.verify_public_element(m_y); + } + +/* +* Check DL Scheme Private Parameters +*/ +bool DL_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + return m_group.verify_group(rng, strong) && m_group.verify_element_pair(m_y, m_x); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dl_algo/dl_algo.h b/src/libs/3rdparty/botan/src/lib/pubkey/dl_algo/dl_algo.h new file mode 100644 index 0000000000..af01bc217a --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dl_algo/dl_algo.h @@ -0,0 +1,140 @@ +/* +* DL Scheme +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DL_ALGO_H_ +#define BOTAN_DL_ALGO_H_ + +#include <botan/dl_group.h> +#include <botan/pk_keys.h> + +namespace Botan { + +/** +* This class represents discrete logarithm (DL) public keys. +*/ +class BOTAN_PUBLIC_API(2,0) DL_Scheme_PublicKey : public virtual Public_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const override; + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector<uint8_t> public_key_bits() const override; + + /** + * Get the DL domain parameters of this key. + * @return DL domain parameters of this key + */ + const DL_Group& get_domain() const { return m_group; } + + /** + * Get the DL domain parameters of this key. + * @return DL domain parameters of this key + */ + const DL_Group& get_group() const { return m_group; } + + /** + * Get the public value y with y = g^x mod p where x is the secret key. + */ + const BigInt& get_y() const { return m_y; } + + /** + * Get the prime p of the underlying DL group. + * @return prime p + */ + const BigInt& group_p() const { return m_group.get_p(); } + + /** + * Get the prime q of the underlying DL group. + * @return prime q + */ + const BigInt& group_q() const { return m_group.get_q(); } + + /** + * Get the generator g of the underlying DL group. + * @return generator g + */ + const BigInt& group_g() const { return m_group.get_g(); } + + /** + * Get the underlying groups encoding format. + * @return encoding format + */ + virtual DL_Group::Format group_format() const = 0; + + size_t key_length() const override; + size_t estimated_strength() const override; + + DL_Scheme_PublicKey& operator=(const DL_Scheme_PublicKey& other) = default; + + protected: + DL_Scheme_PublicKey() = default; + + /** + * Create a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + * @param group_format the underlying groups encoding format + */ + DL_Scheme_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits, + DL_Group::Format group_format); + + DL_Scheme_PublicKey(const DL_Group& group, const BigInt& y); + + /** + * The DL public key + */ + BigInt m_y; + + /** + * The DL group + */ + DL_Group m_group; + }; + +/** +* This class represents discrete logarithm (DL) private keys. +*/ +class BOTAN_PUBLIC_API(2,0) DL_Scheme_PrivateKey : public virtual DL_Scheme_PublicKey, + public virtual Private_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const override; + + /** + * Get the secret key x. + * @return secret key + */ + const BigInt& get_x() const { return m_x; } + + secure_vector<uint8_t> private_key_bits() const override; + + DL_Scheme_PrivateKey& operator=(const DL_Scheme_PrivateKey& other) = default; + + protected: + /** + * Create a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded private key bits + * @param group_format the underlying groups encoding format + */ + DL_Scheme_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits, + DL_Group::Format group_format); + + DL_Scheme_PrivateKey() = default; + + /** + * The DL private key + */ + BigInt m_x; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dl_algo/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/dl_algo/info.txt new file mode 100644 index 0000000000..44e649cd67 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dl_algo/info.txt @@ -0,0 +1,10 @@ +<defines> +DL_PUBLIC_KEY_FAMILY -> 20131128 +</defines> + +<requires> +asn1 +dl_group +numbertheory +rng +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/dl_group.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/dl_group.cpp new file mode 100644 index 0000000000..abc14ec0c7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/dl_group.cpp @@ -0,0 +1,610 @@ +/* +* Discrete Logarithm Parameters +* (C) 1999-2008,2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/dl_group.h> +#include <botan/numthry.h> +#include <botan/reducer.h> +#include <botan/monty.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/pem.h> +#include <botan/workfactor.h> +#include <botan/internal/monty_exp.h> + +namespace Botan { + +class DL_Group_Data final + { + public: + DL_Group_Data(const BigInt& p, const BigInt& q, const BigInt& g) : + m_p(p), m_q(q), m_g(g), + m_mod_p(p), + m_mod_q(q), + m_monty_params(std::make_shared<Montgomery_Params>(m_p, m_mod_p)), + m_monty(monty_precompute(m_monty_params, m_g, /*window bits=*/4)), + m_p_bits(p.bits()), + m_q_bits(q.bits()), + m_estimated_strength(dl_work_factor(m_p_bits)), + m_exponent_bits(dl_exponent_size(m_p_bits)) + { + } + + ~DL_Group_Data() = default; + + DL_Group_Data(const DL_Group_Data& other) = delete; + DL_Group_Data& operator=(const DL_Group_Data& other) = delete; + + const BigInt& p() const { return m_p; } + const BigInt& q() const { return m_q; } + const BigInt& g() const { return m_g; } + + BigInt mod_p(const BigInt& x) const { return m_mod_p.reduce(x); } + + BigInt multiply_mod_p(const BigInt& x, const BigInt& y) const + { + return m_mod_p.multiply(x, y); + } + + BigInt mod_q(const BigInt& x) const { return m_mod_q.reduce(x); } + + BigInt multiply_mod_q(const BigInt& x, const BigInt& y) const + { + return m_mod_q.multiply(x, y); + } + + BigInt square_mod_q(const BigInt& x) const + { + return m_mod_q.square(x); + } + + std::shared_ptr<const Montgomery_Params> monty_params_p() const + { return m_monty_params; } + + size_t p_bits() const { return m_p_bits; } + size_t q_bits() const { return m_q_bits; } + size_t p_bytes() const { return (m_p_bits + 7) / 8; } + + size_t estimated_strength() const { return m_estimated_strength; } + + size_t exponent_bits() const { return m_exponent_bits; } + + BigInt power_g_p(const BigInt& k, size_t max_k_bits) const + { + return monty_execute(*m_monty, k, max_k_bits); + } + + bool q_is_set() const { return m_q_bits > 0; } + + void assert_q_is_set(const std::string& function) const + { + if(q_is_set() == false) + throw Invalid_State("DL_Group::" + function + " q is not set for this group"); + } + + private: + BigInt m_p; + BigInt m_q; + BigInt m_g; + Modular_Reducer m_mod_p; + Modular_Reducer m_mod_q; + std::shared_ptr<const Montgomery_Params> m_monty_params; + std::shared_ptr<const Montgomery_Exponentation_State> m_monty; + size_t m_p_bits; + size_t m_q_bits; + size_t m_estimated_strength; + size_t m_exponent_bits; + }; + +//static +std::shared_ptr<DL_Group_Data> DL_Group::BER_decode_DL_group(const uint8_t data[], size_t data_len, DL_Group::Format format) + { + BigInt p, q, g; + + BER_Decoder decoder(data, data_len); + BER_Decoder ber = decoder.start_cons(SEQUENCE); + + if(format == DL_Group::ANSI_X9_57) + { + ber.decode(p) + .decode(q) + .decode(g) + .verify_end(); + } + else if(format == DL_Group::ANSI_X9_42) + { + ber.decode(p) + .decode(g) + .decode(q) + .discard_remaining(); + } + else if(format == DL_Group::PKCS_3) + { + // q is left as zero + ber.decode(p) + .decode(g) + .discard_remaining(); + } + else + throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); + + return std::make_shared<DL_Group_Data>(p, q, g); + } + +//static +std::shared_ptr<DL_Group_Data> +DL_Group::load_DL_group_info(const char* p_str, + const char* q_str, + const char* g_str) + { + const BigInt p(p_str); + const BigInt q(q_str); + const BigInt g(g_str); + + return std::make_shared<DL_Group_Data>(p, q, g); + } + +//static +std::shared_ptr<DL_Group_Data> +DL_Group::load_DL_group_info(const char* p_str, + const char* g_str) + { + const BigInt p(p_str); + const BigInt q = (p - 1) / 2; + const BigInt g(g_str); + + return std::make_shared<DL_Group_Data>(p, q, g); + } + +namespace { + +DL_Group::Format pem_label_to_dl_format(const std::string& label) + { + if(label == "DH PARAMETERS") + return DL_Group::PKCS_3; + else if(label == "DSA PARAMETERS") + return DL_Group::ANSI_X9_57; + else if(label == "X942 DH PARAMETERS" || label == "X9.42 DH PARAMETERS") + return DL_Group::ANSI_X9_42; + else + throw Decoding_Error("DL_Group: Invalid PEM label " + label); + } + +} + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const std::string& str) + { + // Either a name or a PEM block, try name first + m_data = DL_group_info(str); + + if(m_data == nullptr) + { + try + { + std::string label; + const std::vector<uint8_t> ber = unlock(PEM_Code::decode(str, label)); + Format format = pem_label_to_dl_format(label); + + m_data = BER_decode_DL_group(ber.data(), ber.size(), format); + } + catch(...) {} + } + + if(m_data == nullptr) + throw Invalid_Argument("DL_Group: Unknown group " + str); + } + +namespace { + +/* +* Create generator of the q-sized subgroup (DSA style generator) +*/ +BigInt make_dsa_generator(const BigInt& p, const BigInt& q) + { + const BigInt e = (p - 1) / q; + + if(e == 0 || (p - 1) % q > 0) + throw Invalid_Argument("make_dsa_generator q does not divide p-1"); + + for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i) + { + // TODO precompute! + BigInt g = power_mod(PRIMES[i], e, p); + if(g > 1) + return g; + } + + throw Internal_Error("DL_Group: Couldn't create a suitable generator"); + } + +} + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(RandomNumberGenerator& rng, + PrimeType type, size_t pbits, size_t qbits) + { + if(pbits < 1024) + throw Invalid_Argument("DL_Group: prime size " + std::to_string(pbits) + " is too small"); + + if(type == Strong) + { + if(qbits != 0 && qbits != pbits - 1) + throw Invalid_Argument("Cannot create strong-prime DL_Group with specified q bits"); + + const BigInt p = random_safe_prime(rng, pbits); + const BigInt q = (p - 1) / 2; + + /* + Always choose a generator that is quadratic reside mod p, + this forces g to be a generator of the subgroup of size q. + */ + BigInt g = 2; + if(jacobi(g, p) != 1) + { + // prime table does not contain 2 + for(size_t i = 0; i < PRIME_TABLE_SIZE; ++i) + { + g = PRIMES[i]; + if(jacobi(g, p) == 1) + break; + } + } + + m_data = std::make_shared<DL_Group_Data>(p, q, g); + } + else if(type == Prime_Subgroup) + { + if(qbits == 0) + qbits = dl_exponent_size(pbits); + + const BigInt q = random_prime(rng, qbits); + Modular_Reducer mod_2q(2*q); + BigInt X; + BigInt p; + while(p.bits() != pbits || !is_prime(p, rng, 128, true)) + { + X.randomize(rng, pbits); + p = X - mod_2q.reduce(X) + 1; + } + + const BigInt g = make_dsa_generator(p, q); + m_data = std::make_shared<DL_Group_Data>(p, q, g); + } + else if(type == DSA_Kosherizer) + { + if(qbits == 0) + qbits = ((pbits <= 1024) ? 160 : 256); + + BigInt p, q; + generate_dsa_primes(rng, p, q, pbits, qbits); + const BigInt g = make_dsa_generator(p, q); + m_data = std::make_shared<DL_Group_Data>(p, q, g); + } + else + { + throw Invalid_Argument("DL_Group unknown PrimeType"); + } + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(RandomNumberGenerator& rng, + const std::vector<uint8_t>& seed, + size_t pbits, size_t qbits) + { + BigInt p, q; + + if(!generate_dsa_primes(rng, p, q, pbits, qbits, seed)) + throw Invalid_Argument("DL_Group: The seed given does not generate a DSA group"); + + BigInt g = make_dsa_generator(p, q); + + m_data = std::make_shared<DL_Group_Data>(p, q, g); + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const BigInt& p, const BigInt& g) + { + m_data = std::make_shared<DL_Group_Data>(p, 0, g); + } + +/* +* DL_Group Constructor +*/ +DL_Group::DL_Group(const BigInt& p, const BigInt& q, const BigInt& g) + { + m_data = std::make_shared<DL_Group_Data>(p, q, g); + } + +const DL_Group_Data& DL_Group::data() const + { + if(m_data) + return *m_data; + + throw Invalid_State("DL_Group uninitialized"); + } + +bool DL_Group::verify_public_element(const BigInt& y) const + { + const BigInt& p = get_p(); + const BigInt& q = get_q(); + + if(y <= 1 || y >= p) + return false; + + if(q.is_zero() == false) + { + if(power_mod(y, q, p) != 1) + return false; + } + + return true; + } + +bool DL_Group::verify_element_pair(const BigInt& y, const BigInt& x) const + { + const BigInt& p = get_p(); + + if(y <= 1 || y >= p || x <= 1 || x >= p) + return false; + + if(y != power_g_p(x)) + return false; + + return true; + } + +/* +* Verify the parameters +*/ +bool DL_Group::verify_group(RandomNumberGenerator& rng, + bool strong) const + { + const BigInt& p = get_p(); + const BigInt& q = get_q(); + const BigInt& g = get_g(); + + if(g < 2 || p < 3 || q < 0) + return false; + + const size_t prob = (strong) ? 128 : 10; + + if(q != 0) + { + if((p - 1) % q != 0) + { + return false; + } + if(this->power_g_p(q) != 1) + { + return false; + } + if(!is_prime(q, rng, prob)) + { + return false; + } + } + + if(!is_prime(p, rng, prob)) + { + return false; + } + return true; + } + +/* +* Return the prime +*/ +const BigInt& DL_Group::get_p() const + { + return data().p(); + } + +/* +* Return the generator +*/ +const BigInt& DL_Group::get_g() const + { + return data().g(); + } + +/* +* Return the subgroup +*/ +const BigInt& DL_Group::get_q() const + { + return data().q(); + } + +std::shared_ptr<const Montgomery_Params> DL_Group::monty_params_p() const + { + return data().monty_params_p(); + } + +size_t DL_Group::p_bits() const + { + return data().p_bits(); + } + +size_t DL_Group::p_bytes() const + { + return data().p_bytes(); + } + +size_t DL_Group::q_bits() const + { + data().assert_q_is_set("q_bits"); + return data().q_bits(); + } + +size_t DL_Group::estimated_strength() const + { + return data().estimated_strength(); + } + +size_t DL_Group::exponent_bits() const + { + return data().exponent_bits(); + } + +BigInt DL_Group::inverse_mod_p(const BigInt& x) const + { + // precompute?? + return inverse_mod(x, get_p()); + } + +BigInt DL_Group::mod_p(const BigInt& x) const + { + return data().mod_p(x); + } + +BigInt DL_Group::multiply_mod_p(const BigInt& x, const BigInt& y) const + { + return data().multiply_mod_p(x, y); + } + +BigInt DL_Group::inverse_mod_q(const BigInt& x) const + { + data().assert_q_is_set("inverse_mod_q"); + // precompute?? + return inverse_mod(x, get_q()); + } + +BigInt DL_Group::mod_q(const BigInt& x) const + { + data().assert_q_is_set("mod_q"); + return data().mod_q(x); + } + +BigInt DL_Group::multiply_mod_q(const BigInt& x, const BigInt& y) const + { + data().assert_q_is_set("multiply_mod_q"); + return data().multiply_mod_q(x, y); + } + +BigInt DL_Group::multiply_mod_q(const BigInt& x, const BigInt& y, const BigInt& z) const + { + data().assert_q_is_set("multiply_mod_q"); + return data().multiply_mod_q(data().multiply_mod_q(x, y), z); + } + +BigInt DL_Group::square_mod_q(const BigInt& x) const + { + data().assert_q_is_set("square_mod_q"); + return data().square_mod_q(x); + } + +BigInt DL_Group::multi_exponentiate(const BigInt& x, const BigInt& y, const BigInt& z) const + { + return monty_multi_exp(data().monty_params_p(), get_g(), x, y, z); + } + +BigInt DL_Group::power_g_p(const BigInt& x) const + { + return data().power_g_p(x, x.bits()); + } + +BigInt DL_Group::power_g_p(const BigInt& x, size_t max_x_bits) const + { + return data().power_g_p(x, max_x_bits); + } + +/* +* DER encode the parameters +*/ +std::vector<uint8_t> DL_Group::DER_encode(Format format) const + { + if(get_q().is_zero() && (format == ANSI_X9_57 || format == ANSI_X9_42)) + throw Encoding_Error("Cannot encode DL_Group in ANSI formats when q param is missing"); + + std::vector<uint8_t> output; + DER_Encoder der(output); + + if(format == ANSI_X9_57) + { + der.start_cons(SEQUENCE) + .encode(get_p()) + .encode(get_q()) + .encode(get_g()) + .end_cons(); + } + else if(format == ANSI_X9_42) + { + der.start_cons(SEQUENCE) + .encode(get_p()) + .encode(get_g()) + .encode(get_q()) + .end_cons(); + } + else if(format == PKCS_3) + { + der.start_cons(SEQUENCE) + .encode(get_p()) + .encode(get_g()) + .end_cons(); + } + else + throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); + + return output; + } + +/* +* PEM encode the parameters +*/ +std::string DL_Group::PEM_encode(Format format) const + { + const std::vector<uint8_t> encoding = DER_encode(format); + + if(format == PKCS_3) + return PEM_Code::encode(encoding, "DH PARAMETERS"); + else if(format == ANSI_X9_57) + return PEM_Code::encode(encoding, "DSA PARAMETERS"); + else if(format == ANSI_X9_42) + return PEM_Code::encode(encoding, "X9.42 DH PARAMETERS"); + else + throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format)); + } + +DL_Group::DL_Group(const uint8_t ber[], size_t ber_len, Format format) + { + m_data = BER_decode_DL_group(ber, ber_len, format); + } + +void DL_Group::BER_decode(const std::vector<uint8_t>& ber, Format format) + { + m_data = BER_decode_DL_group(ber.data(), ber.size(), format); + } + +/* +* Decode PEM encoded parameters +*/ +void DL_Group::PEM_decode(const std::string& pem) + { + std::string label; + const std::vector<uint8_t> ber = unlock(PEM_Code::decode(pem, label)); + Format format = pem_label_to_dl_format(label); + + m_data = BER_decode_DL_group(ber.data(), ber.size(), format); + } + +//static +std::string DL_Group::PEM_for_named_group(const std::string& name) + { + DL_Group group(name); + DL_Group::Format format = group.get_q().is_zero() ? DL_Group::PKCS_3 : DL_Group::ANSI_X9_42; + return group.PEM_encode(format); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/dl_group.h b/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/dl_group.h new file mode 100644 index 0000000000..6bc9187613 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/dl_group.h @@ -0,0 +1,332 @@ +/* +* Discrete Logarithm Group +* (C) 1999-2008,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DL_PARAM_H_ +#define BOTAN_DL_PARAM_H_ + +#include <botan/bigint.h> + +namespace Botan { + +class Montgomery_Params; +class DL_Group_Data; + +/** +* This class represents discrete logarithm groups. It holds a prime +* modulus p, a generator g, and (optionally) a prime q which is a +* factor of (p-1). In most cases g generates the order-q subgroup. +*/ +class BOTAN_PUBLIC_API(2,0) DL_Group final + { + public: + /** + * Determine the prime creation for DL groups. + */ + enum PrimeType { Strong, Prime_Subgroup, DSA_Kosherizer }; + + /** + * The DL group encoding format variants. + */ + enum Format { + ANSI_X9_42, + ANSI_X9_57, + PKCS_3, + + DSA_PARAMETERS = ANSI_X9_57, + DH_PARAMETERS = ANSI_X9_42, + ANSI_X9_42_DH_PARAMETERS = ANSI_X9_42, + PKCS3_DH_PARAMETERS = PKCS_3 + }; + + /** + * Construct a DL group with uninitialized internal value. + * Use this constructor is you wish to set the groups values + * from a DER or PEM encoded group. + */ + DL_Group() = default; + + /** + * Construct a DL group that is registered in the configuration. + * @param name the name that is configured in the global configuration + * for the desired group. If no configuration file is specified, + * the default values from the file policy.cpp will be used. For instance, + * use "modp/ietf/3072". + */ + DL_Group(const std::string& name); + + /** + * Create a new group randomly. + * @param rng the random number generator to use + * @param type specifies how the creation of primes p and q shall + * be performed. If type=Strong, then p will be determined as a + * safe prime, and q will be chosen as (p-1)/2. If + * type=Prime_Subgroup and qbits = 0, then the size of q will be + * determined according to the estimated difficulty of the DL + * problem. If type=DSA_Kosherizer, DSA primes will be created. + * @param pbits the number of bits of p + * @param qbits the number of bits of q. Leave it as 0 to have + * the value determined according to pbits. + */ + DL_Group(RandomNumberGenerator& rng, PrimeType type, + size_t pbits, size_t qbits = 0); + + /** + * Create a DSA group with a given seed. + * @param rng the random number generator to use + * @param seed the seed to use to create the random primes + * @param pbits the desired bit size of the prime p + * @param qbits the desired bit size of the prime q. + */ + DL_Group(RandomNumberGenerator& rng, + const std::vector<uint8_t>& seed, + size_t pbits = 1024, size_t qbits = 0); + + /** + * Create a DL group. + * @param p the prime p + * @param g the base g + */ + DL_Group(const BigInt& p, const BigInt& g); + + /** + * Create a DL group. + * @param p the prime p + * @param q the prime q + * @param g the base g + */ + DL_Group(const BigInt& p, const BigInt& q, const BigInt& g); + + /** + * Decode a BER-encoded DL group param + */ + DL_Group(const uint8_t ber[], size_t ber_len, Format format); + + /** + * Decode a BER-encoded DL group param + */ + template<typename Alloc> + DL_Group(const std::vector<uint8_t, Alloc>& ber, Format format) : + DL_Group(ber.data(), ber.size(), format) {} + + /** + * Get the prime p. + * @return prime p + */ + const BigInt& get_p() const; + + /** + * Get the prime q, returns zero if q is not used + * @return prime q + */ + const BigInt& get_q() const; + + /** + * Get the base g. + * @return base g + */ + const BigInt& get_g() const; + + /** + * Perform validity checks on the group. + * @param rng the rng to use + * @param strong whether to perform stronger by lengthier tests + * @return true if the object is consistent, false otherwise + */ + bool verify_group(RandomNumberGenerator& rng, bool strong = true) const; + + /** + * Verify a public element, ie check if y = g^x for some x. + * + * This is not a perfect test. It verifies that 1 < y < p and (if q is set) + * that y is in the subgroup of size q. + */ + bool verify_public_element(const BigInt& y) const; + + /** + * Verify a pair of elements y = g^x + * + * This verifies that 1 < x,y < p and that y=g^x mod p + */ + bool verify_element_pair(const BigInt& y, const BigInt& x) const; + + /** + * Encode this group into a string using PEM encoding. + * @param format the encoding format + * @return string holding the PEM encoded group + */ + std::string PEM_encode(Format format) const; + + /** + * Encode this group into a string using DER encoding. + * @param format the encoding format + * @return string holding the DER encoded group + */ + std::vector<uint8_t> DER_encode(Format format) const; + + /** + * Reduce an integer modulo p + * @return x % p + */ + BigInt mod_p(const BigInt& x) const; + + /** + * Multiply and reduce an integer modulo p + * @return (x*y) % p + */ + BigInt multiply_mod_p(const BigInt& x, const BigInt& y) const; + + /** + * Return the inverse of x mod p + */ + BigInt inverse_mod_p(const BigInt& x) const; + + /** + * Reduce an integer modulo q + * Throws if q is unset on this DL_Group + * @return x % q + */ + BigInt mod_q(const BigInt& x) const; + + /** + * Multiply and reduce an integer modulo q + * Throws if q is unset on this DL_Group + * @return (x*y) % q + */ + BigInt multiply_mod_q(const BigInt& x, const BigInt& y) const; + + /** + * Multiply and reduce an integer modulo q + * Throws if q is unset on this DL_Group + * @return (x*y*z) % q + */ + BigInt multiply_mod_q(const BigInt& x, const BigInt& y, const BigInt& z) const; + + /** + * Square and reduce an integer modulo q + * Throws if q is unset on this DL_Group + * @return (x*x) % q + */ + BigInt square_mod_q(const BigInt& x) const; + + /** + * Return the inverse of x mod q + * Throws if q is unset on this DL_Group + */ + BigInt inverse_mod_q(const BigInt& x) const; + + /** + * Modular exponentiation + * + * @warning this function leaks the size of x via the number of + * loop iterations. Use the version taking the maximum size to + * avoid this. + * + * @return (g^x) % p + */ + BigInt power_g_p(const BigInt& x) const; + + /** + * Modular exponentiation + * @param x the exponent + * @param max_x_bits x is assumed to be at most this many bits long. + * + * @return (g^x) % p + */ + BigInt power_g_p(const BigInt& x, size_t max_x_bits) const; + + /** + * Multi-exponentiate + * Return (g^x * y^z) % p + */ + BigInt multi_exponentiate(const BigInt& x, const BigInt& y, const BigInt& z) const; + + /** + * Return parameters for Montgomery reduction/exponentiation mod p + */ + std::shared_ptr<const Montgomery_Params> monty_params_p() const; + + /** + * Return the size of p in bits + * Same as get_p().bits() + */ + size_t p_bits() const; + + /** + * Return the size of p in bytes + * Same as get_p().bytes() + */ + size_t p_bytes() const; + + /** + * Return the size of q in bits + * Same as get_q().bits() + * Throws if q is unset + */ + size_t q_bits() const; + + /** + * Return size in bits of a secret exponent + * + * This attempts to balance between the attack costs of NFS + * (which depends on the size of the modulus) and Pollard's rho + * (which depends on the size of the exponent). + * + * It may vary over time for a particular group, if the attack + * costs change. + */ + size_t exponent_bits() const; + + /** + * Return an estimate of the strength of this group against + * discrete logarithm attacks (eg NFS). Warning: since this only + * takes into account known attacks it is by necessity an + * overestimate of the actual strength. + */ + size_t estimated_strength() const; + + /** + * Decode a DER/BER encoded group into this instance. + * @param ber a vector containing the DER/BER encoded group + * @param format the format of the encoded group + */ + void BER_decode(const std::vector<uint8_t>& ber, Format format); + + /** + * Decode a PEM encoded group into this instance. + * @param pem the PEM encoding of the group + */ + void PEM_decode(const std::string& pem); + + /** + * Return PEM representation of named DL group + */ + static std::string BOTAN_DEPRECATED("Use DL_Group(name).PEM_encode()") + PEM_for_named_group(const std::string& name); + + /* + * For internal use only + */ + static std::shared_ptr<DL_Group_Data> DL_group_info(const std::string& name); + + private: + static std::shared_ptr<DL_Group_Data> load_DL_group_info(const char* p_str, + const char* q_str, + const char* g_str); + + static std::shared_ptr<DL_Group_Data> load_DL_group_info(const char* p_str, + const char* g_str); + + static std::shared_ptr<DL_Group_Data> + BER_decode_DL_group(const uint8_t data[], size_t data_len, DL_Group::Format format); + + const DL_Group_Data& data() const; + std::shared_ptr<DL_Group_Data> m_data; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/dl_named.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/dl_named.cpp new file mode 100644 index 0000000000..4d7b71bc1d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/dl_named.cpp @@ -0,0 +1,175 @@ +/* +* List of discrete log groups +* (C) 2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/dl_group.h> + +namespace Botan { + +//static +std::shared_ptr<DL_Group_Data> DL_Group::DL_group_info(const std::string& name) + { + /* TLS FFDHE groups */ + + if(name == "ffdhe/ietf/2048") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B423861285C97FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "ffdhe/ietf/3072") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "ffdhe/ietf/4096") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6AFFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "ffdhe/ietf/6144") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD9020BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA63BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3ACDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477A52471F7A9A96910B855322EDB6340D8A00EF092350511E30ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538CD72B03746AE77F5E62292C311562A846505DC82DB854338AE49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B045B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "ffdhe/ietf/8192") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD9020BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA63BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3ACDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477A52471F7A9A96910B855322EDB6340D8A00EF092350511E30ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538CD72B03746AE77F5E62292C311562A846505DC82DB854338AE49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B045B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C8381E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665CB2C0F1CC01BD70229388839D2AF05E454504AC78B7582822846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA4571EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88CD68C8BB7C5C6424CFFFFFFFFFFFFFFFF", + "0x2"); + } + + /* IETF IPsec groups */ + + if(name == "modp/ietf/1024") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/1536") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/2048") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/3072") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/4096") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/6144") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", + "0x2"); + } + + if(name == "modp/ietf/8192") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF", + "0x2"); + } + + /* SRP groups + + SRP groups have a p st (p-1)/2 is prime, but g is not a generator + of subgroup of size q, so set q == 0 to bypass generator check + + Missing q doesn't matter for SRP, and nothing but SRP should be + using these parameters. + */ + + if(name == "modp/srp/1024") + { + return load_DL_group_info("0xEEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", + "0", + "0x2"); + } + + if(name == "modp/srp/1536") + { + return load_DL_group_info("0x9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB", + "0", + "0x2"); + } + + if(name == "modp/srp/2048") + { + return load_DL_group_info("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", + "0", + "0x2"); + } + + if(name == "modp/srp/3072") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", + "0", + "0x5"); + } + + if(name == "modp/srp/4096") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", + "0", + "0x5"); + } + + if(name == "modp/srp/6144") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", + "0", + "0x5"); + } + + if(name == "modp/srp/8192") + { + return load_DL_group_info("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF", + "0", + "0x13"); + } + + /* DSA groups */ + + if(name == "dsa/jce/1024") + { + return load_DL_group_info("0xFD7F53811D75122952DF4A9C2EECE4E7F611B7523CEF4400C31E3F80B6512669455D402251FB593D8D58FABFC5F5BA30F6CB9B556CD7813B801D346FF26660B76B9950A5A49F9FE8047B1022C24FBBA9D7FEB7C61BF83B57E7C6A8A6150F04FB83F6D3C51EC3023554135A169132F675F3AE2B61D72AEFF22203199DD14801C7", + "0x9760508F15230BCCB292B982A2EB840BF0581CF5", + "0x469603512E30278CD3947595DB22EEC9826A6322ADC97344F41D740C325724C8F9EFBAA7D4D803FF8C609DCD100EBC5BDFCFAD7C6A425FAEA786EA2050EBE98351EA1FDA1FDF24D6947AA6B9AA23766953802F4D7D4A8ECBA06D19768A2491FFB16D0EF9C43A99B5F71672FF6F0A24B444D0736D04D38A1A1322DAF6CDD88C9D"); + } + + if(name == "dsa/botan/2048") + { + return load_DL_group_info("0x91C48A4FDFBCF7C02AE95E7DA126122B5DD2864F559B87E8E74A286D52F59BD1DE68DFD645D0E00C60C080031891980374EEB594A532BFD67B9A09EAC4B8663A07910E68F39465FB7040D25DF13932EBAC4347A530ECBA61C854F9B880D3C0C3660080587C45566DADE26BD5A394BE093B4C0F24B5AFFEF8EC6C5B3E57FB89025A9BC16769932131E16D3C94EFCAB18D0DF061203CC53E6103BC72D5594BFD40CA65380F44A9A851DCB075495FC033A8A58071A1BD78FE052F66555648EB4B719D2AFE8B4880F8DAD6F15818BA178F89274C870BE9B96EB08C46C40040CC2EFE1DFB1B1868DD319DE3C34A32A63AB6EB1224209A419680CC7902D1728D4DF9E1", + "0x8CD7D450F86F0AD94EEE4CE469A8756D1EBD1058241943EAFFB0B354585E924D", + "0xD9F5E0761B4DBD1833D6AB1A961A0996C5F22303F72D84C140F67C431D94AB5715BEA81A0C98D39CE4BCF78D6B9EBC895D34FE89D94091D5848615EF15F5E86F11D96F6C969E203DDFA58356420A49CB444B595B901A933CFE0767B594F18A07B7F91DECDBA446B88990F78F2FF91F2FE7CD43FD2E46D18EADA1F7BB6602C617F6EF3A4B284F2FD9BA10A36042DE8FA87A2CA36597FEC81157A1485E44041DF02830111CB880BBE6ED494814886F965CDC3135F5CCF1383728BF65B806F9692C0B10D6C4C09C75A6CA3B4013CB16AB2C105F6BE23AEA9000EAB2178985F972C98057E1C86E44E7218688EA4AE0F3636DCCA745C9DCD4E6AFFB67CCBC13D6131"); + } + + if(name == "dsa/botan/3072") + { + return load_DL_group_info("0xE4B50880759663585E142460CA2D9DFF132F8AE4C840DDA3A2666889124FE5638B84E8A29B7AF3FA1209BE6BFC4B5072ED3B2B7387BAF3F857F478A80228EF3600B76B3DCFB61D20D34465B2506D2CAF87DF6E7DC0CE91BD2D167A46F6ADCC31C531E4F9C7ABBDB92ADDF35B0A806C66292A5F5E17E964DD099903733AC428AB35D80EA6F685BFBA8BE4068E5418AE5ECAD9E8FF073DE2B63E4E7EAD35C8A9B70B5BD47CFB88D373B66F37931939B0AB71BD5595809086DA0155337D185A0E4FB36A519B1B6202B8591E6002449CF1CD3A66384F6D2073B1CD73BECA93BAF1E1A6117D0238F222AE1ED7FED185A890E7F67FAB8FEB9753CC134A5183DFE87AE2595F7B5C2D9FBB42249FDD59513E1D3396B3EB2FD86684F285A8448FE757A029881C40760B94EF919BDF9740C38389599EC51A6E9BB519A8E068491E9CE0A2FCFE3CB60D66CF0DFAD20A8EC684048684A61444575BD1724D7352B44A760077B3BD6BD385CE5B0A7250CC0BF768DA82923806EB9CFBB138843731B618208C759B", + "0xB3EBD364EC69EF8CF3BAF643B75734B16339B2E49E5CDE1B59C1E9FB40EE0C5B", + "0x2BED21EEF83964A230AE89BBA71D9F7C39C52FC8229B4E3BC7E5944D329DA10F010EAC9E7BAF6C009FC4EB2960723E2B56DF4663E4C3AC800E9258DE2F7649D206782893F865EFCA498D2EEF30074EA5E8A7AB262712A4D94A2F3B0B9A92EE400FB38A3CC59A5DC7E436D5C004B22E35028381B51C93407EB32D4AE0FD42CB45E12D0ECEE8A26238EDE2082A7B1522113C66CEF8D745C6CF3CB945F84D2F4DE16D44A71DE198270E13F03553C88B8D323AD0B948A1BF2103A949979B6ED16FB5F3C953D95B7C8E88CA67DCF5A636FB9CA39D924215F7A884ED6C7EE3C96D8D9715427974B7C4351282E13D3773F7D28B452F10892A13C7587328DEA4827B6B369B2A8DC172ADC583F51F2A6598C5483E5BC467B02F91D059C402D18E2C2680F776AA06F49280A2C72C17CC42D5B6E740C5C4B1AB3C51C2ED092BE2A2D8B053AE5773D1425ED2B08F06E2DD50592DF1A478C15591CDFD11564FF88FF38B721D42392FDA473212DCFD8D2D88A976A00AFFE6FFFB430A359E64CA2B351CA2412394"); + } + + return std::shared_ptr<DL_Group_Data>(); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/info.txt new file mode 100644 index 0000000000..a73edb18c1 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dl_group/info.txt @@ -0,0 +1,10 @@ +<defines> +DL_GROUP -> 20131128 +</defines> + +<requires> +asn1 +bigint +numbertheory +pem +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dsa/dsa.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/dsa/dsa.cpp new file mode 100644 index 0000000000..35240292c1 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dsa/dsa.cpp @@ -0,0 +1,218 @@ +/* +* DSA +* (C) 1999-2010,2014,2016 Jack Lloyd +* (C) 2016 René Korthaus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/dsa.h> +#include <botan/keypair.h> +#include <botan/reducer.h> +#include <botan/rng.h> +#include <botan/internal/pk_ops_impl.h> + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + #include <botan/emsa.h> + #include <botan/rfc6979.h> +#endif + +namespace Botan { + +/* +* DSA_PublicKey Constructor +*/ +DSA_PublicKey::DSA_PublicKey(const DL_Group& grp, const BigInt& y1) + { + m_group = grp; + m_y = y1; + } + +/* +* Create a DSA private key +*/ +DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + m_group = grp; + + if(x_arg == 0) + m_x = BigInt::random_integer(rng, 2, group_q()); + else + m_x = x_arg; + + m_y = m_group.power_g_p(m_x, m_group.q_bits()); + } + +DSA_PrivateKey::DSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits) : + DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + m_y = m_group.power_g_p(m_x, m_group.q_bits()); + } + +/* +* Check Private DSA Parameters +*/ +bool DSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong) || m_x >= group_q()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); + } + +namespace { + +/** +* Object that can create a DSA signature +*/ +class DSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA + { + public: + DSA_Signature_Operation(const DSA_PrivateKey& dsa, + const std::string& emsa, + RandomNumberGenerator& rng) : + PK_Ops::Signature_with_EMSA(emsa), + m_group(dsa.get_group()), + m_x(dsa.get_x()) + { +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + m_rfc6979_hash = hash_for_emsa(emsa); +#endif + + m_b = BigInt::random_integer(rng, 2, dsa.group_q()); + m_b_inv = m_group.inverse_mod_q(m_b); + } + + size_t max_input_bits() const override { return m_group.get_q().bits(); } + + secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + private: + const DL_Group m_group; + const BigInt& m_x; +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + std::string m_rfc6979_hash; +#endif + + BigInt m_b, m_b_inv; + }; + +secure_vector<uint8_t> +DSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const BigInt& q = m_group.get_q(); + + BigInt m(msg, msg_len, m_group.q_bits()); + + while(m >= q) + m -= q; + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + BOTAN_UNUSED(rng); + const BigInt k = generate_rfc6979_nonce(m_x, q, m, m_rfc6979_hash); +#else + const BigInt k = BigInt::random_integer(rng, 1, q); +#endif + + const BigInt k_inv = m_group.inverse_mod_q(k); + + const BigInt r = m_group.mod_q(m_group.power_g_p(k, m_group.q_bits())); + + /* + * Blind the input message and compute x*r+m as (x*r*b + m*b)/b + */ + m_b = m_group.square_mod_q(m_b); + m_b_inv = m_group.square_mod_q(m_b_inv); + + m = m_group.multiply_mod_q(m_b, m); + const BigInt xr = m_group.multiply_mod_q(m_b, m_x, r); + + const BigInt s = m_group.multiply_mod_q(m_b_inv, k_inv, m_group.mod_q(xr+m)); + + // With overwhelming probability, a bug rather than actual zero r/s + if(r.is_zero() || s.is_zero()) + throw Internal_Error("Computed zero r/s during DSA signature"); + + return BigInt::encode_fixed_length_int_pair(r, s, q.bytes()); + } + +/** +* Object that can verify a DSA signature +*/ +class DSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA + { + public: + DSA_Verification_Operation(const DSA_PublicKey& dsa, + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + m_group(dsa.get_group()), + m_y(dsa.get_y()) + { + } + + size_t max_input_bits() const override { return m_group.get_q().bits(); } + + bool with_recovery() const override { return false; } + + bool verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) override; + private: + const DL_Group m_group; + const BigInt& m_y; + }; + +bool DSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) + { + const BigInt& q = m_group.get_q(); + const size_t q_bytes = q.bytes(); + + if(sig_len != 2*q_bytes || msg_len > q_bytes) + return false; + + BigInt r(sig, q_bytes); + BigInt s(sig + q_bytes, q_bytes); + BigInt i(msg, msg_len, q.bits()); + + if(r <= 0 || r >= q || s <= 0 || s >= q) + return false; + + s = inverse_mod(s, q); + + const BigInt sr = m_group.multiply_mod_q(s, r); + const BigInt si = m_group.multiply_mod_q(s, i); + + s = m_group.multi_exponentiate(si, m_y, sr); + + return (m_group.mod_q(s) == r); + } + +} + +std::unique_ptr<PK_Ops::Verification> +DSA_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Verification>(new DSA_Verification_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr<PK_Ops::Signature> +DSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Signature>(new DSA_Signature_Operation(*this, params, rng)); + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dsa/dsa.h b/src/libs/3rdparty/botan/src/lib/pubkey/dsa/dsa.h new file mode 100644 index 0000000000..b219a1cf37 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dsa/dsa.h @@ -0,0 +1,87 @@ +/* +* DSA +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DSA_H_ +#define BOTAN_DSA_H_ + +#include <botan/dl_algo.h> + +namespace Botan { + +/** +* DSA Public Key +*/ +class BOTAN_PUBLIC_API(2,0) DSA_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const override { return "DSA"; } + + DL_Group::Format group_format() const override { return DL_Group::ANSI_X9_57; } + size_t message_parts() const override { return 2; } + size_t message_part_size() const override { return group_q().bytes(); } + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + DSA_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits) : + DL_Scheme_PublicKey(alg_id, key_bits, DL_Group::ANSI_X9_57) + { + } + + /** + * Create a public key. + * @param group the underlying DL group + * @param y the public value y = g^x mod p + */ + DSA_PublicKey(const DL_Group& group, const BigInt& y); + + std::unique_ptr<PK_Ops::Verification> + create_verification_op(const std::string& params, + const std::string& provider) const override; + protected: + DSA_PublicKey() = default; + }; + +/** +* DSA Private Key +*/ +class BOTAN_PUBLIC_API(2,0) DSA_PrivateKey final : public DSA_PublicKey, + public virtual DL_Scheme_PrivateKey + { + public: + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded key bits in ANSI X9.57 format + */ + DSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits); + + /** + * Create a private key. + * @param rng the RNG to use + * @param group the underlying DL group + * @param private_key the private key (if zero, a new random key is generated) + */ + DSA_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& group, + const BigInt& private_key = 0); + + bool check_key(RandomNumberGenerator& rng, bool strong) const override; + + std::unique_ptr<PK_Ops::Signature> + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/dsa/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/dsa/info.txt new file mode 100644 index 0000000000..a9f288edea --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/dsa/info.txt @@ -0,0 +1,12 @@ +<defines> +DSA -> 20131128 +</defines> + +<requires> +dl_algo +dl_group +keypair +numbertheory +emsa1 +sha2_32 +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/curve_gfp.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/curve_gfp.cpp new file mode 100644 index 0000000000..bd68a3ed7d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/curve_gfp.cpp @@ -0,0 +1,576 @@ +/* +* Elliptic curves over GF(p) Montgomery Representation +* (C) 2014,2015,2018 Jack Lloyd +* 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/curve_gfp.h> +#include <botan/curve_nistp.h> +#include <botan/numthry.h> +#include <botan/reducer.h> +#include <botan/internal/mp_core.h> +#include <botan/internal/mp_asmi.h> + +namespace Botan { + +namespace { + +class CurveGFp_Montgomery final : public CurveGFp_Repr + { + public: + CurveGFp_Montgomery(const BigInt& p, const BigInt& a, const BigInt& b) : + m_p(p), m_a(a), m_b(b), + m_p_words(m_p.sig_words()), + m_p_dash(monty_inverse(m_p.word_at(0))) + { + Modular_Reducer mod_p(m_p); + + m_r.set_bit(m_p_words * BOTAN_MP_WORD_BITS); + m_r = mod_p.reduce(m_r); + + m_r2 = mod_p.square(m_r); + m_r3 = mod_p.multiply(m_r, m_r2); + m_a_r = mod_p.multiply(m_r, m_a); + m_b_r = mod_p.multiply(m_r, m_b); + + m_a_is_zero = m_a.is_zero(); + m_a_is_minus_3 = (m_a + 3 == m_p); + } + + bool a_is_zero() const override { return m_a_is_zero; } + bool a_is_minus_3() const override { return m_a_is_minus_3; } + + const BigInt& get_a() const override { return m_a; } + + const BigInt& get_b() const override { return m_b; } + + const BigInt& get_p() const override { return m_p; } + + const BigInt& get_a_rep() const override { return m_a_r; } + + const BigInt& get_b_rep() const override { return m_b_r; } + + const BigInt& get_1_rep() const override { return m_r; } + + bool is_one(const BigInt& x) const override { return x == m_r; } + + size_t get_p_words() const override { return m_p_words; } + + size_t get_ws_size() const override { return 2*m_p_words + 4; } + + void redc_mod_p(BigInt& z, secure_vector<word>& ws) const override; + + BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override; + + void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override; + + void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override; + + void curve_mul_words(BigInt& z, + const word x_words[], + const size_t x_size, + const BigInt& y, + secure_vector<word>& ws) const override; + + void curve_sqr_words(BigInt& z, + const word x_words[], + size_t x_size, + secure_vector<word>& ws) const override; + + private: + BigInt m_p; + BigInt m_a, m_b; + BigInt m_a_r, m_b_r; + size_t m_p_words; // cache of m_p.sig_words() + + // Montgomery parameters + BigInt m_r, m_r2, m_r3; + word m_p_dash; + + bool m_a_is_zero; + bool m_a_is_minus_3; + }; + +void CurveGFp_Montgomery::redc_mod_p(BigInt& z, secure_vector<word>& ws) const + { + z.reduce_below(m_p, ws); + } + +BigInt CurveGFp_Montgomery::invert_element(const BigInt& x, secure_vector<word>& ws) const + { + // Should we use Montgomery inverse instead? + const BigInt inv = inverse_mod(x, m_p); + BigInt res; + curve_mul(res, inv, m_r3, ws); + return res; + } + +void CurveGFp_Montgomery::to_curve_rep(BigInt& x, secure_vector<word>& ws) const + { + const BigInt tx = x; + curve_mul(x, tx, m_r2, ws); + } + +void CurveGFp_Montgomery::from_curve_rep(BigInt& z, secure_vector<word>& ws) const + { + if(ws.size() < get_ws_size()) + ws.resize(get_ws_size()); + + const size_t output_size = 2*m_p_words + 2; + if(z.size() < output_size) + z.grow_to(output_size); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + } + +void CurveGFp_Montgomery::curve_mul_words(BigInt& z, + const word x_w[], + size_t x_size, + const BigInt& y, + secure_vector<word>& ws) const + { + BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words); + + if(ws.size() < get_ws_size()) + ws.resize(get_ws_size()); + + const size_t output_size = 2*m_p_words + 2; + if(z.size() < output_size) + z.grow_to(output_size); + + bigint_mul(z.mutable_data(), z.size(), + x_w, x_size, std::min(m_p_words, x_size), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + } + +void CurveGFp_Montgomery::curve_sqr_words(BigInt& z, + const word x[], + size_t x_size, + secure_vector<word>& ws) const + { + if(ws.size() < get_ws_size()) + ws.resize(get_ws_size()); + + const size_t output_size = 2*m_p_words + 2; + if(z.size() < output_size) + z.grow_to(output_size); + + bigint_sqr(z.mutable_data(), z.size(), + x, x_size, std::min(m_p_words, x_size), + ws.data(), ws.size()); + + bigint_monty_redc(z.mutable_data(), + m_p.data(), m_p_words, m_p_dash, + ws.data(), ws.size()); + } + +class CurveGFp_NIST : public CurveGFp_Repr + { + public: + CurveGFp_NIST(size_t p_bits, const BigInt& a, const BigInt& b) : + m_1(1), m_a(a), m_b(b), m_p_words((p_bits + BOTAN_MP_WORD_BITS - 1) / BOTAN_MP_WORD_BITS) + { + // All Solinas prime curves are assumed a == -3 + } + + bool a_is_zero() const override { return false; } + bool a_is_minus_3() const override { return true; } + + const BigInt& get_a() const override { return m_a; } + + const BigInt& get_b() const override { return m_b; } + + const BigInt& get_1_rep() const override { return m_1; } + + size_t get_p_words() const override { return m_p_words; } + + size_t get_ws_size() const override { return 2*m_p_words + 4; } + + const BigInt& get_a_rep() const override { return m_a; } + + const BigInt& get_b_rep() const override { return m_b; } + + bool is_one(const BigInt& x) const override { return x == 1; } + + void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override + { redc_mod_p(x, ws); } + + void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override + { redc_mod_p(x, ws); } + + BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override; + + void curve_mul_words(BigInt& z, + const word x_words[], + const size_t x_size, + const BigInt& y, + secure_vector<word>& ws) const override; + + void curve_mul_tmp(BigInt& x, const BigInt& y, BigInt& tmp, secure_vector<word>& ws) const + { + curve_mul(tmp, x, y, ws); + x.swap(tmp); + } + + void curve_sqr_tmp(BigInt& x, BigInt& tmp, secure_vector<word>& ws) const + { + curve_sqr(tmp, x, ws); + x.swap(tmp); + } + + void curve_sqr_words(BigInt& z, + const word x_words[], + size_t x_size, + secure_vector<word>& ws) const override; + private: + // Curve parameters + BigInt m_1; + BigInt m_a, m_b; + size_t m_p_words; // cache of m_p.sig_words() + }; + +BigInt CurveGFp_NIST::invert_element(const BigInt& x, secure_vector<word>& ws) const + { + BOTAN_UNUSED(ws); + return inverse_mod(x, get_p()); + } + +void CurveGFp_NIST::curve_mul_words(BigInt& z, + const word x_w[], + size_t x_size, + const BigInt& y, + secure_vector<word>& ws) const + { + BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words); + + if(ws.size() < get_ws_size()) + ws.resize(get_ws_size()); + + const size_t output_size = 2*m_p_words + 2; + if(z.size() < output_size) + z.grow_to(output_size); + + bigint_mul(z.mutable_data(), z.size(), + x_w, x_size, std::min(m_p_words, x_size), + y.data(), y.size(), std::min(m_p_words, y.size()), + ws.data(), ws.size()); + + this->redc_mod_p(z, ws); + } + +void CurveGFp_NIST::curve_sqr_words(BigInt& z, const word x[], size_t x_size, + secure_vector<word>& ws) const + { + if(ws.size() < get_ws_size()) + ws.resize(get_ws_size()); + + const size_t output_size = 2*m_p_words + 2; + if(z.size() < output_size) + z.grow_to(output_size); + + bigint_sqr(z.mutable_data(), output_size, + x, x_size, std::min(m_p_words, x_size), + ws.data(), ws.size()); + + this->redc_mod_p(z, ws); + } + +#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32) + +/** +* The NIST P-192 curve +*/ +class CurveGFp_P192 final : 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_mod_p(BigInt& x, secure_vector<word>& ws) const override { redc_p192(x, ws); } + }; + +/** +* The NIST P-224 curve +*/ +class CurveGFp_P224 final : 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_mod_p(BigInt& x, secure_vector<word>& ws) const override { redc_p224(x, ws); } + }; + +/** +* The NIST P-256 curve +*/ +class CurveGFp_P256 final : 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_mod_p(BigInt& x, secure_vector<word>& ws) const override { redc_p256(x, ws); } + BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override; + }; + +BigInt CurveGFp_P256::invert_element(const BigInt& x, secure_vector<word>& ws) const + { + BigInt r, p2, p4, p8, p16, p32, tmp; + + curve_sqr(r, x, ws); + + curve_mul(p2, r, x, ws); + curve_sqr(r, p2, ws); + curve_sqr_tmp(r, tmp, ws); + + curve_mul(p4, r, p2, ws); + + curve_sqr(r, p4, ws); + for(size_t i = 0; i != 3; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul(p8, r, p4, ws);; + + curve_sqr(r, p8, ws); + for(size_t i = 0; i != 7; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul(p16, r, p8, ws); + + curve_sqr(r, p16, ws); + for(size_t i = 0; i != 15; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul(p32, r, p16, ws); + + curve_sqr(r, p32, ws); + for(size_t i = 0; i != 31; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + for(size_t i = 0; i != 32*4; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p32, tmp, ws); + + for(size_t i = 0; i != 32; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p32, tmp, ws); + + for(size_t i = 0; i != 16; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p16, tmp, ws); + for(size_t i = 0; i != 8; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p8, tmp, ws); + + for(size_t i = 0; i != 4; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p4, tmp, ws); + + for(size_t i = 0; i != 2; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, p2, tmp, ws); + + for(size_t i = 0; i != 2; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + return r; + } + +/** +* The NIST P-384 curve +*/ +class CurveGFp_P384 final : 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_mod_p(BigInt& x, secure_vector<word>& ws) const override { redc_p384(x, ws); } + BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override; + }; + +BigInt CurveGFp_P384::invert_element(const BigInt& x, secure_vector<word>& ws) const + { + BigInt r, x2, x3, x15, x30, tmp, rl; + + r = x; + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + x2 = r; + + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + x3 = r; + + for(size_t i = 0; i != 3; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x3, tmp, ws); + + rl = r; + for(size_t i = 0; i != 6; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + for(size_t i = 0; i != 3; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x3, tmp, ws); + + x15 = r; + for(size_t i = 0; i != 15; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x15, tmp, ws); + + x30 = r; + for(size_t i = 0; i != 30; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x30, tmp, ws); + + rl = r; + for(size_t i = 0; i != 60; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 120; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + for(size_t i = 0; i != 15; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x15, tmp, ws); + + for(size_t i = 0; i != 31; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x30, tmp, ws); + + for(size_t i = 0; i != 2; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x2, tmp, ws); + + for(size_t i = 0; i != 94; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x30, tmp, ws); + + for(size_t i = 0; i != 2; ++i) + curve_sqr_tmp(r, tmp, ws); + + curve_mul_tmp(r, x, tmp, ws); + + return r; + } + +#endif + +/** +* The NIST P-521 curve +*/ +class CurveGFp_P521 final : 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_mod_p(BigInt& x, secure_vector<word>& ws) const override { redc_p521(x, ws); } + BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override; + }; + +BigInt CurveGFp_P521::invert_element(const BigInt& x, secure_vector<word>& ws) const + { + BigInt r; + BigInt rl; + BigInt a7; + BigInt tmp; + + curve_sqr(r, x, ws); + curve_mul_tmp(r, x, tmp, ws); + + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + rl = r; + + for(size_t i = 0; i != 3; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + a7 = r; // need this value later + + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + rl = r; + for(size_t i = 0; i != 8; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 16; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 32; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 64; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 128; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + rl = r; + for(size_t i = 0; i != 256; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, rl, tmp, ws); + + for(size_t i = 0; i != 7; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, a7, tmp, ws); + + for(size_t i = 0; i != 2; ++i) + curve_sqr_tmp(r, tmp, ws); + curve_mul_tmp(r, x, tmp, ws); + + return r; + } + +} + +std::shared_ptr<CurveGFp_Repr> +CurveGFp::choose_repr(const BigInt& p, const BigInt& a, const BigInt& b) + { +#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 == prime_p224()) + return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P224(a, b)); + if(p == prime_p256()) + return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P256(a, b)); + if(p == prime_p384()) + return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P384(a, b)); +#endif + + 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/libs/3rdparty/botan/src/lib/pubkey/ec_group/curve_gfp.h b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/curve_gfp.h new file mode 100644 index 0000000000..ce3fe4eba8 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/curve_gfp.h @@ -0,0 +1,269 @@ +/* +* Elliptic curves over GF(p) +* +* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke +* 2010-2011,2012,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_GFP_CURVE_H_ +#define BOTAN_GFP_CURVE_H_ + +#include <botan/bigint.h> +#include <memory> + +namespace Botan { + +class BOTAN_UNSTABLE_API CurveGFp_Repr + { + public: + virtual ~CurveGFp_Repr() = default; + + virtual const BigInt& get_p() const = 0; + virtual const BigInt& get_a() const = 0; + virtual const BigInt& get_b() const = 0; + + virtual size_t get_p_words() const = 0; + + virtual size_t get_ws_size() const = 0; + + virtual bool is_one(const BigInt& x) const = 0; + + virtual bool a_is_zero() const = 0; + + virtual bool a_is_minus_3() const = 0; + + /* + * Returns to_curve_rep(get_a()) + */ + virtual const BigInt& get_a_rep() const = 0; + + /* + * Returns to_curve_rep(get_b()) + */ + virtual const BigInt& get_b_rep() const = 0; + + /* + * Returns to_curve_rep(1) + */ + virtual const BigInt& get_1_rep() const = 0; + + virtual void redc_mod_p(BigInt& z, secure_vector<word>& ws) const = 0; + + virtual BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const = 0; + + virtual void to_curve_rep(BigInt& x, secure_vector<word>& ws) const = 0; + + virtual void from_curve_rep(BigInt& x, secure_vector<word>& ws) const = 0; + + void curve_mul(BigInt& z, const BigInt& x, const BigInt& y, + secure_vector<word>& ws) const + { + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + curve_mul_words(z, x.data(), x.size(), y, ws); + } + + virtual void curve_mul_words(BigInt& z, + const word x_words[], + const size_t x_size, + const BigInt& y, + secure_vector<word>& ws) const = 0; + + void curve_sqr(BigInt& z, const BigInt& x, + secure_vector<word>& ws) const + { + BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words); + curve_sqr_words(z, x.data(), x.size(), ws); + } + + virtual void curve_sqr_words(BigInt& z, + const word x_words[], + size_t x_size, + secure_vector<word>& ws) const = 0; + }; + +/** +* This class represents an elliptic curve over GF(p) +* +* There should not be any reason for applications to use this type. +* If you need EC primitives use the interfaces EC_Group and PointGFp +* +* It is likely this class will be removed entirely in a future major +* release. +*/ +class BOTAN_UNSTABLE_API CurveGFp final + { + public: + + /** + * Create an uninitialized CurveGFp + */ + CurveGFp() = default; + + /** + * Construct the elliptic curve E: y^2 = x^3 + ax + b over GF(p) + * @param p prime number of the field + * @param a first coefficient + * @param b second coefficient + */ + CurveGFp(const BigInt& p, const BigInt& a, const BigInt& b) : + m_repr(choose_repr(p, a, b)) + { + } + + CurveGFp(const CurveGFp&) = default; + + CurveGFp& operator=(const CurveGFp&) = default; + + /** + * @return curve coefficient a + */ + const BigInt& get_a() const { return m_repr->get_a(); } + + /** + * @return curve coefficient b + */ + const BigInt& get_b() const { return m_repr->get_b(); } + + /** + * Get prime modulus of the field of the curve + * @return prime modulus of the field of the curve + */ + const BigInt& get_p() const { return m_repr->get_p(); } + + size_t get_p_words() const { return m_repr->get_p_words(); } + + size_t get_ws_size() const { return m_repr->get_ws_size(); } + + const BigInt& get_a_rep() const { return m_repr->get_a_rep(); } + + const BigInt& get_b_rep() const { return m_repr->get_b_rep(); } + + const BigInt& get_1_rep() const { return m_repr->get_1_rep(); } + + bool a_is_minus_3() const { return m_repr->a_is_minus_3(); } + bool a_is_zero() const { return m_repr->a_is_zero(); } + + bool is_one(const BigInt& x) const { return m_repr->is_one(x); } + + BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const + { + return m_repr->invert_element(x, ws); + } + + void to_rep(BigInt& x, secure_vector<word>& ws) const + { + m_repr->to_curve_rep(x, ws); + } + + void from_rep(BigInt& x, secure_vector<word>& ws) const + { + m_repr->from_curve_rep(x, ws); + } + + BigInt from_rep(const BigInt& x, secure_vector<word>& ws) const + { + BigInt xt(x); + m_repr->from_curve_rep(xt, ws); + return xt; + } + + // TODO: from_rep taking && ref + + void redc_mod_p(BigInt& z, secure_vector<word>& ws) const + { + m_repr->redc_mod_p(z, ws); + } + + void mul(BigInt& z, const BigInt& x, const BigInt& y, secure_vector<word>& ws) const + { + m_repr->curve_mul(z, x, y, ws); + } + + void mul(BigInt& z, const word x_w[], size_t x_size, + const BigInt& y, secure_vector<word>& ws) const + { + m_repr->curve_mul_words(z, x_w, x_size, y, ws); + } + + void sqr(BigInt& z, const BigInt& x, secure_vector<word>& ws) const + { + m_repr->curve_sqr(z, x, ws); + } + + void sqr(BigInt& z, const word x_w[], size_t x_size, secure_vector<word>& ws) const + { + m_repr->curve_sqr_words(z, x_w, x_size, ws); + } + + BigInt mul(const BigInt& x, const BigInt& y, secure_vector<word>& ws) const + { + return mul_to_tmp(x, y, ws); + } + + BigInt sqr(const BigInt& x, secure_vector<word>& ws) const + { + return sqr_to_tmp(x, ws); + } + + BigInt mul_to_tmp(const BigInt& x, const BigInt& y, secure_vector<word>& ws) const + { + BigInt z; + m_repr->curve_mul(z, x, y, ws); + return z; + } + + BigInt sqr_to_tmp(const BigInt& x, secure_vector<word>& ws) const + { + BigInt z; + m_repr->curve_sqr(z, x, ws); + return z; + } + + void swap(CurveGFp& other) + { + std::swap(m_repr, other.m_repr); + } + + /** + * Equality operator + * @param other a curve + * @return true iff *this is the same as other + */ + inline bool operator==(const CurveGFp& other) const + { + if(m_repr.get() == other.m_repr.get()) + return true; + + return (get_p() == other.get_p()) && + (get_a() == other.get_a()) && + (get_b() == other.get_b()); + } + + private: + static std::shared_ptr<CurveGFp_Repr> + choose_repr(const BigInt& p, const BigInt& a, const BigInt& b); + + std::shared_ptr<CurveGFp_Repr> m_repr; + }; + +inline bool operator!=(const CurveGFp& lhs, const CurveGFp& rhs) + { + return !(lhs == rhs); + } + +} + +namespace std { + +template<> inline +void swap<Botan::CurveGFp>(Botan::CurveGFp& curve1, + Botan::CurveGFp& curve2) BOTAN_NOEXCEPT + { + curve1.swap(curve2); + } + +} // namespace std + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/ec_group.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/ec_group.cpp new file mode 100644 index 0000000000..586603507e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/ec_group.cpp @@ -0,0 +1,765 @@ +/* +* ECC Domain Parameters +* +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* (C) 2008,2018 Jack Lloyd +* (C) 2018 Tobias Niemann +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ec_group.h> +#include <botan/internal/point_mul.h> +#include <botan/ber_dec.h> +#include <botan/der_enc.h> +#include <botan/oids.h> +#include <botan/pem.h> +#include <botan/reducer.h> +#include <botan/mutex.h> +#include <botan/rng.h> +#include <vector> + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include <botan/system_rng.h> +#elif defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_32) + #include <botan/hmac_drbg.h> +#endif + +namespace Botan { + +class EC_Group_Data final + { + public: + + EC_Group_Data(const BigInt& p, + const BigInt& a, + const BigInt& b, + const BigInt& g_x, + const BigInt& g_y, + const BigInt& order, + const BigInt& cofactor, + const OID& oid) : + m_curve(p, a, b), + m_base_point(m_curve, g_x, g_y), + m_g_x(g_x), + m_g_y(g_y), + m_order(order), + m_cofactor(cofactor), + m_mod_order(order), + m_base_mult(m_base_point, m_mod_order), + m_oid(oid), + m_p_bits(p.bits()), + m_order_bits(order.bits()), + m_a_is_minus_3(a == p - 3), + m_a_is_zero(a.is_zero()) + { + } + + bool match(const BigInt& p, const BigInt& a, const BigInt& b, + const BigInt& g_x, const BigInt& g_y, + const BigInt& order, const BigInt& cofactor) const + { + return (this->p() == p && + this->a() == a && + this->b() == b && + this->order() == order && + this->cofactor() == cofactor && + this->g_x() == g_x && + this->g_y() == g_y); + } + + const OID& oid() const { return m_oid; } + const BigInt& p() const { return m_curve.get_p(); } + const BigInt& a() const { return m_curve.get_a(); } + const BigInt& b() const { return m_curve.get_b(); } + const BigInt& order() const { return m_order; } + const BigInt& cofactor() const { return m_cofactor; } + const BigInt& g_x() const { return m_g_x; } + const BigInt& g_y() const { return m_g_y; } + + size_t p_bits() const { return m_p_bits; } + size_t p_bytes() const { return (m_p_bits + 7) / 8; } + + size_t order_bits() const { return m_order_bits; } + size_t order_bytes() const { return (m_order_bits + 7) / 8; } + + const CurveGFp& curve() const { return m_curve; } + const PointGFp& base_point() const { return m_base_point; } + + bool a_is_minus_3() const { return m_a_is_minus_3; } + bool a_is_zero() const { return m_a_is_zero; } + + BigInt mod_order(const BigInt& x) const { return m_mod_order.reduce(x); } + + BigInt square_mod_order(const BigInt& x) const + { + return m_mod_order.square(x); + } + + BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const + { + return m_mod_order.multiply(x, y); + } + + BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const + { + return m_mod_order.multiply(m_mod_order.multiply(x, y), z); + } + + BigInt inverse_mod_order(const BigInt& x) const + { + return inverse_mod(x, m_order); + } + + PointGFp blinded_base_point_multiply(const BigInt& k, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws) const + { + return m_base_mult.mul(k, rng, m_order, ws); + } + + private: + CurveGFp m_curve; + PointGFp m_base_point; + + BigInt m_g_x; + BigInt m_g_y; + BigInt m_order; + BigInt m_cofactor; + Modular_Reducer m_mod_order; + PointGFp_Base_Point_Precompute m_base_mult; + OID m_oid; + size_t m_p_bits; + size_t m_order_bits; + bool m_a_is_minus_3; + bool m_a_is_zero; + }; + +class EC_Group_Data_Map final + { + public: + EC_Group_Data_Map() {} + + size_t clear() + { + lock_guard_type<mutex_type> lock(m_mutex); + size_t count = m_registered_curves.size(); + m_registered_curves.clear(); + return count; + } + + std::shared_ptr<EC_Group_Data> lookup(const OID& oid) + { + lock_guard_type<mutex_type> lock(m_mutex); + + for(auto i : m_registered_curves) + { + if(i->oid() == oid) + return i; + } + + // Not found, check hardcoded data + std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid); + + if(data) + { + m_registered_curves.push_back(data); + return data; + } + + // Nope, unknown curve + return std::shared_ptr<EC_Group_Data>(); + } + + std::shared_ptr<EC_Group_Data> lookup_or_create(const BigInt& p, + const BigInt& a, + const BigInt& b, + const BigInt& g_x, + const BigInt& g_y, + const BigInt& order, + const BigInt& cofactor, + const OID& oid) + { + lock_guard_type<mutex_type> lock(m_mutex); + + for(auto i : m_registered_curves) + { + if(oid.has_value()) + { + if(i->oid() == oid) + return i; + else if(i->oid().has_value()) + continue; + } + + if(i->match(p, a, b, g_x, g_y, order, cofactor)) + return i; + } + + // Not found - if OID is set try looking up that way + + if(oid.has_value()) + { + // Not located in existing store - try hardcoded data set + std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid); + + if(data) + { + m_registered_curves.push_back(data); + return data; + } + } + + // Not found or no OID, add data and return + return add_curve(p, a, b, g_x, g_y, order, cofactor, oid); + } + + private: + + std::shared_ptr<EC_Group_Data> add_curve(const BigInt& p, + const BigInt& a, + const BigInt& b, + const BigInt& g_x, + const BigInt& g_y, + const BigInt& order, + const BigInt& cofactor, + const OID& oid) + { + std::shared_ptr<EC_Group_Data> d = + std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid); + + // This function is always called with the lock held + m_registered_curves.push_back(d); + return d; + } + + mutex_type m_mutex; + std::vector<std::shared_ptr<EC_Group_Data>> m_registered_curves; + }; + +//static +EC_Group_Data_Map& EC_Group::ec_group_data() + { + /* + * This exists purely to ensure the allocator is constructed before g_ec_data, + * which ensures that its destructor runs after ~g_ec_data is complete. + */ + + static Allocator_Initializer g_init_allocator; + static EC_Group_Data_Map g_ec_data; + return g_ec_data; + } + +//static +size_t EC_Group::clear_registered_curve_data() + { + return ec_group_data().clear(); + } + +//static +std::shared_ptr<EC_Group_Data> +EC_Group::load_EC_group_info(const char* p_str, + const char* a_str, + const char* b_str, + const char* g_x_str, + const char* g_y_str, + const char* order_str, + const OID& oid) + { + const BigInt p(p_str); + const BigInt a(a_str); + const BigInt b(b_str); + const BigInt g_x(g_x_str); + const BigInt g_y(g_y_str); + const BigInt order(order_str); + const BigInt cofactor(1); // implicit + + return std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid); + } + +//static +std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[], size_t len) + { + BER_Decoder ber(bits, len); + BER_Object obj = ber.get_next_object(); + + if(obj.type() == NULL_TAG) + { + throw Decoding_Error("Cannot handle ImplicitCA ECC parameters"); + } + else if(obj.type() == OBJECT_ID) + { + OID dom_par_oid; + BER_Decoder(bits, len).decode(dom_par_oid); + return ec_group_data().lookup(dom_par_oid); + } + else if(obj.type() == SEQUENCE) + { + BigInt p, a, b, order, cofactor; + std::vector<uint8_t> base_pt; + std::vector<uint8_t> seed; + + BER_Decoder(bits, len) + .start_cons(SEQUENCE) + .decode_and_check<size_t>(1, "Unknown ECC param version code") + .start_cons(SEQUENCE) + .decode_and_check(OID("1.2.840.10045.1.1"), + "Only prime ECC fields supported") + .decode(p) + .end_cons() + .start_cons(SEQUENCE) + .decode_octet_string_bigint(a) + .decode_octet_string_bigint(b) + .decode_optional_string(seed, BIT_STRING, BIT_STRING) + .end_cons() + .decode(base_pt, OCTET_STRING) + .decode(order) + .decode(cofactor) + .end_cons() + .verify_end(); + +#if defined(BOTAN_HAS_SYSTEM_RNG) + System_RNG rng; +#elif defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_32) + /* + * This is not ideal because the data is attacker controlled, but + * it seems like it would be difficult for someone to come up + * with an valid ASN.1 encoding where the prime happened to pass + * Miller-Rabin test with exactly the values chosen when + * HMAC_DRBG is seeded with the overall data. + */ + HMAC_DRBG rng("SHA-256"); + rng.add_entropy(bits, len); +#else + Null_RNG rng; +#endif + + if(p.bits() < 64 || p.is_negative() || (is_prime(p, rng) == false)) + throw Decoding_Error("Invalid ECC p parameter"); + + if(a.is_negative() || a >= p) + throw Decoding_Error("Invalid ECC a parameter"); + + if(b <= 0 || b >= p) + throw Decoding_Error("Invalid ECC b parameter"); + + if(order <= 0) + throw Decoding_Error("Invalid ECC order parameter"); + + if(cofactor <= 0 || cofactor >= 16) + throw Decoding_Error("Invalid ECC cofactor parameter"); + + std::pair<BigInt, BigInt> base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b); + + return ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, order, cofactor, OID()); + } + else + { + throw Decoding_Error("Unexpected tag while decoding ECC domain params"); + } + } + +EC_Group::EC_Group() + { + } + +EC_Group::~EC_Group() + { + // shared_ptr possibly freed here + } + +EC_Group::EC_Group(const OID& domain_oid) + { + this->m_data = ec_group_data().lookup(domain_oid); + if(!this->m_data) + throw Invalid_Argument("Unknown EC_Group " + domain_oid.as_string()); + } + +EC_Group::EC_Group(const std::string& str) + { + if(str == "") + return; // no initialization / uninitialized + + try + { + OID oid = OIDS::lookup(str); + if(oid.empty() == false) + m_data = ec_group_data().lookup(oid); + } + catch(Invalid_OID&) + { + } + + if(m_data == nullptr) + { + if(str.size() > 30 && str.substr(0, 29) == "-----BEGIN EC PARAMETERS-----") + { + // OK try it as PEM ... + secure_vector<uint8_t> ber = PEM_Code::decode_check_label(str, "EC PARAMETERS"); + this->m_data = BER_decode_EC_group(ber.data(), ber.size()); + } + } + + if(m_data == nullptr) + throw Invalid_Argument("Unknown ECC group '" + str + "'"); + } + +//static +std::string EC_Group::PEM_for_named_group(const std::string& name) + { + try + { + EC_Group group(name); + return group.PEM_encode(); + } + catch(...) + { + return ""; + } + } + +EC_Group::EC_Group(const BigInt& p, + const BigInt& a, + const BigInt& b, + const BigInt& base_x, + const BigInt& base_y, + const BigInt& order, + const BigInt& cofactor, + const OID& oid) + { + m_data = ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid); + } + +EC_Group::EC_Group(const std::vector<uint8_t>& ber) + { + m_data = BER_decode_EC_group(ber.data(), ber.size()); + } + +const EC_Group_Data& EC_Group::data() const + { + if(m_data == nullptr) + throw Invalid_State("EC_Group uninitialized"); + return *m_data; + } + +const CurveGFp& EC_Group::get_curve() const + { + return data().curve(); + } + +bool EC_Group::a_is_minus_3() const + { + return data().a_is_minus_3(); + } + +bool EC_Group::a_is_zero() const + { + return data().a_is_zero(); + } + +size_t EC_Group::get_p_bits() const + { + return data().p_bits(); + } + +size_t EC_Group::get_p_bytes() const + { + return data().p_bytes(); + } + +size_t EC_Group::get_order_bits() const + { + return data().order_bits(); + } + +size_t EC_Group::get_order_bytes() const + { + return data().order_bytes(); + } + +const BigInt& EC_Group::get_p() const + { + return data().p(); + } + +const BigInt& EC_Group::get_a() const + { + return data().a(); + } + +const BigInt& EC_Group::get_b() const + { + return data().b(); + } + +const PointGFp& EC_Group::get_base_point() const + { + return data().base_point(); + } + +const BigInt& EC_Group::get_order() const + { + return data().order(); + } + +const BigInt& EC_Group::get_g_x() const + { + return data().g_x(); + } + +const BigInt& EC_Group::get_g_y() const + { + return data().g_y(); + } + +const BigInt& EC_Group::get_cofactor() const + { + return data().cofactor(); + } + +BigInt EC_Group::mod_order(const BigInt& k) const + { + return data().mod_order(k); + } + +BigInt EC_Group::square_mod_order(const BigInt& x) const + { + return data().square_mod_order(x); + } + +BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y) const + { + return data().multiply_mod_order(x, y); + } + +BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const + { + return data().multiply_mod_order(x, y, z); + } + +BigInt EC_Group::inverse_mod_order(const BigInt& x) const + { + return data().inverse_mod_order(x); + } + +const OID& EC_Group::get_curve_oid() const + { + return data().oid(); + } + +PointGFp EC_Group::OS2ECP(const uint8_t bits[], size_t len) const + { + return Botan::OS2ECP(bits, len, data().curve()); + } + +PointGFp EC_Group::point(const BigInt& x, const BigInt& y) const + { + // TODO: randomize the representation? + return PointGFp(data().curve(), x, y); + } + +PointGFp EC_Group::point_multiply(const BigInt& x, const PointGFp& pt, const BigInt& y) const + { + PointGFp_Multi_Point_Precompute xy_mul(get_base_point(), pt); + return xy_mul.multi_exp(x, y); + } + +PointGFp EC_Group::blinded_base_point_multiply(const BigInt& k, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws) const + { + return data().blinded_base_point_multiply(k, rng, ws); + } + +BigInt EC_Group::blinded_base_point_multiply_x(const BigInt& k, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws) const + { + const PointGFp pt = data().blinded_base_point_multiply(k, rng, ws); + + if(pt.is_zero()) + return 0; + return pt.get_affine_x(); + } + +BigInt EC_Group::random_scalar(RandomNumberGenerator& rng) const + { + return BigInt::random_integer(rng, 1, get_order()); + } + +PointGFp EC_Group::blinded_var_point_multiply(const PointGFp& point, + const BigInt& k, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws) const + { + PointGFp_Var_Point_Precompute mul(point, rng, ws); + return mul.mul(k, rng, get_order(), ws); + } + +PointGFp EC_Group::zero_point() const + { + return PointGFp(data().curve()); + } + +std::vector<uint8_t> +EC_Group::DER_encode(EC_Group_Encoding form) const + { + std::vector<uint8_t> output; + + DER_Encoder der(output); + + if(form == EC_DOMPAR_ENC_EXPLICIT) + { + const size_t ecpVers1 = 1; + const OID curve_type("1.2.840.10045.1.1"); // prime field + + const size_t p_bytes = get_p_bytes(); + + der.start_cons(SEQUENCE) + .encode(ecpVers1) + .start_cons(SEQUENCE) + .encode(curve_type) + .encode(get_p()) + .end_cons() + .start_cons(SEQUENCE) + .encode(BigInt::encode_1363(get_a(), p_bytes), + OCTET_STRING) + .encode(BigInt::encode_1363(get_b(), p_bytes), + OCTET_STRING) + .end_cons() + .encode(get_base_point().encode(PointGFp::UNCOMPRESSED), OCTET_STRING) + .encode(get_order()) + .encode(get_cofactor()) + .end_cons(); + } + else if(form == EC_DOMPAR_ENC_OID) + { + const OID oid = get_curve_oid(); + if(oid.empty()) + { + throw Encoding_Error("Cannot encode EC_Group as OID because OID not set"); + } + der.encode(oid); + } + else if(form == EC_DOMPAR_ENC_IMPLICITCA) + { + der.encode_null(); + } + else + { + throw Internal_Error("EC_Group::DER_encode: Unknown encoding"); + } + + return output; + } + +std::string EC_Group::PEM_encode() const + { + const std::vector<uint8_t> der = DER_encode(EC_DOMPAR_ENC_EXPLICIT); + return PEM_Code::encode(der, "EC PARAMETERS"); + } + +bool EC_Group::operator==(const EC_Group& other) const + { + if(m_data == other.m_data) + return true; // same shared rep + + /* + * No point comparing order/cofactor as they are uniquely determined + * by the curve equation (p,a,b) and the base point. + */ + return (get_p() == other.get_p() && + get_a() == other.get_a() && + get_b() == other.get_b() && + get_g_x() == other.get_g_x() && + get_g_y() == other.get_g_y()); + } + +bool EC_Group::verify_public_element(const PointGFp& point) const + { + //check that public point is not at infinity + if(point.is_zero()) + return false; + + //check that public point is on the curve + if(point.on_the_curve() == false) + return false; + + //check that public point has order q + if((point * get_order()).is_zero() == false) + return false; + + if(get_cofactor() > 1) + { + if((point * get_cofactor()).is_zero()) + return false; + } + + return true; + } + +bool EC_Group::verify_group(RandomNumberGenerator& rng, + bool) const + { + const BigInt& p = get_p(); + const BigInt& a = get_a(); + const BigInt& b = get_b(); + const BigInt& order = get_order(); + const PointGFp& base_point = get_base_point(); + + if(a < 0 || a >= p) + return false; + if(b <= 0 || b >= p) + return false; + if(order <= 0) + return false; + + //check if field modulus is prime + if(!is_prime(p, rng, 128)) + { + return false; + } + + //check if order is prime + if(!is_prime(order, rng, 128)) + { + return false; + } + + //compute the discriminant: 4*a^3 + 27*b^2 which must be nonzero + const Modular_Reducer mod_p(p); + + const BigInt discriminant = mod_p.reduce( + mod_p.multiply(4, mod_p.cube(a)) + + mod_p.multiply(27, mod_p.square(b))); + + if(discriminant == 0) + { + return false; + } + + //check for valid cofactor + if(get_cofactor() < 1) + { + return false; + } + + //check if the base point is on the curve + if(!base_point.on_the_curve()) + { + return false; + } + if((base_point * get_cofactor()).is_zero()) + { + return false; + } + //check if order of the base point is correct + if(!(base_point * order).is_zero()) + { + return false; + } + + return true; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/ec_group.h b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/ec_group.h new file mode 100644 index 0000000000..f8c1c1a123 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/ec_group.h @@ -0,0 +1,372 @@ +/* +* ECC Domain Parameters +* +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECC_DOMAIN_PARAMETERS_H_ +#define BOTAN_ECC_DOMAIN_PARAMETERS_H_ + +#include <botan/point_gfp.h> +#include <botan/asn1_oid.h> +#include <memory> +#include <set> + +namespace Botan { + +/** +* This class represents elliptic curce domain parameters +*/ +enum EC_Group_Encoding { + EC_DOMPAR_ENC_EXPLICIT = 0, + EC_DOMPAR_ENC_IMPLICITCA = 1, + EC_DOMPAR_ENC_OID = 2 +}; + +class CurveGFp; + +class EC_Group_Data; +class EC_Group_Data_Map; + +/** +* Class representing an elliptic curve +* +* The internal representation is stored in a shared_ptr, so copying an +* EC_Group is inexpensive. +*/ +class BOTAN_PUBLIC_API(2,0) EC_Group final + { + public: + + /** + * Construct Domain paramers from specified parameters + * @param curve elliptic curve + * @param base_point a base point + * @param order the order of the base point + * @param cofactor the cofactor + */ + BOTAN_DEPRECATED("Use version taking all BigInts") + EC_Group(const CurveGFp& curve, + const PointGFp& base_point, + const BigInt& order, + const BigInt& cofactor) : + EC_Group(curve.get_p(), + curve.get_a(), + curve.get_b(), + base_point.get_affine_x(), + base_point.get_affine_y(), + order, + cofactor) {} + + /** + * Construct Domain paramers from specified parameters + * @param p the elliptic curve p + * @param a the elliptic curve a param + * @param b the elliptic curve b param + * @param base_x the x coordinate of the base point + * @param base_y the y coordinate of the base point + * @param order the order of the base point + * @param cofactor the cofactor + * @param oid an optional OID used to identify this curve + */ + EC_Group(const BigInt& p, + const BigInt& a, + const BigInt& b, + const BigInt& base_x, + const BigInt& base_y, + const BigInt& order, + const BigInt& cofactor, + const OID& oid = OID()); + + /** + * Decode a BER encoded ECC domain parameter set + * @param ber_encoding the bytes of the BER encoding + */ + explicit EC_Group(const std::vector<uint8_t>& ber_encoding); + + /** + * Create an EC domain by OID (or throw if unknown) + * @param oid the OID of the EC domain to create + */ + explicit EC_Group(const OID& oid); + + /** + * Create an EC domain from PEM encoding (as from PEM_encode), or + * from an OID name (eg "secp256r1", or "1.2.840.10045.3.1.7") + * @param pem_or_oid PEM-encoded data, or an OID + */ + explicit EC_Group(const std::string& pem_or_oid); + + /** + * Create an uninitialized EC_Group + */ + EC_Group(); + + ~EC_Group(); + + /** + * Create the DER encoding of this domain + * @param form of encoding to use + * @returns bytes encododed as DER + */ + std::vector<uint8_t> DER_encode(EC_Group_Encoding form) const; + + /** + * Return the PEM encoding (always in explicit form) + * @return string containing PEM data + */ + std::string PEM_encode() const; + + /** + * Return domain parameter curve + * @result domain parameter curve + */ + BOTAN_DEPRECATED("Avoid CurveGFp") const CurveGFp& get_curve() const; + + /** + * Return if a == -3 mod p + */ + bool a_is_minus_3() const; + + /** + * Return if a == 0 mod p + */ + bool a_is_zero() const; + + /** + * Return the size of p in bits (same as get_p().bits()) + */ + size_t get_p_bits() const; + + /** + * Return the size of p in bits (same as get_p().bytes()) + */ + size_t get_p_bytes() const; + + /** + * Return the size of group order in bits (same as get_order().bits()) + */ + size_t get_order_bits() const; + + /** + * Return the size of p in bytes (same as get_order().bytes()) + */ + size_t get_order_bytes() const; + + /** + * Return the prime modulus of the field + */ + const BigInt& get_p() const; + + /** + * Return the a parameter of the elliptic curve equation + */ + const BigInt& get_a() const; + + /** + * Return the b parameter of the elliptic curve equation + */ + const BigInt& get_b() const; + + /** + * Return group base point + * @result base point + */ + const PointGFp& get_base_point() const; + + /** + * Return the x coordinate of the base point + */ + const BigInt& get_g_x() const; + + /** + * Return the y coordinate of the base point + */ + const BigInt& get_g_y() const; + + /** + * Return the order of the base point + * @result order of the base point + */ + const BigInt& get_order() const; + + /* + * Reduce x modulo the order + */ + BigInt mod_order(const BigInt& x) const; + + /* + * Return inverse of x modulo the order + */ + BigInt inverse_mod_order(const BigInt& x) const; + + /* + * Reduce (x*x) modulo the order + */ + BigInt square_mod_order(const BigInt& x) const; + + /* + * Reduce (x*y) modulo the order + */ + BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const; + + /* + * Reduce (x*y*z) modulo the order + */ + BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const; + + /** + * Return the cofactor + * @result the cofactor + */ + const BigInt& get_cofactor() const; + + /** + * Check if y is a plausible point on the curve + * + * In particular, checks that it is a point on the curve, not infinity, + * and that it has order matching the group. + */ + bool verify_public_element(const PointGFp& y) const; + + /** + * Return the OID of these domain parameters + * @result the OID as a string + */ + std::string BOTAN_DEPRECATED("Use get_curve_oid") get_oid() const { return get_curve_oid().as_string(); } + + /** + * Return the OID of these domain parameters + * @result the OID + */ + const OID& get_curve_oid() const; + + /** + * Return a point on this curve with the affine values x, y + */ + PointGFp point(const BigInt& x, const BigInt& y) const; + + /** + * Multi exponentiate. Not constant time. + * @return base_point*x + pt*y + */ + PointGFp point_multiply(const BigInt& x, const PointGFp& pt, const BigInt& y) const; + + /** + * Blinded point multiplication, attempts resistance to side channels + * @param k the scalar + * @param rng a random number generator + * @param ws a temp workspace + * @return base_point*k + */ + PointGFp blinded_base_point_multiply(const BigInt& k, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws) const; + + /** + * Blinded point multiplication, attempts resistance to side channels + * Returns just the x coordinate of the point + * + * @param k the scalar + * @param rng a random number generator + * @param ws a temp workspace + * @return x coordinate of base_point*k + */ + BigInt blinded_base_point_multiply_x(const BigInt& k, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws) const; + + /** + * Blinded point multiplication, attempts resistance to side channels + * @param point input point + * @param k the scalar + * @param rng a random number generator + * @param ws a temp workspace + * @return point*k + */ + PointGFp blinded_var_point_multiply(const PointGFp& point, + const BigInt& k, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws) const; + + /** + * Return a random scalar ie an integer in [1,order) + */ + BigInt random_scalar(RandomNumberGenerator& rng) const; + + /** + * Return the zero (or infinite) point on this curve + */ + PointGFp zero_point() const; + + PointGFp OS2ECP(const uint8_t bits[], size_t len) const; + + template<typename Alloc> + PointGFp OS2ECP(const std::vector<uint8_t, Alloc>& vec) const + { + return this->OS2ECP(vec.data(), vec.size()); + } + + bool initialized() const { return (m_data != nullptr); } + + /** + * Verify EC_Group domain + * @returns true if group is valid. false otherwise + */ + bool verify_group(RandomNumberGenerator& rng, + bool strong = false) const; + + bool operator==(const EC_Group& other) const; + + /** + * Return PEM representation of named EC group + * Deprecated: Use EC_Group(name).PEM_encode() if this is needed + */ + static std::string BOTAN_DEPRECATED("See header comment") PEM_for_named_group(const std::string& name); + + /** + * Return a set of known named EC groups + */ + static const std::set<std::string>& known_named_groups(); + + /* + * For internal use only + */ + static std::shared_ptr<EC_Group_Data> EC_group_info(const OID& oid); + + static size_t clear_registered_curve_data(); + + private: + static EC_Group_Data_Map& ec_group_data(); + + static std::shared_ptr<EC_Group_Data> BER_decode_EC_group(const uint8_t bits[], size_t len); + + static std::shared_ptr<EC_Group_Data> + load_EC_group_info(const char* p, + const char* a, + const char* b, + const char* g_x, + const char* g_y, + const char* order, + const OID& oid); + + // Member data + const EC_Group_Data& data() const; + std::shared_ptr<EC_Group_Data> m_data; + }; + +inline bool operator!=(const EC_Group& lhs, + const EC_Group& rhs) + { + return !(lhs == rhs); + } + +// For compatibility with 1.8 +typedef EC_Group EC_Domain_Params; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/ec_named.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/ec_named.cpp new file mode 100644 index 0000000000..ba91b5eaaf --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/ec_named.cpp @@ -0,0 +1,289 @@ +/* +* List of ECC groups +* (C) 2013,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ec_group.h> + +namespace Botan { + +//static +std::shared_ptr<EC_Group_Data> EC_Group::EC_group_info(const OID& oid) + { + // P-256 + if(oid == OID{1,2,840,10045,3,1,7}) + return load_EC_group_info("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", + "0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", + "0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", + "0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", + "0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", + "0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", + oid); + + // P-384 + if(oid == OID{1,3,132,0,34}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", + "0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", + "0xAA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", + "0x3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", + oid); + // P-521 + if(oid == OID{1,3,132,0,35}) + return load_EC_group_info("0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", + "0x51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", + "0xC6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", + "0x11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", + "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", + oid); + + // brainpool160r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,1}) + return load_EC_group_info("0xE95E4A5F737059DC60DFC7AD95B3D8139515620F", + "0x340E7BE2A280EB74E2BE61BADA745D97E8F7C300", + "0x1E589A8595423412134FAA2DBDEC95C8D8675E58", + "0xBED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3", + "0x1667CB477A1A8EC338F94741669C976316DA6321", + "0xE95E4A5F737059DC60DF5991D45029409E60FC09", + oid); + // brainpool192r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,3}) + return load_EC_group_info("0xC302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", + "0x6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", + "0x469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", + "0xC0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6", + "0x14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F", + "0xC302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", + oid); + // brainpool224r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,5}) + return load_EC_group_info("0xD7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", + "0x68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", + "0x2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", + "0xD9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D", + "0x58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD", + "0xD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", + oid); + // brainpool256r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,7}) + return load_EC_group_info("0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", + "0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", + "0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", + "0x8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", + "0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", + "0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", + oid); + // brainpool320r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,9}) + return load_EC_group_info("0xD35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", + "0x3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", + "0x520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", + "0x43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611", + "0x14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1", + "0xD35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", + oid); + // brainpool384r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,11}) + return load_EC_group_info("0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", + "0x7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", + "0x4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", + "0x1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", + "0x8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", + "0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", + oid); + // brainpool512r1 + if(oid == OID{1,3,36,3,3,2,8,1,1,13}) + return load_EC_group_info("0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", + "0x7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", + "0x3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", + "0x81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", + "0x7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", + "0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", + oid); + // frp256v1 + if(oid == OID{1,2,250,1,223,101,256,1}) + return load_EC_group_info("0xF1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C03", + "0xF1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C00", + "0xEE353FCA5428A9300D4ABA754A44C00FDFEC0C9AE4B1A1803075ED967B7BB73F", + "0xB6B3D4C356C139EB31183D4749D423958C27D2DCAF98B70164C97A2DD98F5CFF", + "0x6142E0F7C8B204911F9271F0F3ECEF8C2701C307E8E4C9E183115A1554062CFB", + "0xF1FD178C0B3AD58F10126DE8CE42435B53DC67E140D2BF941FFDD459C6D655E1", + oid); + // gost_256A + if(oid == OID{1,2,643,2,2,35,1}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94", + "0xA6", + "0x1", + "0x8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893", + oid); + // secp160k1 + if(oid == OID{1,3,132,0,9}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", + "0x0", + "0x7", + "0x3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", + "0x938CF935318FDCED6BC28286531733C3F03C4FEE", + "0x100000000000000000001B8FA16DFAB9ACA16B6B3", + oid); + // secp160r1 + if(oid == OID{1,3,132,0,8}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", + "0x1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", + "0x4A96B5688EF573284664698968C38BB913CBFC82", + "0x23A628553168947D59DCC912042351377AC5FB32", + "0x100000000000000000001F4C8F927AED3CA752257", + oid); + // secp160r2 + if(oid == OID{1,3,132,0,30}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70", + "0xB4E134D3FB59EB8BAB57274904664D5AF50388BA", + "0x52DCB034293A117E1F4FF11B30F7199D3144CE6D", + "0xFEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", + "0x100000000000000000000351EE786A818F3A1A16B", + oid); + // secp192k1 + if(oid == OID{1,3,132,0,31}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", + "0x0", + "0x3", + "0xDB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", + "0x9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", + "0xFFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", + oid); + // secp192r1 + if(oid == OID{1,2,840,10045,3,1,1}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "0x64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", + "0x188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", + "0x7192B95FFC8DA78631011ED6B24CDD573F977A11E794811", + "0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", + oid); + // secp224k1 + if(oid == OID{1,3,132,0,32}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", + "0x0", + "0x5", + "0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", + "0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", + "0x10000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", + oid); + // secp224r1 + if(oid == OID{1,3,132,0,33}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", + "0xB4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", + "0xB70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", + "0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", + oid); + // secp256k1 + if(oid == OID{1,3,132,0,10}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + "0x0", + "0x7", + "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", + "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", + oid); + + // sm2p256v1 + if(oid == OID{1,2,156,10197,1,301}) + return load_EC_group_info("0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", + "0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", + "0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", + "0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", + "0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", + "0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", + oid); + // x962_p192v2 + if(oid == OID{1,2,840,10045,3,1,2}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "0xCC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953", + "0xEEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A", + "0x6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15", + "0xFFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31", + oid); + // x962_p192v3 + if(oid == OID{1,2,840,10045,3,1,3}) + return load_EC_group_info("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", + "0x22123DC2395A05CAA7423DAECCC94760A7D462256BD56916", + "0x7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896", + "0x38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0", + "0xFFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13", + oid); + // x962_p239v1 + if(oid == OID{1,2,840,10045,3,1,4}) + return load_EC_group_info("0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "0x6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A", + "0xFFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF", + "0x7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE", + "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B", + oid); + // x962_p239v2 + if(oid == OID{1,2,840,10045,3,1,5}) + return load_EC_group_info("0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "0x617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C", + "0x38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7", + "0x5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA", + "0x7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063", + oid); + // x962_p239v3 + if(oid == OID{1,2,840,10045,3,1,6}) + return load_EC_group_info("0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", + "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", + "0x255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E", + "0x6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A", + "0x1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3", + "0x7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551", + oid); + + return std::shared_ptr<EC_Group_Data>(); + } + +//static +const std::set<std::string>& EC_Group::known_named_groups() + { + static const std::set<std::string> named_groups = { + "secp160k1", + "secp160r1", + "secp160r2", + "secp192k1", + "secp192r1", + "secp224k1", + "secp224r1", + "secp256k1", + "secp256r1", + "secp384r1", + "secp521r1", + "brainpool160r1", + "brainpool192r1", + "brainpool224r1", + "brainpool256r1", + "brainpool320r1", + "brainpool384r1", + "brainpool512r1", + "x962_p192v2", + "x962_p192v3", + "x962_p239v1", + "x962_p239v2", + "x962_p239v3", + "gost_256A", + "frp256v1", + "sm2p256v1" + }; + return named_groups; + } +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/info.txt new file mode 100644 index 0000000000..e382e25a5e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/info.txt @@ -0,0 +1,20 @@ +<defines> +ECC_GROUP -> 20170225 +EC_CURVE_GFP -> 20131128 +</defines> + +<requires> +asn1 +numbertheory +pem +</requires> + +<header:internal> +point_mul.h +</header:internal> + +<header:public> +curve_gfp.h +ec_group.h +point_gfp.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_gfp.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_gfp.cpp new file mode 100644 index 0000000000..77803de78f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_gfp.cpp @@ -0,0 +1,727 @@ +/* +* Point arithmetic on elliptic curves over GF(p) +* +* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke +* 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/rng.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +PointGFp::PointGFp(const CurveGFp& curve) : + m_curve(curve), + m_coord_x(0), + m_coord_y(curve.get_1_rep()), + m_coord_z(0) + { + // Assumes Montgomery rep of zero is zero + } + +PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) : + m_curve(curve), + m_coord_x(x), + m_coord_y(y), + m_coord_z(m_curve.get_1_rep()) + { + if(x <= 0 || x >= curve.get_p()) + throw Invalid_Argument("Invalid PointGFp affine x"); + if(y <= 0 || y >= curve.get_p()) + throw Invalid_Argument("Invalid PointGFp affine y"); + + secure_vector<word> monty_ws(m_curve.get_ws_size()); + m_curve.to_rep(m_coord_x, monty_ws); + m_curve.to_rep(m_coord_y, monty_ws); + } + +void PointGFp::randomize_repr(RandomNumberGenerator& rng) + { + secure_vector<word> ws(m_curve.get_ws_size()); + randomize_repr(rng, ws); + } + +void PointGFp::randomize_repr(RandomNumberGenerator& rng, secure_vector<word>& ws) + { + const BigInt mask = BigInt::random_integer(rng, 2, m_curve.get_p()); + + /* + * No reason to convert this to Montgomery representation first, + * just pretend the random mask was chosen as Redc(mask) and the + * random mask we generated above is in the Montgomery + * representation. + * //m_curve.to_rep(mask, ws); + */ + const BigInt mask2 = m_curve.sqr_to_tmp(mask, ws); + const BigInt mask3 = m_curve.mul_to_tmp(mask2, mask, ws); + + m_coord_x = m_curve.mul_to_tmp(m_coord_x, mask2, ws); + m_coord_y = m_curve.mul_to_tmp(m_coord_y, mask3, ws); + m_coord_z = m_curve.mul_to_tmp(m_coord_z, mask, ws); + } + +namespace { + +inline void resize_ws(std::vector<BigInt>& ws_bn, size_t cap_size) + { + BOTAN_ASSERT(ws_bn.size() >= PointGFp::WORKSPACE_SIZE, + "Expected size for PointGFp workspace"); + + for(size_t i = 0; i != ws_bn.size(); ++i) + if(ws_bn[i].size() < cap_size) + ws_bn[i].get_word_vector().resize(cap_size); + } + +inline bool all_zeros(const word x[], size_t len) + { + word z = 0; + for(size_t i = 0; i != len; ++i) + z |= x[i]; + return (z == 0); + } + +} + +void PointGFp::add_affine(const word x_words[], size_t x_size, + const word y_words[], size_t y_size, + std::vector<BigInt>& ws_bn) + { + if(all_zeros(x_words, x_size) && all_zeros(y_words, y_size)) + return; + + if(is_zero()) + { + m_coord_x.set_words(x_words, x_size); + m_coord_y.set_words(y_words, y_size); + m_coord_z = m_curve.get_1_rep(); + return; + } + + resize_ws(ws_bn, m_curve.get_ws_size()); + + secure_vector<word>& ws = ws_bn[0].get_word_vector(); + secure_vector<word>& sub_ws = ws_bn[1].get_word_vector(); + + BigInt& T0 = ws_bn[2]; + BigInt& T1 = ws_bn[3]; + BigInt& T2 = ws_bn[4]; + BigInt& T3 = ws_bn[5]; + BigInt& T4 = ws_bn[6]; + + /* + https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 + simplified with Z2 = 1 + */ + + const BigInt& p = m_curve.get_p(); + + m_curve.sqr(T3, m_coord_z, ws); // z1^2 + m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2 + + m_curve.mul(T2, m_coord_z, T3, ws); // z1^3 + m_curve.mul(T0, y_words, y_size, T2, ws); // y2*z1^3 + + T4.mod_sub(m_coord_x, p, sub_ws); // x2*z1^2 - x1*z2^2 + + T0.mod_sub(m_coord_y, p, sub_ws); + + if(T4.is_zero()) + { + if(T0.is_zero()) + { + mult2(ws_bn); + return; + } + + // setting to zero: + m_coord_x = 0; + m_coord_y = m_curve.get_1_rep(); + m_coord_z = 0; + return; + } + + m_curve.sqr(T2, T4, ws); + + m_curve.mul(T3, m_coord_x, T2, ws); + + m_curve.mul(T1, T2, T4, ws); + + m_curve.sqr(m_coord_x, T0, ws); + m_coord_x.mod_sub(T1, p, sub_ws); + m_coord_x.mod_sub(T3, p, sub_ws); + m_coord_x.mod_sub(T3, p, sub_ws); + + T3.mod_sub(m_coord_x, p, sub_ws); + + T2 = m_coord_y; + m_curve.mul(T2, T0, T3, ws); + m_curve.mul(T3, m_coord_y, T1, ws); + T2.mod_sub(T3, p, sub_ws); + m_coord_y = T2; + + m_curve.mul(T3, m_coord_z, T4, ws); + m_coord_z = T3; + } + +void PointGFp::add(const word x_words[], size_t x_size, + const word y_words[], size_t y_size, + const word z_words[], size_t z_size, + std::vector<BigInt>& ws_bn) + { + if(all_zeros(x_words, x_size) && all_zeros(z_words, z_size)) + return; + + if(is_zero()) + { + m_coord_x.set_words(x_words, x_size); + m_coord_y.set_words(y_words, y_size); + m_coord_z.set_words(z_words, z_size); + return; + } + + resize_ws(ws_bn, m_curve.get_ws_size()); + + secure_vector<word>& ws = ws_bn[0].get_word_vector(); + secure_vector<word>& sub_ws = ws_bn[1].get_word_vector(); + + BigInt& T0 = ws_bn[2]; + BigInt& T1 = ws_bn[3]; + BigInt& T2 = ws_bn[4]; + BigInt& T3 = ws_bn[5]; + BigInt& T4 = ws_bn[6]; + BigInt& T5 = ws_bn[7]; + + /* + https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 + */ + + const BigInt& p = m_curve.get_p(); + + m_curve.sqr(T0, z_words, z_size, ws); // z2^2 + m_curve.mul(T1, m_coord_x, T0, ws); // x1*z2^2 + m_curve.mul(T3, z_words, z_size, T0, ws); // z2^3 + m_curve.mul(T2, m_coord_y, T3, ws); // y1*z2^3 + + m_curve.sqr(T3, m_coord_z, ws); // z1^2 + m_curve.mul(T4, x_words, x_size, T3, ws); // x2*z1^2 + + m_curve.mul(T5, m_coord_z, T3, ws); // z1^3 + m_curve.mul(T0, y_words, y_size, T5, ws); // y2*z1^3 + + T4.mod_sub(T1, p, sub_ws); // x2*z1^2 - x1*z2^2 + + T0.mod_sub(T2, p, sub_ws); + + if(T4.is_zero()) + { + if(T0.is_zero()) + { + mult2(ws_bn); + return; + } + + // setting to zero: + m_coord_x = 0; + m_coord_y = m_curve.get_1_rep(); + m_coord_z = 0; + return; + } + + m_curve.sqr(T5, T4, ws); + + m_curve.mul(T3, T1, T5, ws); + + m_curve.mul(T1, T5, T4, ws); + + m_curve.sqr(m_coord_x, T0, ws); + m_coord_x.mod_sub(T1, p, sub_ws); + m_coord_x.mod_sub(T3, p, sub_ws); + m_coord_x.mod_sub(T3, p, sub_ws); + + T3.mod_sub(m_coord_x, p, sub_ws); + + m_curve.mul(m_coord_y, T0, T3, ws); + m_curve.mul(T3, T2, T1, ws); + + m_coord_y.mod_sub(T3, p, sub_ws); + + m_curve.mul(T3, z_words, z_size, m_coord_z, ws); + m_curve.mul(m_coord_z, T3, T4, ws); + } + +void PointGFp::mult2i(size_t iterations, std::vector<BigInt>& ws_bn) + { + if(iterations == 0) + return; + + if(m_coord_y.is_zero()) + { + *this = PointGFp(m_curve); // setting myself to zero + return; + } + + /* + TODO we can save 2 squarings per iteration by computing + a*Z^4 using values cached from previous iteration + */ + for(size_t i = 0; i != iterations; ++i) + mult2(ws_bn); + } + +// *this *= 2 +void PointGFp::mult2(std::vector<BigInt>& ws_bn) + { + if(is_zero()) + return; + + if(m_coord_y.is_zero()) + { + *this = PointGFp(m_curve); // setting myself to zero + return; + } + + resize_ws(ws_bn, m_curve.get_ws_size()); + + secure_vector<word>& ws = ws_bn[0].get_word_vector(); + secure_vector<word>& sub_ws = ws_bn[1].get_word_vector(); + + BigInt& T0 = ws_bn[2]; + BigInt& T1 = ws_bn[3]; + BigInt& T2 = ws_bn[4]; + BigInt& T3 = ws_bn[5]; + BigInt& T4 = ws_bn[6]; + + /* + https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc + */ + const BigInt& p = m_curve.get_p(); + + m_curve.sqr(T0, m_coord_y, ws); + + m_curve.mul(T1, m_coord_x, T0, ws); + T1 <<= 2; // * 4 + m_curve.redc_mod_p(T1, sub_ws); + + if(m_curve.a_is_zero()) + { + // if a == 0 then 3*x^2 + a*z^4 is just 3*x^2 + m_curve.sqr(T4, m_coord_x, ws); // x^2 + T4 *= 3; // 3*x^2 + m_curve.redc_mod_p(T4, sub_ws); + } + else if(m_curve.a_is_minus_3()) + { + /* + if a == -3 then + 3*x^2 + a*z^4 == 3*x^2 - 3*z^4 == 3*(x^2-z^4) == 3*(x-z^2)*(x+z^2) + */ + m_curve.sqr(T3, m_coord_z, ws); // z^2 + + // (x-z^2) + T2 = m_coord_x; + T2.mod_sub(T3, p, sub_ws); + + // (x+z^2) + T3.mod_add(m_coord_x, p, sub_ws); + + m_curve.mul(T4, T2, T3, ws); // (x-z^2)*(x+z^2) + + T4 *= 3; // 3*(x-z^2)*(x+z^2) + m_curve.redc_mod_p(T4, sub_ws); + } + else + { + m_curve.sqr(T3, m_coord_z, ws); // z^2 + m_curve.sqr(T4, T3, ws); // z^4 + m_curve.mul(T3, m_curve.get_a_rep(), T4, ws); // a*z^4 + + m_curve.sqr(T4, m_coord_x, ws); // x^2 + T4 *= 3; // 3*x^2 + T4.mod_add(T3, p, sub_ws); // 3*x^2 + a*z^4 + } + + m_curve.sqr(T2, T4, ws); + T2.mod_sub(T1, p, sub_ws); + T2.mod_sub(T1, p, sub_ws); + + m_curve.sqr(T3, T0, ws); + T3 <<= 3; + m_curve.redc_mod_p(T3, sub_ws); + + T1.mod_sub(T2, p, sub_ws); + + m_curve.mul(T0, T4, T1, ws); + T0.mod_sub(T3, p, sub_ws); + + m_coord_x = T2; + + m_curve.mul(T2, m_coord_y, m_coord_z, ws); + T2 <<= 1; + m_curve.redc_mod_p(T2, sub_ws); + + m_coord_y = T0; + m_coord_z = T2; + } + +// arithmetic operators +PointGFp& PointGFp::operator+=(const PointGFp& rhs) + { + std::vector<BigInt> ws(PointGFp::WORKSPACE_SIZE); + add(rhs, ws); + return *this; + } + +PointGFp& PointGFp::operator-=(const PointGFp& rhs) + { + PointGFp minus_rhs = PointGFp(rhs).negate(); + + if(is_zero()) + *this = minus_rhs; + else + *this += minus_rhs; + + return *this; + } + +PointGFp& PointGFp::operator*=(const BigInt& scalar) + { + *this = scalar * *this; + return *this; + } + +PointGFp operator*(const BigInt& scalar, const PointGFp& point) + { + BOTAN_DEBUG_ASSERT(point.on_the_curve()); + + const size_t scalar_bits = scalar.bits(); + + std::vector<BigInt> ws(PointGFp::WORKSPACE_SIZE); + + PointGFp R[2] = { point.zero(), point }; + + 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); + } + + if(scalar.is_negative()) + R[0].negate(); + + BOTAN_DEBUG_ASSERT(R[0].on_the_curve()); + + return R[0]; + } + +//static +void PointGFp::force_all_affine(std::vector<PointGFp>& points, + secure_vector<word>& ws) + { + if(points.size() <= 1) + { + for(size_t i = 0; i != points.size(); ++i) + points[i].force_affine(); + return; + } + + /* + For >= 2 points use Montgomery's trick + + See Algorithm 2.26 in "Guide to Elliptic Curve Cryptography" + (Hankerson, Menezes, Vanstone) + + TODO is it really necessary to save all k points in c? + */ + + const CurveGFp& curve = points[0].m_curve; + const BigInt& rep_1 = curve.get_1_rep(); + + if(ws.size() < curve.get_ws_size()) + ws.resize(curve.get_ws_size()); + + std::vector<BigInt> c(points.size()); + c[0] = points[0].m_coord_z; + + for(size_t i = 1; i != points.size(); ++i) + { + curve.mul(c[i], c[i-1], points[i].m_coord_z, ws); + } + + BigInt s_inv = curve.invert_element(c[c.size()-1], ws); + + BigInt z_inv, z2_inv, z3_inv; + + for(size_t i = points.size() - 1; i != 0; i--) + { + PointGFp& point = points[i]; + + curve.mul(z_inv, s_inv, c[i-1], ws); + + s_inv = curve.mul_to_tmp(s_inv, point.m_coord_z, ws); + + curve.sqr(z2_inv, z_inv, ws); + curve.mul(z3_inv, z2_inv, z_inv, ws); + point.m_coord_x = curve.mul_to_tmp(point.m_coord_x, z2_inv, ws); + point.m_coord_y = curve.mul_to_tmp(point.m_coord_y, z3_inv, ws); + point.m_coord_z = rep_1; + } + + curve.sqr(z2_inv, s_inv, ws); + curve.mul(z3_inv, z2_inv, s_inv, ws); + points[0].m_coord_x = curve.mul_to_tmp(points[0].m_coord_x, z2_inv, ws); + points[0].m_coord_y = curve.mul_to_tmp(points[0].m_coord_y, z3_inv, ws); + points[0].m_coord_z = rep_1; + } + +void PointGFp::force_affine() + { + if(is_zero()) + throw Invalid_State("Cannot convert zero ECC point to affine"); + + secure_vector<word> ws; + + const BigInt z_inv = m_curve.invert_element(m_coord_z, ws); + const BigInt z2_inv = m_curve.sqr_to_tmp(z_inv, ws); + const BigInt z3_inv = m_curve.mul_to_tmp(z_inv, z2_inv, ws); + m_coord_x = m_curve.mul_to_tmp(m_coord_x, z2_inv, ws); + m_coord_y = m_curve.mul_to_tmp(m_coord_y, z3_inv, ws); + m_coord_z = m_curve.get_1_rep(); + } + +bool PointGFp::is_affine() const + { + return m_curve.is_one(m_coord_z); + } + +BigInt PointGFp::get_affine_x() const + { + if(is_zero()) + throw Illegal_Transformation("Cannot convert zero point to affine"); + + secure_vector<word> monty_ws; + + if(is_affine()) + return m_curve.from_rep(m_coord_x, monty_ws); + + BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); + z2 = m_curve.invert_element(z2, monty_ws); + + BigInt r; + m_curve.mul(r, m_coord_x, z2, monty_ws); + m_curve.from_rep(r, monty_ws); + return r; + } + +BigInt PointGFp::get_affine_y() const + { + if(is_zero()) + throw Illegal_Transformation("Cannot convert zero point to affine"); + + secure_vector<word> monty_ws; + + if(is_affine()) + return m_curve.from_rep(m_coord_y, monty_ws); + + const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); + const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws); + const BigInt z3_inv = m_curve.invert_element(z3, monty_ws); + + BigInt r; + m_curve.mul(r, m_coord_y, z3_inv, monty_ws); + m_curve.from_rep(r, monty_ws); + return r; + } + +bool PointGFp::on_the_curve() const + { + /* + Is the point still on the curve?? (If everything is correct, the + point is always on its curve; then the function will return true. + If somehow the state is corrupted, which suggests a fault attack + (or internal computational error), then return false. + */ + if(is_zero()) + return true; + + secure_vector<word> monty_ws; + + const BigInt y2 = m_curve.from_rep(m_curve.sqr_to_tmp(m_coord_y, monty_ws), monty_ws); + const BigInt x3 = m_curve.mul_to_tmp(m_coord_x, m_curve.sqr_to_tmp(m_coord_x, monty_ws), monty_ws); + const BigInt ax = m_curve.mul_to_tmp(m_coord_x, m_curve.get_a_rep(), monty_ws); + const BigInt z2 = m_curve.sqr_to_tmp(m_coord_z, monty_ws); + + if(m_coord_z == z2) // Is z equal to 1 (in Montgomery form)? + { + if(y2 != m_curve.from_rep(x3 + ax + m_curve.get_b_rep(), monty_ws)) + return false; + } + + const BigInt z3 = m_curve.mul_to_tmp(m_coord_z, z2, monty_ws); + const BigInt ax_z4 = m_curve.mul_to_tmp(ax, m_curve.sqr_to_tmp(z2, monty_ws), monty_ws); + const BigInt b_z6 = m_curve.mul_to_tmp(m_curve.get_b_rep(), m_curve.sqr_to_tmp(z3, monty_ws), monty_ws); + + if(y2 != m_curve.from_rep(x3 + ax_z4 + b_z6, monty_ws)) + return false; + + return true; + } + +// swaps the states of *this and other, does not throw! +void PointGFp::swap(PointGFp& other) + { + 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); + } + +bool PointGFp::operator==(const PointGFp& other) const + { + if(m_curve != other.m_curve) + return false; + + // If this is zero, only equal if other is also zero + if(is_zero()) + return other.is_zero(); + + return (get_affine_x() == other.get_affine_x() && + get_affine_y() == other.get_affine_y()); + } + +// encoding and decoding +std::vector<uint8_t> PointGFp::encode(PointGFp::Compression_Type format) const + { + if(is_zero()) + return std::vector<uint8_t>(1); // single 0 byte + + const size_t p_bytes = m_curve.get_p().bytes(); + + const BigInt x = get_affine_x(); + const BigInt y = get_affine_y(); + + std::vector<uint8_t> result; + + if(format == PointGFp::UNCOMPRESSED) + { + result.resize(1 + 2*p_bytes); + result[0] = 0x04; + BigInt::encode_1363(&result[1], p_bytes, x); + BigInt::encode_1363(&result[1+p_bytes], p_bytes, y); + } + else if(format == PointGFp::COMPRESSED) + { + result.resize(1 + p_bytes); + result[0] = 0x02 | static_cast<uint8_t>(y.get_bit(0)); + BigInt::encode_1363(&result[1], p_bytes, x); + } + else if(format == PointGFp::HYBRID) + { + result.resize(1 + 2*p_bytes); + result[0] = 0x06 | static_cast<uint8_t>(y.get_bit(0)); + BigInt::encode_1363(&result[1], p_bytes, x); + BigInt::encode_1363(&result[1+p_bytes], p_bytes, y); + } + else + throw Invalid_Argument("EC2OSP illegal point encoding"); + + return result; + } + +namespace { + +BigInt decompress_point(bool yMod2, + const BigInt& x, + const BigInt& curve_p, + const BigInt& curve_a, + const BigInt& curve_b) + { + BigInt xpow3 = x * x * x; + + BigInt g = curve_a * x; + g += xpow3; + g += curve_b; + g = g % curve_p; + + BigInt z = ressol(g, curve_p); + + if(z < 0) + throw Illegal_Point("error during EC point decompression"); + + if(z.get_bit(0) != yMod2) + z = curve_p - z; + + return z; + } + +} + +PointGFp OS2ECP(const uint8_t data[], size_t data_len, + const CurveGFp& curve) + { + // Should we really be doing this? + if(data_len <= 1) + return PointGFp(curve); // return zero + + std::pair<BigInt, BigInt> xy = OS2ECP(data, data_len, curve.get_p(), curve.get_a(), curve.get_b()); + + PointGFp point(curve, xy.first, xy.second); + + if(!point.on_the_curve()) + throw Illegal_Point("OS2ECP: Decoded point was not on the curve"); + + return point; + } + +std::pair<BigInt, BigInt> OS2ECP(const uint8_t data[], size_t data_len, + const BigInt& curve_p, + const BigInt& curve_a, + const BigInt& curve_b) + { + if(data_len <= 1) + throw Decoding_Error("OS2ECP invalid point"); + + const uint8_t pc = data[0]; + + BigInt x, y; + + if(pc == 2 || pc == 3) + { + //compressed form + x = BigInt::decode(&data[1], data_len - 1); + + const bool y_mod_2 = ((pc & 0x01) == 1); + y = decompress_point(y_mod_2, x, curve_p, curve_a, curve_b); + } + else if(pc == 4) + { + const size_t l = (data_len - 1) / 2; + + // uncompressed form + x = BigInt::decode(&data[1], l); + y = BigInt::decode(&data[l+1], l); + } + else if(pc == 6 || pc == 7) + { + const size_t l = (data_len - 1) / 2; + + // hybrid form + x = BigInt::decode(&data[1], l); + y = BigInt::decode(&data[l+1], l); + + const bool y_mod_2 = ((pc & 0x01) == 1); + + if(decompress_point(y_mod_2, x, curve_p, curve_a, curve_b) != y) + throw Illegal_Point("OS2ECP: Decoding error in hybrid format"); + } + else + throw Invalid_Argument("OS2ECP: Unknown format type " + std::to_string(pc)); + + return std::make_pair(x, y); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_gfp.h b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_gfp.h new file mode 100644 index 0000000000..fa447bf87a --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_gfp.h @@ -0,0 +1,444 @@ +/* +* Point arithmetic on elliptic curves over GF(p) +* +* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke +* 2008-2011,2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_POINT_GFP_H_ +#define BOTAN_POINT_GFP_H_ + +#include <botan/curve_gfp.h> +#include <botan/exceptn.h> +#include <vector> + +namespace Botan { + +/** +* Exception thrown if you try to convert a zero point to an affine +* coordinate +*/ +class BOTAN_PUBLIC_API(2,0) Illegal_Transformation final : public Exception + { + public: + explicit Illegal_Transformation(const std::string& err = + "Requested transformation is not possible") : + Exception(err) {} + }; + +/** +* Exception thrown if some form of illegal point is decoded +*/ +class BOTAN_PUBLIC_API(2,0) Illegal_Point final : public Exception + { + public: + explicit Illegal_Point(const std::string& err = "Malformed ECP point detected") : + Exception(err) {} + }; + +/** +* This class represents one point on a curve of GF(p) +*/ +class BOTAN_PUBLIC_API(2,0) PointGFp final + { + public: + enum Compression_Type { + UNCOMPRESSED = 0, + COMPRESSED = 1, + HYBRID = 2 + }; + + enum { WORKSPACE_SIZE = 8 }; + + /** + * Construct an uninitialized PointGFp + */ + PointGFp() = default; + + /** + * Construct the zero point + * @param curve The base curve + */ + explicit PointGFp(const CurveGFp& curve); + + /** + * Copy constructor + */ + PointGFp(const PointGFp&) = default; + + /** + * Move Constructor + */ + PointGFp(PointGFp&& other) + { + this->swap(other); + } + + /** + * Standard Assignment + */ + PointGFp& operator=(const PointGFp&) = default; + + /** + * Move Assignment + */ + PointGFp& operator=(PointGFp&& other) + { + if(this != &other) + this->swap(other); + return (*this); + } + + /** + * Construct a point from its affine coordinates + * @param curve the base curve + * @param x affine x coordinate + * @param y affine y coordinate + */ + PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y); + + /** + * EC2OSP - elliptic curve to octet string primitive + * @param format which format to encode using + */ + std::vector<uint8_t> encode(PointGFp::Compression_Type format) const; + + /** + * += Operator + * @param rhs the PointGFp to add to the local value + * @result resulting PointGFp + */ + PointGFp& operator+=(const PointGFp& rhs); + + /** + * -= Operator + * @param rhs the PointGFp to subtract from the local value + * @result resulting PointGFp + */ + PointGFp& operator-=(const PointGFp& rhs); + + /** + * *= Operator + * @param scalar the PointGFp to multiply with *this + * @result resulting PointGFp + */ + PointGFp& operator*=(const BigInt& scalar); + + /** + * Negate this point + * @return *this + */ + PointGFp& negate() + { + if(!is_zero()) + m_coord_y = m_curve.get_p() - m_coord_y; + return *this; + } + + /** + * get affine x coordinate + * @result affine x coordinate + */ + BigInt get_affine_x() const; + + /** + * get affine y coordinate + * @result affine y coordinate + */ + BigInt get_affine_y() const; + + const BigInt& get_x() const { return m_coord_x; } + const BigInt& get_y() const { return m_coord_y; } + const BigInt& get_z() const { return m_coord_z; } + + void swap_coords(BigInt& new_x, BigInt& new_y, BigInt& new_z) + { + m_coord_x.swap(new_x); + m_coord_y.swap(new_y); + m_coord_z.swap(new_z); + } + + /** + * Force this point to affine coordinates + */ + void force_affine(); + + /** + * Force all points on the list to affine coordinates + */ + static void force_all_affine(std::vector<PointGFp>& points, + secure_vector<word>& ws); + + bool is_affine() const; + + /** + * Is this the point at infinity? + * @result true, if this point is at infinity, false otherwise. + */ + bool is_zero() const + { return (m_coord_x.is_zero() && m_coord_z.is_zero()); } + + /** + * Checks whether the point is to be found on the underlying + * curve; used to prevent fault attacks. + * @return if the point is on the curve + */ + bool on_the_curve() const; + + /** + * swaps the states of *this and other, does not throw! + * @param other the object to swap values with + */ + 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); + + /** + * Randomize the point representation + * The actual value (get_affine_x, get_affine_y) does not change + */ + void randomize_repr(RandomNumberGenerator& rng, secure_vector<word>& ws); + + /** + * Equality operator + */ + bool operator==(const PointGFp& other) const; + + /** + * Point addition + * @param other the point to add to *this + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void add(const PointGFp& other, std::vector<BigInt>& workspace) + { + BOTAN_ASSERT_NOMSG(m_curve == other.m_curve); + + const size_t p_words = m_curve.get_p_words(); + + add(other.m_coord_x.data(), std::min(p_words, other.m_coord_x.size()), + other.m_coord_y.data(), std::min(p_words, other.m_coord_y.size()), + other.m_coord_z.data(), std::min(p_words, other.m_coord_z.size()), + workspace); + } + + /** + * Point addition. Array version. + * + * @param x_words the words of the x coordinate of the other point + * @param x_size size of x_words + * @param y_words the words of the y coordinate of the other point + * @param y_size size of y_words + * @param z_words the words of the z coordinate of the other point + * @param z_size size of z_words + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void add(const word x_words[], size_t x_size, + const word y_words[], size_t y_size, + const word z_words[], size_t z_size, + std::vector<BigInt>& workspace); + + /** + * Point addition - mixed J+A + * @param other affine point to add - assumed to be affine! + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void add_affine(const PointGFp& other, std::vector<BigInt>& workspace) + { + BOTAN_ASSERT_NOMSG(m_curve == other.m_curve); + BOTAN_DEBUG_ASSERT(other.is_affine()); + + const size_t p_words = m_curve.get_p_words(); + add_affine(other.m_coord_x.data(), std::min(p_words, other.m_coord_x.size()), + other.m_coord_y.data(), std::min(p_words, other.m_coord_y.size()), + workspace); + } + + /** + * Point addition - mixed J+A. Array version. + * + * @param x_words the words of the x coordinate of the other point + * @param x_size size of x_words + * @param y_words the words of the y coordinate of the other point + * @param y_size size of y_words + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void add_affine(const word x_words[], size_t x_size, + const word y_words[], size_t y_size, + std::vector<BigInt>& workspace); + + /** + * Point doubling + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void mult2(std::vector<BigInt>& workspace); + + /** + * Repeated point doubling + * @param i number of doublings to perform + * @param workspace temp space, at least WORKSPACE_SIZE elements + */ + void mult2i(size_t i, std::vector<BigInt>& workspace); + + /** + * Point addition + * @param other the point to add to *this + * @param workspace temp space, at least WORKSPACE_SIZE elements + * @return other plus *this + */ + PointGFp plus(const PointGFp& other, std::vector<BigInt>& workspace) const + { + PointGFp x = (*this); + x.add(other, workspace); + return x; + } + + /** + * Point doubling + * @param workspace temp space, at least WORKSPACE_SIZE elements + * @return *this doubled + */ + PointGFp double_of(std::vector<BigInt>& workspace) const + { + PointGFp x = (*this); + x.mult2(workspace); + return x; + } + + /** + * Return the zero (aka infinite) point associated with this curve + */ + PointGFp zero() const { return PointGFp(m_curve); } + + /** + * Return base curve of this point + * @result the curve over GF(p) of this point + * + * You should not need to use this + */ + const CurveGFp& get_curve() const { return m_curve; } + + private: + CurveGFp m_curve; + BigInt m_coord_x, m_coord_y, m_coord_z; + }; + +/** +* Point multiplication operator +* @param scalar the scalar value +* @param point the point value +* @return scalar*point on the curve +*/ +BOTAN_PUBLIC_API(2,0) PointGFp operator*(const BigInt& scalar, const PointGFp& point); + +/** +* ECC point multiexponentiation - not constant time! +* @param p1 a point +* @param z1 a scalar +* @param p2 a point +* @param z2 a scalar +* @result (p1 * z1 + p2 * z2) +*/ +BOTAN_PUBLIC_API(2,0) PointGFp multi_exponentiate( + const PointGFp& p1, const BigInt& z1, + const PointGFp& p2, const BigInt& z2); + +// relational operators +inline bool operator!=(const PointGFp& lhs, const PointGFp& rhs) + { + return !(rhs == lhs); + } + +// arithmetic operators +inline PointGFp operator-(const PointGFp& lhs) + { + return PointGFp(lhs).negate(); + } + +inline PointGFp operator+(const PointGFp& lhs, const PointGFp& rhs) + { + PointGFp tmp(lhs); + return tmp += rhs; + } + +inline PointGFp operator-(const PointGFp& lhs, const PointGFp& rhs) + { + PointGFp tmp(lhs); + return tmp -= rhs; + } + +inline PointGFp operator*(const PointGFp& point, const BigInt& scalar) + { + return scalar * point; + } + +// encoding and decoding +inline secure_vector<uint8_t> BOTAN_DEPRECATED("Use PointGFp::encode") + EC2OSP(const PointGFp& point, uint8_t format) + { + std::vector<uint8_t> enc = point.encode(static_cast<PointGFp::Compression_Type>(format)); + return secure_vector<uint8_t>(enc.begin(), enc.end()); + } + +/** +* Perform point decoding +* Use EC_Group::OS2ECP instead +*/ +PointGFp BOTAN_PUBLIC_API(2,0) OS2ECP(const uint8_t data[], size_t data_len, + const CurveGFp& curve); + +/** +* Perform point decoding +* Use EC_Group::OS2ECP instead +* +* @param data the encoded point +* @param data_len length of data in bytes +* @param curve_p the curve equation prime +* @param curve_a the curve equation a parameter +* @param curve_b the curve equation b parameter +*/ +std::pair<BigInt, BigInt> BOTAN_UNSTABLE_API OS2ECP(const uint8_t data[], size_t data_len, + const BigInt& curve_p, + const BigInt& curve_a, + const BigInt& curve_b); + +template<typename Alloc> +PointGFp OS2ECP(const std::vector<uint8_t, Alloc>& data, const CurveGFp& curve) + { return OS2ECP(data.data(), data.size(), curve); } + +class PointGFp_Var_Point_Precompute; + +/** +* Deprecated API for point multiplication +* Use EC_Group::blinded_base_point_multiply or EC_Group::blinded_var_point_multiply +*/ +class BOTAN_PUBLIC_API(2,0) BOTAN_DEPRECATED("See comments") Blinded_Point_Multiply final + { + public: + Blinded_Point_Multiply(const PointGFp& base, const BigInt& order, size_t h = 0); + + ~Blinded_Point_Multiply(); + + PointGFp blinded_multiply(const BigInt& scalar, RandomNumberGenerator& rng); + private: + std::vector<BigInt> m_ws; + const BigInt& m_order; + std::unique_ptr<PointGFp_Var_Point_Precompute> m_point_mul; + }; + +} + +namespace std { + +template<> +inline void swap<Botan::PointGFp>(Botan::PointGFp& x, Botan::PointGFp& y) + { x.swap(y); } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_mul.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_mul.cpp new file mode 100644 index 0000000000..760f060ced --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_mul.cpp @@ -0,0 +1,375 @@ +/* +* (C) 2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/point_mul.h> +#include <botan/rng.h> +#include <botan/reducer.h> +#include <botan/internal/rounding.h> +#include <botan/internal/ct_utils.h> + +namespace Botan { + +PointGFp multi_exponentiate(const PointGFp& x, const BigInt& z1, + const PointGFp& y, const BigInt& z2) + { + PointGFp_Multi_Point_Precompute xy_mul(x, y); + return xy_mul.multi_exp(z1, z2); + } + +Blinded_Point_Multiply::Blinded_Point_Multiply(const PointGFp& base, + const BigInt& order, + size_t h) : + m_ws(PointGFp::WORKSPACE_SIZE), + m_order(order) + { + BOTAN_UNUSED(h); + Null_RNG null_rng; + m_point_mul.reset(new PointGFp_Var_Point_Precompute(base, null_rng, m_ws)); + } + +Blinded_Point_Multiply::~Blinded_Point_Multiply() + { + /* for ~unique_ptr */ + } + +PointGFp Blinded_Point_Multiply::blinded_multiply(const BigInt& scalar, + RandomNumberGenerator& rng) + { + return m_point_mul->mul(scalar, rng, m_order, m_ws); + } + +PointGFp_Base_Point_Precompute::PointGFp_Base_Point_Precompute(const PointGFp& base, + const Modular_Reducer& mod_order) : + m_base_point(base), + m_mod_order(mod_order), + m_p_words(base.get_curve().get_p().sig_words()), + m_T_size(base.get_curve().get_p().bits() + PointGFp_SCALAR_BLINDING_BITS + 1) + { + std::vector<BigInt> ws(PointGFp::WORKSPACE_SIZE); + + const size_t p_bits = base.get_curve().get_p().bits(); + + /* + * Some of the curves (eg secp160k1) have an order slightly larger than + * the size of the prime modulus. In all cases they are at most 1 bit + * longer. The +1 compensates for this. + */ + const size_t T_bits = round_up(p_bits + PointGFp_SCALAR_BLINDING_BITS + 1, 2) / 2; + + std::vector<PointGFp> T(3*T_bits); + T.resize(3*T_bits); + + T[0] = base; + T[1] = T[0]; + T[1].mult2(ws); + T[2] = T[1]; + T[2].add(T[0], ws); + + for(size_t i = 1; i != T_bits; ++i) + { + T[3*i+0] = T[3*i - 2]; + T[3*i+0].mult2(ws); + T[3*i+1] = T[3*i+0]; + T[3*i+1].mult2(ws); + T[3*i+2] = T[3*i+1]; + T[3*i+2].add(T[3*i+0], ws); + } + + PointGFp::force_all_affine(T, ws[0].get_word_vector()); + + m_W.resize(T.size() * 2 * m_p_words); + + word* p = &m_W[0]; + for(size_t i = 0; i != T.size(); ++i) + { + T[i].get_x().encode_words(p, m_p_words); + p += m_p_words; + T[i].get_y().encode_words(p, m_p_words); + p += m_p_words; + } + } + +PointGFp PointGFp_Base_Point_Precompute::mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector<BigInt>& ws) const + { + if(k.is_negative()) + throw Invalid_Argument("PointGFp_Base_Point_Precompute scalar must be positive"); + + // Choose a small mask m and use k' = k + m*order (Coron's 1st countermeasure) + const BigInt mask(rng, PointGFp_SCALAR_BLINDING_BITS); + + // Instead of reducing k mod group order should we alter the mask size?? + const BigInt scalar = m_mod_order.reduce(k) + group_order * mask; + + const size_t windows = round_up(scalar.bits(), 2) / 2; + + const size_t elem_size = 2*m_p_words; + + BOTAN_ASSERT(windows <= m_W.size() / (3*elem_size), + "Precomputed sufficient values for scalar mult"); + + PointGFp R = m_base_point.zero(); + + if(ws.size() < PointGFp::WORKSPACE_SIZE) + ws.resize(PointGFp::WORKSPACE_SIZE); + + // the precomputed multiples are not secret so use std::vector + std::vector<word> Wt(elem_size); + + for(size_t i = 0; i != windows; ++i) + { + const size_t window = windows - i - 1; + const size_t base_addr = (3*window)*elem_size; + + const word w = scalar.get_substring(2*window, 2); + + const word w_is_1 = CT::is_equal<word>(w, 1); + const word w_is_2 = CT::is_equal<word>(w, 2); + const word w_is_3 = CT::is_equal<word>(w, 3); + + for(size_t j = 0; j != elem_size; ++j) + { + const word w1 = m_W[base_addr + 0*elem_size + j]; + const word w2 = m_W[base_addr + 1*elem_size + j]; + const word w3 = m_W[base_addr + 2*elem_size + j]; + + Wt[j] = CT::select3<word>(w_is_1, w1, w_is_2, w2, w_is_3, w3, 0); + } + + R.add_affine(&Wt[0], m_p_words, &Wt[m_p_words], m_p_words, ws); + + if(i == 0) + { + /* + * Since we start with the top bit of the exponent we know the + * first window must have a non-zero element, and thus R is + * now a point other than the point at infinity. + */ + BOTAN_DEBUG_ASSERT(w != 0); + R.randomize_repr(rng, ws[0].get_word_vector()); + } + } + + BOTAN_DEBUG_ASSERT(R.on_the_curve()); + + return R; + } + +PointGFp_Var_Point_Precompute::PointGFp_Var_Point_Precompute(const PointGFp& point, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws) : + m_curve(point.get_curve()), + m_p_words(m_curve.get_p().sig_words()), + m_window_bits(4) + { + if(ws.size() < PointGFp::WORKSPACE_SIZE) + ws.resize(PointGFp::WORKSPACE_SIZE); + + std::vector<PointGFp> U(1U << m_window_bits); + U[0] = point.zero(); + U[1] = point; + + for(size_t i = 2; i < U.size(); i += 2) + { + U[i] = U[i/2].double_of(ws); + U[i+1] = U[i].plus(point, ws); + } + + // Hack to handle Blinded_Point_Multiply + if(rng.is_seeded()) + { + BigInt& mask = ws[0]; + BigInt& mask2 = ws[1]; + BigInt& mask3 = ws[2]; + BigInt& new_x = ws[3]; + BigInt& new_y = ws[4]; + BigInt& new_z = ws[5]; + secure_vector<word>& tmp = ws[6].get_word_vector(); + + const CurveGFp& curve = U[0].get_curve(); + + const size_t p_bits = curve.get_p().bits(); + + // Skipping zero point since it can't be randomized + for(size_t i = 1; i != U.size(); ++i) + { + mask.randomize(rng, p_bits - 1, false); + // Easy way of ensuring mask != 0 + mask.set_bit(0); + + curve.sqr(mask2, mask, tmp); + curve.mul(mask3, mask, mask2, tmp); + + curve.mul(new_x, U[i].get_x(), mask2, tmp); + curve.mul(new_y, U[i].get_y(), mask3, tmp); + curve.mul(new_z, U[i].get_z(), mask, tmp); + + U[i].swap_coords(new_x, new_y, new_z); + } + } + + m_T.resize(U.size() * 3 * m_p_words); + + word* p = &m_T[0]; + for(size_t i = 0; i != U.size(); ++i) + { + U[i].get_x().encode_words(p , m_p_words); + U[i].get_y().encode_words(p + m_p_words, m_p_words); + U[i].get_z().encode_words(p + 2*m_p_words, m_p_words); + p += 3*m_p_words; + } + } + +PointGFp PointGFp_Var_Point_Precompute::mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector<BigInt>& ws) const + { + if(k.is_negative()) + throw Invalid_Argument("PointGFp_Var_Point_Precompute scalar must be positive"); + if(ws.size() < PointGFp::WORKSPACE_SIZE) + ws.resize(PointGFp::WORKSPACE_SIZE); + + // Choose a small mask m and use k' = k + m*order (Coron's 1st countermeasure) + const BigInt mask(rng, PointGFp_SCALAR_BLINDING_BITS, false); + const BigInt scalar = k + group_order * mask; + + const size_t elem_size = 3*m_p_words; + const size_t window_elems = (1ULL << m_window_bits); + + size_t windows = round_up(scalar.bits(), m_window_bits) / m_window_bits; + PointGFp R(m_curve); + secure_vector<word> e(elem_size); + + if(windows > 0) + { + windows--; + + const uint32_t w = scalar.get_substring(windows*m_window_bits, m_window_bits); + + clear_mem(e.data(), e.size()); + for(size_t i = 1; i != window_elems; ++i) + { + const word wmask = CT::is_equal<word>(w, i); + + for(size_t j = 0; j != elem_size; ++j) + { + e[j] |= wmask & m_T[i * elem_size + j]; + } + } + + R.add(&e[0], m_p_words, &e[m_p_words], m_p_words, &e[2*m_p_words], m_p_words, 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, ws[0].get_word_vector()); + } + + while(windows) + { + R.mult2i(m_window_bits, ws); + + const uint32_t w = scalar.get_substring((windows-1)*m_window_bits, m_window_bits); + + clear_mem(e.data(), e.size()); + for(size_t i = 1; i != window_elems; ++i) + { + const word wmask = CT::is_equal<word>(w, i); + + for(size_t j = 0; j != elem_size; ++j) + e[j] |= wmask & m_T[i * elem_size + j]; + } + + R.add(&e[0], m_p_words, &e[m_p_words], m_p_words, &e[2*m_p_words], m_p_words, ws); + + windows--; + } + + BOTAN_DEBUG_ASSERT(R.on_the_curve()); + + return R; + } + + +PointGFp_Multi_Point_Precompute::PointGFp_Multi_Point_Precompute(const PointGFp& x, + const PointGFp& y) + { + std::vector<BigInt> ws(PointGFp::WORKSPACE_SIZE); + + PointGFp x2 = x; + x2.mult2(ws); + + const PointGFp x3(x2.plus(x, ws)); + + PointGFp y2 = y; + y2.mult2(ws); + + const PointGFp y3(y2.plus(y, ws)); + + m_M.reserve(15); + + m_M.push_back(x); + m_M.push_back(x2); + m_M.push_back(x3); + + m_M.push_back(y); + m_M.push_back(y.plus(x, ws)); + m_M.push_back(y.plus(x2, ws)); + m_M.push_back(y.plus(x3, ws)); + + m_M.push_back(y2); + m_M.push_back(y2.plus(x, ws)); + m_M.push_back(y2.plus(x2, ws)); + m_M.push_back(y2.plus(x3, ws)); + + m_M.push_back(y3); + m_M.push_back(y3.plus(x, ws)); + m_M.push_back(y3.plus(x2, ws)); + m_M.push_back(y3.plus(x3, ws)); + + PointGFp::force_all_affine(m_M, ws[0].get_word_vector()); + } + +PointGFp PointGFp_Multi_Point_Precompute::multi_exp(const BigInt& z1, + const BigInt& z2) const + { + std::vector<BigInt> ws(PointGFp::WORKSPACE_SIZE); + + const size_t z_bits = round_up(std::max(z1.bits(), z2.bits()), 2); + + PointGFp H = m_M[0].zero(); + + for(size_t i = 0; i != z_bits; i += 2) + { + if(i > 0) + { + H.mult2i(2, ws); + } + + const uint8_t z1_b = z1.get_substring(z_bits - i - 2, 2); + const uint8_t z2_b = z2.get_substring(z_bits - i - 2, 2); + + const uint8_t z12 = (4*z2_b) + z1_b; + + // This function is not intended to be const time + if(z12) + { + H.add_affine(m_M[z12-1], ws); + } + } + + if(z1.is_negative() != z2.is_negative()) + H.negate(); + + return H; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_mul.h b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_mul.h new file mode 100644 index 0000000000..dbaae29950 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ec_group/point_mul.h @@ -0,0 +1,84 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_POINT_MUL_H_ +#define BOTAN_POINT_MUL_H_ + +#include <botan/point_gfp.h> + +namespace Botan { + +class Modular_Reducer; + +static const size_t PointGFp_SCALAR_BLINDING_BITS = 80; + +class PointGFp_Base_Point_Precompute final + { + public: + PointGFp_Base_Point_Precompute(const PointGFp& base_point, + const Modular_Reducer& mod_order); + + PointGFp mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector<BigInt>& ws) const; + private: + const PointGFp& m_base_point; + const Modular_Reducer& m_mod_order; + + const size_t m_p_words; + const size_t m_T_size; + + /* + * This is a table of T_size * 3*p_word words + */ + std::vector<word> m_W; + }; + +class PointGFp_Var_Point_Precompute final + { + public: + PointGFp_Var_Point_Precompute(const PointGFp& point, + RandomNumberGenerator& rng, + std::vector<BigInt>& ws); + + PointGFp mul(const BigInt& k, + RandomNumberGenerator& rng, + const BigInt& group_order, + std::vector<BigInt>& ws) const; + private: + const CurveGFp m_curve; + const size_t m_p_words; + const size_t m_window_bits; + + /* + * Table of 2^window_bits * 3*2*p_word words + * Kept in locked vector since the base point might be sensitive + * (normally isn't in most protocols but hard to say anything + * categorically.) + */ + secure_vector<word> m_T; + }; + +class PointGFp_Multi_Point_Precompute final + { + public: + PointGFp_Multi_Point_Precompute(const PointGFp& g1, + const PointGFp& g2); + + /* + * Return (g1*k1 + g2*k2) + * Not constant time, intended to use with public inputs + */ + PointGFp multi_exp(const BigInt& k1, + const BigInt& k2) const; + private: + std::vector<PointGFp> m_M; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ecc_key/ecc_key.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/ecc_key/ecc_key.cpp new file mode 100644 index 0000000000..2c23c1b47e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ecc_key/ecc_key.cpp @@ -0,0 +1,201 @@ +/* +* ECC Key implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ecc_key.h> +#include <botan/numthry.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/secmem.h> +#include <botan/point_gfp.h> +#include <botan/workfactor.h> + +namespace Botan { + +size_t EC_PublicKey::key_length() const + { + return domain().get_p_bits(); + } + +size_t EC_PublicKey::estimated_strength() const + { + return ecp_work_factor(key_length()); + } + +EC_PublicKey::EC_PublicKey(const EC_Group& dom_par, + const PointGFp& pub_point) : + m_domain_params(dom_par), m_public_key(pub_point) + { + if (!dom_par.get_curve_oid().empty()) + m_domain_encoding = EC_DOMPAR_ENC_OID; + else + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + +#if 0 + if(domain().get_curve() != public_point().get_curve()) + throw Invalid_Argument("EC_PublicKey: curve mismatch in constructor"); +#endif + } + +EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits) : + m_domain_params{EC_Group(alg_id.get_parameters())}, + m_public_key{domain().OS2ECP(key_bits)} + { + if (!domain().get_curve_oid().empty()) + m_domain_encoding = EC_DOMPAR_ENC_OID; + else + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + } + +bool EC_PublicKey::check_key(RandomNumberGenerator& rng, + bool) const + { + return m_domain_params.verify_group(rng) && + m_domain_params.verify_public_element(public_point()); + } + + +AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), DER_domain()); + } + +std::vector<uint8_t> EC_PublicKey::public_key_bits() const + { + return public_point().encode(point_encoding()); + } + +void EC_PublicKey::set_point_encoding(PointGFp::Compression_Type enc) + { + if(enc != PointGFp::COMPRESSED && + enc != PointGFp::UNCOMPRESSED && + enc != PointGFp::HYBRID) + throw Invalid_Argument("Invalid point encoding for EC_PublicKey"); + + m_point_encoding = enc; + } + +void EC_PublicKey::set_parameter_encoding(EC_Group_Encoding form) + { + if(form != EC_DOMPAR_ENC_EXPLICIT && + form != EC_DOMPAR_ENC_IMPLICITCA && + form != EC_DOMPAR_ENC_OID) + throw Invalid_Argument("Invalid encoding form for EC-key object specified"); + + if((form == EC_DOMPAR_ENC_OID) && (m_domain_params.get_curve_oid().empty())) + throw Invalid_Argument("Invalid encoding form OID specified for " + "EC-key object whose corresponding domain " + "parameters are without oid"); + + m_domain_encoding = form; + } + +const BigInt& EC_PrivateKey::private_value() const + { + if(m_private_key == 0) + throw Invalid_State("EC_PrivateKey::private_value - uninitialized"); + + return m_private_key; + } + +/** +* EC_PrivateKey constructor +*/ +EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& ec_group, + const BigInt& x, + bool with_modular_inverse) + { + m_domain_params = ec_group; + if (!ec_group.get_curve_oid().empty()) + m_domain_encoding = EC_DOMPAR_ENC_OID; + else + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + if(x == 0) + { + m_private_key = ec_group.random_scalar(rng); + } + else + { + m_private_key = x; + } + + // Can't use rng here because ffi load functions use Null_RNG + if(with_modular_inverse) + { + // ECKCDSA + m_public_key = domain().get_base_point() * m_domain_params.inverse_mod_order(m_private_key); + } + else + { + m_public_key = domain().get_base_point() * m_private_key; + } + + BOTAN_ASSERT(m_public_key.on_the_curve(), + "Generated public key point was on the curve"); + } + +secure_vector<uint8_t> EC_PrivateKey::private_key_bits() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast<size_t>(1)) + .encode(BigInt::encode_1363(m_private_key, m_private_key.bytes()), + OCTET_STRING) + .end_cons() + .get_contents(); + } + +EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits, + bool with_modular_inverse) + { + m_domain_params = EC_Group(alg_id.get_parameters()); + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + if (!domain().get_curve_oid().empty()) + m_domain_encoding = EC_DOMPAR_ENC_OID; + else + m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; + + OID key_parameters; + secure_vector<uint8_t> public_key_bits; + + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode_and_check<size_t>(1, "Unknown version code for ECC key") + .decode_octet_string_bigint(m_private_key) + .decode_optional(key_parameters, ASN1_Tag(0), PRIVATE) + .decode_optional_string(public_key_bits, BIT_STRING, 1, PRIVATE) + .end_cons(); + + if(public_key_bits.empty()) + { + if(with_modular_inverse) + { + // ECKCDSA + m_public_key = domain().get_base_point() * m_domain_params.inverse_mod_order(m_private_key); + } + else + { + m_public_key = domain().get_base_point() * m_private_key; + } + + BOTAN_ASSERT(m_public_key.on_the_curve(), + "Public point derived from loaded key was on the curve"); + } + else + { + m_public_key = domain().OS2ECP(public_key_bits); + // OS2ECP verifies that the point is on the curve + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ecc_key/ecc_key.h b/src/libs/3rdparty/botan/src/lib/pubkey/ecc_key/ecc_key.h new file mode 100644 index 0000000000..ec2b5f9be3 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ecc_key/ecc_key.h @@ -0,0 +1,172 @@ +/* +* ECDSA +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECC_PUBLIC_KEY_BASE_H_ +#define BOTAN_ECC_PUBLIC_KEY_BASE_H_ + +#include <botan/ec_group.h> +#include <botan/pk_keys.h> + +namespace Botan { + +/** +* This class represents abstract ECC public keys. When encoding a key +* via an encoder that can be accessed via the corresponding member +* functions, the key will decide upon its internally stored encoding +* information whether to encode itself with or without domain +* parameters, or using the domain parameter oid. Furthermore, a public +* key without domain parameters can be decoded. In that case, it +* cannot be used for verification until its domain parameters are set +* by calling the corresponding member function. +*/ +class BOTAN_PUBLIC_API(2,0) EC_PublicKey : public virtual Public_Key + { + public: + /** + * Create a public key. + * @param dom_par EC domain parameters + * @param pub_point public point on the curve + */ + EC_PublicKey(const EC_Group& dom_par, + const PointGFp& pub_point); + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + EC_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits); + + EC_PublicKey(const EC_PublicKey& other) = default; + EC_PublicKey& operator=(const EC_PublicKey& other) = default; + virtual ~EC_PublicKey() = default; + + /** + * Get the public point of this key. + * @throw Invalid_State is thrown if the + * domain parameters of this point are not set + * @result the public point of this key + */ + const PointGFp& public_point() const { return m_public_key; } + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector<uint8_t> public_key_bits() const override; + + bool check_key(RandomNumberGenerator& rng, + bool strong) const override; + + /** + * Get the domain parameters of this key. + * @throw Invalid_State is thrown if the + * domain parameters of this point are not set + * @result the domain parameters of this key + */ + const EC_Group& domain() const { return m_domain_params; } + + /** + * Set the domain parameter encoding to be used when encoding this key. + * @param enc the encoding to use + */ + void set_parameter_encoding(EC_Group_Encoding enc); + + /** + * Set the point encoding method to be used when encoding this key. + * @param enc the encoding to use + */ + void set_point_encoding(PointGFp::Compression_Type enc); + + /** + * Return the DER encoding of this keys domain in whatever format + * is preset for this particular key + */ + std::vector<uint8_t> DER_domain() const + { return domain().DER_encode(domain_format()); } + + /** + * Get the domain parameter encoding to be used when encoding this key. + * @result the encoding to use + */ + EC_Group_Encoding domain_format() const + { return m_domain_encoding; } + + /** + * Get the point encoding method to be used when encoding this key. + * @result the encoding to use + */ + PointGFp::Compression_Type point_encoding() const + { return m_point_encoding; } + + size_t key_length() const override; + size_t estimated_strength() const override; + + protected: + EC_PublicKey() : m_domain_params{}, m_public_key{}, m_domain_encoding(EC_DOMPAR_ENC_EXPLICIT) + {} + + EC_Group m_domain_params; + PointGFp m_public_key; + EC_Group_Encoding m_domain_encoding; + PointGFp::Compression_Type m_point_encoding = PointGFp::UNCOMPRESSED; + }; + +/** +* This abstract class represents ECC private keys +*/ +class BOTAN_PUBLIC_API(2,0) EC_PrivateKey : public virtual EC_PublicKey, + public virtual Private_Key + { + public: + /* + * If x=0, creates a new private key in the domain + * using the given rng. If with_modular_inverse is set, + * the public key will be calculated by multiplying + * the base point with the modular inverse of + * x (as in ECGDSA and ECKCDSA), otherwise by + * multiplying directly with x (as in ECDSA). + */ + EC_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x, + bool with_modular_inverse=false); + + /* + * Creates a new private key object from the + * ECPrivateKey structure given in key_bits. + * If with_modular_inverse is set, + * the public key will be calculated by multiplying + * the base point with the modular inverse of + * x (as in ECGDSA and ECKCDSA), otherwise by + * multiplying directly with x (as in ECDSA). + */ + EC_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits, + bool with_modular_inverse=false); + + secure_vector<uint8_t> private_key_bits() const override; + + /** + * Get the private key value of this key object. + * @result the private key value of this key object + */ + const BigInt& private_value() const; + + EC_PrivateKey(const EC_PrivateKey& other) = default; + EC_PrivateKey& operator=(const EC_PrivateKey& other) = default; + ~EC_PrivateKey() = default; + protected: + EC_PrivateKey() = default; + + BigInt m_private_key; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ecc_key/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/ecc_key/info.txt new file mode 100644 index 0000000000..f46c9bb544 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ecc_key/info.txt @@ -0,0 +1,10 @@ +<defines> +ECC_PUBLIC_KEY_CRYPTO -> 20131128 +</defines> + +<requires> +asn1 +bigint +ec_group +numbertheory +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ecdh/ecdh.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/ecdh/ecdh.cpp new file mode 100644 index 0000000000..59f245a00c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ecdh/ecdh.cpp @@ -0,0 +1,85 @@ +/* +* ECDH implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ecdh.h> +#include <botan/numthry.h> +#include <botan/internal/pk_ops_impl.h> + +#if defined(BOTAN_HAS_OPENSSL) + #include <botan/internal/openssl.h> +#endif + +namespace Botan { + +namespace { + +/** +* ECDH operation +*/ +class ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF + { + public: + + ECDH_KA_Operation(const ECDH_PrivateKey& key, const std::string& kdf, RandomNumberGenerator& rng) : + PK_Ops::Key_Agreement_with_KDF(kdf), + m_group(key.domain()), + m_rng(rng) + { + m_l_times_priv = m_group.inverse_mod_order(m_group.get_cofactor()) * key.private_value(); + } + + secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override + { + PointGFp input_point = m_group.get_cofactor() * m_group.OS2ECP(w, w_len); + input_point.randomize_repr(m_rng); + + const PointGFp S = m_group.blinded_var_point_multiply( + input_point, m_l_times_priv, m_rng, m_ws); + + if(S.on_the_curve() == false) + throw Internal_Error("ECDH agreed value was not on the curve"); + return BigInt::encode_1363(S.get_affine_x(), m_group.get_p_bytes()); + } + private: + const EC_Group m_group; + BigInt m_l_times_priv; + RandomNumberGenerator& m_rng; + std::vector<BigInt> m_ws; + }; + +} + +std::unique_ptr<PK_Ops::Key_Agreement> +ECDH_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + try + { + return make_openssl_ecdh_ka_op(*this, params); + } + catch(Lookup_Error&) + { + if(provider == "openssl") + throw; + } + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Key_Agreement>(new ECDH_KA_Operation(*this, params, rng)); + + throw Provider_Not_Found(algo_name(), provider); + } + + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ecdh/ecdh.h b/src/libs/3rdparty/botan/src/lib/pubkey/ecdh/ecdh.h new file mode 100644 index 0000000000..f88955ac40 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ecdh/ecdh.h @@ -0,0 +1,106 @@ +/* +* ECDH +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECDH_KEY_H_ +#define BOTAN_ECDH_KEY_H_ + +#include <botan/ecc_key.h> + +namespace Botan { + +/** +* This class represents ECDH Public Keys. +*/ +class BOTAN_PUBLIC_API(2,0) ECDH_PublicKey : public virtual EC_PublicKey + { + public: + /** + * Create an ECDH public key. + * @param alg_id algorithm identifier + * @param key_bits DER encoded public key bits + */ + ECDH_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECDH_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Get this keys algorithm name. + * @return this keys algorithm name + */ + std::string algo_name() const override { return "ECDH"; } + + /** + * @return public point value + */ + std::vector<uint8_t> public_value() const + { return public_point().encode(PointGFp::UNCOMPRESSED); } + + /** + * @return public point value + */ + std::vector<uint8_t> public_value(PointGFp::Compression_Type format) const + { return public_point().encode(format); } + + protected: + ECDH_PublicKey() = default; + }; + +/** +* This class represents ECDH Private Keys. +*/ +class BOTAN_PUBLIC_API(2,0) ECDH_PrivateKey final : public ECDH_PublicKey, + public EC_PrivateKey, + public PK_Key_Agreement_Key + { + public: + + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits ECPrivateKey bits + */ + ECDH_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Generate a new private key + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key; if zero, a new random key is generated + */ + ECDH_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} + + std::vector<uint8_t> public_value() const override + { return ECDH_PublicKey::public_value(PointGFp::UNCOMPRESSED); } + + std::vector<uint8_t> public_value(PointGFp::Compression_Type type) const + { return ECDH_PublicKey::public_value(type); } + + std::unique_ptr<PK_Ops::Key_Agreement> + create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ecdh/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/ecdh/info.txt new file mode 100644 index 0000000000..11ca921dab --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ecdh/info.txt @@ -0,0 +1,10 @@ +<defines> +ECDH -> 20131128 +</defines> + +<requires> +asn1 +ec_group +ecc_key +numbertheory +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ecdsa/ecdsa.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/ecdsa/ecdsa.cpp new file mode 100644 index 0000000000..2409d8f0d2 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ecdsa/ecdsa.cpp @@ -0,0 +1,256 @@ +/* +* ECDSA implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* 2007 Falko Strenzke, FlexSecure GmbH +* 2008-2010,2015,2016,2018 Jack Lloyd +* 2016 René Korthaus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ecdsa.h> +#include <botan/internal/pk_ops_impl.h> +#include <botan/internal/point_mul.h> +#include <botan/keypair.h> +#include <botan/reducer.h> +#include <botan/emsa.h> + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + #include <botan/rfc6979.h> +#endif + +#if defined(BOTAN_HAS_BEARSSL) + #include <botan/internal/bearssl.h> +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include <botan/internal/openssl.h> +#endif + +namespace Botan { + +bool ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!public_point().on_the_curve()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); + } + +namespace { + +/** +* ECDSA signature operation +*/ +class ECDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA + { + public: + + ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa, + const std::string& emsa, + RandomNumberGenerator& rng) : + PK_Ops::Signature_with_EMSA(emsa), + m_group(ecdsa.domain()), + m_x(ecdsa.private_value()) + { +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + m_rfc6979_hash = hash_for_emsa(emsa); +#endif + + m_b = m_group.random_scalar(rng); + m_b_inv = m_group.inverse_mod_order(m_b); + } + + size_t max_input_bits() const override { return m_group.get_order_bits(); } + + secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + + private: + const EC_Group m_group; + const BigInt& m_x; + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + std::string m_rfc6979_hash; +#endif + + std::vector<BigInt> m_ws; + + BigInt m_b, m_b_inv; + }; + +secure_vector<uint8_t> +ECDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + BigInt m(msg, msg_len, m_group.get_order_bits()); + +#if defined(BOTAN_HAS_RFC6979_GENERATOR) + const BigInt k = generate_rfc6979_nonce(m_x, m_group.get_order(), m, m_rfc6979_hash); +#else + const BigInt k = m_group.random_scalar(rng); +#endif + + const BigInt r = m_group.mod_order( + m_group.blinded_base_point_multiply_x(k, rng, m_ws)); + + const BigInt k_inv = m_group.inverse_mod_order(k); + + /* + * Blind the input message and compute x*r+m as (x*r*b + m*b)/b + */ + m_b = m_group.square_mod_order(m_b); + m_b_inv = m_group.square_mod_order(m_b_inv); + + m = m_group.multiply_mod_order(m_b, m); + const BigInt xr = m_group.multiply_mod_order(m_x, m_b, r); + + const BigInt s = m_group.multiply_mod_order(k_inv, xr + m, m_b_inv); + + // With overwhelming probability, a bug rather than actual zero r/s + if(r.is_zero() || s.is_zero()) + throw Internal_Error("During ECDSA signature generated zero r/s"); + + return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order_bytes()); + } + +/** +* ECDSA verification operation +*/ +class ECDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA + { + public: + ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + m_group(ecdsa.domain()), + m_gy_mul(m_group.get_base_point(), ecdsa.public_point()) + { + } + + size_t max_input_bits() const override { return m_group.get_order_bits(); } + + bool with_recovery() const override { return false; } + + bool verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) override; + private: + const EC_Group m_group; + const PointGFp_Multi_Point_Precompute m_gy_mul; + }; + +bool ECDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, + const uint8_t sig[], size_t sig_len) + { + if(sig_len != m_group.get_order_bytes() * 2) + return false; + + const BigInt e(msg, msg_len, m_group.get_order_bits()); + + const BigInt r(sig, sig_len / 2); + const BigInt s(sig + sig_len / 2, sig_len / 2); + + if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) + return false; + + const BigInt w = m_group.inverse_mod_order(s); + + const BigInt u1 = m_group.multiply_mod_order(m_group.mod_order(e), w); + const BigInt u2 = m_group.multiply_mod_order(r, w); + const PointGFp R = m_gy_mul.multi_exp(u1, u2); + + if(R.is_zero()) + return false; + + const BigInt v = m_group.mod_order(R.get_affine_x()); + return (v == r); + } + +} + +std::unique_ptr<PK_Ops::Verification> +ECDSA_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_BEARSSL) + if(provider == "bearssl" || provider.empty()) + { + try + { + return make_bearssl_ecdsa_ver_op(*this, params); + } + catch(Lookup_Error& e) + { + if(provider == "bearssl") + throw; + } + } +#endif + +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + try + { + return make_openssl_ecdsa_ver_op(*this, params); + } + catch(Lookup_Error& e) + { + if(provider == "openssl") + throw; + } + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Verification>(new ECDSA_Verification_Operation(*this, params)); + + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr<PK_Ops::Signature> +ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_BEARSSL) + if(provider == "bearssl" || provider.empty()) + { + try + { + return make_bearssl_ecdsa_sig_op(*this, params); + } + catch(Lookup_Error& e) + { + if(provider == "bearssl") + throw; + } + } +#endif + +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + try + { + return make_openssl_ecdsa_sig_op(*this, params); + } + catch(Lookup_Error& e) + { + if(provider == "openssl") + throw; + } + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Signature>(new ECDSA_Signature_Operation(*this, params, rng)); + + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ecdsa/ecdsa.h b/src/libs/3rdparty/botan/src/lib/pubkey/ecdsa/ecdsa.h new file mode 100644 index 0000000000..2929059c56 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ecdsa/ecdsa.h @@ -0,0 +1,98 @@ +/* +* ECDSA +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECDSA_KEY_H_ +#define BOTAN_ECDSA_KEY_H_ + +#include <botan/ecc_key.h> + +namespace Botan { + +/** +* This class represents ECDSA Public Keys. +*/ +class BOTAN_PUBLIC_API(2,0) ECDSA_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Create a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECDSA_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + ECDSA_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Get this keys algorithm name. + * @result this keys algorithm name ("ECDSA") + */ + std::string algo_name() const override { return "ECDSA"; } + + size_t message_parts() const override { return 2; } + + size_t message_part_size() const override + { return domain().get_order().bytes(); } + + std::unique_ptr<PK_Ops::Verification> + create_verification_op(const std::string& params, + const std::string& provider) const override; + protected: + ECDSA_PublicKey() = default; + }; + +/** +* This class represents ECDSA Private Keys +*/ +class BOTAN_PUBLIC_API(2,0) ECDSA_PrivateKey final : public ECDSA_PublicKey, + public EC_PrivateKey + { + public: + + /** + * Load a private key + * @param alg_id the X.509 algorithm identifier + * @param key_bits ECPrivateKey bits + */ + ECDSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits) : + EC_PrivateKey(alg_id, key_bits) {} + + /** + * Create a private key. + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key (if zero, generate a new random key) + */ + ECDSA_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} + + bool check_key(RandomNumberGenerator& rng, bool) const override; + + std::unique_ptr<PK_Ops::Signature> + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/ecdsa/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/ecdsa/info.txt new file mode 100644 index 0000000000..6bd32ca175 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/ecdsa/info.txt @@ -0,0 +1,14 @@ +<defines> +ECDSA -> 20131128 +</defines> + +<requires> +asn1 +ec_group +ecc_key +keypair +numbertheory +rng +emsa1 +sha2_32 +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/info.txt new file mode 100644 index 0000000000..c6e8036e59 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/info.txt @@ -0,0 +1,31 @@ +<defines> +PUBLIC_KEY_CRYPTO -> 20131128 +</defines> + +<header:public> +blinding.h +pk_algs.h +pk_keys.h +pk_ops.h +pk_ops_fwd.h +pkcs8.h +pubkey.h +workfactor.h +x509_key.h +</header:public> + +<header:internal> +pk_ops_impl.h +</header:internal> + +<requires> +asn1 +bigint +kdf +pem +pk_pad +numbertheory +rng +hash +hex +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/keypair/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/keypair/info.txt new file mode 100644 index 0000000000..ed85abf691 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/keypair/info.txt @@ -0,0 +1,6 @@ +<defines> +KEYPAIR_TESTING -> 20131128 +</defines> + +<requires> +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/keypair/keypair.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/keypair/keypair.cpp new file mode 100644 index 0000000000..e8d88e99f3 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/keypair/keypair.cpp @@ -0,0 +1,85 @@ +/* +* Keypair Checks +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/keypair.h> +#include <botan/pubkey.h> +#include <botan/rng.h> + +namespace Botan { + +namespace KeyPair { + +/* +* Check an encryption key pair for consistency +*/ +bool encryption_consistency_check(RandomNumberGenerator& rng, + const Private_Key& private_key, + const Public_Key& public_key, + const std::string& padding) + { + PK_Encryptor_EME encryptor(public_key, rng, padding); + PK_Decryptor_EME decryptor(private_key, rng, padding); + + /* + Weird corner case, if the key is too small to encrypt anything at + all. This can happen with very small RSA keys with PSS + */ + if(encryptor.maximum_input_size() == 0) + return true; + + std::vector<uint8_t> plaintext = + unlock(rng.random_vec(encryptor.maximum_input_size() - 1)); + + std::vector<uint8_t> ciphertext = encryptor.encrypt(plaintext, rng); + if(ciphertext == plaintext) + return false; + + std::vector<uint8_t> decrypted = unlock(decryptor.decrypt(ciphertext)); + + return (plaintext == decrypted); + } + +/* +* Check a signature key pair for consistency +*/ +bool signature_consistency_check(RandomNumberGenerator& rng, + const Private_Key& private_key, + const Public_Key& public_key, + const std::string& padding) + { + PK_Signer signer(private_key, rng, padding); + PK_Verifier verifier(public_key, padding); + + std::vector<uint8_t> message(32); + rng.randomize(message.data(), message.size()); + + std::vector<uint8_t> signature; + + try + { + signature = signer.sign_message(message, rng); + } + catch(Encoding_Error&) + { + return false; + } + + if(!verifier.verify_message(message, signature)) + return false; + + // Now try to check a corrupt signature, ensure it does not succeed + ++signature[0]; + + if(verifier.verify_message(message, signature)) + return false; + + return true; + } + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/keypair/keypair.h b/src/libs/3rdparty/botan/src/lib/pubkey/keypair/keypair.h new file mode 100644 index 0000000000..4f28f325fd --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/keypair/keypair.h @@ -0,0 +1,83 @@ +/* +* Keypair Checks +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_KEYPAIR_CHECKS_H_ +#define BOTAN_KEYPAIR_CHECKS_H_ + +#include <botan/pk_keys.h> + +namespace Botan { + +namespace KeyPair { + +/** +* Tests whether the key is consistent for encryption; whether +* encrypting and then decrypting gives to the original plaintext. +* @param rng the rng to use +* @param private_key the key to test +* @param public_key the key to test +* @param padding the encryption padding method to use +* @return true if consistent otherwise false +*/ +BOTAN_PUBLIC_API(2,0) bool +encryption_consistency_check(RandomNumberGenerator& rng, + const Private_Key& private_key, + const Public_Key& public_key, + const std::string& padding); + +/** +* Tests whether the key is consistent for signatures; whether a +* signature can be created and then verified +* @param rng the rng to use +* @param private_key the key to test +* @param public_key the key to test +* @param padding the signature padding method to use +* @return true if consistent otherwise false +*/ +BOTAN_PUBLIC_API(2,0) bool +signature_consistency_check(RandomNumberGenerator& rng, + const Private_Key& private_key, + const Public_Key& public_key, + const std::string& padding); + +/** +* Tests whether the key is consistent for encryption; whether +* encrypting and then decrypting gives to the original plaintext. +* @param rng the rng to use +* @param key the key to test +* @param padding the encryption padding method to use +* @return true if consistent otherwise false +*/ +inline bool +encryption_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding) + { + return encryption_consistency_check(rng, key, key, padding); + } + +/** +* Tests whether the key is consistent for signatures; whether a +* signature can be created and then verified +* @param rng the rng to use +* @param key the key to test +* @param padding the signature padding method to use +* @return true if consistent otherwise false +*/ +inline bool +signature_consistency_check(RandomNumberGenerator& rng, + const Private_Key& key, + const std::string& padding) + { + return signature_consistency_check(rng, key, key, padding); + } + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pbes2/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/pbes2/info.txt new file mode 100644 index 0000000000..f8c6d37196 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pbes2/info.txt @@ -0,0 +1,10 @@ +<defines> +PKCS5_PBES2 -> 20141119 +</defines> + +<requires> +asn1 +cbc +hmac +pbkdf2 +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pbes2/pbes2.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/pbes2/pbes2.cpp new file mode 100644 index 0000000000..cfac722d7c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pbes2/pbes2.cpp @@ -0,0 +1,312 @@ +/* +* PKCS #5 PBES2 +* (C) 1999-2008,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pbes2.h> +#include <botan/cipher_mode.h> +#include <botan/pbkdf.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/parsing.h> +#include <botan/alg_id.h> +#include <botan/oids.h> +#include <botan/rng.h> + +#if defined(BOTAN_HAS_SCRYPT) + #include <botan/scrypt.h> +#endif + +namespace Botan { + +namespace { + +SymmetricKey derive_key(const std::string& passphrase, + const AlgorithmIdentifier& kdf_algo, + size_t default_key_size) + { + if(kdf_algo.get_oid() == OIDS::lookup("PKCS5.PBKDF2")) + { + secure_vector<uint8_t> salt; + size_t iterations = 0, key_length = 0; + + AlgorithmIdentifier prf_algo; + BER_Decoder(kdf_algo.get_parameters()) + .start_cons(SEQUENCE) + .decode(salt, OCTET_STRING) + .decode(iterations) + .decode_optional(key_length, INTEGER, UNIVERSAL) + .decode_optional(prf_algo, SEQUENCE, CONSTRUCTED, + AlgorithmIdentifier("HMAC(SHA-160)", + AlgorithmIdentifier::USE_NULL_PARAM)) + .end_cons(); + + if(salt.size() < 8) + throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small"); + + const std::string prf = OIDS::lookup(prf_algo.get_oid()); + + std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")")); + + if(key_length == 0) + key_length = default_key_size; + + return pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations); + } +#if defined(BOTAN_HAS_SCRYPT) + else if(kdf_algo.get_oid() == OIDS::lookup("Scrypt")) + { + secure_vector<uint8_t> salt; + size_t N = 0, r = 0, p = 0; + size_t key_length = 0; + + AlgorithmIdentifier prf_algo; + BER_Decoder(kdf_algo.get_parameters()) + .start_cons(SEQUENCE) + .decode(salt, OCTET_STRING) + .decode(N) + .decode(r) + .decode(p) + .decode_optional(key_length, INTEGER, UNIVERSAL) + .end_cons(); + + if(key_length == 0) + key_length = default_key_size; + + secure_vector<uint8_t> output(key_length); + scrypt(output.data(), output.size(), passphrase, + salt.data(), salt.size(), N, r, p); + + return SymmetricKey(output); + } +#endif + else + throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " + + kdf_algo.get_oid().as_string()); + } + +secure_vector<uint8_t> derive_key(const std::string& passphrase, + const std::string& digest, + RandomNumberGenerator& rng, + size_t* msec_in_iterations_out, + size_t iterations_if_msec_null, + size_t key_length, + AlgorithmIdentifier& kdf_algo) + { + const secure_vector<uint8_t> salt = rng.random_vec(12); + + if(digest == "Scrypt") + { +#if defined(BOTAN_HAS_SCRYPT) + + Scrypt_Params params(32768, 8, 4); + + if(msec_in_iterations_out) + params = Scrypt_Params(std::chrono::milliseconds(*msec_in_iterations_out)); + else + params = Scrypt_Params(iterations_if_msec_null); + + secure_vector<uint8_t> key(key_length); + scrypt(key.data(), key.size(), passphrase, + salt.data(), salt.size(), params); + + std::vector<uint8_t> scrypt_params; + DER_Encoder(scrypt_params) + .start_cons(SEQUENCE) + .encode(salt, OCTET_STRING) + .encode(params.N()) + .encode(params.r()) + .encode(params.p()) + .encode(key_length) + .end_cons(); + + kdf_algo = AlgorithmIdentifier(OIDS::lookup("Scrypt"), scrypt_params); + return key; +#else + throw Not_Implemented("Scrypt is not available in this build"); +#endif + } + else + { + const std::string prf = "HMAC(" + digest + ")"; + + std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")")); + + size_t iterations = iterations_if_msec_null; + + secure_vector<uint8_t> key; + + if(msec_in_iterations_out) + { + std::chrono::milliseconds msec(*msec_in_iterations_out); + key = pbkdf->derive_key(key_length, passphrase, salt.data(), salt.size(), msec, iterations).bits_of(); + *msec_in_iterations_out = iterations; + } + else + { + key = pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations); + } + + std::vector<uint8_t> pbkdf2_params; + + DER_Encoder(pbkdf2_params) + .start_cons(SEQUENCE) + .encode(salt, OCTET_STRING) + .encode(iterations) + .encode(key_length) + .encode_if(prf != "HMAC(SHA-160)", + AlgorithmIdentifier(prf, AlgorithmIdentifier::USE_NULL_PARAM)) + .end_cons(); + + kdf_algo = AlgorithmIdentifier("PKCS5.PBKDF2", pbkdf2_params); + return key; + } + } + +/* +* PKCS#5 v2.0 PBE Encryption +*/ +std::pair<AlgorithmIdentifier, std::vector<uint8_t>> +pbes2_encrypt_shared(const secure_vector<uint8_t>& key_bits, + const std::string& passphrase, + size_t* msec_in_iterations_out, + size_t iterations_if_msec_null, + const std::string& cipher, + const std::string& prf, + RandomNumberGenerator& rng) + { + const std::vector<std::string> cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Encoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); + + if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM") + throw Encoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); + + const OID cipher_oid = OIDS::lookup(cipher); + if(cipher_oid.empty()) + throw Encoding_Error("PBE-PKCS5 v2.0: No OID assigned for " + cipher); + + std::unique_ptr<Cipher_Mode> enc = Cipher_Mode::create(cipher, ENCRYPTION); + + if(!enc) + throw Decoding_Error("PBE-PKCS5 cannot encrypt no cipher " + cipher); + + const size_t key_length = enc->key_spec().maximum_keylength(); + + const secure_vector<uint8_t> iv = rng.random_vec(enc->default_nonce_length()); + + AlgorithmIdentifier kdf_algo; + + const secure_vector<uint8_t> derived_key = + derive_key(passphrase, prf, rng, + msec_in_iterations_out, iterations_if_msec_null, + key_length, kdf_algo); + + enc->set_key(derived_key); + enc->start(iv); + secure_vector<uint8_t> ctext = key_bits; + enc->finish(ctext); + + std::vector<uint8_t> pbes2_params; + + DER_Encoder(pbes2_params) + .start_cons(SEQUENCE) + .encode(kdf_algo) + .encode( + AlgorithmIdentifier(cipher, + DER_Encoder().encode(iv, OCTET_STRING).get_contents_unlocked() + ) + ) + .end_cons(); + + AlgorithmIdentifier id(OIDS::lookup("PBE-PKCS5v20"), pbes2_params); + + return std::make_pair(id, unlock(ctext)); + } + + +} + +std::pair<AlgorithmIdentifier, std::vector<uint8_t>> +pbes2_encrypt(const secure_vector<uint8_t>& key_bits, + const std::string& passphrase, + std::chrono::milliseconds msec, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng) + { + size_t msec_in_iterations_out = static_cast<size_t>(msec.count()); + return pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng); + // return value msec_in_iterations_out discarded + } + +std::pair<AlgorithmIdentifier, std::vector<uint8_t>> +pbes2_encrypt_msec(const secure_vector<uint8_t>& key_bits, + const std::string& passphrase, + std::chrono::milliseconds msec, + size_t* out_iterations_if_nonnull, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng) + { + size_t msec_in_iterations_out = static_cast<size_t>(msec.count()); + + auto ret = pbes2_encrypt_shared(key_bits, passphrase, &msec_in_iterations_out, 0, cipher, digest, rng); + + if(out_iterations_if_nonnull) + *out_iterations_if_nonnull = msec_in_iterations_out; + + return ret; + } + +std::pair<AlgorithmIdentifier, std::vector<uint8_t>> +pbes2_encrypt_iter(const secure_vector<uint8_t>& key_bits, + const std::string& passphrase, + size_t pbkdf_iter, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng) + { + return pbes2_encrypt_shared(key_bits, passphrase, nullptr, pbkdf_iter, cipher, digest, rng); + } + +secure_vector<uint8_t> +pbes2_decrypt(const secure_vector<uint8_t>& key_bits, + const std::string& passphrase, + const std::vector<uint8_t>& params) + { + AlgorithmIdentifier kdf_algo, enc_algo; + + BER_Decoder(params) + .start_cons(SEQUENCE) + .decode(kdf_algo) + .decode(enc_algo) + .end_cons(); + + const std::string cipher = OIDS::lookup(enc_algo.get_oid()); + const std::vector<std::string> cipher_spec = split_on(cipher, '/'); + if(cipher_spec.size() != 2) + throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); + if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM") + throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); + + secure_vector<uint8_t> iv; + BER_Decoder(enc_algo.get_parameters()).decode(iv, OCTET_STRING).verify_end(); + + std::unique_ptr<Cipher_Mode> dec = Cipher_Mode::create(cipher, DECRYPTION); + if(!dec) + throw Decoding_Error("PBE-PKCS5 cannot decrypt no cipher " + cipher); + + dec->set_key(derive_key(passphrase, kdf_algo, dec->key_spec().maximum_keylength())); + + dec->start(iv); + + secure_vector<uint8_t> buf = key_bits; + dec->finish(buf); + + return buf; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pbes2/pbes2.h b/src/libs/3rdparty/botan/src/lib/pubkey/pbes2/pbes2.h new file mode 100644 index 0000000000..bc56abd97f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pbes2/pbes2.h @@ -0,0 +1,85 @@ +/* +* PKCS #5 v2.0 PBE +* (C) 1999-2007,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PBE_PKCS_v20_H_ +#define BOTAN_PBE_PKCS_v20_H_ + +#include <botan/alg_id.h> +#include <chrono> + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Encrypt with PBES2 from PKCS #5 v2.0 +* @param key_bits the input +* @param passphrase the passphrase to use for encryption +* @param msec how many milliseconds to run PBKDF2 +* @param cipher specifies the block cipher to use to encrypt +* @param digest specifies the PRF to use with PBKDF2 (eg "HMAC(SHA-1)") +* @param rng a random number generator +*/ +std::pair<AlgorithmIdentifier, std::vector<uint8_t>> +BOTAN_PUBLIC_API(2,0) pbes2_encrypt(const secure_vector<uint8_t>& key_bits, + const std::string& passphrase, + std::chrono::milliseconds msec, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng); + +/** +* Encrypt with PBES2 from PKCS #5 v2.0 +* @param key_bits the input +* @param passphrase the passphrase to use for encryption +* @param msec how many milliseconds to run PBKDF2 +* @param out_iterations_if_nonnull if not null, set to the number +* of PBKDF iterations used +* @param cipher specifies the block cipher to use to encrypt +* @param digest specifies the PRF to use with PBKDF2 (eg "HMAC(SHA-1)") +* @param rng a random number generator +*/ +std::pair<AlgorithmIdentifier, std::vector<uint8_t>> +BOTAN_PUBLIC_API(2,1) pbes2_encrypt_msec(const secure_vector<uint8_t>& key_bits, + const std::string& passphrase, + std::chrono::milliseconds msec, + size_t* out_iterations_if_nonnull, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng); + +/** +* Encrypt with PBES2 from PKCS #5 v2.0 +* @param key_bits the input +* @param passphrase the passphrase to use for encryption +* @param iterations how many iterations to run PBKDF2 +* @param cipher specifies the block cipher to use to encrypt +* @param digest specifies the PRF to use with PBKDF2 (eg "HMAC(SHA-1)") +* @param rng a random number generator +*/ +std::pair<AlgorithmIdentifier, std::vector<uint8_t>> +BOTAN_PUBLIC_API(2,1) pbes2_encrypt_iter(const secure_vector<uint8_t>& key_bits, + const std::string& passphrase, + size_t iterations, + const std::string& cipher, + const std::string& digest, + RandomNumberGenerator& rng); + +/** +* Decrypt a PKCS #5 v2.0 encrypted stream +* @param key_bits the input +* @param passphrase the passphrase to use for decryption +* @param params the PBES2 parameters +*/ +secure_vector<uint8_t> +BOTAN_PUBLIC_API(2,0) pbes2_decrypt(const secure_vector<uint8_t>& key_bits, + const std::string& passphrase, + const std::vector<uint8_t>& params); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pem/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/pem/info.txt new file mode 100644 index 0000000000..471d9abd63 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pem/info.txt @@ -0,0 +1,7 @@ +<defines> +PEM_CODEC -> 20131128 +</defines> + +<requires> +base64 +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pem/pem.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/pem/pem.cpp new file mode 100644 index 0000000000..d2433860dd --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pem/pem.cpp @@ -0,0 +1,169 @@ +/* +* PEM Encoding/Decoding +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pem.h> +#include <botan/data_src.h> +#include <botan/base64.h> +#include <botan/exceptn.h> + +namespace Botan { + +namespace PEM_Code { + +namespace { + +std::string linewrap(size_t width, const std::string& in) + { + std::string out; + for(size_t i = 0; i != in.size(); ++i) + { + if(i > 0 && i % width == 0) + { + out.push_back('\n'); + } + out.push_back(in[i]); + } + if(out.size() > 0 && out[out.size()-1] != '\n') + { + out.push_back('\n'); + } + + return out; + } + +} + +/* +* PEM encode BER/DER-encoded objects +*/ +std::string encode(const uint8_t der[], size_t length, const std::string& label, size_t width) + { + const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n"; + const std::string PEM_TRAILER = "-----END " + label + "-----\n"; + + return (PEM_HEADER + linewrap(width, base64_encode(der, length)) + PEM_TRAILER); + } + +/* +* Decode PEM down to raw BER/DER +*/ +secure_vector<uint8_t> decode_check_label(DataSource& source, + const std::string& label_want) + { + std::string label_got; + secure_vector<uint8_t> ber = decode(source, label_got); + if(label_got != label_want) + throw Decoding_Error("PEM: Label mismatch, wanted " + label_want + + ", got " + label_got); + return ber; + } + +/* +* Decode PEM down to raw BER/DER +*/ +secure_vector<uint8_t> decode(DataSource& source, std::string& label) + { + const size_t RANDOM_CHAR_LIMIT = 8; + + label.clear(); + + const std::string PEM_HEADER1 = "-----BEGIN "; + const std::string PEM_HEADER2 = "-----"; + size_t position = 0; + + while(position != PEM_HEADER1.length()) + { + uint8_t b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM header found"); + if(b == PEM_HEADER1[position]) + ++position; + else if(position >= RANDOM_CHAR_LIMIT) + throw Decoding_Error("PEM: Malformed PEM header"); + else + position = 0; + } + position = 0; + while(position != PEM_HEADER2.length()) + { + uint8_t b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM header found"); + if(b == PEM_HEADER2[position]) + ++position; + else if(position) + throw Decoding_Error("PEM: Malformed PEM header"); + + if(position == 0) + label += static_cast<char>(b); + } + + std::vector<char> b64; + + const std::string PEM_TRAILER = "-----END " + label + "-----"; + position = 0; + while(position != PEM_TRAILER.length()) + { + uint8_t b; + if(!source.read_byte(b)) + throw Decoding_Error("PEM: No PEM trailer found"); + if(b == PEM_TRAILER[position]) + ++position; + else if(position) + throw Decoding_Error("PEM: Malformed PEM trailer"); + + if(position == 0) + b64.push_back(b); + } + + return base64_decode(b64.data(), b64.size()); + } + +secure_vector<uint8_t> decode_check_label(const std::string& pem, + const std::string& label_want) + { + DataSource_Memory src(pem); + return decode_check_label(src, label_want); + } + +secure_vector<uint8_t> decode(const std::string& pem, std::string& label) + { + DataSource_Memory src(pem); + return decode(src, label); + } + +/* +* Search for a PEM signature +*/ +bool matches(DataSource& source, const std::string& extra, + size_t search_range) + { + const std::string PEM_HEADER = "-----BEGIN " + extra; + + secure_vector<uint8_t> search_buf(search_range); + size_t got = source.peek(search_buf.data(), search_buf.size(), 0); + + if(got < PEM_HEADER.length()) + return false; + + size_t index = 0; + + for(size_t j = 0; j != got; ++j) + { + if(search_buf[j] == PEM_HEADER[index]) + ++index; + else + index = 0; + if(index == PEM_HEADER.size()) + return true; + } + return false; + } + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pem/pem.h b/src/libs/3rdparty/botan/src/lib/pubkey/pem/pem.h new file mode 100644 index 0000000000..c02294dce5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pem/pem.h @@ -0,0 +1,91 @@ +/* +* PEM Encoding/Decoding +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PEM_H_ +#define BOTAN_PEM_H_ + +#include <botan/secmem.h> +#include <string> + +namespace Botan { + +class DataSource; + +namespace PEM_Code { + +/** +* Encode some binary data in PEM format +* @param data binary data to encode +* @param data_len length of binary data in bytes +* @param label PEM label put after BEGIN and END +* @param line_width after this many characters, a new line is inserted +*/ +BOTAN_PUBLIC_API(2,0) std::string encode(const uint8_t data[], + size_t data_len, + const std::string& label, + size_t line_width = 64); + +/** +* Encode some binary data in PEM format +* @param data binary data to encode +* @param label PEM label +* @param line_width after this many characters, a new line is inserted +*/ +template<typename Alloc> +std::string encode(const std::vector<uint8_t, Alloc>& data, + const std::string& label, + size_t line_width = 64) + { + return encode(data.data(), data.size(), label, line_width); + } + +/** +* Decode PEM data +* @param pem a datasource containing PEM encoded data +* @param label is set to the PEM label found for later inspection +*/ +BOTAN_PUBLIC_API(2,0) secure_vector<uint8_t> decode(DataSource& pem, + std::string& label); + +/** +* Decode PEM data +* @param pem a string containing PEM encoded data +* @param label is set to the PEM label found for later inspection +*/ +BOTAN_PUBLIC_API(2,0) secure_vector<uint8_t> decode(const std::string& pem, + std::string& label); + +/** +* Decode PEM data +* @param pem a datasource containing PEM encoded data +* @param label is what we expect the label to be +*/ +BOTAN_PUBLIC_API(2,0) +secure_vector<uint8_t> decode_check_label(DataSource& pem, + const std::string& label); + +/** +* Decode PEM data +* @param pem a string containing PEM encoded data +* @param label is what we expect the label to be +*/ +BOTAN_PUBLIC_API(2,0) +secure_vector<uint8_t> decode_check_label(const std::string& pem, + const std::string& label); + +/** +* Heuristic test for PEM data. +*/ +BOTAN_PUBLIC_API(2,0) bool matches(DataSource& source, + const std::string& extra = "", + size_t search_range = 4096); + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pk_algs.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/pk_algs.cpp new file mode 100644 index 0000000000..89ef7c708e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pk_algs.cpp @@ -0,0 +1,434 @@ +/* +* PK Key +* (C) 1999-2010,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pk_algs.h> +#include <botan/oids.h> +#include <botan/parsing.h> + +#if defined(BOTAN_HAS_RSA) + #include <botan/rsa.h> +#endif + +#if defined(BOTAN_HAS_DSA) + #include <botan/dsa.h> +#endif + +#if defined(BOTAN_HAS_DL_GROUP) + #include <botan/dl_group.h> +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include <botan/dh.h> +#endif + +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + #include <botan/ecc_key.h> +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include <botan/ecdsa.h> +#endif + +#if defined(BOTAN_HAS_ECGDSA) + #include <botan/ecgdsa.h> +#endif + +#if defined(BOTAN_HAS_ECKCDSA) + #include <botan/eckcdsa.h> +#endif + +#if defined(BOTAN_HAS_ED25519) + #include <botan/ed25519.h> +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + #include <botan/gost_3410.h> +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + #include <botan/elgamal.h> +#endif + +#if defined(BOTAN_HAS_ECDH) + #include <botan/ecdh.h> +#endif + +#if defined(BOTAN_HAS_CURVE_25519) + #include <botan/curve25519.h> +#endif + +#if defined(BOTAN_HAS_MCELIECE) + #include <botan/mceliece.h> +#endif + +#if defined(BOTAN_HAS_XMSS) + #include <botan/xmss.h> +#endif + +#if defined(BOTAN_HAS_SM2) + #include <botan/sm2.h> + #include <botan/sm2_enc.h> +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include <botan/internal/openssl.h> +#endif + +namespace Botan { + +std::unique_ptr<Public_Key> +load_public_key(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits) + { + const std::vector<std::string> alg_info = split_on(OIDS::lookup(alg_id.get_oid()), '/'); + + if(alg_info.empty()) + throw Decoding_Error("Unknown algorithm OID: " + alg_id.get_oid().as_string()); + + const std::string alg_name = alg_info[0]; + +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") + return std::unique_ptr<Public_Key>(new RSA_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_CURVE_25519) + if(alg_name == "Curve25519") + return std::unique_ptr<Public_Key>(new Curve25519_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_MCELIECE) + if(alg_name == "McEliece") + return std::unique_ptr<Public_Key>(new McEliece_PublicKey(key_bits)); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") + return std::unique_ptr<Public_Key>(new ECDSA_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(alg_name == "ECDH") + return std::unique_ptr<Public_Key>(new ECDH_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") + return std::unique_ptr<Public_Key>(new DH_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") + return std::unique_ptr<Public_Key>(new DSA_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(alg_name == "ElGamal") + return std::unique_ptr<Public_Key>(new ElGamal_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECGDSA) + if(alg_name == "ECGDSA") + return std::unique_ptr<Public_Key>(new ECGDSA_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECKCDSA) + if(alg_name == "ECKCDSA") + return std::unique_ptr<Public_Key>(new ECKCDSA_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ED25519) + if(alg_name == "Ed25519") + return std::unique_ptr<Public_Key>(new Ed25519_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(alg_name == "GOST-34.10") + return std::unique_ptr<Public_Key>(new GOST_3410_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_SM2) + if(alg_name == "SM2_Sig") + return std::unique_ptr<Public_Key>(new SM2_Signature_PublicKey(alg_id, key_bits)); + if(alg_name == "SM2_Enc") + return std::unique_ptr<Public_Key>(new SM2_Encryption_PublicKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_XMSS) + if(alg_name == "XMSS") + return std::unique_ptr<Public_Key>(new XMSS_PublicKey(key_bits)); +#endif + + throw Decoding_Error("Unhandled PK algorithm " + alg_name); + } + +std::unique_ptr<Private_Key> +load_private_key(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits) + { + const std::string alg_name = OIDS::lookup(alg_id.get_oid()); + if(alg_name == "") + throw Decoding_Error("Unknown algorithm OID: " + alg_id.get_oid().as_string()); + +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") + return std::unique_ptr<Private_Key>(new RSA_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_CURVE_25519) + if(alg_name == "Curve25519") + return std::unique_ptr<Private_Key>(new Curve25519_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") + return std::unique_ptr<Private_Key>(new ECDSA_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(alg_name == "ECDH") + return std::unique_ptr<Private_Key>(new ECDH_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") + return std::unique_ptr<Private_Key>(new DH_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") + return std::unique_ptr<Private_Key>(new DSA_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_MCELIECE) + if(alg_name == "McEliece") + return std::unique_ptr<Private_Key>(new McEliece_PrivateKey(key_bits)); +#endif + +#if defined(BOTAN_HAS_ECGDSA) + if(alg_name == "ECGDSA") + return std::unique_ptr<Private_Key>(new ECGDSA_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ECKCDSA) + if(alg_name == "ECKCDSA") + return std::unique_ptr<Private_Key>(new ECKCDSA_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ED25519) + if(alg_name == "Ed25519") + return std::unique_ptr<Private_Key>(new Ed25519_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(alg_name == "GOST-34.10") + return std::unique_ptr<Private_Key>(new GOST_3410_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_SM2) + if(alg_name == "SM2_Sig") + return std::unique_ptr<Private_Key>(new SM2_Signature_PrivateKey(alg_id, key_bits)); + if(alg_name == "SM2_Enc") + return std::unique_ptr<Private_Key>(new SM2_Encryption_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(alg_name == "ElGamal") + return std::unique_ptr<Private_Key>(new ElGamal_PrivateKey(alg_id, key_bits)); +#endif + +#if defined(BOTAN_HAS_XMSS) + if(alg_name == "XMSS") + return std::unique_ptr<Private_Key>(new XMSS_PrivateKey(key_bits)); +#endif + + throw Decoding_Error("Unhandled PK algorithm " + alg_name); + } + +#if defined(BOTAN_HAS_ECC_GROUP) + +namespace { + +std::string default_ec_group_for(const std::string& alg_name) + { + if(alg_name == "SM2_Enc" || alg_name == "SM2_Sig") + return "sm2p256v1"; + if(alg_name == "GOST-34.10") + return "gost_256A"; + if(alg_name == "ECGDSA") + return "brainpool256r1"; + return "secp256r1"; + + } + +} + +#endif + +std::unique_ptr<Private_Key> +create_private_key(const std::string& alg_name, + RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) + { + /* + * Default paramaters are chosen for work factor > 2**128 where possible + */ + +#if defined(BOTAN_HAS_CURVE_25519) + if(alg_name == "Curve25519") + return std::unique_ptr<Private_Key>(new Curve25519_PrivateKey(rng)); +#endif + +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") + { + const size_t rsa_bits = (params.empty() ? 3072 : to_u32bit(params)); +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + std::unique_ptr<Botan::Private_Key> pk; + if((pk = make_openssl_rsa_private_key(rng, rsa_bits))) + return pk; + + if(!provider.empty()) + return nullptr; + } +#endif + return std::unique_ptr<Private_Key>(new RSA_PrivateKey(rng, rsa_bits)); + } +#endif + +#if defined(BOTAN_HAS_MCELIECE) + if(alg_name == "McEliece") + { + std::vector<std::string> mce_param = + Botan::split_on(params.empty() ? "2960,57" : params, ','); + + if(mce_param.size() != 2) + throw Invalid_Argument("create_private_key bad McEliece parameters " + params); + + size_t mce_n = Botan::to_u32bit(mce_param[0]); + size_t mce_t = Botan::to_u32bit(mce_param[1]); + + return std::unique_ptr<Botan::Private_Key>(new Botan::McEliece_PrivateKey(rng, mce_n, mce_t)); + } +#endif + +#if defined(BOTAN_HAS_XMSS) + if(alg_name == "XMSS") + { + return std::unique_ptr<Private_Key>( + new XMSS_PrivateKey(XMSS_Parameters(params.empty() ? "XMSS_SHA2-512_W16_H10" : params).oid(), rng)); + } +#endif + +#if defined(BOTAN_HAS_ED25519) + if(alg_name == "Ed25519") + { + return std::unique_ptr<Private_Key>(new Ed25519_PrivateKey(rng)); + } +#endif + + // ECC crypto +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + + if(alg_name == "ECDSA" || + alg_name == "ECDH" || + alg_name == "ECKCDSA" || + alg_name == "ECGDSA" || + alg_name == "SM2_Sig" || + alg_name == "SM2_Enc" || + alg_name == "GOST-34.10") + { + const EC_Group ec_group(params.empty() ? default_ec_group_for(alg_name) : params); + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") + return std::unique_ptr<Private_Key>(new ECDSA_PrivateKey(rng, ec_group)); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(alg_name == "ECDH") + return std::unique_ptr<Private_Key>(new ECDH_PrivateKey(rng, ec_group)); +#endif + +#if defined(BOTAN_HAS_ECKCDSA) + if(alg_name == "ECKCDSA") + return std::unique_ptr<Private_Key>(new ECKCDSA_PrivateKey(rng, ec_group)); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(alg_name == "GOST-34.10") + return std::unique_ptr<Private_Key>(new GOST_3410_PrivateKey(rng, ec_group)); +#endif + +#if defined(BOTAN_HAS_SM2) + if(alg_name == "SM2_Sig") + return std::unique_ptr<Private_Key>(new SM2_Signature_PrivateKey(rng, ec_group)); + if(alg_name == "SM2_Enc") + return std::unique_ptr<Private_Key>(new SM2_Encryption_PrivateKey(rng, ec_group)); +#endif + +#if defined(BOTAN_HAS_ECGDSA) + if(alg_name == "ECGDSA") + return std::unique_ptr<Private_Key>(new ECGDSA_PrivateKey(rng, ec_group)); +#endif + } +#endif + + // DL crypto +#if defined(BOTAN_HAS_DL_GROUP) + if(alg_name == "DH" || alg_name == "DSA" || alg_name == "ElGamal") + { + std::string default_group = (alg_name == "DSA") ? "dsa/botan/2048" : "modp/ietf/2048"; + DL_Group modp_group(params.empty() ? default_group : params); + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") + return std::unique_ptr<Private_Key>(new DH_PrivateKey(rng, modp_group)); +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") + return std::unique_ptr<Private_Key>(new DSA_PrivateKey(rng, modp_group)); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(alg_name == "ElGamal") + return std::unique_ptr<Private_Key>(new ElGamal_PrivateKey(rng, modp_group)); +#endif + } +#endif + + BOTAN_UNUSED(alg_name, rng, params, provider); + + return std::unique_ptr<Private_Key>(); + } + +std::vector<std::string> +probe_provider_private_key(const std::string& alg_name, + const std::vector<std::string> possible) + { + std::vector<std::string> providers; + for(auto&& prov : possible) + { + if(prov == "base" || +#if defined(BOTAN_HAS_OPENSSL) + (prov == "openssl" && alg_name == "RSA") || +#endif + 0) + { + providers.push_back(prov); // available + } + } + + BOTAN_UNUSED(alg_name); + + return providers; + } +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pk_algs.h b/src/libs/3rdparty/botan/src/lib/pubkey/pk_algs.h new file mode 100644 index 0000000000..e3c7174288 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pk_algs.h @@ -0,0 +1,46 @@ +/* +* PK Key Factory +* (C) 1999-2010,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PK_KEY_FACTORY_H_ +#define BOTAN_PK_KEY_FACTORY_H_ + +#include <botan/pk_keys.h> +#include <botan/alg_id.h> +#include <memory> + +namespace Botan { + +BOTAN_PUBLIC_API(2,0) std::unique_ptr<Public_Key> +load_public_key(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits); + +BOTAN_PUBLIC_API(2,0) std::unique_ptr<Private_Key> +load_private_key(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits); + +/** +* Create a new key +* For ECC keys, algo_params specifies EC group (eg, "secp256r1") +* For DH/DSA/ElGamal keys, algo_params is DL group (eg, "modp/ietf/2048") +* For RSA, algo_params is integer keylength +* For McEliece, algo_params is n,t +* If algo_params is left empty, suitable default parameters are chosen. +*/ +BOTAN_PUBLIC_API(2,0) std::unique_ptr<Private_Key> +create_private_key(const std::string& algo_name, + RandomNumberGenerator& rng, + const std::string& algo_params = "", + const std::string& provider = ""); + +BOTAN_PUBLIC_API(2,2) +std::vector<std::string> +probe_provider_private_key(const std::string& algo_name, + const std::vector<std::string> possible); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pk_keys.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/pk_keys.cpp new file mode 100644 index 0000000000..fbbc6f7dd4 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pk_keys.cpp @@ -0,0 +1,148 @@ +/* +* PK Key Types +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pk_keys.h> +#include <botan/pk_ops.h> +#include <botan/der_enc.h> +#include <botan/oids.h> +#include <botan/hash.h> +#include <botan/hex.h> + +namespace Botan { + +std::string create_hex_fingerprint(const uint8_t bits[], + size_t bits_len, + const std::string& hash_name) + { + std::unique_ptr<HashFunction> hash_fn(HashFunction::create_or_throw(hash_name)); + const std::string hex_hash = hex_encode(hash_fn->process(bits, bits_len)); + + std::string fprint; + + for(size_t i = 0; i != hex_hash.size(); i += 2) + { + if(i != 0) + fprint.push_back(':'); + + fprint.push_back(hex_hash[i]); + fprint.push_back(hex_hash[i+1]); + } + + return fprint; + } + +std::vector<uint8_t> Public_Key::subject_public_key() const + { + std::vector<uint8_t> output; + + DER_Encoder(output).start_cons(SEQUENCE) + .encode(algorithm_identifier()) + .encode(public_key_bits(), BIT_STRING) + .end_cons(); + + return output; + } + +/* +* Default OID access +*/ +OID Public_Key::get_oid() const + { + try { + return OIDS::lookup(algo_name()); + } + catch(Lookup_Error&) + { + throw Lookup_Error("PK algo " + algo_name() + " has no defined OIDs"); + } + } + +secure_vector<uint8_t> Private_Key::private_key_info() const + { + const size_t PKCS8_VERSION = 0; + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(PKCS8_VERSION) + .encode(pkcs8_algorithm_identifier()) + .encode(private_key_bits(), OCTET_STRING) + .end_cons() + .get_contents(); + } + +/* +* Hash of the X.509 subjectPublicKey encoding +*/ +std::string Public_Key::fingerprint_public(const std::string& hash_algo) const + { + return create_hex_fingerprint(subject_public_key(), hash_algo); + } + +/* +* Hash of the PKCS #8 encoding for this key object +*/ +std::string Private_Key::fingerprint_private(const std::string& hash_algo) const + { + return create_hex_fingerprint(private_key_bits(), hash_algo); + } + +std::unique_ptr<PK_Ops::Encryption> +Public_Key::create_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support encryption"); + } + +std::unique_ptr<PK_Ops::KEM_Encryption> +Public_Key::create_kem_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support KEM encryption"); + } + +std::unique_ptr<PK_Ops::Verification> +Public_Key::create_verification_op(const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support verification"); + } + +std::unique_ptr<PK_Ops::Decryption> +Private_Key::create_decryption_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support decryption"); + } + +std::unique_ptr<PK_Ops::KEM_Decryption> +Private_Key::create_kem_decryption_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support KEM decryption"); + } + +std::unique_ptr<PK_Ops::Signature> +Private_Key::create_signature_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support signatures"); + } + +std::unique_ptr<PK_Ops::Key_Agreement> +Private_Key::create_key_agreement_op(RandomNumberGenerator& /*rng*/, + const std::string& /*params*/, + const std::string& /*provider*/) const + { + throw Lookup_Error(algo_name() + " does not support key agreement"); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pk_keys.h b/src/libs/3rdparty/botan/src/lib/pubkey/pk_keys.h new file mode 100644 index 0000000000..79254ea290 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pk_keys.h @@ -0,0 +1,317 @@ +/* +* PK Key Types +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PK_KEYS_H_ +#define BOTAN_PK_KEYS_H_ + +#include <botan/secmem.h> +#include <botan/asn1_oid.h> +#include <botan/alg_id.h> +#include <botan/pk_ops_fwd.h> + +namespace Botan { + +class RandomNumberGenerator; + +/** +* Public Key Base Class. +*/ +class BOTAN_PUBLIC_API(2,0) Public_Key + { + public: + Public_Key() =default; + Public_Key(const Public_Key& other) = default; + Public_Key& operator=(const Public_Key& other) = default; + virtual ~Public_Key() = default; + + /** + * Get the name of the underlying public key scheme. + * @return name of the public key scheme + */ + virtual std::string algo_name() const = 0; + + /** + * Return the estimated strength of the underlying key against + * the best currently known attack. Note that this ignores anything + * but pure attacks against the key itself and do not take into + * account padding schemes, usage mistakes, etc which might reduce + * the strength. However it does suffice to provide an upper bound. + * + * @return estimated strength in bits + */ + virtual size_t estimated_strength() const = 0; + + /** + * Return an integer value best approximating the length of the + * primary security parameter. For example for RSA this will be + * the size of the modulus, for ECDSA the size of the ECC group, + * and for McEliece the size of the code will be returned. + */ + virtual size_t key_length() const = 0; + + /** + * Get the OID of the underlying public key scheme. + * @return OID of the public key scheme + */ + virtual OID get_oid() const; + + /** + * Test the key values for consistency. + * @param rng rng to use + * @param strong whether to perform strong and lengthy version + * of the test + * @return true if the test is passed + */ + virtual bool check_key(RandomNumberGenerator& rng, + bool strong) const = 0; + + + /** + * @return X.509 AlgorithmIdentifier for this key + */ + virtual AlgorithmIdentifier algorithm_identifier() const = 0; + + /** + * @return BER encoded public key bits + */ + virtual std::vector<uint8_t> public_key_bits() const = 0; + + /** + * @return X.509 subject key encoding for this key object + */ + std::vector<uint8_t> subject_public_key() const; + + /** + * @return Hash of the subject public key + */ + std::string fingerprint_public(const std::string& alg = "SHA-256") const; + + // Internal or non-public declarations follow + + /** + * Returns more than 1 if the output of this algorithm + * (ciphertext, signature) should be treated as more than one + * value. This is used for algorithms like DSA and ECDSA, where + * the (r,s) output pair can be encoded as either a plain binary + * list or a TLV tagged DER encoding depending on the protocol. + * + * This function is public but applications should have few + * reasons to ever call this. + * + * @return number of message parts + */ + virtual size_t message_parts() const { return 1; } + + /** + * Returns how large each of the message parts refered to + * by message_parts() is + * + * This function is public but applications should have few + * reasons to ever call this. + * + * @return size of the message parts in bits + */ + virtual size_t message_part_size() const { return 0; } + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return an encryption operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr<PK_Ops::Encryption> + create_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return a KEM encryption operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr<PK_Ops::KEM_Encryption> + create_kem_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return a verification operation for this key/params or throw + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr<PK_Ops::Verification> + create_verification_op(const std::string& params, + const std::string& provider) const; + }; + +/** +* Private Key Base Class +*/ +class BOTAN_PUBLIC_API(2,0) Private_Key : public virtual Public_Key + { + public: + Private_Key() = default; + Private_Key(const Private_Key& other) = default; + Private_Key& operator=(const Private_Key& other) = default; + virtual ~Private_Key() = default; + + /** + * @return BER encoded private key bits + */ + virtual secure_vector<uint8_t> private_key_bits() const = 0; + + /** + * @return PKCS #8 private key encoding for this key object + */ + secure_vector<uint8_t> private_key_info() const; + + /** + * @return PKCS #8 AlgorithmIdentifier for this key + * Might be different from the X.509 identifier, but normally is not + */ + virtual AlgorithmIdentifier pkcs8_algorithm_identifier() const + { return algorithm_identifier(); } + + // Internal or non-public declarations follow + + /** + * @return Hash of the PKCS #8 encoding for this key object + */ + std::string fingerprint_private(const std::string& alg) const; + + BOTAN_DEPRECATED("Use fingerprint_private or fingerprint_public") + inline std::string fingerprint(const std::string& alg) const + { + return fingerprint_private(alg); // match behavior in previous versions + } + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return an decryption operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + * + */ + virtual std::unique_ptr<PK_Ops::Decryption> + create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return a KEM decryption operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr<PK_Ops::KEM_Decryption> + create_kem_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return a signature operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr<PK_Ops::Signature> + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + + /** + * This is an internal library function exposed on key types. + * In almost all cases applications should use wrappers in pubkey.h + * + * Return a key agreement operation for this key/params or throw + * + * @param rng a random number generator. The PK_Op may maintain a + * reference to the RNG and use it many times. The rng must outlive + * any operations which reference it. + * @param params additional parameters + * @param provider the provider to use + */ + virtual std::unique_ptr<PK_Ops::Key_Agreement> + create_key_agreement_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const; + }; + +/** +* PK Secret Value Derivation Key +*/ +class BOTAN_PUBLIC_API(2,0) PK_Key_Agreement_Key : public virtual Private_Key + { + public: + /* + * @return public component of this key + */ + virtual std::vector<uint8_t> public_value() const = 0; + + PK_Key_Agreement_Key() = default; + PK_Key_Agreement_Key(const PK_Key_Agreement_Key&) = default; + PK_Key_Agreement_Key& operator=(const PK_Key_Agreement_Key&) = default; + virtual ~PK_Key_Agreement_Key() = default; + }; + +/* +* Old compat typedefs +* TODO: remove these? +*/ +typedef PK_Key_Agreement_Key PK_KA_Key; +typedef Public_Key X509_PublicKey; +typedef Private_Key PKCS8_PrivateKey; + +std::string BOTAN_PUBLIC_API(2,4) + create_hex_fingerprint(const uint8_t bits[], size_t len, + const std::string& hash_name); + +template<typename Alloc> +std::string create_hex_fingerprint(const std::vector<uint8_t, Alloc>& vec, + const std::string& hash_name) + { + return create_hex_fingerprint(vec.data(), vec.size(), hash_name); + } + + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops.cpp new file mode 100644 index 0000000000..025836878b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops.cpp @@ -0,0 +1,173 @@ +/* +* PK Operation Types +* (C) 2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/pk_ops_impl.h> +#include <botan/internal/bit_ops.h> +#include <botan/rng.h> + +namespace Botan { + +PK_Ops::Encryption_with_EME::Encryption_with_EME(const std::string& eme) + { + m_eme.reset(get_eme(eme)); + if(!m_eme.get()) + throw Algorithm_Not_Found(eme); + } + +size_t PK_Ops::Encryption_with_EME::max_input_bits() const + { + return 8 * m_eme->maximum_input_size(max_raw_input_bits()); + } + +secure_vector<uint8_t> PK_Ops::Encryption_with_EME::encrypt(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const size_t max_raw = max_raw_input_bits(); + const std::vector<uint8_t> encoded = unlock(m_eme->encode(msg, msg_len, max_raw, rng)); + return raw_encrypt(encoded.data(), encoded.size(), rng); + } + +PK_Ops::Decryption_with_EME::Decryption_with_EME(const std::string& eme) + { + m_eme.reset(get_eme(eme)); + if(!m_eme.get()) + throw Algorithm_Not_Found(eme); + } + +secure_vector<uint8_t> +PK_Ops::Decryption_with_EME::decrypt(uint8_t& valid_mask, + const uint8_t ciphertext[], + size_t ciphertext_len) + { + const secure_vector<uint8_t> raw = raw_decrypt(ciphertext, ciphertext_len); + return m_eme->unpad(valid_mask, raw.data(), raw.size()); + } + +PK_Ops::Key_Agreement_with_KDF::Key_Agreement_with_KDF(const std::string& kdf) + { + if(kdf != "Raw") + m_kdf.reset(get_kdf(kdf)); + } + +secure_vector<uint8_t> PK_Ops::Key_Agreement_with_KDF::agree(size_t key_len, + const uint8_t w[], size_t w_len, + const uint8_t salt[], size_t salt_len) + { + secure_vector<uint8_t> z = raw_agree(w, w_len); + if(m_kdf) + return m_kdf->derive_key(key_len, z, salt, salt_len); + return z; + } + +PK_Ops::Signature_with_EMSA::Signature_with_EMSA(const std::string& emsa) : + Signature(), + m_emsa(get_emsa(emsa)), + m_hash(hash_for_emsa(emsa)), + m_prefix_used(false) + { + if(!m_emsa) + throw Algorithm_Not_Found(emsa); + } + +void PK_Ops::Signature_with_EMSA::update(const uint8_t msg[], size_t msg_len) + { + if(has_prefix() && !m_prefix_used) + { + m_prefix_used = true; + secure_vector<uint8_t> prefix = message_prefix(); + m_emsa->update(prefix.data(), prefix.size()); + } + m_emsa->update(msg, msg_len); + } + +secure_vector<uint8_t> PK_Ops::Signature_with_EMSA::sign(RandomNumberGenerator& rng) + { + m_prefix_used = false; + const secure_vector<uint8_t> msg = m_emsa->raw_data(); + const auto padded = m_emsa->encoding_of(msg, this->max_input_bits(), rng); + return raw_sign(padded.data(), padded.size(), rng); + } + +PK_Ops::Verification_with_EMSA::Verification_with_EMSA(const std::string& emsa) : + Verification(), + m_emsa(get_emsa(emsa)), + m_hash(hash_for_emsa(emsa)), + m_prefix_used(false) + { + if(!m_emsa) + throw Algorithm_Not_Found(emsa); + } + +void PK_Ops::Verification_with_EMSA::update(const uint8_t msg[], size_t msg_len) + { + if(has_prefix() && !m_prefix_used) + { + m_prefix_used = true; + secure_vector<uint8_t> prefix = message_prefix(); + m_emsa->update(prefix.data(), prefix.size()); + } + m_emsa->update(msg, msg_len); + } + +bool PK_Ops::Verification_with_EMSA::is_valid_signature(const uint8_t sig[], size_t sig_len) + { + m_prefix_used = false; + const secure_vector<uint8_t> msg = m_emsa->raw_data(); + + if(with_recovery()) + { + secure_vector<uint8_t> output_of_key = verify_mr(sig, sig_len); + return m_emsa->verify(output_of_key, msg, max_input_bits()); + } + else + { + Null_RNG rng; + secure_vector<uint8_t> encoded = m_emsa->encoding_of(msg, max_input_bits(), rng); + return verify(encoded.data(), encoded.size(), sig, sig_len); + } + } + +void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(secure_vector<uint8_t>& out_encapsulated_key, + secure_vector<uint8_t>& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const uint8_t salt[], + size_t salt_len) + { + secure_vector<uint8_t> raw_shared; + this->raw_kem_encrypt(out_encapsulated_key, raw_shared, rng); + + out_shared_key = m_kdf->derive_key(desired_shared_key_len, + raw_shared.data(), raw_shared.size(), + salt, salt_len); + } + +PK_Ops::KEM_Encryption_with_KDF::KEM_Encryption_with_KDF(const std::string& kdf) + { + m_kdf.reset(get_kdf(kdf)); + } + +secure_vector<uint8_t> +PK_Ops::KEM_Decryption_with_KDF::kem_decrypt(const uint8_t encap_key[], + size_t len, + size_t desired_shared_key_len, + const uint8_t salt[], + size_t salt_len) + { + secure_vector<uint8_t> raw_shared = this->raw_kem_decrypt(encap_key, len); + + return m_kdf->derive_key(desired_shared_key_len, + raw_shared.data(), raw_shared.size(), + salt, salt_len); + } + +PK_Ops::KEM_Decryption_with_KDF::KEM_Decryption_with_KDF(const std::string& kdf) + { + m_kdf.reset(get_kdf(kdf)); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops.h b/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops.h new file mode 100644 index 0000000000..0aaf0b0dfe --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops.h @@ -0,0 +1,150 @@ +/* +* (C) 2010,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PK_OPERATIONS_H_ +#define BOTAN_PK_OPERATIONS_H_ + +/** +* Ordinary applications should never need to include or use this +* header. It is exposed only for specialized applications which want +* to implement new versions of public key crypto without merging them +* as changes to the library. One actual example of such usage is an +* application which creates RSA signatures using a custom TPM library. +* Unless you're doing something like that, you don't need anything +* here. Instead use pubkey.h which wraps these types safely and +* provides a stable application-oriented API. +*/ + +#include <botan/pk_keys.h> +#include <botan/secmem.h> + +namespace Botan { + +class RandomNumberGenerator; +class EME; +class KDF; +class EMSA; + +namespace PK_Ops { + +/** +* Public key encryption interface +*/ +class BOTAN_PUBLIC_API(2,0) Encryption + { + public: + virtual secure_vector<uint8_t> encrypt(const uint8_t msg[], + size_t msg_len, + RandomNumberGenerator& rng) = 0; + + virtual size_t max_input_bits() const = 0; + + virtual ~Encryption() = default; + }; + +/** +* Public key decryption interface +*/ +class BOTAN_PUBLIC_API(2,0) Decryption + { + public: + virtual secure_vector<uint8_t> decrypt(uint8_t& valid_mask, + const uint8_t ciphertext[], + size_t ciphertext_len) = 0; + + virtual ~Decryption() = default; + }; + +/** +* Public key signature verification interface +*/ +class BOTAN_PUBLIC_API(2,0) Verification + { + public: + /* + * Add more data to the message currently being signed + * @param msg the message + * @param msg_len the length of msg in bytes + */ + virtual void update(const uint8_t msg[], size_t msg_len) = 0; + + /* + * Perform a verification operation + * @param rng a random number generator + */ + virtual bool is_valid_signature(const uint8_t sig[], size_t sig_len) = 0; + + virtual ~Verification() = default; + }; + +/** +* Public key signature creation interface +*/ +class BOTAN_PUBLIC_API(2,0) Signature + { + public: + /* + * Add more data to the message currently being signed + * @param msg the message + * @param msg_len the length of msg in bytes + */ + virtual void update(const uint8_t msg[], size_t msg_len) = 0; + + /* + * Perform a signature operation + * @param rng a random number generator + */ + virtual secure_vector<uint8_t> sign(RandomNumberGenerator& rng) = 0; + + virtual ~Signature() = default; + }; + +/** +* A generic key agreement operation (eg DH or ECDH) +*/ +class BOTAN_PUBLIC_API(2,0) Key_Agreement + { + public: + virtual secure_vector<uint8_t> agree(size_t key_len, + const uint8_t other_key[], size_t other_key_len, + const uint8_t salt[], size_t salt_len) = 0; + + virtual ~Key_Agreement() = default; + }; + +/** +* KEM (key encapsulation) +*/ +class BOTAN_PUBLIC_API(2,0) KEM_Encryption + { + public: + virtual void kem_encrypt(secure_vector<uint8_t>& out_encapsulated_key, + secure_vector<uint8_t>& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const uint8_t salt[], + size_t salt_len) = 0; + + virtual ~KEM_Encryption() = default; + }; + +class BOTAN_PUBLIC_API(2,0) KEM_Decryption + { + public: + virtual secure_vector<uint8_t> kem_decrypt(const uint8_t encap_key[], + size_t len, + size_t desired_shared_key_len, + const uint8_t salt[], + size_t salt_len) = 0; + + virtual ~KEM_Decryption() = default; + }; + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops_fwd.h b/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops_fwd.h new file mode 100644 index 0000000000..92a3c2a969 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops_fwd.h @@ -0,0 +1,27 @@ +/* +* PK Operation Types Forward Decls +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PK_OPERATIONS_FWD_H_ +#define BOTAN_PK_OPERATIONS_FWD_H_ + +namespace Botan { + +namespace PK_Ops { + +class Encryption; +class Decryption; +class Verification; +class Signature; +class Key_Agreement; +class KEM_Encryption; +class KEM_Decryption; + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops_impl.h b/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops_impl.h new file mode 100644 index 0000000000..1878a74177 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pk_ops_impl.h @@ -0,0 +1,231 @@ + +/* +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PK_OPERATION_IMPL_H_ +#define BOTAN_PK_OPERATION_IMPL_H_ + +#include <botan/pk_ops.h> +#include <botan/eme.h> +#include <botan/kdf.h> +#include <botan/emsa.h> + +namespace Botan { + +namespace PK_Ops { + +class Encryption_with_EME : public Encryption + { + public: + size_t max_input_bits() const override; + + secure_vector<uint8_t> encrypt(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + + ~Encryption_with_EME() = default; + protected: + explicit Encryption_with_EME(const std::string& eme); + private: + virtual size_t max_raw_input_bits() const = 0; + + virtual secure_vector<uint8_t> raw_encrypt(const uint8_t msg[], size_t len, + RandomNumberGenerator& rng) = 0; + std::unique_ptr<EME> m_eme; + }; + +class Decryption_with_EME : public Decryption + { + public: + secure_vector<uint8_t> decrypt(uint8_t& valid_mask, + const uint8_t msg[], size_t msg_len) override; + + ~Decryption_with_EME() = default; + protected: + explicit Decryption_with_EME(const std::string& eme); + private: + virtual secure_vector<uint8_t> raw_decrypt(const uint8_t msg[], size_t len) = 0; + std::unique_ptr<EME> m_eme; + }; + +class Verification_with_EMSA : public Verification + { + public: + ~Verification_with_EMSA() = default; + + void update(const uint8_t msg[], size_t msg_len) override; + bool is_valid_signature(const uint8_t sig[], size_t sig_len) override; + + bool do_check(const secure_vector<uint8_t>& msg, + const uint8_t sig[], size_t sig_len); + + std::string hash_for_signature() { return m_hash; } + + protected: + explicit Verification_with_EMSA(const std::string& emsa); + + /** + * Get the maximum message size in bits supported by this public key. + * @return maximum message in bits + */ + virtual size_t max_input_bits() const = 0; + + /** + * @return boolean specifying if this signature scheme uses + * a message prefix returned by message_prefix() + */ + virtual bool has_prefix() { return false; } + + /** + * @return the message prefix if this signature scheme uses + * a message prefix, signaled via has_prefix() + */ + virtual secure_vector<uint8_t> message_prefix() const { throw Exception( "No prefix" ); } + + /** + * @return boolean specifying if this key type supports message + * recovery and thus if you need to call verify() or verify_mr() + */ + virtual bool with_recovery() const = 0; + + /* + * Perform a signature check operation + * @param msg the message + * @param msg_len the length of msg in bytes + * @param sig the signature + * @param sig_len the length of sig in bytes + * @returns if signature is a valid one for message + */ + virtual bool verify(const uint8_t[], size_t, + const uint8_t[], size_t) + { + throw Invalid_State("Message recovery required"); + } + + /* + * Perform a signature operation (with message recovery) + * Only call this if with_recovery() returns true + * @param msg the message + * @param msg_len the length of msg in bytes + * @returns recovered message + */ + virtual secure_vector<uint8_t> verify_mr(const uint8_t[], size_t) + { + throw Invalid_State("Message recovery not supported"); + } + + std::unique_ptr<EMSA> clone_emsa() const { return std::unique_ptr<EMSA>(m_emsa->clone()); } + + private: + std::unique_ptr<EMSA> m_emsa; + const std::string m_hash; + bool m_prefix_used; + }; + +class Signature_with_EMSA : public Signature + { + public: + void update(const uint8_t msg[], size_t msg_len) override; + + secure_vector<uint8_t> sign(RandomNumberGenerator& rng) override; + protected: + explicit Signature_with_EMSA(const std::string& emsa); + ~Signature_with_EMSA() = default; + + std::string hash_for_signature() { return m_hash; } + + /** + * @return boolean specifying if this signature scheme uses + * a message prefix returned by message_prefix() + */ + virtual bool has_prefix() { return false; } + + /** + * @return the message prefix if this signature scheme uses + * a message prefix, signaled via has_prefix() + */ + virtual secure_vector<uint8_t> message_prefix() const { throw Exception( "No prefix" ); } + + std::unique_ptr<EMSA> clone_emsa() const { return std::unique_ptr<EMSA>(m_emsa->clone()); } + + private: + + /** + * Get the maximum message size in bits supported by this public key. + * @return maximum message in bits + */ + virtual size_t max_input_bits() const = 0; + + bool self_test_signature(const std::vector<uint8_t>& msg, + const std::vector<uint8_t>& sig) const; + + virtual secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator& rng) = 0; + + std::unique_ptr<EMSA> m_emsa; + const std::string m_hash; + bool m_prefix_used; + }; + +class Key_Agreement_with_KDF : public Key_Agreement + { + public: + secure_vector<uint8_t> agree(size_t key_len, + const uint8_t other_key[], size_t other_key_len, + const uint8_t salt[], size_t salt_len) override; + + protected: + explicit Key_Agreement_with_KDF(const std::string& kdf); + ~Key_Agreement_with_KDF() = default; + private: + virtual secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) = 0; + std::unique_ptr<KDF> m_kdf; + }; + +class KEM_Encryption_with_KDF : public KEM_Encryption + { + public: + void kem_encrypt(secure_vector<uint8_t>& out_encapsulated_key, + secure_vector<uint8_t>& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const uint8_t salt[], + size_t salt_len) override; + + protected: + virtual void raw_kem_encrypt(secure_vector<uint8_t>& out_encapsulated_key, + secure_vector<uint8_t>& raw_shared_key, + Botan::RandomNumberGenerator& rng) = 0; + + explicit KEM_Encryption_with_KDF(const std::string& kdf); + ~KEM_Encryption_with_KDF() = default; + private: + std::unique_ptr<KDF> m_kdf; + }; + +class KEM_Decryption_with_KDF : public KEM_Decryption + { + public: + secure_vector<uint8_t> kem_decrypt(const uint8_t encap_key[], + size_t len, + size_t desired_shared_key_len, + const uint8_t salt[], + size_t salt_len) override; + + protected: + virtual secure_vector<uint8_t> + raw_kem_decrypt(const uint8_t encap_key[], size_t len) = 0; + + explicit KEM_Decryption_with_KDF(const std::string& kdf); + ~KEM_Decryption_with_KDF() = default; + private: + std::unique_ptr<KDF> m_kdf; + }; + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.cpp new file mode 100644 index 0000000000..8d3eba6dc7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.cpp @@ -0,0 +1,468 @@ +/* +* PKCS #8 +* (C) 1999-2010,2014,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pkcs8.h> +#include <botan/rng.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/alg_id.h> +#include <botan/oids.h> +#include <botan/pem.h> +#include <botan/scan_name.h> +#include <botan/pk_algs.h> + +#if defined(BOTAN_HAS_PKCS5_PBES2) + #include <botan/pbes2.h> +#endif + +namespace Botan { + +namespace PKCS8 { + +namespace { + +/* +* Get info from an EncryptedPrivateKeyInfo +*/ +secure_vector<uint8_t> PKCS8_extract(DataSource& source, + AlgorithmIdentifier& pbe_alg_id) + { + secure_vector<uint8_t> key_data; + + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(pbe_alg_id) + .decode(key_data, OCTET_STRING) + .verify_end(); + + return key_data; + } + +/* +* PEM decode and/or decrypt a private key +*/ +secure_vector<uint8_t> PKCS8_decode( + DataSource& source, + std::function<std::string ()> get_passphrase, + AlgorithmIdentifier& pk_alg_id, + bool is_encrypted) + { + AlgorithmIdentifier pbe_alg_id; + secure_vector<uint8_t> key_data, key; + + try { + if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) + { + if(is_encrypted) + { + key_data = PKCS8_extract(source, pbe_alg_id); + } + else + { + // todo read more efficiently + while(!source.end_of_data()) + { + uint8_t b; + size_t read = source.read_byte(b); + if(read) + { + key_data.push_back(b); + } + } + } + } + else + { + std::string label; + key_data = PEM_Code::decode(source, label); + + // todo remove autodetect for pem as well? + if(label == "PRIVATE KEY") + is_encrypted = false; + else if(label == "ENCRYPTED PRIVATE KEY") + { + DataSource_Memory key_source(key_data); + key_data = PKCS8_extract(key_source, pbe_alg_id); + } + else + throw PKCS8_Exception("Unknown PEM label " + label); + } + + if(key_data.empty()) + throw PKCS8_Exception("No key data found"); + } + catch(Decoding_Error& e) + { + throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what())); + } + + try + { + if(is_encrypted) + { + if(OIDS::lookup(pbe_alg_id.get_oid()) != "PBE-PKCS5v20") + throw Exception("Unknown PBE type " + pbe_alg_id.get_oid().as_string()); +#if defined(BOTAN_HAS_PKCS5_PBES2) + key = pbes2_decrypt(key_data, get_passphrase(), pbe_alg_id.get_parameters()); +#else + BOTAN_UNUSED(get_passphrase); + throw Decoding_Error("Private key is encrypted but PBES2 was disabled in build"); +#endif + } + else + key = key_data; + + BER_Decoder(key) + .start_cons(SEQUENCE) + .decode_and_check<size_t>(0, "Unknown PKCS #8 version number") + .decode(pk_alg_id) + .decode(key, OCTET_STRING) + .discard_remaining() + .end_cons(); + } + catch(std::exception& e) + { + throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what())); + } + return key; + } + +} + +/* +* BER encode a PKCS #8 private key, unencrypted +*/ +secure_vector<uint8_t> BER_encode(const Private_Key& key) + { + // keeping around for compat + return key.private_key_info(); + } + +/* +* PEM encode a PKCS #8 private key, unencrypted +*/ +std::string PEM_encode(const Private_Key& key) + { + return PEM_Code::encode(PKCS8::BER_encode(key), "PRIVATE KEY"); + } + +#if defined(BOTAN_HAS_PKCS5_PBES2) + +namespace { + +std::pair<std::string, std::string> +choose_pbe_params(const std::string& pbe_algo, const std::string& key_algo) + { + if(pbe_algo.empty()) + { + // Defaults: + if(key_algo == "Curve25519" || key_algo == "McEliece") + return std::make_pair("AES-256/GCM", "SHA-512"); + else // for everything else (RSA, DSA, ECDSA, GOST, ...) + return std::make_pair("AES-256/CBC", "SHA-256"); + } + + SCAN_Name request(pbe_algo); + if(request.algo_name() != "PBE-PKCS5v20" || request.arg_count() != 2) + throw Exception("Unsupported PBE " + pbe_algo); + return std::make_pair(request.arg(0), request.arg(1)); + } + +} + +#endif + +/* +* BER encode a PKCS #8 private key, encrypted +*/ +std::vector<uint8_t> BER_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec, + const std::string& pbe_algo) + { +#if defined(BOTAN_HAS_PKCS5_PBES2) + const auto pbe_params = choose_pbe_params(pbe_algo, key.algo_name()); + + const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info = + pbes2_encrypt_msec(PKCS8::BER_encode(key), pass, msec, nullptr, + pbe_params.first, pbe_params.second, rng); + + std::vector<uint8_t> output; + DER_Encoder der(output); + der.start_cons(SEQUENCE) + .encode(pbe_info.first) + .encode(pbe_info.second, OCTET_STRING) + .end_cons(); + + return output; +#else + BOTAN_UNUSED(key, rng, pass, msec, pbe_algo); + throw Encoding_Error("PKCS8::BER_encode cannot encrypt because PBES2 was disabled in build"); +#endif + } + +/* +* PEM encode a PKCS #8 private key, encrypted +*/ +std::string PEM_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec, + const std::string& pbe_algo) + { + if(pass.empty()) + return PEM_encode(key); + + return PEM_Code::encode(PKCS8::BER_encode(key, rng, pass, msec, pbe_algo), + "ENCRYPTED PRIVATE KEY"); + } + +/* +* BER encode a PKCS #8 private key, encrypted +*/ +std::vector<uint8_t> BER_encode_encrypted_pbkdf_iter(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + size_t pbkdf_iterations, + const std::string& cipher, + const std::string& pbkdf_hash) + { +#if defined(BOTAN_HAS_PKCS5_PBES2) + const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info = + pbes2_encrypt_iter(key.private_key_info(), + pass, pbkdf_iterations, + cipher.empty() ? "AES-256/CBC" : cipher, + pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash, + rng); + + std::vector<uint8_t> output; + DER_Encoder der(output); + der.start_cons(SEQUENCE) + .encode(pbe_info.first) + .encode(pbe_info.second, OCTET_STRING) + .end_cons(); + + return output; + +#else + BOTAN_UNUSED(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash); + throw Encoding_Error("PKCS8::BER_encode_encrypted_pbkdf_iter cannot encrypt because PBES2 disabled in build"); +#endif + } + +/* +* PEM encode a PKCS #8 private key, encrypted +*/ +std::string PEM_encode_encrypted_pbkdf_iter(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + size_t pbkdf_iterations, + const std::string& cipher, + const std::string& pbkdf_hash) + { + return PEM_Code::encode( + PKCS8::BER_encode_encrypted_pbkdf_iter(key, rng, pass, pbkdf_iterations, cipher, pbkdf_hash), + "ENCRYPTED PRIVATE KEY"); + } + +/* +* BER encode a PKCS #8 private key, encrypted +*/ +std::vector<uint8_t> BER_encode_encrypted_pbkdf_msec(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds pbkdf_msec, + size_t* pbkdf_iterations, + const std::string& cipher, + const std::string& pbkdf_hash) + { +#if defined(BOTAN_HAS_PKCS5_PBES2) + const std::pair<AlgorithmIdentifier, std::vector<uint8_t>> pbe_info = + pbes2_encrypt_msec(key.private_key_info(), pass, + pbkdf_msec, pbkdf_iterations, + cipher.empty() ? "AES-256/CBC" : cipher, + pbkdf_hash.empty() ? "SHA-256" : pbkdf_hash, + rng); + + std::vector<uint8_t> output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode(pbe_info.first) + .encode(pbe_info.second, OCTET_STRING) + .end_cons(); + + return output; +#else + BOTAN_UNUSED(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash); + throw Encoding_Error("BER_encode_encrypted_pbkdf_msec cannot encrypt because PBES2 disabled in build"); +#endif + } + +/* +* PEM encode a PKCS #8 private key, encrypted +*/ +std::string PEM_encode_encrypted_pbkdf_msec(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds pbkdf_msec, + size_t* pbkdf_iterations, + const std::string& cipher, + const std::string& pbkdf_hash) + { + return PEM_Code::encode( + PKCS8::BER_encode_encrypted_pbkdf_msec(key, rng, pass, pbkdf_msec, pbkdf_iterations, cipher, pbkdf_hash), + "ENCRYPTED PRIVATE KEY"); + } + +namespace { + +/* +* Extract a private key (encrypted/unencrypted) and return it +*/ +std::unique_ptr<Private_Key> +load_key(DataSource& source, + std::function<std::string ()> get_pass, + bool is_encrypted) + { + AlgorithmIdentifier alg_id; + secure_vector<uint8_t> pkcs8_key = PKCS8_decode(source, get_pass, alg_id, is_encrypted); + + const std::string alg_name = OIDS::lookup(alg_id.get_oid()); + if(alg_name.empty() || alg_name == alg_id.get_oid().as_string()) + throw PKCS8_Exception("Unknown algorithm OID: " + + alg_id.get_oid().as_string()); + + return load_private_key(alg_id, pkcs8_key); + } + +} + +/* +* Extract an encrypted private key and return it +*/ +std::unique_ptr<Private_Key> load_key(DataSource& source, + std::function<std::string ()> get_pass) + { + return load_key(source, get_pass, true); + } + +/* +* Extract an encrypted private key and return it +*/ +std::unique_ptr<Private_Key> load_key(DataSource& source, + const std::string& pass) + { + return load_key(source, [pass]() { return pass; }, true); + } + +/* +* Extract an unencrypted private key and return it +*/ +std::unique_ptr<Private_Key> load_key(DataSource& source) + { + auto fail_fn = []() -> std::string { + throw PKCS8_Exception("Internal error: Attempt to read password for unencrypted key"); + }; + + return load_key(source, fail_fn, false); + } + +/* +* Make a copy of this private key +*/ +std::unique_ptr<Private_Key> copy_key(const Private_Key& key) + { + DataSource_Memory source(PEM_encode(key)); + return PKCS8::load_key(source); + } + +/* +* Extract an encrypted private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + std::function<std::string ()> get_pass) + { + BOTAN_UNUSED(rng); + return PKCS8::load_key(source, get_pass).release(); + } + +/* +* Extract an encrypted private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const std::string& pass) + { + BOTAN_UNUSED(rng); + return PKCS8::load_key(source, pass).release(); + } + +/* +* Extract an unencrypted private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng) + { + BOTAN_UNUSED(rng); + return PKCS8::load_key(source).release(); + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +/* +* Extract an encrypted private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng, + std::function<std::string ()> get_pass) + { + BOTAN_UNUSED(rng); + DataSource_Stream in(fsname); + return PKCS8::load_key(in, get_pass).release(); + } + +/* +* Extract an encrypted private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng, + const std::string& pass) + { + BOTAN_UNUSED(rng); + DataSource_Stream in(fsname); + return PKCS8::load_key(in, [pass]() { return pass; }).release(); + } + +/* +* Extract an unencrypted private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng) + { + BOTAN_UNUSED(rng); + DataSource_Stream in(fsname); + return PKCS8::load_key(in).release(); + } +#endif + +/* +* Make a copy of this private key +*/ +Private_Key* copy_key(const Private_Key& key, + RandomNumberGenerator& rng) + { + BOTAN_UNUSED(rng); + return PKCS8::copy_key(key).release(); + } + + + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.h b/src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.h new file mode 100644 index 0000000000..0bc9a18f14 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pkcs8.h @@ -0,0 +1,288 @@ +/* +* PKCS #8 +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PKCS8_H_ +#define BOTAN_PKCS8_H_ + +#include <botan/pk_keys.h> +#include <botan/exceptn.h> +#include <botan/secmem.h> +#include <functional> +#include <chrono> +#include <memory> + +namespace Botan { + +class DataSource; +class RandomNumberGenerator; + +/** +* PKCS #8 General Exception +*/ +class BOTAN_PUBLIC_API(2,0) PKCS8_Exception final : public Decoding_Error + { + public: + explicit PKCS8_Exception(const std::string& error) : + Decoding_Error("PKCS #8: " + error) {} + }; + +/** +* This namespace contains functions for handling PKCS #8 private keys +*/ +namespace PKCS8 { + +/** +* BER encode a private key +* @param key the private key to encode +* @return BER encoded key +*/ +BOTAN_PUBLIC_API(2,0) secure_vector<uint8_t> BER_encode(const Private_Key& key); + +/** +* Get a string containing a PEM encoded private key. +* @param key the key to encode +* @return encoded key +*/ +BOTAN_PUBLIC_API(2,0) std::string PEM_encode(const Private_Key& key); + +/** +* Encrypt a key using PKCS #8 encryption +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param msec number of milliseconds to run the password derivation +* @param pbe_algo the name of the desired password-based encryption +* algorithm; if empty ("") a reasonable (portable/secure) +* default will be chosen. +* @return encrypted key in binary BER form +*/ +BOTAN_PUBLIC_API(2,0) std::vector<uint8_t> +BER_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec = std::chrono::milliseconds(300), + const std::string& pbe_algo = ""); + +/** +* Get a string containing a PEM encoded private key, encrypting it with a +* password. +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param msec number of milliseconds to run the password derivation +* @param pbe_algo the name of the desired password-based encryption +* algorithm; if empty ("") a reasonable (portable/secure) +* default will be chosen. +* @return encrypted key in PEM form +*/ +BOTAN_PUBLIC_API(2,0) std::string +PEM_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds msec = std::chrono::milliseconds(300), + const std::string& pbe_algo = ""); + +/** +* Encrypt a key using PKCS #8 encryption and a fixed iteration count +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbkdf_iter number of interations to run PBKDF2 +* @param cipher if non-empty specifies the cipher to use. CBC and GCM modes +* are supported, for example "AES-128/CBC", "AES-256/GCM", "Serpent/CBC". +* If empty a suitable default is chosen. +* @param pbkdf_hash if non-empty specifies the PBKDF hash function to use. +* For example "SHA-256" or "SHA-384". If empty a suitable default is chosen. +* @return encrypted key in binary BER form +*/ +BOTAN_PUBLIC_API(2,1) std::vector<uint8_t> +BER_encode_encrypted_pbkdf_iter(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + size_t pbkdf_iter, + const std::string& cipher = "", + const std::string& pbkdf_hash = ""); + +/** +* Get a string containing a PEM encoded private key, encrypting it with a +* password. +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbkdf_iter number of iterations to run PBKDF +* @param cipher if non-empty specifies the cipher to use. CBC and GCM modes +* are supported, for example "AES-128/CBC", "AES-256/GCM", "Serpent/CBC". +* If empty a suitable default is chosen. +* @param pbkdf_hash if non-empty specifies the PBKDF hash function to use. +* For example "SHA-256" or "SHA-384". If empty a suitable default is chosen. +* @return encrypted key in PEM form +*/ +BOTAN_PUBLIC_API(2,1) std::string +PEM_encode_encrypted_pbkdf_iter(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + size_t pbkdf_iter, + const std::string& cipher = "", + const std::string& pbkdf_hash = ""); + +/** +* Encrypt a key using PKCS #8 encryption and a variable iteration count +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbkdf_msec how long to run PBKDF2 +* @param pbkdf_iterations if non-null, set to the number of iterations used +* @param cipher if non-empty specifies the cipher to use. CBC and GCM modes +* are supported, for example "AES-128/CBC", "AES-256/GCM", "Serpent/CBC". +* If empty a suitable default is chosen. +* @param pbkdf_hash if non-empty specifies the PBKDF hash function to use. +* For example "SHA-256" or "SHA-384". If empty a suitable default is chosen. +* @return encrypted key in binary BER form +*/ +BOTAN_PUBLIC_API(2,1) std::vector<uint8_t> +BER_encode_encrypted_pbkdf_msec(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds pbkdf_msec, + size_t* pbkdf_iterations, + const std::string& cipher = "", + const std::string& pbkdf_hash = ""); + +/** +* Get a string containing a PEM encoded private key, encrypting it with a +* password. +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbkdf_msec how long in milliseconds to run PBKDF2 +* @param pbkdf_iterations (output argument) number of iterations of PBKDF +* that ended up being used +* @param cipher if non-empty specifies the cipher to use. CBC and GCM modes +* are supported, for example "AES-128/CBC", "AES-256/GCM", "Serpent/CBC". +* If empty a suitable default is chosen. +* @param pbkdf_hash if non-empty specifies the PBKDF hash function to use. +* For example "SHA-256" or "SHA-384". If empty a suitable default is chosen. +* @return encrypted key in PEM form +*/ +BOTAN_PUBLIC_API(2,1) std::string +PEM_encode_encrypted_pbkdf_msec(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + std::chrono::milliseconds pbkdf_msec, + size_t* pbkdf_iterations, + const std::string& cipher = "", + const std::string& pbkdf_hash = ""); + +/** +* Load an encrypted key from a data source. +* @param source the data source providing the encoded key +* @param rng ignored for compatability +* @param get_passphrase a function that returns passphrases +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + std::function<std::string ()> get_passphrase); + +/** Load an encrypted key from a data source. +* @param source the data source providing the encoded key +* @param rng ignored for compatability +* @param pass the passphrase to decrypt the key +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const std::string& pass); + +/** Load an unencrypted key from a data source. +* @param source the data source providing the encoded key +* @param rng ignored for compatability +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +/** +* Load an encrypted key from a file. +* @param filename the path to the file containing the encoded key +* @param rng ignored for compatability +* @param get_passphrase a function that returns passphrases +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng, + std::function<std::string ()> get_passphrase); + +/** Load an encrypted key from a file. +* @param filename the path to the file containing the encoded key +* @param rng ignored for compatability +* @param pass the passphrase to decrypt the key +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng, + const std::string& pass); + +/** Load an unencrypted key from a file. +* @param filename the path to the file containing the encoded key +* @param rng ignored for compatability +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng); +#endif + +/** +* Copy an existing encoded key object. +* @param key the key to copy +* @param rng ignored for compatability +* @return new copy of the key +*/ +BOTAN_PUBLIC_API(2,0) Private_Key* copy_key(const Private_Key& key, + RandomNumberGenerator& rng); + + +/** +* Load an encrypted key from a data source. +* @param source the data source providing the encoded key +* @param get_passphrase a function that returns passphrases +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,3) +std::unique_ptr<Private_Key> load_key(DataSource& source, + std::function<std::string ()> get_passphrase); + +/** Load an encrypted key from a data source. +* @param source the data source providing the encoded key +* @param pass the passphrase to decrypt the key +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,3) +std::unique_ptr<Private_Key> load_key(DataSource& source, + const std::string& pass); + +/** Load an unencrypted key from a data source. +* @param source the data source providing the encoded key +* @return loaded private key object +*/ +BOTAN_PUBLIC_API(2,3) +std::unique_ptr<Private_Key> load_key(DataSource& source); + +/** +* Copy an existing encoded key object. +* @param key the key to copy +* @return new copy of the key +*/ +BOTAN_PUBLIC_API(2,3) +std::unique_ptr<Private_Key> copy_key(const Private_Key& key); + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pubkey.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/pubkey.cpp new file mode 100644 index 0000000000..99d8927663 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pubkey.cpp @@ -0,0 +1,350 @@ +/* +* (C) 1999-2010,2015,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pubkey.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/bigint.h> +#include <botan/pk_ops.h> +#include <botan/internal/ct_utils.h> +#include <botan/rng.h> + +namespace Botan { + +secure_vector<uint8_t> PK_Decryptor::decrypt(const uint8_t in[], size_t length) const + { + uint8_t valid_mask = 0; + + secure_vector<uint8_t> decoded = do_decrypt(valid_mask, in, length); + + if(valid_mask == 0) + throw Decoding_Error("Invalid public key ciphertext, cannot decrypt"); + + return decoded; + } + +secure_vector<uint8_t> +PK_Decryptor::decrypt_or_random(const uint8_t in[], + size_t length, + size_t expected_pt_len, + RandomNumberGenerator& rng, + const uint8_t required_content_bytes[], + const uint8_t required_content_offsets[], + size_t required_contents_length) const + { + const secure_vector<uint8_t> fake_pms = rng.random_vec(expected_pt_len); + + uint8_t valid_mask = 0; + secure_vector<uint8_t> decoded = do_decrypt(valid_mask, in, length); + + valid_mask &= CT::is_equal(decoded.size(), expected_pt_len); + + decoded.resize(expected_pt_len); + + for(size_t i = 0; i != required_contents_length; ++i) + { + /* + These values are chosen by the application and for TLS are constants, + so this early failure via assert is fine since we know 0,1 < 48 + + If there is a protocol that has content checks on the key where + the expected offsets are controllable by the attacker this could + still leak. + + Alternately could always reduce the offset modulo the length? + */ + + const uint8_t exp = required_content_bytes[i]; + const uint8_t off = required_content_offsets[i]; + + BOTAN_ASSERT(off < expected_pt_len, "Offset in range of plaintext"); + + valid_mask &= CT::is_equal(decoded[off], exp); + } + + CT::conditional_copy_mem(valid_mask, + /*output*/decoded.data(), + /*from0*/decoded.data(), + /*from1*/fake_pms.data(), + expected_pt_len); + + return decoded; + } + +secure_vector<uint8_t> +PK_Decryptor::decrypt_or_random(const uint8_t in[], + size_t length, + size_t expected_pt_len, + RandomNumberGenerator& rng) const + { + return decrypt_or_random(in, length, expected_pt_len, rng, + nullptr, nullptr, 0); + } + +PK_Encryptor_EME::PK_Encryptor_EME(const Public_Key& key, + RandomNumberGenerator& rng, + const std::string& padding, + const std::string& provider) + { + m_op = key.create_encryption_op(rng, padding, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support encryption"); + } + +PK_Encryptor_EME::~PK_Encryptor_EME() { /* for unique_ptr */ } + +std::vector<uint8_t> +PK_Encryptor_EME::enc(const uint8_t in[], size_t length, RandomNumberGenerator& rng) const + { + return unlock(m_op->encrypt(in, length, rng)); + } + +size_t PK_Encryptor_EME::maximum_input_size() const + { + return m_op->max_input_bits() / 8; + } + +PK_Decryptor_EME::PK_Decryptor_EME(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& padding, + const std::string& provider) + { + m_op = key.create_decryption_op(rng, padding, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support decryption"); + } + +PK_Decryptor_EME::~PK_Decryptor_EME() { /* for unique_ptr */ } + +secure_vector<uint8_t> PK_Decryptor_EME::do_decrypt(uint8_t& valid_mask, + const uint8_t in[], size_t in_len) const + { + return m_op->decrypt(valid_mask, in, in_len); + } + +PK_KEM_Encryptor::PK_KEM_Encryptor(const Public_Key& key, + RandomNumberGenerator& rng, + const std::string& param, + const std::string& provider) + { + m_op = key.create_kem_encryption_op(rng, param, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support KEM encryption"); + } + +PK_KEM_Encryptor::~PK_KEM_Encryptor() { /* for unique_ptr */ } + +void PK_KEM_Encryptor::encrypt(secure_vector<uint8_t>& out_encapsulated_key, + secure_vector<uint8_t>& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const uint8_t salt[], + size_t salt_len) + { + m_op->kem_encrypt(out_encapsulated_key, + out_shared_key, + desired_shared_key_len, + rng, + salt, + salt_len); + } + +PK_KEM_Decryptor::PK_KEM_Decryptor(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& param, + const std::string& provider) + { + m_op = key.create_kem_decryption_op(rng, param, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support KEM decryption"); + } + +PK_KEM_Decryptor::~PK_KEM_Decryptor() { /* for unique_ptr */ } + +secure_vector<uint8_t> PK_KEM_Decryptor::decrypt(const uint8_t encap_key[], + size_t encap_key_len, + size_t desired_shared_key_len, + const uint8_t salt[], + size_t salt_len) + { + return m_op->kem_decrypt(encap_key, encap_key_len, + desired_shared_key_len, + salt, salt_len); + } + +PK_Key_Agreement::PK_Key_Agreement(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& kdf, + const std::string& provider) + { + m_op = key.create_key_agreement_op(rng, kdf, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support key agreement"); + } + +PK_Key_Agreement::~PK_Key_Agreement() { /* for unique_ptr */ } + +PK_Key_Agreement& PK_Key_Agreement::operator=(PK_Key_Agreement&& other) + { + if(this != &other) + { + m_op = std::move(other.m_op); + } + return (*this); + } + +PK_Key_Agreement::PK_Key_Agreement(PK_Key_Agreement&& other) : + m_op(std::move(other.m_op)) + {} + +SymmetricKey PK_Key_Agreement::derive_key(size_t key_len, + const uint8_t in[], size_t in_len, + const uint8_t salt[], + size_t salt_len) const + { + return m_op->agree(key_len, in, in_len, salt, salt_len); + } + +PK_Signer::PK_Signer(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& emsa, + Signature_Format format, + const std::string& provider) + { + m_op = key.create_signature_op(rng, emsa, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support signature generation"); + m_sig_format = format; + m_parts = key.message_parts(); + m_part_size = key.message_part_size(); + } + +PK_Signer::~PK_Signer() { /* for unique_ptr */ } + +void PK_Signer::update(const uint8_t in[], size_t length) + { + m_op->update(in, length); + } + +namespace { + +std::vector<uint8_t> der_encode_signature(const std::vector<uint8_t>& sig, + size_t parts, + size_t part_size) + { + if(sig.size() % parts != 0 || sig.size() != parts * part_size) + throw Encoding_Error("Unexpected size for DER signature"); + + std::vector<BigInt> sig_parts(parts); + for(size_t i = 0; i != sig_parts.size(); ++i) + sig_parts[i].binary_decode(&sig[part_size*i], part_size); + + std::vector<uint8_t> output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode_list(sig_parts) + .end_cons(); + return output; + } + +} + +std::vector<uint8_t> PK_Signer::signature(RandomNumberGenerator& rng) + { + const std::vector<uint8_t> sig = unlock(m_op->sign(rng)); + + if(m_sig_format == IEEE_1363) + { + return sig; + } + else if(m_sig_format == DER_SEQUENCE) + { + return der_encode_signature(sig, m_parts, m_part_size); + } + else + throw Internal_Error("PK_Signer: Invalid signature format enum"); + } + +PK_Verifier::PK_Verifier(const Public_Key& key, + const std::string& emsa, + Signature_Format format, + const std::string& provider) + { + m_op = key.create_verification_op(emsa, provider); + if(!m_op) + throw Invalid_Argument("Key type " + key.algo_name() + " does not support signature verification"); + m_sig_format = format; + m_parts = key.message_parts(); + m_part_size = key.message_part_size(); + } + +PK_Verifier::~PK_Verifier() { /* for unique_ptr */ } + +void PK_Verifier::set_input_format(Signature_Format format) + { + if(format != IEEE_1363 && m_parts == 1) + throw Invalid_Argument("PK_Verifier: This algorithm does not support DER encoding"); + m_sig_format = format; + } + +bool PK_Verifier::verify_message(const uint8_t msg[], size_t msg_length, + const uint8_t sig[], size_t sig_length) + { + update(msg, msg_length); + return check_signature(sig, sig_length); + } + +void PK_Verifier::update(const uint8_t in[], size_t length) + { + m_op->update(in, length); + } + +bool PK_Verifier::check_signature(const uint8_t sig[], size_t length) + { + try { + if(m_sig_format == IEEE_1363) + { + return m_op->is_valid_signature(sig, length); + } + else if(m_sig_format == DER_SEQUENCE) + { + std::vector<uint8_t> real_sig; + BER_Decoder decoder(sig, length); + BER_Decoder ber_sig = decoder.start_cons(SEQUENCE); + + BOTAN_ASSERT_NOMSG(m_parts != 0 && m_part_size != 0); + + size_t count = 0; + + while(ber_sig.more_items()) + { + BigInt sig_part; + ber_sig.decode(sig_part); + real_sig += BigInt::encode_1363(sig_part, m_part_size); + ++count; + } + + if(count != m_parts) + throw Decoding_Error("PK_Verifier: signature size invalid"); + + const std::vector<uint8_t> reencoded = + der_encode_signature(real_sig, m_parts, m_part_size); + + if(reencoded.size() != length || + same_mem(reencoded.data(), sig, reencoded.size()) == false) + { + throw Decoding_Error("PK_Verifier: signature is not the canonical DER encoding"); + } + + return m_op->is_valid_signature(real_sig.data(), real_sig.size()); + } + else + throw Internal_Error("PK_Verifier: Invalid signature format enum"); + } + catch(Invalid_Argument&) { return false; } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/pubkey.h b/src/libs/3rdparty/botan/src/lib/pubkey/pubkey.h new file mode 100644 index 0000000000..a33142079f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/pubkey.h @@ -0,0 +1,771 @@ +/* +* Public Key Interface +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PUBKEY_H_ +#define BOTAN_PUBKEY_H_ + +#include <botan/pk_keys.h> +#include <botan/pk_ops_fwd.h> +#include <botan/symkey.h> + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include <botan/system_rng.h> + #define BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS +#endif + +namespace Botan { + +class RandomNumberGenerator; + +/** +* The two types of signature format supported by Botan. +*/ +enum Signature_Format { IEEE_1363, DER_SEQUENCE }; + +/** +* Public Key Encryptor +* This is the primary interface for public key encryption +*/ +class BOTAN_PUBLIC_API(2,0) PK_Encryptor + { + public: + + /** + * Encrypt a message. + * @param in the message as a byte array + * @param length the length of the above byte array + * @param rng the random number source to use + * @return encrypted message + */ + std::vector<uint8_t> encrypt(const uint8_t in[], size_t length, + RandomNumberGenerator& rng) const + { + return enc(in, length, rng); + } + + /** + * Encrypt a message. + * @param in the message + * @param rng the random number source to use + * @return encrypted message + */ + template<typename Alloc> + std::vector<uint8_t> encrypt(const std::vector<uint8_t, Alloc>& in, + RandomNumberGenerator& rng) const + { + return enc(in.data(), in.size(), rng); + } + + /** + * Return the maximum allowed message size in bytes. + * @return maximum message size in bytes + */ + virtual size_t maximum_input_size() const = 0; + + PK_Encryptor() = default; + virtual ~PK_Encryptor() = default; + + PK_Encryptor(const PK_Encryptor&) = delete; + PK_Encryptor& operator=(const PK_Encryptor&) = delete; + + private: + virtual std::vector<uint8_t> enc(const uint8_t[], size_t, + RandomNumberGenerator&) const = 0; + }; + +/** +* Public Key Decryptor +*/ +class BOTAN_PUBLIC_API(2,0) PK_Decryptor + { + public: + /** + * Decrypt a ciphertext, throwing an exception if the input + * seems to be invalid (eg due to an accidental or malicious + * error in the ciphertext). + * + * @param in the ciphertext as a byte array + * @param length the length of the above byte array + * @return decrypted message + */ + secure_vector<uint8_t> decrypt(const uint8_t in[], size_t length) const; + + /** + * Same as above, but taking a vector + * @param in the ciphertext + * @return decrypted message + */ + template<typename Alloc> + secure_vector<uint8_t> decrypt(const std::vector<uint8_t, Alloc>& in) const + { + return decrypt(in.data(), in.size()); + } + + /** + * Decrypt a ciphertext. If the ciphertext is invalid (eg due to + * invalid padding) or is not the expected length, instead + * returns a random string of the expected length. Use to avoid + * oracle attacks, especially against PKCS #1 v1.5 decryption. + */ + secure_vector<uint8_t> + decrypt_or_random(const uint8_t in[], + size_t length, + size_t expected_pt_len, + RandomNumberGenerator& rng) const; + + /** + * Decrypt a ciphertext. If the ciphertext is invalid (eg due to + * invalid padding) or is not the expected length, instead + * returns a random string of the expected length. Use to avoid + * oracle attacks, especially against PKCS #1 v1.5 decryption. + * + * Additionally checks (also in const time) that: + * contents[required_content_offsets[i]] == required_content_bytes[i] + * for 0 <= i < required_contents + * + * Used for example in TLS, which encodes the client version in + * the content bytes: if there is any timing variation the version + * check can be used as an oracle to recover the key. + */ + secure_vector<uint8_t> + decrypt_or_random(const uint8_t in[], + size_t length, + size_t expected_pt_len, + RandomNumberGenerator& rng, + const uint8_t required_content_bytes[], + const uint8_t required_content_offsets[], + size_t required_contents) const; + + PK_Decryptor() = default; + virtual ~PK_Decryptor() = default; + + PK_Decryptor(const PK_Decryptor&) = delete; + PK_Decryptor& operator=(const PK_Decryptor&) = delete; + + private: + virtual secure_vector<uint8_t> do_decrypt(uint8_t& valid_mask, + const uint8_t in[], size_t in_len) const = 0; + }; + +/** +* Public Key Signer. Use the sign_message() functions for small +* messages. Use multiple calls update() to process large messages and +* generate the signature by finally calling signature(). +*/ +class BOTAN_PUBLIC_API(2,0) PK_Signer final + { + public: + + /** + * Construct a PK Signer. + * @param key the key to use inside this signer + * @param rng the random generator to use + * @param emsa the EMSA to use + * An example would be "EMSA1(SHA-224)". + * @param format the signature format to use + * @param provider the provider to use + */ + PK_Signer(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& emsa, + Signature_Format format = IEEE_1363, + const std::string& provider = ""); + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + /** + * Construct a PK Signer. + * @param key the key to use inside this signer + * @param emsa the EMSA to use + * An example would be "EMSA1(SHA-224)". + * @param format the signature format to use + */ + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_Signer(const Private_Key& key, + const std::string& emsa, + Signature_Format format = IEEE_1363, + const std::string& provider = "") : + PK_Signer(key, system_rng(), emsa, format, provider) + {} +#endif + + ~PK_Signer(); + + PK_Signer(const PK_Signer&) = delete; + PK_Signer& operator=(const PK_Signer&) = delete; + + /** + * Sign a message all in one go + * @param in the message to sign as a byte array + * @param length the length of the above byte array + * @param rng the rng to use + * @return signature + */ + std::vector<uint8_t> sign_message(const uint8_t in[], size_t length, + RandomNumberGenerator& rng) + { + this->update(in, length); + return this->signature(rng); + } + + /** + * Sign a message. + * @param in the message to sign + * @param rng the rng to use + * @return signature + */ + std::vector<uint8_t> sign_message(const std::vector<uint8_t>& in, + RandomNumberGenerator& rng) + { return sign_message(in.data(), in.size(), rng); } + + /** + * Sign a message. + * @param in the message to sign + * @param rng the rng to use + * @return signature + */ + std::vector<uint8_t> sign_message(const secure_vector<uint8_t>& in, + RandomNumberGenerator& rng) + { return sign_message(in.data(), in.size(), rng); } + + /** + * Add a message part (single byte). + * @param in the byte to add + */ + void update(uint8_t in) { update(&in, 1); } + + /** + * Add a message part. + * @param in the message part to add as a byte array + * @param length the length of the above byte array + */ + void update(const uint8_t in[], size_t length); + + /** + * Add a message part. + * @param in the message part to add + */ + void update(const std::vector<uint8_t>& in) { update(in.data(), in.size()); } + + /** + * Add a message part. + * @param in the message part to add + */ + void update(const std::string& in) + { + update(cast_char_ptr_to_uint8(in.data()), in.size()); + } + + /** + * Get the signature of the so far processed message (provided by the + * calls to update()). + * @param rng the rng to use + * @return signature of the total message + */ + std::vector<uint8_t> signature(RandomNumberGenerator& rng); + + /** + * Set the output format of the signature. + * @param format the signature format to use + */ + void set_output_format(Signature_Format format) { m_sig_format = format; } + private: + std::unique_ptr<PK_Ops::Signature> m_op; + Signature_Format m_sig_format; + size_t m_parts, m_part_size; + }; + +/** +* Public Key Verifier. Use the verify_message() functions for small +* messages. Use multiple calls update() to process large messages and +* verify the signature by finally calling check_signature(). +*/ +class BOTAN_PUBLIC_API(2,0) PK_Verifier final + { + public: + /** + * Construct a PK Verifier. + * @param pub_key the public key to verify against + * @param emsa the EMSA to use (eg "EMSA3(SHA-1)") + * @param format the signature format to use + * @param provider the provider to use + */ + PK_Verifier(const Public_Key& pub_key, + const std::string& emsa, + Signature_Format format = IEEE_1363, + const std::string& provider = ""); + + ~PK_Verifier(); + + PK_Verifier& operator=(const PK_Verifier&) = delete; + PK_Verifier(const PK_Verifier&) = delete; + + /** + * Verify a signature. + * @param msg the message that the signature belongs to, as a byte array + * @param msg_length the length of the above byte array msg + * @param sig the signature as a byte array + * @param sig_length the length of the above byte array sig + * @return true if the signature is valid + */ + bool verify_message(const uint8_t msg[], size_t msg_length, + const uint8_t sig[], size_t sig_length); + /** + * Verify a signature. + * @param msg the message that the signature belongs to + * @param sig the signature + * @return true if the signature is valid + */ + template<typename Alloc, typename Alloc2> + bool verify_message(const std::vector<uint8_t, Alloc>& msg, + const std::vector<uint8_t, Alloc2>& sig) + { + return verify_message(msg.data(), msg.size(), + sig.data(), sig.size()); + } + + /** + * Add a message part (single byte) of the message corresponding to the + * signature to be verified. + * @param in the byte to add + */ + void update(uint8_t in) { update(&in, 1); } + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + * @param msg_part the new message part as a byte array + * @param length the length of the above byte array + */ + void update(const uint8_t msg_part[], size_t length); + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + * @param in the new message part + */ + void update(const std::vector<uint8_t>& in) + { update(in.data(), in.size()); } + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + */ + void update(const std::string& in) + { + update(cast_char_ptr_to_uint8(in.data()), in.size()); + } + + /** + * Check the signature of the buffered message, i.e. the one build + * by successive calls to update. + * @param sig the signature to be verified as a byte array + * @param length the length of the above byte array + * @return true if the signature is valid, false otherwise + */ + bool check_signature(const uint8_t sig[], size_t length); + + /** + * Check the signature of the buffered message, i.e. the one build + * by successive calls to update. + * @param sig the signature to be verified + * @return true if the signature is valid, false otherwise + */ + template<typename Alloc> + bool check_signature(const std::vector<uint8_t, Alloc>& sig) + { + return check_signature(sig.data(), sig.size()); + } + + /** + * Set the format of the signatures fed to this verifier. + * @param format the signature format to use + */ + void set_input_format(Signature_Format format); + + private: + std::unique_ptr<PK_Ops::Verification> m_op; + Signature_Format m_sig_format; + size_t m_parts, m_part_size; + }; + +/** +* Key used for key agreement +*/ +class BOTAN_PUBLIC_API(2,0) PK_Key_Agreement final + { + public: + + /** + * Construct a PK Key Agreement. + * @param key the key to use + * @param rng the random generator to use + * @param kdf name of the KDF to use (or 'Raw' for no KDF) + * @param provider the algo provider to use (or empty for default) + */ + PK_Key_Agreement(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& kdf, + const std::string& provider = ""); + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + /** + * Construct a PK Key Agreement. + * @param key the key to use + * @param kdf name of the KDF to use (or 'Raw' for no KDF) + * @param provider the algo provider to use (or empty for default) + */ + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_Key_Agreement(const Private_Key& key, + const std::string& kdf, + const std::string& provider = "") : + PK_Key_Agreement(key, system_rng(), kdf, provider) + {} +#endif + + ~PK_Key_Agreement(); + + // For ECIES + PK_Key_Agreement& operator=(PK_Key_Agreement&&); + PK_Key_Agreement(PK_Key_Agreement&&); + + PK_Key_Agreement& operator=(const PK_Key_Agreement&) = delete; + PK_Key_Agreement(const PK_Key_Agreement&) = delete; + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + * @param params_len the length of params in bytes + */ + SymmetricKey derive_key(size_t key_len, + const uint8_t in[], + size_t in_len, + const uint8_t params[], + size_t params_len) const; + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + * @param params_len the length of params in bytes + */ + SymmetricKey derive_key(size_t key_len, + const std::vector<uint8_t>& in, + const uint8_t params[], + size_t params_len) const + { + return derive_key(key_len, in.data(), in.size(), + params, params_len); + } + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param in_len the length of in in bytes + * @param params extra derivation params + */ + SymmetricKey derive_key(size_t key_len, + const uint8_t in[], size_t in_len, + const std::string& params = "") const + { + return derive_key(key_len, in, in_len, + cast_char_ptr_to_uint8(params.data()), + params.length()); + } + + /* + * Perform Key Agreement Operation + * @param key_len the desired key output size + * @param in the other parties key + * @param params extra derivation params + */ + SymmetricKey derive_key(size_t key_len, + const std::vector<uint8_t>& in, + const std::string& params = "") const + { + return derive_key(key_len, in.data(), in.size(), + cast_char_ptr_to_uint8(params.data()), + params.length()); + } + + private: + std::unique_ptr<PK_Ops::Key_Agreement> m_op; + }; + +/** +* Encryption using a standard message recovery algorithm like RSA or +* ElGamal, paired with an encoding scheme like OAEP. +*/ +class BOTAN_PUBLIC_API(2,0) PK_Encryptor_EME final : public PK_Encryptor + { + public: + size_t maximum_input_size() const override; + + /** + * Construct an instance. + * @param key the key to use inside the encryptor + * @param rng the RNG to use + * @param padding the message encoding scheme to use (eg "OAEP(SHA-256)") + * @param provider the provider to use + */ + PK_Encryptor_EME(const Public_Key& key, + RandomNumberGenerator& rng, + const std::string& padding, + const std::string& provider = ""); + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + /** + * Construct an instance. + * @param key the key to use inside the encryptor + * @param padding the message encoding scheme to use (eg "OAEP(SHA-256)") + */ + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_Encryptor_EME(const Public_Key& key, + const std::string& padding, + const std::string& provider = "") : + PK_Encryptor_EME(key, system_rng(), padding, provider) {} +#endif + + ~PK_Encryptor_EME(); + + PK_Encryptor_EME& operator=(const PK_Encryptor_EME&) = delete; + PK_Encryptor_EME(const PK_Encryptor_EME&) = delete; + private: + std::vector<uint8_t> enc(const uint8_t[], size_t, + RandomNumberGenerator& rng) const override; + + std::unique_ptr<PK_Ops::Encryption> m_op; + }; + +/** +* Decryption with an MR algorithm and an EME. +*/ +class BOTAN_PUBLIC_API(2,0) PK_Decryptor_EME final : public PK_Decryptor + { + public: + /** + * Construct an instance. + * @param key the key to use inside the decryptor + * @param rng the random generator to use + * @param eme the EME to use + * @param provider the provider to use + */ + PK_Decryptor_EME(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& eme, + const std::string& provider = ""); + + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + /** + * Construct an instance. + * @param key the key to use inside the decryptor + * @param eme the message encoding scheme to use (eg "OAEP(SHA-256)") + */ + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_Decryptor_EME(const Private_Key& key, + const std::string& eme, + const std::string& provider = "") : + PK_Decryptor_EME(key, system_rng(), eme, provider) {} +#endif + + ~PK_Decryptor_EME(); + PK_Decryptor_EME& operator=(const PK_Decryptor_EME&) = delete; + PK_Decryptor_EME(const PK_Decryptor_EME&) = delete; + private: + secure_vector<uint8_t> do_decrypt(uint8_t& valid_mask, + const uint8_t in[], + size_t in_len) const override; + + std::unique_ptr<PK_Ops::Decryption> m_op; + }; + +/** +* Public Key Key Encapsulation Mechanism Encryption. +*/ +class BOTAN_PUBLIC_API(2,0) PK_KEM_Encryptor final + { + public: + /** + * Construct an instance. + * @param key the key to use inside the encryptor + * @param rng the RNG to use + * @param kem_param additional KEM parameters + * @param provider the provider to use + */ + PK_KEM_Encryptor(const Public_Key& key, + RandomNumberGenerator& rng, + const std::string& kem_param = "", + const std::string& provider = ""); + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_KEM_Encryptor(const Public_Key& key, + const std::string& kem_param = "", + const std::string& provider = "") : + PK_KEM_Encryptor(key, system_rng(), kem_param, provider) {} +#endif + + ~PK_KEM_Encryptor(); + + PK_KEM_Encryptor& operator=(const PK_KEM_Encryptor&) = delete; + PK_KEM_Encryptor(const PK_KEM_Encryptor&) = delete; + + /** + * Generate a shared key for data encryption. + * @param out_encapsulated_key the generated encapsulated key + * @param out_shared_key the generated shared key + * @param desired_shared_key_len desired size of the shared key in bytes + * @param rng the RNG to use + * @param salt a salt value used in the KDF + * @param salt_len size of the salt value in bytes + */ + void encrypt(secure_vector<uint8_t>& out_encapsulated_key, + secure_vector<uint8_t>& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const uint8_t salt[], + size_t salt_len); + + /** + * Generate a shared key for data encryption. + * @param out_encapsulated_key the generated encapsulated key + * @param out_shared_key the generated shared key + * @param desired_shared_key_len desired size of the shared key in bytes + * @param rng the RNG to use + * @param salt a salt value used in the KDF + */ + template<typename Alloc> + void encrypt(secure_vector<uint8_t>& out_encapsulated_key, + secure_vector<uint8_t>& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng, + const std::vector<uint8_t, Alloc>& salt) + { + this->encrypt(out_encapsulated_key, + out_shared_key, + desired_shared_key_len, + rng, + salt.data(), salt.size()); + } + + + /** + * Generate a shared key for data encryption. + * @param out_encapsulated_key the generated encapsulated key + * @param out_shared_key the generated shared key + * @param desired_shared_key_len desired size of the shared key in bytes + * @param rng the RNG to use + */ + void encrypt(secure_vector<uint8_t>& out_encapsulated_key, + secure_vector<uint8_t>& out_shared_key, + size_t desired_shared_key_len, + Botan::RandomNumberGenerator& rng) + { + this->encrypt(out_encapsulated_key, + out_shared_key, + desired_shared_key_len, + rng, + nullptr, + 0); + } + + private: + std::unique_ptr<PK_Ops::KEM_Encryption> m_op; + }; + +/** +* Public Key Key Encapsulation Mechanism Decryption. +*/ +class BOTAN_PUBLIC_API(2,0) PK_KEM_Decryptor final + { + public: + /** + * Construct an instance. + * @param key the key to use inside the decryptor + * @param rng the RNG to use + * @param kem_param additional KEM parameters + * @param provider the provider to use + */ + PK_KEM_Decryptor(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& kem_param = "", + const std::string& provider = ""); + +#if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) + BOTAN_DEPRECATED("Use constructor taking a RNG object") + PK_KEM_Decryptor(const Private_Key& key, + const std::string& kem_param = "", + const std::string& provider = "") : + PK_KEM_Decryptor(key, system_rng(), kem_param, provider) + {} +#endif + + ~PK_KEM_Decryptor(); + PK_KEM_Decryptor& operator=(const PK_KEM_Decryptor&) = delete; + PK_KEM_Decryptor(const PK_KEM_Decryptor&) = delete; + + /** + * Decrypts the shared key for data encryption. + * @param encap_key the encapsulated key + * @param encap_key_len size of the encapsulated key in bytes + * @param desired_shared_key_len desired size of the shared key in bytes + * @param salt a salt value used in the KDF + * @param salt_len size of the salt value in bytes + * @return the shared data encryption key + */ + secure_vector<uint8_t> decrypt(const uint8_t encap_key[], + size_t encap_key_len, + size_t desired_shared_key_len, + const uint8_t salt[], + size_t salt_len); + + /** + * Decrypts the shared key for data encryption. + * @param encap_key the encapsulated key + * @param encap_key_len size of the encapsulated key in bytes + * @param desired_shared_key_len desired size of the shared key in bytes + * @return the shared data encryption key + */ + secure_vector<uint8_t> decrypt(const uint8_t encap_key[], + size_t encap_key_len, + size_t desired_shared_key_len) + { + return this->decrypt(encap_key, encap_key_len, + desired_shared_key_len, + nullptr, 0); + } + + /** + * Decrypts the shared key for data encryption. + * @param encap_key the encapsulated key + * @param desired_shared_key_len desired size of the shared key in bytes + * @param salt a salt value used in the KDF + * @return the shared data encryption key + */ + template<typename Alloc1, typename Alloc2> + secure_vector<uint8_t> decrypt(const std::vector<uint8_t, Alloc1>& encap_key, + size_t desired_shared_key_len, + const std::vector<uint8_t, Alloc2>& salt) + { + return this->decrypt(encap_key.data(), encap_key.size(), + desired_shared_key_len, + salt.data(), salt.size()); + } + + private: + std::unique_ptr<PK_Ops::KEM_Decryption> m_op; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/rsa/info.txt b/src/libs/3rdparty/botan/src/lib/pubkey/rsa/info.txt new file mode 100644 index 0000000000..9fc9354b83 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/rsa/info.txt @@ -0,0 +1,10 @@ +<defines> +RSA -> 20160730 +</defines> + +<requires> +keypair +numbertheory +emsa_pssr +sha2_32 +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/rsa/rsa.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/rsa/rsa.cpp new file mode 100644 index 0000000000..eb4c612ae0 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/rsa/rsa.cpp @@ -0,0 +1,579 @@ +/* +* RSA +* (C) 1999-2010,2015,2016,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/rsa.h> +#include <botan/internal/pk_ops_impl.h> +#include <botan/keypair.h> +#include <botan/blinding.h> +#include <botan/reducer.h> +#include <botan/workfactor.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/pow_mod.h> +#include <botan/monty.h> +#include <botan/internal/monty_exp.h> + +#if defined(BOTAN_HAS_OPENSSL) + #include <botan/internal/openssl.h> +#endif + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + #include <future> +#endif + +namespace Botan { + +size_t RSA_PublicKey::key_length() const + { + return m_n.bits(); + } + +size_t RSA_PublicKey::estimated_strength() const + { + return if_work_factor(key_length()); + } + +AlgorithmIdentifier RSA_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), + AlgorithmIdentifier::USE_NULL_PARAM); + } + +std::vector<uint8_t> RSA_PublicKey::public_key_bits() const + { + std::vector<uint8_t> output; + DER_Encoder der(output); + der.start_cons(SEQUENCE) + .encode(m_n) + .encode(m_e) + .end_cons(); + + return output; + } + +RSA_PublicKey::RSA_PublicKey(const AlgorithmIdentifier&, + const std::vector<uint8_t>& key_bits) + { + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode(m_n) + .decode(m_e) + .end_cons(); + } + +/* +* Check RSA Public Parameters +*/ +bool RSA_PublicKey::check_key(RandomNumberGenerator&, bool) const + { + if(m_n < 35 || m_n.is_even() || m_e < 3 || m_e.is_even()) + return false; + return true; + } + +secure_vector<uint8_t> RSA_PrivateKey::private_key_bits() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast<size_t>(0)) + .encode(m_n) + .encode(m_e) + .encode(m_d) + .encode(m_p) + .encode(m_q) + .encode(m_d1) + .encode(m_d2) + .encode(m_c) + .end_cons() + .get_contents(); + } + +RSA_PrivateKey::RSA_PrivateKey(const AlgorithmIdentifier&, + const secure_vector<uint8_t>& key_bits) + { + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode_and_check<size_t>(0, "Unknown PKCS #1 key format version") + .decode(m_n) + .decode(m_e) + .decode(m_d) + .decode(m_p) + .decode(m_q) + .decode(m_d1) + .decode(m_d2) + .decode(m_c) + .end_cons(); + } + +RSA_PrivateKey::RSA_PrivateKey(const BigInt& prime1, + const BigInt& prime2, + const BigInt& exp, + const BigInt& d_exp, + const BigInt& mod) : + m_d{ d_exp }, m_p{ prime1 }, m_q{ prime2 }, m_d1{}, m_d2{}, m_c{ inverse_mod( m_q, m_p ) } + { + m_n = mod.is_nonzero() ? mod : m_p * m_q; + m_e = exp; + + if(m_d == 0) + { + const BigInt phi_n = lcm(m_p - 1, m_q - 1); + m_d = inverse_mod(m_e, phi_n); + } + + m_d1 = m_d % (m_p - 1); + m_d2 = m_d % (m_q - 1); + } + +/* +* Create a RSA private key +*/ +RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, + size_t bits, size_t exp) + { + if(bits < 1024) + throw Invalid_Argument(algo_name() + ": Can't make a key that is only " + + std::to_string(bits) + " bits long"); + if(exp < 3 || exp % 2 == 0) + throw Invalid_Argument(algo_name() + ": Invalid encryption exponent"); + + m_e = exp; + + const size_t p_bits = (bits + 1) / 2; + const size_t q_bits = bits - p_bits; + + do + { + m_p = generate_rsa_prime(rng, rng, p_bits, m_e); + m_q = generate_rsa_prime(rng, rng, q_bits, m_e); + m_n = m_p * m_q; + } while(m_n.bits() != bits); + + // FIXME: lcm calls gcd which is not const time + const BigInt phi_n = lcm(m_p - 1, m_q - 1); + // FIXME: this uses binary ext gcd because phi_n is even + m_d = inverse_mod(m_e, phi_n); + m_d1 = m_d % (m_p - 1); + m_d2 = m_d % (m_q - 1); + m_c = inverse_mod(m_q, m_p); + } + +/* +* Check Private RSA Parameters +*/ +bool RSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(m_n < 35 || m_n.is_even() || m_e < 3 || m_e.is_even()) + return false; + + if(m_d < 2 || m_p < 3 || m_q < 3 || m_p*m_q != m_n) + return false; + + if(m_d1 != m_d % (m_p - 1) || m_d2 != m_d % (m_q - 1) || m_c != inverse_mod(m_q, m_p)) + return false; + + const size_t prob = (strong) ? 128 : 12; + + if(!is_prime(m_p, rng, prob) || !is_prime(m_q, rng, prob)) + return false; + + if(strong) + { + if((m_e * m_d) % lcm(m_p - 1, m_q - 1) != 1) + return false; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA4(SHA-256)"); + } + + return true; + } + +namespace { + +/** +* RSA private (decrypt/sign) operation +*/ +class RSA_Private_Operation + { + protected: + size_t get_max_input_bits() const { return (m_mod_bits - 1); } + + const size_t exp_blinding_bits = 64; + + explicit RSA_Private_Operation(const RSA_PrivateKey& rsa, RandomNumberGenerator& rng) : + m_key(rsa), + m_mod_p(m_key.get_p()), + m_mod_q(m_key.get_q()), + m_monty_p(std::make_shared<Montgomery_Params>(m_key.get_p(), m_mod_p)), + m_monty_q(std::make_shared<Montgomery_Params>(m_key.get_q(), m_mod_q)), + m_powermod_e_n(m_key.get_e(), m_key.get_n()), + m_blinder(m_key.get_n(), + rng, + [this](const BigInt& k) { return m_powermod_e_n(k); }, + [this](const BigInt& k) { return inverse_mod(k, m_key.get_n()); }), + m_blinding_bits(64), + m_mod_bytes(m_key.get_n().bytes()), + m_mod_bits(m_key.get_n().bits()), + m_max_d1_bits(m_key.get_p().bits() + m_blinding_bits), + m_max_d2_bits(m_key.get_q().bits() + m_blinding_bits) + { + } + + BigInt blinded_private_op(const BigInt& m) const + { + if(m >= m_key.get_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 + { + const size_t powm_window = 4; + + const BigInt d1_mask(m_blinder.rng(), m_blinding_bits); + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + auto future_j1 = std::async(std::launch::async, [this, &m, &d1_mask, powm_window]() { + const BigInt masked_d1 = m_key.get_d1() + (d1_mask * (m_key.get_p() - 1)); + auto powm_d1_p = monty_precompute(m_monty_p, m, powm_window); + return monty_execute(*powm_d1_p, masked_d1, m_max_d1_bits); + }); +#else + const BigInt masked_d1 = m_key.get_d1() + (d1_mask * (m_key.get_p() - 1)); + auto powm_d1_p = monty_precompute(m_monty_p, m, powm_window); + BigInt j1 = monty_execute(*powm_d1_p, masked_d1, m_max_d1_bits); +#endif + + const BigInt d2_mask(m_blinder.rng(), m_blinding_bits); + const BigInt masked_d2 = m_key.get_d2() + (d2_mask * (m_key.get_q() - 1)); + auto powm_d2_q = monty_precompute(m_monty_q, m, powm_window); + const BigInt j2 = monty_execute(*powm_d2_q, masked_d2, m_max_d2_bits); + + /* + * To recover the final value from the CRT representation (j1,j2) + * we use Garner's algorithm: + * c = q^-1 mod p (this is precomputed) + * h = c*(j1-j2) mod p + * m = j2 + h*q + */ + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + BigInt j1 = future_j1.get(); +#endif + + /* + To prevent a side channel that allows detecting case where j1 < j2, + add p to j1 before reducing [computing c*(p+j1-j2) mod p] + */ + j1 = m_mod_p.reduce(sub_mul(m_key.get_p() + j1, j2, m_key.get_c())); + return mul_add(j1, m_key.get_q(), j2); + } + + const RSA_PrivateKey& m_key; + + // TODO these could all be computed once and stored in the key object + Modular_Reducer m_mod_p; + Modular_Reducer m_mod_q; + std::shared_ptr<const Montgomery_Params> m_monty_p; + std::shared_ptr<const Montgomery_Params> m_monty_q; + + Fixed_Exponent_Power_Mod m_powermod_e_n; + Blinder m_blinder; + const size_t m_blinding_bits; + const size_t m_mod_bytes; + const size_t m_mod_bits; + const size_t m_max_d1_bits; + const size_t m_max_d2_bits; + }; + +class RSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA, + private RSA_Private_Operation + { + public: + + size_t max_input_bits() const override { return get_max_input_bits(); } + + RSA_Signature_Operation(const RSA_PrivateKey& rsa, const std::string& emsa, RandomNumberGenerator& rng) : + PK_Ops::Signature_with_EMSA(emsa), + RSA_Private_Operation(rsa, rng) + { + } + + secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator&) override + { + const BigInt m(msg, msg_len); + const BigInt x = blinded_private_op(m); + const BigInt c = m_powermod_e_n(x); + BOTAN_ASSERT(m == c, "RSA sign consistency check"); + return BigInt::encode_1363(x, m_mod_bytes); + } + }; + +class RSA_Decryption_Operation final : public PK_Ops::Decryption_with_EME, + private RSA_Private_Operation + { + public: + + RSA_Decryption_Operation(const RSA_PrivateKey& rsa, const std::string& eme, RandomNumberGenerator& rng) : + PK_Ops::Decryption_with_EME(eme), + RSA_Private_Operation(rsa, rng) + { + } + + secure_vector<uint8_t> raw_decrypt(const uint8_t msg[], size_t msg_len) override + { + const BigInt m(msg, msg_len); + const BigInt x = blinded_private_op(m); + const BigInt c = m_powermod_e_n(x); + BOTAN_ASSERT(m == c, "RSA decrypt consistency check"); + return BigInt::encode_1363(x, m_mod_bytes); + } + }; + +class RSA_KEM_Decryption_Operation final : public PK_Ops::KEM_Decryption_with_KDF, + private RSA_Private_Operation + { + public: + + RSA_KEM_Decryption_Operation(const RSA_PrivateKey& key, + const std::string& kdf, + RandomNumberGenerator& rng) : + PK_Ops::KEM_Decryption_with_KDF(kdf), + RSA_Private_Operation(key, rng) + {} + + secure_vector<uint8_t> + raw_kem_decrypt(const uint8_t encap_key[], size_t len) override + { + const BigInt m(encap_key, len); + const BigInt x = blinded_private_op(m); + const BigInt c = m_powermod_e_n(x); + BOTAN_ASSERT(m == c, "RSA KEM consistency check"); + return BigInt::encode_1363(x, m_mod_bytes); + } + }; + +/** +* RSA public (encrypt/verify) operation +*/ +class RSA_Public_Operation + { + public: + explicit RSA_Public_Operation(const RSA_PublicKey& rsa) : + m_n(rsa.get_n()), + m_e(rsa.get_e()), + m_monty_n(std::make_shared<Montgomery_Params>(m_n)) + {} + + size_t get_max_input_bits() const { return (m_n.bits() - 1); } + + protected: + BigInt public_op(const BigInt& m) const + { + if(m >= m_n) + throw Invalid_Argument("RSA public op - input is too large"); + + const size_t powm_window = 1; + + auto powm_m_n = monty_precompute(m_monty_n, m, powm_window, false); + return monty_execute_vartime(*powm_m_n, m_e); + } + + const BigInt& get_n() const { return m_n; } + + const BigInt& m_n; + const BigInt& m_e; + std::shared_ptr<Montgomery_Params> m_monty_n; + }; + +class RSA_Encryption_Operation final : public PK_Ops::Encryption_with_EME, + private RSA_Public_Operation + { + public: + + RSA_Encryption_Operation(const RSA_PublicKey& rsa, const std::string& eme) : + PK_Ops::Encryption_with_EME(eme), + RSA_Public_Operation(rsa) + { + } + + size_t max_raw_input_bits() const override { return get_max_input_bits(); } + + secure_vector<uint8_t> raw_encrypt(const uint8_t msg[], size_t msg_len, + RandomNumberGenerator&) override + { + BigInt m(msg, msg_len); + return BigInt::encode_1363(public_op(m), m_n.bytes()); + } + }; + +class RSA_Verify_Operation final : public PK_Ops::Verification_with_EMSA, + private RSA_Public_Operation + { + public: + + size_t max_input_bits() const override { return get_max_input_bits(); } + + RSA_Verify_Operation(const RSA_PublicKey& rsa, const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + RSA_Public_Operation(rsa) + { + } + + bool with_recovery() const override { return true; } + + secure_vector<uint8_t> verify_mr(const uint8_t msg[], size_t msg_len) override + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(public_op(m)); + } + }; + +class RSA_KEM_Encryption_Operation final : public PK_Ops::KEM_Encryption_with_KDF, + private RSA_Public_Operation + { + public: + + RSA_KEM_Encryption_Operation(const RSA_PublicKey& key, + const std::string& kdf) : + PK_Ops::KEM_Encryption_with_KDF(kdf), + RSA_Public_Operation(key) {} + + private: + void raw_kem_encrypt(secure_vector<uint8_t>& out_encapsulated_key, + secure_vector<uint8_t>& raw_shared_key, + Botan::RandomNumberGenerator& rng) override + { + const BigInt r = BigInt::random_integer(rng, 1, get_n()); + const BigInt c = public_op(r); + + out_encapsulated_key = BigInt::encode_locked(c); + raw_shared_key = BigInt::encode_locked(r); + } + }; + +} + +std::unique_ptr<PK_Ops::Encryption> +RSA_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + try + { + return make_openssl_rsa_enc_op(*this, params); + } + catch(Exception& e) + { + /* + * If OpenSSL for some reason could not handle this (eg due to OAEP params), + * throw if openssl was specifically requested but otherwise just fall back + * to the normal version. + */ + if(provider == "openssl") + throw Lookup_Error("OpenSSL RSA provider rejected key:" + std::string(e.what())); + } + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Encryption>(new RSA_Encryption_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr<PK_Ops::KEM_Encryption> +RSA_PublicKey::create_kem_encryption_op(RandomNumberGenerator& /*rng*/, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::KEM_Encryption>(new RSA_KEM_Encryption_Operation(*this, params)); + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr<PK_Ops::Verification> +RSA_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + std::unique_ptr<PK_Ops::Verification> res = make_openssl_rsa_ver_op(*this, params); + if(res) + return res; + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Verification>(new RSA_Verify_Operation(*this, params)); + + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr<PK_Ops::Decryption> +RSA_PrivateKey::create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + try + { + return make_openssl_rsa_dec_op(*this, params); + } + catch(Exception& e) + { + if(provider == "openssl") + throw Lookup_Error("OpenSSL RSA provider rejected key:" + std::string(e.what())); + } + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Decryption>(new RSA_Decryption_Operation(*this, params, rng)); + + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr<PK_Ops::KEM_Decryption> +RSA_PrivateKey::create_kem_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::KEM_Decryption>(new RSA_KEM_Decryption_Operation(*this, params, rng)); + + throw Provider_Not_Found(algo_name(), provider); + } + +std::unique_ptr<PK_Ops::Signature> +RSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider == "openssl" || provider.empty()) + { + std::unique_ptr<PK_Ops::Signature> res = make_openssl_rsa_sig_op(*this, params); + if(res) + return res; + } +#endif + + if(provider == "base" || provider.empty()) + return std::unique_ptr<PK_Ops::Signature>(new RSA_Signature_Operation(*this, params, rng)); + + throw Provider_Not_Found(algo_name(), provider); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/rsa/rsa.h b/src/libs/3rdparty/botan/src/lib/pubkey/rsa/rsa.h new file mode 100644 index 0000000000..ad4fceab99 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/rsa/rsa.h @@ -0,0 +1,164 @@ +/* +* RSA +* (C) 1999-2008,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RSA_H_ +#define BOTAN_RSA_H_ + +#include <botan/pk_keys.h> +#include <botan/bigint.h> + +namespace Botan { + +/** +* RSA Public Key +*/ +class BOTAN_PUBLIC_API(2,0) RSA_PublicKey : public virtual Public_Key + { + public: + /** + * Load a public key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits DER encoded public key bits + */ + RSA_PublicKey(const AlgorithmIdentifier& alg_id, + const std::vector<uint8_t>& key_bits); + + /** + * Create a public key. + * @arg n the modulus + * @arg e the exponent + */ + RSA_PublicKey(const BigInt& n, const BigInt& e) : + m_n(n), m_e(e) {} + + std::string algo_name() const override { return "RSA"; } + + bool check_key(RandomNumberGenerator& rng, bool) const override; + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector<uint8_t> public_key_bits() const override; + + /** + * @return public modulus + */ + const BigInt& get_n() const { return m_n; } + + /** + * @return public exponent + */ + const BigInt& get_e() const { return m_e; } + + size_t key_length() const override; + size_t estimated_strength() const override; + + std::unique_ptr<PK_Ops::Encryption> + create_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr<PK_Ops::KEM_Encryption> + create_kem_encryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr<PK_Ops::Verification> + create_verification_op(const std::string& params, + const std::string& provider) const override; + + protected: + RSA_PublicKey() = default; + + BigInt m_n, m_e; + }; + +/** +* RSA Private Key +*/ +class BOTAN_PUBLIC_API(2,0) RSA_PrivateKey final : public Private_Key, public RSA_PublicKey + { + public: + /** + * Load a private key. + * @param alg_id the X.509 algorithm identifier + * @param key_bits PKCS#1 RSAPrivateKey bits + */ + RSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& key_bits); + + /** + * Construct a private key from the specified parameters. + * @param p the first prime + * @param q the second prime + * @param e the exponent + * @param d if specified, this has to be d with + * exp * d = 1 mod (p - 1, q - 1). Leave it as 0 if you wish to + * the constructor to calculate it. + * @param n if specified, this must be n = p * q. Leave it as 0 + * if you wish to the constructor to calculate it. + */ + RSA_PrivateKey(const BigInt& p, const BigInt& q, + const BigInt& e, const BigInt& d = 0, + const BigInt& n = 0); + + /** + * Create a new private key with the specified bit length + * @param rng the random number generator to use + * @param bits the desired bit length of the private key + * @param exp the public exponent to be used + */ + RSA_PrivateKey(RandomNumberGenerator& rng, + size_t bits, size_t exp = 65537); + + bool check_key(RandomNumberGenerator& rng, bool) const override; + + /** + * Get the first prime p. + * @return prime p + */ + const BigInt& get_p() const { return m_p; } + + /** + * Get the second prime q. + * @return prime q + */ + const BigInt& get_q() const { return m_q; } + + /** + * Get d with exp * d = 1 mod (p - 1, q - 1). + * @return d + */ + const BigInt& get_d() const { return m_d; } + + const BigInt& get_c() const { return m_c; } + const BigInt& get_d1() const { return m_d1; } + const BigInt& get_d2() const { return m_d2; } + + secure_vector<uint8_t> private_key_bits() const override; + + std::unique_ptr<PK_Ops::Decryption> + create_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr<PK_Ops::KEM_Decryption> + create_kem_decryption_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + std::unique_ptr<PK_Ops::Signature> + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; + + private: + BigInt m_d, m_p, m_q, m_d1, m_d2, m_c; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/workfactor.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/workfactor.cpp new file mode 100644 index 0000000000..71604c06bb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/workfactor.cpp @@ -0,0 +1,64 @@ +/* +* Public Key Work Factor Functions +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/workfactor.h> +#include <algorithm> +#include <cmath> + +namespace Botan { + +size_t ecp_work_factor(size_t bits) + { + return bits / 2; + } + +namespace { + +size_t nfs_workfactor(size_t bits, double k) + { + // approximates natural logarithm of integer of given bitsize + const double log2_e = std::log2(std::exp(1)); + const double log_p = bits / log2_e; + + const double log_log_p = std::log(log_p); + + // RFC 3766: k * e^((1.92 + o(1)) * cubrt(ln(n) * (ln(ln(n)))^2)) + const double est = 1.92 * std::pow(log_p * log_log_p * log_log_p, 1.0/3.0); + + // return log2 of the workfactor + return static_cast<size_t>(std::log2(k) + log2_e * est); + } + +} + +size_t if_work_factor(size_t bits) + { + // RFC 3766 estimates k at .02 and o(1) to be effectively zero for sizes of interest + + return nfs_workfactor(bits, .02); + } + +size_t dl_work_factor(size_t bits) + { + // Lacking better estimates... + return if_work_factor(bits); + } + +size_t dl_exponent_size(size_t bits) + { + /* + This uses a slightly tweaked version of the standard work factor + function above. It assumes k is 1 (thus overestimating the strength + of the prime group by 5-6 bits), and always returns at least 128 bits + (this only matters for very small primes). + */ + const size_t MIN_WORKFACTOR = 64; + + return 2 * std::max<size_t>(MIN_WORKFACTOR, nfs_workfactor(bits, 1)); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/workfactor.h b/src/libs/3rdparty/botan/src/lib/pubkey/workfactor.h new file mode 100644 index 0000000000..0eea246d7e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/workfactor.h @@ -0,0 +1,50 @@ +/* +* Public Key Work Factor Functions +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_WORKFACTOR_H_ +#define BOTAN_WORKFACTOR_H_ + +#include <botan/types.h> + +namespace Botan { + +/** +* Estimate work factor for discrete logarithm +* @param prime_group_size size of the group in bits +* @return estimated security level for this group +*/ +BOTAN_PUBLIC_API(2,0) size_t dl_work_factor(size_t prime_group_size); + +/** +* Return the appropriate exponent size to use for a particular prime +* group. This is twice the size of the estimated cost of breaking the +* key using an index calculus attack; the assumption is that if an +* arbitrary discrete log on a group of size bits would take about 2^n +* effort, and thus using an exponent of size 2^(2*n) implies that all +* available attacks are about as easy (as e.g Pollard's kangaroo +* algorithm can compute the DL in sqrt(x) operations) while minimizing +* the exponent size for performance reasons. +*/ +BOTAN_PUBLIC_API(2,0) size_t dl_exponent_size(size_t prime_group_size); + +/** +* Estimate work factor for integer factorization +* @param n_bits size of modulus in bits +* @return estimated security level for this modulus +*/ +BOTAN_PUBLIC_API(2,0) size_t if_work_factor(size_t n_bits); + +/** +* Estimate work factor for EC discrete logarithm +* @param prime_group_size size of the group in bits +* @return estimated security level for this group +*/ +BOTAN_PUBLIC_API(2,0) size_t ecp_work_factor(size_t prime_group_size); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/x509_key.cpp b/src/libs/3rdparty/botan/src/lib/pubkey/x509_key.cpp new file mode 100644 index 0000000000..6e49d953a4 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/x509_key.cpp @@ -0,0 +1,106 @@ +/* +* X.509 Public Key +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509_key.h> +#include <botan/data_src.h> +#include <botan/ber_dec.h> +#include <botan/pem.h> +#include <botan/alg_id.h> +#include <botan/pk_algs.h> + +namespace Botan { + +namespace X509 { + +std::vector<uint8_t> BER_encode(const Public_Key& key) + { + // keeping it around for compat + return key.subject_public_key(); + } + +/* +* PEM encode a X.509 public key +*/ +std::string PEM_encode(const Public_Key& key) + { + return PEM_Code::encode(key.subject_public_key(), + "PUBLIC KEY"); + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(DataSource& source) + { + try { + AlgorithmIdentifier alg_id; + std::vector<uint8_t> key_bits; + + if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) + { + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(alg_id) + .decode(key_bits, BIT_STRING) + .end_cons(); + } + else + { + DataSource_Memory ber( + PEM_Code::decode_check_label(source, "PUBLIC KEY") + ); + + BER_Decoder(ber) + .start_cons(SEQUENCE) + .decode(alg_id) + .decode(key_bits, BIT_STRING) + .end_cons(); + } + + if(key_bits.empty()) + throw Decoding_Error("X.509 public key decoding failed"); + + return load_public_key(alg_id, key_bits).release(); + } + catch(Decoding_Error& e) + { + throw Decoding_Error("X.509 public key decoding failed: " + std::string(e.what())); + } + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +/* +* Extract a public key and return it +*/ +Public_Key* load_key(const std::string& fsname) + { + DataSource_Stream source(fsname, true); + return X509::load_key(source); + } +#endif + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(const std::vector<uint8_t>& mem) + { + DataSource_Memory source(mem); + return X509::load_key(source); + } + +/* +* Make a copy of this public key +*/ +Public_Key* copy_key(const Public_Key& key) + { + DataSource_Memory source(PEM_encode(key)); + return X509::load_key(source); + } + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/pubkey/x509_key.h b/src/libs/3rdparty/botan/src/lib/pubkey/x509_key.h new file mode 100644 index 0000000000..58d537bbe7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/pubkey/x509_key.h @@ -0,0 +1,80 @@ +/* +* X.509 Public Key +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_PUBLIC_KEY_H_ +#define BOTAN_X509_PUBLIC_KEY_H_ + +#include <botan/pk_keys.h> +#include <botan/types.h> +#include <string> +#include <vector> + +namespace Botan { + +class RandomNumberGenerator; +class DataSource; + +/** +* The two types of X509 encoding supported by Botan. +* This enum is not used anymore, and will be removed in a future major release. +*/ +enum X509_Encoding { RAW_BER, PEM }; + +/** +* This namespace contains functions for handling X.509 public keys +*/ +namespace X509 { + +/** +* BER encode a key +* @param key the public key to encode +* @return BER encoding of this key +*/ +BOTAN_PUBLIC_API(2,0) std::vector<uint8_t> BER_encode(const Public_Key& key); + +/** +* PEM encode a public key into a string. +* @param key the key to encode +* @return PEM encoded key +*/ +BOTAN_PUBLIC_API(2,0) std::string PEM_encode(const Public_Key& key); + +/** +* Create a public key from a data source. +* @param source the source providing the DER or PEM encoded key +* @return new public key object +*/ +BOTAN_PUBLIC_API(2,0) Public_Key* load_key(DataSource& source); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +/** +* Create a public key from a file +* @param filename pathname to the file to load +* @return new public key object +*/ +BOTAN_PUBLIC_API(2,0) Public_Key* load_key(const std::string& filename); +#endif + +/** +* Create a public key from a memory region. +* @param enc the memory region containing the DER or PEM encoded key +* @return new public key object +*/ +BOTAN_PUBLIC_API(2,0) Public_Key* load_key(const std::vector<uint8_t>& enc); + +/** +* Copy a key. +* @param key the public key to copy +* @return new public key object +*/ +BOTAN_PUBLIC_API(2,0) Public_Key* copy_key(const Public_Key& key); + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.cpp b/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.cpp new file mode 100644 index 0000000000..ec439e7cfb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.cpp @@ -0,0 +1,112 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/auto_rng.h> +#include <botan/entropy_src.h> +#include <botan/hmac_drbg.h> + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include <botan/system_rng.h> +#endif + +#if !defined(BOTAN_AUTO_RNG_HMAC) +#error "No hash function defined for AutoSeeded_RNG in build.h (try enabling sha2_32)" +#endif + +namespace Botan { + +AutoSeeded_RNG::~AutoSeeded_RNG() + { + // for unique_ptr + } + +AutoSeeded_RNG::AutoSeeded_RNG(RandomNumberGenerator& underlying_rng, + size_t reseed_interval) + { + m_rng.reset(new HMAC_DRBG(MessageAuthenticationCode::create_or_throw(BOTAN_AUTO_RNG_HMAC), + underlying_rng, + reseed_interval)); + force_reseed(); + } + +AutoSeeded_RNG::AutoSeeded_RNG(Entropy_Sources& entropy_sources, + size_t reseed_interval) + { + m_rng.reset(new HMAC_DRBG(MessageAuthenticationCode::create_or_throw(BOTAN_AUTO_RNG_HMAC), + entropy_sources, + reseed_interval)); + force_reseed(); + } + +AutoSeeded_RNG::AutoSeeded_RNG(RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval) + { + m_rng.reset(new HMAC_DRBG( + MessageAuthenticationCode::create_or_throw(BOTAN_AUTO_RNG_HMAC), + underlying_rng, entropy_sources, reseed_interval)); + force_reseed(); + } + +AutoSeeded_RNG::AutoSeeded_RNG(size_t reseed_interval) : +#if defined(BOTAN_HAS_SYSTEM_RNG) + AutoSeeded_RNG(system_rng(), reseed_interval) +#else + AutoSeeded_RNG(Entropy_Sources::global_sources(), reseed_interval) +#endif + { + } + +void AutoSeeded_RNG::force_reseed() + { + m_rng->force_reseed(); + m_rng->next_byte(); + + if(!m_rng->is_seeded()) + { + throw Exception("AutoSeeded_RNG reseeding failed"); + } + } + +bool AutoSeeded_RNG::is_seeded() const + { + return m_rng->is_seeded(); + } + +void AutoSeeded_RNG::clear() + { + m_rng->clear(); + } + +std::string AutoSeeded_RNG::name() const + { + return m_rng->name(); + } + +void AutoSeeded_RNG::add_entropy(const uint8_t in[], size_t len) + { + m_rng->add_entropy(in, len); + } + +size_t AutoSeeded_RNG::reseed(Entropy_Sources& srcs, + size_t poll_bits, + std::chrono::milliseconds poll_timeout) + { + return m_rng->reseed(srcs, poll_bits, poll_timeout); + } + +void AutoSeeded_RNG::randomize(uint8_t output[], size_t output_len) + { + randomize_with_ts_input(output, output_len); + } + +void AutoSeeded_RNG::randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t ad[], size_t ad_len) + { + m_rng->randomize_with_input(output, output_len, ad, ad_len); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.h b/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.h new file mode 100644 index 0000000000..866c56e12f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.h @@ -0,0 +1,96 @@ +/* +* Auto Seeded RNG +* (C) 2008,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_AUTO_SEEDING_RNG_H_ +#define BOTAN_AUTO_SEEDING_RNG_H_ + +#include <botan/rng.h> + +namespace Botan { + +class Stateful_RNG; + +/** +* A userspace PRNG +*/ +class BOTAN_PUBLIC_API(2,0) AutoSeeded_RNG final : public RandomNumberGenerator + { + public: + void randomize(uint8_t out[], size_t len) override; + + void randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) override; + + bool is_seeded() const override; + + /** + * Mark state as requiring a reseed on next use + */ + void force_reseed(); + + size_t reseed(Entropy_Sources& srcs, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS, + std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override; + + void add_entropy(const uint8_t in[], size_t len) override; + + std::string name() const override; + + void clear() override; + + /** + * Uses the system RNG (if available) or else a default group of + * entropy sources (all other systems) to gather seed material. + * + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + AutoSeeded_RNG(size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + /** + * Uses the BOTAN_AUTO_RNG_DRBG RNG to gather seed material. + * + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + AutoSeeded_RNG(RandomNumberGenerator& underlying_rng, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + /** + * Uses the BOTAN_AUTO_RNG_DRBG RNG to gather seed material. + * + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + AutoSeeded_RNG(Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + /** + * Uses the BOTAN_AUTO_RNG_DRBG RNG to gather seed material. + * + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + AutoSeeded_RNG(RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + ~AutoSeeded_RNG(); + + private: + std::unique_ptr<Stateful_RNG> m_rng; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/rng/auto_rng/info.txt b/src/libs/3rdparty/botan/src/lib/rng/auto_rng/info.txt new file mode 100644 index 0000000000..f1adcc8001 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/auto_rng/info.txt @@ -0,0 +1,8 @@ +<defines> +AUTO_SEEDING_RNG -> 20160821 +AUTO_RNG -> 20161126 +</defines> + +<requires> +hmac_drbg +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp new file mode 100644 index 0000000000..a01b761d99 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp @@ -0,0 +1,184 @@ +/* +* HMAC_DRBG +* (C) 2014,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/hmac_drbg.h> +#include <algorithm> + +namespace Botan { + +HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + RandomNumberGenerator& underlying_rng, + size_t reseed_interval, + size_t max_number_of_bytes_per_request) : + Stateful_RNG(underlying_rng, reseed_interval), + m_mac(std::move(prf)), + m_max_number_of_bytes_per_request(max_number_of_bytes_per_request) + { + BOTAN_ASSERT_NONNULL(m_mac); + + if(m_max_number_of_bytes_per_request == 0 || m_max_number_of_bytes_per_request > 64 * 1024) + { + throw Invalid_Argument("Invalid value for max_number_of_bytes_per_request"); + } + + clear(); + } + +HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval, + size_t max_number_of_bytes_per_request ) : + Stateful_RNG(underlying_rng, entropy_sources, reseed_interval), + m_mac(std::move(prf)), + m_max_number_of_bytes_per_request(max_number_of_bytes_per_request) + { + BOTAN_ASSERT_NONNULL(m_mac); + + if(m_max_number_of_bytes_per_request == 0 || m_max_number_of_bytes_per_request > 64 * 1024) + { + throw Invalid_Argument("Invalid value for max_number_of_bytes_per_request"); + } + + clear(); + } + +HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + Entropy_Sources& entropy_sources, + size_t reseed_interval, + size_t max_number_of_bytes_per_request) : + Stateful_RNG(entropy_sources, reseed_interval), + m_mac(std::move(prf)), + m_max_number_of_bytes_per_request(max_number_of_bytes_per_request) + { + BOTAN_ASSERT_NONNULL(m_mac); + + if(m_max_number_of_bytes_per_request == 0 || m_max_number_of_bytes_per_request > 64 * 1024) + { + throw Invalid_Argument("Invalid value for max_number_of_bytes_per_request"); + } + + clear(); + } + +HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf) : + Stateful_RNG(), + m_mac(std::move(prf)), + m_max_number_of_bytes_per_request(64*1024) + { + BOTAN_ASSERT_NONNULL(m_mac); + clear(); + } + +void HMAC_DRBG::clear() + { + Stateful_RNG::clear(); + + m_V.resize(m_mac->output_length()); + for(size_t i = 0; i != m_V.size(); ++i) + m_V[i] = 0x01; + m_mac->set_key(std::vector<uint8_t>(m_mac->output_length(), 0x00)); + } + +std::string HMAC_DRBG::name() const + { + return "HMAC_DRBG(" + m_mac->name() + ")"; + } + +void HMAC_DRBG::randomize(uint8_t output[], size_t output_len) + { + randomize_with_input(output, output_len, nullptr, 0); + } + +/* +* HMAC_DRBG generation +* See NIST SP800-90A section 10.1.2.5 +*/ +void HMAC_DRBG::randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) + { + while(output_len > 0) + { + size_t this_req = std::min(m_max_number_of_bytes_per_request, output_len); + output_len -= this_req; + + reseed_check(); + + if(input_len > 0) + { + update(input, input_len); + } + + while(this_req) + { + const size_t to_copy = std::min(this_req, m_V.size()); + m_mac->update(m_V.data(), m_V.size()); + m_mac->final(m_V.data()); + copy_mem(output, m_V.data(), to_copy); + + output += to_copy; + this_req -= to_copy; + } + + update(input, input_len); + } + + } + +/* +* Reset V and the mac key with new values +* See NIST SP800-90A section 10.1.2.2 +*/ +void HMAC_DRBG::update(const uint8_t input[], size_t input_len) + { + m_mac->update(m_V); + m_mac->update(0x00); + m_mac->update(input, input_len); + m_mac->set_key(m_mac->final()); + + m_mac->update(m_V.data(), m_V.size()); + m_mac->final(m_V.data()); + + if(input_len > 0) + { + m_mac->update(m_V); + m_mac->update(0x01); + m_mac->update(input, input_len); + m_mac->set_key(m_mac->final()); + + m_mac->update(m_V.data(), m_V.size()); + m_mac->final(m_V.data()); + } + } + +void HMAC_DRBG::add_entropy(const uint8_t input[], size_t input_len) + { + update(input, input_len); + + if(8*input_len >= security_level()) + { + reset_reseed_counter(); + } + } + +size_t HMAC_DRBG::security_level() const + { + // security strength of the hash function + // for pre-image resistance (see NIST SP 800-57) + // SHA-160: 128 bits, SHA-224, SHA-512/224: 192 bits, + // SHA-256, SHA-512/256, SHA-384, SHA-512: >= 256 bits + // NIST SP 800-90A only supports up to 256 bits though + if(m_mac->output_length() < 32) + { + return (m_mac->output_length() - 4) * 8; + } + else + { + return 32 * 8; + } + } +} diff --git a/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.h b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.h new file mode 100644 index 0000000000..edf38b6842 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.h @@ -0,0 +1,159 @@ +/* +* HMAC_DRBG (SP800-90A) +* (C) 2014,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_HMAC_DRBG_H_ +#define BOTAN_HMAC_DRBG_H_ + +#include <botan/stateful_rng.h> +#include <botan/mac.h> + +namespace Botan { + +class Entropy_Sources; + +/** +* HMAC_DRBG from NIST SP800-90A +*/ +class BOTAN_PUBLIC_API(2,0) HMAC_DRBG final : public Stateful_RNG + { + public: + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * Automatic reseeding is disabled completely, as it has no access to + * any source for seed material. + * + * If a fork is detected, the RNG will be unable to reseed itself + * in response. In this case, an exception will be thrown rather + * than generating duplicated output. + */ + explicit HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf); + + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * Automatic reseeding from @p underlying_rng will take place after + * @p reseed_interval many requests or after a fork was detected. + * + * @param prf MAC to use as a PRF + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + * @param max_number_of_bytes_per_request requests that are in size higher + * than max_number_of_bytes_per_request are treated as if multiple single + * requests of max_number_of_bytes_per_request size had been made. + * In theory SP 800-90A requires that we reject any request for a DRBG + * output longer than max_number_of_bytes_per_request. To avoid inconveniencing + * the caller who wants an output larger than max_number_of_bytes_per_request, + * instead treat these requests as if multiple requests of + * max_number_of_bytes_per_request size had been made. NIST requires for + * HMAC_DRBG that every implementation set a value no more than 2**19 bits + * (or 64 KiB). Together with @p reseed_interval = 1 you can enforce that for + * example every 512 bit automatic reseeding occurs. + */ + HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + RandomNumberGenerator& underlying_rng, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, + size_t max_number_of_bytes_per_request = 64 * 1024); + + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * Automatic reseeding from @p entropy_sources will take place after + * @p reseed_interval many requests or after a fork was detected. + * + * @param prf MAC to use as a PRF + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed. + * @param max_number_of_bytes_per_request requests that are in size higher + * than max_number_of_bytes_per_request are treated as if multiple single + * requests of max_number_of_bytes_per_request size had been made. + * In theory SP 800-90A requires that we reject any request for a DRBG + * output longer than max_number_of_bytes_per_request. To avoid inconveniencing + * the caller who wants an output larger than max_number_of_bytes_per_request, + * instead treat these requests as if multiple requests of + * max_number_of_bytes_per_request size had been made. NIST requires for + * HMAC_DRBG that every implementation set a value no more than 2**19 bits + * (or 64 KiB). Together with @p reseed_interval = 1 you can enforce that for + * example every 512 bit automatic reseeding occurs. + */ + HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, + size_t max_number_of_bytes_per_request = 64 * 1024); + + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * Automatic reseeding from @p underlying_rng and @p entropy_sources + * will take place after @p reseed_interval many requests or after + * a fork was detected. + * + * @param prf MAC to use as a PRF + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed. + * @param max_number_of_bytes_per_request requests that are in size higher + * than max_number_of_bytes_per_request are treated as if multiple single + * requests of max_number_of_bytes_per_request size had been made. + * In theory SP 800-90A requires that we reject any request for a DRBG + * output longer than max_number_of_bytes_per_request. To avoid inconveniencing + * the caller who wants an output larger than max_number_of_bytes_per_request, + * instead treat these requests as if multiple requests of + * max_number_of_bytes_per_request size had been made. NIST requires for + * HMAC_DRBG that every implementation set a value no more than 2**19 bits + * (or 64 KiB). Together with @p reseed_interval = 1 you can enforce that for + * example every 512 bit automatic reseeding occurs. + */ + HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, + size_t max_number_of_bytes_per_request = 64 * 1024); + + /** + * Constructor taking a string for the hash + */ + explicit HMAC_DRBG(const std::string& hmac_hash) : + Stateful_RNG(), + m_mac(MessageAuthenticationCode::create_or_throw("HMAC(" + hmac_hash + ")")), + m_max_number_of_bytes_per_request(64 * 1024) + { + clear(); + } + + std::string name() const override; + + void clear() override; + + void randomize(uint8_t output[], size_t output_len) override; + + void randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) override; + + void add_entropy(const uint8_t input[], size_t input_len) override; + + size_t security_level() const override; + + size_t max_number_of_bytes_per_request() const override + { return m_max_number_of_bytes_per_request; } + + private: + void update(const uint8_t input[], size_t input_len); + + std::unique_ptr<MessageAuthenticationCode> m_mac; + secure_vector<uint8_t> m_V; + const size_t m_max_number_of_bytes_per_request; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/info.txt b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/info.txt new file mode 100644 index 0000000000..a8922bdf0e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/info.txt @@ -0,0 +1,8 @@ +<defines> +HMAC_DRBG -> 20140319 +</defines> + +<requires> +hmac +stateful_rng +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/rng/info.txt b/src/libs/3rdparty/botan/src/lib/rng/info.txt new file mode 100644 index 0000000000..4c88ba3826 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/info.txt @@ -0,0 +1,3 @@ +<requires> +entropy +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/info.txt b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/info.txt new file mode 100644 index 0000000000..0d0fc42a42 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/info.txt @@ -0,0 +1,13 @@ +<defines> +RDRAND_RNG -> 20160619 +</defines> + +need_isa rdrand + +<cc> +gcc +clang +icc +msvc +</cc> + diff --git a/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp new file mode 100644 index 0000000000..c365a5f760 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp @@ -0,0 +1,83 @@ +/* +* RDRAND RNG +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/rdrand_rng.h> +#include <botan/loadstor.h> +#include <botan/cpuid.h> + +#if !defined(BOTAN_USE_GCC_INLINE_ASM) + #include <immintrin.h> +#endif + +namespace Botan { + +RDRAND_RNG::RDRAND_RNG() + { + if(!CPUID::has_rdrand()) + throw Exception("Current CPU does not support RDRAND instruction"); + } + +//static +uint32_t RDRAND_RNG::rdrand() + { + for(;;) + { + bool ok = false; + uint32_t r = rdrand_status(ok); + if(ok) + return r; + } + } + +//static +BOTAN_FUNC_ISA("rdrnd") +uint32_t RDRAND_RNG::rdrand_status(bool& ok) + { + ok = false; + uint32_t r = 0; + + for(size_t i = 0; i != BOTAN_ENTROPY_RDRAND_RETRIES; ++i) + { +#if defined(BOTAN_USE_GCC_INLINE_ASM) + int cf = 0; + + // Encoding of rdrand %eax + asm(".byte 0x0F, 0xC7, 0xF0; adcl $0,%1" : + "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc"); +#else + int cf = _rdrand32_step(&r); +#endif + if(1 == cf) + { + ok = true; + break; + } + } + + return r; + } + +void RDRAND_RNG::randomize(uint8_t out[], size_t out_len) + { + while(out_len >= 4) + { + uint32_t r = RDRAND_RNG::rdrand(); + + store_le(r, out); + out += 4; + out_len -= 4; + } + + if(out_len) // between 1 and 3 trailing bytes + { + uint32_t r = RDRAND_RNG::rdrand(); + for(size_t i = 0; i != out_len; ++i) + out[i] = get_byte(i, r); + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.h b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.h new file mode 100644 index 0000000000..377de419f7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.h @@ -0,0 +1,61 @@ +/* +* RDRAND RNG +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RNG_RDRAND_H_ +#define BOTAN_RNG_RDRAND_H_ + +#include <botan/rng.h> + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) RDRAND_RNG final : public Hardware_RNG + { + public: + /** + * On correctly working hardware, RDRAND is always supposed to + * succeed within a set number of retries. If after that many + * retries RDRAND has still not suceeded, sets ok = false and + * returns 0. + */ + static uint32_t rdrand_status(bool& ok); + + /* + * Calls RDRAND until it succeeds, this could hypothetically + * loop forever on broken hardware. + */ + static uint32_t rdrand(); + + /** + * Constructor will throw if CPU does not have RDRAND bit set + */ + RDRAND_RNG(); + + /** + * Uses RDRAND to produce output + */ + void randomize(uint8_t out[], size_t out_len) override; + + /* + * No way to provide entropy to RDRAND generator, so add_entropy is ignored + */ + void add_entropy(const uint8_t[], size_t) override + { /* no op */ } + + /* + * No way to reseed RDRAND generator, so reseed is ignored + */ + size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override + { return 0; /* no op */ } + + std::string name() const override { return "RDRAND"; } + + bool is_seeded() const override { return true; } + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/rng/rng.cpp b/src/libs/3rdparty/botan/src/lib/rng/rng.cpp new file mode 100644 index 0000000000..2cf3b7b81e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/rng.cpp @@ -0,0 +1,74 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/rng.h> +#include <botan/entropy_src.h> +#include <botan/loadstor.h> +#include <botan/internal/os_utils.h> + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + #include <botan/auto_rng.h> +#endif + +namespace Botan { + +void RandomNumberGenerator::randomize_with_ts_input(uint8_t output[], size_t output_len) + { + /* + Form additional input which is provided to the PRNG implementation + to paramaterize the KDF output. + */ + uint8_t additional_input[16] = { 0 }; + store_le(OS::get_system_timestamp_ns(), additional_input); + store_le(OS::get_high_resolution_clock(), additional_input + 8); + + randomize_with_input(output, output_len, additional_input, sizeof(additional_input)); + } + +void RandomNumberGenerator::randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) + { + this->add_entropy(input, input_len); + this->randomize(output, output_len); + } + +size_t RandomNumberGenerator::reseed(Entropy_Sources& srcs, + size_t poll_bits, + std::chrono::milliseconds poll_timeout) + { + return srcs.poll(*this, poll_bits, poll_timeout); + } + +void RandomNumberGenerator::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits) + { + secure_vector<uint8_t> buf(poll_bits / 8); + rng.randomize(buf.data(), buf.size()); + this->add_entropy(buf.data(), buf.size()); + } + +RandomNumberGenerator* RandomNumberGenerator::make_rng() + { +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + return new AutoSeeded_RNG; +#else + throw Exception("make_rng failed, no AutoSeeded_RNG in this build"); +#endif + } + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) +Serialized_RNG::Serialized_RNG() : m_rng(new AutoSeeded_RNG) {} +#else +Serialized_RNG::Serialized_RNG() + { + throw Exception("Serialized_RNG default constructor failed: AutoSeeded_RNG disabled in build"); + } +#endif + +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/rng/rng.h b/src/libs/3rdparty/botan/src/lib/rng/rng.h new file mode 100644 index 0000000000..f6fa80df06 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/rng.h @@ -0,0 +1,264 @@ +/* +* Random Number Generator base classes +* (C) 1999-2009,2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H_ +#define BOTAN_RANDOM_NUMBER_GENERATOR_H_ + +#include <botan/secmem.h> +#include <botan/exceptn.h> +#include <botan/mutex.h> +#include <chrono> +#include <string> + +namespace Botan { + +class Entropy_Sources; + +/** +* An interface to a cryptographic random number generator +*/ +class BOTAN_PUBLIC_API(2,0) RandomNumberGenerator + { + public: + virtual ~RandomNumberGenerator() = default; + + RandomNumberGenerator() = default; + + /* + * Never copy a RNG, create a new one + */ + RandomNumberGenerator(const RandomNumberGenerator& rng) = delete; + RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete; + + /** + * Randomize a byte array. + * @param output the byte array to hold the random output. + * @param length the length of the byte array output in bytes. + */ + virtual void randomize(uint8_t output[], size_t length) = 0; + + /** + * Incorporate some additional data into the RNG state. For + * example adding nonces or timestamps from a peer's protocol + * message can help hedge against VM state rollback attacks. + * A few RNG types do not accept any externally provided input, + * in which case this function is a no-op. + * + * @param input a byte array containg the entropy to be added + * @param length the length of the byte array in + */ + virtual void add_entropy(const uint8_t input[], size_t length) = 0; + + /** + * Incorporate some additional data into the RNG state. + */ + template<typename T> void add_entropy_T(const T& t) + { + this->add_entropy(reinterpret_cast<const uint8_t*>(&t), sizeof(T)); + } + + /** + * Incorporate entropy into the RNG state then produce output. + * Some RNG types implement this using a single operation, default + * calls add_entropy + randomize in sequence. + * + * Use this to further bind the outputs to your current + * process/protocol state. For instance if generating a new key + * for use in a session, include a session ID or other such + * value. See NIST SP 800-90 A, B, C series for more ideas. + * + * @param output buffer to hold the random output + * @param output_len size of the output buffer in bytes + * @param input entropy buffer to incorporate + * @param input_len size of the input buffer in bytes + */ + virtual void randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len); + + /** + * This calls `randomize_with_input` using some timestamps as extra input. + * + * For a stateful RNG using non-random but potentially unique data the + * extra input can help protect against problems with fork, VM state + * rollback, or other cases where somehow an RNG state is duplicated. If + * both of the duplicated RNG states later incorporate a timestamp (and the + * timestamps don't themselves repeat), their outputs will diverge. + */ + virtual void randomize_with_ts_input(uint8_t output[], size_t output_len); + + /** + * @return the name of this RNG type + */ + virtual std::string name() const = 0; + + /** + * Clear all internally held values of this RNG + * @post is_seeded() == false + */ + virtual void clear() = 0; + + /** + * Check whether this RNG is seeded. + * @return true if this RNG was already seeded, false otherwise. + */ + virtual bool is_seeded() const = 0; + + /** + * Poll provided sources for up to poll_bits bits of entropy + * or until the timeout expires. Returns estimate of the number + * of bits collected. + */ + virtual size_t reseed(Entropy_Sources& srcs, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS, + std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT); + + /** + * Reseed by reading specified bits from the RNG + */ + virtual void reseed_from_rng(RandomNumberGenerator& rng, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS); + + // Some utility functions built on the interface above: + + /** + * Return a random vector + * @param bytes number of bytes in the result + * @return randomized vector of length bytes + */ + secure_vector<uint8_t> random_vec(size_t bytes) + { + secure_vector<uint8_t> output(bytes); + this->randomize(output.data(), output.size()); + return output; + } + + /** + * Return a random byte + * @return random byte + */ + uint8_t next_byte() + { + uint8_t b; + this->randomize(&b, 1); + return b; + } + + /** + * @return a random byte that is greater than zero + */ + uint8_t next_nonzero_byte() + { + uint8_t b = this->next_byte(); + while(b == 0) + b = this->next_byte(); + return b; + } + + /** + * Create a seeded and active RNG object for general application use + * Added in 1.8.0 + * Use AutoSeeded_RNG instead + */ + BOTAN_DEPRECATED("Use AutoSeeded_RNG") + static RandomNumberGenerator* make_rng(); + }; + +/** +* Convenience typedef +*/ +typedef RandomNumberGenerator RNG; + +/** +* Hardware_RNG has no members but exists to tag hardware RNG types +* (PKCS11_RNG, TPM_RNG, RDRAND_RNG) +*/ +class BOTAN_PUBLIC_API(2,0) Hardware_RNG : public RandomNumberGenerator + { + public: + virtual void clear() final override { /* no way to clear state of hardware RNG */ } + }; + +/** +* Null/stub RNG - fails if you try to use it for anything +* This is not generally useful except for in certain tests +*/ +class BOTAN_PUBLIC_API(2,0) Null_RNG final : public RandomNumberGenerator + { + public: + bool is_seeded() const override { return false; } + + void clear() override {} + + void randomize(uint8_t[], size_t) override + { + throw PRNG_Unseeded("Null_RNG called"); + } + + void add_entropy(const uint8_t[], size_t) override {} + + std::string name() const override { return "Null_RNG"; } + }; + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) +/** +* Wraps access to a RNG in a mutex +* Note that most of the time it's much better to use a RNG per thread +* otherwise the RNG will act as an unnecessary contention point +*/ +class BOTAN_PUBLIC_API(2,0) Serialized_RNG final : public RandomNumberGenerator + { + public: + void randomize(uint8_t out[], size_t len) override + { + lock_guard_type<mutex_type> lock(m_mutex); + m_rng->randomize(out, len); + } + + bool is_seeded() const override + { + lock_guard_type<mutex_type> lock(m_mutex); + return m_rng->is_seeded(); + } + + void clear() override + { + lock_guard_type<mutex_type> lock(m_mutex); + m_rng->clear(); + } + + std::string name() const override + { + lock_guard_type<mutex_type> lock(m_mutex); + return m_rng->name(); + } + + size_t reseed(Entropy_Sources& src, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS, + std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override + { + lock_guard_type<mutex_type> lock(m_mutex); + return m_rng->reseed(src, poll_bits, poll_timeout); + } + + void add_entropy(const uint8_t in[], size_t len) override + { + lock_guard_type<mutex_type> lock(m_mutex); + m_rng->add_entropy(in, len); + } + + BOTAN_DEPRECATED("Use Serialized_RNG(new AutoSeeded_RNG)") Serialized_RNG(); + + explicit Serialized_RNG(RandomNumberGenerator* rng) : m_rng(rng) {} + private: + mutable mutex_type m_mutex; + std::unique_ptr<RandomNumberGenerator> m_rng; + }; +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/info.txt b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/info.txt new file mode 100644 index 0000000000..edc2d91694 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/info.txt @@ -0,0 +1,3 @@ +<defines> +STATEFUL_RNG -> 20160819 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.cpp b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.cpp new file mode 100644 index 0000000000..dec7917938 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.cpp @@ -0,0 +1,112 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/stateful_rng.h> +#include <botan/internal/os_utils.h> +#include <botan/loadstor.h> + +namespace Botan { + +void Stateful_RNG::clear() + { + m_reseed_counter = 0; + m_last_pid = 0; + } + +void Stateful_RNG::force_reseed() + { + m_reseed_counter = 0; + } + +bool Stateful_RNG::is_seeded() const + { + return m_reseed_counter > 0; + } + +void Stateful_RNG::initialize_with(const uint8_t input[], size_t len) + { + add_entropy(input, len); + + if(8*len >= security_level()) + { + reset_reseed_counter(); + } + } + +void Stateful_RNG::randomize_with_ts_input(uint8_t output[], size_t output_len) + { + uint8_t additional_input[24] = { 0 }; + store_le(OS::get_system_timestamp_ns(), additional_input); + store_le(OS::get_high_resolution_clock(), additional_input + 8); + store_le(m_last_pid, additional_input + 16); + store_le(static_cast<uint32_t>(m_reseed_counter), additional_input + 20); + + randomize_with_input(output, output_len, additional_input, sizeof(additional_input)); + } + +size_t Stateful_RNG::reseed(Entropy_Sources& srcs, + size_t poll_bits, + std::chrono::milliseconds poll_timeout) + { + size_t bits_collected = RandomNumberGenerator::reseed(srcs, poll_bits, poll_timeout); + + if(bits_collected >= security_level()) + { + reset_reseed_counter(); + } + + return bits_collected; + } + +void Stateful_RNG::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits) + { + RandomNumberGenerator::reseed_from_rng(rng, poll_bits); + + if(poll_bits >= security_level()) + { + reset_reseed_counter(); + } + } + +void Stateful_RNG::reseed_check() + { + const uint32_t cur_pid = OS::get_process_id(); + + const bool fork_detected = (m_last_pid > 0) && (cur_pid != m_last_pid); + + if(is_seeded() == false || + fork_detected || + (m_reseed_interval > 0 && m_reseed_counter >= m_reseed_interval)) + { + m_reseed_counter = 0; + m_last_pid = cur_pid; + + if(m_underlying_rng) + { + reseed_from_rng(*m_underlying_rng, security_level()); + } + + if(m_entropy_sources) + { + reseed(*m_entropy_sources, security_level()); + } + + if(!is_seeded()) + { + if(fork_detected) + throw Exception("Detected use of fork but cannot reseed DRBG"); + else + throw PRNG_Unseeded(name()); + } + } + else + { + BOTAN_ASSERT(m_reseed_counter != 0, "RNG is seeded"); + m_reseed_counter += 1; + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.h b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.h new file mode 100644 index 0000000000..18697ae231 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.h @@ -0,0 +1,151 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STATEFUL_RNG_H_ +#define BOTAN_STATEFUL_RNG_H_ + +#include <botan/rng.h> + +namespace Botan { + +/** +* Inherited by RNGs which maintain in-process state, like HMAC_DRBG. +* On Unix these RNGs are vulnerable to problems with fork, where the +* RNG state is duplicated, and the parent and child process RNGs will +* produce identical output until one of them reseeds. Stateful_RNG +* reseeds itself whenever a fork is detected, or after a set number of +* bytes have been output. +* +* Not implemented by RNGs which access an external RNG, such as the +* system PRNG or a hardware RNG. +*/ +class BOTAN_PUBLIC_API(2,0) Stateful_RNG : public RandomNumberGenerator + { + public: + /** + * @param rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + Stateful_RNG(RandomNumberGenerator& rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval) : + m_underlying_rng(&rng), + m_entropy_sources(&entropy_sources), + m_reseed_interval(reseed_interval) + {} + + /** + * @param rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + Stateful_RNG(RandomNumberGenerator& rng, size_t reseed_interval) : + m_underlying_rng(&rng), + m_reseed_interval(reseed_interval) + {} + + /** + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed + */ + Stateful_RNG(Entropy_Sources& entropy_sources, size_t reseed_interval) : + m_entropy_sources(&entropy_sources), + m_reseed_interval(reseed_interval) + {} + + /** + * In this case, automatic reseeding is impossible + */ + Stateful_RNG() : m_reseed_interval(0) {} + + /** + * Consume this input and mark the RNG as initialized regardless + * of the length of the input or the current seeded state of + * the RNG. + */ + void initialize_with(const uint8_t input[], size_t length); + + bool is_seeded() const override final; + + /** + * Mark state as requiring a reseed on next use + */ + void force_reseed(); + + void reseed_from_rng(RandomNumberGenerator& rng, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS) override final; + + /** + * Overrides default implementation and also includes the current + * process ID and the reseed counter. + */ + void randomize_with_ts_input(uint8_t output[], size_t output_len) override final; + + /** + * Poll provided sources for up to poll_bits bits of entropy + * or until the timeout expires. Returns estimate of the number + * of bits collected. + */ + size_t reseed(Entropy_Sources& srcs, + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS, + std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override; + + /** + * @return intended security level of this DRBG + */ + virtual size_t security_level() const = 0; + + /** + * Some DRBGs have a notion of the maximum number of bytes per + * request. Longer requests (to randomize) will be treated as + * multiple requests, and may initiate reseeding multiple times, + * depending on the values of max_number_of_bytes_per_request and + * reseed_interval(). This function returns zero if the RNG in + * question does not have such a notion. + * + * @return max number of bytes per request (or zero) + */ + virtual size_t max_number_of_bytes_per_request() const = 0; + + size_t reseed_interval() const { return m_reseed_interval; } + + void clear() override; + + protected: + void reseed_check(); + + /** + * Called by a subclass to notify that a reseed has been + * successfully performed. + */ + void reset_reseed_counter() { m_reseed_counter = 1; } + + private: + // A non-owned and possibly null pointer to shared RNG + RandomNumberGenerator* m_underlying_rng = nullptr; + + // A non-owned and possibly null pointer to a shared Entropy_Source + Entropy_Sources* m_entropy_sources = nullptr; + + const size_t m_reseed_interval; + uint32_t m_last_pid = 0; + + /* + * Set to 1 after a successful seeding, then incremented. Reset + * to 0 by clear() or a fork. This logic is used even if + * automatic reseeding is disabled (via m_reseed_interval = 0) + */ + size_t m_reseed_counter = 0; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/rng/system_rng/info.txt b/src/libs/3rdparty/botan/src/lib/rng/system_rng/info.txt new file mode 100644 index 0000000000..da4fce4e36 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/system_rng/info.txt @@ -0,0 +1,18 @@ +<defines> +SYSTEM_RNG -> 20141202 +</defines> + +<os_features> +dev_random,posix1 +arc4random +rtlgenrandom +crypto_ng +</os_features> + +<libs> +uwp -> bcrypt.lib +</libs> + +<requires> +rtlgenrandom?dyn_load +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.cpp b/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.cpp new file mode 100644 index 0000000000..c3b37ea9cc --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.cpp @@ -0,0 +1,231 @@ +/* +* System RNG +* (C) 2014,2015,2017,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/system_rng.h> + +#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM) + #include <botan/dyn_load.h> + #define NOMINMAX 1 + #define _WINSOCKAPI_ // stop windows.h including winsock.h + #include <windows.h> + +#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG) + #include <bcrypt.h> + +#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM) + #include <stdlib.h> + +#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM) + #include <sys/types.h> + #include <sys/stat.h> + #include <fcntl.h> + #include <unistd.h> + #include <errno.h> +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM) + +class System_RNG_Impl final : public RandomNumberGenerator + { + public: + System_RNG_Impl() : m_advapi("advapi32.dll") + { + // This throws if the function is not found + m_rtlgenrandom = m_advapi.resolve<RtlGenRandom_fptr>("SystemFunction036"); + } + + void randomize(uint8_t buf[], size_t len) override + { + bool success = m_rtlgenrandom(buf, len) == TRUE; + if(!success) + throw Exception("RtlGenRandom failed"); + } + + void add_entropy(const uint8_t[], size_t) override { /* ignored */ } + bool is_seeded() const override { return true; } + void clear() override { /* not possible */ } + std::string name() const override { return "RtlGenRandom"; } + private: + // Use type BYTE instead of BOOLEAN because of a naming conflict + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx + using RtlGenRandom_fptr = BYTE (NTAPI *)(PVOID, ULONG); + + Dynamically_Loaded_Library m_advapi; + RtlGenRandom_fptr m_rtlgenrandom; + }; + +#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG) + +class System_RNG_Impl final : public RandomNumberGenerator + { + public: + System_RNG_Impl() + { + NTSTATUS ret = ::BCryptOpenAlgorithmProvider(&m_prov, + BCRYPT_RNG_ALGORITHM, + MS_PRIMITIVE_PROVIDER, 0); + if(ret != STATUS_SUCCESS) + throw Exception("System_RNG failed to acquire crypto provider"); + } + + ~System_RNG_Impl() + { + ::BCryptCloseAlgorithmProvider(m_prov, 0); + } + + void randomize(uint8_t buf[], size_t len) override + { + NTSTATUS ret = ::BCryptGenRandom(m_prov, static_cast<PUCHAR>(buf), static_cast<ULONG>(len), 0); + if(ret != STATUS_SUCCESS) + throw Exception("System_RNG call to BCryptGenRandom failed"); + } + + void add_entropy(const uint8_t in[], size_t length) override + { + /* + There is a flag BCRYPT_RNG_USE_ENTROPY_IN_BUFFER to provide + entropy inputs, but it is ignored in Windows 8 and later. + */ + } + + bool is_seeded() const override { return true; } + void clear() override { /* not possible */ } + std::string name() const override { return "crypto_ng"; } + private: + BCRYPT_ALG_HANDLE m_handle; + }; + +#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM) + +class System_RNG_Impl final : public RandomNumberGenerator + { + public: + // No constructor or destructor needed as no userland state maintained + + void randomize(uint8_t buf[], size_t len) override + { + ::arc4random_buf(buf, len); + } + + void add_entropy(const uint8_t[], size_t) override { /* ignored */ } + bool is_seeded() const override { return true; } + void clear() override { /* not possible */ } + std::string name() const override { return "arc4random"; } + }; + +#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM) + +// Read a random device + +class System_RNG_Impl final : public RandomNumberGenerator + { + public: + System_RNG_Impl() + { + #ifndef O_NOCTTY + #define O_NOCTTY 0 + #endif + + m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDWR | O_NOCTTY); + + /* + Cannot open in read-write mode. Fall back to read-only, + calls to add_entropy will fail, but randomize will work + */ + if(m_fd < 0) + m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDONLY | O_NOCTTY); + + if(m_fd < 0) + throw Exception("System_RNG failed to open RNG device"); + } + + ~System_RNG_Impl() + { + ::close(m_fd); + m_fd = -1; + } + + void randomize(uint8_t buf[], size_t len) override; + void add_entropy(const uint8_t in[], size_t length) override; + bool is_seeded() const override { return true; } + void clear() override { /* not possible */ } + std::string name() const override { return BOTAN_SYSTEM_RNG_DEVICE; } + private: + int m_fd; + }; + +void System_RNG_Impl::randomize(uint8_t buf[], size_t len) + { + while(len) + { + ssize_t got = ::read(m_fd, buf, len); + + if(got < 0) + { + if(errno == EINTR) + continue; + throw Exception("System_RNG read failed error " + std::to_string(errno)); + } + if(got == 0) + throw Exception("System_RNG EOF on device"); // ?!? + + buf += got; + len -= got; + } + } + +void System_RNG_Impl::add_entropy(const uint8_t input[], size_t len) + { + while(len) + { + ssize_t got = ::write(m_fd, input, len); + + if(got < 0) + { + if(errno == EINTR) + continue; + + /* + * This is seen on OS X CI, despite the fact that the man page + * for Darwin urandom explicitly states that writing to it is + * supported, and write(2) does not document EPERM at all. + * But in any case EPERM seems indicative of a policy decision + * by the OS or sysadmin that additional entropy is not wanted + * in the system pool, so we accept that and return here, + * since there is no corrective action possible. + * + * In Linux EBADF or EPERM is returned if m_fd is not opened for + * writing. + */ + if(errno == EPERM || errno == EBADF) + return; + + // maybe just ignore any failure here and return? + throw Exception("System_RNG write failed error " + std::to_string(errno)); + } + + input += got; + len -= got; + } + } + +#endif + +} + +RandomNumberGenerator& system_rng() + { + static System_RNG_Impl g_system_rng; + return g_system_rng; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.h b/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.h new file mode 100644 index 0000000000..4e3beaf9fb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.h @@ -0,0 +1,41 @@ +/* +* System RNG interface +* (C) 2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SYSTEM_RNG_H_ +#define BOTAN_SYSTEM_RNG_H_ + +#include <botan/rng.h> + +namespace Botan { + +/** +* Return a shared reference to a global PRNG instance provided by the +* operating system. For instance might be instantiated by /dev/urandom +* or CryptGenRandom. +*/ +BOTAN_PUBLIC_API(2,0) RandomNumberGenerator& system_rng(); + +/* +* Instantiable reference to the system RNG. +*/ +class BOTAN_PUBLIC_API(2,0) System_RNG final : public RandomNumberGenerator + { + public: + std::string name() const override { return system_rng().name(); } + + void randomize(uint8_t out[], size_t len) override { system_rng().randomize(out, len); } + + void add_entropy(const uint8_t in[], size_t length) override { system_rng().add_entropy(in, length); } + + bool is_seeded() const override { return system_rng().is_seeded(); } + + void clear() override { system_rng().clear(); } + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/stream/ctr/ctr.cpp b/src/libs/3rdparty/botan/src/lib/stream/ctr/ctr.cpp new file mode 100644 index 0000000000..2616463443 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/stream/ctr/ctr.cpp @@ -0,0 +1,203 @@ +/* +* Counter mode +* (C) 1999-2011,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ctr.h> +#include <botan/exceptn.h> +#include <botan/loadstor.h> + +namespace Botan { + +CTR_BE::CTR_BE(BlockCipher* ciph) : + m_cipher(ciph), + m_block_size(m_cipher->block_size()), + m_ctr_size(m_block_size), + m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size), + m_counter(m_cipher->parallel_bytes()), + m_pad(m_counter.size()), + m_pad_pos(0) + { + } + +CTR_BE::CTR_BE(BlockCipher* cipher, size_t ctr_size) : + m_cipher(cipher), + m_block_size(m_cipher->block_size()), + m_ctr_size(ctr_size), + m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size), + m_counter(m_cipher->parallel_bytes()), + m_pad(m_counter.size()), + m_pad_pos(0) + { + BOTAN_ARG_CHECK(m_ctr_size >= 4 && m_ctr_size <= m_block_size, + "Invalid CTR-BE counter size"); + } + +void CTR_BE::clear() + { + m_cipher->clear(); + zeroise(m_pad); + zeroise(m_counter); + zap(m_iv); + m_pad_pos = 0; + } + +void CTR_BE::key_schedule(const uint8_t key[], size_t key_len) + { + m_cipher->set_key(key, key_len); + + // Set a default all-zeros IV + set_iv(nullptr, 0); + } + +std::string CTR_BE::name() const + { + if(m_ctr_size == m_block_size) + return ("CTR-BE(" + m_cipher->name() + ")"); + else + return ("CTR-BE(" + m_cipher->name() + "," + std::to_string(m_ctr_size) + ")"); + + } + +void CTR_BE::cipher(const uint8_t in[], uint8_t out[], size_t length) + { + verify_key_set(m_iv.empty() == false); + + const uint8_t* pad_bits = &m_pad[0]; + const size_t pad_size = m_pad.size(); + + if(m_pad_pos > 0) + { + const size_t avail = pad_size - m_pad_pos; + const size_t take = std::min(length, avail); + xor_buf(out, in, pad_bits + m_pad_pos, take); + length -= take; + in += take; + out += take; + m_pad_pos += take; + + if(take == avail) + { + add_counter(m_ctr_blocks); + m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); + m_pad_pos = 0; + } + } + + while(length >= pad_size) + { + xor_buf(out, in, pad_bits, pad_size); + length -= pad_size; + in += pad_size; + out += pad_size; + + add_counter(m_ctr_blocks); + m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); + } + + xor_buf(out, in, pad_bits, length); + m_pad_pos += length; + } + +void CTR_BE::set_iv(const uint8_t iv[], size_t iv_len) + { + if(!valid_iv_length(iv_len)) + throw Invalid_IV_Length(name(), iv_len); + + m_iv.resize(m_cipher->block_size()); + zeroise(m_iv); + buffer_insert(m_iv, 0, iv, iv_len); + + seek(0); + } + +void CTR_BE::add_counter(const uint64_t counter) + { + const size_t ctr_size = m_ctr_size; + const size_t ctr_blocks = m_ctr_blocks; + const size_t BS = m_block_size; + + if(ctr_size == 4) + { + size_t off = (BS - 4); + for(size_t i = 0; i != ctr_blocks; ++i) + { + uint32_t low32 = load_be<uint32_t>(&m_counter[off], 0); + low32 += counter; + store_be(low32, &m_counter[off]); + off += BS; + } + } + else if(ctr_size == 8) + { + size_t off = (BS - 8); + for(size_t i = 0; i != ctr_blocks; ++i) + { + uint64_t low64 = load_be<uint64_t>(&m_counter[off], 0); + low64 += counter; + store_be(low64, &m_counter[off]); + off += BS; + } + } + else if(ctr_size == 16) + { + size_t off = (BS - 16); + for(size_t i = 0; i != ctr_blocks; ++i) + { + uint64_t b0 = load_be<uint64_t>(&m_counter[off], 0); + uint64_t b1 = load_be<uint64_t>(&m_counter[off], 1); + b1 += counter; + b0 += (b1 < counter) ? 1 : 0; // carry + store_be(b0, &m_counter[off]); + store_be(b1, &m_counter[off+8]); + off += BS; + } + } + else + { + for(size_t i = 0; i != ctr_blocks; ++i) + { + uint64_t local_counter = counter; + uint16_t carry = static_cast<uint8_t>(local_counter); + for(size_t j = 0; (carry || local_counter) && j != ctr_size; ++j) + { + const size_t off = i*BS + (BS-1-j); + const uint16_t cnt = static_cast<uint16_t>(m_counter[off]) + carry; + m_counter[off] = static_cast<uint8_t>(cnt); + local_counter = (local_counter >> 8); + carry = (cnt >> 8) + static_cast<uint8_t>(local_counter); + } + } + } + } + +void CTR_BE::seek(uint64_t offset) + { + verify_key_set(m_iv.empty() == false); + + const uint64_t base_counter = m_ctr_blocks * (offset / m_counter.size()); + + zeroise(m_counter); + buffer_insert(m_counter, 0, m_iv); + + const size_t BS = m_block_size; + + // Set m_counter blocks to IV, IV + 1, ... IV + n + for(size_t i = 1; i != m_ctr_blocks; ++i) + { + buffer_insert(m_counter, i*BS, &m_counter[(i-1)*BS], BS); + + for(size_t j = 0; j != m_ctr_size; ++j) + if(++m_counter[i*BS + (BS - 1 - j)]) + break; + } + + if(base_counter > 0) + add_counter(base_counter); + + m_cipher->encrypt_n(m_counter.data(), m_pad.data(), m_ctr_blocks); + m_pad_pos = offset % m_counter.size(); + } +} diff --git a/src/libs/3rdparty/botan/src/lib/stream/ctr/ctr.h b/src/libs/3rdparty/botan/src/lib/stream/ctr/ctr.h new file mode 100644 index 0000000000..c4c5981616 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/stream/ctr/ctr.h @@ -0,0 +1,66 @@ +/* +* CTR-BE Mode +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CTR_BE_H_ +#define BOTAN_CTR_BE_H_ + +#include <botan/block_cipher.h> +#include <botan/stream_cipher.h> + +namespace Botan { + +/** +* CTR-BE (Counter mode, big-endian) +*/ +class BOTAN_PUBLIC_API(2,0) CTR_BE final : public StreamCipher + { + public: + void cipher(const uint8_t in[], uint8_t out[], size_t length) override; + + void set_iv(const uint8_t iv[], size_t iv_len) override; + + bool valid_iv_length(size_t iv_len) const override + { return (iv_len <= m_cipher->block_size()); } + + Key_Length_Specification key_spec() const override + { + return m_cipher->key_spec(); + } + + std::string name() const override; + + CTR_BE* clone() const override + { return new CTR_BE(m_cipher->clone(), m_ctr_size); } + + void clear() override; + + /** + * @param cipher the block cipher to use + */ + explicit CTR_BE(BlockCipher* cipher); + + CTR_BE(BlockCipher* cipher, size_t ctr_size); + + void seek(uint64_t offset) override; + private: + void key_schedule(const uint8_t key[], size_t key_len) override; + void add_counter(const uint64_t counter); + + std::unique_ptr<BlockCipher> m_cipher; + + const size_t m_block_size; + const size_t m_ctr_size; + const size_t m_ctr_blocks; + + secure_vector<uint8_t> m_counter, m_pad; + std::vector<uint8_t> m_iv; + size_t m_pad_pos; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/stream/ctr/info.txt b/src/libs/3rdparty/botan/src/lib/stream/ctr/info.txt new file mode 100644 index 0000000000..270ceecf8b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/stream/ctr/info.txt @@ -0,0 +1,7 @@ +<defines> +CTR_BE -> 20131128 +</defines> + +<requires> +block +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/stream/info.txt b/src/libs/3rdparty/botan/src/lib/stream/info.txt new file mode 100644 index 0000000000..4f62c5a7c1 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/stream/info.txt @@ -0,0 +1,7 @@ +<defines> +STREAM_CIPHER -> 20131128 +</defines> + +<header:public> +stream_cipher.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/stream/stream_cipher.cpp b/src/libs/3rdparty/botan/src/lib/stream/stream_cipher.cpp new file mode 100644 index 0000000000..692464723c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/stream/stream_cipher.cpp @@ -0,0 +1,149 @@ +/* +* Stream Ciphers +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/stream_cipher.h> +#include <botan/scan_name.h> +#include <botan/exceptn.h> + +#if defined(BOTAN_HAS_CHACHA) + #include <botan/chacha.h> +#endif + +#if defined(BOTAN_HAS_SALSA20) + #include <botan/salsa20.h> +#endif + +#if defined(BOTAN_HAS_SHAKE_CIPHER) + #include <botan/shake_cipher.h> +#endif + +#if defined(BOTAN_HAS_CTR_BE) + #include <botan/ctr.h> +#endif + +#if defined(BOTAN_HAS_OFB) + #include <botan/ofb.h> +#endif + +#if defined(BOTAN_HAS_RC4) + #include <botan/rc4.h> +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include <botan/internal/openssl.h> +#endif + +namespace Botan { + +std::unique_ptr<StreamCipher> StreamCipher::create(const std::string& algo_spec, + const std::string& provider) + { + const SCAN_Name req(algo_spec); + +#if defined(BOTAN_HAS_CTR_BE) + if((req.algo_name() == "CTR-BE" || req.algo_name() == "CTR") && req.arg_count_between(1,2)) + { + if(provider.empty() || provider == "base") + { + auto cipher = BlockCipher::create(req.arg(0)); + if(cipher) + { + size_t ctr_size = req.arg_as_integer(1, cipher->block_size()); + return std::unique_ptr<StreamCipher>(new CTR_BE(cipher.release(), ctr_size)); + } + } + } +#endif + +#if defined(BOTAN_HAS_CHACHA) + if(req.algo_name() == "ChaCha") + { + if(provider.empty() || provider == "base") + return std::unique_ptr<StreamCipher>(new ChaCha(req.arg_as_integer(0, 20))); + } + + if(req.algo_name() == "ChaCha20") + { + if(provider.empty() || provider == "base") + return std::unique_ptr<StreamCipher>(new ChaCha(20)); + } +#endif + +#if defined(BOTAN_HAS_SALSA20) + if(req.algo_name() == "Salsa20") + { + if(provider.empty() || provider == "base") + return std::unique_ptr<StreamCipher>(new Salsa20); + } +#endif + +#if defined(BOTAN_HAS_SHAKE_CIPHER) + if(req.algo_name() == "SHAKE-128") + { + if(provider.empty() || provider == "base") + return std::unique_ptr<StreamCipher>(new SHAKE_128_Cipher); + } +#endif + +#if defined(BOTAN_HAS_OFB) + if(req.algo_name() == "OFB" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto c = BlockCipher::create(req.arg(0))) + return std::unique_ptr<StreamCipher>(new OFB(c.release())); + } + } +#endif + +#if defined(BOTAN_HAS_RC4) + + if(req.algo_name() == "RC4" || + req.algo_name() == "ARC4" || + req.algo_name() == "MARK-4") + { + const size_t skip = (req.algo_name() == "MARK-4") ? 256 : req.arg_as_integer(0, 0); + +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + return std::unique_ptr<StreamCipher>(make_openssl_rc4(skip)); + } +#endif + + if(provider.empty() || provider == "base") + { + return std::unique_ptr<StreamCipher>(new RC4(skip)); + } + } + +#endif + + BOTAN_UNUSED(req); + BOTAN_UNUSED(provider); + + return nullptr; + } + +//static +std::unique_ptr<StreamCipher> +StreamCipher::create_or_throw(const std::string& algo, + const std::string& provider) + { + if(auto sc = StreamCipher::create(algo, provider)) + { + return sc; + } + throw Lookup_Error("Stream cipher", algo, provider); + } + +std::vector<std::string> StreamCipher::providers(const std::string& algo_spec) + { + return probe_providers_of<StreamCipher>(algo_spec, {"base", "openssl"}); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/stream/stream_cipher.h b/src/libs/3rdparty/botan/src/lib/stream/stream_cipher.h new file mode 100644 index 0000000000..03ffcadd04 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/stream/stream_cipher.h @@ -0,0 +1,129 @@ +/* +* Stream Cipher +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STREAM_CIPHER_H_ +#define BOTAN_STREAM_CIPHER_H_ + +#include <botan/sym_algo.h> +#include <string> +#include <memory> + +namespace Botan { + +/** +* Base class for all stream ciphers +*/ +class BOTAN_PUBLIC_API(2,0) StreamCipher : public SymmetricAlgorithm + { + public: + virtual ~StreamCipher() = default; + + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * @return a null pointer if the algo/provider combination cannot be found + */ + static std::unique_ptr<StreamCipher> + create(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * Create an instance based on a name + * If provider is empty then best available is chosen. + * @param algo_spec algorithm name + * @param provider provider implementation to use + * Throws a Lookup_Error if the algo/provider combination cannot be found + */ + static std::unique_ptr<StreamCipher> + create_or_throw(const std::string& algo_spec, + const std::string& provider = ""); + + /** + * @return list of available providers for this algorithm, empty if not available + */ + static std::vector<std::string> providers(const std::string& algo_spec); + + /** + * Encrypt or decrypt a message + * @param in the plaintext + * @param out the byte array to hold the output, i.e. the ciphertext + * @param len the length of both in and out in bytes + */ + virtual void cipher(const uint8_t in[], uint8_t out[], size_t len) = 0; + + /** + * Encrypt or decrypt a message + * The message is encrypted/decrypted in place. + * @param buf the plaintext / ciphertext + * @param len the length of buf in bytes + */ + void cipher1(uint8_t buf[], size_t len) + { cipher(buf, buf, len); } + + /** + * Encrypt a message + * The message is encrypted/decrypted in place. + * @param inout the plaintext / ciphertext + */ + template<typename Alloc> + void encipher(std::vector<uint8_t, Alloc>& inout) + { cipher(inout.data(), inout.data(), inout.size()); } + + /** + * Encrypt a message + * The message is encrypted in place. + * @param inout the plaintext / ciphertext + */ + template<typename Alloc> + void encrypt(std::vector<uint8_t, Alloc>& inout) + { cipher(inout.data(), inout.data(), inout.size()); } + + /** + * Decrypt a message in place + * The message is decrypted in place. + * @param inout the plaintext / ciphertext + */ + template<typename Alloc> + void decrypt(std::vector<uint8_t, Alloc>& inout) + { cipher(inout.data(), inout.data(), inout.size()); } + + /** + * Resync the cipher using the IV + * @param iv the initialization vector + * @param iv_len the length of the IV in bytes + */ + virtual void set_iv(const uint8_t iv[], size_t iv_len) = 0; + + /** + * @param iv_len the length of the IV in bytes + * @return if the length is valid for this algorithm + */ + virtual bool valid_iv_length(size_t iv_len) const { return (iv_len == 0); } + + /** + * @return a new object representing the same algorithm as *this + */ + virtual StreamCipher* clone() const = 0; + + /** + * Set the offset and the state used later to generate the keystream + * @param offset the offset where we begin to generate the keystream + */ + virtual void seek(uint64_t offset) = 0; + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/assert.cpp b/src/libs/3rdparty/botan/src/lib/utils/assert.cpp new file mode 100644 index 0000000000..cd957e00d1 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/assert.cpp @@ -0,0 +1,47 @@ +/* +* Runtime assertion checking +* (C) 2010,2012,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/exceptn.h> +#include <sstream> + +namespace Botan { + +void throw_invalid_argument(const char* message, + const char* func, + const char* file) + { + std::ostringstream format; + + format << message << " in " << func << ":" << file; + + throw Invalid_Argument(format.str()); + } + +void assertion_failure(const char* expr_str, + const char* assertion_made, + const char* func, + const char* file, + int line) + { + std::ostringstream format; + + format << "False assertion "; + + if(assertion_made && assertion_made[0] != 0) + format << "'" << assertion_made << "' (expression " << expr_str << ") "; + else + format << expr_str << " "; + + if(func) + format << "in " << func << " "; + + format << "@" << file << ":" << line; + + throw Exception(format.str()); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/assert.h b/src/libs/3rdparty/botan/src/lib/utils/assert.h new file mode 100644 index 0000000000..a12872f2bc --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/assert.h @@ -0,0 +1,145 @@ +/* +* Runtime assertion checking +* (C) 2010,2018 Jack Lloyd +* 2017 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASSERTION_CHECKING_H_ +#define BOTAN_ASSERTION_CHECKING_H_ + +#include <botan/build.h> +#include <botan/compiler.h> + +namespace Botan { + +/** +* Called when an assertion fails +* Throws an Exception object +*/ +BOTAN_NORETURN void BOTAN_PUBLIC_API(2,0) + assertion_failure(const char* expr_str, + const char* assertion_made, + const char* func, + const char* file, + int line); + +/** +* Called when an invalid argument is used +* Throws Invalid_Argument +*/ +BOTAN_NORETURN void BOTAN_UNSTABLE_API throw_invalid_argument(const char* message, + const char* func, + const char* file); + + +#define BOTAN_ARG_CHECK(expr, msg) \ + do { if(!(expr)) Botan::throw_invalid_argument(msg, BOTAN_CURRENT_FUNCTION, __FILE__); } while(0) + +/** +* Make an assertion +*/ +#define BOTAN_ASSERT(expr, assertion_made) \ + do { \ + if(!(expr)) \ + Botan::assertion_failure(#expr, \ + assertion_made, \ + BOTAN_CURRENT_FUNCTION, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Make an assertion +*/ +#define BOTAN_ASSERT_NOMSG(expr) \ + do { \ + if(!(expr)) \ + Botan::assertion_failure(#expr, \ + "", \ + BOTAN_CURRENT_FUNCTION, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that value1 == value2 +*/ +#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made) \ + do { \ + if((expr1) != (expr2)) \ + Botan::assertion_failure(#expr1 " == " #expr2, \ + assertion_made, \ + BOTAN_CURRENT_FUNCTION, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that expr1 (if true) implies expr2 is also true +*/ +#define BOTAN_ASSERT_IMPLICATION(expr1, expr2, msg) \ + do { \ + if((expr1) && !(expr2)) \ + Botan::assertion_failure(#expr1 " implies " #expr2, \ + msg, \ + BOTAN_CURRENT_FUNCTION, \ + __FILE__, \ + __LINE__); \ + } while(0) + +/** +* Assert that a pointer is not null +*/ +#define BOTAN_ASSERT_NONNULL(ptr) \ + do { \ + if((ptr) == nullptr) \ + Botan::assertion_failure(#ptr " is not null", \ + "", \ + BOTAN_CURRENT_FUNCTION, \ + __FILE__, \ + __LINE__); \ + } while(0) + +#if defined(BOTAN_ENABLE_DEBUG_ASSERTS) + +#define BOTAN_DEBUG_ASSERT(expr) BOTAN_ASSERT_NOMSG(expr) + +#else + +#define BOTAN_DEBUG_ASSERT(expr) do {} while(0) + +#endif + +/** +* Mark variable as unused. Takes between 1 and 9 arguments and marks all as unused, +* e.g. BOTAN_UNUSED(a); or BOTAN_UNUSED(x, y, z); +*/ +#define _BOTAN_UNUSED_IMPL1(a) static_cast<void>(a) +#define _BOTAN_UNUSED_IMPL2(a, b) static_cast<void>(a); _BOTAN_UNUSED_IMPL1(b) +#define _BOTAN_UNUSED_IMPL3(a, b, c) static_cast<void>(a); _BOTAN_UNUSED_IMPL2(b, c) +#define _BOTAN_UNUSED_IMPL4(a, b, c, d) static_cast<void>(a); _BOTAN_UNUSED_IMPL3(b, c, d) +#define _BOTAN_UNUSED_IMPL5(a, b, c, d, e) static_cast<void>(a); _BOTAN_UNUSED_IMPL4(b, c, d, e) +#define _BOTAN_UNUSED_IMPL6(a, b, c, d, e, f) static_cast<void>(a); _BOTAN_UNUSED_IMPL5(b, c, d, e, f) +#define _BOTAN_UNUSED_IMPL7(a, b, c, d, e, f, g) static_cast<void>(a); _BOTAN_UNUSED_IMPL6(b, c, d, e, f, g) +#define _BOTAN_UNUSED_IMPL8(a, b, c, d, e, f, g, h) static_cast<void>(a); _BOTAN_UNUSED_IMPL7(b, c, d, e, f, g, h) +#define _BOTAN_UNUSED_IMPL9(a, b, c, d, e, f, g, h, i) static_cast<void>(a); _BOTAN_UNUSED_IMPL8(b, c, d, e, f, g, h, i) +#define _BOTAN_UNUSED_GET_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, IMPL_NAME, ...) IMPL_NAME + +#define BOTAN_UNUSED(...) _BOTAN_UNUSED_GET_IMPL(__VA_ARGS__, \ + _BOTAN_UNUSED_IMPL9, \ + _BOTAN_UNUSED_IMPL8, \ + _BOTAN_UNUSED_IMPL7, \ + _BOTAN_UNUSED_IMPL6, \ + _BOTAN_UNUSED_IMPL5, \ + _BOTAN_UNUSED_IMPL4, \ + _BOTAN_UNUSED_IMPL3, \ + _BOTAN_UNUSED_IMPL2, \ + _BOTAN_UNUSED_IMPL1, \ + unused dummy rest value \ + ) /* we got an one of _BOTAN_UNUSED_IMPL*, now call it */ (__VA_ARGS__) + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/bit_ops.h b/src/libs/3rdparty/botan/src/lib/utils/bit_ops.h new file mode 100644 index 0000000000..c7e4014923 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/bit_ops.h @@ -0,0 +1,161 @@ +/* +* Bit/Word Operations +* (C) 1999-2008 Jack Lloyd +* (C) Copyright Projet SECRET, INRIA, Rocquencourt +* (C) Bhaskar Biswas and Nicolas Sendrier +* (C) 2014 cryptosource GmbH +* (C) 2014 Falko Strenzke fstrenzke@cryptosource.de +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BIT_OPS_H_ +#define BOTAN_BIT_OPS_H_ + +#include <botan/types.h> + +namespace Botan { + +/** +* Power of 2 test. T should be an unsigned integer type +* @param arg an integer value +* @return true iff arg is 2^n for some n > 0 +*/ +template<typename T> +inline bool is_power_of_2(T arg) + { + return ((arg != 0 && arg != 1) && ((arg & (arg-1)) == 0)); + } + +/** +* Return the index of the highest set bit +* T is an unsigned integer type +* @param n an integer value +* @return index of the highest set bit in n +*/ +template<typename T> +inline size_t high_bit(T n) + { + for(size_t i = 8*sizeof(T); i > 0; --i) + if((n >> (i - 1)) & 0x01) + return i; + return 0; + } + +/** +* Return the index of the lowest set bit +* T is an unsigned integer type +* @param n an integer value +* @return index of the lowest set bit in n +*/ +template<typename T> +inline size_t low_bit(T n) + { + for(size_t i = 0; i != 8*sizeof(T); ++i) + if((n >> i) & 0x01) + return (i + 1); + return 0; + } + +/** +* Return the number of significant bytes in n +* @param n an integer value +* @return number of significant bytes in n +*/ +template<typename T> +inline size_t significant_bytes(T n) + { + for(size_t i = 0; i != sizeof(T); ++i) + if(get_byte(i, n)) + return sizeof(T)-i; + return 0; + } + +/** +* Compute Hamming weights +* @param n an integer value +* @return number of bits in n set to 1 +*/ +template<typename T> +inline size_t hamming_weight(T n) + { + const uint8_t NIBBLE_WEIGHTS[] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + + size_t weight = 0; + for(size_t i = 0; i != 2*sizeof(T); ++i) + weight += NIBBLE_WEIGHTS[(n >> (4*i)) & 0x0F]; + return weight; + } + +/** +* Count the trailing zero bits in n +* @param n an integer value +* @return maximum x st 2^x divides n +*/ +template<typename T> +inline size_t ctz(T n) + { + for(size_t i = 0; i != 8*sizeof(T); ++i) + if((n >> i) & 0x01) + return i; + return 8*sizeof(T); + } + +#if defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) + +template<> +inline size_t ctz(uint32_t n) + { + if(n == 0) + return 32; + return __builtin_ctz(n); + } + +template<> +inline size_t ctz(uint64_t n) + { + if(n == 0) + return 64; + return __builtin_ctzll(n); + } + +template<> +inline size_t high_bit(uint32_t x) + { + if(x == 0) + return 0; + return (32 - __builtin_clz(x)); + } + +template<> +inline size_t high_bit(uint64_t x) + { + if(x == 0) + return 0; + return (64 - __builtin_clzll(x)); + } + +#endif + +template<typename T> +size_t ceil_log2(T x) + { + if(x >> (sizeof(T)*8-1)) + return sizeof(T)*8; + + size_t result = 0; + T compare = 1; + + while(compare < x) + { + compare <<= 1; + result++; + } + + return result; + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/bswap.h b/src/libs/3rdparty/botan/src/lib/utils/bswap.h new file mode 100644 index 0000000000..8d5731f1b0 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/bswap.h @@ -0,0 +1,99 @@ +/* +* Byte Swapping Operations +* (C) 1999-2011 Jack Lloyd +* (C) 2007 Yves Jerschow +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BYTE_SWAP_H_ +#define BOTAN_BYTE_SWAP_H_ + +#include <botan/types.h> +#include <botan/rotate.h> + +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + #include <stdlib.h> +#endif + +namespace Botan { + +/** +* Swap a 16 bit integer +*/ +inline uint16_t reverse_bytes(uint16_t val) + { + return rotl<8>(val); + } + +/** +* Swap a 32 bit integer +*/ +inline uint32_t reverse_bytes(uint32_t val) + { +#if defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) + return __builtin_bswap32(val); + +#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) + return _byteswap_ulong(val); + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + // GCC-style inline assembly for x86 or x86-64 + asm("bswapl %0" : "=r" (val) : "0" (val)); + return val; + +#else + + // Generic implementation + return (rotr<8>(val) & 0xFF00FF00) | (rotl<8>(val) & 0x00FF00FF); + +#endif + } + +/** +* Swap a 64 bit integer +*/ +inline uint64_t reverse_bytes(uint64_t val) + { +#if defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) + return __builtin_bswap64(val); + +#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) + return _byteswap_uint64(val); + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_X86_64) + // GCC-style inline assembly for x86-64 + asm("bswapq %0" : "=r" (val) : "0" (val)); + return val; + +#else + /* Generic implementation. Defined in terms of 32-bit bswap so any + * optimizations in that version can help. + */ + + uint32_t hi = static_cast<uint32_t>(val >> 32); + uint32_t lo = static_cast<uint32_t>(val); + + hi = reverse_bytes(hi); + lo = reverse_bytes(lo); + + return (static_cast<uint64_t>(lo) << 32) | hi; +#endif + } + +/** +* Swap 4 Ts in an array +*/ +template<typename T> +inline void bswap_4(T x[4]) + { + x[0] = reverse_bytes(x[0]); + x[1] = reverse_bytes(x[1]); + x[2] = reverse_bytes(x[2]); + x[3] = reverse_bytes(x[3]); + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/calendar.cpp b/src/libs/3rdparty/botan/src/lib/utils/calendar.cpp new file mode 100644 index 0000000000..fe04f1d239 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/calendar.cpp @@ -0,0 +1,119 @@ +/* +* Calendar Functions +* (C) 1999-2010,2017 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/calendar.h> +#include <botan/exceptn.h> +#include <ctime> +#include <sstream> +#include <iomanip> +#include <stdlib.h> + +namespace Botan { + +namespace { + +std::tm do_gmtime(std::time_t time_val) + { + std::tm tm; + +#if defined(BOTAN_TARGET_OS_HAS_WIN32) + ::gmtime_s(&tm, &time_val); // Windows +#elif defined(BOTAN_TARGET_OS_HAS_POSIX1) + ::gmtime_r(&time_val, &tm); // Unix/SUSv2 +#else + std::tm* tm_p = std::gmtime(&time_val); + if (tm_p == nullptr) + throw Encoding_Error("time_t_to_tm could not convert"); + tm = *tm_p; +#endif + + return tm; + } + +/* +Portable replacement for timegm, _mkgmtime, etc + +Algorithm due to Howard Hinnant + +See https://howardhinnant.github.io/date_algorithms.html#days_from_civil +for details and explaination. The code is slightly simplified by our assumption +that the date is at least 1970, which is sufficient for our purposes. +*/ +size_t days_since_epoch(uint32_t year, uint32_t month, uint32_t day) + { + if(month <= 2) + year -= 1; + const uint32_t era = year / 400; + const uint32_t yoe = year - era * 400; // [0, 399] + const uint32_t doy = (153*(month + (month > 2 ? -3 : 9)) + 2)/5 + day-1; // [0, 365] + const uint32_t doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096] + return era * 146097 + doe - 719468; + } + +} + +std::chrono::system_clock::time_point calendar_point::to_std_timepoint() const + { + if(get_year() < 1970) + throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years before 1970"); + + // 32 bit time_t ends at January 19, 2038 + // https://msdn.microsoft.com/en-us/library/2093ets1.aspx + // Throw after 2037 if 32 bit time_t is used + if(get_year() > 2037 && sizeof(std::time_t) == 4) + { + throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years after 2037 on this system"); + } + else if(get_year() >= 2400) + { + // This upper bound is somewhat arbitrary + throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years after 2400"); + } + + const uint64_t seconds_64 = (days_since_epoch(get_year(), get_month(), get_day()) * 86400) + + (get_hour() * 60 * 60) + (get_minutes() * 60) + get_seconds(); + + const time_t seconds_time_t = static_cast<time_t>(seconds_64); + + if(seconds_64 - seconds_time_t != 0) + { + throw Invalid_Argument("calendar_point::to_std_timepoint time_t overflow"); + } + + return std::chrono::system_clock::from_time_t(seconds_time_t); + } + +std::string calendar_point::to_string() const + { + // desired format: <YYYY>-<MM>-<dd>T<HH>:<mm>:<ss> + std::stringstream output; + output << std::setfill('0') + << std::setw(4) << get_year() << "-" + << std::setw(2) << get_month() << "-" + << std::setw(2) << get_day() << "T" + << std::setw(2) << get_hour() << ":" + << std::setw(2) << get_minutes() << ":" + << std::setw(2) << get_seconds(); + return output.str(); + } + + +calendar_point calendar_value( + const std::chrono::system_clock::time_point& time_point) + { + std::tm tm = do_gmtime(std::chrono::system_clock::to_time_t(time_point)); + + return calendar_point(tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/calendar.h b/src/libs/3rdparty/botan/src/lib/utils/calendar.h new file mode 100644 index 0000000000..83759070b8 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/calendar.h @@ -0,0 +1,91 @@ +/* +* Calendar Functions +* (C) 1999-2009,2015 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CALENDAR_H_ +#define BOTAN_CALENDAR_H_ + +#include <botan/types.h> +#include <chrono> +#include <string> + +namespace Botan { + +/** +* Struct representing a particular date and time +*/ +class BOTAN_PUBLIC_API(2,0) calendar_point + { + public: + + /** The year */ + uint32_t get_year() const { return year; } + + /** The month, 1 through 12 for Jan to Dec */ + uint32_t get_month() const { return month; } + + /** The day of the month, 1 through 31 (or 28 or 30 based on month */ + uint32_t get_day() const { return day; } + + /** Hour in 24-hour form, 0 to 23 */ + uint32_t get_hour() const { return hour; } + + /** Minutes in the hour, 0 to 60 */ + uint32_t get_minutes() const { return minutes; } + + /** Seconds in the minute, 0 to 60, but might be slightly + larger to deal with leap seconds on some systems + */ + uint32_t get_seconds() const { return seconds; } + + /** + * Initialize a calendar_point + * @param y the year + * @param mon the month + * @param d the day + * @param h the hour + * @param min the minute + * @param sec the second + */ + calendar_point(uint32_t y, uint32_t mon, uint32_t d, uint32_t h, uint32_t min, uint32_t sec) : + year(y), month(mon), day(d), hour(h), minutes(min), seconds(sec) {} + + /** + * Returns an STL timepoint object + */ + std::chrono::system_clock::time_point to_std_timepoint() const; + + /** + * Returns a human readable string of the struct's components. + * Formatting might change over time. Currently it is RFC339 'iso-date-time'. + */ + std::string to_string() const; + + BOTAN_DEPRECATED_PUBLIC_MEMBER_VARIABLES: + /* + The member variables are public for historical reasons. Use the get_xxx() functions + defined above. These members will be made private in a future major release. + */ + uint32_t year; + uint32_t month; + uint32_t day; + uint32_t hour; + uint32_t minutes; + uint32_t seconds; + }; + +/** +* Convert a time_point to a calendar_point +* @param time_point a time point from the system clock +* @return calendar_point object representing this time point +*/ +BOTAN_PUBLIC_API(2,0) calendar_point calendar_value( + const std::chrono::system_clock::time_point& time_point); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/charset.cpp b/src/libs/3rdparty/botan/src/lib/utils/charset.cpp new file mode 100644 index 0000000000..ca32c652db --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/charset.cpp @@ -0,0 +1,283 @@ +/* +* Character Set Handling +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/charset.h> +#include <botan/exceptn.h> +#include <botan/loadstor.h> +#include <cctype> + +namespace Botan { + +namespace { + +void append_utf8_for(std::string& s, uint32_t c) + { + if(c >= 0xD800 && c < 0xE000) + throw Decoding_Error("Invalid Unicode character"); + + if(c <= 0x7F) + { + const uint8_t b0 = static_cast<uint8_t>(c); + s.push_back(static_cast<char>(b0)); + } + else if(c <= 0x7FF) + { + const uint8_t b0 = 0xC0 | static_cast<uint8_t>(c >> 6); + const uint8_t b1 = 0x80 | static_cast<uint8_t>(c & 0x3F); + s.push_back(static_cast<char>(b0)); + s.push_back(static_cast<char>(b1)); + } + else if(c <= 0xFFFF) + { + const uint8_t b0 = 0xE0 | static_cast<uint8_t>(c >> 12); + const uint8_t b1 = 0x80 | static_cast<uint8_t>((c >> 6) & 0x3F); + const uint8_t b2 = 0x80 | static_cast<uint8_t>(c & 0x3F); + s.push_back(static_cast<char>(b0)); + s.push_back(static_cast<char>(b1)); + s.push_back(static_cast<char>(b2)); + } + else if(c <= 0x10FFFF) + { + const uint8_t b0 = 0xF0 | static_cast<uint8_t>(c >> 18); + const uint8_t b1 = 0x80 | static_cast<uint8_t>((c >> 12) & 0x3F); + const uint8_t b2 = 0x80 | static_cast<uint8_t>((c >> 6) & 0x3F); + const uint8_t b3 = 0x80 | static_cast<uint8_t>(c & 0x3F); + s.push_back(static_cast<char>(b0)); + s.push_back(static_cast<char>(b1)); + s.push_back(static_cast<char>(b2)); + s.push_back(static_cast<char>(b3)); + } + else + throw Decoding_Error("Invalid Unicode character"); + + } + +} + +std::string ucs2_to_utf8(const uint8_t ucs2[], size_t len) + { + if(len % 2 != 0) + throw Decoding_Error("Invalid length for UCS-2 string"); + + const size_t chars = len / 2; + + std::string s; + for(size_t i = 0; i != chars; ++i) + { + const uint16_t c = load_be<uint16_t>(ucs2, i); + append_utf8_for(s, c); + } + + return s; + } + +std::string ucs4_to_utf8(const uint8_t ucs4[], size_t len) + { + if(len % 4 != 0) + throw Decoding_Error("Invalid length for UCS-4 string"); + + const size_t chars = len / 4; + + std::string s; + for(size_t i = 0; i != chars; ++i) + { + const uint32_t c = load_be<uint32_t>(ucs4, i); + append_utf8_for(s, c); + } + + return s; + } + +/* +* Convert from UTF-8 to ISO 8859-1 +*/ +std::string utf8_to_latin1(const std::string& utf8) + { + std::string iso8859; + + size_t position = 0; + while(position != utf8.size()) + { + const uint8_t c1 = static_cast<uint8_t>(utf8[position++]); + + if(c1 <= 0x7F) + { + iso8859 += static_cast<char>(c1); + } + else if(c1 >= 0xC0 && c1 <= 0xC7) + { + if(position == utf8.size()) + throw Decoding_Error("UTF-8: sequence truncated"); + + const uint8_t c2 = static_cast<uint8_t>(utf8[position++]); + const uint8_t iso_char = ((c1 & 0x07) << 6) | (c2 & 0x3F); + + if(iso_char <= 0x7F) + throw Decoding_Error("UTF-8: sequence longer than needed"); + + iso8859 += static_cast<char>(iso_char); + } + else + throw Decoding_Error("UTF-8: Unicode chars not in Latin1 used"); + } + + return iso8859; + } + +namespace Charset { + +namespace { + +/* +* Convert from UCS-2 to ISO 8859-1 +*/ +std::string ucs2_to_latin1(const std::string& ucs2) + { + if(ucs2.size() % 2 == 1) + throw Decoding_Error("UCS-2 string has an odd number of bytes"); + + std::string latin1; + + for(size_t i = 0; i != ucs2.size(); i += 2) + { + const uint8_t c1 = ucs2[i]; + const uint8_t c2 = ucs2[i+1]; + + if(c1 != 0) + throw Decoding_Error("UCS-2 has non-Latin1 characters"); + + latin1 += static_cast<char>(c2); + } + + return latin1; + } + +/* +* Convert from ISO 8859-1 to UTF-8 +*/ +std::string latin1_to_utf8(const std::string& iso8859) + { + std::string utf8; + for(size_t i = 0; i != iso8859.size(); ++i) + { + const uint8_t c = static_cast<uint8_t>(iso8859[i]); + + if(c <= 0x7F) + utf8 += static_cast<char>(c); + else + { + utf8 += static_cast<char>((0xC0 | (c >> 6))); + utf8 += static_cast<char>((0x80 | (c & 0x3F))); + } + } + return utf8; + } + +} + +/* +* Perform character set transcoding +*/ +std::string transcode(const std::string& str, + Character_Set to, Character_Set from) + { + if(to == LOCAL_CHARSET) + to = LATIN1_CHARSET; + if(from == LOCAL_CHARSET) + from = LATIN1_CHARSET; + + if(to == from) + return str; + + if(from == LATIN1_CHARSET && to == UTF8_CHARSET) + return latin1_to_utf8(str); + if(from == UTF8_CHARSET && to == LATIN1_CHARSET) + return utf8_to_latin1(str); + if(from == UCS2_CHARSET && to == LATIN1_CHARSET) + return ucs2_to_latin1(str); + + throw Invalid_Argument("Unknown transcoding operation from " + + std::to_string(from) + " to " + std::to_string(to)); + } + +/* +* Check if a character represents a digit +*/ +bool is_digit(char c) + { + if(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || + c == '5' || c == '6' || c == '7' || c == '8' || c == '9') + return true; + return false; + } + +/* +* Check if a character represents whitespace +*/ +bool is_space(char c) + { + if(c == ' ' || c == '\t' || c == '\n' || c == '\r') + return true; + return false; + } + +/* +* Convert a character to a digit +*/ +uint8_t char2digit(char c) + { + switch(c) + { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + } + + throw Invalid_Argument("char2digit: Input is not a digit character"); + } + +/* +* Convert a digit to a character +*/ +char digit2char(uint8_t b) + { + switch(b) + { + case 0: return '0'; + case 1: return '1'; + case 2: return '2'; + case 3: return '3'; + case 4: return '4'; + case 5: return '5'; + case 6: return '6'; + case 7: return '7'; + case 8: return '8'; + case 9: return '9'; + } + + throw Invalid_Argument("digit2char: Input is not a digit"); + } + +/* +* Case-insensitive character comparison +*/ +bool caseless_cmp(char a, char b) + { + return (std::tolower(static_cast<unsigned char>(a)) == + std::tolower(static_cast<unsigned char>(b))); + } + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/charset.h b/src/libs/3rdparty/botan/src/lib/utils/charset.h new file mode 100644 index 0000000000..4913f0a5aa --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/charset.h @@ -0,0 +1,78 @@ +/* +* Character Set Handling +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CHARSET_H_ +#define BOTAN_CHARSET_H_ + +#include <botan/types.h> +#include <string> + +namespace Botan { + +/** +* Convert a sequence of UCS-2 (big endian) characters to a UTF-8 string +* This is used for ASN.1 BMPString type +* @param ucs2 the sequence of UCS-2 characters +* @param len length of ucs2 in bytes, must be a multiple of 2 +*/ +std::string BOTAN_UNSTABLE_API ucs2_to_utf8(const uint8_t ucs2[], size_t len); + +/** +* Convert a sequence of UCS-4 (big endian) characters to a UTF-8 string +* This is used for ASN.1 UniversalString type +* @param ucs4 the sequence of UCS-4 characters +* @param len length of ucs4 in bytes, must be a multiple of 4 +*/ +std::string BOTAN_UNSTABLE_API ucs4_to_utf8(const uint8_t ucs4[], size_t len); + +/** +* Convert a UTF-8 string to Latin-1 +* If a character outside the Latin-1 range is encountered, an exception is thrown. +*/ +std::string BOTAN_UNSTABLE_API utf8_to_latin1(const std::string& utf8); + +/** +* The different charsets (nominally) supported by Botan. +*/ +enum Character_Set { + LOCAL_CHARSET, + UCS2_CHARSET, + UTF8_CHARSET, + LATIN1_CHARSET +}; + +namespace Charset { + +/* +* Character set conversion - avoid this. +* For specific conversions, use the functions above like +* ucs2_to_utf8 and utf8_to_latin1 +* +* If you need something more complex than that, use a real library +* such as iconv, Boost.Locale, or ICU +*/ +std::string BOTAN_PUBLIC_API(2,0) + BOTAN_DEPRECATED("Avoid. See comment in header.") + transcode(const std::string& str, + Character_Set to, + Character_Set from); + +/* +* Simple character classifier functions +*/ +bool BOTAN_PUBLIC_API(2,0) is_digit(char c); +bool BOTAN_PUBLIC_API(2,0) is_space(char c); +bool BOTAN_PUBLIC_API(2,0) caseless_cmp(char x, char y); + +uint8_t BOTAN_PUBLIC_API(2,0) char2digit(char c); +char BOTAN_PUBLIC_API(2,0) digit2char(uint8_t b); + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/codec_base.h b/src/libs/3rdparty/botan/src/lib/utils/codec_base.h new file mode 100644 index 0000000000..e7dbc33e4c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/codec_base.h @@ -0,0 +1,165 @@ +/* +* Base Encoding and Decoding +* (C) 2018 Erwan Chaussy +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_BASE_CODEC_H_ +#define BOTAN_BASE_CODEC_H_ + +#include <botan/secmem.h> +#include <vector> +#include <string> + +namespace Botan { + +/** +* Perform encoding using the base provided +* @param base object giving access to the encodings specifications +* @param output an array of at least base.encode_max_output bytes +* @param input is some binary data +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding chars will be applied if needed +* @return number of bytes written to output +*/ +template <class Base> +size_t base_encode(Base&& base, + char output[], + const uint8_t input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs) + { + input_consumed = 0; + + const size_t encoding_bytes_in = base.encoding_bytes_in(); + const size_t encoding_bytes_out = base.encoding_bytes_out(); + + size_t input_remaining = input_length; + size_t output_produced = 0; + + while(input_remaining >= encoding_bytes_in) + { + base.encode(output + output_produced, input + input_consumed); + + input_consumed += encoding_bytes_in; + output_produced += encoding_bytes_out; + input_remaining -= encoding_bytes_in; + } + + if(final_inputs && input_remaining) + { + std::vector<uint8_t> remainder(encoding_bytes_in, 0); + for(size_t i = 0; i != input_remaining; ++i) + { remainder[i] = input[input_consumed + i]; } + + base.encode(output + output_produced, remainder.data()); + + const size_t bits_consumed = base.bits_consumed(); + const size_t remaining_bits_before_padding = base.remaining_bits_before_padding(); + + size_t empty_bits = 8 * (encoding_bytes_in - input_remaining); + size_t index = output_produced + encoding_bytes_out - 1; + while(empty_bits >= remaining_bits_before_padding) + { + output[index--] = '='; + empty_bits -= bits_consumed; + } + + input_consumed += input_remaining; + output_produced += encoding_bytes_out; + } + + return output_produced; + } + +/** +* Perform decoding using the base provided +* @param base object giving access to the encodings specifications +* @param output an array of at least base.decode_max_output bytes +* @param input some base input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding is allowed +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +template <typename Base> +size_t base_decode(Base&& base, + uint8_t output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws = true) + { + const size_t decoding_bytes_in = base.decoding_bytes_in(); + const size_t decoding_bytes_out = base.decoding_bytes_out(); + + uint8_t* out_ptr = output; + std::vector<uint8_t> decode_buf(decoding_bytes_in, 0); + size_t decode_buf_pos = 0; + size_t final_truncate = 0; + + clear_mem(output, base.decode_max_output(input_length)); + + for(size_t i = 0; i != input_length; ++i) + { + const uint8_t bin = base.lookup_binary_value(input[i]); + + if(base.check_bad_char(bin, input[i], ignore_ws)) // May throw Invalid_Argument + { + decode_buf[decode_buf_pos] = bin; + ++decode_buf_pos; + } + + /* + * If we're at the end of the input, pad with 0s and truncate + */ + if(final_inputs && (i == input_length - 1)) + { + if(decode_buf_pos) + { + for(size_t j = decode_buf_pos; j < decoding_bytes_in; ++j) + { decode_buf[j] = 0; } + + final_truncate = decoding_bytes_in - decode_buf_pos; + decode_buf_pos = decoding_bytes_in; + } + } + + if(decode_buf_pos == decoding_bytes_in) + { + base.decode(out_ptr, decode_buf.data()); + + out_ptr += decoding_bytes_out; + decode_buf_pos = 0; + input_consumed = i+1; + } + } + + while(input_consumed < input_length && + base.lookup_binary_value(input[input_consumed]) == 0x80) + { + ++input_consumed; + } + + size_t written = (out_ptr - output) - base.bytes_to_remove(final_truncate); + + return written; + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/compiler.h b/src/libs/3rdparty/botan/src/lib/utils/compiler.h new file mode 100644 index 0000000000..202b5cb755 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/compiler.h @@ -0,0 +1,203 @@ +/* +* Define useful compiler-specific macros +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +/* This header is included in both C++ and C (via ffi.h) and should only + contain macro definitions. +*/ + +#ifndef BOTAN_UTIL_COMPILER_FLAGS_H_ +#define BOTAN_UTIL_COMPILER_FLAGS_H_ + +/* Should we use GCC-style inline assembler? */ +#if !defined(BOTAN_USE_GCC_INLINE_ASM) && (defined(__GNUC__) || defined(__xlc__) || defined(__SUNPRO_CC)) + #define BOTAN_USE_GCC_INLINE_ASM 1 +#endif + +/** +* Used to annotate API exports which are public and supported. +* These APIs will not be broken/removed unless strictly required for +* functionality or security, and only in new major versions. +* @param maj The major version this public API was released in +* @param min The minor version this public API was released in +*/ +#define BOTAN_PUBLIC_API(maj,min) BOTAN_DLL + +/** +* Used to annotate API exports which are public and can be used by +* applications if needed, but which are intentionally not documented, +* and which may change incompatibly in a future major version. +*/ +#define BOTAN_UNSTABLE_API BOTAN_DLL + +/** +* Used to annotate API exports which are exported but only for the +* purposes of testing. They should not be used by applications and +* may be removed or changed without notice. +*/ +#define BOTAN_TEST_API BOTAN_DLL + +/* +* Define BOTAN_GCC_VERSION +*/ +#ifdef __GNUC__ + #define BOTAN_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__) +#else + #define BOTAN_GCC_VERSION 0 +#endif + +/* +* Define BOTAN_CLANG_VERSION +*/ +#ifdef __clang__ + #define BOTAN_CLANG_VERSION (__clang_major__ * 10 + __clang_minor__) +#else + #define BOTAN_CLANG_VERSION 0 +#endif + +/* +* Define special macro when building under MSVC 2013 since there are +* many compiler workarounds required for that version. +*/ +#if defined(_MSC_VER) && (_MSC_VER < 1900) + #define BOTAN_BUILD_COMPILER_IS_MSVC_2013 +#endif + +/* +* Define BOTAN_FUNC_ISA +*/ +#if (defined(__GNUG__) && !defined(__clang__)) || (BOTAN_CLANG_VERSION > 38) + #define BOTAN_FUNC_ISA(isa) __attribute__ ((target(isa))) +#else + #define BOTAN_FUNC_ISA(isa) +#endif + +/* +* Define BOTAN_WARN_UNUSED_RESULT +*/ +#if defined(__GNUG__) || defined(__clang__) + #define BOTAN_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) +#else + #define BOTAN_WARN_UNUSED_RESULT +#endif + +/* +* Define BOTAN_MALLOC_FN +*/ +#if defined(__GNUG__) || defined(__clang__) + #define BOTAN_MALLOC_FN __attribute__ ((malloc)) +#elif defined(_MSC_VER) + #define BOTAN_MALLOC_FN __declspec(restrict) +#else + #define BOTAN_MALLOC_FN +#endif + +/* +* Define BOTAN_DEPRECATED +*/ +#if !defined(BOTAN_NO_DEPRECATED_WARNINGS) + + #if defined(__clang__) + #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated)) + + #elif defined(_MSC_VER) + #define BOTAN_DEPRECATED(msg) __declspec(deprecated(msg)) + + #elif defined(__GNUG__) + // msg supported since GCC 4.5, earliest we support is 4.8 + #define BOTAN_DEPRECATED(msg) __attribute__ ((deprecated(msg))) + #endif + +#endif + +#if !defined(BOTAN_DEPRECATED) + #define BOTAN_DEPRECATED(msg) +#endif + +/* +* Define BOTAN_NORETURN +*/ +#if !defined(BOTAN_NORETURN) + + #if defined (__clang__) || defined (__GNUG__) + #define BOTAN_NORETURN __attribute__ ((__noreturn__)) + + #elif defined (_MSC_VER) + #define BOTAN_NORETURN __declspec(noreturn) + + #else + #define BOTAN_NORETURN + #endif + +#endif + +/* +* Define BOTAN_CURRENT_FUNCTION +*/ +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC_2013) + #define BOTAN_CURRENT_FUNCTION __FUNCTION__ +#else + #define BOTAN_CURRENT_FUNCTION __func__ +#endif + +/* +* Define BOTAN_NOEXCEPT (for MSVC 2013) +*/ +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC_2013) + // noexcept is not supported in VS 2013 + #include <yvals.h> + #define BOTAN_NOEXCEPT _NOEXCEPT +#else + #define BOTAN_NOEXCEPT noexcept +#endif + +/* +* Define BOTAN_CONSTEXPR (for MSVC 2013) +*/ +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC_2013) + #define BOTAN_CONSTEXPR /**/ +#else + #define BOTAN_CONSTEXPR constexpr +#endif + +/* +* Define BOTAN_ALIGNAS (for MSVC 2013) +*/ +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC_2013) + #define BOTAN_ALIGNAS(n) /**/ +#else + #define BOTAN_ALIGNAS(n) alignas(n) +#endif + +/* +* Define BOTAN_PARALLEL_FOR +*/ +#if !defined(BOTAN_PARALLEL_FOR) + +#if defined(BOTAN_TARGET_HAS_OPENMP) + #define BOTAN_PARALLEL_FOR _Pragma("omp parallel for") for +#else + #define BOTAN_PARALLEL_FOR for +#endif + +#endif + +/* +* Define BOTAN_PARALLEL_SIMD_FOR +*/ +#if !defined(BOTAN_PARALLEL_SIMD_FOR) + +#if defined(BOTAN_TARGET_HAS_OPENMP) + #define BOTAN_PARALLEL_SIMD_FOR _Pragma("omp simd") for +#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) && (BOTAN_GCC_VERSION >= 490) + #define BOTAN_PARALLEL_SIMD_FOR _Pragma("GCC ivdep") for +#else + #define BOTAN_PARALLEL_SIMD_FOR for +#endif + +#endif + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid.cpp b/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid.cpp new file mode 100644 index 0000000000..3938c72423 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid.cpp @@ -0,0 +1,179 @@ +/* +* Runtime CPU detection +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cpuid.h> +#include <botan/types.h> +#include <botan/exceptn.h> +#include <botan/parsing.h> +#include <ostream> + +namespace Botan { + +uint64_t CPUID::g_processor_features = 0; +size_t CPUID::g_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE; +CPUID::Endian_status CPUID::g_endian_status = ENDIAN_UNKNOWN; + +bool CPUID::has_simd_32() + { +#if defined(BOTAN_TARGET_SUPPORTS_SSE2) + return CPUID::has_sse2(); +#elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC) + return CPUID::has_altivec(); +#elif defined(BOTAN_TARGET_SUPPORTS_NEON) + return CPUID::has_neon(); +#else + return true; +#endif + } + +//static +std::string CPUID::to_string() + { + std::vector<std::string> flags; + +#define CPUID_PRINT(flag) do { if(has_##flag()) { flags.push_back(#flag); } } while(0) + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + CPUID_PRINT(sse2); + CPUID_PRINT(ssse3); + CPUID_PRINT(sse41); + CPUID_PRINT(sse42); + CPUID_PRINT(avx2); + CPUID_PRINT(avx512f); + + CPUID_PRINT(rdtsc); + CPUID_PRINT(bmi1); + CPUID_PRINT(bmi2); + CPUID_PRINT(adx); + + CPUID_PRINT(aes_ni); + CPUID_PRINT(clmul); + CPUID_PRINT(rdrand); + CPUID_PRINT(rdseed); + CPUID_PRINT(intel_sha); +#endif + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + CPUID_PRINT(altivec); + CPUID_PRINT(ppc_crypto); +#endif + +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + CPUID_PRINT(neon); + CPUID_PRINT(arm_sha1); + CPUID_PRINT(arm_sha2); + CPUID_PRINT(arm_aes); + CPUID_PRINT(arm_pmull); +#endif + +#undef CPUID_PRINT + + return string_join(flags, ' '); + } + +//static +void CPUID::print(std::ostream& o) + { + o << "CPUID flags: " << CPUID::to_string() << "\n"; + } + +//static +void CPUID::initialize() + { + g_processor_features = 0; + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \ + defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \ + defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + g_processor_features = CPUID::detect_cpu_features(&g_cache_line_size); + +#endif + + g_endian_status = runtime_check_endian(); + g_processor_features |= CPUID::CPUID_INITIALIZED_BIT; + } + +//static +CPUID::Endian_status CPUID::runtime_check_endian() + { + // Check runtime endian + const uint32_t endian32 = 0x01234567; + const uint8_t* e8 = reinterpret_cast<const uint8_t*>(&endian32); + + Endian_status endian = ENDIAN_UNKNOWN; + + if(e8[0] == 0x01 && e8[1] == 0x23 && e8[2] == 0x45 && e8[3] == 0x67) + { + endian = ENDIAN_BIG; + } + else if(e8[0] == 0x67 && e8[1] == 0x45 && e8[2] == 0x23 && e8[3] == 0x01) + { + endian = ENDIAN_LITTLE; + } + else + { + throw Internal_Error("Unexpected endian at runtime, neither big nor little"); + } + + // If we were compiled with a known endian, verify it matches at runtime +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + BOTAN_ASSERT(endian == ENDIAN_LITTLE, "Build and runtime endian match"); +#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + BOTAN_ASSERT(endian == ENDIAN_BIG, "Build and runtime endian match"); +#endif + + return endian; + } + +std::vector<Botan::CPUID::CPUID_bits> +CPUID::bit_from_string(const std::string& tok) + { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + if(tok == "sse2" || tok == "simd") + return {Botan::CPUID::CPUID_SSE2_BIT}; + if(tok == "ssse3") + return {Botan::CPUID::CPUID_SSSE3_BIT}; + if(tok == "aesni") + return {Botan::CPUID::CPUID_AESNI_BIT}; + if(tok == "clmul") + return {Botan::CPUID::CPUID_CLMUL_BIT}; + if(tok == "avx2") + return {Botan::CPUID::CPUID_AVX2_BIT}; + if(tok == "sha") + return {Botan::CPUID::CPUID_SHA_BIT}; + if(tok == "bmi2") + return {Botan::CPUID::CPUID_BMI2_BIT}; + if(tok == "adx") + return {Botan::CPUID::CPUID_ADX_BIT}; + if(tok == "intel_sha") + return {Botan::CPUID::CPUID_SHA_BIT}; + +#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + if(tok == "altivec" || tok == "simd") + return {Botan::CPUID::CPUID_ALTIVEC_BIT}; + +#elif defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + if(tok == "neon" || tok == "simd") + return {Botan::CPUID::CPUID_ARM_NEON_BIT}; + if(tok == "armv8sha1") + return {Botan::CPUID::CPUID_ARM_SHA1_BIT}; + if(tok == "armv8sha2") + return {Botan::CPUID::CPUID_ARM_SHA2_BIT}; + if(tok == "armv8aes") + return {Botan::CPUID::CPUID_ARM_AES_BIT}; + if(tok == "armv8pmull") + return {Botan::CPUID::CPUID_ARM_PMULL_BIT}; + +#else + BOTAN_UNUSED(tok); +#endif + + return {}; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid.h b/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid.h new file mode 100644 index 0000000000..633824a6cc --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid.h @@ -0,0 +1,327 @@ +/* +* Runtime CPU detection +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CPUID_H_ +#define BOTAN_CPUID_H_ + +#include <botan/types.h> +#include <vector> +#include <string> +#include <iosfwd> + +namespace Botan { + +/** +* A class handling runtime CPU feature detection. It is limited to +* just the features necessary to implement CPU specific code in Botan, +* rather than being a general purpose utility. +* +* This class supports: +* +* - x86 features using CPUID. x86 is also the only processor with +* accurate cache line detection currently. +* +* - PowerPC AltiVec detection on Linux, NetBSD, OpenBSD, and Darwin +* +* - ARM NEON and crypto extensions detection. On Linux and Android +* systems which support getauxval, that is used to access CPU +* feature information. Otherwise a relatively portable but +* thread-unsafe mechanism involving executing probe functions which +* catching SIGILL signal is used. +*/ +class BOTAN_PUBLIC_API(2,1) CPUID final + { + public: + /** + * Probe the CPU and see what extensions are supported + */ + static void initialize(); + + static bool has_simd_32(); + + /** + * Deprecated equivalent to + * o << "CPUID flags: " << CPUID::to_string() << "\n"; + */ + BOTAN_DEPRECATED("Use CPUID::to_string") + static void print(std::ostream& o); + + /** + * Return a possibly empty string containing list of known CPU + * extensions. Each name will be seperated by a space, and the ordering + * will be arbitrary. This list only contains values that are useful to + * Botan (for example FMA instructions are not checked). + * + * Example outputs "sse2 ssse3 rdtsc", "neon arm_aes", "altivec" + */ + static std::string to_string(); + + /** + * Return a best guess of the cache line size + */ + static size_t cache_line_size() + { + if(g_processor_features == 0) + { + initialize(); + } + return g_cache_line_size; + } + + static bool is_little_endian() + { + return endian_status() == ENDIAN_LITTLE; + } + + static bool is_big_endian() + { + return endian_status() == ENDIAN_BIG; + } + + enum CPUID_bits : uint64_t { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + // These values have no relation to cpuid bitfields + + // SIMD instruction sets + CPUID_SSE2_BIT = (1ULL << 0), + CPUID_SSSE3_BIT = (1ULL << 1), + CPUID_SSE41_BIT = (1ULL << 2), + CPUID_SSE42_BIT = (1ULL << 3), + CPUID_AVX2_BIT = (1ULL << 4), + CPUID_AVX512F_BIT = (1ULL << 5), + + // Misc useful instructions + CPUID_RDTSC_BIT = (1ULL << 10), + CPUID_BMI2_BIT = (1ULL << 11), + CPUID_ADX_BIT = (1ULL << 12), + CPUID_BMI1_BIT = (1ULL << 13), + + // Crypto-specific ISAs + CPUID_AESNI_BIT = (1ULL << 16), + CPUID_CLMUL_BIT = (1ULL << 17), + CPUID_RDRAND_BIT = (1ULL << 18), + CPUID_RDSEED_BIT = (1ULL << 19), + CPUID_SHA_BIT = (1ULL << 20), +#endif + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + CPUID_ALTIVEC_BIT = (1ULL << 0), + CPUID_PPC_CRYPTO_BIT = (1ULL << 1), +#endif + +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + CPUID_ARM_NEON_BIT = (1ULL << 0), + CPUID_ARM_AES_BIT = (1ULL << 16), + CPUID_ARM_PMULL_BIT = (1ULL << 17), + CPUID_ARM_SHA1_BIT = (1ULL << 18), + CPUID_ARM_SHA2_BIT = (1ULL << 19), +#endif + + CPUID_INITIALIZED_BIT = (1ULL << 63) + }; + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + /** + * Check if the processor supports AltiVec/VMX + */ + static bool has_altivec() + { return has_cpuid_bit(CPUID_ALTIVEC_BIT); } + + /** + * Check if the processor supports POWER8 crypto extensions + */ + static bool has_ppc_crypto() + { return has_cpuid_bit(CPUID_PPC_CRYPTO_BIT); } + +#endif + +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + /** + * Check if the processor supports NEON SIMD + */ + static bool has_neon() + { return has_cpuid_bit(CPUID_ARM_NEON_BIT); } + + /** + * Check if the processor supports ARMv8 SHA1 + */ + static bool has_arm_sha1() + { return has_cpuid_bit(CPUID_ARM_SHA1_BIT); } + + /** + * Check if the processor supports ARMv8 SHA2 + */ + static bool has_arm_sha2() + { return has_cpuid_bit(CPUID_ARM_SHA2_BIT); } + + /** + * Check if the processor supports ARMv8 AES + */ + static bool has_arm_aes() + { return has_cpuid_bit(CPUID_ARM_AES_BIT); } + + /** + * Check if the processor supports ARMv8 PMULL + */ + static bool has_arm_pmull() + { return has_cpuid_bit(CPUID_ARM_PMULL_BIT); } +#endif + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + /** + * Check if the processor supports RDTSC + */ + static bool has_rdtsc() + { return has_cpuid_bit(CPUID_RDTSC_BIT); } + + /** + * Check if the processor supports SSE2 + */ + static bool has_sse2() + { return has_cpuid_bit(CPUID_SSE2_BIT); } + + /** + * Check if the processor supports SSSE3 + */ + static bool has_ssse3() + { return has_cpuid_bit(CPUID_SSSE3_BIT); } + + /** + * Check if the processor supports SSE4.1 + */ + static bool has_sse41() + { return has_cpuid_bit(CPUID_SSE41_BIT); } + + /** + * Check if the processor supports SSE4.2 + */ + static bool has_sse42() + { return has_cpuid_bit(CPUID_SSE42_BIT); } + + /** + * Check if the processor supports AVX2 + */ + static bool has_avx2() + { return has_cpuid_bit(CPUID_AVX2_BIT); } + + /** + * Check if the processor supports AVX-512F + */ + static bool has_avx512f() + { return has_cpuid_bit(CPUID_AVX512F_BIT); } + + /** + * Check if the processor supports BMI1 + */ + static bool has_bmi1() + { return has_cpuid_bit(CPUID_BMI1_BIT); } + + /** + * Check if the processor supports BMI2 + */ + static bool has_bmi2() + { return has_cpuid_bit(CPUID_BMI2_BIT); } + + /** + * Check if the processor supports AES-NI + */ + static bool has_aes_ni() + { return has_cpuid_bit(CPUID_AESNI_BIT); } + + /** + * Check if the processor supports CLMUL + */ + static bool has_clmul() + { return has_cpuid_bit(CPUID_CLMUL_BIT); } + + /** + * Check if the processor supports Intel SHA extension + */ + static bool has_intel_sha() + { return has_cpuid_bit(CPUID_SHA_BIT); } + + /** + * Check if the processor supports ADX extension + */ + static bool has_adx() + { return has_cpuid_bit(CPUID_ADX_BIT); } + + /** + * Check if the processor supports RDRAND + */ + static bool has_rdrand() + { return has_cpuid_bit(CPUID_RDRAND_BIT); } + + /** + * Check if the processor supports RDSEED + */ + static bool has_rdseed() + { return has_cpuid_bit(CPUID_RDSEED_BIT); } +#endif + + /* + * Clear a CPUID bit + * Call CPUID::initialize to reset + * + * This is only exposed for testing, don't use unless you know + * what you are doing. + */ + static void clear_cpuid_bit(CPUID_bits bit) + { + const uint64_t mask = ~(static_cast<uint64_t>(bit)); + g_processor_features &= mask; + } + + /* + * Don't call this function, use CPUID::has_xxx above + * It is only exposed for the tests. + */ + static bool has_cpuid_bit(CPUID_bits elem) + { + if(g_processor_features == 0) + initialize(); + + const uint64_t elem64 = static_cast<uint64_t>(elem); + return ((g_processor_features & elem64) == elem64); + } + + static std::vector<CPUID::CPUID_bits> bit_from_string(const std::string& tok); + private: + enum Endian_status : uint32_t { + ENDIAN_UNKNOWN = 0x00000000, + ENDIAN_BIG = 0x01234567, + ENDIAN_LITTLE = 0x67452301, + }; + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \ + defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \ + defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + static uint64_t detect_cpu_features(size_t* cache_line_size); + +#endif + + static Endian_status runtime_check_endian(); + + static Endian_status endian_status() + { + if(g_endian_status == ENDIAN_UNKNOWN) + { + g_endian_status = runtime_check_endian(); + } + return g_endian_status; + } + + static uint64_t g_processor_features; + static size_t g_cache_line_size; + static Endian_status g_endian_status; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid_arm.cpp b/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid_arm.cpp new file mode 100644 index 0000000000..39b6db652e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid_arm.cpp @@ -0,0 +1,214 @@ +/* +* Runtime CPU detection for ARM +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cpuid.h> + +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + +#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) + #include <sys/auxv.h> + +#elif defined(BOTAN_TARGET_OS_IS_IOS) + #include <sys/types.h> + #include <sys/sysctl.h> + +#else + #include <botan/internal/os_utils.h> + +#endif + +#endif + +namespace Botan { + +#if defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + +#if defined(BOTAN_TARGET_OS_IS_IOS) + +namespace { + +uint64_t flags_by_ios_machine_type(const std::string& machine) + { + /* + * This relies on a map of known machine names to features. This + * will quickly grow out of date as new products are introduced, but + * is apparently the best we can do for iOS. + */ + + struct version_info { + std::string name; + size_t min_version_neon; + size_t min_version_armv8; + }; + + static const version_info min_versions[] = { + { "iPhone", 2, 6 }, + { "iPad", 1, 4 }, + { "iPod", 4, 7 }, + { "AppleTV", 2, 5 }, + }; + + if(machine.size() < 3) + return 0; + + auto comma = machine.find(','); + + // Simulator, or something we don't know about + if(comma == std::string::npos) + return 0; + + std::string product = machine.substr(0, comma); + + size_t version = 0; + size_t place = 1; + while(product.size() > 1 && ::isdigit(product.back())) + { + const size_t digit = product.back() - '0'; + version += digit * place; + place *= 10; + product.pop_back(); + } + + if(version == 0) + return 0; + + for(const version_info& info : min_versions) + { + if(info.name != product) + continue; + + if(version >= info.min_version_armv8) + { + return CPUID::CPUID_ARM_AES_BIT | + CPUID::CPUID_ARM_PMULL_BIT | + CPUID::CPUID_ARM_SHA1_BIT | + CPUID::CPUID_ARM_SHA2_BIT | + CPUID::CPUID_ARM_NEON_BIT; + } + + if(version >= info.min_version_neon) + return CPUID::CPUID_ARM_NEON_BIT; + } + + // Some other product we don't know about + return 0; + } + +} + +#endif + +uint64_t CPUID::detect_cpu_features(size_t* cache_line_size) + { + uint64_t detected_features = 0; + +#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) + /* + * On systems with getauxval these bits should normally be defined + * in bits/auxv.h but some buggy? glibc installs seem to miss them. + * These following values are all fixed, for the Linux ELF format, + * so we just hardcode them in ARM_hwcap_bit enum. + */ + + enum ARM_hwcap_bit { +#if defined(BOTAN_TARGET_ARCH_IS_ARM32) + NEON_bit = (1 << 12), + AES_bit = (1 << 0), + PMULL_bit = (1 << 1), + SHA1_bit = (1 << 2), + SHA2_bit = (1 << 3), + + ARCH_hwcap_neon = 16, // AT_HWCAP + ARCH_hwcap_crypto = 26, // AT_HWCAP2 +#elif defined(BOTAN_TARGET_ARCH_IS_ARM64) + NEON_bit = (1 << 1), + AES_bit = (1 << 3), + PMULL_bit = (1 << 4), + SHA1_bit = (1 << 5), + SHA2_bit = (1 << 6), + + ARCH_hwcap_neon = 16, // AT_HWCAP + ARCH_hwcap_crypto = 16, // AT_HWCAP +#endif + }; + +#if defined(AT_DCACHEBSIZE) + const unsigned long dcache_line = ::getauxval(AT_DCACHEBSIZE); + + // plausibility check + if(dcache_line == 32 || dcache_line == 64 || dcache_line == 128) + *cache_line_size = static_cast<size_t>(dcache_line); +#endif + + const unsigned long hwcap_neon = ::getauxval(ARM_hwcap_bit::ARCH_hwcap_neon); + if(hwcap_neon & ARM_hwcap_bit::NEON_bit) + detected_features |= CPUID::CPUID_ARM_NEON_BIT; + + /* + On aarch64 this ends up calling getauxval twice with AT_HWCAP + It doesn't seem worth optimizing this out, since getauxval is + just reading a field in the ELF header. + */ + const unsigned long hwcap_crypto = ::getauxval(ARM_hwcap_bit::ARCH_hwcap_crypto); + if(hwcap_crypto & ARM_hwcap_bit::AES_bit) + detected_features |= CPUID::CPUID_ARM_AES_BIT; + if(hwcap_crypto & ARM_hwcap_bit::PMULL_bit) + detected_features |= CPUID::CPUID_ARM_PMULL_BIT; + if(hwcap_crypto & ARM_hwcap_bit::SHA1_bit) + detected_features |= CPUID::CPUID_ARM_SHA1_BIT; + if(hwcap_crypto & ARM_hwcap_bit::SHA2_bit) + detected_features |= CPUID::CPUID_ARM_SHA2_BIT; + +#elif defined(BOTAN_TARGET_OS_IS_IOS) + + char machine[64] = { 0 }; + size_t size = sizeof(machine) - 1; + ::sysctlbyname("hw.machine", machine, &size, nullptr, 0); + + detected_features = flags_by_ios_machine_type(machine); + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_ARM64) + + /* + No getauxval API available, fall back on probe functions. We only + bother with Aarch64 here to simplify the code and because going to + extreme contortions to support detect NEON on devices that probably + don't support it doesn't seem worthwhile. + + NEON registers v0-v7 are caller saved in Aarch64 + */ + + auto neon_probe = []() -> int { asm("and v0.16b, v0.16b, v0.16b"); return 1; }; + auto aes_probe = []() -> int { asm(".word 0x4e284800"); return 1; }; + auto pmull_probe = []() -> int { asm(".word 0x0ee0e000"); return 1; }; + auto sha1_probe = []() -> int { asm(".word 0x5e280800"); return 1; }; + auto sha2_probe = []() -> int { asm(".word 0x5e282800"); return 1; }; + + // Only bother running the crypto detection if we found NEON + + if(OS::run_cpu_instruction_probe(neon_probe) == 1) + { + detected_features |= CPUID::CPUID_ARM_NEON_BIT; + + if(OS::run_cpu_instruction_probe(aes_probe) == 1) + detected_features |= CPUID::CPUID_ARM_AES_BIT; + if(OS::run_cpu_instruction_probe(pmull_probe) == 1) + detected_features |= CPUID::CPUID_ARM_PMULL_BIT; + if(OS::run_cpu_instruction_probe(sha1_probe) == 1) + detected_features |= CPUID::CPUID_ARM_SHA1_BIT; + if(OS::run_cpu_instruction_probe(sha2_probe) == 1) + detected_features |= CPUID::CPUID_ARM_SHA2_BIT; + } + +#endif + + return detected_features; + } + +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid_ppc.cpp b/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid_ppc.cpp new file mode 100644 index 0000000000..43b6847852 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid_ppc.cpp @@ -0,0 +1,129 @@ +/* +* Runtime CPU detection for POWER/PowerPC +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cpuid.h> +#include <botan/internal/os_utils.h> + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +/* +* On Darwin and OpenBSD ppc, use sysctl to detect AltiVec +*/ +#if defined(BOTAN_TARGET_OS_IS_DARWIN) + #include <sys/sysctl.h> +#elif defined(BOTAN_TARGET_OS_IS_OPENBSD) + #include <sys/param.h> + #include <sys/sysctl.h> + #include <machine/cpu.h> +#elif defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) + #include <sys/auxv.h> +#endif + +#endif + +namespace Botan { + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + +/* +* PowerPC specific block: check for AltiVec using either +* sysctl or by reading processor version number register. +*/ +uint64_t CPUID::detect_cpu_features(size_t* cache_line_size) + { + BOTAN_UNUSED(cache_line_size); + +#if defined(BOTAN_TARGET_OS_IS_DARWIN) || defined(BOTAN_TARGET_OS_IS_OPENBSD) + // On Darwin/OS X and OpenBSD, use sysctl + + int sels[2] = { +#if defined(BOTAN_TARGET_OS_IS_OPENBSD) + CTL_MACHDEP, CPU_ALTIVEC +#else + CTL_HW, HW_VECTORUNIT +#endif + }; + + int vector_type = 0; + size_t length = sizeof(vector_type); + int error = ::sysctl(sels, 2, &vector_type, &length, NULL, 0); + + if(error == 0 && vector_type > 0) + return CPUID::CPUID_ALTIVEC_BIT; + +#elif defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) && defined(BOTAN_TARGET_ARCH_IS_PPC64) + + enum PPC_hwcap_bit { + ALTIVEC_bit = (1 << 28), + CRYPTO_bit = (1 << 25), + + ARCH_hwcap_altivec = 16, // AT_HWCAP + ARCH_hwcap_crypto = 26, // AT_HWCAP2 + }; + + uint64_t detected_features = 0; + + const unsigned long hwcap_altivec = ::getauxval(PPC_hwcap_bit::ARCH_hwcap_altivec); + if(hwcap_altivec & PPC_hwcap_bit::ALTIVEC_bit) + detected_features |= CPUID::CPUID_ALTIVEC_BIT; + + const unsigned long hwcap_crypto = ::getauxval(PPC_hwcap_bit::ARCH_hwcap_crypto); + if(hwcap_crypto & PPC_hwcap_bit::CRYPTO_bit) + detected_features |= CPUID::CPUID_PPC_CRYPTO_BIT; + + return detected_features; + +#else + + /* + On PowerPC, MSR 287 is PVR, the Processor Version Number + Normally it is only accessible to ring 0, but Linux and NetBSD + (others, too, maybe?) will trap and emulate it for us. + */ + + int pvr = OS::run_cpu_instruction_probe([]() -> int { + uint32_t pvr = 0; + asm volatile("mfspr %0, 287" : "=r" (pvr)); + // Top 16 bits suffice to identify the model + return static_cast<int>(pvr >> 16); + }); + + if(pvr > 0) + { + const uint16_t ALTIVEC_PVR[] = { + 0x003E, // IBM POWER6 + 0x003F, // IBM POWER7 + 0x004A, // IBM POWER7p + 0x004D, // IBM POWER8 + 0x004B, // IBM POWER8E + 0x000C, // G4-7400 + 0x0039, // G5 970 + 0x003C, // G5 970FX + 0x0044, // G5 970MP + 0x0070, // Cell PPU + 0, // end + }; + + for(size_t i = 0; ALTIVEC_PVR[i]; ++i) + { + if(pvr == ALTIVEC_PVR[i]) + return CPUID::CPUID_ALTIVEC_BIT; + } + + return 0; + } + + // TODO try direct instruction probing + +#endif + + return 0; + } + +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid_x86.cpp b/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid_x86.cpp new file mode 100644 index 0000000000..5387a801ec --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/cpuid/cpuid_x86.cpp @@ -0,0 +1,178 @@ +/* +* Runtime CPU detection for x86 +* (C) 2009,2010,2013,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cpuid.h> +#include <botan/mem_ops.h> +#include <botan/loadstor.h> + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + #include <intrin.h> +#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL) + #include <ia32intrin.h> +#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) + #include <cpuid.h> +#endif + +#endif + +namespace Botan { + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + +uint64_t CPUID::detect_cpu_features(size_t* cache_line_size) + { +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + #define X86_CPUID(type, out) do { __cpuid((int*)out, type); } while(0) + #define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0) + +#elif defined(BOTAN_BUILD_COMPILER_IS_INTEL) + #define X86_CPUID(type, out) do { __cpuid(out, type); } while(0) + #define X86_CPUID_SUBLEVEL(type, level, out) do { __cpuidex((int*)out, type, level); } while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && defined(BOTAN_USE_GCC_INLINE_ASM) + #define X86_CPUID(type, out) \ + asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ + : "0" (type)) + + #define X86_CPUID_SUBLEVEL(type, level, out) \ + asm("cpuid\n\t" : "=a" (out[0]), "=b" (out[1]), "=c" (out[2]), "=d" (out[3]) \ + : "0" (type), "2" (level)) + +#elif defined(BOTAN_BUILD_COMPILER_IS_GCC) || defined(BOTAN_BUILD_COMPILER_IS_CLANG) + #define X86_CPUID(type, out) do { __get_cpuid(type, out, out+1, out+2, out+3); } while(0) + + #define X86_CPUID_SUBLEVEL(type, level, out) \ + do { __cpuid_count(type, level, out[0], out[1], out[2], out[3]); } while(0) +#else + #warning "No way of calling x86 cpuid instruction for this compiler" + #define X86_CPUID(type, out) do { clear_mem(out, 4); } while(0) + #define X86_CPUID_SUBLEVEL(type, level, out) do { clear_mem(out, 4); } while(0) +#endif + + uint64_t features_detected = 0; + uint32_t cpuid[4] = { 0 }; + + // CPUID 0: vendor identification, max sublevel + X86_CPUID(0, cpuid); + + const uint32_t max_supported_sublevel = cpuid[0]; + + const uint32_t INTEL_CPUID[3] = { 0x756E6547, 0x6C65746E, 0x49656E69 }; + const uint32_t AMD_CPUID[3] = { 0x68747541, 0x444D4163, 0x69746E65 }; + const bool is_intel = same_mem(cpuid + 1, INTEL_CPUID, 3); + const bool is_amd = same_mem(cpuid + 1, AMD_CPUID, 3); + + if(max_supported_sublevel >= 1) + { + // CPUID 1: feature bits + X86_CPUID(1, cpuid); + const uint64_t flags0 = (static_cast<uint64_t>(cpuid[2]) << 32) | cpuid[3]; + + enum x86_CPUID_1_bits : uint64_t { + RDTSC = (1ULL << 4), + SSE2 = (1ULL << 26), + CLMUL = (1ULL << 33), + SSSE3 = (1ULL << 41), + SSE41 = (1ULL << 51), + SSE42 = (1ULL << 52), + AESNI = (1ULL << 57), + RDRAND = (1ULL << 62) + }; + + if(flags0 & x86_CPUID_1_bits::RDTSC) + features_detected |= CPUID::CPUID_RDTSC_BIT; + if(flags0 & x86_CPUID_1_bits::SSE2) + features_detected |= CPUID::CPUID_SSE2_BIT; + if(flags0 & x86_CPUID_1_bits::CLMUL) + features_detected |= CPUID::CPUID_CLMUL_BIT; + if(flags0 & x86_CPUID_1_bits::SSSE3) + features_detected |= CPUID::CPUID_SSSE3_BIT; + if(flags0 & x86_CPUID_1_bits::SSE41) + features_detected |= CPUID::CPUID_SSE41_BIT; + if(flags0 & x86_CPUID_1_bits::SSE42) + features_detected |= CPUID::CPUID_SSE42_BIT; + if(flags0 & x86_CPUID_1_bits::AESNI) + features_detected |= CPUID::CPUID_AESNI_BIT; + if(flags0 & x86_CPUID_1_bits::RDRAND) + features_detected |= CPUID::CPUID_RDRAND_BIT; + } + + if(is_intel) + { + // Intel cache line size is in cpuid(1) output + *cache_line_size = 8 * get_byte(2, cpuid[1]); + } + else if(is_amd) + { + // AMD puts it in vendor zone + X86_CPUID(0x80000005, cpuid); + *cache_line_size = get_byte(3, cpuid[2]); + } + + if(max_supported_sublevel >= 7) + { + clear_mem(cpuid, 4); + X86_CPUID_SUBLEVEL(7, 0, cpuid); + + enum x86_CPUID_7_bits : uint64_t { + BMI1 = (1ULL << 3), + AVX2 = (1ULL << 5), + BMI2 = (1ULL << 8), + AVX512F = (1ULL << 16), + RDSEED = (1ULL << 18), + ADX = (1ULL << 19), + SHA = (1ULL << 29), + }; + uint64_t flags7 = (static_cast<uint64_t>(cpuid[2]) << 32) | cpuid[1]; + + if(flags7 & x86_CPUID_7_bits::AVX2) + features_detected |= CPUID::CPUID_AVX2_BIT; + if(flags7 & x86_CPUID_7_bits::BMI1) + { + features_detected |= CPUID::CPUID_BMI1_BIT; + /* + We only set the BMI2 bit if BMI1 is also supported, so BMI2 + code can safely use both extensions. No known processor + implements BMI2 but not BMI1. + */ + if(flags7 & x86_CPUID_7_bits::BMI2) + features_detected |= CPUID::CPUID_BMI2_BIT; + } + + if(flags7 & x86_CPUID_7_bits::AVX512F) + features_detected |= CPUID::CPUID_AVX512F_BIT; + if(flags7 & x86_CPUID_7_bits::RDSEED) + features_detected |= CPUID::CPUID_RDSEED_BIT; + if(flags7 & x86_CPUID_7_bits::ADX) + features_detected |= CPUID::CPUID_ADX_BIT; + if(flags7 & x86_CPUID_7_bits::SHA) + features_detected |= CPUID::CPUID_SHA_BIT; + } + +#undef X86_CPUID +#undef X86_CPUID_SUBLEVEL + + /* + * If we don't have access to CPUID, we can still safely assume that + * any x86-64 processor has SSE2 and RDTSC + */ +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) + if(features_detected == 0) + { + features_detected |= CPUID::CPUID_SSE2_BIT; + features_detected |= CPUID::CPUID_RDTSC_BIT; + } +#endif + + return features_detected; + } + +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/cpuid/info.txt b/src/libs/3rdparty/botan/src/lib/utils/cpuid/info.txt new file mode 100644 index 0000000000..987d7eae4d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/cpuid/info.txt @@ -0,0 +1,7 @@ +<defines> +CPUID -> 20170917 +</defines> + +<header:public> +cpuid.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/utils/ct_utils.h b/src/libs/3rdparty/botan/src/lib/utils/ct_utils.h new file mode 100644 index 0000000000..0132678742 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/ct_utils.h @@ -0,0 +1,208 @@ +/* +* Functions for constant time operations on data and testing of +* constant time annotations using valgrind. +* +* For more information about constant time programming see +* Wagner, Molnar, et al "The Program Counter Security Model" +* +* (C) 2010 Falko Strenzke +* (C) 2015,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TIMING_ATTACK_CM_H_ +#define BOTAN_TIMING_ATTACK_CM_H_ + +#include <botan/secmem.h> +#include <vector> + +#if defined(BOTAN_HAS_VALGRIND) + #include <valgrind/memcheck.h> +#endif + +namespace Botan { + +namespace CT { + +/** +* Use valgrind to mark the contents of memory as being undefined. +* Valgrind will accept operations which manipulate undefined values, +* but will warn if an undefined value is used to decided a conditional +* jump or a load/store address. So if we poison all of our inputs we +* can confirm that the operations in question are truly const time +* when compiled by whatever compiler is in use. +* +* Even better, the VALGRIND_MAKE_MEM_* macros work even when the +* program is not run under valgrind (though with a few cycles of +* overhead, which is unfortunate in final binaries as these +* annotations tend to be used in fairly important loops). +* +* This approach was first used in ctgrind (https://github.com/agl/ctgrind) +* but calling the valgrind mecheck API directly works just as well and +* doesn't require a custom patched valgrind. +*/ +template<typename T> +inline void poison(const T* p, size_t n) + { +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_UNDEFINED(p, n * sizeof(T)); +#else + BOTAN_UNUSED(p); + BOTAN_UNUSED(n); +#endif + } + +template<typename T> +inline void unpoison(const T* p, size_t n) + { +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_DEFINED(p, n * sizeof(T)); +#else + BOTAN_UNUSED(p); + BOTAN_UNUSED(n); +#endif + } + +template<typename T> +inline void unpoison(T& p) + { +#if defined(BOTAN_HAS_VALGRIND) + VALGRIND_MAKE_MEM_DEFINED(&p, sizeof(T)); +#else + BOTAN_UNUSED(p); +#endif + } + +/* +* T should be an unsigned machine integer type +* Expand to a mask used for other operations +* @param in an integer +* @return If n is zero, returns zero. Otherwise +* returns a T with all bits set for use as a mask with +* select. +*/ +template<typename T> +inline T expand_mask(T x) + { + T r = x; + // First fold r down to a single bit + for(size_t i = 1; i != sizeof(T)*8; i *= 2) + { + r = r | static_cast<T>(r >> i); + } + r &= 1; + r = static_cast<T>(~(r - 1)); + return r; + } + +template<typename T> +inline T expand_top_bit(T a) + { + return expand_mask<T>(a >> (sizeof(T)*8-1)); + } + +template<typename T> +inline T select(T mask, T from0, T from1) + { + return static_cast<T>((from0 & mask) | (from1 & ~mask)); + } + +template<typename T> +inline T select2(T mask0, T val0, T mask1, T val1, T val2) + { + return select<T>(mask0, val0, select<T>(mask1, val1, val2)); + } + +template<typename T> +inline T select3(T mask0, T val0, T mask1, T val1, T mask2, T val2, T val3) + { + return select2<T>(mask0, val0, mask1, val1, select<T>(mask2, val2, val3)); + } + +template<typename PredT, typename ValT> +inline ValT val_or_zero(PredT pred_val, ValT val) + { + return select(CT::expand_mask<ValT>(pred_val), val, static_cast<ValT>(0)); + } + +template<typename T> +inline T is_zero(T x) + { + return static_cast<T>(~expand_mask(x)); + } + +template<typename T> +inline T is_equal(T x, T y) + { + return is_zero<T>(x ^ y); + } + +template<typename T> +inline T is_less(T a, T b) + { + return expand_top_bit<T>(a ^ ((a^b) | ((a-b)^a))); + } + +template<typename T> +inline T is_lte(T a, T b) + { + return CT::is_less(a, b) | CT::is_equal(a, b); + } + +template<typename T> +inline T conditional_copy_mem(T value, + T* to, + const T* from0, + const T* from1, + size_t elems) + { + const T mask = CT::expand_mask(value); + + for(size_t i = 0; i != elems; ++i) + { + to[i] = CT::select(mask, from0[i], from1[i]); + } + + return mask; + } + +template<typename T> +inline void cond_zero_mem(T cond, + T* array, + size_t elems) + { + const T mask = CT::expand_mask(cond); + const T zero(0); + + for(size_t i = 0; i != elems; ++i) + { + array[i] = CT::select(mask, zero, array[i]); + } + } + +inline secure_vector<uint8_t> strip_leading_zeros(const uint8_t in[], size_t length) + { + size_t leading_zeros = 0; + + uint8_t only_zeros = 0xFF; + + for(size_t i = 0; i != length; ++i) + { + only_zeros = only_zeros & CT::is_zero<uint8_t>(in[i]); + leading_zeros += CT::select<uint8_t>(only_zeros, 1, 0); + } + + return secure_vector<uint8_t>(in + leading_zeros, in + length); + } + +inline secure_vector<uint8_t> strip_leading_zeros(const secure_vector<uint8_t>& in) + { + return strip_leading_zeros(in.data(), in.size()); + } + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/data_src.cpp b/src/libs/3rdparty/botan/src/lib/utils/data_src.cpp new file mode 100644 index 0000000000..c5689534ff --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/data_src.cpp @@ -0,0 +1,214 @@ +/* +* DataSource +* (C) 1999-2007 Jack Lloyd +* 2005 Matthew Gregan +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/data_src.h> +#include <botan/exceptn.h> +#include <algorithm> +#include <istream> + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + #include <fstream> +#endif + +namespace Botan { + +/* +* Read a single byte from the DataSource +*/ +size_t DataSource::read_byte(uint8_t& out) + { + return read(&out, 1); + } + +/* +* Peek a single byte from the DataSource +*/ +size_t DataSource::peek_byte(uint8_t& out) const + { + return peek(&out, 1, 0); + } + +/* +* Discard the next N bytes of the data +*/ +size_t DataSource::discard_next(size_t n) + { + uint8_t buf[64] = { 0 }; + size_t discarded = 0; + + while(n) + { + const size_t got = this->read(buf, std::min(n, sizeof(buf))); + discarded += got; + n -= got; + + if(got == 0) + break; + } + + return discarded; + } + +/* +* Read from a memory buffer +*/ +size_t DataSource_Memory::read(uint8_t out[], size_t length) + { + const size_t got = std::min<size_t>(m_source.size() - m_offset, length); + copy_mem(out, m_source.data() + m_offset, got); + m_offset += got; + return got; + } + +bool DataSource_Memory::check_available(size_t n) + { + return (n <= (m_source.size() - m_offset)); + } + +/* +* Peek into a memory buffer +*/ +size_t DataSource_Memory::peek(uint8_t out[], size_t length, + size_t peek_offset) const + { + const size_t bytes_left = m_source.size() - m_offset; + if(peek_offset >= bytes_left) return 0; + + const size_t got = std::min(bytes_left - peek_offset, length); + copy_mem(out, &m_source[m_offset + peek_offset], got); + return got; + } + +/* +* Check if the memory buffer is empty +*/ +bool DataSource_Memory::end_of_data() const + { + return (m_offset == m_source.size()); + } + +/* +* DataSource_Memory Constructor +*/ +DataSource_Memory::DataSource_Memory(const std::string& in) : + m_source(cast_char_ptr_to_uint8(in.data()), + cast_char_ptr_to_uint8(in.data()) + in.length()), + m_offset(0) + { + } + +/* +* Read from a stream +*/ +size_t DataSource_Stream::read(uint8_t out[], size_t length) + { + m_source.read(cast_uint8_ptr_to_char(out), length); + if(m_source.bad()) + throw Stream_IO_Error("DataSource_Stream::read: Source failure"); + + const size_t got = static_cast<size_t>(m_source.gcount()); + m_total_read += got; + return got; + } + +bool DataSource_Stream::check_available(size_t n) + { + const std::streampos orig_pos = m_source.tellg(); + m_source.seekg(0, std::ios::end); + const size_t avail = static_cast<size_t>(m_source.tellg() - orig_pos); + m_source.seekg(orig_pos); + return (avail >= n); + } + +/* +* Peek into a stream +*/ +size_t DataSource_Stream::peek(uint8_t out[], size_t length, size_t offset) const + { + if(end_of_data()) + throw Invalid_State("DataSource_Stream: Cannot peek when out of data"); + + size_t got = 0; + + if(offset) + { + secure_vector<uint8_t> buf(offset); + m_source.read(cast_uint8_ptr_to_char(buf.data()), buf.size()); + if(m_source.bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + got = static_cast<size_t>(m_source.gcount()); + } + + if(got == offset) + { + m_source.read(cast_uint8_ptr_to_char(out), length); + if(m_source.bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + got = static_cast<size_t>(m_source.gcount()); + } + + if(m_source.eof()) + m_source.clear(); + m_source.seekg(m_total_read, std::ios::beg); + + return got; + } + +/* +* Check if the stream is empty or in error +*/ +bool DataSource_Stream::end_of_data() const + { + return (!m_source.good()); + } + +/* +* Return a human-readable ID for this stream +*/ +std::string DataSource_Stream::id() const + { + return m_identifier; + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + +/* +* DataSource_Stream Constructor +*/ +DataSource_Stream::DataSource_Stream(const std::string& path, + bool use_binary) : + m_identifier(path), + m_source_memory(new std::ifstream(path, use_binary ? std::ios::binary : std::ios::in)), + m_source(*m_source_memory), + m_total_read(0) + { + if(!m_source.good()) + { + throw Stream_IO_Error("DataSource: Failure opening file " + path); + } + } + +#endif + +/* +* DataSource_Stream Constructor +*/ +DataSource_Stream::DataSource_Stream(std::istream& in, + const std::string& name) : + m_identifier(name), + m_source(in), + m_total_read(0) + { + } + +DataSource_Stream::~DataSource_Stream() + { + // for ~unique_ptr + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/data_src.h b/src/libs/3rdparty/botan/src/lib/utils/data_src.h new file mode 100644 index 0000000000..09c1bffdf7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/data_src.h @@ -0,0 +1,181 @@ +/* +* DataSource +* (C) 1999-2007 Jack Lloyd +* 2012 Markus Wanner +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DATA_SRC_H_ +#define BOTAN_DATA_SRC_H_ + +#include <botan/secmem.h> +#include <string> +#include <iosfwd> + +namespace Botan { + +/** +* This class represents an abstract data source object. +*/ +class BOTAN_PUBLIC_API(2,0) DataSource + { + public: + /** + * Read from the source. Moves the internal offset so that every + * call to read will return a new portion of the source. + * + * @param out the byte array to write the result to + * @param length the length of the byte array out + * @return length in bytes that was actually read and put + * into out + */ + virtual size_t read(uint8_t out[], size_t length) BOTAN_WARN_UNUSED_RESULT = 0; + + virtual bool check_available(size_t n) = 0; + + /** + * Read from the source but do not modify the internal + * offset. Consecutive calls to peek() will return portions of + * the source starting at the same position. + * + * @param out the byte array to write the output to + * @param length the length of the byte array out + * @param peek_offset the offset into the stream to read at + * @return length in bytes that was actually read and put + * into out + */ + virtual size_t peek(uint8_t out[], size_t length, size_t peek_offset) const BOTAN_WARN_UNUSED_RESULT = 0; + + /** + * Test whether the source still has data that can be read. + * @return true if there is no more data to read, false otherwise + */ + virtual bool end_of_data() const = 0; + /** + * return the id of this data source + * @return std::string representing the id of this data source + */ + virtual std::string id() const { return ""; } + + /** + * Read one byte. + * @param out the byte to read to + * @return length in bytes that was actually read and put + * into out + */ + size_t read_byte(uint8_t& out); + + /** + * Peek at one byte. + * @param out an output byte + * @return length in bytes that was actually read and put + * into out + */ + size_t peek_byte(uint8_t& out) const; + + /** + * Discard the next N bytes of the data + * @param N the number of bytes to discard + * @return number of bytes actually discarded + */ + size_t discard_next(size_t N); + + /** + * @return number of bytes read so far. + */ + virtual size_t get_bytes_read() const = 0; + + DataSource() = default; + virtual ~DataSource() = default; + DataSource& operator=(const DataSource&) = delete; + DataSource(const DataSource&) = delete; + }; + +/** +* This class represents a Memory-Based DataSource +*/ +class BOTAN_PUBLIC_API(2,0) DataSource_Memory final : public DataSource + { + public: + size_t read(uint8_t[], size_t) override; + size_t peek(uint8_t[], size_t, size_t) const override; + bool check_available(size_t n) override; + bool end_of_data() const override; + + /** + * Construct a memory source that reads from a string + * @param in the string to read from + */ + explicit DataSource_Memory(const std::string& in); + + /** + * Construct a memory source that reads from a byte array + * @param in the byte array to read from + * @param length the length of the byte array + */ + DataSource_Memory(const uint8_t in[], size_t length) : + m_source(in, in + length), m_offset(0) {} + + /** + * Construct a memory source that reads from a secure_vector + * @param in the MemoryRegion to read from + */ + explicit DataSource_Memory(const secure_vector<uint8_t>& in) : + m_source(in), m_offset(0) {} + + /** + * Construct a memory source that reads from a std::vector + * @param in the MemoryRegion to read from + */ + explicit DataSource_Memory(const std::vector<uint8_t>& in) : + m_source(in.begin(), in.end()), m_offset(0) {} + + size_t get_bytes_read() const override { return m_offset; } + private: + secure_vector<uint8_t> m_source; + size_t m_offset; + }; + +/** +* This class represents a Stream-Based DataSource. +*/ +class BOTAN_PUBLIC_API(2,0) DataSource_Stream final : public DataSource + { + public: + size_t read(uint8_t[], size_t) override; + size_t peek(uint8_t[], size_t, size_t) const override; + bool check_available(size_t n) override; + bool end_of_data() const override; + std::string id() const override; + + DataSource_Stream(std::istream&, + const std::string& id = "<std::istream>"); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + /** + * Construct a Stream-Based DataSource from filesystem path + * @param file the path to the file + * @param use_binary whether to treat the file as binary or not + */ + DataSource_Stream(const std::string& file, bool use_binary = false); +#endif + + DataSource_Stream(const DataSource_Stream&) = delete; + + DataSource_Stream& operator=(const DataSource_Stream&) = delete; + + ~DataSource_Stream(); + + size_t get_bytes_read() const override { return m_total_read; } + private: + const std::string m_identifier; + + std::unique_ptr<std::istream> m_source_memory; + std::istream& m_source; + size_t m_total_read; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/database.h b/src/libs/3rdparty/botan/src/lib/utils/database.h new file mode 100644 index 0000000000..21a207445a --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/database.h @@ -0,0 +1,74 @@ +/* +* SQL database interface +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SQL_DATABASE_H_ +#define BOTAN_SQL_DATABASE_H_ + +#include <botan/types.h> +#include <botan/exceptn.h> +#include <string> +#include <chrono> +#include <vector> + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) SQL_Database + { + public: + + class BOTAN_PUBLIC_API(2,0) SQL_DB_Error final : public Exception + { + public: + explicit SQL_DB_Error(const std::string& what) : Exception("SQL database", what) {} + }; + + class BOTAN_PUBLIC_API(2,0) Statement + { + public: + /* Bind statement parameters */ + virtual void bind(int column, const std::string& str) = 0; + + virtual void bind(int column, size_t i) = 0; + + virtual void bind(int column, std::chrono::system_clock::time_point time) = 0; + + virtual void bind(int column, const std::vector<uint8_t>& blob) = 0; + + virtual void bind(int column, const uint8_t* data, size_t len) = 0; + + /* Get output */ + virtual std::pair<const uint8_t*, size_t> get_blob(int column) = 0; + + virtual std::string get_str(int column) = 0; + + virtual size_t get_size_t(int column) = 0; + + /* Run to completion */ + virtual size_t spin() = 0; + + /* Maybe update */ + virtual bool step() = 0; + + virtual ~Statement() = default; + }; + + /* + * Create a new statement for execution. + * Use ?1, ?2, ?3, etc for parameters to set later with bind + */ + virtual std::shared_ptr<Statement> new_statement(const std::string& base_sql) const = 0; + + virtual size_t row_count(const std::string& table_name) = 0; + + virtual void create_table(const std::string& table_schema) = 0; + + virtual ~SQL_Database() = default; +}; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/donna128.h b/src/libs/3rdparty/botan/src/lib/utils/donna128.h new file mode 100644 index 0000000000..ff571906d8 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/donna128.h @@ -0,0 +1,143 @@ +/* +* A minimal 128-bit integer type for curve25519-donna +* (C) 2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CURVE25519_DONNA128_H_ +#define BOTAN_CURVE25519_DONNA128_H_ + +#include <botan/mul128.h> + +namespace Botan { + +class donna128 final + { + public: + donna128(uint64_t ll = 0, uint64_t hh = 0) { l = ll; h = hh; } + + donna128(const donna128&) = default; + donna128& operator=(const donna128&) = default; + + friend donna128 operator>>(const donna128& x, size_t shift) + { + donna128 z = x; + if(shift > 0) + { + const uint64_t carry = z.h << (64 - shift); + z.h = (z.h >> shift); + z.l = (z.l >> shift) | carry; + } + return z; + } + + friend donna128 operator<<(const donna128& x, size_t shift) + { + donna128 z = x; + if(shift > 0) + { + const uint64_t carry = z.l >> (64 - shift); + z.l = (z.l << shift); + z.h = (z.h << shift) | carry; + } + return z; + } + + friend uint64_t operator&(const donna128& x, uint64_t mask) + { + return x.l & mask; + } + + uint64_t operator&=(uint64_t mask) + { + h = 0; + l &= mask; + return l; + } + + donna128& operator+=(const donna128& x) + { + l += x.l; + h += x.h; + + const uint64_t carry = (l < x.l); + h += carry; + return *this; + } + + donna128& operator+=(uint64_t x) + { + l += x; + const uint64_t carry = (l < x); + h += carry; + return *this; + } + + uint64_t lo() const { return l; } + uint64_t hi() const { return h; } + private: + uint64_t h = 0, l = 0; + }; + +inline donna128 operator*(const donna128& x, uint64_t y) + { + BOTAN_ARG_CHECK(x.hi() == 0, "High 64 bits of donna128 set to zero during multiply"); + + uint64_t lo = 0, hi = 0; + mul64x64_128(x.lo(), y, &lo, &hi); + return donna128(lo, hi); + } + +inline donna128 operator*(uint64_t y, const donna128& x) + { + return x * y; + } + +inline donna128 operator+(const donna128& x, const donna128& y) + { + donna128 z = x; + z += y; + return z; + } + +inline donna128 operator+(const donna128& x, uint64_t y) + { + donna128 z = x; + z += y; + return z; + } + +inline donna128 operator|(const donna128& x, const donna128& y) + { + return donna128(x.lo() | y.lo(), x.hi() | y.hi()); + } + +inline uint64_t carry_shift(const donna128& a, size_t shift) + { + return (a >> shift).lo(); + } + +inline uint64_t combine_lower(const donna128& a, size_t s1, + const donna128& b, size_t s2) + { + donna128 z = (a >> s1) | (b << s2); + return z.lo(); + } + +#if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) +inline uint64_t carry_shift(const uint128_t a, size_t shift) + { + return static_cast<uint64_t>(a >> shift); + } + +inline uint64_t combine_lower(const uint128_t a, size_t s1, + const uint128_t b, size_t s2) + { + return static_cast<uint64_t>((a >> s1) | (b << s2)); + } +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/dyn_load/dyn_load.cpp b/src/libs/3rdparty/botan/src/lib/utils/dyn_load/dyn_load.cpp new file mode 100644 index 0000000000..1bbcffbdb5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/dyn_load/dyn_load.cpp @@ -0,0 +1,79 @@ +/* +* Dynamically Loaded Object +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/dyn_load.h> +#include <botan/exceptn.h> + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + #include <dlfcn.h> +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + #define NOMINMAX 1 + #define _WINSOCKAPI_ // stop windows.h including winsock.h + #include <windows.h> +#endif + +namespace Botan { + +namespace { + +void raise_runtime_loader_exception(const std::string& lib_name, + const char* msg) + { + throw Exception("Failed to load " + lib_name + ": " + + (msg ? msg : "Unknown error")); + } + +} + +Dynamically_Loaded_Library::Dynamically_Loaded_Library( + const std::string& library) : + m_lib_name(library), m_lib(nullptr) + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + m_lib = ::dlopen(m_lib_name.c_str(), RTLD_LAZY); + + if(!m_lib) + raise_runtime_loader_exception(m_lib_name, ::dlerror()); + +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + m_lib = ::LoadLibraryA(m_lib_name.c_str()); + + if(!m_lib) + raise_runtime_loader_exception(m_lib_name, "LoadLibrary failed"); +#endif + + if(!m_lib) + raise_runtime_loader_exception(m_lib_name, "Dynamic load not supported"); + } + +Dynamically_Loaded_Library::~Dynamically_Loaded_Library() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + ::dlclose(m_lib); +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + ::FreeLibrary((HMODULE)m_lib); +#endif + } + +void* Dynamically_Loaded_Library::resolve_symbol(const std::string& symbol) + { + void* addr = nullptr; + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + addr = ::dlsym(m_lib, symbol.c_str()); +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + addr = reinterpret_cast<void*>(::GetProcAddress((HMODULE)m_lib, symbol.c_str())); +#endif + + if(!addr) + throw Exception("Failed to resolve symbol " + symbol + + " in " + m_lib_name); + + return addr; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/dyn_load/dyn_load.h b/src/libs/3rdparty/botan/src/lib/utils/dyn_load/dyn_load.h new file mode 100644 index 0000000000..3caf65f277 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/dyn_load/dyn_load.h @@ -0,0 +1,68 @@ +/* +* Dynamically Loaded Object +* (C) 2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DYNAMIC_LOADER_H_ +#define BOTAN_DYNAMIC_LOADER_H_ + +#include <botan/types.h> +#include <string> + +namespace Botan { + +/** +* Represents a DLL or shared object +*/ +class BOTAN_PUBLIC_API(2,0) Dynamically_Loaded_Library final + { + public: + /** + * Load a DLL (or fail with an exception) + * @param lib_name name or path to a library + * + * If you don't use a full path, the search order will be defined + * by whatever the system linker does by default. Always using fully + * qualified pathnames can help prevent code injection attacks (eg + * via manipulation of LD_LIBRARY_PATH on Linux) + */ + Dynamically_Loaded_Library(const std::string& lib_name); + + /** + * Unload the DLL + * @warning Any pointers returned by resolve()/resolve_symbol() + * should not be used after this destructor runs. + */ + ~Dynamically_Loaded_Library(); + + /** + * Load a symbol (or fail with an exception) + * @param symbol names the symbol to load + * @return address of the loaded symbol + */ + void* resolve_symbol(const std::string& symbol); + + /** + * Convenience function for casting symbol to the right type + * @param symbol names the symbol to load + * @return address of the loaded symbol + */ + template<typename T> + T resolve(const std::string& symbol) + { + return reinterpret_cast<T>(resolve_symbol(symbol)); + } + + private: + Dynamically_Loaded_Library(const Dynamically_Loaded_Library&); + Dynamically_Loaded_Library& operator=(const Dynamically_Loaded_Library&); + + std::string m_lib_name; + void* m_lib; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/dyn_load/info.txt b/src/libs/3rdparty/botan/src/lib/utils/dyn_load/info.txt new file mode 100644 index 0000000000..4dd4932a00 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/dyn_load/info.txt @@ -0,0 +1,17 @@ +<defines> +DYNAMIC_LOADER -> 20160310 +</defines> + +load_on dep + +<os_features> +posix1 +win32 +</os_features> + +<libs> +android -> dl +linux -> dl +solaris -> dl +darwin -> dl +</libs> diff --git a/src/libs/3rdparty/botan/src/lib/utils/exceptn.cpp b/src/libs/3rdparty/botan/src/lib/utils/exceptn.cpp new file mode 100644 index 0000000000..a72e45ba4c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/exceptn.cpp @@ -0,0 +1,105 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/exceptn.h> + +namespace Botan { + +Exception::Exception(const std::string& msg) : m_msg(msg) + {} + +Exception::Exception(const char* prefix, const std::string& msg) : + m_msg(std::string(prefix) + " " + msg) + {} + +Invalid_Argument::Invalid_Argument(const std::string& msg) : + Exception("Invalid argument", msg) + {} + +Invalid_Argument::Invalid_Argument(const std::string& msg, const std::string& where) : + Exception("Invalid argument", msg + " in " + where) + {} + +Lookup_Error::Lookup_Error(const std::string& type, + const std::string& algo, + const std::string& provider) : + Exception("Unavailable " + type + " " + algo + + (provider.empty() ? std::string("") : (" for provider " + provider))) + {} + +Internal_Error::Internal_Error(const std::string& err) : + Exception("Internal error: " + err) + {} + +Invalid_Key_Length::Invalid_Key_Length(const std::string& name, size_t length) : + Invalid_Argument(name + " cannot accept a key of length " + + std::to_string(length)) + {} + +Invalid_IV_Length::Invalid_IV_Length(const std::string& mode, size_t bad_len) : + Invalid_Argument("IV length " + std::to_string(bad_len) + + " is invalid for " + mode) + {} + +Key_Not_Set::Key_Not_Set(const std::string& algo) : + Invalid_State("Key not set in " + algo) + {} + +Policy_Violation::Policy_Violation(const std::string& err) : + Invalid_State("Policy violation: " + err) {} + +PRNG_Unseeded::PRNG_Unseeded(const std::string& algo) : + Invalid_State("PRNG not seeded: " + algo) + {} + +Algorithm_Not_Found::Algorithm_Not_Found(const std::string& name) : + Lookup_Error("Could not find any algorithm named \"" + name + "\"") + {} + +No_Provider_Found::No_Provider_Found(const std::string& name) : + Exception("Could not find any provider for algorithm named \"" + name + "\"") + {} + +Provider_Not_Found::Provider_Not_Found(const std::string& algo, const std::string& provider) : + Lookup_Error("Could not find provider '" + provider + "' for " + algo) + {} + +Invalid_Algorithm_Name::Invalid_Algorithm_Name(const std::string& name): + Invalid_Argument("Invalid algorithm name: " + name) + {} + +Encoding_Error::Encoding_Error(const std::string& name) : + Invalid_Argument("Encoding error: " + name) + {} + +Decoding_Error::Decoding_Error(const std::string& name) : + Invalid_Argument("Decoding error: " + name) + {} + +Decoding_Error::Decoding_Error(const std::string& name, const char* exception_message) : + Invalid_Argument("Decoding error: " + name + " failed with exception " + exception_message) {} + +Integrity_Failure::Integrity_Failure(const std::string& msg) : + Exception("Integrity failure: " + msg) + {} + +Invalid_OID::Invalid_OID(const std::string& oid) : + Decoding_Error("Invalid ASN.1 OID: " + oid) + {} + +Stream_IO_Error::Stream_IO_Error(const std::string& err) : + Exception("I/O error: " + err) + {} + +Self_Test_Failure::Self_Test_Failure(const std::string& err) : + Internal_Error("Self test failed: " + err) + {} + +Not_Implemented::Not_Implemented(const std::string& err) : + Exception("Not implemented", err) + {} + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/exceptn.h b/src/libs/3rdparty/botan/src/lib/utils/exceptn.h new file mode 100644 index 0000000000..f2896aa83b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/exceptn.h @@ -0,0 +1,230 @@ +/* +* Exceptions +* (C) 1999-2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_EXCEPTION_H_ +#define BOTAN_EXCEPTION_H_ + +#include <botan/types.h> +#include <exception> +#include <string> + +namespace Botan { + +/** +* Base class for all exceptions thrown by the library +*/ +class BOTAN_PUBLIC_API(2,0) Exception : public std::exception + { + public: + Exception(const char* prefix, const std::string& msg); + explicit Exception(const std::string& msg); + const char* what() const BOTAN_NOEXCEPT override { return m_msg.c_str(); } + private: + std::string m_msg; + }; + +/** +* An invalid argument +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_Argument : public Exception + { + public: + explicit Invalid_Argument(const std::string& msg); + + explicit Invalid_Argument(const std::string& msg, const std::string& where); +}; + +/** +* 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. +*/ +class BOTAN_PUBLIC_API(2,0) Unsupported_Argument final : public Invalid_Argument + { + public: + explicit Unsupported_Argument(const std::string& msg) : Invalid_Argument(msg) {} + }; + +/** +* Invalid_State Exception +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_State : public Exception + { + public: + explicit Invalid_State(const std::string& err) : Exception(err) {} + }; + +class BOTAN_PUBLIC_API(2,4) Key_Not_Set : public Invalid_State + { + public: + explicit Key_Not_Set(const std::string& algo); + }; + +/** +* Lookup_Error Exception +*/ +class BOTAN_PUBLIC_API(2,0) Lookup_Error : public Exception + { + public: + explicit Lookup_Error(const std::string& err) : Exception(err) {} + + Lookup_Error(const std::string& type, + const std::string& algo, + const std::string& provider); + }; + +/** +* Internal_Error Exception +*/ +class BOTAN_PUBLIC_API(2,0) Internal_Error : public Exception + { + public: + explicit Internal_Error(const std::string& err); + }; + +/** +* Invalid_Key_Length Exception +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_Key_Length final : public Invalid_Argument + { + public: + Invalid_Key_Length(const std::string& name, size_t length); + }; + +/** +* Invalid_IV_Length Exception +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_IV_Length final : public Invalid_Argument + { + public: + Invalid_IV_Length(const std::string& mode, size_t bad_len); + }; + +/** +* PRNG_Unseeded Exception +*/ +class BOTAN_PUBLIC_API(2,0) PRNG_Unseeded final : public Invalid_State + { + public: + explicit PRNG_Unseeded(const std::string& algo); + }; + +/** +* Policy_Violation Exception +*/ +class BOTAN_PUBLIC_API(2,0) Policy_Violation final : public Invalid_State + { + public: + BOTAN_DEPRECATED("deprecated") explicit Policy_Violation(const std::string& err); + }; + +/** +* Algorithm_Not_Found Exception +*/ +class BOTAN_PUBLIC_API(2,0) Algorithm_Not_Found final : public Lookup_Error + { + public: + explicit Algorithm_Not_Found(const std::string& name); + }; + +/** +* No_Provider_Found Exception +*/ +class BOTAN_PUBLIC_API(2,0) No_Provider_Found final : public Exception + { + public: + BOTAN_DEPRECATED("deprecated") explicit No_Provider_Found(const std::string& name); + }; + +/** +* Provider_Not_Found is thrown when a specific provider was requested +* but that provider is not available. +*/ +class BOTAN_PUBLIC_API(2,0) Provider_Not_Found final : public Lookup_Error + { + public: + Provider_Not_Found(const std::string& algo, const std::string& provider); + }; + +/** +* Invalid_Algorithm_Name Exception +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_Algorithm_Name final : public Invalid_Argument + { + public: + explicit Invalid_Algorithm_Name(const std::string& name); + }; + +/** +* Encoding_Error Exception +*/ +class BOTAN_PUBLIC_API(2,0) Encoding_Error final : public Invalid_Argument + { + public: + explicit Encoding_Error(const std::string& name); + }; + +/** +* Decoding_Error Exception +*/ +class BOTAN_PUBLIC_API(2,0) Decoding_Error : public Invalid_Argument + { + public: + explicit Decoding_Error(const std::string& name); + + Decoding_Error(const std::string& name, const char* exception_message); + }; + +/** +* Integrity_Failure Exception +*/ +class BOTAN_PUBLIC_API(2,0) Integrity_Failure final : public Exception + { + public: + explicit Integrity_Failure(const std::string& msg); + }; + +/** +* Invalid_OID Exception +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_OID final : public Decoding_Error + { + public: + explicit Invalid_OID(const std::string& oid); + }; + +/** +* Stream_IO_Error Exception +*/ +class BOTAN_PUBLIC_API(2,0) Stream_IO_Error final : public Exception + { + public: + explicit Stream_IO_Error(const std::string& err); + }; + +/** +* Self Test Failure Exception +*/ +class BOTAN_PUBLIC_API(2,0) Self_Test_Failure final : public Internal_Error + { + public: + BOTAN_DEPRECATED("deprecated") explicit Self_Test_Failure(const std::string& err); + }; + +/** +* Not Implemented Exception +*/ +class BOTAN_PUBLIC_API(2,0) Not_Implemented final : public Exception + { + public: + explicit Not_Implemented(const std::string& err); + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/filesystem.cpp b/src/libs/3rdparty/botan/src/lib/utils/filesystem.cpp new file mode 100644 index 0000000000..053c91e701 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/filesystem.cpp @@ -0,0 +1,204 @@ +/* +* (C) 2015,2017 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/exceptn.h> +#include <botan/internal/filesystem.h> +#include <algorithm> + +#if defined(BOTAN_TARGET_OS_HAS_STL_FILESYSTEM_MSVC) && defined(BOTAN_BUILD_COMPILER_IS_MSVC) + #include <filesystem> +#elif defined(BOTAN_HAS_BOOST_FILESYSTEM) + #include <boost/filesystem.hpp> +#elif defined(BOTAN_TARGET_OS_HAS_POSIX1) + #include <sys/types.h> + #include <sys/stat.h> + #include <dirent.h> + #include <deque> + #include <memory> + #include <functional> +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + #define NOMINMAX 1 + #define _WINSOCKAPI_ // stop windows.h including winsock.h + #include <windows.h> + #include <deque> + #include <memory> +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_TARGET_OS_HAS_STL_FILESYSTEM_MSVC) && defined(BOTAN_BUILD_COMPILER_IS_MSVC) +std::vector<std::string> impl_stl_filesystem(const std::string& dir) + { +#if (_MSVC_LANG >= 201703L) + using namespace std::filesystem; +#else + using namespace std::tr2::sys; +#endif + + std::vector<std::string> out; + + path p(dir); + + if(is_directory(p)) + { + for(recursive_directory_iterator itr(p), end; itr != end; ++itr) + { + if(is_regular_file(itr->path())) + { + out.push_back(itr->path().string()); + } + } + } + + return out; + } + +#elif defined(BOTAN_HAS_BOOST_FILESYSTEM) + +std::vector<std::string> impl_boost_filesystem(const std::string& dir_path) +{ + namespace fs = boost::filesystem; + + std::vector<std::string> out; + + for(fs::recursive_directory_iterator dir(dir_path), end; dir != end; ++dir) + { + if(fs::is_regular_file(dir->path())) + { + out.push_back(dir->path().string()); + } + } + + return out; +} + +#elif defined(BOTAN_TARGET_OS_HAS_POSIX1) + +std::vector<std::string> impl_readdir(const std::string& dir_path) + { + std::vector<std::string> out; + std::deque<std::string> dir_list; + dir_list.push_back(dir_path); + + while(!dir_list.empty()) + { + const std::string cur_path = dir_list[0]; + dir_list.pop_front(); + + std::unique_ptr<DIR, std::function<int (DIR*)>> dir(::opendir(cur_path.c_str()), ::closedir); + + if(dir) + { + while(struct dirent* dirent = ::readdir(dir.get())) + { + const std::string filename = dirent->d_name; + if(filename == "." || filename == "..") + continue; + const std::string full_path = cur_path + "/" + filename; + + struct stat stat_buf; + + if(::stat(full_path.c_str(), &stat_buf) == -1) + continue; + + if(S_ISDIR(stat_buf.st_mode)) + dir_list.push_back(full_path); + else if(S_ISREG(stat_buf.st_mode)) + out.push_back(full_path); + } + } + } + + return out; + } + +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + +std::vector<std::string> impl_win32(const std::string& dir_path) + { + std::vector<std::string> out; + std::deque<std::string> dir_list; + dir_list.push_back(dir_path); + + while(!dir_list.empty()) + { + const std::string cur_path = dir_list[0]; + dir_list.pop_front(); + + WIN32_FIND_DATAA find_data; + HANDLE dir = ::FindFirstFileA((cur_path + "/*").c_str(), &find_data); + + if(dir != INVALID_HANDLE_VALUE) + { + do + { + const std::string filename = find_data.cFileName; + if(filename == "." || filename == "..") + continue; + const std::string full_path = cur_path + "/" + filename; + + if(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + dir_list.push_back(full_path); + } + else + { + out.push_back(full_path); + } + } + while(::FindNextFileA(dir, &find_data)); + } + + ::FindClose(dir); + } + + return out; +} +#endif + +} + +bool has_filesystem_impl() + { +#if defined(BOTAN_TARGET_OS_HAS_STL_FILESYSTEM_MSVC) && defined(BOTAN_BUILD_COMPILER_IS_MSVC) + return true; +#elif defined(BOTAN_HAS_BOOST_FILESYSTEM) + return true; +#elif defined(BOTAN_TARGET_OS_HAS_POSIX1) + return true; +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + return true; +#else + return false; +#endif + } + +std::vector<std::string> get_files_recursive(const std::string& dir) + { + std::vector<std::string> files; + +#if defined(BOTAN_TARGET_OS_HAS_STL_FILESYSTEM_MSVC) && defined(BOTAN_BUILD_COMPILER_IS_MSVC) + files = impl_stl_filesystem(dir); +#elif defined(BOTAN_HAS_BOOST_FILESYSTEM) + files = impl_boost_filesystem(dir); +#elif defined(BOTAN_TARGET_OS_HAS_POSIX1) + files = impl_readdir(dir); +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + files = impl_win32(dir); +#else + BOTAN_UNUSED(dir); + throw No_Filesystem_Access(); +#endif + + std::sort(files.begin(), files.end()); + + return files; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/filesystem.h b/src/libs/3rdparty/botan/src/lib/utils/filesystem.h new file mode 100644 index 0000000000..382da7de34 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/filesystem.h @@ -0,0 +1,33 @@ +/* +* (C) 2015 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTIL_FILESYSTEM_H_ +#define BOTAN_UTIL_FILESYSTEM_H_ + +#include <botan/types.h> +#include <vector> +#include <string> + +namespace Botan { + +/** +* No_Filesystem_Access Exception +*/ +class BOTAN_PUBLIC_API(2,0) No_Filesystem_Access final : public Exception + { + public: + No_Filesystem_Access() : Exception("No filesystem access enabled.") + {} + }; + +BOTAN_TEST_API bool has_filesystem_impl(); + +BOTAN_TEST_API std::vector<std::string> get_files_recursive(const std::string& dir); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/info.txt b/src/libs/3rdparty/botan/src/lib/utils/info.txt new file mode 100644 index 0000000000..fb9325f932 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/info.txt @@ -0,0 +1,42 @@ +<defines> +UTIL_FUNCTIONS -> 20171003 +</defines> + +load_on always + +<header:public> +assert.h +bswap.h +calendar.h +charset.h +compiler.h +data_src.h +database.h +exceptn.h +loadstor.h +mem_ops.h +mul128.h +mutex.h +parsing.h +rotate.h +types.h +version.h +stl_compatibility.h +</header:public> + +<header:internal> +bit_ops.h +codec_base.h +ct_utils.h +donna128.h +filesystem.h +os_utils.h +prefetch.h +rounding.h +safeint.h +stl_util.h +</header:internal> + +<requires> +cpuid +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/utils/loadstor.h b/src/libs/3rdparty/botan/src/lib/utils/loadstor.h new file mode 100644 index 0000000000..70ad20591c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/loadstor.h @@ -0,0 +1,697 @@ +/* +* Load/Store Operators +* (C) 1999-2007,2015,2017 Jack Lloyd +* 2007 Yves Jerschow +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_LOAD_STORE_H_ +#define BOTAN_LOAD_STORE_H_ + +#include <botan/types.h> +#include <botan/bswap.h> +#include <botan/mem_ops.h> +#include <vector> + +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + #define BOTAN_ENDIAN_N2L(x) reverse_bytes(x) + #define BOTAN_ENDIAN_L2N(x) reverse_bytes(x) + #define BOTAN_ENDIAN_N2B(x) (x) + #define BOTAN_ENDIAN_B2N(x) (x) + +#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + #define BOTAN_ENDIAN_N2L(x) (x) + #define BOTAN_ENDIAN_L2N(x) (x) + #define BOTAN_ENDIAN_N2B(x) reverse_bytes(x) + #define BOTAN_ENDIAN_B2N(x) reverse_bytes(x) + +#endif + +namespace Botan { + +/** +* Byte extraction +* @param byte_num which byte to extract, 0 == highest byte +* @param input the value to extract from +* @return byte byte_num of input +*/ +template<typename T> inline uint8_t get_byte(size_t byte_num, T input) + { + return static_cast<uint8_t>( + input >> (((~byte_num)&(sizeof(T)-1)) << 3) + ); + } + +/** +* Make a uint16_t from two bytes +* @param i0 the first byte +* @param i1 the second byte +* @return i0 || i1 +*/ +inline uint16_t make_uint16(uint8_t i0, uint8_t i1) + { + return static_cast<uint16_t>((static_cast<uint16_t>(i0) << 8) | i1); + } + +/** +* Make a uint32_t from four bytes +* @param i0 the first byte +* @param i1 the second byte +* @param i2 the third byte +* @param i3 the fourth byte +* @return i0 || i1 || i2 || i3 +*/ +inline uint32_t make_uint32(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3) + { + return ((static_cast<uint32_t>(i0) << 24) | + (static_cast<uint32_t>(i1) << 16) | + (static_cast<uint32_t>(i2) << 8) | + (static_cast<uint32_t>(i3))); + } + +/** +* Make a uint32_t from eight bytes +* @param i0 the first byte +* @param i1 the second byte +* @param i2 the third byte +* @param i3 the fourth byte +* @param i4 the fifth byte +* @param i5 the sixth byte +* @param i6 the seventh byte +* @param i7 the eighth byte +* @return i0 || i1 || i2 || i3 || i4 || i5 || i6 || i7 +*/ +inline uint64_t make_uint64(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3, + uint8_t i4, uint8_t i5, uint8_t i6, uint8_t i7) + { + return ((static_cast<uint64_t>(i0) << 56) | + (static_cast<uint64_t>(i1) << 48) | + (static_cast<uint64_t>(i2) << 40) | + (static_cast<uint64_t>(i3) << 32) | + (static_cast<uint64_t>(i4) << 24) | + (static_cast<uint64_t>(i5) << 16) | + (static_cast<uint64_t>(i6) << 8) | + (static_cast<uint64_t>(i7))); + } + +/** +* Load a big-endian word +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th T of in, as a big-endian value +*/ +template<typename T> +inline T load_be(const uint8_t in[], size_t off) + { + in += off * sizeof(T); + T out = 0; + for(size_t i = 0; i != sizeof(T); ++i) + out = static_cast<T>((out << 8) | in[i]); + return out; + } + +/** +* Load a little-endian word +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th T of in, as a litte-endian value +*/ +template<typename T> +inline T load_le(const uint8_t in[], size_t off) + { + in += off * sizeof(T); + T out = 0; + for(size_t i = 0; i != sizeof(T); ++i) + out = (out << 8) | in[sizeof(T)-1-i]; + return out; + } + +/** +* Load a big-endian uint16_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint16_t of in, as a big-endian value +*/ +template<> +inline uint16_t load_be<uint16_t>(const uint8_t in[], size_t off) + { + in += off * sizeof(uint16_t); + +#if defined(BOTAN_ENDIAN_N2B) + uint16_t x; + std::memcpy(&x, in, sizeof(x)); + return BOTAN_ENDIAN_N2B(x); +#else + return make_uint16(in[0], in[1]); +#endif + } + +/** +* Load a little-endian uint16_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint16_t of in, as a little-endian value +*/ +template<> +inline uint16_t load_le<uint16_t>(const uint8_t in[], size_t off) + { + in += off * sizeof(uint16_t); + +#if defined(BOTAN_ENDIAN_N2L) + uint16_t x; + std::memcpy(&x, in, sizeof(x)); + return BOTAN_ENDIAN_N2L(x); +#else + return make_uint16(in[1], in[0]); +#endif + } + +/** +* Load a big-endian uint32_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint32_t of in, as a big-endian value +*/ +template<> +inline uint32_t load_be<uint32_t>(const uint8_t in[], size_t off) + { + in += off * sizeof(uint32_t); +#if defined(BOTAN_ENDIAN_N2B) + uint32_t x; + std::memcpy(&x, in, sizeof(x)); + return BOTAN_ENDIAN_N2B(x); +#else + return make_uint32(in[0], in[1], in[2], in[3]); +#endif + } + +/** +* Load a little-endian uint32_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint32_t of in, as a little-endian value +*/ +template<> +inline uint32_t load_le<uint32_t>(const uint8_t in[], size_t off) + { + in += off * sizeof(uint32_t); +#if defined(BOTAN_ENDIAN_N2L) + uint32_t x; + std::memcpy(&x, in, sizeof(x)); + return BOTAN_ENDIAN_N2L(x); +#else + return make_uint32(in[3], in[2], in[1], in[0]); +#endif + } + +/** +* Load a big-endian uint64_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint64_t of in, as a big-endian value +*/ +template<> +inline uint64_t load_be<uint64_t>(const uint8_t in[], size_t off) + { + in += off * sizeof(uint64_t); +#if defined(BOTAN_ENDIAN_N2B) + uint64_t x; + std::memcpy(&x, in, sizeof(x)); + return BOTAN_ENDIAN_N2B(x); +#else + return make_uint64(in[0], in[1], in[2], in[3], + in[4], in[5], in[6], in[7]); +#endif + } + +/** +* Load a little-endian uint64_t +* @param in a pointer to some bytes +* @param off an offset into the array +* @return off'th uint64_t of in, as a little-endian value +*/ +template<> +inline uint64_t load_le<uint64_t>(const uint8_t in[], size_t off) + { + in += off * sizeof(uint64_t); +#if defined(BOTAN_ENDIAN_N2L) + uint64_t x; + std::memcpy(&x, in, sizeof(x)); + return BOTAN_ENDIAN_N2L(x); +#else + return make_uint64(in[7], in[6], in[5], in[4], + in[3], in[2], in[1], in[0]); +#endif + } + +/** +* Load two little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +*/ +template<typename T> +inline void load_le(const uint8_t in[], T& x0, T& x1) + { + x0 = load_le<T>(in, 0); + x1 = load_le<T>(in, 1); + } + +/** +* Load four little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +*/ +template<typename T> +inline void load_le(const uint8_t in[], + T& x0, T& x1, T& x2, T& x3) + { + x0 = load_le<T>(in, 0); + x1 = load_le<T>(in, 1); + x2 = load_le<T>(in, 2); + x3 = load_le<T>(in, 3); + } + +/** +* Load eight little-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +* @param x4 where the fifth word will be written +* @param x5 where the sixth word will be written +* @param x6 where the seventh word will be written +* @param x7 where the eighth word will be written +*/ +template<typename T> +inline void load_le(const uint8_t in[], + T& x0, T& x1, T& x2, T& x3, + T& x4, T& x5, T& x6, T& x7) + { + x0 = load_le<T>(in, 0); + x1 = load_le<T>(in, 1); + x2 = load_le<T>(in, 2); + x3 = load_le<T>(in, 3); + x4 = load_le<T>(in, 4); + x5 = load_le<T>(in, 5); + x6 = load_le<T>(in, 6); + x7 = load_le<T>(in, 7); + } + +/** +* Load a variable number of little-endian words +* @param out the output array of words +* @param in the input array of bytes +* @param count how many words are in in +*/ +template<typename T> +inline void load_le(T out[], + const uint8_t in[], + size_t count) + { + if(count > 0) + { +#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + std::memcpy(out, in, sizeof(T)*count); +#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + std::memcpy(out, in, sizeof(T)*count); + const size_t blocks = count - (count % 4); + const size_t left = count - blocks; + + for(size_t i = 0; i != blocks; i += 4) + bswap_4(out + i); + + for(size_t i = 0; i != left; ++i) + out[blocks+i] = reverse_bytes(out[blocks+i]); +#else + for(size_t i = 0; i != count; ++i) + out[i] = load_le<T>(in, i); +#endif + } + } + +/** +* Load two big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +*/ +template<typename T> +inline void load_be(const uint8_t in[], T& x0, T& x1) + { + x0 = load_be<T>(in, 0); + x1 = load_be<T>(in, 1); + } + +/** +* Load four big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +*/ +template<typename T> +inline void load_be(const uint8_t in[], + T& x0, T& x1, T& x2, T& x3) + { + x0 = load_be<T>(in, 0); + x1 = load_be<T>(in, 1); + x2 = load_be<T>(in, 2); + x3 = load_be<T>(in, 3); + } + +/** +* Load eight big-endian words +* @param in a pointer to some bytes +* @param x0 where the first word will be written +* @param x1 where the second word will be written +* @param x2 where the third word will be written +* @param x3 where the fourth word will be written +* @param x4 where the fifth word will be written +* @param x5 where the sixth word will be written +* @param x6 where the seventh word will be written +* @param x7 where the eighth word will be written +*/ +template<typename T> +inline void load_be(const uint8_t in[], + T& x0, T& x1, T& x2, T& x3, + T& x4, T& x5, T& x6, T& x7) + { + x0 = load_be<T>(in, 0); + x1 = load_be<T>(in, 1); + x2 = load_be<T>(in, 2); + x3 = load_be<T>(in, 3); + x4 = load_be<T>(in, 4); + x5 = load_be<T>(in, 5); + x6 = load_be<T>(in, 6); + x7 = load_be<T>(in, 7); + } + +/** +* Load a variable number of big-endian words +* @param out the output array of words +* @param in the input array of bytes +* @param count how many words are in in +*/ +template<typename T> +inline void load_be(T out[], + const uint8_t in[], + size_t count) + { + if(count > 0) + { +#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) + std::memcpy(out, in, sizeof(T)*count); + +#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN) + std::memcpy(out, in, sizeof(T)*count); + const size_t blocks = count - (count % 4); + const size_t left = count - blocks; + + for(size_t i = 0; i != blocks; i += 4) + bswap_4(out + i); + + for(size_t i = 0; i != left; ++i) + out[blocks+i] = reverse_bytes(out[blocks+i]); +#else + for(size_t i = 0; i != count; ++i) + out[i] = load_be<T>(in, i); +#endif + } + } + +/** +* Store a big-endian uint16_t +* @param in the input uint16_t +* @param out the byte array to write to +*/ +inline void store_be(uint16_t in, uint8_t out[2]) + { +#if defined(BOTAN_ENDIAN_N2B) + uint16_t o = BOTAN_ENDIAN_N2B(in); + std::memcpy(out, &o, sizeof(o)); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); +#endif + } + +/** +* Store a little-endian uint16_t +* @param in the input uint16_t +* @param out the byte array to write to +*/ +inline void store_le(uint16_t in, uint8_t out[2]) + { +#if defined(BOTAN_ENDIAN_N2L) + uint16_t o = BOTAN_ENDIAN_N2L(in); + std::memcpy(out, &o, sizeof(o)); +#else + out[0] = get_byte(1, in); + out[1] = get_byte(0, in); +#endif + } + +/** +* Store a big-endian uint32_t +* @param in the input uint32_t +* @param out the byte array to write to +*/ +inline void store_be(uint32_t in, uint8_t out[4]) + { +#if defined(BOTAN_ENDIAN_B2N) + uint32_t o = BOTAN_ENDIAN_B2N(in); + std::memcpy(out, &o, sizeof(o)); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); + out[2] = get_byte(2, in); + out[3] = get_byte(3, in); +#endif + } + +/** +* Store a little-endian uint32_t +* @param in the input uint32_t +* @param out the byte array to write to +*/ +inline void store_le(uint32_t in, uint8_t out[4]) + { +#if defined(BOTAN_ENDIAN_L2N) + uint32_t o = BOTAN_ENDIAN_L2N(in); + std::memcpy(out, &o, sizeof(o)); +#else + out[0] = get_byte(3, in); + out[1] = get_byte(2, in); + out[2] = get_byte(1, in); + out[3] = get_byte(0, in); +#endif + } + +/** +* Store a big-endian uint64_t +* @param in the input uint64_t +* @param out the byte array to write to +*/ +inline void store_be(uint64_t in, uint8_t out[8]) + { +#if defined(BOTAN_ENDIAN_B2N) + uint64_t o = BOTAN_ENDIAN_B2N(in); + std::memcpy(out, &o, sizeof(o)); +#else + out[0] = get_byte(0, in); + out[1] = get_byte(1, in); + out[2] = get_byte(2, in); + out[3] = get_byte(3, in); + out[4] = get_byte(4, in); + out[5] = get_byte(5, in); + out[6] = get_byte(6, in); + out[7] = get_byte(7, in); +#endif + } + +/** +* Store a little-endian uint64_t +* @param in the input uint64_t +* @param out the byte array to write to +*/ +inline void store_le(uint64_t in, uint8_t out[8]) + { +#if defined(BOTAN_ENDIAN_L2N) + uint64_t o = BOTAN_ENDIAN_L2N(in); + std::memcpy(out, &o, sizeof(o)); +#else + out[0] = get_byte(7, in); + out[1] = get_byte(6, in); + out[2] = get_byte(5, in); + out[3] = get_byte(4, in); + out[4] = get_byte(3, in); + out[5] = get_byte(2, in); + out[6] = get_byte(1, in); + out[7] = get_byte(0, in); +#endif + } + +/** +* Store two little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +*/ +template<typename T> +inline void store_le(uint8_t out[], T x0, T x1) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + } + +/** +* Store two big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +*/ +template<typename T> +inline void store_be(uint8_t out[], T x0, T x1) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + } + +/** +* Store four little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +*/ +template<typename T> +inline void store_le(uint8_t out[], T x0, T x1, T x2, T x3) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + store_le(x2, out + (2 * sizeof(T))); + store_le(x3, out + (3 * sizeof(T))); + } + +/** +* Store four big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +*/ +template<typename T> +inline void store_be(uint8_t out[], T x0, T x1, T x2, T x3) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + store_be(x2, out + (2 * sizeof(T))); + store_be(x3, out + (3 * sizeof(T))); + } + +/** +* Store eight little-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +* @param x4 the fifth word +* @param x5 the sixth word +* @param x6 the seventh word +* @param x7 the eighth word +*/ +template<typename T> +inline void store_le(uint8_t out[], T x0, T x1, T x2, T x3, + T x4, T x5, T x6, T x7) + { + store_le(x0, out + (0 * sizeof(T))); + store_le(x1, out + (1 * sizeof(T))); + store_le(x2, out + (2 * sizeof(T))); + store_le(x3, out + (3 * sizeof(T))); + store_le(x4, out + (4 * sizeof(T))); + store_le(x5, out + (5 * sizeof(T))); + store_le(x6, out + (6 * sizeof(T))); + store_le(x7, out + (7 * sizeof(T))); + } + +/** +* Store eight big-endian words +* @param out the output byte array +* @param x0 the first word +* @param x1 the second word +* @param x2 the third word +* @param x3 the fourth word +* @param x4 the fifth word +* @param x5 the sixth word +* @param x6 the seventh word +* @param x7 the eighth word +*/ +template<typename T> +inline void store_be(uint8_t out[], T x0, T x1, T x2, T x3, + T x4, T x5, T x6, T x7) + { + store_be(x0, out + (0 * sizeof(T))); + store_be(x1, out + (1 * sizeof(T))); + store_be(x2, out + (2 * sizeof(T))); + store_be(x3, out + (3 * sizeof(T))); + store_be(x4, out + (4 * sizeof(T))); + store_be(x5, out + (5 * sizeof(T))); + store_be(x6, out + (6 * sizeof(T))); + store_be(x7, out + (7 * sizeof(T))); + } + +template<typename T> +void copy_out_be(uint8_t out[], size_t out_bytes, const T in[]) + { + while(out_bytes >= sizeof(T)) + { + store_be(in[0], out); + out += sizeof(T); + out_bytes -= sizeof(T); + in += 1; + } + + for(size_t i = 0; i != out_bytes; ++i) + out[i] = get_byte(i%8, in[0]); + } + +template<typename T, typename Alloc> +void copy_out_vec_be(uint8_t out[], size_t out_bytes, const std::vector<T, Alloc>& in) + { + copy_out_be(out, out_bytes, in.data()); + } + +template<typename T> +void copy_out_le(uint8_t out[], size_t out_bytes, const T in[]) + { + while(out_bytes >= sizeof(T)) + { + store_le(in[0], out); + out += sizeof(T); + out_bytes -= sizeof(T); + in += 1; + } + + for(size_t i = 0; i != out_bytes; ++i) + out[i] = get_byte(sizeof(T) - 1 - (i % 8), in[0]); + } + +template<typename T, typename Alloc> +void copy_out_vec_le(uint8_t out[], size_t out_bytes, const std::vector<T, Alloc>& in) + { + copy_out_le(out, out_bytes, in.data()); + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/mem_ops.cpp b/src/libs/3rdparty/botan/src/lib/utils/mem_ops.cpp new file mode 100644 index 0000000000..b7ecd53260 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/mem_ops.cpp @@ -0,0 +1,63 @@ +/* +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/mem_ops.h> +#include <cstdlib> + +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + #include <botan/locking_allocator.h> +#endif + +namespace Botan { + +BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size) + { +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + if(void* p = mlock_allocator::instance().allocate(elems, elem_size)) + return p; +#endif + + void* ptr = std::calloc(elems, elem_size); + if(!ptr) + throw std::bad_alloc(); + return ptr; + } + +void deallocate_memory(void* p, size_t elems, size_t elem_size) + { + if(p == nullptr) + return; + + secure_scrub_memory(p, elems * elem_size); + +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + if(mlock_allocator::instance().deallocate(p, elems, elem_size)) + return; +#endif + + std::free(p); + } + +void initialize_allocator() + { +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + mlock_allocator::instance(); +#endif + } + +bool constant_time_compare(const uint8_t x[], + const uint8_t y[], + size_t len) + { + volatile uint8_t difference = 0; + + for(size_t i = 0; i != len; ++i) + difference |= (x[i] ^ y[i]); + + return difference == 0; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/mem_ops.h b/src/libs/3rdparty/botan/src/lib/utils/mem_ops.h new file mode 100644 index 0000000000..c59c02d5a5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/mem_ops.h @@ -0,0 +1,272 @@ +/* +* Memory Operations +* (C) 1999-2009,2012,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MEMORY_OPS_H_ +#define BOTAN_MEMORY_OPS_H_ + +#include <botan/types.h> +#include <cstring> +#include <vector> + +namespace Botan { + +/** +* Allocate a memory buffer by some method. This should only be used for +* primitive types (uint8_t, uint32_t, etc). +* +* @param elems the number of elements +* @param elem_size the size of each element +* @return pointer to allocated and zeroed memory, or throw std::bad_alloc on failure +*/ +BOTAN_PUBLIC_API(2,3) BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size); + +/** +* Free a pointer returned by allocate_memory +* @param p the pointer returned by allocate_memory +* @param elems the number of elements, as passed to allocate_memory +* @param elem_size the size of each element, as passed to allocate_memory +*/ +BOTAN_PUBLIC_API(2,3) void deallocate_memory(void* p, size_t elems, size_t elem_size); + +/** +* Ensure the allocator is initialized +*/ +void initialize_allocator(); + +class Allocator_Initializer + { + public: + Allocator_Initializer() { initialize_allocator(); } + }; + +/** +* Scrub memory contents in a way that a compiler should not elide, +* using some system specific technique. Note that this function might +* not zero the memory (for example, in some hypothetical +* implementation it might combine the memory contents with the output +* of a system PRNG), but if you can detect any difference in behavior +* at runtime then the clearing is side-effecting and you can just +* use `clear_mem`. +* +* Use this function to scrub memory just before deallocating it, or on +* a stack buffer before returning from the function. +* +* @param ptr a pointer to memory to scrub +* @param n the number of bytes pointed to by ptr +*/ +BOTAN_PUBLIC_API(2,0) void secure_scrub_memory(void* ptr, size_t n); + +/** +* Memory comparison, input insensitive +* @param x a pointer to an array +* @param y a pointer to another array +* @param len the number of Ts in x and y +* @return true iff x[i] == y[i] forall i in [0...n) +*/ +BOTAN_PUBLIC_API(2,3) bool constant_time_compare(const uint8_t x[], + const uint8_t y[], + size_t len); + +/** +* Zero out some bytes +* @param ptr a pointer to memory to zero +* @param bytes the number of bytes to zero in ptr +*/ +inline void clear_bytes(void* ptr, size_t bytes) + { + if(bytes > 0) + { + std::memset(ptr, 0, bytes); + } + } + +/** +* Zero memory before use. This simply calls memset and should not be +* used in cases where the compiler cannot see the call as a +* side-effecting operation (for example, if calling clear_mem before +* deallocating memory, the compiler would be allowed to omit the call +* to memset entirely under the as-if rule.) +* +* @param ptr a pointer to an array of Ts to zero +* @param n the number of Ts pointed to by ptr +*/ +template<typename T> inline void clear_mem(T* ptr, size_t n) + { + clear_bytes(ptr, sizeof(T)*n); + } + +/** +* Copy memory +* @param out the destination array +* @param in the source array +* @param n the number of elements of in/out +*/ +template<typename T> inline void copy_mem(T* out, const T* in, size_t n) + { + if(n > 0) + { + std::memmove(out, in, sizeof(T)*n); + } + } + +/** +* Set memory to a fixed value +* @param ptr a pointer to an array +* @param n the number of Ts pointed to by ptr +* @param val the value to set each byte to +*/ +template<typename T> +inline void set_mem(T* ptr, size_t n, uint8_t val) + { + if(n > 0) + { + std::memset(ptr, val, sizeof(T)*n); + } + } + +inline const uint8_t* cast_char_ptr_to_uint8(const char* s) + { + return reinterpret_cast<const uint8_t*>(s); + } + +inline const char* cast_uint8_ptr_to_char(const uint8_t* b) + { + return reinterpret_cast<const char*>(b); + } + +inline uint8_t* cast_char_ptr_to_uint8(char* s) + { + return reinterpret_cast<uint8_t*>(s); + } + +inline char* cast_uint8_ptr_to_char(uint8_t* b) + { + return reinterpret_cast<char*>(b); + } + +/** +* Memory comparison, input insensitive +* @param p1 a pointer to an array +* @param p2 a pointer to another array +* @param n the number of Ts in p1 and p2 +* @return true iff p1[i] == p2[i] forall i in [0...n) +*/ +template<typename T> inline bool same_mem(const T* p1, const T* p2, size_t n) + { + volatile T difference = 0; + + for(size_t i = 0; i != n; ++i) + difference |= (p1[i] ^ p2[i]); + + return difference == 0; + } + +/** +* XOR arrays. Postcondition out[i] = in[i] ^ out[i] forall i = 0...length +* @param out the input/output buffer +* @param in the read-only input buffer +* @param length the length of the buffers +*/ +inline void xor_buf(uint8_t out[], + const uint8_t in[], + size_t length) + { + while(length >= 16) + { + uint64_t x0, x1, y0, y1; + std::memcpy(&x0, in, 8); + std::memcpy(&x1, in + 8, 8); + std::memcpy(&y0, out, 8); + std::memcpy(&y1, out + 8, 8); + + y0 ^= x0; + y1 ^= x1; + std::memcpy(out, &y0, 8); + std::memcpy(out + 8, &y1, 8); + out += 16; in += 16; length -= 16; + } + + while(length > 0) + { + out[0] ^= in[0]; + out += 1; + in += 1; + length -= 1; + } + } + +/** +* XOR arrays. Postcondition out[i] = in[i] ^ in2[i] forall i = 0...length +* @param out the output buffer +* @param in the first input buffer +* @param in2 the second output buffer +* @param length the length of the three buffers +*/ +inline void xor_buf(uint8_t out[], + const uint8_t in[], + const uint8_t in2[], + size_t length) + { + while(length >= 16) + { + uint64_t x0, x1, y0, y1; + std::memcpy(&x0, in, 8); + std::memcpy(&x1, in + 8, 8); + std::memcpy(&y0, in2, 8); + std::memcpy(&y1, in2 + 8, 8); + + x0 ^= y0; + x1 ^= y1; + std::memcpy(out, &x0, 8); + std::memcpy(out + 8, &x1, 8); + out += 16; in += 16; in2 += 16; length -= 16; + } + + for(size_t i = 0; i != length; ++i) + out[i] = in[i] ^ in2[i]; + } + +template<typename Alloc, typename Alloc2> +void xor_buf(std::vector<uint8_t, Alloc>& out, + const std::vector<uint8_t, Alloc2>& in, + size_t n) + { + xor_buf(out.data(), in.data(), n); + } + +template<typename Alloc> +void xor_buf(std::vector<uint8_t, Alloc>& out, + const uint8_t* in, + size_t n) + { + xor_buf(out.data(), in, n); + } + +template<typename Alloc, typename Alloc2> +void xor_buf(std::vector<uint8_t, Alloc>& out, + const uint8_t* in, + const std::vector<uint8_t, Alloc2>& in2, + size_t n) + { + xor_buf(out.data(), in, in2.data(), n); + } + +template<typename Alloc, typename Alloc2> +std::vector<uint8_t, Alloc>& +operator^=(std::vector<uint8_t, Alloc>& out, + const std::vector<uint8_t, Alloc2>& in) + { + if(out.size() < in.size()) + out.resize(in.size()); + + xor_buf(out.data(), in.data(), in.size()); + return out; + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/mul128.h b/src/libs/3rdparty/botan/src/lib/utils/mul128.h new file mode 100644 index 0000000000..1e28082548 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/mul128.h @@ -0,0 +1,123 @@ +/* +* 64x64->128 bit multiply operation +* (C) 2013,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTIL_MUL128_H_ +#define BOTAN_UTIL_MUL128_H_ + +#include <botan/types.h> + +namespace Botan { + +#if defined(__SIZEOF_INT128__) && defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) && !defined(__xlc__) + #define BOTAN_TARGET_HAS_NATIVE_UINT128 + + // Prefer TI mode over __int128 as GCC rejects the latter in pendantic mode + #if defined(__GNUG__) + typedef unsigned int uint128_t __attribute__((mode(TI))); + #else + typedef unsigned __int128 uint128_t; + #endif +#endif + +} + +#if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) \ + do { \ + const uint128_t r = static_cast<uint128_t>(a) * b; \ + *hi = (r >> 64) & 0xFFFFFFFFFFFFFFFF; \ + *lo = (r ) & 0xFFFFFFFFFFFFFFFF; \ + } while(0) + +#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) && defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT) + +#include <intrin.h> +#pragma intrinsic(_umul128) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) \ + do { *lo = _umul128(a, b, hi); } while(0) + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("mulq %3" : "=d" (*hi), "=a" (*lo) : "a" (a), "rm" (b) : "cc"); \ + } while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("umulh %1,%2,%0" : "=r" (*hi) : "r" (a), "r" (b)); \ + *lo = a * b; \ +} while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_IA64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("xmpy.hu %0=%1,%2" : "=f" (*hi) : "f" (a), "f" (b)); \ + *lo = a * b; \ +} while(0) + +#elif defined(BOTAN_TARGET_ARCH_IS_PPC64) + +#define BOTAN_FAST_64X64_MUL(a,b,lo,hi) do { \ + asm("mulhdu %0,%1,%2" : "=r" (*hi) : "r" (a), "r" (b) : "cc"); \ + *lo = a * b; \ +} while(0) + +#endif + +#endif + +namespace Botan { + +/** +* Perform a 64x64->128 bit multiplication +*/ +inline void mul64x64_128(uint64_t a, uint64_t b, uint64_t* lo, uint64_t* hi) + { +#if defined(BOTAN_FAST_64X64_MUL) + BOTAN_FAST_64X64_MUL(a, b, lo, hi); +#else + + /* + * Do a 64x64->128 multiply using four 32x32->64 multiplies plus + * some adds and shifts. Last resort for CPUs like UltraSPARC (with + * 64-bit registers/ALU, but no 64x64->128 multiply) or 32-bit CPUs. + */ + const size_t HWORD_BITS = 32; + const uint32_t HWORD_MASK = 0xFFFFFFFF; + + const uint32_t a_hi = (a >> HWORD_BITS); + const uint32_t a_lo = (a & HWORD_MASK); + const uint32_t b_hi = (b >> HWORD_BITS); + const uint32_t b_lo = (b & HWORD_MASK); + + uint64_t x0 = static_cast<uint64_t>(a_hi) * b_hi; + uint64_t x1 = static_cast<uint64_t>(a_lo) * b_hi; + uint64_t x2 = static_cast<uint64_t>(a_hi) * b_lo; + uint64_t x3 = static_cast<uint64_t>(a_lo) * b_lo; + + // this cannot overflow as (2^32-1)^2 + 2^32-1 < 2^64-1 + x2 += x3 >> HWORD_BITS; + + // this one can overflow + x2 += x1; + + // propagate the carry if any + x0 += static_cast<uint64_t>(static_cast<bool>(x2 < x1)) << HWORD_BITS; + + *hi = x0 + (x2 >> HWORD_BITS); + *lo = ((x2 & HWORD_MASK) << HWORD_BITS) + (x3 & HWORD_MASK); +#endif + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/mutex.h b/src/libs/3rdparty/botan/src/lib/utils/mutex.h new file mode 100644 index 0000000000..34fed5c81e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/mutex.h @@ -0,0 +1,58 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTIL_MUTEX_H_ +#define BOTAN_UTIL_MUTEX_H_ + +#include <botan/types.h> + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) + +#include <mutex> + +namespace Botan { + +template<typename T> using lock_guard_type = std::lock_guard<T>; +typedef std::mutex mutex_type; + +} + +#else + +// No threads + +namespace Botan { + +template<typename Mutex> +class lock_guard final + { + public: + explicit lock_guard(Mutex& m) : m_mutex(m) + { m_mutex.lock(); } + + ~lock_guard() { m_mutex.unlock(); } + + lock_guard(const lock_guard& other) = delete; + lock_guard& operator=(const lock_guard& other) = delete; + private: + Mutex& m_mutex; + }; + +class noop_mutex final + { + public: + void lock() {} + void unlock() {} + }; + +typedef noop_mutex mutex_type; +template<typename T> using lock_guard_type = lock_guard<T>; + +} + +#endif + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/os_utils.cpp b/src/libs/3rdparty/botan/src/lib/utils/os_utils.cpp new file mode 100644 index 0000000000..c7f04a8554 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/os_utils.cpp @@ -0,0 +1,448 @@ +/* +* OS and machine specific utility functions +* (C) 2015,2016,2017 Jack Lloyd +* (C) 2016 Daniel Neus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/os_utils.h> +#include <botan/cpuid.h> +#include <botan/exceptn.h> +#include <botan/mem_ops.h> + +#include <chrono> +#include <cstdlib> + +#if defined(BOTAN_TARGET_OS_HAS_EXPLICIT_BZERO) + #include <string.h> +#endif + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + #include <sys/types.h> + #include <sys/resource.h> + #include <sys/mman.h> + #include <signal.h> + #include <setjmp.h> + #include <unistd.h> + #include <errno.h> +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + #define NOMINMAX 1 + #include <windows.h> +#endif + +namespace Botan { + +// Not defined in OS namespace for historical reasons +void secure_scrub_memory(void* ptr, size_t n) + { +#if defined(BOTAN_TARGET_OS_HAS_RTLSECUREZEROMEMORY) + ::RtlSecureZeroMemory(ptr, n); + +#elif defined(BOTAN_TARGET_OS_HAS_EXPLICIT_BZERO) + ::explicit_bzero(ptr, n); + +#elif defined(BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO) && (BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO == 1) + /* + Call memset through a static volatile pointer, which the compiler + should not elide. This construct should be safe in conforming + compilers, but who knows. I did confirm that on x86-64 GCC 6.1 and + Clang 3.8 both create code that saves the memset address in the + data segment and uncondtionally loads and jumps to that address. + */ + static void* (*const volatile memset_ptr)(void*, int, size_t) = std::memset; + (memset_ptr)(ptr, 0, n); +#else + + volatile uint8_t* p = reinterpret_cast<volatile uint8_t*>(ptr); + + for(size_t i = 0; i != n; ++i) + p[i] = 0; +#endif + } + +uint32_t OS::get_process_id() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + return ::getpid(); +#elif defined(BOTAN_TARGET_OS_HAS_WIN32) + return ::GetCurrentProcessId(); +#elif defined(BOTAN_TARGET_OS_IS_INCLUDEOS) || defined(BOTAN_TARGET_OS_IS_LLVM) + return 0; // truly no meaningful value +#else + #error "Missing get_process_id" +#endif + } + +uint64_t OS::get_processor_timestamp() + { + uint64_t rtc = 0; + +#if defined(BOTAN_TARGET_OS_HAS_WIN32) + LARGE_INTEGER tv; + ::QueryPerformanceCounter(&tv); + rtc = tv.QuadPart; + +#elif defined(BOTAN_USE_GCC_INLINE_ASM) + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + + if(CPUID::has_rdtsc()) + { + uint32_t rtc_low = 0, rtc_high = 0; + asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low)); + rtc = (static_cast<uint64_t>(rtc_high) << 32) | rtc_low; + } + +#elif defined(BOTAN_TARGET_ARCH_IS_PPC64) + + for(;;) + { + uint32_t rtc_low = 0, rtc_high = 0, rtc_high2 = 0; + asm volatile("mftbu %0" : "=r" (rtc_high)); + asm volatile("mftb %0" : "=r" (rtc_low)); + asm volatile("mftbu %0" : "=r" (rtc_high2)); + + if(rtc_high == rtc_high2) + { + rtc = (static_cast<uint64_t>(rtc_high) << 32) | rtc_low; + break; + } + } + +#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) + asm volatile("rpcc %0" : "=r" (rtc)); + + // OpenBSD does not trap access to the %tick register +#elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD) + asm volatile("rd %%tick, %0" : "=r" (rtc)); + +#elif defined(BOTAN_TARGET_ARCH_IS_IA64) + asm volatile("mov %0=ar.itc" : "=r" (rtc)); + +#elif defined(BOTAN_TARGET_ARCH_IS_S390X) + asm volatile("stck 0(%0)" : : "a" (&rtc) : "memory", "cc"); + +#elif defined(BOTAN_TARGET_ARCH_IS_HPPA) + asm volatile("mfctl 16,%0" : "=r" (rtc)); // 64-bit only? + +#else + //#warning "OS::get_processor_timestamp not implemented" +#endif + +#endif + + return rtc; + } + +uint64_t OS::get_high_resolution_clock() + { + if(uint64_t cpu_clock = OS::get_processor_timestamp()) + return cpu_clock; + + /* + If we got here either we either don't have an asm instruction + above, or (for x86) RDTSC is not available at runtime. Try some + clock_gettimes and return the first one that works, or otherwise + fall back to std::chrono. + */ + +#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) + + // The ordering here is somewhat arbitrary... + const clockid_t clock_types[] = { +#if defined(CLOCK_MONOTONIC_HR) + CLOCK_MONOTONIC_HR, +#endif +#if defined(CLOCK_MONOTONIC_RAW) + CLOCK_MONOTONIC_RAW, +#endif +#if defined(CLOCK_MONOTONIC) + CLOCK_MONOTONIC, +#endif +#if defined(CLOCK_PROCESS_CPUTIME_ID) + CLOCK_PROCESS_CPUTIME_ID, +#endif +#if defined(CLOCK_THREAD_CPUTIME_ID) + CLOCK_THREAD_CPUTIME_ID, +#endif + }; + + for(clockid_t clock : clock_types) + { + struct timespec ts; + if(::clock_gettime(clock, &ts) == 0) + { + return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec); + } + } +#endif + + // Plain C++11 fallback + auto now = std::chrono::high_resolution_clock::now().time_since_epoch(); + return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count(); + } + +uint64_t OS::get_system_timestamp_ns() + { +#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME) + struct timespec ts; + if(::clock_gettime(CLOCK_REALTIME, &ts) == 0) + { + return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec); + } +#endif + + auto now = std::chrono::system_clock::now().time_since_epoch(); + return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count(); + } + +size_t OS::system_page_size() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + long p = ::sysconf(_SC_PAGESIZE); + if(p > 1) + return static_cast<size_t>(p); + else + return 4096; +#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + SYSTEM_INFO sys_info; + ::GetSystemInfo(&sys_info); + return sys_info.dwPageSize; +#endif + + // default value + return 4096; + } + +size_t OS::get_memory_locking_limit() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + /* + * Linux defaults to only 64 KiB of mlockable memory per process + * (too small) but BSDs offer a small fraction of total RAM (more + * than we need). Bound the total mlock size to 512 KiB which is + * enough to run the entire test suite without spilling to non-mlock + * memory (and thus presumably also enough for many useful + * programs), but small enough that we should not cause problems + * even if many processes are mlocking on the same machine. + */ + size_t mlock_requested = BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB; + + /* + * Allow override via env variable + */ + if(const char* env = std::getenv("BOTAN_MLOCK_POOL_SIZE")) + { + try + { + const size_t user_req = std::stoul(env, nullptr); + mlock_requested = std::min(user_req, mlock_requested); + } + catch(std::exception&) { /* ignore it */ } + } + +#if defined(RLIMIT_MEMLOCK) + if(mlock_requested > 0) + { + struct ::rlimit limits; + + ::getrlimit(RLIMIT_MEMLOCK, &limits); + + if(limits.rlim_cur < limits.rlim_max) + { + limits.rlim_cur = limits.rlim_max; + ::setrlimit(RLIMIT_MEMLOCK, &limits); + ::getrlimit(RLIMIT_MEMLOCK, &limits); + } + + return std::min<size_t>(limits.rlim_cur, mlock_requested * 1024); + } +#else + /* + * If RLIMIT_MEMLOCK is not defined, likely the OS does not support + * unprivileged mlock calls. + */ + return 0; +#endif + +#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + SIZE_T working_min = 0, working_max = 0; + if(!::GetProcessWorkingSetSize(::GetCurrentProcess(), &working_min, &working_max)) + { + return 0; + } + + // According to Microsoft MSDN: + // The maximum number of pages that a process can lock is equal to the number of pages in its minimum working set minus a small overhead + // In the book "Windows Internals Part 2": the maximum lockable pages are minimum working set size - 8 pages + // But the information in the book seems to be inaccurate/outdated + // I've tested this on Windows 8.1 x64, Windows 10 x64 and Windows 7 x86 + // On all three OS the value is 11 instead of 8 + size_t overhead = OS::system_page_size() * 11ULL; + if(working_min > overhead) + { + size_t lockable_bytes = working_min - overhead; + if(lockable_bytes < (BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB * 1024ULL)) + { + return lockable_bytes; + } + else + { + return BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB * 1024ULL; + } + } +#endif + + return 0; + } + +void* OS::allocate_locked_pages(size_t length) + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + +#if !defined(MAP_NOCORE) + #define MAP_NOCORE 0 +#endif + +#if !defined(MAP_ANONYMOUS) + #define MAP_ANONYMOUS MAP_ANON +#endif + + void* ptr = ::mmap(nullptr, + length, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED | MAP_NOCORE, + /*fd*/-1, + /*offset*/0); + + if(ptr == MAP_FAILED) + { + return nullptr; + } + +#if defined(MADV_DONTDUMP) + ::madvise(ptr, length, MADV_DONTDUMP); +#endif + +#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + if(::mlock(ptr, length) != 0) + { + ::munmap(ptr, length); + return nullptr; // failed to lock + } +#endif + + ::memset(ptr, 0, length); + + return ptr; +#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + LPVOID ptr = ::VirtualAlloc(nullptr, length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if(!ptr) + { + return nullptr; + } + + if(::VirtualLock(ptr, length) == 0) + { + ::VirtualFree(ptr, 0, MEM_RELEASE); + return nullptr; // failed to lock + } + + return ptr; +#else + BOTAN_UNUSED(length); + return nullptr; /* not implemented */ +#endif + } + +void OS::free_locked_pages(void* ptr, size_t length) + { + if(ptr == nullptr || length == 0) + return; + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + secure_scrub_memory(ptr, length); + +#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + ::munlock(ptr, length); +#endif + + ::munmap(ptr, length); +#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) + secure_scrub_memory(ptr, length); + ::VirtualUnlock(ptr, length); + ::VirtualFree(ptr, 0, MEM_RELEASE); +#else + // Invalid argument because no way this pointer was allocated by us + throw Invalid_Argument("Invalid ptr to free_locked_pages"); +#endif + } + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) +namespace { + +static ::sigjmp_buf g_sigill_jmp_buf; + +void botan_sigill_handler(int) + { + siglongjmp(g_sigill_jmp_buf, /*non-zero return value*/1); + } + +} +#endif + +int OS::run_cpu_instruction_probe(std::function<int ()> probe_fn) + { + volatile int probe_result = -3; + +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + struct sigaction old_sigaction; + struct sigaction sigaction; + + sigaction.sa_handler = botan_sigill_handler; + sigemptyset(&sigaction.sa_mask); + sigaction.sa_flags = 0; + + int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction); + + if(rc != 0) + throw Exception("run_cpu_instruction_probe sigaction failed"); + + rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/1); + + if(rc == 0) + { + // first call to sigsetjmp + probe_result = probe_fn(); + } + else if(rc == 1) + { + // non-local return from siglongjmp in signal handler: return error + probe_result = -1; + } + + // Restore old SIGILL handler, if any + rc = ::sigaction(SIGILL, &old_sigaction, nullptr); + if(rc != 0) + throw Exception("run_cpu_instruction_probe sigaction restore failed"); + +#elif defined(BOTAN_TARGET_OS_IS_WINDOWS) && defined(BOTAN_TARGET_COMPILER_IS_MSVC) + + // Windows SEH + __try + { + probe_result = probe_fn(); + } + __except(::GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ? + EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + probe_result = -1; + } + +#endif + + return probe_result; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/os_utils.h b/src/libs/3rdparty/botan/src/lib/utils/os_utils.h new file mode 100644 index 0000000000..5210b2523b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/os_utils.h @@ -0,0 +1,118 @@ +/* +* OS specific utility functions +* (C) 2015,2016,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OS_UTILS_H_ +#define BOTAN_OS_UTILS_H_ + +#include <botan/types.h> +#include <functional> + +namespace Botan { + +namespace OS { + +/* +* This header is internal (not installed) and these functions are not +* intended to be called by applications. However they are given public +* visibility (using BOTAN_TEST_API macro) for the tests. This also probably +* allows them to be overridden by the application on ELF systems, but +* this hasn't been tested. +*/ + +/** +* @return process ID assigned by the operating system. +* On Unix and Windows systems, this always returns a result +* On IncludeOS it returns 0 since there is no process ID to speak of +* in a unikernel. +*/ +uint32_t BOTAN_TEST_API get_process_id(); + +/** +* @return CPU processor clock, if available +* +* On Windows, calls QueryPerformanceCounter. +* +* Under GCC or Clang on supported platforms the hardware cycle counter is queried. +* Currently supported processors are x86, PPC, Alpha, SPARC, IA-64, S/390x, and HP-PA. +* If no CPU cycle counter is available on this system, returns zero. +*/ +uint64_t BOTAN_TEST_API get_processor_timestamp(); + +/* +* @return best resolution timestamp available +* +* The epoch and update rate of this clock is arbitrary and depending +* on the hardware it may not tick at a constant rate. +* +* Uses hardware cycle counter, if available. +* On POSIX platforms clock_gettime is used with a monotonic timer +* As a final fallback std::chrono::high_resolution_clock is used. +*/ +uint64_t BOTAN_TEST_API get_high_resolution_clock(); + +/** +* @return system clock (reflecting wall clock) with best resolution +* available, normalized to nanoseconds resolution. +*/ +uint64_t BOTAN_TEST_API get_system_timestamp_ns(); + +/** +* @return maximum amount of memory (in bytes) Botan could/should +* hyptothetically allocate for the memory poool. Reads environment +* variable "BOTAN_MLOCK_POOL_SIZE", set to "0" to disable pool. +*/ +size_t get_memory_locking_limit(); + +/** +* Return the size of a memory page, if that can be derived on the +* current system. Otherwise returns some default value (eg 4096) +*/ +size_t system_page_size(); + +/** +* Request so many bytes of page-aligned RAM locked into memory using +* mlock, VirtualLock, or similar. Returns null on failure. The memory +* returned is zeroed. Free it with free_locked_pages. +* @param length requested allocation in bytes +*/ +void* allocate_locked_pages(size_t length); + +/** +* Free memory allocated by allocate_locked_pages +* @param ptr a pointer returned by allocate_locked_pages +* @param length length passed to allocate_locked_pages +*/ +void free_locked_pages(void* ptr, size_t length); + +/** +* Run a probe instruction to test for support for a CPU instruction. +* Runs in system-specific env that catches illegal instructions; this +* function always fails if the OS doesn't provide this. +* Returns value of probe_fn, if it could run. +* If error occurs, returns negative number. +* This allows probe_fn to indicate errors of its own, if it wants. +* For example the instruction might not only be only available on some +* CPUs, but also buggy on some subset of these - the probe function +* can test to make sure the instruction works properly before +* indicating that the instruction is available. +* +* @warning on Unix systems uses signal handling in a way that is not +* thread safe. It should only be called in a single-threaded context +* (ie, at static init time). +* +* If probe_fn throws an exception the result is undefined. +* +* Return codes: +* -1 illegal instruction detected +*/ +int BOTAN_TEST_API run_cpu_instruction_probe(std::function<int ()> probe_fn); + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/parsing.cpp b/src/libs/3rdparty/botan/src/lib/utils/parsing.cpp new file mode 100644 index 0000000000..cfae0cb708 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/parsing.cpp @@ -0,0 +1,477 @@ +/* +* Various string utils and parsing functions +* (C) 1999-2007,2013,2014,2015,2018 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/parsing.h> +#include <botan/exceptn.h> +#include <botan/charset.h> +#include <botan/loadstor.h> +#include <algorithm> +#include <cctype> +#include <limits> +#include <set> + +namespace Botan { + +uint16_t to_uint16(const std::string& str) + { + const uint32_t x = to_u32bit(str); + + if(x >> 16) + throw Invalid_Argument("Integer value exceeds 16 bit range"); + + return static_cast<uint16_t>(x); + } + +uint32_t to_u32bit(const std::string& str) + { + // std::stoul is not strict enough. Ensure that str is digit only [0-9]* + for(const char chr : str) + { + if(chr < '0' || chr > '9') + { + std::string chrAsString(1, chr); + throw Invalid_Argument("String contains non-digit char: " + chrAsString); + } + } + + const unsigned long int x = std::stoul(str); + + if(sizeof(unsigned long int) > 4) + { + // x might be uint64 + if (x > std::numeric_limits<uint32_t>::max()) + { + throw Invalid_Argument("Integer value of " + str + " exceeds 32 bit range"); + } + } + + return static_cast<uint32_t>(x); + } + +/* +* Convert a string into a time duration +*/ +uint32_t timespec_to_u32bit(const std::string& timespec) + { + if(timespec.empty()) + return 0; + + const char suffix = timespec[timespec.size()-1]; + std::string value = timespec.substr(0, timespec.size()-1); + + uint32_t scale = 1; + + if(Charset::is_digit(suffix)) + value += suffix; + else if(suffix == 's') + scale = 1; + else if(suffix == 'm') + scale = 60; + else if(suffix == 'h') + scale = 60 * 60; + else if(suffix == 'd') + scale = 24 * 60 * 60; + else if(suffix == 'y') + scale = 365 * 24 * 60 * 60; + else + throw Decoding_Error("timespec_to_u32bit: Bad input " + timespec); + + return scale * to_u32bit(value); + } + +/* +* Parse a SCAN-style algorithm name +*/ +std::vector<std::string> parse_algorithm_name(const std::string& namex) + { + if(namex.find('(') == std::string::npos && + namex.find(')') == std::string::npos) + return std::vector<std::string>(1, namex); + + std::string name = namex, substring; + std::vector<std::string> elems; + size_t level = 0; + + elems.push_back(name.substr(0, name.find('('))); + name = name.substr(name.find('(')); + + for(auto i = name.begin(); i != name.end(); ++i) + { + char c = *i; + + if(c == '(') + ++level; + if(c == ')') + { + if(level == 1 && i == name.end() - 1) + { + if(elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + return elems; + } + + if(level == 0 || (level == 1 && i != name.end() - 1)) + throw Invalid_Algorithm_Name(namex); + --level; + } + + if(c == ',' && level == 1) + { + if(elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + substring.clear(); + } + else + substring += c; + } + + if(!substring.empty()) + throw Invalid_Algorithm_Name(namex); + + return elems; + } + +std::vector<std::string> split_on(const std::string& str, char delim) + { + return split_on_pred(str, [delim](char c) { return c == delim; }); + } + +std::vector<std::string> split_on_pred(const std::string& str, + std::function<bool (char)> pred) + { + std::vector<std::string> elems; + if(str.empty()) return elems; + + std::string substr; + for(auto i = str.begin(); i != str.end(); ++i) + { + if(pred(*i)) + { + if(!substr.empty()) + elems.push_back(substr); + substr.clear(); + } + else + substr += *i; + } + + if(substr.empty()) + throw Invalid_Argument("Unable to split string: " + str); + elems.push_back(substr); + + return elems; + } + +/* +* Join a string +*/ +std::string string_join(const std::vector<std::string>& strs, char delim) + { + std::string out = ""; + + for(size_t i = 0; i != strs.size(); ++i) + { + if(i != 0) + out += delim; + out += strs[i]; + } + + return out; + } + +/* +* Parse an ASN.1 OID string +*/ +std::vector<uint32_t> parse_asn1_oid(const std::string& oid) + { + std::string substring; + std::vector<uint32_t> oid_elems; + + for(auto i = oid.begin(); i != oid.end(); ++i) + { + char c = *i; + + if(c == '.') + { + if(substring.empty()) + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + substring.clear(); + } + else + substring += c; + } + + if(substring.empty()) + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + + if(oid_elems.size() < 2) + throw Invalid_OID(oid); + + return oid_elems; + } + +/* +* X.500 String Comparison +*/ +bool x500_name_cmp(const std::string& name1, const std::string& name2) + { + auto p1 = name1.begin(); + auto p2 = name2.begin(); + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + while(p1 != name1.end() && p2 != name2.end()) + { + if(Charset::is_space(*p1)) + { + if(!Charset::is_space(*p2)) + return false; + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + if(p1 == name1.end() && p2 == name2.end()) + return true; + if(p1 == name1.end() || p2 == name2.end()) + return false; + } + + if(!Charset::caseless_cmp(*p1, *p2)) + return false; + ++p1; + ++p2; + } + + while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1; + while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2; + + if((p1 != name1.end()) || (p2 != name2.end())) + return false; + return true; + } + +/* +* Convert a decimal-dotted string to binary IP +*/ +uint32_t string_to_ipv4(const std::string& str) + { + std::vector<std::string> parts = split_on(str, '.'); + + if(parts.size() != 4) + throw Decoding_Error("Invalid IP string " + str); + + uint32_t ip = 0; + + for(auto part = parts.begin(); part != parts.end(); ++part) + { + uint32_t octet = to_u32bit(*part); + + if(octet > 255) + throw Decoding_Error("Invalid IP string " + str); + + ip = (ip << 8) | (octet & 0xFF); + } + + return ip; + } + +/* +* Convert an IP address to decimal-dotted string +*/ +std::string ipv4_to_string(uint32_t ip) + { + std::string str; + + for(size_t i = 0; i != sizeof(ip); ++i) + { + if(i) + str += "."; + str += std::to_string(get_byte(i, ip)); + } + + return str; + } + +std::string erase_chars(const std::string& str, const std::set<char>& chars) + { + std::string out; + + for(auto c: str) + if(chars.count(c) == 0) + out += c; + + return out; + } + +std::string replace_chars(const std::string& str, + const std::set<char>& chars, + char to_char) + { + std::string out = str; + + for(size_t i = 0; i != out.size(); ++i) + if(chars.count(out[i])) + out[i] = to_char; + + return out; + } + +std::string replace_char(const std::string& str, char from_char, char to_char) + { + std::string out = str; + + for(size_t i = 0; i != out.size(); ++i) + if(out[i] == from_char) + out[i] = to_char; + + return out; + } + +namespace { + +std::string tolower_string(const std::string& in) + { + std::string s = in; + for(size_t i = 0; i != s.size(); ++i) + { + if(std::isalpha(static_cast<unsigned char>(s[i]))) + s[i] = std::tolower(static_cast<unsigned char>(s[i])); + } + return s; + } + +} + +bool host_wildcard_match(const std::string& issued_, const std::string& host_) + { + const std::string issued = tolower_string(issued_); + const std::string host = tolower_string(host_); + + if(host.empty() || issued.empty()) + return false; + + /* + If there are embedded nulls in your issued name + Well I feel bad for you son + */ + if(std::count(issued.begin(), issued.end(), char(0)) > 0) + return false; + + // If more than one wildcard, then issued name is invalid + const size_t stars = std::count(issued.begin(), issued.end(), '*'); + if(stars > 1) + return false; + + // '*' is not a valid character in DNS names so should not appear on the host side + if(std::count(host.begin(), host.end(), '*') != 0) + return false; + + // Similarly a DNS name can't end in . + if(host[host.size() - 1] == '.') + return false; + + // And a host can't have an empty name component, so reject that + if(host.find("..") != std::string::npos) + return false; + + // Exact match: accept + if(issued == host) + { + return true; + } + + /* + Otherwise it might be a wildcard + + If the issued size is strictly longer than the hostname size it + couldn't possibly be a match, even if the issued value is a + wildcard. The only exception is when the wildcard ends up empty + (eg www.example.com matches www*.example.com) + */ + if(issued.size() > host.size() + 1) + { + return false; + } + + // If no * at all then not a wildcard, and so not a match + if(stars != 1) + { + return false; + } + + /* + Now walk through the issued string, making sure every character + matches. When we come to the (singular) '*', jump forward in the + hostname by the cooresponding amount. We know exactly how much + space the wildcard takes because it must be exactly `len(host) - + len(issued) + 1 chars`. + + We also verify that the '*' comes in the leftmost component, and + doesn't skip over any '.' in the hostname. + */ + size_t dots_seen = 0; + size_t host_idx = 0; + + for(size_t i = 0; i != issued.size(); ++i) + { + dots_seen += (issued[i] == '.'); + + if(issued[i] == '*') + { + // Fail: wildcard can only come in leftmost component + if(dots_seen > 0) + { + return false; + } + + /* + Since there is only one * we know the tail of the issued and + hostname must be an exact match. In this case advance host_idx + to match. + */ + const size_t advance = (host.size() - issued.size() + 1); + + if(host_idx + advance > host.size()) // shouldn't happen + return false; + + // Can't be any intervening .s that we would have skipped + if(std::count(host.begin() + host_idx, + host.begin() + host_idx + advance, '.') != 0) + return false; + + host_idx += advance; + } + else + { + if(issued[i] != host[host_idx]) + { + return false; + } + + host_idx += 1; + } + } + + // Wildcard issued name must have at least 3 components + if(dots_seen < 2) + { + return false; + } + + return true; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/parsing.h b/src/libs/3rdparty/botan/src/lib/utils/parsing.h new file mode 100644 index 0000000000..9185cfaadf --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/parsing.h @@ -0,0 +1,153 @@ +/* +* Various string utils and parsing functions +* (C) 1999-2007,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PARSER_H_ +#define BOTAN_PARSER_H_ + +#include <botan/types.h> +#include <string> +#include <vector> +#include <set> + +#include <istream> +#include <functional> +#include <map> + +namespace Botan { + +/** +* Parse a SCAN-style algorithm name +* @param scan_name the name +* @return the name components +*/ +BOTAN_PUBLIC_API(2,0) std::vector<std::string> +parse_algorithm_name(const std::string& scan_name); + +/** +* Split a string +* @param str the input string +* @param delim the delimitor +* @return string split by delim +*/ +BOTAN_PUBLIC_API(2,0) std::vector<std::string> split_on( + const std::string& str, char delim); + +/** +* Split a string on a character predicate +* @param str the input string +* @param pred the predicate +*/ +BOTAN_PUBLIC_API(2,0) std::vector<std::string> +split_on_pred(const std::string& str, + std::function<bool (char)> pred); + +/** +* Erase characters from a string +*/ +BOTAN_PUBLIC_API(2,0) +BOTAN_DEPRECATED("Unused") +std::string erase_chars(const std::string& str, const std::set<char>& chars); + +/** +* Replace a character in a string +* @param str the input string +* @param from_char the character to replace +* @param to_char the character to replace it with +* @return str with all instances of from_char replaced by to_char +*/ +BOTAN_PUBLIC_API(2,0) +BOTAN_DEPRECATED("Unused") +std::string replace_char(const std::string& str, + char from_char, + char to_char); + +/** +* Replace a character in a string +* @param str the input string +* @param from_chars the characters to replace +* @param to_char the character to replace it with +* @return str with all instances of from_chars replaced by to_char +*/ +BOTAN_PUBLIC_API(2,0) +BOTAN_DEPRECATED("Unused") +std::string replace_chars(const std::string& str, + const std::set<char>& from_chars, + char to_char); + +/** +* Join a string +* @param strs strings to join +* @param delim the delimitor +* @return string joined by delim +*/ +BOTAN_PUBLIC_API(2,0) +std::string string_join(const std::vector<std::string>& strs, + char delim); + +/** +* Parse an ASN.1 OID +* @param oid the OID in string form +* @return OID components +*/ +BOTAN_PUBLIC_API(2,0) std::vector<uint32_t> parse_asn1_oid(const std::string& oid); + +/** +* Compare two names using the X.509 comparison algorithm +* @param name1 the first name +* @param name2 the second name +* @return true if name1 is the same as name2 by the X.509 comparison rules +*/ +BOTAN_PUBLIC_API(2,0) +bool x500_name_cmp(const std::string& name1, + const std::string& name2); + +/** +* Convert a string to a number +* @param str the string to convert +* @return number value of the string +*/ +BOTAN_PUBLIC_API(2,0) uint32_t to_u32bit(const std::string& str); + +/** +* Convert a string to a number +* @param str the string to convert +* @return number value of the string +*/ +BOTAN_PUBLIC_API(2,3) uint16_t to_uint16(const std::string& str); + +/** +* Convert a time specification to a number +* @param timespec the time specification +* @return number of seconds represented by timespec +*/ +BOTAN_PUBLIC_API(2,0) uint32_t BOTAN_DEPRECATED("Not used anymore") +timespec_to_u32bit(const std::string& timespec); + +/** +* Convert a string representation of an IPv4 address to a number +* @param ip_str the string representation +* @return integer IPv4 address +*/ +BOTAN_PUBLIC_API(2,0) uint32_t string_to_ipv4(const std::string& ip_str); + +/** +* Convert an IPv4 address to a string +* @param ip_addr the IPv4 address to convert +* @return string representation of the IPv4 address +*/ +BOTAN_PUBLIC_API(2,0) std::string ipv4_to_string(uint32_t ip_addr); + +std::map<std::string, std::string> BOTAN_PUBLIC_API(2,0) read_cfg(std::istream& is); + +std::string BOTAN_PUBLIC_API(2,0) clean_ws(const std::string& s); + +bool BOTAN_PUBLIC_API(2,0) host_wildcard_match(const std::string& wildcard, const std::string& host); + + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/prefetch.h b/src/libs/3rdparty/botan/src/lib/utils/prefetch.h new file mode 100644 index 0000000000..92c41e5738 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/prefetch.h @@ -0,0 +1,39 @@ +/* +* Prefetching Operations +* (C) 2009 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PREFETCH_H_ +#define BOTAN_PREFETCH_H_ + +#include <botan/cpuid.h> + +namespace Botan { + +template<typename T> +inline void prefetch_readonly(const T* addr, size_t length) + { +#if defined(__GNUG__) + const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); + + for(size_t i = 0; i <= length; i += Ts_per_cache_line) + __builtin_prefetch(addr + i, 0); +#endif + } + +template<typename T> +inline void prefetch_readwrite(const T* addr, size_t length) + { +#if defined(__GNUG__) + const size_t Ts_per_cache_line = CPUID::cache_line_size() / sizeof(T); + + for(size_t i = 0; i <= length; i += Ts_per_cache_line) + __builtin_prefetch(addr + i, 1); +#endif + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/read_cfg.cpp b/src/libs/3rdparty/botan/src/lib/utils/read_cfg.cpp new file mode 100644 index 0000000000..bf68c04792 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/read_cfg.cpp @@ -0,0 +1,63 @@ +/* +* Simple config/test file reader +* (C) 2013,2014,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/parsing.h> +#include <botan/exceptn.h> + +namespace Botan { + +std::string clean_ws(const std::string& s) + { + const char* ws = " \t\n"; + auto start = s.find_first_not_of(ws); + auto end = s.find_last_not_of(ws); + + if(start == std::string::npos) + return ""; + + if(end == std::string::npos) + return s.substr(start, end); + else + return s.substr(start, start + end + 1); + } + +std::map<std::string, std::string> read_cfg(std::istream& is) + { + std::map<std::string, std::string> kv; + size_t line = 0; + + while(is.good()) + { + std::string s; + + std::getline(is, s); + + ++line; + + if(s.empty() || s[0] == '#') + continue; + + s = clean_ws(s.substr(0, s.find('#'))); + + if(s.empty()) + continue; + + auto eq = s.find("="); + + if(eq == std::string::npos || eq == 0 || eq == s.size() - 1) + throw Exception("Bad read_cfg input '" + s + "' on line " + std::to_string(line)); + + const std::string key = clean_ws(s.substr(0, eq)); + const std::string val = clean_ws(s.substr(eq + 1, std::string::npos)); + + kv[key] = val; + } + + return kv; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/rotate.h b/src/libs/3rdparty/botan/src/lib/utils/rotate.h new file mode 100644 index 0000000000..4bb76c9ed4 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/rotate.h @@ -0,0 +1,104 @@ +/* +* Word Rotation Operations +* (C) 1999-2008,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_WORD_ROTATE_H_ +#define BOTAN_WORD_ROTATE_H_ + +#include <botan/types.h> + +namespace Botan { + +/** +* Bit rotation left by a compile-time constant amount +* @param input the input word +* @return input rotated left by ROT bits +*/ +template<size_t ROT, typename T> +inline T rotl(T input) + { + static_assert(ROT > 0 && ROT < 8*sizeof(T), "Invalid rotation constant"); + return static_cast<T>((input << ROT) | (input >> (8*sizeof(T) - ROT))); + } + +/** +* Bit rotation right by a compile-time constant amount +* @param input the input word +* @return input rotated right by ROT bits +*/ +template<size_t ROT, typename T> +inline T rotr(T input) + { + static_assert(ROT > 0 && ROT < 8*sizeof(T), "Invalid rotation constant"); + return static_cast<T>((input >> ROT) | (input << (8*sizeof(T) - ROT))); + } + +/** +* Bit rotation left, variable rotation amount +* @param input the input word +* @param rot the number of bits to rotate, must be between 0 and sizeof(T)*8-1 +* @return input rotated left by rot bits +*/ +template<typename T> +inline T rotl_var(T input, size_t rot) + { + return rot ? static_cast<T>((input << rot) | (input >> (sizeof(T)*8 - rot))) : input; + } + +/** +* Bit rotation right, variable rotation amount +* @param input the input word +* @param rot the number of bits to rotate, must be between 0 and sizeof(T)*8-1 +* @return input rotated right by rot bits +*/ +template<typename T> +inline T rotr_var(T input, size_t rot) + { + return rot ? static_cast<T>((input >> rot) | (input << (sizeof(T)*8 - rot))) : input; + } + +#if BOTAN_USE_GCC_INLINE_ASM + +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) || defined(BOTAN_TARGET_ARCH_IS_X86_32) + +template<> +inline uint32_t rotl_var(uint32_t input, size_t rot) + { + asm("roll %1,%0" : "+r" (input) : "c" (static_cast<uint8_t>(rot))); + return input; + } + +template<> +inline uint32_t rotr_var(uint32_t input, size_t rot) + { + asm("rorl %1,%0" : "+r" (input) : "c" (static_cast<uint8_t>(rot))); + return input; + } + +#endif + +#endif + + +template<typename T> +BOTAN_DEPRECATED("Use rotl<N> or rotl_var") +inline T rotate_left(T input, size_t rot) + { + // rotl_var does not reduce + return rotl_var(input, rot % (8 * sizeof(T))); + } + +template<typename T> +BOTAN_DEPRECATED("Use rotr<N> or rotr_var") +inline T rotate_right(T input, size_t rot) + { + // rotr_var does not reduce + return rotr_var(input, rot % (8 * sizeof(T))); + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/rounding.h b/src/libs/3rdparty/botan/src/lib/utils/rounding.h new file mode 100644 index 0000000000..a03e3a4ee2 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/rounding.h @@ -0,0 +1,59 @@ +/* +* Integer Rounding Functions +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ROUNDING_H_ +#define BOTAN_ROUNDING_H_ + +#include <botan/types.h> + +namespace Botan { + +/** +* Round up +* @param n a non-negative integer +* @param align_to the alignment boundary +* @return n rounded up to a multiple of align_to +*/ +inline size_t round_up(size_t n, size_t align_to) + { + BOTAN_ARG_CHECK(align_to != 0, "align_to must not be 0"); + + if(n % align_to) + n += align_to - (n % align_to); + return n; + } + +/** +* Round down +* @param n an integer +* @param align_to the alignment boundary +* @return n rounded down to a multiple of align_to +*/ +template<typename T> +inline T round_down(T n, T align_to) + { + if(align_to == 0) + return n; + + return (n - (n % align_to)); + } + +/** +* Clamp +*/ +inline size_t clamp(size_t n, size_t lower_bound, size_t upper_bound) + { + if(n < lower_bound) + return lower_bound; + if(n > upper_bound) + return upper_bound; + return n; + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/safeint.h b/src/libs/3rdparty/botan/src/lib/utils/safeint.h new file mode 100644 index 0000000000..377f134187 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/safeint.h @@ -0,0 +1,39 @@ +/* +* Safe(r) Integer Handling +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_UTILS_SAFE_INT_H_ +#define BOTAN_UTILS_SAFE_INT_H_ + +#include <botan/exceptn.h> +#include <string> + +namespace Botan { + +class BOTAN_PUBLIC_API(2,0) Integer_Overflow_Detected final : public Exception + { + public: + Integer_Overflow_Detected(const std::string& file, int line) : + Exception("Integer overflow detected at " + file + ":" + std::to_string(line)) + {} + }; + +inline size_t checked_add(size_t x, size_t y, const char* file, int line) + { + // TODO: use __builtin_x_overflow on GCC and Clang + size_t z = x + y; + if(z < x) + { + throw Integer_Overflow_Detected(file, line); + } + return z; + } + +#define BOTAN_CHECKED_ADD(x,y) checked_add(x,y,__FILE__,__LINE__) + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/simd/info.txt b/src/libs/3rdparty/botan/src/lib/utils/simd/info.txt new file mode 100644 index 0000000000..7784902a60 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/simd/info.txt @@ -0,0 +1,7 @@ +<defines> +SIMD_32 -> 20131128 +</defines> + +<header:internal> +simd_32.h +</header:internal> diff --git a/src/libs/3rdparty/botan/src/lib/utils/simd/simd_32.h b/src/libs/3rdparty/botan/src/lib/utils/simd/simd_32.h new file mode 100644 index 0000000000..8e6ac3639c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/simd/simd_32.h @@ -0,0 +1,699 @@ +/* +* Lightweight wrappers for SIMD operations +* (C) 2009,2011,2016,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SIMD_32_H_ +#define BOTAN_SIMD_32_H_ + +#include <botan/types.h> +#include <botan/loadstor.h> +#include <botan/bswap.h> +#include <botan/cpuid.h> + +#if defined(BOTAN_TARGET_SUPPORTS_SSE2) + #include <emmintrin.h> + #define BOTAN_SIMD_USE_SSE2 + +#elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC) + #include <altivec.h> + #undef vector + #undef bool + #define BOTAN_SIMD_USE_ALTIVEC + +#elif defined(BOTAN_TARGET_SUPPORTS_NEON) + #include <arm_neon.h> + #define BOTAN_SIMD_USE_NEON +#endif + +namespace Botan { + +/** +* 4x32 bit SIMD register +* +* This class is not a general purpose SIMD type, and only offers +* instructions needed for evaluation of specific crypto primitives. +* For example it does not currently have equality operators of any +* kind. +* +* Implemented for SSE2, VMX (Altivec), and NEON. +*/ +class SIMD_4x32 final + { + public: + + SIMD_4x32& operator=(const SIMD_4x32& other) = default; + SIMD_4x32(const SIMD_4x32& other) = default; + +#if !defined(BOTAN_BUILD_COMPILER_IS_MSVC_2013) + SIMD_4x32& operator=(SIMD_4x32&& other) = default; + SIMD_4x32(SIMD_4x32&& other) = default; +#endif + + /** + * Zero initialize SIMD register with 4 32-bit elements + */ + SIMD_4x32() // zero initialized + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_sse = _mm_setzero_si128(); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_vmx = vec_splat_u32(0); +#elif defined(BOTAN_SIMD_USE_NEON) + m_neon = vdupq_n_u32(0); +#else + m_scalar[0] = 0; + m_scalar[1] = 0; + m_scalar[2] = 0; + m_scalar[3] = 0; +#endif + } + + /** + * Load SIMD register with 4 32-bit elements + */ + explicit SIMD_4x32(const uint32_t B[4]) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_sse = _mm_loadu_si128(reinterpret_cast<const __m128i*>(B)); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_vmx = (__vector unsigned int){B[0], B[1], B[2], B[3]}; +#elif defined(BOTAN_SIMD_USE_NEON) + m_neon = vld1q_u32(B); +#else + m_scalar[0] = B[0]; + m_scalar[1] = B[1]; + m_scalar[2] = B[2]; + m_scalar[3] = B[3]; +#endif + } + + /** + * Load SIMD register with 4 32-bit elements + */ + SIMD_4x32(uint32_t B0, uint32_t B1, uint32_t B2, uint32_t B3) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_sse = _mm_set_epi32(B3, B2, B1, B0); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_vmx = (__vector unsigned int){B0, B1, B2, B3}; +#elif defined(BOTAN_SIMD_USE_NEON) + // Better way to do this? + const uint32_t B[4] = { B0, B1, B2, B3 }; + m_neon = vld1q_u32(B); +#else + m_scalar[0] = B0; + m_scalar[1] = B1; + m_scalar[2] = B2; + m_scalar[3] = B3; +#endif + } + + /** + * Load SIMD register with one 32-bit element repeated + */ + static SIMD_4x32 splat(uint32_t B) + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_set1_epi32(B)); +#elif defined(BOTAN_SIMD_USE_ARM) + return SIMD_4x32(vdupq_n_u32(B)); +#else + return SIMD_4x32(B, B, B, B); +#endif + } + + /** + * Load a SIMD register with little-endian convention + */ + static SIMD_4x32 load_le(const void* in) + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in))); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + uint32_t R[4]; + Botan::load_le(R, static_cast<const uint8_t*>(in), 4); + return SIMD_4x32(R); + +#elif defined(BOTAN_SIMD_USE_NEON) + + uint32_t in32[4]; + std::memcpy(in32, in, 16); + if(CPUID::is_big_endian()) + { + bswap_4(in32); + } + return SIMD_4x32(vld1q_u32(in32)); + +#else + SIMD_4x32 out; + Botan::load_le(out.m_scalar, static_cast<const uint8_t*>(in), 4); + return out; +#endif + } + + /** + * Load a SIMD register with big-endian convention + */ + static SIMD_4x32 load_be(const void* in) + { +#if defined(BOTAN_SIMD_USE_SSE2) + + return load_le(in).bswap(); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + uint32_t R[4]; + Botan::load_be(R, static_cast<const uint8_t*>(in), 4); + return SIMD_4x32(R); + +#elif defined(BOTAN_SIMD_USE_NEON) + + uint32_t in32[4]; + std::memcpy(in32, in, 16); + if(CPUID::is_little_endian()) + { + bswap_4(in32); + } + return SIMD_4x32(vld1q_u32(in32)); + +#else + SIMD_4x32 out; + Botan::load_be(out.m_scalar, static_cast<const uint8_t*>(in), 4); + return out; +#endif + } + + /** + * Load a SIMD register with little-endian convention + */ + void store_le(uint8_t out[]) const + { +#if defined(BOTAN_SIMD_USE_SSE2) + + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), m_sse); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + union { + __vector unsigned int V; + uint32_t R[4]; + } vec; + vec.V = m_vmx; + Botan::store_le(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); + +#elif defined(BOTAN_SIMD_USE_NEON) + + if(CPUID::is_big_endian()) + { + SIMD_4x32 swap = bswap(); + swap.store_be(out); + } + else + { + uint32_t out32[4] = { 0 }; + vst1q_u32(out32, m_neon); + copy_out_le(out, 16, out32); + } +#else + Botan::store_le(out, m_scalar[0], m_scalar[1], m_scalar[2], m_scalar[3]); +#endif + } + + /** + * Load a SIMD register with big-endian convention + */ + void store_be(uint8_t out[]) const + { +#if defined(BOTAN_SIMD_USE_SSE2) + + bswap().store_le(out); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + union { + __vector unsigned int V; + uint32_t R[4]; + } vec; + vec.V = m_vmx; + Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]); + +#elif defined(BOTAN_SIMD_USE_NEON) + + if(CPUID::is_little_endian()) + { + SIMD_4x32 swap = bswap(); + swap.store_le(out); + } + else + { + uint32_t out32[4] = { 0 }; + vst1q_u32(out32, m_neon); + copy_out_be(out, 16, out32); + } + +#else + Botan::store_be(out, m_scalar[0], m_scalar[1], m_scalar[2], m_scalar[3]); +#endif + } + + + /* + * This is used for SHA-2/SHACAL2 + * Return rotr(ROT1) ^ rotr(ROT2) ^ rotr(ROT3) + */ + template<size_t ROT1, size_t ROT2, size_t ROT3> + SIMD_4x32 rho() const + { + SIMD_4x32 res; + +#if defined(BOTAN_SIMD_USE_SSE2) + + res.m_sse = _mm_or_si128(_mm_slli_epi32(m_sse, static_cast<int>(32-ROT1)), + _mm_srli_epi32(m_sse, static_cast<int>(ROT1))); + res.m_sse = _mm_xor_si128( + res.m_sse, + _mm_or_si128(_mm_slli_epi32(m_sse, static_cast<int>(32-ROT2)), + _mm_srli_epi32(m_sse, static_cast<int>(ROT2)))); + res.m_sse = _mm_xor_si128( + res.m_sse, + _mm_or_si128(_mm_slli_epi32(m_sse, static_cast<int>(32-ROT3)), + _mm_srli_epi32(m_sse, static_cast<int>(ROT3)))); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + const unsigned int r1 = static_cast<unsigned int>(32-ROT1); + const unsigned int r2 = static_cast<unsigned int>(32-ROT2); + const unsigned int r3 = static_cast<unsigned int>(32-ROT3); + res.m_vmx = vec_rl(m_vmx, (__vector unsigned int){r1, r1, r1, r1}); + res.m_vmx = vec_xor(res.m_vmx, vec_rl(m_vmx, (__vector unsigned int){r2, r2, r2, r2})); + res.m_vmx = vec_xor(res.m_vmx, vec_rl(m_vmx, (__vector unsigned int){r3, r3, r3, r3})); + +#elif defined(BOTAN_SIMD_USE_NEON) + res.m_neon = vorrq_u32(vshlq_n_u32(m_neon, static_cast<int>(32-ROT1)), + vshrq_n_u32(m_neon, static_cast<int>(ROT1))); + + res.m_neon = veorq_u32( + res.m_neon, + vorrq_u32(vshlq_n_u32(m_neon, static_cast<int>(32-ROT2)), + vshrq_n_u32(m_neon, static_cast<int>(ROT2)))); + + res.m_neon = veorq_u32( + res.m_neon, + vorrq_u32(vshlq_n_u32(m_neon, static_cast<int>(32-ROT3)), + vshrq_n_u32(m_neon, static_cast<int>(ROT3)))); + +#else + + for(size_t i = 0; i != 4; ++i) + { + res.m_scalar[i] = Botan::rotr<ROT1>(m_scalar[i]) ^ + Botan::rotr<ROT2>(m_scalar[i]) ^ + Botan::rotr<ROT3>(m_scalar[i]); + } +#endif + + return res; + } + + /** + * Left rotation by a compile time constant + */ + template<size_t ROT> + SIMD_4x32 rotl() const + { + static_assert(ROT > 0 && ROT < 32, "Invalid rotation constant"); + +#if defined(BOTAN_SIMD_USE_SSE2) + + return SIMD_4x32(_mm_or_si128(_mm_slli_epi32(m_sse, static_cast<int>(ROT)), + _mm_srli_epi32(m_sse, static_cast<int>(32-ROT)))); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + const unsigned int r = static_cast<unsigned int>(ROT); + return SIMD_4x32(vec_rl(m_vmx, (__vector unsigned int){r, r, r, r})); + +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vorrq_u32(vshlq_n_u32(m_neon, static_cast<int>(ROT)), + vshrq_n_u32(m_neon, static_cast<int>(32-ROT)))); + +#else + return SIMD_4x32(Botan::rotl<ROT>(m_scalar[0]), + Botan::rotl<ROT>(m_scalar[1]), + Botan::rotl<ROT>(m_scalar[2]), + Botan::rotl<ROT>(m_scalar[3])); +#endif + } + + /** + * Right rotation by a compile time constant + */ + template<size_t ROT> + SIMD_4x32 rotr() const + { + return this->rotl<32-ROT>(); + } + + /** + * Add elements of a SIMD vector + */ + SIMD_4x32 operator+(const SIMD_4x32& other) const + { + SIMD_4x32 retval(*this); + retval += other; + return retval; + } + + /** + * Subtract elements of a SIMD vector + */ + SIMD_4x32 operator-(const SIMD_4x32& other) const + { + SIMD_4x32 retval(*this); + retval -= other; + return retval; + } + + /** + * XOR elements of a SIMD vector + */ + SIMD_4x32 operator^(const SIMD_4x32& other) const + { + SIMD_4x32 retval(*this); + retval ^= other; + return retval; + } + + /** + * Binary OR elements of a SIMD vector + */ + SIMD_4x32 operator|(const SIMD_4x32& other) const + { + SIMD_4x32 retval(*this); + retval |= other; + return retval; + } + + /** + * Binary AND elements of a SIMD vector + */ + SIMD_4x32 operator&(const SIMD_4x32& other) const + { + SIMD_4x32 retval(*this); + retval &= other; + return retval; + } + + void operator+=(const SIMD_4x32& other) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_sse = _mm_add_epi32(m_sse, other.m_sse); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_vmx = vec_add(m_vmx, other.m_vmx); +#elif defined(BOTAN_SIMD_USE_NEON) + m_neon = vaddq_u32(m_neon, other.m_neon); +#else + m_scalar[0] += other.m_scalar[0]; + m_scalar[1] += other.m_scalar[1]; + m_scalar[2] += other.m_scalar[2]; + m_scalar[3] += other.m_scalar[3]; +#endif + } + + void operator-=(const SIMD_4x32& other) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_sse = _mm_sub_epi32(m_sse, other.m_sse); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_vmx = vec_sub(m_vmx, other.m_vmx); +#elif defined(BOTAN_SIMD_USE_NEON) + m_neon = vsubq_u32(m_neon, other.m_neon); +#else + m_scalar[0] -= other.m_scalar[0]; + m_scalar[1] -= other.m_scalar[1]; + m_scalar[2] -= other.m_scalar[2]; + m_scalar[3] -= other.m_scalar[3]; +#endif + } + + void operator^=(const SIMD_4x32& other) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_sse = _mm_xor_si128(m_sse, other.m_sse); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_vmx = vec_xor(m_vmx, other.m_vmx); +#elif defined(BOTAN_SIMD_USE_NEON) + m_neon = veorq_u32(m_neon, other.m_neon); +#else + m_scalar[0] ^= other.m_scalar[0]; + m_scalar[1] ^= other.m_scalar[1]; + m_scalar[2] ^= other.m_scalar[2]; + m_scalar[3] ^= other.m_scalar[3]; +#endif + } + + void operator|=(const SIMD_4x32& other) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_sse = _mm_or_si128(m_sse, other.m_sse); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_vmx = vec_or(m_vmx, other.m_vmx); +#elif defined(BOTAN_SIMD_USE_NEON) + m_neon = vorrq_u32(m_neon, other.m_neon); +#else + m_scalar[0] |= other.m_scalar[0]; + m_scalar[1] |= other.m_scalar[1]; + m_scalar[2] |= other.m_scalar[2]; + m_scalar[3] |= other.m_scalar[3]; +#endif + } + + void operator&=(const SIMD_4x32& other) + { +#if defined(BOTAN_SIMD_USE_SSE2) + m_sse = _mm_and_si128(m_sse, other.m_sse); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + m_vmx = vec_and(m_vmx, other.m_vmx); +#elif defined(BOTAN_SIMD_USE_NEON) + m_neon = vandq_u32(m_neon, other.m_neon); +#else + m_scalar[0] &= other.m_scalar[0]; + m_scalar[1] &= other.m_scalar[1]; + m_scalar[2] &= other.m_scalar[2]; + m_scalar[3] &= other.m_scalar[3]; +#endif + } + + + template<int SHIFT> SIMD_4x32 shl() const + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_slli_epi32(m_sse, SHIFT)); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const unsigned int s = static_cast<unsigned int>(SHIFT); + return SIMD_4x32(vec_sl(m_vmx, (__vector unsigned int){s, s, s, s})); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vshlq_n_u32(m_neon, SHIFT)); +#else + return SIMD_4x32(m_scalar[0] << SHIFT, + m_scalar[1] << SHIFT, + m_scalar[2] << SHIFT, + m_scalar[3] << SHIFT); +#endif + } + + template<int SHIFT> SIMD_4x32 shr() const + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_srli_epi32(m_sse, SHIFT)); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const unsigned int s = static_cast<unsigned int>(SHIFT); + return SIMD_4x32(vec_sr(m_vmx, (__vector unsigned int){s, s, s, s})); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vshrq_n_u32(m_neon, SHIFT)); +#else + return SIMD_4x32(m_scalar[0] >> SHIFT, m_scalar[1] >> SHIFT, + m_scalar[2] >> SHIFT, m_scalar[3] >> SHIFT); + +#endif + } + + SIMD_4x32 operator~() const + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_xor_si128(m_sse, _mm_set1_epi32(0xFFFFFFFF))); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + return SIMD_4x32(vec_nor(m_vmx, m_vmx)); +#elif defined(BOTAN_SIMD_USE_NEON) + return SIMD_4x32(vmvnq_u32(m_neon)); +#else + return SIMD_4x32(~m_scalar[0], ~m_scalar[1], ~m_scalar[2], ~m_scalar[3]); +#endif + } + + // (~reg) & other + SIMD_4x32 andc(const SIMD_4x32& other) const + { +#if defined(BOTAN_SIMD_USE_SSE2) + return SIMD_4x32(_mm_andnot_si128(m_sse, other.m_sse)); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + /* + AltiVec does arg1 & ~arg2 rather than SSE's ~arg1 & arg2 + so swap the arguments + */ + return SIMD_4x32(vec_andc(other.m_vmx, m_vmx)); +#elif defined(BOTAN_SIMD_USE_NEON) + // NEON is also a & ~b + return SIMD_4x32(vbicq_u32(other.m_neon, m_neon)); +#else + return SIMD_4x32((~m_scalar[0]) & other.m_scalar[0], + (~m_scalar[1]) & other.m_scalar[1], + (~m_scalar[2]) & other.m_scalar[2], + (~m_scalar[3]) & other.m_scalar[3]); +#endif + } + + /** + * Return copy *this with each word byte swapped + */ + SIMD_4x32 bswap() const + { +#if defined(BOTAN_SIMD_USE_SSE2) + + __m128i T = m_sse; + T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1)); + return SIMD_4x32(_mm_or_si128(_mm_srli_epi16(T, 8), _mm_slli_epi16(T, 8))); + +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + + union { + __vector unsigned int V; + uint32_t R[4]; + } vec; + + vec.V = m_vmx; + bswap_4(vec.R); + return SIMD_4x32(vec.R[0], vec.R[1], vec.R[2], vec.R[3]); + +#elif defined(BOTAN_SIMD_USE_NEON) + + //return SIMD_4x32(vrev64q_u32(m_neon)); + + // FIXME this is really slow + SIMD_4x32 ror8 = this->rotr<8>(); + SIMD_4x32 rol8 = this->rotl<8>(); + + const SIMD_4x32 mask1 = SIMD_4x32::splat(0xFF00FF00); + const SIMD_4x32 mask2 = SIMD_4x32::splat(0x00FF00FF); + return (ror8 & mask1) | (rol8 & mask2); +#else + // scalar + return SIMD_4x32(reverse_bytes(m_scalar[0]), + reverse_bytes(m_scalar[1]), + reverse_bytes(m_scalar[2]), + reverse_bytes(m_scalar[3])); +#endif + } + + /** + * 4x4 Transposition on SIMD registers + */ + static void transpose(SIMD_4x32& B0, SIMD_4x32& B1, + SIMD_4x32& B2, SIMD_4x32& B3) + { +#if defined(BOTAN_SIMD_USE_SSE2) + const __m128i T0 = _mm_unpacklo_epi32(B0.m_sse, B1.m_sse); + const __m128i T1 = _mm_unpacklo_epi32(B2.m_sse, B3.m_sse); + const __m128i T2 = _mm_unpackhi_epi32(B0.m_sse, B1.m_sse); + const __m128i T3 = _mm_unpackhi_epi32(B2.m_sse, B3.m_sse); + + B0.m_sse = _mm_unpacklo_epi64(T0, T1); + B1.m_sse = _mm_unpackhi_epi64(T0, T1); + B2.m_sse = _mm_unpacklo_epi64(T2, T3); + B3.m_sse = _mm_unpackhi_epi64(T2, T3); +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + const __vector unsigned int T0 = vec_mergeh(B0.m_vmx, B2.m_vmx); + const __vector unsigned int T1 = vec_mergeh(B1.m_vmx, B3.m_vmx); + const __vector unsigned int T2 = vec_mergel(B0.m_vmx, B2.m_vmx); + const __vector unsigned int T3 = vec_mergel(B1.m_vmx, B3.m_vmx); + + B0.m_vmx = vec_mergeh(T0, T1); + B1.m_vmx = vec_mergel(T0, T1); + B2.m_vmx = vec_mergeh(T2, T3); + B3.m_vmx = vec_mergel(T2, T3); +#elif defined(BOTAN_SIMD_USE_NEON) + +#if defined(BOTAN_TARGET_ARCH_IS_ARM32) + + const uint32x4x2_t T0 = vzipq_u32(B0.m_neon, B2.m_neon); + const uint32x4x2_t T1 = vzipq_u32(B1.m_neon, B3.m_neon); + const uint32x4x2_t O0 = vzipq_u32(T0.val[0], T1.val[0]); + const uint32x4x2_t O1 = vzipq_u32(T0.val[1], T1.val[1]); + + B0.m_neon = O0.val[0]; + B1.m_neon = O0.val[1]; + B2.m_neon = O1.val[0]; + B3.m_neon = O1.val[1]; + +#elif defined(BOTAN_TARGET_ARCH_IS_ARM64) + const uint32x4_t T0 = vzip1q_u32(B0.m_neon, B2.m_neon); + const uint32x4_t T2 = vzip2q_u32(B0.m_neon, B2.m_neon); + + const uint32x4_t T1 = vzip1q_u32(B1.m_neon, B3.m_neon); + const uint32x4_t T3 = vzip2q_u32(B1.m_neon, B3.m_neon); + + B0.m_neon = vzip1q_u32(T0, T1); + B1.m_neon = vzip2q_u32(T0, T1); + + B2.m_neon = vzip1q_u32(T2, T3); + B3.m_neon = vzip2q_u32(T2, T3); +#endif + +#else + // scalar + SIMD_4x32 T0(B0.m_scalar[0], B1.m_scalar[0], B2.m_scalar[0], B3.m_scalar[0]); + SIMD_4x32 T1(B0.m_scalar[1], B1.m_scalar[1], B2.m_scalar[1], B3.m_scalar[1]); + SIMD_4x32 T2(B0.m_scalar[2], B1.m_scalar[2], B2.m_scalar[2], B3.m_scalar[2]); + SIMD_4x32 T3(B0.m_scalar[3], B1.m_scalar[3], B2.m_scalar[3], B3.m_scalar[3]); + + B0 = T0; + B1 = T1; + B2 = T2; + B3 = T3; +#endif + } + + private: + +#if defined(BOTAN_SIMD_USE_SSE2) + explicit SIMD_4x32(__m128i in) : m_sse(in) {} +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + explicit SIMD_4x32(__vector unsigned int in) : m_vmx(in) {} +#elif defined(BOTAN_SIMD_USE_NEON) + explicit SIMD_4x32(uint32x4_t in) : m_neon(in) {} +#endif + +#if defined(BOTAN_SIMD_USE_SSE2) + __m128i m_sse; +#elif defined(BOTAN_SIMD_USE_ALTIVEC) + __vector unsigned int m_vmx; +#elif defined(BOTAN_SIMD_USE_NEON) + uint32x4_t m_neon; +#else + uint32_t m_scalar[4]; +#endif + }; + +typedef SIMD_4x32 SIMD_32; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/stl_compatibility.h b/src/libs/3rdparty/botan/src/lib/utils/stl_compatibility.h new file mode 100644 index 0000000000..099af83b38 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/stl_compatibility.h @@ -0,0 +1,77 @@ +/* +* STL standards compatibility functions +* (C) 2017 Tomasz Frydrych +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STL_COMPATIBILITY_H_ +#define BOTAN_STL_COMPATIBILITY_H_ + +#include <memory> + +#if __cplusplus < 201402L +#include <cstddef> +#include <type_traits> +#include <utility> +#endif + +namespace Botan +{ +/* +* std::make_unique functionality similar as we have in C++14. +* C++11 version based on proposal for C++14 implemenatation by Stephan T. Lavavej +* source: https://isocpp.org/files/papers/N3656.txt +*/ +#if __cplusplus >= 201402L +template <typename T, typename ... Args> +constexpr auto make_unique(Args&&... args) + { + return std::make_unique<T>(std::forward<Args>(args)...); + } + +template<class T> +constexpr auto make_unique(std::size_t size) + { + return std::make_unique<T>(size); + } + +#else +namespace stlCompatibilityDetails +{ +template<class T> struct _Unique_if + { + typedef std::unique_ptr<T> _Single_object; + }; + +template<class T> struct _Unique_if<T[]> + { + typedef std::unique_ptr<T[]> _Unknown_bound; + }; + +template<class T, size_t N> struct _Unique_if<T[N]> + { + typedef void _Known_bound; + }; +} // namespace stlCompatibilityDetails + +template<class T, class... Args> +typename stlCompatibilityDetails::_Unique_if<T>::_Single_object make_unique(Args&&... args) + { + return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); + } + +template<class T> +typename stlCompatibilityDetails::_Unique_if<T>::_Unknown_bound make_unique(size_t n) + { + typedef typename std::remove_extent<T>::type U; + return std::unique_ptr<T>(new U[n]()); + } + +template<class T, class... Args> +typename stlCompatibilityDetails::_Unique_if<T>::_Known_bound make_unique(Args&&...) = delete; + +#endif + +} // namespace Botan +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/stl_util.h b/src/libs/3rdparty/botan/src/lib/utils/stl_util.h new file mode 100644 index 0000000000..d9167bb7db --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/stl_util.h @@ -0,0 +1,110 @@ +/* +* STL Utility Functions +* (C) 1999-2007 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STL_UTIL_H_ +#define BOTAN_STL_UTIL_H_ + +#include <vector> +#include <string> +#include <map> +#include <set> +#include <botan/secmem.h> + +namespace Botan { + +inline std::vector<uint8_t> to_byte_vector(const std::string& s) + { + return std::vector<uint8_t>(s.cbegin(), s.cend()); + } + +inline std::string to_string(const secure_vector<uint8_t> &bytes) + { + return std::string(bytes.cbegin(), bytes.cend()); + } + +/** +* Return the keys of a map as a std::set +*/ +template<typename K, typename V> +std::set<K> map_keys_as_set(const std::map<K, V>& kv) + { + std::set<K> s; + for(auto&& i : kv) + { + s.insert(i.first); + } + return s; + } + +/* +* Searching through a std::map +* @param mapping the map to search +* @param key is what to look for +* @param null_result is the value to return if key is not in mapping +* @return mapping[key] or null_result +*/ +template<typename K, typename V> +inline V search_map(const std::map<K, V>& mapping, + const K& key, + const V& null_result = V()) + { + auto i = mapping.find(key); + if(i == mapping.end()) + return null_result; + return i->second; + } + +template<typename K, typename V, typename R> +inline R search_map(const std::map<K, V>& mapping, const K& key, + const R& null_result, const R& found_result) + { + auto i = mapping.find(key); + if(i == mapping.end()) + return null_result; + return found_result; + } + +/* +* Insert a key/value pair into a multimap +*/ +template<typename K, typename V> +void multimap_insert(std::multimap<K, V>& multimap, + const K& key, const V& value) + { + multimap.insert(std::make_pair(key, value)); + } + +/** +* Existence check for values +*/ +template<typename T> +bool value_exists(const std::vector<T>& vec, + const T& val) + { + for(size_t i = 0; i != vec.size(); ++i) + if(vec[i] == val) + return true; + return false; + } + +template<typename T, typename Pred> +void map_remove_if(Pred pred, T& assoc) + { + auto i = assoc.begin(); + while(i != assoc.end()) + { + if(pred(i->first)) + assoc.erase(i++); + else + i++; + } + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/types.h b/src/libs/3rdparty/botan/src/lib/utils/types.h new file mode 100644 index 0000000000..51f0e3bc37 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/types.h @@ -0,0 +1,109 @@ +/* +* Low Level Types +* (C) 1999-2007 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TYPES_H_ +#define BOTAN_TYPES_H_ + +#include <botan/build.h> // IWYU pragma: export +#include <botan/assert.h> // IWYU pragma: export +#include <cstddef> // IWYU pragma: export +#include <cstdint> // IWYU pragma: export +#include <memory> // IWYU pragma: export + +namespace Botan { + +/** +* @mainpage Botan Crypto Library API Reference +* +* <dl> +* <dt>Abstract Base Classes<dd> +* BlockCipher, HashFunction, KDF, MessageAuthenticationCode, RandomNumberGenerator, +* StreamCipher, SymmetricAlgorithm, AEAD_Mode, Cipher_Mode +* <dt>Public Key Interface Classes<dd> +* PK_Key_Agreement, PK_Signer, PK_Verifier, PK_Encryptor, PK_Decryptor +* <dt>Authenticated Encryption Modes<dd> +* @ref CCM_Mode "CCM", @ref ChaCha20Poly1305_Mode "ChaCha20Poly1305", @ref EAX_Mode "EAX", +* @ref GCM_Mode "GCM", @ref OCB_Mode "OCB", @ref SIV_Mode "SIV" +* <dt>Block Ciphers<dd> +* @ref aria.h "ARIA", @ref aes.h "AES", @ref Blowfish, @ref camellia.h "Camellia", @ref Cascade_Cipher "Cascade", +* @ref CAST_128 "CAST-128", @ref CAST_128 "CAST-256", DES, @ref DESX "DES-X", @ref TripleDES "3DES", +* @ref GOST_28147_89 "GOST 28147-89", IDEA, KASUMI, Lion, MISTY1, Noekeon, SEED, Serpent, SHACAL2, SM4, +* @ref Threefish_512 "Threefish", Twofish, XTEA +* <dt>Stream Ciphers<dd> +* ChaCha, @ref CTR_BE "CTR", OFB, RC4, Salsa20 +* <dt>Hash Functions<dd> +* Blake2b, @ref GOST_34_11 "GOST 34.11", @ref Keccak_1600 "Keccak", MD4, MD5, @ref RIPEMD_160 "RIPEMD-160", +* @ref SHA_160 "SHA-1", @ref SHA_224 "SHA-224", @ref SHA_256 "SHA-256", @ref SHA_384 "SHA-384", +* @ref SHA_512 "SHA-512", @ref Skein_512 "Skein-512", SM3, Streebog, Tiger, Whirlpool +* <dt>Non-Cryptographic Checksums<dd> +* Adler32, CRC24, CRC32 +* <dt>Message Authentication Codes<dd> +* @ref CBC_MAC "CBC-MAC", CMAC, HMAC, Poly1305, SipHash, ANSI_X919_MAC +* <dt>Random Number Generators<dd> +* AutoSeeded_RNG, HMAC_DRBG, RDRAND_RNG, System_RNG +* <dt>Key Derivation<dd> +* HKDF, @ref KDF1 "KDF1 (IEEE 1363)", @ref KDF1_18033 "KDF1 (ISO 18033-2)", @ref KDF2 "KDF2 (IEEE 1363)", +* @ref sp800_108.h "SP800-108", @ref SP800_56C "SP800-56C", @ref PKCS5_PBKDF1 "PBKDF1 (PKCS#5), +* @ref PKCS5_PBKDF2 "PBKDF2 (PKCS#5)" +* <dt>Password Hashing<dd> +* @ref bcrypt.h "bcrypt", @ref passhash9.h "passhash9" +* <dt>Public Key Cryptosystems<dd> +* @ref dlies.h "DLIES", @ref ecies.h "ECIES", @ref elgamal.h "ElGamal" +* @ref rsa.h "RSA", @ref newhope.h "NewHope", @ref mceliece.h "McEliece" and @ref mceies.h "MCEIES", +* @ref sm2_enc.h "SM2" +* <dt>Public Key Signature Schemes<dd> +* @ref dsa.h "DSA", @ref ecdsa.h "ECDSA", @ref ecgdsa.h "ECGDSA", @ref eckcdsa.h "ECKCDSA", +* @ref gost_3410.h "GOST 34.10-2001", @ref sm2.h "SM2", @ref xmss.h "XMSS" +* <dt>Key Agreement<dd> +* @ref dh.h "DH", @ref ecdh.h "ECDH" +* <dt>Compression<dd> +* @ref bzip2.h "bzip2", @ref lzma.h "lzma", @ref zlib.h "zlib" +* <dt>TLS<dd> +* TLS::Client, TLS::Server, TLS::Policy, TLS::Protocol_Version, TLS::Callbacks, TLS::Ciphersuite, +* TLS::Session, TLS::Session_Manager, Credentials_Manager +* <dt>X.509<dd> +* X509_Certificate, X509_CRL, X509_CA, Certificate_Extension, PKCS10_Request, X509_Cert_Options, +* Certificate_Store, Certificate_Store_In_SQL, Certificate_Store_In_SQLite +* </dl> +*/ + +using std::uint8_t; +using std::uint16_t; +using std::uint32_t; +using std::uint64_t; +using std::int32_t; +using std::int64_t; +using std::size_t; + +/* +* These typedefs are no longer used within the library headers +* or code. They are kept only for compatability with software +* written against older versions. +*/ +using byte = std::uint8_t; +using u16bit = std::uint16_t; +using u32bit = std::uint32_t; +using u64bit = std::uint64_t; +using s32bit = std::int32_t; + +#if (BOTAN_MP_WORD_BITS == 8) + typedef uint8_t word; +#elif (BOTAN_MP_WORD_BITS == 16) + typedef uint16_t word; +#elif (BOTAN_MP_WORD_BITS == 32) + typedef uint32_t word; +#elif (BOTAN_MP_WORD_BITS == 64) + typedef uint64_t word; +#else + #error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 +#endif + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/utils/version.cpp b/src/libs/3rdparty/botan/src/lib/utils/version.cpp new file mode 100644 index 0000000000..ccf83bf6cb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/version.cpp @@ -0,0 +1,92 @@ +/* +* Version Information +* (C) 1999-2013,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/version.h> +#include <sstream> + +namespace Botan { + +/* + These are intentionally compiled rather than inlined, so an + application running against a shared library can test the true + version they are running against. +*/ + +#define QUOTE(name) #name +#define STR(macro) QUOTE(macro) + +const char* short_version_cstr() + { + return STR(BOTAN_VERSION_MAJOR) "." + STR(BOTAN_VERSION_MINOR) "." + STR(BOTAN_VERSION_PATCH); + } + +const char* version_cstr() + { + + /* + It is intentional that this string is a compile-time constant; + it makes it much easier to find in binaries. + */ + + return "Botan " STR(BOTAN_VERSION_MAJOR) "." + STR(BOTAN_VERSION_MINOR) "." + STR(BOTAN_VERSION_PATCH) " (" +#if defined(BOTAN_UNSAFE_FUZZER_MODE) + "UNSAFE FUZZER MODE BUILD " +#endif + BOTAN_VERSION_RELEASE_TYPE +#if (BOTAN_VERSION_DATESTAMP != 0) + ", dated " STR(BOTAN_VERSION_DATESTAMP) +#endif + ", revision " BOTAN_VERSION_VC_REVISION + ", distribution " BOTAN_DISTRIBUTION_INFO ")"; + } + +#undef STR +#undef QUOTE + +/* +* Return the version as a string +*/ +std::string version_string() + { + return std::string(version_cstr()); + } + +std::string short_version_string() + { + return std::string(short_version_cstr()); + } + +uint32_t version_datestamp() { return BOTAN_VERSION_DATESTAMP; } + +/* +* Return parts of the version as integers +*/ +uint32_t version_major() { return BOTAN_VERSION_MAJOR; } +uint32_t version_minor() { return BOTAN_VERSION_MINOR; } +uint32_t version_patch() { return BOTAN_VERSION_PATCH; } + +std::string runtime_version_check(uint32_t major, + uint32_t minor, + uint32_t patch) + { + if(major != version_major() || minor != version_minor() || patch != version_patch()) + { + std::ostringstream oss; + oss << "Warning: linked version (" << short_version_string() << ")" + << " does not match version built against " + << "(" << major << '.' << minor << '.' << patch << ")\n"; + return oss.str(); + } + + return ""; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/utils/version.h b/src/libs/3rdparty/botan/src/lib/utils/version.h new file mode 100644 index 0000000000..fe59de625c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/utils/version.h @@ -0,0 +1,101 @@ +/* +* Version Information +* (C) 1999-2011,2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_VERSION_H_ +#define BOTAN_VERSION_H_ + +#include <botan/types.h> +#include <string> + +namespace Botan { + +/* +* Get information describing the version +*/ + +/** +* Get a human-readable string identifying the version of Botan. +* No particular format should be assumed. +* @return version string +*/ +BOTAN_PUBLIC_API(2,0) std::string version_string(); + +/** +* Same as version_string() except returning a pointer to a statically +* allocated string. +* @return version string +*/ +BOTAN_PUBLIC_API(2,0) const char* version_cstr(); + +/** +* Return a version string of the form "MAJOR.MINOR.PATCH" where +* each of the values is an integer. +*/ +BOTAN_PUBLIC_API(2,4) std::string short_version_string(); + +/** +* Same as version_short_string except returning a pointer to the string. +*/ +BOTAN_PUBLIC_API(2,4) const char* short_version_cstr(); + +/** +* Return the date this version of botan was released, in an integer of +* the form YYYYMMDD. For instance a version released on May 21, 2013 +* would return the integer 20130521. If the currently running version +* is not an official release, this function will return 0 instead. +* +* @return release date, or zero if unreleased +*/ +BOTAN_PUBLIC_API(2,0) uint32_t version_datestamp(); + +/** +* Get the major version number. +* @return major version number +*/ +BOTAN_PUBLIC_API(2,0) uint32_t version_major(); + +/** +* Get the minor version number. +* @return minor version number +*/ +BOTAN_PUBLIC_API(2,0) uint32_t version_minor(); + +/** +* Get the patch number. +* @return patch number +*/ +BOTAN_PUBLIC_API(2,0) uint32_t version_patch(); + +/** +* Usable for checking that the DLL version loaded at runtime exactly +* matches the compile-time version. Call using BOTAN_VERSION_* macro +* values. Returns the empty string if an exact match, otherwise an +* appropriate message. Added with 1.11.26. +*/ +BOTAN_PUBLIC_API(2,0) std::string +runtime_version_check(uint32_t major, + uint32_t minor, + uint32_t patch); + +/* +* Macros for compile-time version checks +*/ +#define BOTAN_VERSION_CODE_FOR(a,b,c) ((a << 16) | (b << 8) | (c)) + +/** +* Compare using BOTAN_VERSION_CODE_FOR, as in +* # if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,8,0) +* # error "Botan version too old" +* # endif +*/ +#define BOTAN_VERSION_CODE BOTAN_VERSION_CODE_FOR(BOTAN_VERSION_MAJOR, \ + BOTAN_VERSION_MINOR, \ + BOTAN_VERSION_PATCH) + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/asn1_alt_name.cpp b/src/libs/3rdparty/botan/src/lib/x509/asn1_alt_name.cpp new file mode 100644 index 0000000000..4e052ca588 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/asn1_alt_name.cpp @@ -0,0 +1,248 @@ +/* +* AlternativeName +* (C) 1999-2007 Jack Lloyd +* 2007 Yves Jerschow +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/asn1_alt_name.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/oids.h> +#include <botan/internal/stl_util.h> +#include <botan/parsing.h> +#include <botan/loadstor.h> +#include <botan/x509_dn.h> + +#include <sstream> + +namespace Botan { + +/* +* Create an AlternativeName +*/ +AlternativeName::AlternativeName(const std::string& email_addr, + const std::string& uri, + const std::string& dns, + const std::string& ip) + { + add_attribute("RFC822", email_addr); + add_attribute("DNS", dns); + add_attribute("URI", uri); + add_attribute("IP", ip); + } + +/* +* Add an attribute to an alternative name +*/ +void AlternativeName::add_attribute(const std::string& type, + const std::string& value) + { + if(type.empty() || value.empty()) + return; + + auto range = m_alt_info.equal_range(type); + for(auto j = range.first; j != range.second; ++j) + if(j->second == value) + return; + + multimap_insert(m_alt_info, type, value); + } + +/* +* Add an OtherName field +*/ +void AlternativeName::add_othername(const OID& oid, const std::string& value, + ASN1_Tag type) + { + if(value.empty()) + return; + multimap_insert(m_othernames, oid, ASN1_String(value, type)); + } + +/* +* Return all of the alternative names +*/ +std::multimap<std::string, std::string> AlternativeName::contents() const + { + std::multimap<std::string, std::string> names; + + for(auto i = m_alt_info.begin(); i != m_alt_info.end(); ++i) + multimap_insert(names, i->first, i->second); + + for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i) + multimap_insert(names, OIDS::lookup(i->first), i->second.value()); + + return names; + } + +bool AlternativeName::has_field(const std::string& attr) const + { + auto range = m_alt_info.equal_range(attr); + return (range.first != range.second); + } + +std::string AlternativeName::get_first_attribute(const std::string& attr) const + { + auto i = m_alt_info.lower_bound(attr); + if(i != m_alt_info.end() && i->first == attr) + return i->second; + + return ""; + } + +std::vector<std::string> AlternativeName::get_attribute(const std::string& attr) const + { + std::vector<std::string> results; + auto range = m_alt_info.equal_range(attr); + for(auto i = range.first; i != range.second; ++i) + results.push_back(i->second); + return results; + } + +/* +* Return if this object has anything useful +*/ +bool AlternativeName::has_items() const + { + return (m_alt_info.size() > 0 || m_othernames.size() > 0); + } + +namespace { + +/* +* DER encode an AlternativeName entry +*/ +void encode_entries(DER_Encoder& encoder, + const std::multimap<std::string, std::string>& attr, + const std::string& type, ASN1_Tag tagging) + { + auto range = attr.equal_range(type); + + for(auto i = range.first; i != range.second; ++i) + { + if(type == "RFC822" || type == "DNS" || type == "URI") + { + ASN1_String asn1_string(i->second, IA5_STRING); + encoder.add_object(tagging, CONTEXT_SPECIFIC, asn1_string.value()); + } + else if(type == "IP") + { + const uint32_t ip = string_to_ipv4(i->second); + uint8_t ip_buf[4] = { 0 }; + store_be(ip, ip_buf); + encoder.add_object(tagging, CONTEXT_SPECIFIC, ip_buf, 4); + } + else if (type == "DN") + { + std::stringstream ss(i->second); + X509_DN dn; + ss >> dn; + encoder.encode(dn); + } + } + } + +} + +/* +* DER encode an AlternativeName extension +*/ +void AlternativeName::encode_into(DER_Encoder& der) const + { + der.start_cons(SEQUENCE); + + encode_entries(der, m_alt_info, "RFC822", ASN1_Tag(1)); + encode_entries(der, m_alt_info, "DNS", ASN1_Tag(2)); + encode_entries(der, m_alt_info, "DN", ASN1_Tag(4)); + encode_entries(der, m_alt_info, "URI", ASN1_Tag(6)); + encode_entries(der, m_alt_info, "IP", ASN1_Tag(7)); + + for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i) + { + der.start_explicit(0) + .encode(i->first) + .start_explicit(0) + .encode(i->second) + .end_explicit() + .end_explicit(); + } + + der.end_cons(); + } + +/* +* Decode a BER encoded AlternativeName +*/ +void AlternativeName::decode_from(BER_Decoder& source) + { + BER_Decoder names = source.start_cons(SEQUENCE); + + // FIXME this is largely a duplication of GeneralName::decode_from + + while(names.more_items()) + { + BER_Object obj = names.get_next_object(); + + if(obj.is_a(0, CONTEXT_SPECIFIC)) + { + BER_Decoder othername(obj); + + OID oid; + othername.decode(oid); + if(othername.more_items()) + { + BER_Object othername_value_outer = othername.get_next_object(); + othername.verify_end(); + + if(othername_value_outer.is_a(0, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false) + throw Decoding_Error("Invalid tags on otherName value"); + + BER_Decoder othername_value_inner(othername_value_outer); + + BER_Object value = othername_value_inner.get_next_object(); + othername_value_inner.verify_end(); + + if(ASN1_String::is_string_type(value.type()) && value.get_class() == UNIVERSAL) + { + add_othername(oid, ASN1::to_string(value), value.type()); + } + } + } + if(obj.is_a(1, CONTEXT_SPECIFIC)) + { + add_attribute("RFC822", ASN1::to_string(obj)); + } + else if(obj.is_a(2, CONTEXT_SPECIFIC)) + { + add_attribute("DNS", ASN1::to_string(obj)); + } + else if(obj.is_a(6, CONTEXT_SPECIFIC)) + { + add_attribute("URI", ASN1::to_string(obj)); + } + else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED))) + { + BER_Decoder dec(obj); + X509_DN dn; + std::stringstream ss; + + dec.decode(dn); + ss << dn; + + add_attribute("DN", ss.str()); + } + else if(obj.is_a(7, CONTEXT_SPECIFIC)) + { + if(obj.length() == 4) + { + const uint32_t ip = load_be<uint32_t>(obj.bits(), 0); + add_attribute("IP", ipv4_to_string(ip)); + } + } + + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/asn1_alt_name.h b/src/libs/3rdparty/botan/src/lib/x509/asn1_alt_name.h new file mode 100644 index 0000000000..83ac215baa --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/asn1_alt_name.h @@ -0,0 +1,60 @@ +/* +* (C) 1999-2007 Jack Lloyd +* 2007 Yves Jerschow +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_ALT_NAME_H_ +#define BOTAN_X509_ALT_NAME_H_ + +#include <botan/asn1_obj.h> +#include <botan/asn1_str.h> +#include <botan/asn1_oid.h> +#include <map> + +namespace Botan { + +/** +* Alternative Name +*/ +class BOTAN_PUBLIC_API(2,0) AlternativeName final : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + std::multimap<std::string, std::string> contents() const; + + bool has_field(const std::string& attr) const; + std::vector<std::string> get_attribute(const std::string& attr) const; + + std::string get_first_attribute(const std::string& attr) const; + + void add_attribute(const std::string& type, const std::string& value); + void add_othername(const OID& oid, const std::string& value, ASN1_Tag type); + + const std::multimap<std::string, std::string>& get_attributes() const + { + return m_alt_info; + } + + const std::multimap<OID, ASN1_String>& get_othernames() const + { + return m_othernames; + } + + bool has_items() const; + + AlternativeName(const std::string& email_addr = "", + const std::string& uri = "", + const std::string& dns = "", + const std::string& ip_address = ""); + private: + std::multimap<std::string, std::string> m_alt_info; + std::multimap<OID, ASN1_String> m_othernames; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/cert_status.cpp b/src/libs/3rdparty/botan/src/lib/x509/cert_status.cpp new file mode 100644 index 0000000000..79bcd1b074 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/cert_status.cpp @@ -0,0 +1,122 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cert_status.h> + +namespace Botan { + +//static +const char* to_string(Certificate_Status_Code code) + { + switch(code) + { + case Certificate_Status_Code::VERIFIED: + return "Verified"; + case Certificate_Status_Code::OCSP_RESPONSE_GOOD: + return "OCSP response accepted as affirming unrevoked status for certificate"; + case Certificate_Status_Code::OCSP_SIGNATURE_OK: + return "Signature on OCSP response was found valid"; + case Certificate_Status_Code::VALID_CRL_CHECKED: + return "Valid CRL examined"; + + case Certificate_Status_Code::CERT_SERIAL_NEGATIVE: + return "Certificate serial number is negative"; + case Certificate_Status_Code::DN_TOO_LONG: + return "Distinguished name too long"; + case Certificate_Status_Code::OSCP_NO_REVOCATION_URL: + return "OCSP URL not available"; + case Certificate_Status_Code::OSCP_SERVER_NOT_AVAILABLE: + return "OSCP server not available"; + + case Certificate_Status_Code::NO_REVOCATION_DATA: + return "No revocation data"; + case Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK: + return "Signature method too weak"; + case Certificate_Status_Code::UNTRUSTED_HASH: + return "Hash function used is considered too weak for security"; + + case Certificate_Status_Code::CERT_NOT_YET_VALID: + return "Certificate is not yet valid"; + case Certificate_Status_Code::CERT_HAS_EXPIRED: + return "Certificate has expired"; + case Certificate_Status_Code::OCSP_NOT_YET_VALID: + return "OCSP is not yet valid"; + case Certificate_Status_Code::OCSP_HAS_EXPIRED: + return "OCSP response has expired"; + case Certificate_Status_Code::CRL_NOT_YET_VALID: + return "CRL response is not yet valid"; + case Certificate_Status_Code::CRL_HAS_EXPIRED: + return "CRL has expired"; + + case Certificate_Status_Code::CERT_ISSUER_NOT_FOUND: + return "Certificate issuer not found"; + case Certificate_Status_Code::CANNOT_ESTABLISH_TRUST: + return "Cannot establish trust"; + case Certificate_Status_Code::CERT_CHAIN_LOOP: + return "Loop in certificate chain"; + case Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT: + return "Certificate chain does not end in a CA certificate"; + case Certificate_Status_Code::CHAIN_NAME_MISMATCH: + return "Certificate issuer does not match subject of issuing cert"; + + case Certificate_Status_Code::POLICY_ERROR: + return "Certificate policy error"; + case Certificate_Status_Code::DUPLICATE_CERT_POLICY: + return "Certificate contains duplicate policy"; + case Certificate_Status_Code::INVALID_USAGE: + return "Certificate does not allow the requested usage"; + case Certificate_Status_Code::CERT_CHAIN_TOO_LONG: + return "Certificate chain too long"; + case Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER: + return "CA certificate not allowed to issue certs"; + case Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER: + return "CA certificate not allowed to issue CRLs"; + case Certificate_Status_Code::NO_MATCHING_CRLDP: + return "No CRL with matching distribution point for certificate"; + case Certificate_Status_Code::OCSP_CERT_NOT_LISTED: + return "OCSP cert not listed"; + case Certificate_Status_Code::OCSP_BAD_STATUS: + return "OCSP bad status"; + case Certificate_Status_Code::CERT_NAME_NOMATCH: + return "Certificate does not match provided name"; + case Certificate_Status_Code::NAME_CONSTRAINT_ERROR: + return "Certificate does not pass name constraint"; + case Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION: + return "Unknown critical extension encountered"; + case Certificate_Status_Code::DUPLICATE_CERT_EXTENSION: + return "Duplicate certificate extension encountered"; + case Certificate_Status_Code::EXT_IN_V1_V2_CERT: + return "Encountered extension in certificate with version < 3"; + case Certificate_Status_Code::OCSP_SIGNATURE_ERROR: + return "OCSP signature error"; + case Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND: + return "Unable to find certificate issusing OCSP response"; + case Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE: + return "OCSP issuer's keyusage prohibits OCSP"; + case Certificate_Status_Code::OCSP_RESPONSE_INVALID: + return "OCSP parsing valid"; + case Certificate_Status_Code::OCSP_NO_HTTP: + return "OCSP requests not available, no HTTP support compiled in"; + case Certificate_Status_Code::CERT_IS_REVOKED: + return "Certificate is revoked"; + case Certificate_Status_Code::CRL_BAD_SIGNATURE: + return "CRL bad signature"; + case Certificate_Status_Code::SIGNATURE_ERROR: + return "Signature error"; + case Certificate_Status_Code::CERT_PUBKEY_INVALID: + return "Certificate public key invalid"; + case Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN: + return "Certificate signed with unknown/unavailable algorithm"; + case Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS: + return "Certificate signature has invalid parameters"; + + // intentionally no default so we are warned if new enum values are added + } + + return nullptr; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/cert_status.h b/src/libs/3rdparty/botan/src/lib/x509/cert_status.h new file mode 100644 index 0000000000..1c3a5de890 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/cert_status.h @@ -0,0 +1,99 @@ +/* +* Path validation result enums +* (C) 2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_PATH_RESULT_H_ +#define BOTAN_X509_PATH_RESULT_H_ + +#include <botan/types.h> + +namespace Botan { + +/** +* Certificate validation status code +*/ +enum class Certificate_Status_Code { + OK = 0, + VERIFIED = 0, + + // Revocation status + OCSP_RESPONSE_GOOD = 1, + OCSP_SIGNATURE_OK = 2, + VALID_CRL_CHECKED = 3, + OCSP_NO_HTTP = 4, + + // Warnings + FIRST_WARNING_STATUS = 500, + CERT_SERIAL_NEGATIVE = 500, + DN_TOO_LONG = 501, + OSCP_NO_REVOCATION_URL = 502, + OSCP_SERVER_NOT_AVAILABLE = 503, + + // Errors + FIRST_ERROR_STATUS = 1000, + + SIGNATURE_METHOD_TOO_WEAK = 1000, + UNTRUSTED_HASH = 1001, + NO_REVOCATION_DATA = 1002, + NO_MATCHING_CRLDP = 1003, + + // Time problems + CERT_NOT_YET_VALID = 2000, + CERT_HAS_EXPIRED = 2001, + OCSP_NOT_YET_VALID = 2002, + OCSP_HAS_EXPIRED = 2003, + CRL_NOT_YET_VALID = 2004, + CRL_HAS_EXPIRED = 2005, + + // Chain generation problems + CERT_ISSUER_NOT_FOUND = 3000, + CANNOT_ESTABLISH_TRUST = 3001, + CERT_CHAIN_LOOP = 3002, + CHAIN_LACKS_TRUST_ROOT = 3003, + CHAIN_NAME_MISMATCH = 3004, + + // Validation errors + POLICY_ERROR = 4000, + INVALID_USAGE = 4001, + CERT_CHAIN_TOO_LONG = 4002, + CA_CERT_NOT_FOR_CERT_ISSUER = 4003, + NAME_CONSTRAINT_ERROR = 4004, + + // Revocation errors + CA_CERT_NOT_FOR_CRL_ISSUER = 4005, + OCSP_CERT_NOT_LISTED = 4006, + OCSP_BAD_STATUS = 4007, + + // Other problems + CERT_NAME_NOMATCH = 4008, + UNKNOWN_CRITICAL_EXTENSION = 4009, + DUPLICATE_CERT_EXTENSION = 4010, + OCSP_SIGNATURE_ERROR = 4501, + OCSP_ISSUER_NOT_FOUND = 4502, + OCSP_RESPONSE_MISSING_KEYUSAGE = 4503, + OCSP_RESPONSE_INVALID = 4504, + EXT_IN_V1_V2_CERT = 4505, + DUPLICATE_CERT_POLICY = 4506, + + // Hard failures + CERT_IS_REVOKED = 5000, + CRL_BAD_SIGNATURE = 5001, + SIGNATURE_ERROR = 5002, + CERT_PUBKEY_INVALID = 5003, + SIGNATURE_ALGO_UNKNOWN = 5004, + SIGNATURE_ALGO_BAD_PARAMS = 5005 +}; + +/** +* Convert a status code to a human readable diagnostic message +* @param code the certifcate status +* @return string literal constant, or nullptr if code unknown +*/ +BOTAN_PUBLIC_API(2,0) const char* to_string(Certificate_Status_Code code); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/certstor.cpp b/src/libs/3rdparty/botan/src/lib/x509/certstor.cpp new file mode 100644 index 0000000000..2356a70c6c --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/certstor.cpp @@ -0,0 +1,216 @@ +/* +* Certificate Store +* (C) 1999-2010,2013 Jack Lloyd +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/certstor.h> +#include <botan/internal/filesystem.h> +#include <botan/hash.h> +#include <botan/data_src.h> + +namespace Botan { + +std::shared_ptr<const X509_CRL> Certificate_Store::find_crl_for(const X509_Certificate&) const + { + return {}; + } + +void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert) + { + for(const auto& c : m_certs) + if(*c == cert) + return; + + m_certs.push_back(std::make_shared<const X509_Certificate>(cert)); + } + +void Certificate_Store_In_Memory::add_certificate(std::shared_ptr<const X509_Certificate> cert) + { + for(const auto& c : m_certs) + if(*c == *cert) + return; + + m_certs.push_back(cert); + } + +std::vector<X509_DN> Certificate_Store_In_Memory::all_subjects() const + { + std::vector<X509_DN> subjects; + for(const auto& cert : m_certs) + subjects.push_back(cert->subject_dn()); + return subjects; + } + +std::shared_ptr<const X509_Certificate> +Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn, + const std::vector<uint8_t>& key_id) const + { + for(const auto& cert : m_certs) + { + // Only compare key ids if set in both call and in the cert + if(key_id.size()) + { + std::vector<uint8_t> skid = cert->subject_key_id(); + + if(skid.size() && skid != key_id) // no match + continue; + } + + if(cert->subject_dn() == subject_dn) + return cert; + } + + return nullptr; + } + +std::vector<std::shared_ptr<const X509_Certificate>> Certificate_Store_In_Memory::find_all_certs( + const X509_DN& subject_dn, + const std::vector<uint8_t>& key_id) const + { + std::vector<std::shared_ptr<const X509_Certificate>> matches; + + for(const auto& cert : m_certs) + { + if(key_id.size()) + { + std::vector<uint8_t> skid = cert->subject_key_id(); + + if(skid.size() && skid != key_id) // no match + continue; + } + + if(cert->subject_dn() == subject_dn) + matches.push_back(cert); + } + + return matches; + } + +std::shared_ptr<const X509_Certificate> +Certificate_Store_In_Memory::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const + { + if(key_hash.size() != 20) + throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_pubkey_sha1 invalid hash"); + + std::unique_ptr<HashFunction> hash(HashFunction::create("SHA-1")); + + for(const auto& cert : m_certs){ + hash->update(cert->subject_public_key_bitstring()); + if(key_hash == hash->final_stdvec()) //final_stdvec also clears the hash to initial state + return cert; + } + + return nullptr; + } + +std::shared_ptr<const X509_Certificate> +Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const + { + if(subject_hash.size() != 32) + throw Invalid_Argument("Certificate_Store_In_Memory::find_cert_by_raw_subject_dn_sha256 invalid hash"); + + std::unique_ptr<HashFunction> hash(HashFunction::create("SHA-256")); + + for(const auto& cert : m_certs){ + hash->update(cert->raw_subject_dn()); + if(subject_hash == hash->final_stdvec()) //final_stdvec also clears the hash to initial state + return cert; + } + + return nullptr; + } + +void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl) + { + std::shared_ptr<const X509_CRL> crl_s = std::make_shared<const X509_CRL>(crl); + return add_crl(crl_s); + } + +void Certificate_Store_In_Memory::add_crl(std::shared_ptr<const X509_CRL> crl) + { + X509_DN crl_issuer = crl->issuer_dn(); + + for(auto& c : m_crls) + { + // Found an update of a previously existing one; replace it + if(c->issuer_dn() == crl_issuer) + { + if(c->this_update() <= crl->this_update()) + c = crl; + return; + } + } + + // Totally new CRL, add to the list + m_crls.push_back(crl); + } + +std::shared_ptr<const X509_CRL> Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const + { + const std::vector<uint8_t>& key_id = subject.authority_key_id(); + + for(const auto& c : m_crls) + { + // Only compare key ids if set in both call and in the CRL + if(key_id.size()) + { + std::vector<uint8_t> akid = c->authority_key_id(); + + if(akid.size() && akid != key_id) // no match + continue; + } + + if(c->issuer_dn() == subject.issuer_dn()) + return c; + } + + return {}; + } + +Certificate_Store_In_Memory::Certificate_Store_In_Memory(const X509_Certificate& cert) + { + add_certificate(cert); + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +Certificate_Store_In_Memory::Certificate_Store_In_Memory(const std::string& dir) + { + if(dir.empty()) + return; + + std::vector<std::string> maybe_certs = get_files_recursive(dir); + + if(maybe_certs.empty()) + { + maybe_certs.push_back(dir); + } + + for(auto&& cert_file : maybe_certs) + { + try + { + DataSource_Stream src(cert_file, true); + while(!src.end_of_data()) + { + try + { + m_certs.push_back(std::make_shared<X509_Certificate>(src)); + } + catch(std::exception&) + { + // stop searching for other certificate at first exception + break; + } + } + } + catch(std::exception&) + { + } + } + } +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/certstor.h b/src/libs/3rdparty/botan/src/lib/x509/certstor.h new file mode 100644 index 0000000000..36d2e4abdd --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/certstor.h @@ -0,0 +1,163 @@ +/* +* Certificate Store +* (C) 1999-2010,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CERT_STORE_H_ +#define BOTAN_CERT_STORE_H_ + +#include <botan/x509cert.h> +#include <botan/x509_crl.h> + +namespace Botan { + +/** +* Certificate Store Interface +*/ +class BOTAN_PUBLIC_API(2,0) Certificate_Store + { + public: + virtual ~Certificate_Store() = default; + + /** + * Find a certificate by Subject DN and (optionally) key identifier + * @param subject_dn the subject's distinguished name + * @param key_id an optional key id + * @return a matching certificate or nullptr otherwise + */ + virtual std::shared_ptr<const X509_Certificate> + find_cert(const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const = 0; + + /** + * Find all certificates with a given Subject DN. + * Subject DN and even the key identifier might not be unique. + */ + virtual std::vector<std::shared_ptr<const X509_Certificate>> find_all_certs( + const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const = 0; + + + /** + * Find a certificate by searching for one with a matching SHA-1 hash of + * public key. Used for OCSP. + * @param key_hash SHA-1 hash of the subject's public key + * @return a matching certificate or nullptr otherwise + */ + virtual std::shared_ptr<const X509_Certificate> + find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const = 0; + + /** + * Find a certificate by searching for one with a matching SHA-256 hash of + * raw subject name. Used for OCSP. + * @param subject_hash SHA-256 hash of the subject's raw name + * @return a matching certificate or nullptr otherwise + */ + virtual std::shared_ptr<const X509_Certificate> + find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const = 0; + + /** + * Finds a CRL for the given certificate + * @param subject the subject certificate + * @return the CRL for subject or nullptr otherwise + */ + virtual std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const; + + /** + * @return whether the certificate is known + * @param cert certififcate to be searched + */ + bool certificate_known(const X509_Certificate& cert) const + { + return find_cert(cert.subject_dn(), cert.subject_key_id()) != nullptr; + } + + // remove this (used by TLS::Server) + virtual std::vector<X509_DN> all_subjects() const = 0; + }; + +/** +* In Memory Certificate Store +*/ +class BOTAN_PUBLIC_API(2,0) Certificate_Store_In_Memory final : public Certificate_Store + { + public: + /** + * Attempt to parse all files in dir (including subdirectories) + * as certificates. Ignores errors. + */ + explicit Certificate_Store_In_Memory(const std::string& dir); + + /** + * Adds given certificate to the store. + */ + explicit Certificate_Store_In_Memory(const X509_Certificate& cert); + + /** + * Create an empty store. + */ + Certificate_Store_In_Memory() = default; + + /** + * Add a certificate to the store. + * @param cert certificate to be added + */ + void add_certificate(const X509_Certificate& cert); + + /** + * Add a certificate already in a shared_ptr to the store. + * @param cert certificate to be added + */ + void add_certificate(std::shared_ptr<const X509_Certificate> cert); + + /** + * Add a certificate revocation list (CRL) to the store. + * @param crl CRL to be added + */ + void add_crl(const X509_CRL& crl); + + /** + * Add a certificate revocation list (CRL) to the store as a shared_ptr + * @param crl CRL to be added + */ + void add_crl(std::shared_ptr<const X509_CRL> crl); + + /** + * @return DNs for all certificates managed by the store + */ + std::vector<X509_DN> all_subjects() const override; + + /* + * Find a certificate by Subject DN and (optionally) key identifier + * @return the first certificate that matches + */ + std::shared_ptr<const X509_Certificate> find_cert( + const X509_DN& subject_dn, + const std::vector<uint8_t>& key_id) const override; + + /* + * Find all certificates with a given Subject DN. + * Subject DN and even the key identifier might not be unique. + */ + std::vector<std::shared_ptr<const X509_Certificate>> find_all_certs( + const X509_DN& subject_dn, const std::vector<uint8_t>& key_id) const override; + + std::shared_ptr<const X509_Certificate> + find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const override; + + std::shared_ptr<const X509_Certificate> + find_cert_by_raw_subject_dn_sha256(const std::vector<uint8_t>& subject_hash) const override; + + /** + * Finds a CRL for the given certificate + */ + std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override; + private: + // TODO: Add indexing on the DN and key id to avoid linear search + std::vector<std::shared_ptr<const X509_Certificate>> m_certs; + std::vector<std::shared_ptr<const X509_CRL>> m_crls; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/crl_ent.cpp b/src/libs/3rdparty/botan/src/lib/x509/crl_ent.cpp new file mode 100644 index 0000000000..38a1963f1b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/crl_ent.cpp @@ -0,0 +1,140 @@ +/* +* CRL Entry +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/crl_ent.h> +#include <botan/x509cert.h> +#include <botan/x509_ext.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/bigint.h> + +namespace Botan { + +struct CRL_Entry_Data + { + std::vector<uint8_t> m_serial; + X509_Time m_time; + CRL_Code m_reason = UNSPECIFIED; + Extensions m_extensions; + }; + +/* +* Create a CRL_Entry +*/ +CRL_Entry::CRL_Entry(const X509_Certificate& cert, CRL_Code why) + { + m_data.reset(new CRL_Entry_Data); + m_data->m_serial = cert.serial_number(); + m_data->m_time = X509_Time(std::chrono::system_clock::now()); + m_data->m_reason = why; + + if(why != UNSPECIFIED) + { + m_data->m_extensions.add(new Cert_Extension::CRL_ReasonCode(why)); + } + } + +/* +* Compare two CRL_Entrys for equality +*/ +bool operator==(const CRL_Entry& a1, const CRL_Entry& a2) + { + if(a1.serial_number() != a2.serial_number()) + return false; + if(a1.expire_time() != a2.expire_time()) + return false; + if(a1.reason_code() != a2.reason_code()) + return false; + return true; + } + +/* +* Compare two CRL_Entrys for inequality +*/ +bool operator!=(const CRL_Entry& a1, const CRL_Entry& a2) + { + return !(a1 == a2); + } + +/* +* DER encode a CRL_Entry +*/ +void CRL_Entry::encode_into(DER_Encoder& der) const + { + der.start_cons(SEQUENCE) + .encode(BigInt::decode(serial_number())) + .encode(expire_time()) + .start_cons(SEQUENCE) + .encode(extensions()) + .end_cons() + .end_cons(); + } + +/* +* Decode a BER encoded CRL_Entry +*/ +void CRL_Entry::decode_from(BER_Decoder& source) + { + BigInt serial_number_bn; + + std::unique_ptr<CRL_Entry_Data> data(new CRL_Entry_Data); + + BER_Decoder entry = source.start_cons(SEQUENCE); + + entry.decode(serial_number_bn).decode(data->m_time); + data->m_serial = BigInt::encode(serial_number_bn); + + if(entry.more_items()) + { + entry.decode(data->m_extensions); + if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::CRL_ReasonCode>()) + { + data->m_reason = ext->get_reason(); + } + else + { + data->m_reason = UNSPECIFIED; + } + } + + entry.end_cons(); + + m_data.reset(data.release()); + } + +const CRL_Entry_Data& CRL_Entry::data() const + { + if(!m_data) + { + throw Invalid_State("CRL_Entry_Data uninitialized"); + } + + return *m_data.get(); + } + +const std::vector<uint8_t>& CRL_Entry::serial_number() const + { + return data().m_serial; + } + +const X509_Time& CRL_Entry::expire_time() const + { + return data().m_time; + } + +CRL_Code CRL_Entry::reason_code() const + { + return data().m_reason; + } + +const Extensions& CRL_Entry::extensions() const + { + return data().m_extensions; + } + + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/crl_ent.h b/src/libs/3rdparty/botan/src/lib/x509/crl_ent.h new file mode 100644 index 0000000000..27549251f0 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/crl_ent.h @@ -0,0 +1,104 @@ +/* +* CRL Entry +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CRL_ENTRY_H_ +#define BOTAN_CRL_ENTRY_H_ + +#include <botan/asn1_time.h> + +namespace Botan { + +class Extensions; +class X509_Certificate; +struct CRL_Entry_Data; + +/** +* X.509v2 CRL Reason Code. +*/ +enum CRL_Code : uint32_t { + UNSPECIFIED = 0, + KEY_COMPROMISE = 1, + CA_COMPROMISE = 2, + AFFILIATION_CHANGED = 3, + SUPERSEDED = 4, + CESSATION_OF_OPERATION = 5, + CERTIFICATE_HOLD = 6, + REMOVE_FROM_CRL = 8, + PRIVLEDGE_WITHDRAWN = 9, + AA_COMPROMISE = 10, + + DELETE_CRL_ENTRY = 0xFF00, + OCSP_GOOD = 0xFF01, + OCSP_UNKNOWN = 0xFF02 +}; + +/** +* This class represents CRL entries +*/ +class BOTAN_PUBLIC_API(2,0) CRL_Entry final : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + /** + * Get the serial number of the certificate associated with this entry. + * @return certificate's serial number + */ + const std::vector<uint8_t>& serial_number() const; + + /** + * Get the revocation date of the certificate associated with this entry + * @return certificate's revocation date + */ + const X509_Time& expire_time() const; + + /** + * Get the entries reason code + * @return reason code + */ + CRL_Code reason_code() const; + + /** + * Get the extensions on this CRL entry + */ + const Extensions& extensions() const; + + /** + * Create uninitialized CRL_Entry object + */ + CRL_Entry() = default; + + /** + * Construct an CRL entry. + * @param cert the certificate to revoke + * @param reason the reason code to set in the entry + */ + CRL_Entry(const X509_Certificate& cert, + CRL_Code reason = UNSPECIFIED); + + private: + friend class X509_CRL; + + const CRL_Entry_Data& data() const; + + std::shared_ptr<CRL_Entry_Data> m_data; + }; + +/** +* Test two CRL entries for equality in all fields. +*/ +BOTAN_PUBLIC_API(2,0) bool operator==(const CRL_Entry&, const CRL_Entry&); + +/** +* Test two CRL entries for inequality in at least one field. +*/ +BOTAN_PUBLIC_API(2,0) bool operator!=(const CRL_Entry&, const CRL_Entry&); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/datastor.cpp b/src/libs/3rdparty/botan/src/lib/x509/datastor.cpp new file mode 100644 index 0000000000..2cdd3458ca --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/datastor.cpp @@ -0,0 +1,205 @@ +/* +* Data Store +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/datastor.h> +#include <botan/exceptn.h> +#include <botan/parsing.h> +#include <botan/hex.h> +#include <botan/internal/stl_util.h> + +namespace Botan { + +/* +* Data_Store Equality Comparison +*/ +bool Data_Store::operator==(const Data_Store& other) const + { + return (m_contents == other.m_contents); + } + +/* +* Check if this key has at least one value +*/ +bool Data_Store::has_value(const std::string& key) const + { + return (m_contents.lower_bound(key) != m_contents.end()); + } + +/* +* Search based on an arbitrary predicate +*/ +std::multimap<std::string, std::string> Data_Store::search_for( + std::function<bool (std::string, std::string)> predicate) const + { + std::multimap<std::string, std::string> out; + + for(auto i = m_contents.begin(); i != m_contents.end(); ++i) + if(predicate(i->first, i->second)) + out.insert(std::make_pair(i->first, i->second)); + + return out; + } + +/* +* Search based on key equality +*/ +std::vector<std::string> Data_Store::get(const std::string& looking_for) const + { + std::vector<std::string> out; + auto range = m_contents.equal_range(looking_for); + for(auto i = range.first; i != range.second; ++i) + out.push_back(i->second); + return out; + } + +/* +* Get a single atom +*/ +std::string Data_Store::get1(const std::string& key) const + { + std::vector<std::string> vals = get(key); + + if(vals.empty()) + throw Invalid_State("Data_Store::get1: No values set for " + key); + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1: More than one value for " + key); + + return vals[0]; + } + +std::string Data_Store::get1(const std::string& key, + const std::string& default_value) const + { + std::vector<std::string> vals = get(key); + + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1: More than one value for " + key); + + if(vals.empty()) + return default_value; + + return vals[0]; + } + +/* +* Get a single std::vector atom +*/ +std::vector<uint8_t> +Data_Store::get1_memvec(const std::string& key) const + { + std::vector<std::string> vals = get(key); + + if(vals.empty()) + return std::vector<uint8_t>(); + + if(vals.size() > 1) + throw Invalid_State("Data_Store::get1_memvec: Multiple values for " + + key); + + return hex_decode(vals[0]); + } + +/* +* Get a single uint32_t atom +*/ +uint32_t Data_Store::get1_uint32(const std::string& key, + uint32_t default_val) const + { + std::vector<std::string> vals = get(key); + + if(vals.empty()) + return default_val; + else if(vals.size() > 1) + throw Invalid_State("Data_Store::get1_uint32: Multiple values for " + key); + + return to_u32bit(vals[0]); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, const std::string& val) + { + multimap_insert(m_contents, key, val); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, uint32_t val) + { + add(key, std::to_string(val)); + } + +/* +* Insert a single key and value +*/ +void Data_Store::add(const std::string& key, const secure_vector<uint8_t>& val) + { + add(key, hex_encode(val.data(), val.size())); + } + +void Data_Store::add(const std::string& key, const std::vector<uint8_t>& val) + { + add(key, hex_encode(val.data(), val.size())); + } + +/* +* Insert a mapping of key/value pairs +*/ +void Data_Store::add(const std::multimap<std::string, std::string>& in) + { + std::multimap<std::string, std::string>::const_iterator i = in.begin(); + while(i != in.end()) + { + m_contents.insert(*i); + ++i; + } + } + +/* +* Create and populate a X509_DN +*/ +X509_DN create_dn(const Data_Store& info) + { + auto names = info.search_for( + [](const std::string& key, const std::string&) + { + return (key.find("X520.") != std::string::npos); + }); + + X509_DN dn; + + for(auto i = names.begin(); i != names.end(); ++i) + dn.add_attribute(i->first, i->second); + + return dn; + } + +/* +* Create and populate an AlternativeName +*/ +AlternativeName create_alt_name(const Data_Store& info) + { + auto names = info.search_for( + [](const std::string& key, const std::string&) + { + return (key == "RFC822" || + key == "DNS" || + key == "URI" || + key == "IP"); + }); + + AlternativeName alt_name; + + for(auto i = names.begin(); i != names.end(); ++i) + alt_name.add_attribute(i->first, i->second); + + return alt_name; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/datastor.h b/src/libs/3rdparty/botan/src/lib/x509/datastor.h new file mode 100644 index 0000000000..ec3c5189bd --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/datastor.h @@ -0,0 +1,84 @@ +/* +* Data Store +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_DATA_STORE_H_ +#define BOTAN_DATA_STORE_H_ + +#include <botan/x509_dn.h> +#include <botan/asn1_alt_name.h> +#include <functional> +#include <string> +#include <vector> +#include <map> + +namespace Botan { + +/** +* Data Store +* +* This class is used internally by the library, and exposed for ABI +* reasons. There is no reason for applications to use this type directly. +* It will be removed in a future major release. +*/ +class BOTAN_UNSTABLE_API Data_Store final + { + public: + /** + * A search function + */ + bool operator==(const Data_Store&) const; + + std::multimap<std::string, std::string> search_for( + std::function<bool (std::string, std::string)> predicate) const; + + std::vector<std::string> get(const std::string&) const; + + std::string get1(const std::string& key) const; + + std::string get1(const std::string& key, + const std::string& default_value) const; + + std::vector<uint8_t> get1_memvec(const std::string&) const; + uint32_t get1_uint32(const std::string&, uint32_t = 0) const; + + bool has_value(const std::string&) const; + + void add(const std::multimap<std::string, std::string>&); + void add(const std::string&, const std::string&); + void add(const std::string&, uint32_t); + void add(const std::string&, const secure_vector<uint8_t>&); + void add(const std::string&, const std::vector<uint8_t>&); + private: + std::multimap<std::string, std::string> m_contents; + }; + +/* +* Data Store Extraction Operations +*/ + +/* +* Create and populate a X509_DN +* @param info data store containing DN information +* @return DN containing attributes from data store +*/ +BOTAN_PUBLIC_API(2,0) X509_DN +BOTAN_DEPRECATED("Avoid roundtripping names through Data_Store") +create_dn(const Data_Store& info); + +/* +* Create and populate an AlternativeName +* @param info data store containing AlternativeName information +* @return AlternativeName containing attributes from data store +*/ +BOTAN_PUBLIC_API(2,0) AlternativeName +BOTAN_DEPRECATED("Avoid roundtripping names through Data_Store") +create_alt_name(const Data_Store& info); + + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/info.txt b/src/libs/3rdparty/botan/src/lib/x509/info.txt new file mode 100644 index 0000000000..6b136cbcf2 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/info.txt @@ -0,0 +1,11 @@ +<defines> +X509_CERTIFICATES -> 20151023 +OCSP -> 20161118 +</defines> + +<requires> +asn1 +pubkey +sha1 +sha2_32 +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/x509/key_constraint.cpp b/src/libs/3rdparty/botan/src/lib/x509/key_constraint.cpp new file mode 100644 index 0000000000..dfadedac59 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/key_constraint.cpp @@ -0,0 +1,100 @@ +/* +* KeyUsage +* (C) 1999-2007,2016 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/key_constraint.h> +#include <botan/pk_keys.h> +#include <vector> + +namespace Botan { + +std::string key_constraints_to_string(Key_Constraints constraints) + { + std::vector<std::string> str; + + if(constraints == NO_CONSTRAINTS) + return "no_constraints"; + + if(constraints & DIGITAL_SIGNATURE) + str.push_back("digital_signature"); + + if(constraints & NON_REPUDIATION) + str.push_back("non_repudiation"); + + if(constraints & KEY_ENCIPHERMENT) + str.push_back("key_encipherment"); + + if(constraints & DATA_ENCIPHERMENT) + str.push_back("data_encipherment"); + + if(constraints & KEY_AGREEMENT) + str.push_back("key_agreement"); + + if(constraints & KEY_CERT_SIGN) + str.push_back("key_cert_sign"); + + if(constraints & CRL_SIGN) + str.push_back("crl_sign"); + + if(constraints & ENCIPHER_ONLY) + str.push_back("encipher_only"); + + if(constraints & DECIPHER_ONLY) + str.push_back("decipher_only"); + + // Not 0 (checked at start) but nothing matched above! + if(str.empty()) + return "other_unknown_constraints"; + + if(str.size() == 1) + return str[0]; + + std::string out; + for(size_t i = 0; i < str.size() - 1; ++i) + { + out += str[i]; + out += ','; + } + out += str[str.size() - 1]; + + return out; + } + +/* +* Make sure the given key constraints are permitted for the given key type +*/ +void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, + Key_Constraints constraints) + { + const std::string name = pub_key.algo_name(); + + size_t permitted = 0; + + if(name == "DH" || name == "ECDH") + { + permitted |= KEY_AGREEMENT | ENCIPHER_ONLY | DECIPHER_ONLY; + } + + if(name == "RSA" || name == "ElGamal") + { + permitted |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT; + } + + if(name == "RSA" || name == "DSA" || + name == "ECDSA" || name == "ECGDSA" || name == "ECKCDSA" || name == "GOST-34.10" || + name == "Ed25519") + { + permitted |= DIGITAL_SIGNATURE | NON_REPUDIATION | KEY_CERT_SIGN | CRL_SIGN; + } + + if((constraints & permitted) != constraints) + { + throw Exception("Invalid " + name + " constraints " + key_constraints_to_string(constraints)); + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/key_constraint.h b/src/libs/3rdparty/botan/src/lib/x509/key_constraint.h new file mode 100644 index 0000000000..3d456f6c44 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/key_constraint.h @@ -0,0 +1,49 @@ +/* +* Enumerations +* (C) 1999-2007 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ENUMS_H_ +#define BOTAN_ENUMS_H_ + +#include <botan/types.h> +#include <string> + +namespace Botan { + +/** +* X.509v3 Key Constraints. +* If updating update copy in ffi.h +*/ +enum Key_Constraints { + NO_CONSTRAINTS = 0, + DIGITAL_SIGNATURE = 1 << 15, + NON_REPUDIATION = 1 << 14, + KEY_ENCIPHERMENT = 1 << 13, + DATA_ENCIPHERMENT = 1 << 12, + KEY_AGREEMENT = 1 << 11, + KEY_CERT_SIGN = 1 << 10, + CRL_SIGN = 1 << 9, + ENCIPHER_ONLY = 1 << 8, + DECIPHER_ONLY = 1 << 7 +}; + +class Public_Key; + +/** +* Check that key constraints are permitted for a specific public key. +* @param pub_key the public key on which the constraints shall be enforced on +* @param constraints the constraints that shall be enforced on the key +* @throw Exception if the given constraints are not permitted for this key +*/ +BOTAN_PUBLIC_API(2,0) void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, + Key_Constraints constraints); + +std::string BOTAN_PUBLIC_API(2,0) key_constraints_to_string(Key_Constraints); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/name_constraint.cpp b/src/libs/3rdparty/botan/src/lib/x509/name_constraint.cpp new file mode 100644 index 0000000000..b64e04d29d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/name_constraint.cpp @@ -0,0 +1,269 @@ +/* +* X.509 Name Constraint +* (C) 2015 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/name_constraint.h> +#include <botan/asn1_alt_name.h> +#include <botan/ber_dec.h> +#include <botan/loadstor.h> +#include <botan/x509_dn.h> +#include <botan/x509cert.h> +#include <botan/parsing.h> +#include <sstream> + +namespace Botan { + +class DER_Encoder; + +GeneralName::GeneralName(const std::string& str) : GeneralName() + { + size_t p = str.find(':'); + + if(p != std::string::npos) + { + m_type = str.substr(0, p); + m_name = str.substr(p + 1, std::string::npos); + } + else + { + throw Invalid_Argument("Failed to decode Name Constraint"); + } + } + +void GeneralName::encode_into(DER_Encoder&) const + { + throw Not_Implemented("GeneralName encoding"); + } + +void GeneralName::decode_from(class BER_Decoder& ber) + { + BER_Object obj = ber.get_next_object(); + + if(obj.is_a(1, CONTEXT_SPECIFIC)) + { + m_type = "RFC822"; + m_name = ASN1::to_string(obj); + } + else if(obj.is_a(2, CONTEXT_SPECIFIC)) + { + m_type = "DNS"; + m_name = ASN1::to_string(obj); + } + else if(obj.is_a(6, CONTEXT_SPECIFIC)) + { + m_type = "URI"; + m_name = ASN1::to_string(obj); + } + else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED))) + { + m_type = "DN"; + X509_DN dn; + BER_Decoder dec(obj); + std::stringstream ss; + + dn.decode_from(dec); + ss << dn; + + m_name = ss.str(); + } + else if(obj.is_a(7, CONTEXT_SPECIFIC)) + { + if(obj.length() == 8) + { + m_type = "IP"; + m_name = ipv4_to_string(load_be<uint32_t>(obj.bits(), 0)) + "/" + + ipv4_to_string(load_be<uint32_t>(obj.bits(), 1)); + } + else if(obj.length() == 32) + { + throw Decoding_Error("Unsupported IPv6 name constraint"); + } + else + { + throw Decoding_Error("Invalid IP name constraint size " + std::to_string(obj.length())); + } + } + else + { + throw Decoding_Error("Found unknown GeneralName type"); + } + } + +GeneralName::MatchResult GeneralName::matches(const X509_Certificate& cert) const + { + std::vector<std::string> nam; + std::function<bool(const GeneralName*, const std::string&)> match_fn; + + const X509_DN& dn = cert.subject_dn(); + const AlternativeName& alt_name = cert.subject_alt_name(); + + if(type() == "DNS") + { + match_fn = std::mem_fn(&GeneralName::matches_dns); + + nam = alt_name.get_attribute("DNS"); + + if(nam.empty()) + { + nam = dn.get_attribute("CN"); + } + } + else if(type() == "DN") + { + match_fn = std::mem_fn(&GeneralName::matches_dn); + + std::stringstream ss; + ss << dn; + nam.push_back(ss.str()); + } + else if(type() == "IP") + { + match_fn = std::mem_fn(&GeneralName::matches_ip); + nam = alt_name.get_attribute("IP"); + } + else + { + return MatchResult::UnknownType; + } + + if(nam.empty()) + { + return MatchResult::NotFound; + } + + bool some = false; + bool all = true; + + for(const std::string& n: nam) + { + bool m = match_fn(this, n); + + some |= m; + all &= m; + } + + if(all) + { + return MatchResult::All; + } + else if(some) + { + return MatchResult::Some; + } + else + { + return MatchResult::None; + } + } + +bool GeneralName::matches_dns(const std::string& nam) const + { + if(nam.size() == name().size()) + { + return nam == name(); + } + else if(name().size() > nam.size()) + { + return false; + } + else // name.size() < nam.size() + { + std::string constr = name().front() == '.' ? name() : "." + name(); + // constr is suffix of nam + return constr == nam.substr(nam.size() - constr.size(), constr.size()); + } + } + +bool GeneralName::matches_dn(const std::string& nam) const + { + std::stringstream ss(nam); + std::stringstream tt(name()); + X509_DN nam_dn, my_dn; + + ss >> nam_dn; + tt >> my_dn; + + auto attr = nam_dn.get_attributes(); + bool ret = true; + size_t trys = 0; + + for(const auto& c: my_dn.dn_info()) + { + auto i = attr.equal_range(c.first); + + if(i.first != i.second) + { + trys += 1; + ret = ret && (i.first->second == c.second.value()); + } + } + + return trys > 0 && ret; + } + +bool GeneralName::matches_ip(const std::string& nam) const + { + uint32_t ip = string_to_ipv4(nam); + std::vector<std::string> p = split_on(name(), '/'); + + if(p.size() != 2) + throw Decoding_Error("failed to parse IPv4 address"); + + uint32_t net = string_to_ipv4(p.at(0)); + uint32_t mask = string_to_ipv4(p.at(1)); + + return (ip & mask) == net; + } + +std::ostream& operator<<(std::ostream& os, const GeneralName& gn) + { + os << gn.type() << ":" << gn.name(); + return os; + } + +GeneralSubtree::GeneralSubtree(const std::string& str) : GeneralSubtree() + { + size_t p0, p1; + size_t min = std::stoull(str, &p0, 10); + size_t max = std::stoull(str.substr(p0 + 1), &p1, 10); + GeneralName gn(str.substr(p0 + p1 + 2)); + + if(p0 > 0 && p1 > 0) + { + m_minimum = min; + m_maximum = max; + m_base = gn; + } + else + { + throw Invalid_Argument("Failed to decode Name Constraint"); + } + } + +void GeneralSubtree::encode_into(DER_Encoder&) const + { + throw Not_Implemented("General Subtree encoding"); + } + +void GeneralSubtree::decode_from(class BER_Decoder& ber) + { + ber.start_cons(SEQUENCE) + .decode(m_base) + .decode_optional(m_minimum,ASN1_Tag(0), CONTEXT_SPECIFIC,size_t(0)) + .end_cons(); + + if(m_minimum != 0) + throw Decoding_Error("GeneralSubtree minimum must be 0"); + + m_maximum = std::numeric_limits<std::size_t>::max(); + } + +std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs) + { + os << gs.minimum() << "," << gs.maximum() << "," << gs.base(); + return os; + } +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/name_constraint.h b/src/libs/3rdparty/botan/src/lib/x509/name_constraint.h new file mode 100644 index 0000000000..34ee5dc324 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/name_constraint.h @@ -0,0 +1,182 @@ +/* +* X.509 Name Constraint +* (C) 2015 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_NAME_CONSTRAINT_H_ +#define BOTAN_NAME_CONSTRAINT_H_ + +#include <botan/asn1_obj.h> +#include <ostream> +#include <limits> + +namespace Botan { + +class BER_Encoder; +class DER_Encoder; +class X509_Certificate; + +/** +* @brief X.509 GeneralName Type +* +* Handles parsing GeneralName types in their BER and canonical string +* encoding. Allows matching GeneralNames against each other using +* the rules laid out in the RFC 5280, sec. 4.2.1.10 (Name Contraints). +*/ +class BOTAN_PUBLIC_API(2,0) GeneralName final : public ASN1_Object + { + public: + enum MatchResult : int + { + All, + Some, + None, + NotFound, + UnknownType, + }; + + /** + * Creates an empty GeneralName. + */ + GeneralName() = default; + + /** + * Creates a new GeneralName for its string format. + * @param str type and name, colon-separated, e.g., "DNS:google.com" + */ + GeneralName(const std::string& str); + + void encode_into(DER_Encoder&) const override; + + void decode_from(BER_Decoder&) override; + + /** + * @return Type of the name. Can be DN, DNS, IP, RFC822 or URI. + */ + const std::string& type() const { return m_type; } + + /** + * @return The name as string. Format depends on type. + */ + const std::string& name() const { return m_name; } + + /** + * Checks whether a given certificate (partially) matches this name. + * @param cert certificate to be matched + * @return the match result + */ + MatchResult matches(const X509_Certificate& cert) const; + + private: + std::string m_type; + std::string m_name; + + bool matches_dns(const std::string&) const; + bool matches_dn(const std::string&) const; + bool matches_ip(const std::string&) const; + }; + +std::ostream& operator<<(std::ostream& os, const GeneralName& gn); + +/** +* @brief A single Name Constraint +* +* The Name Constraint extension adds a minimum and maximum path +* length to a GeneralName to form a constraint. The length limits +* are currently unused. +*/ +class BOTAN_PUBLIC_API(2,0) GeneralSubtree final : public ASN1_Object + { + public: + /** + * Creates an empty name constraint. + */ + GeneralSubtree() : m_base(), m_minimum(0), m_maximum(std::numeric_limits<std::size_t>::max()) + {} + + /*** + * Creates a new name constraint. + * @param base name + * @param min minimum path length + * @param max maximum path length + */ + GeneralSubtree(GeneralName base, size_t min, size_t max) + : m_base(base), m_minimum(min), m_maximum(max) + {} + + /** + * Creates a new name constraint for its string format. + * @param str name constraint + */ + GeneralSubtree(const std::string& str); + + void encode_into(DER_Encoder&) const override; + + void decode_from(BER_Decoder&) override; + + /** + * @return name + */ + GeneralName base() const { return m_base; } + + /** + * @return minimum path length + */ + size_t minimum() const { return m_minimum; } + + /** + * @return maximum path length + */ + size_t maximum() const { return m_maximum; } + + private: + GeneralName m_base; + size_t m_minimum; + size_t m_maximum; + }; + +std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs); + +/** +* @brief Name Constraints +* +* Wraps the Name Constraints associated with a certificate. +*/ +class BOTAN_PUBLIC_API(2,0) NameConstraints final + { + public: + /** + * Creates an empty name NameConstraints. + */ + NameConstraints() : m_permitted_subtrees(), m_excluded_subtrees() {} + + /** + * Creates NameConstraints from a list of permitted and excluded subtrees. + * @param permitted_subtrees names for which the certificate is permitted + * @param excluded_subtrees names for which the certificate is not permitted + */ + NameConstraints(std::vector<GeneralSubtree>&& permitted_subtrees, + std::vector<GeneralSubtree>&& excluded_subtrees) + : m_permitted_subtrees(permitted_subtrees), m_excluded_subtrees(excluded_subtrees) + {} + + /** + * @return permitted names + */ + const std::vector<GeneralSubtree>& permitted() const { return m_permitted_subtrees; } + + /** + * @return excluded names + */ + const std::vector<GeneralSubtree>& excluded() const { return m_excluded_subtrees; } + + private: + std::vector<GeneralSubtree> m_permitted_subtrees; + std::vector<GeneralSubtree> m_excluded_subtrees; +}; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/ocsp.cpp b/src/libs/3rdparty/botan/src/lib/x509/ocsp.cpp new file mode 100644 index 0000000000..115c4117ac --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/ocsp.cpp @@ -0,0 +1,354 @@ +/* +* OCSP +* (C) 2012,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ocsp.h> +#include <botan/certstor.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/x509_ext.h> +#include <botan/oids.h> +#include <botan/base64.h> +#include <botan/pubkey.h> +#include <botan/parsing.h> + +#if defined(BOTAN_HAS_HTTP_UTIL) + #include <botan/http_util.h> +#endif + +namespace Botan { + +namespace OCSP { + +namespace { + +// TODO: should this be in a header somewhere? +void decode_optional_list(BER_Decoder& ber, + ASN1_Tag tag, + std::vector<X509_Certificate>& output) + { + BER_Object obj = ber.get_next_object(); + + if(obj.is_a(tag, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) == false) + { + ber.push_back(obj); + return; + } + + BER_Decoder list(obj); + + while(list.more_items()) + { + BER_Object certbits = list.get_next_object(); + X509_Certificate cert(certbits.bits(), certbits.length()); + output.push_back(std::move(cert)); + } + } + +} + +Request::Request(const X509_Certificate& issuer_cert, + const X509_Certificate& subject_cert) : + m_issuer(issuer_cert), + m_certid(m_issuer, BigInt::decode(subject_cert.serial_number())) + { + if(subject_cert.issuer_dn() != issuer_cert.subject_dn()) + throw Invalid_Argument("Invalid cert pair to OCSP::Request (mismatched issuer,subject args?)"); + } + +Request::Request(const X509_Certificate& issuer_cert, + const BigInt& subject_serial) : + m_issuer(issuer_cert), + m_certid(m_issuer, subject_serial) + { + } + +std::vector<uint8_t> Request::BER_encode() const + { + std::vector<uint8_t> output; + DER_Encoder(output).start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .start_explicit(0) + .encode(static_cast<size_t>(0)) // version # + .end_explicit() + .start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .encode(m_certid) + .end_cons() + .end_cons() + .end_cons() + .end_cons(); + + return output; + } + +std::string Request::base64_encode() const + { + return Botan::base64_encode(BER_encode()); + } + +Response::Response(Certificate_Status_Code status) + { + m_dummy_response_status = status; + } + +Response::Response(const uint8_t response_bits[], size_t response_bits_len) : + m_response_bits(response_bits, response_bits + response_bits_len) + { + m_dummy_response_status = Certificate_Status_Code::OCSP_RESPONSE_INVALID; + + BER_Decoder response_outer = BER_Decoder(m_response_bits).start_cons(SEQUENCE); + + size_t resp_status = 0; + + response_outer.decode(resp_status, ENUMERATED, UNIVERSAL); + + if(resp_status != 0) + throw Exception("OCSP response status " + std::to_string(resp_status)); + + if(response_outer.more_items()) + { + BER_Decoder response_bytes = + response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE); + + response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"), + "Unknown response type in OCSP response"); + + BER_Decoder basicresponse = + BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE); + + basicresponse.start_cons(SEQUENCE) + .raw_bytes(m_tbs_bits) + .end_cons() + .decode(m_sig_algo) + .decode(m_signature, BIT_STRING); + decode_optional_list(basicresponse, ASN1_Tag(0), m_certs); + + size_t responsedata_version = 0; + Extensions extensions; + + BER_Decoder(m_tbs_bits) + .decode_optional(responsedata_version, ASN1_Tag(0), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode_optional(m_signer_name, ASN1_Tag(1), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode_optional_string(m_key_hash, OCTET_STRING, 2, + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode(m_produced_at) + + .decode_list(m_responses) + + .decode_optional(extensions, ASN1_Tag(1), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + } + + response_outer.end_cons(); + } + +Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const + { + if (m_responses.empty()) + return m_dummy_response_status; + + try + { + std::unique_ptr<Public_Key> pub_key(issuer.subject_public_key()); + + const std::vector<std::string> sig_info = + split_on(OIDS::lookup(m_sig_algo.get_oid()), '/'); + + if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) + return Certificate_Status_Code::OCSP_RESPONSE_INVALID; + + std::string padding = sig_info[1]; + Signature_Format format = (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; + + PK_Verifier verifier(*pub_key, padding, format); + + if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature)) + return Certificate_Status_Code::OCSP_SIGNATURE_OK; + else + return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; + } + catch(Exception&) + { + return Certificate_Status_Code::OCSP_SIGNATURE_ERROR; + } + } + +Certificate_Status_Code Response::check_signature(const std::vector<Certificate_Store*>& trusted_roots, + const std::vector<std::shared_ptr<const X509_Certificate>>& ee_cert_path) const + { + if (m_responses.empty()) + return m_dummy_response_status; + + std::shared_ptr<const X509_Certificate> signing_cert; + + for(size_t i = 0; i != trusted_roots.size(); ++i) + { + if(m_signer_name.empty() && m_key_hash.empty()) + return Certificate_Status_Code::OCSP_RESPONSE_INVALID; + + if(!m_signer_name.empty()) + { + signing_cert = trusted_roots[i]->find_cert(m_signer_name, std::vector<uint8_t>()); + if(signing_cert) + { + break; + } + } + + if(m_key_hash.size() > 0) + { + signing_cert = trusted_roots[i]->find_cert_by_pubkey_sha1(m_key_hash); + if(signing_cert) + { + break; + } + } + } + + if(!signing_cert && ee_cert_path.size() > 1) + { + // End entity cert is not allowed to sign their own OCSP request :) + for(size_t i = 1; i < ee_cert_path.size(); ++i) + { + // Check all CA certificates in the (assumed validated) EE cert path + if(!m_signer_name.empty() && ee_cert_path[i]->subject_dn() == m_signer_name) + { + signing_cert = ee_cert_path[i]; + break; + } + + if(m_key_hash.size() > 0 && ee_cert_path[i]->subject_public_key_bitstring_sha1() == m_key_hash) + { + signing_cert = ee_cert_path[i]; + break; + } + } + } + + if(!signing_cert && m_certs.size() > 0) + { + for(size_t i = 0; i < m_certs.size(); ++i) + { + // Check all CA certificates in the (assumed validated) EE cert path + if(!m_signer_name.empty() && m_certs[i].subject_dn() == m_signer_name) + { + signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]); + break; + } + + if(m_key_hash.size() > 0 && m_certs[i].subject_public_key_bitstring_sha1() == m_key_hash) + { + signing_cert = std::make_shared<const X509_Certificate>(m_certs[i]); + break; + } + } + } + + if(!signing_cert) + return Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND; + + if(!signing_cert->allowed_usage(CRL_SIGN) && + !signing_cert->allowed_extended_usage("PKIX.OCSPSigning")) + { + return Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE; + } + + return this->verify_signature(*signing_cert); + } + +Certificate_Status_Code Response::status_for(const X509_Certificate& issuer, + const X509_Certificate& subject, + std::chrono::system_clock::time_point ref_time) const + { + if (m_responses.empty()) + return m_dummy_response_status; + + for(const auto& response : m_responses) + { + if(response.certid().is_id_for(issuer, subject)) + { + X509_Time x509_ref_time(ref_time); + + if(response.cert_status() == 1) + return Certificate_Status_Code::CERT_IS_REVOKED; + + if(response.this_update() > x509_ref_time) + return Certificate_Status_Code::OCSP_NOT_YET_VALID; + + if(response.next_update().time_is_set() && x509_ref_time > response.next_update()) + return Certificate_Status_Code::OCSP_HAS_EXPIRED; + + if(response.cert_status() == 0) + return Certificate_Status_Code::OCSP_RESPONSE_GOOD; + else + return Certificate_Status_Code::OCSP_BAD_STATUS; + } + } + + return Certificate_Status_Code::OCSP_CERT_NOT_LISTED; + } + +#if defined(BOTAN_HAS_HTTP_UTIL) + +Response online_check(const X509_Certificate& issuer, + const BigInt& subject_serial, + const std::string& ocsp_responder, + Certificate_Store* trusted_roots, + std::chrono::milliseconds timeout) + { + if(ocsp_responder.empty()) + throw Invalid_Argument("No OCSP responder specified"); + + OCSP::Request req(issuer, subject_serial); + + auto http = HTTP::POST_sync(ocsp_responder, + "application/ocsp-request", + req.BER_encode(), + 1, + timeout); + + http.throw_unless_ok(); + + // Check the MIME type? + + OCSP::Response response(http.body()); + + std::vector<Certificate_Store*> trusted_roots_vec; + trusted_roots_vec.push_back(trusted_roots); + + if(trusted_roots) + response.check_signature(trusted_roots_vec); + + return response; + } + + +Response online_check(const X509_Certificate& issuer, + const X509_Certificate& subject, + Certificate_Store* trusted_roots, + std::chrono::milliseconds timeout) + { + if(subject.issuer_dn() != issuer.subject_dn()) + throw Invalid_Argument("Invalid cert pair to OCSP::online_check (mismatched issuer,subject args?)"); + + return online_check(issuer, + BigInt::decode(subject.serial_number()), + subject.ocsp_responder(), + trusted_roots, + timeout); + } + +#endif + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/ocsp.h b/src/libs/3rdparty/botan/src/lib/x509/ocsp.h new file mode 100644 index 0000000000..884b1c5b33 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/ocsp.h @@ -0,0 +1,212 @@ +/* +* OCSP +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OCSP_H_ +#define BOTAN_OCSP_H_ + +#include <botan/cert_status.h> +#include <botan/ocsp_types.h> +#include <botan/x509_dn.h> +#include <chrono> + +namespace Botan { + +class Certificate_Store; + +namespace OCSP { + +/** +* An OCSP request. +*/ +class BOTAN_PUBLIC_API(2,0) Request final + { + public: + /** + * Create an OCSP request. + * @param issuer_cert issuer certificate + * @param subject_cert subject certificate + */ + Request(const X509_Certificate& issuer_cert, + const X509_Certificate& subject_cert); + + Request(const X509_Certificate& issuer_cert, + const BigInt& subject_serial); + + /** + * @return BER-encoded OCSP request + */ + std::vector<uint8_t> BER_encode() const; + + /** + * @return Base64-encoded OCSP request + */ + std::string base64_encode() const; + + /** + * @return issuer certificate + */ + const X509_Certificate& issuer() const { return m_issuer; } + + /** + * @return subject certificate + */ + const X509_Certificate& subject() const { throw Not_Implemented("Method have been deprecated"); } + + const std::vector<uint8_t>& issuer_key_hash() const + { return m_certid.issuer_key_hash(); } + private: + X509_Certificate m_issuer; + CertID m_certid; + }; + +/** +* OCSP response. +* +* Note this class is only usable as an OCSP client +*/ +class BOTAN_PUBLIC_API(2,0) Response final + { + public: + /** + * Creates an empty OCSP response. + */ + Response() = default; + + /** + * Create a fake OCSP response from a given status code. + * @param status the status code the check functions will return + */ + Response(Certificate_Status_Code status); + + /** + * Parses an OCSP response. + * @param response_bits response bits received + */ + Response(const std::vector<uint8_t>& response_bits) : + Response(response_bits.data(), response_bits.size()) + {} + + /** + * Parses an OCSP response. + * @param response_bits response bits received + * @param response_bits_len length of response in bytes + */ + Response(const uint8_t response_bits[], + size_t response_bits_len); + + /** + * Check signature and return status + * The optional cert_path is the (already validated!) certificate path of + * the end entity which is being inquired about + * @param trust_roots list of certstores containing trusted roots + * @param cert_path optionally, the (already verified!) certificate path for the certificate + * this is an OCSP response for. This is necessary to find the correct intermediate CA in + * some cases. + */ + Certificate_Status_Code check_signature(const std::vector<Certificate_Store*>& trust_roots, + const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path = {}) const; + + /** + * Verify that issuer's key signed this response + * @param issuer certificate of issuer + * @return if signature valid OCSP_SIGNATURE_OK else an error code + */ + Certificate_Status_Code verify_signature(const X509_Certificate& issuer) const; + + /** + * @return the time this OCSP response was supposedly produced at + */ + const X509_Time& produced_at() const { return m_produced_at; } + + /** + * @return DN of signer, if provided in response (may be empty) + */ + const X509_DN& signer_name() const { return m_signer_name; } + + /** + * @return key hash, if provided in response (may be empty) + */ + const std::vector<uint8_t>& signer_key_hash() const { return m_key_hash; } + + const std::vector<uint8_t>& raw_bits() const { return m_response_bits; } + + /** + * Searches the OCSP response for issuer and subject certificate. + * @param issuer issuer certificate + * @param subject subject certificate + * @param ref_time the reference time + * @return OCSP status code, possible values: + * CERT_IS_REVOKED, + * OCSP_NOT_YET_VALID, + * OCSP_HAS_EXPIRED, + * OCSP_RESPONSE_GOOD, + * OCSP_BAD_STATUS, + * OCSP_CERT_NOT_LISTED + */ + Certificate_Status_Code status_for(const X509_Certificate& issuer, + const X509_Certificate& subject, + std::chrono::system_clock::time_point ref_time = std::chrono::system_clock::now()) const; + + /** + * @return the certificate chain, if provided in response + */ + const std::vector<X509_Certificate> &certificates() const { return m_certs; } + + private: + std::vector<uint8_t> m_response_bits; + X509_Time m_produced_at; + X509_DN m_signer_name; + std::vector<uint8_t> m_key_hash; + std::vector<uint8_t> m_tbs_bits; + AlgorithmIdentifier m_sig_algo; + std::vector<uint8_t> m_signature; + std::vector<X509_Certificate> m_certs; + + std::vector<SingleResponse> m_responses; + + Certificate_Status_Code m_dummy_response_status; + }; + +#if defined(BOTAN_HAS_HTTP_UTIL) + +/** +* Makes an online OCSP request via HTTP and returns the OCSP response. +* @param issuer issuer certificate +* @param subject_serial the subject's serial number +* @param ocsp_responder the OCSP responder to query +* @param trusted_roots trusted roots for the OCSP response +* @param timeout a timeout on the HTTP request +* @return OCSP response +*/ +BOTAN_PUBLIC_API(2,1) +Response online_check(const X509_Certificate& issuer, + const BigInt& subject_serial, + const std::string& ocsp_responder, + Certificate_Store* trusted_roots, + std::chrono::milliseconds timeout = std::chrono::milliseconds(3000)); + +/** +* Makes an online OCSP request via HTTP and returns the OCSP response. +* @param issuer issuer certificate +* @param subject subject certificate +* @param trusted_roots trusted roots for the OCSP response +* @param timeout a timeout on the HTTP request +* @return OCSP response +*/ +BOTAN_PUBLIC_API(2,0) +Response online_check(const X509_Certificate& issuer, + const X509_Certificate& subject, + Certificate_Store* trusted_roots, + std::chrono::milliseconds timeout = std::chrono::milliseconds(3000)); + +#endif + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/ocsp_types.cpp b/src/libs/3rdparty/botan/src/lib/x509/ocsp_types.cpp new file mode 100644 index 0000000000..3eda5c05bb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/ocsp_types.cpp @@ -0,0 +1,105 @@ +/* +* OCSP subtypes +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ocsp_types.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/x509_ext.h> +#include <botan/hash.h> +#include <botan/oids.h> + +namespace Botan { + +namespace OCSP { + +CertID::CertID(const X509_Certificate& issuer, + const BigInt& subject_serial) + { + /* + In practice it seems some responders, including, notably, + ocsp.verisign.com, will reject anything but SHA-1 here + */ + std::unique_ptr<HashFunction> hash(HashFunction::create_or_throw("SHA-160")); + + m_hash_id = AlgorithmIdentifier(hash->name(), AlgorithmIdentifier::USE_NULL_PARAM); + m_issuer_key_hash = unlock(hash->process(issuer.subject_public_key_bitstring())); + m_issuer_dn_hash = unlock(hash->process(issuer.raw_subject_dn())); + m_subject_serial = subject_serial; + } + +bool CertID::is_id_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const + { + try + { + if(BigInt::decode(subject.serial_number()) != m_subject_serial) + return false; + + std::unique_ptr<HashFunction> hash(HashFunction::create(OIDS::lookup(m_hash_id.get_oid()))); + + if(m_issuer_dn_hash != unlock(hash->process(subject.raw_issuer_dn()))) + return false; + + if(m_issuer_key_hash != unlock(hash->process(issuer.subject_public_key_bitstring()))) + return false; + } + catch(...) + { + return false; + } + + return true; + } + +void CertID::encode_into(class DER_Encoder& to) const + { + to.start_cons(SEQUENCE) + .encode(m_hash_id) + .encode(m_issuer_dn_hash, OCTET_STRING) + .encode(m_issuer_key_hash, OCTET_STRING) + .encode(m_subject_serial) + .end_cons(); + } + +void CertID::decode_from(class BER_Decoder& from) + { + from.start_cons(SEQUENCE) + .decode(m_hash_id) + .decode(m_issuer_dn_hash, OCTET_STRING) + .decode(m_issuer_key_hash, OCTET_STRING) + .decode(m_subject_serial) + .end_cons(); + + } + +void SingleResponse::encode_into(class DER_Encoder&) const + { + throw Not_Implemented("SingleResponse::encode_into"); + } + +void SingleResponse::decode_from(class BER_Decoder& from) + { + BER_Object cert_status; + Extensions extensions; + + from.start_cons(SEQUENCE) + .decode(m_certid) + .get_next(cert_status) + .decode(m_thisupdate) + .decode_optional(m_nextupdate, ASN1_Tag(0), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) + .decode_optional(extensions, + ASN1_Tag(1), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) + .end_cons(); + + m_cert_status = cert_status.type(); + } + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/ocsp_types.h b/src/libs/3rdparty/botan/src/lib/x509/ocsp_types.h new file mode 100644 index 0000000000..8131addb16 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/ocsp_types.h @@ -0,0 +1,68 @@ +/* +* OCSP subtypes +* (C) 2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_OCSP_TYPES_H_ +#define BOTAN_OCSP_TYPES_H_ + +#include <botan/x509cert.h> +#include <botan/asn1_time.h> +#include <botan/bigint.h> + +namespace Botan { + +namespace OCSP { + +class BOTAN_PUBLIC_API(2,0) CertID final : public ASN1_Object + { + public: + CertID() = default; + + CertID(const X509_Certificate& issuer, + const BigInt& subject_serial); + + bool is_id_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const; + + void encode_into(class DER_Encoder& to) const override; + + void decode_from(class BER_Decoder& from) override; + + const std::vector<uint8_t>& issuer_key_hash() const { return m_issuer_key_hash; } + + private: + AlgorithmIdentifier m_hash_id; + std::vector<uint8_t> m_issuer_dn_hash; + std::vector<uint8_t> m_issuer_key_hash; + BigInt m_subject_serial; + }; + +class BOTAN_PUBLIC_API(2,0) SingleResponse final : public ASN1_Object + { + public: + const CertID& certid() const { return m_certid; } + + size_t cert_status() const { return m_cert_status; } + + X509_Time this_update() const { return m_thisupdate; } + + X509_Time next_update() const { return m_nextupdate; } + + void encode_into(class DER_Encoder& to) const override; + + void decode_from(class BER_Decoder& from) override; + private: + CertID m_certid; + size_t m_cert_status = 2; // unknown + X509_Time m_thisupdate; + X509_Time m_nextupdate; + }; + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/pkcs10.cpp b/src/libs/3rdparty/botan/src/lib/x509/pkcs10.cpp new file mode 100644 index 0000000000..2da002cd16 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/pkcs10.cpp @@ -0,0 +1,314 @@ +/* +* PKCS #10 +* (C) 1999-2007,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/pkcs10.h> +#include <botan/x509_ext.h> +#include <botan/x509cert.h> +#include <botan/ber_dec.h> +#include <botan/der_enc.h> +#include <botan/pubkey.h> +#include <botan/oids.h> +#include <botan/pem.h> + +namespace Botan { + +struct PKCS10_Data + { + X509_DN m_subject_dn; + std::vector<uint8_t> m_public_key_bits; + AlternativeName m_alt_name; + std::string m_challenge; + Extensions m_extensions; + }; + +std::string PKCS10_Request::PEM_label() const + { + return "CERTIFICATE REQUEST"; + } + +std::vector<std::string> PKCS10_Request::alternate_PEM_labels() const + { + return { "NEW CERTIFICATE REQUEST" }; + } + +PKCS10_Request::PKCS10_Request(DataSource& src) + { + load_data(src); + } + +PKCS10_Request::PKCS10_Request(const std::vector<uint8_t>& vec) + { + DataSource_Memory src(vec.data(), vec.size()); + load_data(src); + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +PKCS10_Request::PKCS10_Request(const std::string& fsname) + { + DataSource_Stream src(fsname, true); + load_data(src); + } +#endif + +//static +PKCS10_Request PKCS10_Request::create(const Private_Key& key, + const X509_DN& subject_dn, + const Extensions& extensions, + const std::string& hash_fn, + RandomNumberGenerator& rng, + const std::string& padding_scheme, + const std::string& challenge) + { + const std::map<std::string,std::string> sig_opts = { {"padding", padding_scheme} }; + + AlgorithmIdentifier sig_algo; + std::unique_ptr<PK_Signer> signer = choose_sig_format(sig_algo, key, rng, hash_fn, padding_scheme); + + const size_t PKCS10_VERSION = 0; + + DER_Encoder tbs_req; + + tbs_req.start_cons(SEQUENCE) + .encode(PKCS10_VERSION) + .encode(subject_dn) + .raw_bytes(key.subject_public_key()) + .start_explicit(0); + + if(challenge.empty() == false) + { + ASN1_String challenge_str(challenge, DIRECTORY_STRING); + + tbs_req.encode( + Attribute("PKCS9.ChallengePassword", + DER_Encoder().encode(challenge_str).get_contents_unlocked() + ) + ); + } + + tbs_req.encode( + Attribute("PKCS9.ExtensionRequest", + DER_Encoder() + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .get_contents_unlocked() + ) + ) + .end_explicit() + .end_cons(); + + const std::vector<uint8_t> req = + X509_Object::make_signed(signer.get(), rng, sig_algo, + tbs_req.get_contents()); + + return PKCS10_Request(req); + } + +/* +* Decode the CertificateRequestInfo +*/ +namespace { + +std::unique_ptr<PKCS10_Data> decode_pkcs10(const std::vector<uint8_t>& body) + { + std::unique_ptr<PKCS10_Data> data(new PKCS10_Data); + + BER_Decoder cert_req_info(body); + + size_t version; + cert_req_info.decode(version); + if(version != 0) + throw Decoding_Error("Unknown version code in PKCS #10 request: " + + std::to_string(version)); + + cert_req_info.decode(data->m_subject_dn); + + BER_Object public_key = cert_req_info.get_next_object(); + if(public_key.is_a(SEQUENCE, CONSTRUCTED) == false) + throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key", public_key.tagging()); + + data->m_public_key_bits = ASN1::put_in_sequence(public_key.bits(), public_key.length()); + + BER_Object attr_bits = cert_req_info.get_next_object(); + + std::set<std::string> pkcs9_email; + + if(attr_bits.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) + { + BER_Decoder attributes(attr_bits); + while(attributes.more_items()) + { + Attribute attr; + attributes.decode(attr); + + const OID& oid = attr.get_oid(); + BER_Decoder value(attr.get_parameters()); + + if(oid == OIDS::lookup("PKCS9.EmailAddress")) + { + ASN1_String email; + value.decode(email); + pkcs9_email.insert(email.value()); + } + else if(oid == OIDS::lookup("PKCS9.ChallengePassword")) + { + ASN1_String challenge_password; + value.decode(challenge_password); + data->m_challenge = challenge_password.value(); + } + else if(oid == OIDS::lookup("PKCS9.ExtensionRequest")) + { + value.decode(data->m_extensions).verify_end(); + } + } + attributes.verify_end(); + } + else if(attr_bits.is_set()) + throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", attr_bits.tagging()); + + cert_req_info.verify_end(); + + if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::Subject_Alternative_Name>()) + { + data->m_alt_name = ext->get_alt_name(); + } + + for(std::string email : pkcs9_email) + { + data->m_alt_name.add_attribute("RFC882", email); + } + + return data; + } + +} + +void PKCS10_Request::force_decode() + { + m_data.reset(); + + std::unique_ptr<PKCS10_Data> data = decode_pkcs10(signed_body()); + + m_data.reset(data.release()); + + if(!this->check_signature(subject_public_key())) + throw Decoding_Error("PKCS #10 request: Bad signature detected"); + } + +const PKCS10_Data& PKCS10_Request::data() const + { + if(m_data == nullptr) + throw Decoding_Error("PKCS10_Request decoding failed"); + return *m_data.get(); + } + +/* +* Return the challenge password (if any) +*/ +std::string PKCS10_Request::challenge_password() const + { + return data().m_challenge; + } + +/* +* Return the name of the requestor +*/ +const X509_DN& PKCS10_Request::subject_dn() const + { + return data().m_subject_dn; + } + +/* +* Return the public key of the requestor +*/ +const std::vector<uint8_t>& PKCS10_Request::raw_public_key() const + { + return data().m_public_key_bits; + } + +/* +* Return the public key of the requestor +*/ +Public_Key* PKCS10_Request::subject_public_key() const + { + DataSource_Memory source(raw_public_key()); + return X509::load_key(source); + } + +/* +* Return the alternative names of the requestor +*/ +const AlternativeName& PKCS10_Request::subject_alt_name() const + { + return data().m_alt_name; + } + +/* +* Return the X509v3 extensions +*/ +const Extensions& PKCS10_Request::extensions() const + { + return data().m_extensions; + } + +/* +* Return the key constraints (if any) +*/ +Key_Constraints PKCS10_Request::constraints() const + { + if(auto ext = extensions().get(OIDS::lookup("X509v3.KeyUsage"))) + { + return dynamic_cast<Cert_Extension::Key_Usage&>(*ext).get_constraints(); + } + + return NO_CONSTRAINTS; + } + +/* +* Return the extendend key constraints (if any) +*/ +std::vector<OID> PKCS10_Request::ex_constraints() const + { + if(auto ext = extensions().get(OIDS::lookup("X509v3.ExtendedKeyUsage"))) + { + return dynamic_cast<Cert_Extension::Extended_Key_Usage&>(*ext).get_oids(); + } + + return {}; + } + +/* +* Return is a CA certificate is requested +*/ +bool PKCS10_Request::is_CA() const + { + if(auto ext = extensions().get(OIDS::lookup("X509v3.BasicConstraints"))) + { + return dynamic_cast<Cert_Extension::Basic_Constraints&>(*ext).get_is_ca(); + } + + return false; + } + +/* +* Return the desired path limit (if any) +*/ +size_t PKCS10_Request::path_limit() const + { + if(auto ext = extensions().get(OIDS::lookup("X509v3.BasicConstraints"))) + { + Cert_Extension::Basic_Constraints& basic_constraints = dynamic_cast<Cert_Extension::Basic_Constraints&>(*ext); + if(basic_constraints.get_is_ca()) + { + return basic_constraints.get_path_limit(); + } + } + + return 0; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/pkcs10.h b/src/libs/3rdparty/botan/src/lib/x509/pkcs10.h new file mode 100644 index 0000000000..bd8cdb2e14 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/pkcs10.h @@ -0,0 +1,148 @@ +/* +* PKCS #10 +* (C) 1999-2007 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_PKCS10_H_ +#define BOTAN_PKCS10_H_ + +#include <botan/x509_obj.h> +#include <botan/x509_dn.h> +#include <botan/key_constraint.h> +#include <botan/asn1_attribute.h> +#include <botan/asn1_alt_name.h> +#include <vector> + +namespace Botan { + +class Private_Key; +class Extensions; +struct PKCS10_Data; + +/** +* PKCS #10 Certificate Request. +*/ +class BOTAN_PUBLIC_API(2,0) PKCS10_Request final : public X509_Object + { + public: + /** + * Get the subject public key. + * @return subject public key + */ + Public_Key* subject_public_key() const; + + /** + * Get the raw DER encoded public key. + * @return raw DER encoded public key + */ + const std::vector<uint8_t>& raw_public_key() const; + + /** + * Get the subject DN. + * @return subject DN + */ + const X509_DN& subject_dn() const; + + /** + * Get the subject alternative name. + * @return subject alternative name. + */ + const AlternativeName& subject_alt_name() const; + + /** + * Get the key constraints for the key associated with this + * PKCS#10 object. + * @return key constraints + */ + Key_Constraints constraints() const; + + /** + * Get the extendend key constraints (if any). + * @return extended key constraints + */ + std::vector<OID> ex_constraints() const; + + /** + * Find out whether this is a CA request. + * @result true if it is a CA request, false otherwise. + */ + bool is_CA() const; + + /** + * Return the constraint on the path length defined + * in the BasicConstraints extension. + * @return path limit + */ + size_t path_limit() const; + + /** + * Get the challenge password for this request + * @return challenge password for this request + */ + std::string challenge_password() const; + + /** + * Get the X509v3 extensions. + * @return X509v3 extensions + */ + const Extensions& extensions() const; + + /** + * Create a PKCS#10 Request from a data source. + * @param source the data source providing the DER encoded request + */ + explicit PKCS10_Request(DataSource& source); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + /** + * Create a PKCS#10 Request from a file. + * @param filename the name of the file containing the DER or PEM + * encoded request file + */ + explicit PKCS10_Request(const std::string& filename); +#endif + + /** + * Create a PKCS#10 Request from binary data. + * @param vec a std::vector containing the DER value + */ + explicit PKCS10_Request(const std::vector<uint8_t>& vec); + + /** + * Create a new PKCS10 certificate request + * @param key the key that will be included in the certificate request + * @param subject_dn the DN to be placed in the request + * @param extensions extensions to include in the request + * @param hash_fn the hash function to use to create the signature + * @param rng a random number generator + * @param padding_scheme if set specifies the padding scheme, otherwise an + * algorithm-specific default is used. + * @param challenge a challenge string to be included in the PKCS10 request, + * sometimes used for revocation purposes. + */ + static PKCS10_Request create(const Private_Key& key, + const X509_DN& subject_dn, + const Extensions& extensions, + const std::string& hash_fn, + RandomNumberGenerator& rng, + const std::string& padding_scheme = "", + const std::string& challenge = ""); + + private: + std::string PEM_label() const override; + + std::vector<std::string> alternate_PEM_labels() const override; + + void force_decode() override; + + const PKCS10_Data& data() const; + + std::shared_ptr<PKCS10_Data> m_data; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_ca.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509_ca.cpp new file mode 100644 index 0000000000..73eea4a95b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_ca.cpp @@ -0,0 +1,338 @@ +/* +* X.509 Certificate Authority +* (C) 1999-2010 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509_ca.h> +#include <botan/x509self.h> +#include <botan/pkcs10.h> +#include <botan/pubkey.h> +#include <botan/der_enc.h> +#include <botan/bigint.h> +#include <botan/parsing.h> +#include <botan/oids.h> +#include <botan/hash.h> +#include <botan/key_constraint.h> +#include <botan/emsa.h> +#include <botan/scan_name.h> +#include <algorithm> +#include <iterator> +#include <map> + +namespace Botan { + +/* +* Load the certificate and private key +*/ +X509_CA::X509_CA(const X509_Certificate& c, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) : + m_ca_cert(c), + m_hash_fn(hash_fn) + { + if(!m_ca_cert.is_CA_cert()) + throw Invalid_Argument("X509_CA: This certificate is not for a CA"); + + std::map<std::string,std::string> opts; + // constructor without additional options: use the padding used in the CA certificate + // sig_oid_str = <sig_alg>/<padding>, so padding with all its options will look + // like a cipher mode to the scanner + std::string sig_oid_str = OIDS::lookup(c.signature_algorithm().oid); + SCAN_Name scanner(sig_oid_str); + std::string pad = scanner.cipher_mode(); + if(!pad.empty()) + opts.insert({"padding",pad}); + + m_signer.reset(choose_sig_format(key, opts, rng, hash_fn, m_ca_sig_algo)); + } + +/* +* Load the certificate and private key, and additional options +*/ +X509_CA::X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::map<std::string,std::string>& opts, + const std::string& hash_fn, + RandomNumberGenerator& rng) : m_ca_cert(ca_certificate), m_hash_fn(hash_fn) + { + if(!m_ca_cert.is_CA_cert()) + throw Invalid_Argument("X509_CA: This certificate is not for a CA"); + + m_signer.reset(choose_sig_format(key, opts, rng, hash_fn, m_ca_sig_algo)); + } + +/* +* X509_CA Destructor +*/ +X509_CA::~X509_CA() + { + /* for unique_ptr */ + } + +namespace { + +Extensions choose_extensions(const PKCS10_Request& req, + const X509_Certificate& ca_cert, + const std::string& hash_fn) + { + Key_Constraints constraints; + if(req.is_CA()) + { + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + } + else + { + std::unique_ptr<Public_Key> key(req.subject_public_key()); + verify_cert_constraints_valid_for_key_type(*key, req.constraints()); + constraints = req.constraints(); + } + + Extensions extensions = req.extensions(); + + extensions.replace( + new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()), + true); + + if(constraints != NO_CONSTRAINTS) + { + extensions.replace(new Cert_Extension::Key_Usage(constraints), true); + } + + extensions.replace(new Cert_Extension::Authority_Key_ID(ca_cert.subject_key_id())); + extensions.replace(new Cert_Extension::Subject_Key_ID(req.raw_public_key(), hash_fn)); + + extensions.replace( + new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name())); + + extensions.replace( + new Cert_Extension::Extended_Key_Usage(req.ex_constraints())); + + return extensions; + } + +} + +X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const BigInt& serial_number, + const X509_Time& not_before, + const X509_Time& not_after) const + { + auto extensions = choose_extensions(req, m_ca_cert, m_hash_fn); + + return make_cert(m_signer.get(), rng, serial_number, + m_ca_sig_algo, req.raw_public_key(), + not_before, not_after, + m_ca_cert.subject_dn(), req.subject_dn(), + extensions); + } + +/* +* Sign a PKCS #10 certificate request +*/ +X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const X509_Time& not_before, + const X509_Time& not_after) const + { + auto extensions = choose_extensions(req, m_ca_cert, m_hash_fn); + + return make_cert(m_signer.get(), rng, m_ca_sig_algo, + req.raw_public_key(), + not_before, not_after, + m_ca_cert.subject_dn(), req.subject_dn(), + extensions); + } + +X509_Certificate X509_CA::make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& sig_algo, + const std::vector<uint8_t>& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions) + { + const size_t SERIAL_BITS = 128; + BigInt serial_no(rng, SERIAL_BITS); + + return make_cert(signer, rng, serial_no, sig_algo, pub_key, + not_before, not_after, issuer_dn, subject_dn, extensions); + } + +/* +* Create a new certificate +*/ +X509_Certificate X509_CA::make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const BigInt& serial_no, + const AlgorithmIdentifier& sig_algo, + const std::vector<uint8_t>& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions) + { + const size_t X509_CERT_VERSION = 3; + + // clang-format off + return X509_Certificate(X509_Object::make_signed( + signer, rng, sig_algo, + DER_Encoder().start_cons(SEQUENCE) + .start_explicit(0) + .encode(X509_CERT_VERSION-1) + .end_explicit() + + .encode(serial_no) + + .encode(sig_algo) + .encode(issuer_dn) + + .start_cons(SEQUENCE) + .encode(not_before) + .encode(not_after) + .end_cons() + + .encode(subject_dn) + .raw_bytes(pub_key) + + .start_explicit(3) + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .end_explicit() + .end_cons() + .get_contents() + )); + // clang-format on + } + +/* +* Create a new, empty CRL +*/ +X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, + uint32_t next_update) const + { + return new_crl(rng, + std::chrono::system_clock::now(), + std::chrono::seconds(next_update)); + } + +/* +* Update a CRL with new entries +*/ +X509_CRL X509_CA::update_crl(const X509_CRL& crl, + const std::vector<CRL_Entry>& new_revoked, + RandomNumberGenerator& rng, + uint32_t next_update) const + { + return update_crl(crl, new_revoked, rng, + std::chrono::system_clock::now(), + std::chrono::seconds(next_update)); + } + + +X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const + { + std::vector<CRL_Entry> empty; + return make_crl(empty, 1, rng, issue_time, next_update); + } + +X509_CRL X509_CA::update_crl(const X509_CRL& last_crl, + const std::vector<CRL_Entry>& new_revoked, + RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const + { + std::vector<CRL_Entry> revoked = last_crl.get_revoked(); + + std::copy(new_revoked.begin(), new_revoked.end(), + std::back_inserter(revoked)); + + return make_crl(revoked, last_crl.crl_number() + 1, rng, issue_time, next_update); + } + +/* +* Create a CRL +*/ +X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked, + uint32_t crl_number, + RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const + { + const size_t X509_CRL_VERSION = 2; + + auto expire_time = issue_time + next_update; + + Extensions extensions; + extensions.add(new Cert_Extension::Authority_Key_ID(m_ca_cert.subject_key_id())); + extensions.add(new Cert_Extension::CRL_Number(crl_number)); + + // clang-format off + const std::vector<uint8_t> crl = X509_Object::make_signed( + m_signer.get(), rng, m_ca_sig_algo, + DER_Encoder().start_cons(SEQUENCE) + .encode(X509_CRL_VERSION-1) + .encode(m_ca_sig_algo) + .encode(m_ca_cert.subject_dn()) + .encode(X509_Time(issue_time)) + .encode(X509_Time(expire_time)) + .encode_if(revoked.size() > 0, + DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(revoked) + .end_cons() + ) + .start_explicit(0) + .start_cons(SEQUENCE) + .encode(extensions) + .end_cons() + .end_explicit() + .end_cons() + .get_contents()); + // clang-format on + + return X509_CRL(crl); + } + +/* +* Return the CA's certificate +*/ +X509_Certificate X509_CA::ca_certificate() const + { + return m_ca_cert; + } + +/* +* Choose a signing format for the key +*/ + +PK_Signer* choose_sig_format(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& hash_fn, + AlgorithmIdentifier& sig_algo) + { + return X509_Object::choose_sig_format(sig_algo, key, rng, hash_fn, "").release(); + } + +PK_Signer* choose_sig_format(const Private_Key& key, + const std::map<std::string,std::string>& opts, + RandomNumberGenerator& rng, + const std::string& hash_fn, + AlgorithmIdentifier& sig_algo) + { + std::string padding; + if(opts.count("padding")) + padding = opts.at("padding"); + return X509_Object::choose_sig_format(sig_algo, key, rng, hash_fn, padding).release(); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_ca.h b/src/libs/3rdparty/botan/src/lib/x509/x509_ca.h new file mode 100644 index 0000000000..c8ffab69d5 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_ca.h @@ -0,0 +1,262 @@ +/* +* X.509 Certificate Authority +* (C) 1999-2008 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_CA_H_ +#define BOTAN_X509_CA_H_ + +#include <botan/x509cert.h> +#include <botan/x509_crl.h> +#include <chrono> + +#if defined(BOTAN_HAS_SYSTEM_RNG) + #include <botan/system_rng.h> +#endif + +namespace Botan { + +class BigInt; +class Private_Key; +class PKCS10_Request; +class PK_Signer; + +/** +* This class represents X.509 Certificate Authorities (CAs). +*/ +class BOTAN_PUBLIC_API(2,0) X509_CA final + { + public: + /** + * Sign a PKCS#10 Request. + * @param req the request to sign + * @param rng the rng to use + * @param not_before the starting time for the certificate + * @param not_after the expiration time for the certificate + * @return resulting certificate + */ + X509_Certificate sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const X509_Time& not_before, + const X509_Time& not_after) const; + + /** + * Sign a PKCS#10 Request. + * @param req the request to sign + * @param rng the rng to use + * @param serial_number the serial number the cert will be assigned. + * @param not_before the starting time for the certificate + * @param not_after the expiration time for the certificate + * @return resulting certificate + */ + X509_Certificate sign_request(const PKCS10_Request& req, + RandomNumberGenerator& rng, + const BigInt& serial_number, + const X509_Time& not_before, + const X509_Time& not_after) const; + + /** + * Get the certificate of this CA. + * @return CA certificate + */ + X509_Certificate ca_certificate() const; + + /** + * Create a new and empty CRL for this CA. + * @param rng the random number generator to use + * @param issue_time the issue time (typically system_clock::now) + * @param next_update the time interval after issue_data within which + * a new CRL will be produced. + * @return new CRL + */ + X509_CRL new_crl(RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const; + + /** + * Create a new CRL by with additional entries. + * @param last_crl the last CRL of this CA to add the new entries to + * @param new_entries contains the new CRL entries to be added to the CRL + * @param rng the random number generator to use + * @param issue_time the issue time (typically system_clock::now) + * @param next_update the time interval after issue_data within which + * a new CRL will be produced. + */ + X509_CRL update_crl(const X509_CRL& last_crl, + const std::vector<CRL_Entry>& new_entries, + RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const; + + /** + * Create a new and empty CRL for this CA. + * @param rng the random number generator to use + * @param next_update the time to set in next update in seconds + * as the offset from the current time + * @return new CRL + */ + X509_CRL new_crl(RandomNumberGenerator& rng, + uint32_t next_update = 604800) const; + + /** + * Create a new CRL by with additional entries. + * @param last_crl the last CRL of this CA to add the new entries to + * @param new_entries contains the new CRL entries to be added to the CRL + * @param rng the random number generator to use + * @param next_update the time to set in next update in seconds + * as the offset from the current time + */ + X509_CRL update_crl(const X509_CRL& last_crl, + const std::vector<CRL_Entry>& new_entries, + RandomNumberGenerator& rng, + uint32_t next_update = 604800) const; + + /** + * Interface for creating new certificates + * @param signer a signing object + * @param rng a random number generator + * @param sig_algo the signature algorithm identifier + * @param pub_key the serialized public key + * @param not_before the start time of the certificate + * @param not_after the end time of the certificate + * @param issuer_dn the DN of the issuer + * @param subject_dn the DN of the subject + * @param extensions an optional list of certificate extensions + * @returns newly minted certificate + */ + static X509_Certificate make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& sig_algo, + const std::vector<uint8_t>& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions); + + /** + * Interface for creating new certificates + * @param signer a signing object + * @param rng a random number generator + * @param serial_number the serial number the cert will be assigned + * @param sig_algo the signature algorithm identifier + * @param pub_key the serialized public key + * @param not_before the start time of the certificate + * @param not_after the end time of the certificate + * @param issuer_dn the DN of the issuer + * @param subject_dn the DN of the subject + * @param extensions an optional list of certificate extensions + * @returns newly minted certificate + */ + static X509_Certificate make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const BigInt& serial_number, + const AlgorithmIdentifier& sig_algo, + const std::vector<uint8_t>& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions); + + /** + * Create a new CA object. + * @param ca_certificate the certificate of the CA + * @param key the private key of the CA + * @param hash_fn name of a hash function to use for signing + * @param rng the random generator to use + */ + X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + + /** + * Create a new CA object. + * @param ca_certificate the certificate of the CA + * @param key the private key of the CA + * @param opts additional options, e.g. padding, as key value pairs + * @param hash_fn name of a hash function to use for signing + * @param rng the random generator to use + */ + X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::map<std::string,std::string>& opts, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +#if defined(BOTAN_HAS_SYSTEM_RNG) + BOTAN_DEPRECATED("Use version taking RNG object") + X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::string& hash_fn) : + X509_CA(ca_certificate, key, hash_fn, system_rng()) + {} +#endif + + X509_CA(const X509_CA&) = delete; + X509_CA& operator=(const X509_CA&) = delete; + +#if !defined(BOTAN_BUILD_COMPILER_IS_MSVC_2013) + X509_CA(X509_CA&&) = default; + X509_CA& operator=(X509_CA&&) = default; +#endif + + ~X509_CA(); + + private: + X509_CRL make_crl(const std::vector<CRL_Entry>& entries, + uint32_t crl_number, + RandomNumberGenerator& rng, + std::chrono::system_clock::time_point issue_time, + std::chrono::seconds next_update) const; + + AlgorithmIdentifier m_ca_sig_algo; + X509_Certificate m_ca_cert; + std::string m_hash_fn; + std::unique_ptr<PK_Signer> m_signer; + }; + +/** +* Choose the default signature format for a certain public key signature +* scheme. +* @param key will be the key to choose a padding scheme for +* @param rng the random generator to use +* @param hash_fn is the desired hash function +* @param alg_id will be set to the chosen scheme +* @return A PK_Signer object for generating signatures +*/ +BOTAN_PUBLIC_API(2,0) PK_Signer* choose_sig_format(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& hash_fn, + AlgorithmIdentifier& alg_id); + +/** +* @verbatim +* Choose the default signature format for a certain public key signature +* scheme. +* +* The only option recognized by opts at this moment is "padding" +* Find an entry from src/build-data/oids.txt under [signature] of the form +* <sig_algo>/<padding>[(<hash_algo>)] and add {"padding",<padding>} +* to opts. +* @endverbatim +* +* @param key will be the key to choose a padding scheme for +* @param opts contains additional options for building the certificate +* @param rng the random generator to use +* @param hash_fn is the desired hash function +* @param alg_id will be set to the chosen scheme +* @return A PK_Signer object for generating signatures +*/ +PK_Signer* choose_sig_format(const Private_Key& key, + const std::map<std::string,std::string>& opts, + RandomNumberGenerator& rng, + const std::string& hash_fn, + AlgorithmIdentifier& alg_id); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_crl.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509_crl.cpp new file mode 100644 index 0000000000..47742c1dad --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_crl.cpp @@ -0,0 +1,268 @@ +/* +* X.509 CRL +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509_crl.h> +#include <botan/x509_ext.h> +#include <botan/x509cert.h> +#include <botan/ber_dec.h> + +#include <sstream> + +namespace Botan { + +struct CRL_Data + { + X509_DN m_issuer; + X509_Time m_this_update; + X509_Time m_next_update; + std::vector<CRL_Entry> m_entries; + Extensions m_extensions; + + // cached values from extensions + size_t m_crl_number = 0; + std::vector<uint8_t> m_auth_key_id; + std::string m_issuing_distribution_point; + }; + +std::string X509_CRL::PEM_label() const + { + return "X509 CRL"; + } + +std::vector<std::string> X509_CRL::alternate_PEM_labels() const + { + return { "CRL" }; + } + +X509_CRL::X509_CRL(DataSource& src) + { + load_data(src); + } + +X509_CRL::X509_CRL(const std::vector<uint8_t>& vec) + { + DataSource_Memory src(vec.data(), vec.size()); + load_data(src); + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +X509_CRL::X509_CRL(const std::string& fsname) + { + DataSource_Stream src(fsname, true); + load_data(src); + } +#endif + +X509_CRL::X509_CRL(const X509_DN& issuer, + const X509_Time& this_update, + const X509_Time& next_update, + const std::vector<CRL_Entry>& revoked) : + X509_Object() + { + m_data.reset(new CRL_Data); + m_data->m_issuer = issuer; + m_data->m_this_update = this_update; + m_data->m_next_update = next_update; + m_data->m_entries = revoked; + } + +/** +* Check if this particular certificate is listed in the CRL +*/ +bool X509_CRL::is_revoked(const X509_Certificate& cert) const + { + /* + If the cert wasn't issued by the CRL issuer, it's possible the cert + is revoked, but not by this CRL. Maybe throw an exception instead? + */ + if(cert.issuer_dn() != issuer_dn()) + return false; + + std::vector<uint8_t> crl_akid = authority_key_id(); + std::vector<uint8_t> cert_akid = cert.authority_key_id(); + + if(!crl_akid.empty() && !cert_akid.empty()) + { + if(crl_akid != cert_akid) + return false; + } + + std::vector<uint8_t> cert_serial = cert.serial_number(); + + bool is_revoked = false; + + // FIXME would be nice to avoid a linear scan here - maybe sort the entries? + for(const CRL_Entry& entry : get_revoked()) + { + if(cert_serial == entry.serial_number()) + { + if(entry.reason_code() == REMOVE_FROM_CRL) + is_revoked = false; + else + is_revoked = true; + } + } + + return is_revoked; + } + +/* +* Decode the TBSCertList data +*/ +namespace { + +std::unique_ptr<CRL_Data> decode_crl_body(const std::vector<uint8_t>& body, + const AlgorithmIdentifier& sig_algo) + { + std::unique_ptr<CRL_Data> data(new CRL_Data); + + BER_Decoder tbs_crl(body); + + size_t version; + tbs_crl.decode_optional(version, INTEGER, UNIVERSAL); + + if(version != 0 && version != 1) + throw X509_CRL::X509_CRL_Error("Unknown X.509 CRL version " + + std::to_string(version+1)); + + AlgorithmIdentifier sig_algo_inner; + tbs_crl.decode(sig_algo_inner); + + if(sig_algo != sig_algo_inner) + throw X509_CRL::X509_CRL_Error("Algorithm identifier mismatch"); + + tbs_crl.decode(data->m_issuer) + .decode(data->m_this_update) + .decode(data->m_next_update); + + BER_Object next = tbs_crl.get_next_object(); + + if(next.is_a(SEQUENCE, CONSTRUCTED)) + { + BER_Decoder cert_list(std::move(next)); + + while(cert_list.more_items()) + { + CRL_Entry entry; + cert_list.decode(entry); + data->m_entries.push_back(entry); + } + next = tbs_crl.get_next_object(); + } + + if(next.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) + { + BER_Decoder crl_options(std::move(next)); + crl_options.decode(data->m_extensions).verify_end(); + next = tbs_crl.get_next_object(); + } + + if(next.is_set()) + throw X509_CRL::X509_CRL_Error("Unknown tag in CRL"); + + tbs_crl.verify_end(); + + // Now cache some fields from the extensions + if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::CRL_Number>()) + { + data->m_crl_number = ext->get_crl_number(); + } + if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::Authority_Key_ID>()) + { + data->m_auth_key_id = ext->get_key_id(); + } + if(auto ext = data->m_extensions.get_extension_object_as<Cert_Extension::CRL_Issuing_Distribution_Point>()) + { + std::stringstream ss; + + for(const auto& pair : ext->get_point().contents()) + { + ss << pair.first << ": " << pair.second << " "; + } + data->m_issuing_distribution_point = ss.str(); + } + + return data; + } + +} + +void X509_CRL::force_decode() + { + m_data.reset(decode_crl_body(signed_body(), signature_algorithm()).release()); + } + +const CRL_Data& X509_CRL::data() const + { + if(!m_data) + { + throw Invalid_State("X509_CRL uninitialized"); + } + return *m_data.get(); + } + +const Extensions& X509_CRL::extensions() const + { + return data().m_extensions; + } + +/* +* Return the list of revoked certificates +*/ +const std::vector<CRL_Entry>& X509_CRL::get_revoked() const + { + return data().m_entries; + } + +/* +* Return the distinguished name of the issuer +*/ +const X509_DN& X509_CRL::issuer_dn() const + { + return data().m_issuer; + } + +/* +* Return the key identifier of the issuer +*/ +const std::vector<uint8_t>& X509_CRL::authority_key_id() const + { + return data().m_auth_key_id; + } + +/* +* Return the CRL number of this CRL +*/ +uint32_t X509_CRL::crl_number() const + { + return data().m_crl_number; + } + +/* +* Return the issue data of the CRL +*/ +const X509_Time& X509_CRL::this_update() const + { + return data().m_this_update; + } + +/* +* Return the date when a new CRL will be issued +*/ +const X509_Time& X509_CRL::next_update() const + { + return data().m_next_update; + } + +/* +* Return the CRL's distribution point +*/ +std::string X509_CRL::crl_issuing_distribution_point() const + { + return data().m_issuing_distribution_point; + } +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_crl.h b/src/libs/3rdparty/botan/src/lib/x509/x509_crl.h new file mode 100644 index 0000000000..89925aa043 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_crl.h @@ -0,0 +1,141 @@ +/* +* X.509 CRL +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_CRL_H_ +#define BOTAN_X509_CRL_H_ + +#include <botan/x509_obj.h> +#include <botan/x509_dn.h> +#include <botan/crl_ent.h> +#include <vector> + +namespace Botan { + +class Extensions; +class X509_Certificate; + +struct CRL_Data; + +/** +* This class represents X.509 Certificate Revocation Lists (CRLs). +*/ +class BOTAN_PUBLIC_API(2,0) X509_CRL final : public X509_Object + { + public: + /** + * This class represents CRL related errors. + */ + class BOTAN_PUBLIC_API(2,0) X509_CRL_Error final : public Exception + { + public: + explicit X509_CRL_Error(const std::string& error) : + Exception("X509_CRL: " + error) {} + }; + + /** + * Check if this particular certificate is listed in the CRL + */ + bool is_revoked(const X509_Certificate& cert) const; + + /** + * Get the entries of this CRL in the form of a vector. + * @return vector containing the entries of this CRL. + */ + const std::vector<CRL_Entry>& get_revoked() const; + + /** + * Get the issuer DN of this CRL. + * @return CRLs issuer DN + */ + const X509_DN& issuer_dn() const; + + /** + * @return extension data for this CRL + */ + const Extensions& extensions() const; + + /** + * Get the AuthorityKeyIdentifier of this CRL. + * @return this CRLs AuthorityKeyIdentifier + */ + const std::vector<uint8_t>& authority_key_id() const; + + /** + * Get the serial number of this CRL. + * @return CRLs serial number + */ + uint32_t crl_number() const; + + /** + * Get the CRL's thisUpdate value. + * @return CRLs thisUpdate + */ + const X509_Time& this_update() const; + + /** + * Get the CRL's nextUpdate value. + * @return CRLs nextdUpdate + */ + const X509_Time& next_update() const; + + /** + * Get the CRL's distribution point + * @return CRL.IssuingDistributionPoint from the CRL's Data_Store + */ + std::string crl_issuing_distribution_point() const; + + /** + * Create an uninitialized CRL object. Any attempts to access + * this object will throw an exception. + */ + X509_CRL() = default; + + /** + * Construct a CRL from a data source. + * @param source the data source providing the DER or PEM encoded CRL. + */ + X509_CRL(DataSource& source); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + /** + * Construct a CRL from a file containing the DER or PEM encoded CRL. + * @param filename the name of the CRL file + */ + X509_CRL(const std::string& filename); +#endif + + /** + * Construct a CRL from a binary vector + * @param vec the binary (DER) representation of the CRL + */ + X509_CRL(const std::vector<uint8_t>& vec); + + /** + * Construct a CRL + * @param issuer issuer of this CRL + * @param thisUpdate valid from + * @param nextUpdate valid until + * @param revoked entries to be included in the CRL + */ + X509_CRL(const X509_DN& issuer, const X509_Time& thisUpdate, + const X509_Time& nextUpdate, const std::vector<CRL_Entry>& revoked); + + private: + std::string PEM_label() const override; + + std::vector<std::string> alternate_PEM_labels() const override; + + void force_decode() override; + + const CRL_Data& data() const; + + std::shared_ptr<CRL_Data> m_data; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_dn.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509_dn.cpp new file mode 100644 index 0000000000..9eb509daba --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_dn.cpp @@ -0,0 +1,382 @@ +/* +* X509_DN +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509_dn.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/parsing.h> +#include <botan/internal/stl_util.h> +#include <botan/oids.h> +#include <ostream> +#include <cctype> + +namespace Botan { + +/* +* Add an attribute to a X509_DN +*/ +void X509_DN::add_attribute(const std::string& type, + const std::string& str) + { + add_attribute(OIDS::lookup(type), str); + } + +/* +* Add an attribute to a X509_DN +*/ +void X509_DN::add_attribute(const OID& oid, const ASN1_String& str) + { + if(str.empty()) + return; + + m_rdn.push_back(std::make_pair(oid, str)); + m_dn_bits.clear(); + } + +/* +* Get the attributes of this X509_DN +*/ +std::multimap<OID, std::string> X509_DN::get_attributes() const + { + std::multimap<OID, std::string> retval; + + for(auto& i : m_rdn) + multimap_insert(retval, i.first, i.second.value()); + return retval; + } + +/* +* Get the contents of this X.500 Name +*/ +std::multimap<std::string, std::string> X509_DN::contents() const + { + std::multimap<std::string, std::string> retval; + + for(auto& i : m_rdn) + { + std::string str_value = OIDS::oid2str(i.first); + + if(str_value.empty()) + str_value = i.first.as_string(); + multimap_insert(retval, str_value, i.second.value()); + } + return retval; + } + +bool X509_DN::has_field(const std::string& attr) const + { + return has_field(OIDS::lookup(deref_info_field(attr))); + } + +bool X509_DN::has_field(const OID& oid) const + { + for(auto& i : m_rdn) + { + if(i.first == oid) + return true; + } + + return false; + } + +std::string X509_DN::get_first_attribute(const std::string& attr) const + { + const OID oid = OIDS::lookup(deref_info_field(attr)); + return get_first_attribute(oid).value(); + } + +ASN1_String X509_DN::get_first_attribute(const OID& oid) const + { + for(auto& i : m_rdn) + { + if(i.first == oid) + { + return i.second; + } + } + + return ASN1_String(); + } + +/* +* Get a single attribute type +*/ +std::vector<std::string> X509_DN::get_attribute(const std::string& attr) const + { + const OID oid = OIDS::lookup(deref_info_field(attr)); + + std::vector<std::string> values; + + for(auto& i : m_rdn) + { + if(i.first == oid) + { + values.push_back(i.second.value()); + } + } + + return values; + } + +/* +* Deref aliases in a subject/issuer info request +*/ +std::string X509_DN::deref_info_field(const std::string& info) + { + if(info == "Name" || info == "CommonName" || info == "CN") return "X520.CommonName"; + if(info == "SerialNumber" || info == "SN") return "X520.SerialNumber"; + if(info == "Country" || info == "C") return "X520.Country"; + if(info == "Organization" || info == "O") return "X520.Organization"; + if(info == "Organizational Unit" || info == "OrgUnit" || info == "OU") + return "X520.OrganizationalUnit"; + if(info == "Locality" || info == "L") return "X520.Locality"; + if(info == "State" || info == "Province" || info == "ST") return "X520.State"; + if(info == "Email") return "RFC822"; + return info; + } + +/* +* Compare two X509_DNs for equality +*/ +bool operator==(const X509_DN& dn1, const X509_DN& dn2) + { + auto attr1 = dn1.get_attributes(); + auto attr2 = dn2.get_attributes(); + + if(attr1.size() != attr2.size()) return false; + + auto p1 = attr1.begin(); + auto p2 = attr2.begin(); + + while(true) + { + if(p1 == attr1.end() && p2 == attr2.end()) + break; + if(p1 == attr1.end()) return false; + if(p2 == attr2.end()) return false; + if(p1->first != p2->first) return false; + if(!x500_name_cmp(p1->second, p2->second)) + return false; + ++p1; + ++p2; + } + return true; + } + +/* +* Compare two X509_DNs for inequality +*/ +bool operator!=(const X509_DN& dn1, const X509_DN& dn2) + { + return !(dn1 == dn2); + } + +/* +* Induce an arbitrary ordering on DNs +*/ +bool operator<(const X509_DN& dn1, const X509_DN& dn2) + { + auto attr1 = dn1.get_attributes(); + auto attr2 = dn2.get_attributes(); + + if(attr1.size() < attr2.size()) return true; + if(attr1.size() > attr2.size()) return false; + + for(auto p1 = attr1.begin(); p1 != attr1.end(); ++p1) + { + auto p2 = attr2.find(p1->first); + if(p2 == attr2.end()) return false; + if(p1->second > p2->second) return false; + if(p1->second < p2->second) return true; + } + return false; + } + +/* +* DER encode a DistinguishedName +*/ +void X509_DN::encode_into(DER_Encoder& der) const + { + der.start_cons(SEQUENCE); + + if(!m_dn_bits.empty()) + { + /* + If we decoded this from somewhere, encode it back exactly as + we received it + */ + der.raw_bytes(m_dn_bits); + } + else + { + for(const auto& dn : m_rdn) + { + der.start_cons(SET) + .start_cons(SEQUENCE) + .encode(dn.first) + .encode(dn.second) + .end_cons() + .end_cons(); + } + } + + der.end_cons(); + } + +/* +* Decode a BER encoded DistinguishedName +*/ +void X509_DN::decode_from(BER_Decoder& source) + { + std::vector<uint8_t> bits; + + source.start_cons(SEQUENCE) + .raw_bytes(bits) + .end_cons(); + + BER_Decoder sequence(bits); + + while(sequence.more_items()) + { + BER_Decoder rdn = sequence.start_cons(SET); + + while(rdn.more_items()) + { + OID oid; + ASN1_String str; + + rdn.start_cons(SEQUENCE).decode(oid).decode(str).end_cons(); + + add_attribute(oid, str); + } + } + + m_dn_bits = bits; + } + +namespace { + +std::string to_short_form(const OID& oid) + { + const std::string long_id = OIDS::oid2str(oid); + + if(long_id.empty()) + return oid.to_string(); + + if(long_id == "X520.CommonName") + return "CN"; + + if(long_id == "X520.Country") + return "C"; + + if(long_id == "X520.Organization") + return "O"; + + if(long_id == "X520.OrganizationalUnit") + return "OU"; + + return long_id; + } + +} + +std::ostream& operator<<(std::ostream& out, const X509_DN& dn) + { + auto info = dn.dn_info(); + + for(size_t i = 0; i != info.size(); ++i) + { + out << to_short_form(info[i].first) << "=\""; + for(char c : info[i].second.value()) + { + if(c == '\\' || c == '\"') + { + out << "\\"; + } + out << c; + } + out << "\""; + + if(i + 1 < info.size()) + { + out << ","; + } + } + return out; + } + +std::istream& operator>>(std::istream& in, X509_DN& dn) + { + in >> std::noskipws; + do + { + std::string key; + std::string val; + char c; + + while(in.good()) + { + in >> c; + + if(std::isspace(c) && key.empty()) + continue; + else if(!std::isspace(c)) + { + key.push_back(c); + break; + } + else + break; + } + + while(in.good()) + { + in >> c; + + if(!std::isspace(c) && c != '=') + key.push_back(c); + else if(c == '=') + break; + else + throw Invalid_Argument("Ill-formed X.509 DN"); + } + + bool in_quotes = false; + while(in.good()) + { + in >> c; + + if(std::isspace(c)) + { + if(!in_quotes && !val.empty()) + break; + else if(in_quotes) + val.push_back(' '); + } + else if(c == '"') + in_quotes = !in_quotes; + else if(c == '\\') + { + if(in.good()) + in >> c; + val.push_back(c); + } + else if(c == ',' && !in_quotes) + break; + else + val.push_back(c); + } + + if(!key.empty() && !val.empty()) + dn.add_attribute(X509_DN::deref_info_field(key),val); + else + break; + } + while(in.good()); + return in; + } +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_dn.h b/src/libs/3rdparty/botan/src/lib/x509/x509_dn.h new file mode 100644 index 0000000000..9d8beb0bf1 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_dn.h @@ -0,0 +1,97 @@ +/* +* X.509 Distinguished Name +* (C) 1999-2010,2018 Jack Lloyd +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_DN_H_ +#define BOTAN_X509_DN_H_ + +#include <botan/asn1_obj.h> +#include <botan/asn1_oid.h> +#include <botan/asn1_str.h> +#include <vector> +#include <map> +#include <iosfwd> + +namespace Botan { + +/** +* Distinguished Name +*/ +class BOTAN_PUBLIC_API(2,0) X509_DN final : public ASN1_Object + { + public: + X509_DN() = default; + + explicit X509_DN(const std::multimap<OID, std::string>& args) + { + for(auto i : args) + add_attribute(i.first, i.second); + } + + explicit X509_DN(const std::multimap<std::string, std::string>& args) + { + for(auto i : args) + add_attribute(i.first, i.second); + } + + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + bool has_field(const OID& oid) const; + ASN1_String get_first_attribute(const OID& oid) const; + + /* + * Return the BER encoded data, if any + */ + const std::vector<uint8_t>& get_bits() const { return m_dn_bits; } + + bool empty() const { return m_rdn.empty(); } + + const std::vector<std::pair<OID,ASN1_String>>& dn_info() const { return m_rdn; } + + std::multimap<OID, std::string> get_attributes() const; + std::multimap<std::string, std::string> contents() const; + + bool has_field(const std::string& attr) const; + std::vector<std::string> get_attribute(const std::string& attr) const; + std::string get_first_attribute(const std::string& attr) const; + + void add_attribute(const std::string& key, const std::string& val); + + void add_attribute(const OID& oid, const std::string& val) + { + add_attribute(oid, ASN1_String(val)); + } + + void add_attribute(const OID& oid, const ASN1_String& val); + + static std::string deref_info_field(const std::string& key); + + /** + * Lookup upper bounds in characters for the length of distinguished name fields + * as given in RFC 5280, Appendix A. + * + * @param oid the oid of the DN to lookup + * @return the upper bound, or zero if no ub is known to Botan + */ + static size_t lookup_ub(const OID& oid); + + private: + std::vector<std::pair<OID,ASN1_String>> m_rdn; + std::vector<uint8_t> m_dn_bits; + }; + +bool BOTAN_PUBLIC_API(2,0) operator==(const X509_DN&, const X509_DN&); +bool BOTAN_PUBLIC_API(2,0) operator!=(const X509_DN&, const X509_DN&); +bool BOTAN_PUBLIC_API(2,0) operator<(const X509_DN&, const X509_DN&); + +BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream& out, const X509_DN& dn); +BOTAN_PUBLIC_API(2,0) std::istream& operator>>(std::istream& in, X509_DN& dn); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_dn_ub.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509_dn_ub.cpp new file mode 100644 index 0000000000..cf8714320e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_dn_ub.cpp @@ -0,0 +1,58 @@ +/* +* DN_UB maps: Upper bounds on the length of DN strings +* +* This file was automatically generated by ./src/scripts/oids.py on 2017-12-23 +* +* All manual edits to this file will be lost. Edit the script +* then regenerate this source file. +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509_dn.h> +#include <botan/asn1_oid.h> +#include <map> + +namespace { +/** + * Upper bounds for the length of distinguished name fields as given in RFC 5280, Appendix A. + * Only OIDS recognized by botan are considered, so far. + * Maps OID string representations instead of human readable strings in order + * to avoid an additional lookup. + */ +static const std::map<Botan::OID, size_t> DN_UB = + { + { Botan::OID("2.5.4.10"), 64 }, // X520.Organization + { Botan::OID("2.5.4.11"), 64 }, // X520.OrganizationalUnit + { Botan::OID("2.5.4.12"), 64 }, // X520.Title + { Botan::OID("2.5.4.3"), 64 }, // X520.CommonName + { Botan::OID("2.5.4.4"), 40 }, // X520.Surname + { Botan::OID("2.5.4.42"), 32768 }, // X520.GivenName + { Botan::OID("2.5.4.43"), 32768 }, // X520.Initials + { Botan::OID("2.5.4.44"), 32768 }, // X520.GenerationalQualifier + { Botan::OID("2.5.4.46"), 64 }, // X520.DNQualifier + { Botan::OID("2.5.4.5"), 64 }, // X520.SerialNumber + { Botan::OID("2.5.4.6"), 3 }, // X520.Country + { Botan::OID("2.5.4.65"), 128 }, // X520.Pseudonym + { Botan::OID("2.5.4.7"), 128 }, // X520.Locality + { Botan::OID("2.5.4.8"), 128 } // X520.State + }; +} + +namespace Botan { + +//static +size_t X509_DN::lookup_ub(const OID& oid) + { + auto ub_entry = DN_UB.find(oid); + if(ub_entry != DN_UB.end()) + { + return ub_entry->second; + } + else + { + return 0; + } + } +} + diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_ext.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509_ext.cpp new file mode 100644 index 0000000000..122be2885d --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_ext.cpp @@ -0,0 +1,1000 @@ +/* +* X.509 Certificate Extensions +* (C) 1999-2010,2012 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509_ext.h> +#include <botan/x509cert.h> +#include <botan/datastor.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/oids.h> +#include <botan/hash.h> +#include <botan/internal/bit_ops.h> +#include <algorithm> +#include <set> +#include <sstream> + +namespace Botan { + +/* +* Create a Certificate_Extension object of some kind to handle +*/ +std::unique_ptr<Certificate_Extension> +Extensions::create_extn_obj(const OID& oid, + bool critical, + const std::vector<uint8_t>& body) + { + const std::string oid_str = oid.as_string(); + + std::unique_ptr<Certificate_Extension> extn; + + if(oid == Cert_Extension::Subject_Key_ID::static_oid()) + { + extn.reset(new Cert_Extension::Subject_Key_ID); + } + else if(oid == Cert_Extension::Key_Usage::static_oid()) + { + extn.reset(new Cert_Extension::Key_Usage); + } + else if(oid == Cert_Extension::Subject_Alternative_Name::static_oid()) + { + extn.reset(new Cert_Extension::Subject_Alternative_Name); + } + else if(oid == Cert_Extension::Issuer_Alternative_Name::static_oid()) + { + extn.reset(new Cert_Extension::Issuer_Alternative_Name); + } + else if(oid == Cert_Extension::Basic_Constraints::static_oid()) + { + extn.reset(new Cert_Extension::Basic_Constraints); + } + else if(oid == Cert_Extension::CRL_Number::static_oid()) + { + extn.reset(new Cert_Extension::CRL_Number); + } + else if(oid == Cert_Extension::CRL_ReasonCode::static_oid()) + { + extn.reset(new Cert_Extension::CRL_ReasonCode); + } + else if(oid == Cert_Extension::Authority_Key_ID::static_oid()) + { + extn.reset(new Cert_Extension::Authority_Key_ID); + } + else if(oid == Cert_Extension::Name_Constraints::static_oid()) + { + extn.reset(new Cert_Extension::Name_Constraints); + } + else if(oid == Cert_Extension::CRL_Distribution_Points::static_oid()) + { + extn.reset(new Cert_Extension::CRL_Distribution_Points); + } + else if(oid == Cert_Extension::CRL_Issuing_Distribution_Point::static_oid()) + { + extn.reset(new Cert_Extension::CRL_Issuing_Distribution_Point); + } + else if(oid == Cert_Extension::Certificate_Policies::static_oid()) + { + extn.reset(new Cert_Extension::Certificate_Policies); + } + else if(oid == Cert_Extension::Extended_Key_Usage::static_oid()) + { + extn.reset(new Cert_Extension::Extended_Key_Usage); + } + else if(oid == Cert_Extension::Authority_Information_Access::static_oid()) + { + extn.reset(new Cert_Extension::Authority_Information_Access); + } + else + { + // some other unknown extension type + extn.reset(new Cert_Extension::Unknown_Extension(oid, critical)); + } + + try + { + extn->decode_inner(body); + } + catch(Decoding_Error& e) + { + throw Decoding_Error("Decoding X.509 extension " + oid.as_string() + " failed", e.what()); + } + return extn; + } + +/* +* Validate the extension (the default implementation is a NOP) +*/ +void Certificate_Extension::validate(const X509_Certificate&, const X509_Certificate&, + const std::vector<std::shared_ptr<const X509_Certificate>>&, + std::vector<std::set<Certificate_Status_Code>>&, + size_t) + { + } + +/* +* Add a new cert +*/ +void Extensions::add(Certificate_Extension* extn, bool critical) + { + // sanity check: we don't want to have the same extension more than once + if(m_extension_info.count(extn->oid_of()) > 0) + throw Invalid_Argument(extn->oid_name() + " extension already present in Extensions::add"); + + const OID oid = extn->oid_of(); + Extensions_Info info(critical, extn); + m_extension_oids.push_back(oid); + m_extension_info.emplace(oid, info); + } + +bool Extensions::add_new(Certificate_Extension* extn, bool critical) + { + if(m_extension_info.count(extn->oid_of()) > 0) + { + delete extn; + return false; // already exists + } + + const OID oid = extn->oid_of(); + Extensions_Info info(critical, extn); + m_extension_oids.push_back(oid); + m_extension_info.emplace(oid, info); + return true; + } + +void Extensions::replace(Certificate_Extension* extn, bool critical) + { + // Remove it if it existed + m_extension_info.erase(extn->oid_of()); + + const OID oid = extn->oid_of(); + Extensions_Info info(critical, extn); + m_extension_oids.push_back(oid); + m_extension_info.emplace(oid, info); + } + +bool Extensions::extension_set(const OID& oid) const + { + return (m_extension_info.find(oid) != m_extension_info.end()); + } + +bool Extensions::critical_extension_set(const OID& oid) const + { + auto i = m_extension_info.find(oid); + if(i != m_extension_info.end()) + return i->second.is_critical(); + return false; + } + +const Certificate_Extension* Extensions::get_extension_object(const OID& oid) const + { + auto extn = m_extension_info.find(oid); + if(extn == m_extension_info.end()) + return nullptr; + + return &extn->second.obj(); + } + +std::unique_ptr<Certificate_Extension> Extensions::get(const OID& oid) const + { + if(const Certificate_Extension* ext = this->get_extension_object(oid)) + { + return std::unique_ptr<Certificate_Extension>(ext->copy()); + } + return nullptr; + } + +std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> Extensions::extensions() const + { + std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> exts; + for(auto&& ext : m_extension_info) + { + exts.push_back( + std::make_pair( + std::unique_ptr<Certificate_Extension>(ext.second.obj().copy()), + ext.second.is_critical()) + ); + } + return exts; + } + +std::map<OID, std::pair<std::vector<uint8_t>, bool>> Extensions::extensions_raw() const + { + std::map<OID, std::pair<std::vector<uint8_t>, bool>> out; + for(auto&& ext : m_extension_info) + { + out.emplace(ext.first, + std::make_pair(ext.second.bits(), + ext.second.is_critical())); + } + return out; + } + +/* +* Encode an Extensions list +*/ +void Extensions::encode_into(DER_Encoder& to_object) const + { + for(auto ext_info : m_extension_info) + { + const OID& oid = ext_info.first; + const bool should_encode = ext_info.second.obj().should_encode(); + + if(should_encode) + { + const bool is_critical = ext_info.second.is_critical(); + const std::vector<uint8_t>& ext_value = ext_info.second.bits(); + + to_object.start_cons(SEQUENCE) + .encode(oid) + .encode_optional(is_critical, false) + .encode(ext_value, OCTET_STRING) + .end_cons(); + } + } + } + +/* +* Decode a list of Extensions +*/ +void Extensions::decode_from(BER_Decoder& from_source) + { + m_extension_oids.clear(); + m_extension_info.clear(); + + BER_Decoder sequence = from_source.start_cons(SEQUENCE); + + while(sequence.more_items()) + { + OID oid; + bool critical; + std::vector<uint8_t> bits; + + sequence.start_cons(SEQUENCE) + .decode(oid) + .decode_optional(critical, BOOLEAN, UNIVERSAL, false) + .decode(bits, OCTET_STRING) + .end_cons(); + + std::unique_ptr<Certificate_Extension> obj = create_extn_obj(oid, critical, bits); + Extensions_Info info(critical, bits, obj.release()); + + m_extension_oids.push_back(oid); + m_extension_info.emplace(oid, info); + } + sequence.verify_end(); + } + +/* +* Write the extensions to an info store +*/ +void Extensions::contents_to(Data_Store& subject_info, + Data_Store& issuer_info) const + { + for(auto&& m_extn_info : m_extension_info) + { + m_extn_info.second.obj().contents_to(subject_info, issuer_info); + subject_info.add(m_extn_info.second.obj().oid_name() + ".is_critical", + m_extn_info.second.is_critical()); + } + } + +namespace Cert_Extension { + +/* +* Checked accessor for the path_limit member +*/ +size_t Basic_Constraints::get_path_limit() const + { + if(!m_is_ca) + throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA"); + return m_path_limit; + } + +/* +* Encode the extension +*/ +std::vector<uint8_t> Basic_Constraints::encode_inner() const + { + std::vector<uint8_t> output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode_if(m_is_ca, + DER_Encoder() + .encode(m_is_ca) + .encode_optional(m_path_limit, NO_CERT_PATH_LIMIT) + ) + .end_cons(); + return output; + } + +/* +* Decode the extension +*/ +void Basic_Constraints::decode_inner(const std::vector<uint8_t>& in) + { + BER_Decoder(in) + .start_cons(SEQUENCE) + .decode_optional(m_is_ca, BOOLEAN, UNIVERSAL, false) + .decode_optional(m_path_limit, INTEGER, UNIVERSAL, NO_CERT_PATH_LIMIT) + .end_cons(); + + if(m_is_ca == false) + m_path_limit = 0; + } + +/* +* Return a textual representation +*/ +void Basic_Constraints::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.BasicConstraints.is_ca", (m_is_ca ? 1 : 0)); + subject.add("X509v3.BasicConstraints.path_constraint", static_cast<uint32_t>(m_path_limit)); + } + +/* +* Encode the extension +*/ +std::vector<uint8_t> Key_Usage::encode_inner() const + { + if(m_constraints == NO_CONSTRAINTS) + throw Encoding_Error("Cannot encode zero usage constraints"); + + const size_t unused_bits = low_bit(m_constraints) - 1; + + std::vector<uint8_t> der; + der.push_back(BIT_STRING); + der.push_back(2 + ((unused_bits < 8) ? 1 : 0)); + der.push_back(unused_bits % 8); + der.push_back((m_constraints >> 8) & 0xFF); + if(m_constraints & 0xFF) + der.push_back(m_constraints & 0xFF); + + return der; + } + +/* +* Decode the extension +*/ +void Key_Usage::decode_inner(const std::vector<uint8_t>& in) + { + BER_Decoder ber(in); + + BER_Object obj = ber.get_next_object(); + + obj.assert_is_a(BIT_STRING, UNIVERSAL, "usage constraint"); + + if(obj.length() != 2 && obj.length() != 3) + throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); + + uint16_t usage = 0; + + const uint8_t* bits = obj.bits(); + + if(bits[0] >= 8) + throw BER_Decoding_Error("Invalid unused bits in usage constraint"); + + const uint8_t mask = static_cast<uint8_t>(0xFF << bits[0]); + + if(obj.length() == 2) + { + usage = make_uint16(bits[1] & mask, 0); + } + else if(obj.length() == 3) + { + usage = make_uint16(bits[1], bits[2] & mask); + } + + m_constraints = Key_Constraints(usage); + } + +/* +* Return a textual representation +*/ +void Key_Usage::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.KeyUsage", m_constraints); + } + +/* +* Encode the extension +*/ +std::vector<uint8_t> Subject_Key_ID::encode_inner() const + { + std::vector<uint8_t> output; + DER_Encoder(output).encode(m_key_id, OCTET_STRING); + return output; + } + +/* +* Decode the extension +*/ +void Subject_Key_ID::decode_inner(const std::vector<uint8_t>& in) + { + BER_Decoder(in).decode(m_key_id, OCTET_STRING).verify_end(); + } + +/* +* Return a textual representation +*/ +void Subject_Key_ID::contents_to(Data_Store& subject, Data_Store&) const + { + subject.add("X509v3.SubjectKeyIdentifier", m_key_id); + } + +/* +* Subject_Key_ID Constructor +*/ +Subject_Key_ID::Subject_Key_ID(const std::vector<uint8_t>& pub_key, const std::string& hash_name) + { + std::unique_ptr<HashFunction> hash(HashFunction::create_or_throw(hash_name)); + + m_key_id.resize(hash->output_length()); + + hash->update(pub_key); + hash->final(m_key_id.data()); + + // Truncate longer hashes, 192 bits here seems plenty + const size_t max_skid_len = (192 / 8); + if(m_key_id.size() > max_skid_len) + m_key_id.resize(max_skid_len); + } + +/* +* Encode the extension +*/ +std::vector<uint8_t> Authority_Key_ID::encode_inner() const + { + std::vector<uint8_t> output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode(m_key_id, OCTET_STRING, ASN1_Tag(0), CONTEXT_SPECIFIC) + .end_cons(); + return output; + } + +/* +* Decode the extension +*/ +void Authority_Key_ID::decode_inner(const std::vector<uint8_t>& in) + { + BER_Decoder(in) + .start_cons(SEQUENCE) + .decode_optional_string(m_key_id, OCTET_STRING, 0); + } + +/* +* Return a textual representation +*/ +void Authority_Key_ID::contents_to(Data_Store&, Data_Store& issuer) const + { + if(m_key_id.size()) + issuer.add("X509v3.AuthorityKeyIdentifier", m_key_id); + } + +/* +* Encode the extension +*/ +std::vector<uint8_t> Subject_Alternative_Name::encode_inner() const + { + std::vector<uint8_t> output; + DER_Encoder(output).encode(m_alt_name); + return output; + } + +/* +* Encode the extension +*/ +std::vector<uint8_t> Issuer_Alternative_Name::encode_inner() const + { + std::vector<uint8_t> output; + DER_Encoder(output).encode(m_alt_name); + return output; + } + +/* +* Decode the extension +*/ +void Subject_Alternative_Name::decode_inner(const std::vector<uint8_t>& in) + { + BER_Decoder(in).decode(m_alt_name); + } + +/* +* Decode the extension +*/ +void Issuer_Alternative_Name::decode_inner(const std::vector<uint8_t>& in) + { + BER_Decoder(in).decode(m_alt_name); + } + +/* +* Return a textual representation +*/ +void Subject_Alternative_Name::contents_to(Data_Store& subject_info, + Data_Store&) const + { + subject_info.add(get_alt_name().contents()); + } + +/* +* Return a textual representation +*/ +void Issuer_Alternative_Name::contents_to(Data_Store&, Data_Store& issuer_info) const + { + issuer_info.add(get_alt_name().contents()); + } + +/* +* Encode the extension +*/ +std::vector<uint8_t> Extended_Key_Usage::encode_inner() const + { + std::vector<uint8_t> output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode_list(m_oids) + .end_cons(); + return output; + } + +/* +* Decode the extension +*/ +void Extended_Key_Usage::decode_inner(const std::vector<uint8_t>& in) + { + BER_Decoder(in).decode_list(m_oids); + } + +/* +* Return a textual representation +*/ +void Extended_Key_Usage::contents_to(Data_Store& subject, Data_Store&) const + { + for(size_t i = 0; i != m_oids.size(); ++i) + subject.add("X509v3.ExtendedKeyUsage", m_oids[i].as_string()); + } + +/* +* Encode the extension +*/ +std::vector<uint8_t> Name_Constraints::encode_inner() const + { + throw Not_Implemented("Name_Constraints encoding"); + } + + +/* +* Decode the extension +*/ +void Name_Constraints::decode_inner(const std::vector<uint8_t>& in) + { + std::vector<GeneralSubtree> permit, exclude; + BER_Decoder ber(in); + BER_Decoder ext = ber.start_cons(SEQUENCE); + BER_Object per = ext.get_next_object(); + + ext.push_back(per); + if(per.is_a(0, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) + { + ext.decode_list(permit,ASN1_Tag(0),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + if(permit.empty()) + throw Encoding_Error("Empty Name Contraint list"); + } + + BER_Object exc = ext.get_next_object(); + ext.push_back(exc); + if(per.is_a(1, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) + { + ext.decode_list(exclude,ASN1_Tag(1),ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + if(exclude.empty()) + throw Encoding_Error("Empty Name Contraint list"); + } + + ext.end_cons(); + + if(permit.empty() && exclude.empty()) + throw Encoding_Error("Empty Name Contraint extension"); + + m_name_constraints = NameConstraints(std::move(permit),std::move(exclude)); + } + +/* +* Return a textual representation +*/ +void Name_Constraints::contents_to(Data_Store& subject, Data_Store&) const + { + std::stringstream ss; + + for(const GeneralSubtree& gs: m_name_constraints.permitted()) + { + ss << gs; + subject.add("X509v3.NameConstraints.permitted", ss.str()); + ss.str(std::string()); + } + for(const GeneralSubtree& gs: m_name_constraints.excluded()) + { + ss << gs; + subject.add("X509v3.NameConstraints.excluded", ss.str()); + ss.str(std::string()); + } + } + +void Name_Constraints::validate(const X509_Certificate& subject, const X509_Certificate& issuer, + const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + std::vector<std::set<Certificate_Status_Code>>& cert_status, + size_t pos) + { + if(!m_name_constraints.permitted().empty() || !m_name_constraints.excluded().empty()) + { + if(!subject.is_CA_cert() || !subject.is_critical("X509v3.NameConstraints")) + cert_status.at(pos).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR); + + const bool issuer_name_constraint_critical = + issuer.is_critical("X509v3.NameConstraints"); + + const bool at_self_signed_root = (pos == cert_path.size() - 1); + + // Check that all subordinate certs pass the name constraint + for(size_t j = 0; j <= pos; ++j) + { + if(pos == j && at_self_signed_root) + continue; + + bool permitted = m_name_constraints.permitted().empty(); + bool failed = false; + + for(auto c: m_name_constraints.permitted()) + { + switch(c.base().matches(*cert_path.at(j))) + { + case GeneralName::MatchResult::NotFound: + case GeneralName::MatchResult::All: + permitted = true; + break; + case GeneralName::MatchResult::UnknownType: + failed = issuer_name_constraint_critical; + permitted = true; + break; + default: + break; + } + } + + for(auto c: m_name_constraints.excluded()) + { + switch(c.base().matches(*cert_path.at(j))) + { + case GeneralName::MatchResult::All: + case GeneralName::MatchResult::Some: + failed = true; + break; + case GeneralName::MatchResult::UnknownType: + failed = issuer_name_constraint_critical; + break; + default: + break; + } + } + + if(failed || !permitted) + { + cert_status.at(j).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR); + } + } + } + } + +namespace { + +/* +* A policy specifier +*/ +class Policy_Information final : public ASN1_Object + { + public: + Policy_Information() = default; + explicit Policy_Information(const OID& oid) : m_oid(oid) {} + + const OID& oid() const { return m_oid; } + + void encode_into(DER_Encoder& codec) const override + { + codec.start_cons(SEQUENCE) + .encode(m_oid) + .end_cons(); + } + + void decode_from(BER_Decoder& codec) override + { + codec.start_cons(SEQUENCE) + .decode(m_oid) + .discard_remaining() + .end_cons(); + } + + private: + OID m_oid; + }; + +} + +/* +* Encode the extension +*/ +std::vector<uint8_t> Certificate_Policies::encode_inner() const + { + std::vector<Policy_Information> policies; + + for(size_t i = 0; i != m_oids.size(); ++i) + policies.push_back(Policy_Information(m_oids[i])); + + std::vector<uint8_t> output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .encode_list(policies) + .end_cons(); + return output; + } + +/* +* Decode the extension +*/ +void Certificate_Policies::decode_inner(const std::vector<uint8_t>& in) + { + std::vector<Policy_Information> policies; + + BER_Decoder(in).decode_list(policies); + m_oids.clear(); + for(size_t i = 0; i != policies.size(); ++i) + m_oids.push_back(policies[i].oid()); + } + +/* +* Return a textual representation +*/ +void Certificate_Policies::contents_to(Data_Store& info, Data_Store&) const + { + for(size_t i = 0; i != m_oids.size(); ++i) + info.add("X509v3.CertificatePolicies", m_oids[i].as_string()); + } + +void Certificate_Policies::validate( + const X509_Certificate& /*subject*/, + const X509_Certificate& /*issuer*/, + const std::vector<std::shared_ptr<const X509_Certificate>>& /*cert_path*/, + std::vector<std::set<Certificate_Status_Code>>& cert_status, + size_t pos) + { + std::set<OID> oid_set(m_oids.begin(), m_oids.end()); + if(oid_set.size() != m_oids.size()) + { + cert_status.at(pos).insert(Certificate_Status_Code::DUPLICATE_CERT_POLICY); + } + } + +std::vector<uint8_t> Authority_Information_Access::encode_inner() const + { + ASN1_String url(m_ocsp_responder, IA5_STRING); + + std::vector<uint8_t> output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .encode(OIDS::lookup("PKIX.OCSP")) + .add_object(ASN1_Tag(6), CONTEXT_SPECIFIC, url.value()) + .end_cons() + .end_cons(); + return output; + } + +void Authority_Information_Access::decode_inner(const std::vector<uint8_t>& in) + { + BER_Decoder ber = BER_Decoder(in).start_cons(SEQUENCE); + + while(ber.more_items()) + { + OID oid; + + BER_Decoder info = ber.start_cons(SEQUENCE); + + info.decode(oid); + + if(oid == OIDS::lookup("PKIX.OCSP")) + { + BER_Object name = info.get_next_object(); + + if(name.is_a(6, CONTEXT_SPECIFIC)) + { + m_ocsp_responder = ASN1::to_string(name); + } + + } + if(oid == OIDS::lookup("PKIX.CertificateAuthorityIssuers")) + { + BER_Object name = info.get_next_object(); + + if(name.is_a(6, CONTEXT_SPECIFIC)) + { + m_ca_issuers.push_back(ASN1::to_string(name)); + } + } + } + } + +void Authority_Information_Access::contents_to(Data_Store& subject, Data_Store&) const + { + if(!m_ocsp_responder.empty()) + subject.add("OCSP.responder", m_ocsp_responder); + for(const std::string& ca_issuer : m_ca_issuers) + subject.add("PKIX.CertificateAuthorityIssuers", ca_issuer); + } + +/* +* Checked accessor for the crl_number member +*/ +size_t CRL_Number::get_crl_number() const + { + if(!m_has_value) + throw Invalid_State("CRL_Number::get_crl_number: Not set"); + return m_crl_number; + } + +/* +* Copy a CRL_Number extension +*/ +CRL_Number* CRL_Number::copy() const + { + if(!m_has_value) + throw Invalid_State("CRL_Number::copy: Not set"); + return new CRL_Number(m_crl_number); + } + +/* +* Encode the extension +*/ +std::vector<uint8_t> CRL_Number::encode_inner() const + { + std::vector<uint8_t> output; + DER_Encoder(output).encode(m_crl_number); + return output; + } + +/* +* Decode the extension +*/ +void CRL_Number::decode_inner(const std::vector<uint8_t>& in) + { + BER_Decoder(in).decode(m_crl_number); + m_has_value = true; + } + +/* +* Return a textual representation +*/ +void CRL_Number::contents_to(Data_Store& info, Data_Store&) const + { + info.add("X509v3.CRLNumber", static_cast<uint32_t>(m_crl_number)); + } + +/* +* Encode the extension +*/ +std::vector<uint8_t> CRL_ReasonCode::encode_inner() const + { + std::vector<uint8_t> output; + DER_Encoder(output).encode(static_cast<size_t>(m_reason), ENUMERATED, UNIVERSAL); + return output; + } + +/* +* Decode the extension +*/ +void CRL_ReasonCode::decode_inner(const std::vector<uint8_t>& in) + { + size_t reason_code = 0; + BER_Decoder(in).decode(reason_code, ENUMERATED, UNIVERSAL); + m_reason = static_cast<CRL_Code>(reason_code); + } + +/* +* Return a textual representation +*/ +void CRL_ReasonCode::contents_to(Data_Store& info, Data_Store&) const + { + info.add("X509v3.CRLReasonCode", m_reason); + } + +std::vector<uint8_t> CRL_Distribution_Points::encode_inner() const + { + throw Not_Implemented("CRL_Distribution_Points encoding"); + } + +void CRL_Distribution_Points::decode_inner(const std::vector<uint8_t>& buf) + { + BER_Decoder(buf) + .decode_list(m_distribution_points) + .verify_end(); + + std::stringstream ss; + + for(size_t i = 0; i != m_distribution_points.size(); ++i) + { + auto contents = m_distribution_points[i].point().contents(); + + for(const auto& pair : contents) + { + ss << pair.first << ": " << pair.second << " "; + } + } + + m_crl_distribution_urls.push_back(ss.str()); + } + +void CRL_Distribution_Points::contents_to(Data_Store& subject, Data_Store&) const + { + for(const std::string& crl_url : m_crl_distribution_urls) + subject.add("CRL.DistributionPoint", crl_url); + } + +void CRL_Distribution_Points::Distribution_Point::encode_into(class DER_Encoder&) const + { + throw Not_Implemented("CRL_Distribution_Points encoding"); + } + +void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder& ber) + { + ber.start_cons(SEQUENCE) + .start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC) + .decode_optional_implicit(m_point, ASN1_Tag(0), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED), + SEQUENCE, CONSTRUCTED) + .end_cons().end_cons(); + } + +std::vector<uint8_t> CRL_Issuing_Distribution_Point::encode_inner() const + { + throw Not_Implemented("CRL_Issuing_Distribution_Point encoding"); + } + +void CRL_Issuing_Distribution_Point::decode_inner(const std::vector<uint8_t>& buf) + { + BER_Decoder(buf).decode(m_distribution_point).verify_end(); + } + +void CRL_Issuing_Distribution_Point::contents_to(Data_Store& info, Data_Store&) const + { + auto contents = m_distribution_point.point().contents(); + std::stringstream ss; + + for(const auto& pair : contents) + { + ss << pair.first << ": " << pair.second << " "; + } + + info.add("X509v3.CRLIssuingDistributionPoint", ss.str()); + } + +std::vector<uint8_t> Unknown_Extension::encode_inner() const + { + return m_bytes; + } + +void Unknown_Extension::decode_inner(const std::vector<uint8_t>& bytes) + { + // Just treat as an opaque blob at this level + m_bytes = bytes; + } + +void Unknown_Extension::contents_to(Data_Store&, Data_Store&) const + { + // No information store + } + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_ext.h b/src/libs/3rdparty/botan/src/lib/x509/x509_ext.h new file mode 100644 index 0000000000..6e71fb8797 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_ext.h @@ -0,0 +1,790 @@ +/* +* X.509 Certificate Extensions +* (C) 1999-2007,2012 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_EXTENSIONS_H_ +#define BOTAN_X509_EXTENSIONS_H_ + +#include <botan/asn1_obj.h> +#include <botan/asn1_oid.h> +#include <botan/asn1_alt_name.h> +#include <botan/cert_status.h> +#include <botan/name_constraint.h> +#include <botan/key_constraint.h> +#include <botan/crl_ent.h> +#include <set> + +namespace Botan { + +class Data_Store; +class X509_Certificate; + +/** +* X.509 Certificate Extension +*/ +class BOTAN_PUBLIC_API(2,0) Certificate_Extension + { + public: + /** + * @return OID representing this extension + */ + virtual OID oid_of() const = 0; + + /* + * @return specific OID name + * If possible OIDS table should match oid_name to OIDS, ie + * OIDS::lookup(ext->oid_name()) == ext->oid_of() + * Should return empty string if OID is not known + */ + virtual std::string oid_name() const = 0; + + /** + * Make a copy of this extension + * @return copy of this + */ + virtual Certificate_Extension* copy() const = 0; + + /* + * Add the contents of this extension into the information + * for the subject and/or issuer, as necessary. + * @param subject the subject info + * @param issuer the issuer info + */ + virtual void contents_to(Data_Store& subject, + Data_Store& issuer) const = 0; + + /* + * Callback visited during path validation. + * + * An extension can implement this callback to inspect + * the path during path validation. + * + * If an error occurs during validation of this extension, + * an appropriate status code shall be added to cert_status. + * + * @param subject Subject certificate that contains this extension + * @param issuer Issuer certificate + * @param status Certificate validation status codes for subject certificate + * @param cert_path Certificate path which is currently validated + * @param pos Position of subject certificate in cert_path + */ + virtual void validate(const X509_Certificate& subject, const X509_Certificate& issuer, + const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + std::vector<std::set<Certificate_Status_Code>>& cert_status, + size_t pos); + + virtual ~Certificate_Extension() = default; + protected: + friend class Extensions; + virtual bool should_encode() const { return true; } + virtual std::vector<uint8_t> encode_inner() const = 0; + virtual void decode_inner(const std::vector<uint8_t>&) = 0; + }; + +/** +* X.509 Certificate Extension List +*/ +class BOTAN_PUBLIC_API(2,0) Extensions final : public ASN1_Object + { + public: + /** + * Look up an object in the extensions, based on OID Returns + * nullptr if not set, if the extension was either absent or not + * handled. The pointer returned is owned by the Extensions + * object. + * This would be better with an optional<T> return value + */ + const Certificate_Extension* get_extension_object(const OID& oid) const; + + template<typename T> + const T* get_extension_object_as(const OID& oid = T::static_oid()) const + { + if(const Certificate_Extension* extn = get_extension_object(oid)) + { + if(const T* extn_as_T = dynamic_cast<const T*>(extn)) + { + return extn_as_T; + } + else + { + throw Exception("Exception::get_extension_object_as dynamic_cast failed"); + } + } + + return nullptr; + } + + /** + * Return the set of extensions in the order they appeared in the certificate + * (or as they were added, if constructed) + */ + const std::vector<OID>& get_extension_oids() const + { + return m_extension_oids; + } + + /** + * Return true if an extension was set + */ + bool extension_set(const OID& oid) const; + + /** + * Return true if an extesion was set and marked critical + */ + bool critical_extension_set(const OID& oid) const; + + /** + * Return the raw bytes of the extension + * Will throw if OID was not set as an extension. + */ + std::vector<uint8_t> get_extension_bits(const OID& oid) const; + + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + void contents_to(Data_Store&, Data_Store&) const; + + /** + * Adds a new extension to the list. + * @param extn pointer to the certificate extension (Extensions takes ownership) + * @param critical whether this extension should be marked as critical + * @throw Invalid_Argument if the extension is already present in the list + */ + void add(Certificate_Extension* extn, bool critical = false); + + /** + * Adds a new extension to the list unless it already exists. If the extension + * already exists within the Extensions object, the extn pointer will be deleted. + * + * @param extn pointer to the certificate extension (Extensions takes ownership) + * @param critical whether this extension should be marked as critical + * @return true if the object was added false if the extension was already used + */ + bool add_new(Certificate_Extension* extn, bool critical = false); + + /** + * Adds an extension to the list or replaces it. + * @param extn the certificate extension + * @param critical whether this extension should be marked as critical + */ + void replace(Certificate_Extension* extn, bool critical = false); + + /** + * Searches for an extension by OID and returns the result. + * Only the known extensions types declared in this header + * are searched for by this function. + * @return Copy of extension with oid, nullptr if not found. + * Can avoid creating a copy by using get_extension_object function + */ + std::unique_ptr<Certificate_Extension> get(const OID& oid) const; + + /** + * Searches for an extension by OID and returns the result decoding + * it to some arbitrary extension type chosen by the application. + * + * Only the unknown extensions, that is, extensions types that + * are not declared in this header, are searched for by this + * function. + * + * @return Pointer to new extension with oid, nullptr if not found. + */ + template<typename T> + std::unique_ptr<T> get_raw(const OID& oid) const + { + auto extn_info = m_extension_info.find(oid); + + if(extn_info != m_extension_info.end()) + { + // Unknown_Extension oid_name is empty + if(extn_info->second.obj().oid_name() == "") + { + std::unique_ptr<T> ext(new T); + ext->decode_inner(extn_info->second.bits()); + return std::move(ext); + } + } + return nullptr; + } + + /** + * Returns a copy of the list of extensions together with the corresponding + * criticality flag. All extensions are encoded as some object, falling back + * to Unknown_Extension class which simply allows reading the bytes as well + * as the criticality flag. + */ + std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const; + + /** + * Returns the list of extensions as raw, encoded bytes + * together with the corresponding criticality flag. + * Contains all extensions, including any extensions encoded as Unknown_Extension + */ + std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const; + + Extensions() {} + + Extensions(const Extensions&) = default; + Extensions& operator=(const Extensions&) = default; + +#if !defined(BOTAN_BUILD_COMPILER_IS_MSVC_2013) + Extensions(Extensions&&) = default; + Extensions& operator=(Extensions&&) = default; +#endif + + private: + static std::unique_ptr<Certificate_Extension> + create_extn_obj(const OID& oid, + bool critical, + const std::vector<uint8_t>& body); + + class Extensions_Info + { + public: + Extensions_Info(bool critical, + Certificate_Extension* ext) : + m_obj(ext), + m_bits(m_obj->encode_inner()), + m_critical(critical) + { + } + + Extensions_Info(bool critical, + const std::vector<uint8_t>& encoding, + Certificate_Extension* ext) : + m_obj(ext), + m_bits(encoding), + m_critical(critical) + { + } + + bool is_critical() const { return m_critical; } + const std::vector<uint8_t>& bits() const { return m_bits; } + const Certificate_Extension& obj() const + { + BOTAN_ASSERT_NONNULL(m_obj.get()); + return *m_obj.get(); + } + + private: + std::shared_ptr<Certificate_Extension> m_obj; + std::vector<uint8_t> m_bits; + bool m_critical = false; + }; + + std::vector<OID> m_extension_oids; + std::map<OID, Extensions_Info> m_extension_info; + }; + +namespace Cert_Extension { + +static const size_t NO_CERT_PATH_LIMIT = 0xFFFFFFF0; + +/** +* Basic Constraints Extension +*/ +class BOTAN_PUBLIC_API(2,0) Basic_Constraints final : public Certificate_Extension + { + public: + Basic_Constraints* copy() const override + { return new Basic_Constraints(m_is_ca, m_path_limit); } + + Basic_Constraints(bool ca = false, size_t limit = 0) : + m_is_ca(ca), m_path_limit(limit) {} + + bool get_is_ca() const { return m_is_ca; } + size_t get_path_limit() const; + + static OID static_oid() { return OID("2.5.29.19"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override + { return "X509v3.BasicConstraints"; } + + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + bool m_is_ca; + size_t m_path_limit; + }; + +/** +* Key Usage Constraints Extension +*/ +class BOTAN_PUBLIC_API(2,0) Key_Usage final : public Certificate_Extension + { + public: + Key_Usage* copy() const override { return new Key_Usage(m_constraints); } + + explicit Key_Usage(Key_Constraints c = NO_CONSTRAINTS) : m_constraints(c) {} + + Key_Constraints get_constraints() const { return m_constraints; } + + static OID static_oid() { return OID("2.5.29.15"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override { return "X509v3.KeyUsage"; } + + bool should_encode() const override + { return (m_constraints != NO_CONSTRAINTS); } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + Key_Constraints m_constraints; + }; + +/** +* Subject Key Identifier Extension +*/ +class BOTAN_PUBLIC_API(2,0) Subject_Key_ID final : public Certificate_Extension + { + public: + Subject_Key_ID() = default; + + explicit Subject_Key_ID(const std::vector<uint8_t>& k) : m_key_id(k) {} + + Subject_Key_ID(const std::vector<uint8_t>& public_key, + const std::string& hash_fn); + + Subject_Key_ID* copy() const override + { return new Subject_Key_ID(m_key_id); } + + const std::vector<uint8_t>& get_key_id() const { return m_key_id; } + + static OID static_oid() { return OID("2.5.29.14"); } + OID oid_of() const override { return static_oid(); } + + private: + + std::string oid_name() const override + { return "X509v3.SubjectKeyIdentifier"; } + + bool should_encode() const override { return (m_key_id.size() > 0); } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + std::vector<uint8_t> m_key_id; + }; + +/** +* Authority Key Identifier Extension +*/ +class BOTAN_PUBLIC_API(2,0) Authority_Key_ID final : public Certificate_Extension + { + public: + Authority_Key_ID* copy() const override + { return new Authority_Key_ID(m_key_id); } + + Authority_Key_ID() = default; + explicit Authority_Key_ID(const std::vector<uint8_t>& k) : m_key_id(k) {} + + const std::vector<uint8_t>& get_key_id() const { return m_key_id; } + + static OID static_oid() { return OID("2.5.29.35"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override + { return "X509v3.AuthorityKeyIdentifier"; } + + bool should_encode() const override { return (m_key_id.size() > 0); } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + std::vector<uint8_t> m_key_id; + }; + +/** +* Subject Alternative Name Extension +*/ +class BOTAN_PUBLIC_API(2,4) Subject_Alternative_Name final : public Certificate_Extension + { + public: + const AlternativeName& get_alt_name() const { return m_alt_name; } + + static OID static_oid() { return OID("2.5.29.17"); } + OID oid_of() const override { return static_oid(); } + + Subject_Alternative_Name* copy() const override + { return new Subject_Alternative_Name(get_alt_name()); } + + explicit Subject_Alternative_Name(const AlternativeName& name = AlternativeName()) : + m_alt_name(name) {} + + private: + std::string oid_name() const override { return "X509v3.SubjectAlternativeName"; } + + bool should_encode() const override { return m_alt_name.has_items(); } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + AlternativeName m_alt_name; + }; + +/** +* Issuer Alternative Name Extension +*/ +class BOTAN_PUBLIC_API(2,0) Issuer_Alternative_Name final : public Certificate_Extension + { + public: + const AlternativeName& get_alt_name() const { return m_alt_name; } + + static OID static_oid() { return OID("2.5.29.18"); } + OID oid_of() const override { return static_oid(); } + + Issuer_Alternative_Name* copy() const override + { return new Issuer_Alternative_Name(get_alt_name()); } + + explicit Issuer_Alternative_Name(const AlternativeName& name = AlternativeName()) : + m_alt_name(name) {} + + private: + std::string oid_name() const override { return "X509v3.IssuerAlternativeName"; } + + bool should_encode() const override { return m_alt_name.has_items(); } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + AlternativeName m_alt_name; + }; + +/** +* Extended Key Usage Extension +*/ +class BOTAN_PUBLIC_API(2,0) Extended_Key_Usage final : public Certificate_Extension + { + public: + Extended_Key_Usage* copy() const override + { return new Extended_Key_Usage(m_oids); } + + Extended_Key_Usage() = default; + explicit Extended_Key_Usage(const std::vector<OID>& o) : m_oids(o) {} + + const std::vector<OID>& get_oids() const { return m_oids; } + + static OID static_oid() { return OID("2.5.29.37"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override { return "X509v3.ExtendedKeyUsage"; } + + bool should_encode() const override { return (m_oids.size() > 0); } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + std::vector<OID> m_oids; + }; + +/** +* Name Constraints +*/ +class BOTAN_PUBLIC_API(2,0) Name_Constraints final : public Certificate_Extension + { + public: + Name_Constraints* copy() const override + { return new Name_Constraints(m_name_constraints); } + + Name_Constraints() = default; + Name_Constraints(const NameConstraints &nc) : m_name_constraints(nc) {} + + void validate(const X509_Certificate& subject, const X509_Certificate& issuer, + const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + std::vector<std::set<Certificate_Status_Code>>& cert_status, + size_t pos) override; + + const NameConstraints& get_name_constraints() const { return m_name_constraints; } + + static OID static_oid() { return OID("2.5.29.30"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override + { return "X509v3.NameConstraints"; } + + bool should_encode() const override { return true; } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + NameConstraints m_name_constraints; + }; + +/** +* Certificate Policies Extension +*/ +class BOTAN_PUBLIC_API(2,0) Certificate_Policies final : public Certificate_Extension + { + public: + Certificate_Policies* copy() const override + { return new Certificate_Policies(m_oids); } + + Certificate_Policies() = default; + explicit Certificate_Policies(const std::vector<OID>& o) : m_oids(o) {} + + BOTAN_DEPRECATED("Use get_policy_oids") + std::vector<OID> get_oids() const { return m_oids; } + + const std::vector<OID>& get_policy_oids() const { return m_oids; } + + static OID static_oid() { return OID("2.5.29.32"); } + OID oid_of() const override { return static_oid(); } + + void validate(const X509_Certificate& subject, const X509_Certificate& issuer, + const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + std::vector<std::set<Certificate_Status_Code>>& cert_status, + size_t pos) override; + private: + std::string oid_name() const override + { return "X509v3.CertificatePolicies"; } + + bool should_encode() const override { return (m_oids.size() > 0); } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + std::vector<OID> m_oids; + }; + +/** +* Authority Information Access Extension +*/ +class BOTAN_PUBLIC_API(2,0) Authority_Information_Access final : public Certificate_Extension + { + public: + Authority_Information_Access* copy() const override + { return new Authority_Information_Access(m_ocsp_responder, m_ca_issuers); } + + Authority_Information_Access() = default; + + explicit Authority_Information_Access(const std::string& ocsp, const std::vector<std::string>& ca_issuers = std::vector<std::string>()) : + m_ocsp_responder(ocsp), m_ca_issuers(ca_issuers) {} + + std::string ocsp_responder() const { return m_ocsp_responder; } + + static OID static_oid() { return OID("1.3.6.1.5.5.7.1.1"); } + OID oid_of() const override { return static_oid(); } + const std::vector<std::string> ca_issuers() const { return m_ca_issuers; } + + private: + std::string oid_name() const override + { return "PKIX.AuthorityInformationAccess"; } + + bool should_encode() const override { return (!m_ocsp_responder.empty()); } + + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + + void contents_to(Data_Store&, Data_Store&) const override; + + std::string m_ocsp_responder; + std::vector<std::string> m_ca_issuers; + }; + +/** +* CRL Number Extension +*/ +class BOTAN_PUBLIC_API(2,0) CRL_Number final : public Certificate_Extension + { + public: + CRL_Number* copy() const override; + + CRL_Number() : m_has_value(false), m_crl_number(0) {} + CRL_Number(size_t n) : m_has_value(true), m_crl_number(n) {} + + size_t get_crl_number() const; + + static OID static_oid() { return OID("2.5.29.20"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override { return "X509v3.CRLNumber"; } + + bool should_encode() const override { return m_has_value; } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + bool m_has_value; + size_t m_crl_number; + }; + +/** +* CRL Entry Reason Code Extension +*/ +class BOTAN_PUBLIC_API(2,0) CRL_ReasonCode final : public Certificate_Extension + { + public: + CRL_ReasonCode* copy() const override + { return new CRL_ReasonCode(m_reason); } + + explicit CRL_ReasonCode(CRL_Code r = UNSPECIFIED) : m_reason(r) {} + + CRL_Code get_reason() const { return m_reason; } + + static OID static_oid() { return OID("2.5.29.21"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override { return "X509v3.ReasonCode"; } + + bool should_encode() const override { return (m_reason != UNSPECIFIED); } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + CRL_Code m_reason; + }; + +/** +* CRL Distribution Points Extension +* todo enforce restrictions from RFC 5280 4.2.1.13 +*/ +class BOTAN_PUBLIC_API(2,0) CRL_Distribution_Points final : public Certificate_Extension + { + public: + class BOTAN_PUBLIC_API(2,0) Distribution_Point final : public ASN1_Object + { + public: + void encode_into(class DER_Encoder&) const override; + void decode_from(class BER_Decoder&) override; + + const AlternativeName& point() const { return m_point; } + private: + AlternativeName m_point; + }; + + CRL_Distribution_Points* copy() const override + { return new CRL_Distribution_Points(m_distribution_points); } + + CRL_Distribution_Points() = default; + + explicit CRL_Distribution_Points(const std::vector<Distribution_Point>& points) : + m_distribution_points(points) {} + + const std::vector<Distribution_Point>& distribution_points() const + { return m_distribution_points; } + + const std::vector<std::string>& crl_distribution_urls() const + { return m_crl_distribution_urls; } + + static OID static_oid() { return OID("2.5.29.31"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override + { return "X509v3.CRLDistributionPoints"; } + + bool should_encode() const override + { return !m_distribution_points.empty(); } + + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + std::vector<Distribution_Point> m_distribution_points; + std::vector<std::string> m_crl_distribution_urls; + }; + +/** +* CRL Issuing Distribution Point Extension +* todo enforce restrictions from RFC 5280 5.2.5 +*/ +class CRL_Issuing_Distribution_Point final : public Certificate_Extension + { + public: + CRL_Issuing_Distribution_Point() = default; + + explicit CRL_Issuing_Distribution_Point(const CRL_Distribution_Points::Distribution_Point& distribution_point) : + m_distribution_point(distribution_point) {} + + CRL_Issuing_Distribution_Point* copy() const override + { return new CRL_Issuing_Distribution_Point(m_distribution_point); } + + const AlternativeName& get_point() const + { return m_distribution_point.point(); } + + static OID static_oid() { return OID("2.5.29.28"); } + OID oid_of() const override { return static_oid(); } + + private: + std::string oid_name() const override + { return "X509v3.CRLIssuingDistributionPoint"; } + + bool should_encode() const override { return true; } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + CRL_Distribution_Points::Distribution_Point m_distribution_point; + }; + +/** +* An unknown X.509 extension +* Will add a failure to the path validation result, if critical +*/ +class BOTAN_PUBLIC_API(2,4) Unknown_Extension final : public Certificate_Extension + { + public: + Unknown_Extension(const OID& oid, bool critical) : + m_oid(oid), m_critical(critical) {} + + Unknown_Extension* copy() const override + { return new Unknown_Extension(m_oid, m_critical); } + + /** + * Return the OID of this unknown extension + */ + OID oid_of() const override + { return m_oid; } + + //static_oid not defined for Unknown_Extension + + /** + * Return the extension contents + */ + const std::vector<uint8_t>& extension_contents() const { return m_bytes; } + + /** + * Return if this extension was marked critical + */ + bool is_critical_extension() const { return m_critical; } + + void validate(const X509_Certificate&, const X509_Certificate&, + const std::vector<std::shared_ptr<const X509_Certificate>>&, + std::vector<std::set<Certificate_Status_Code>>& cert_status, + size_t pos) override + { + if(m_critical) + { + cert_status.at(pos).insert(Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION); + } + } + + private: + std::string oid_name() const override { return ""; } + + bool should_encode() const override { return true; } + std::vector<uint8_t> encode_inner() const override; + void decode_inner(const std::vector<uint8_t>&) override; + void contents_to(Data_Store&, Data_Store&) const override; + + OID m_oid; + bool m_critical; + std::vector<uint8_t> m_bytes; + }; + + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_obj.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509_obj.cpp new file mode 100644 index 0000000000..0604530729 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_obj.cpp @@ -0,0 +1,379 @@ +/* +* X.509 SIGNED Object +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509_obj.h> +#include <botan/pubkey.h> +#include <botan/oids.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/parsing.h> +#include <botan/pem.h> +#include <botan/emsa.h> +#include <algorithm> + +namespace Botan { + +namespace { +struct Pss_params + { + AlgorithmIdentifier hash_algo; + AlgorithmIdentifier mask_gen_algo; + AlgorithmIdentifier mask_gen_hash; // redundant: decoded mask_gen_algo.parameters + size_t salt_len; + size_t trailer_field; + }; + +Pss_params decode_pss_params(const std::vector<uint8_t>& encoded_pss_params) + { + const AlgorithmIdentifier default_hash("SHA-160", AlgorithmIdentifier::USE_NULL_PARAM); + const AlgorithmIdentifier default_mgf("MGF1", default_hash.BER_encode()); + + Pss_params pss_parameter; + BER_Decoder(encoded_pss_params) + .start_cons(SEQUENCE) + .decode_optional(pss_parameter.hash_algo, ASN1_Tag(0), PRIVATE, default_hash) + .decode_optional(pss_parameter.mask_gen_algo, ASN1_Tag(1), PRIVATE, default_mgf) + .decode_optional(pss_parameter.salt_len, ASN1_Tag(2), PRIVATE, size_t(20)) + .decode_optional(pss_parameter.trailer_field, ASN1_Tag(3), PRIVATE, size_t(1)) + .end_cons(); + + BER_Decoder(pss_parameter.mask_gen_algo.get_parameters()).decode(pss_parameter.mask_gen_hash); + + return pss_parameter; + } +} + +/* +* Read a PEM or BER X.509 object +*/ +void X509_Object::load_data(DataSource& in) + { + try { + if(ASN1::maybe_BER(in) && !PEM_Code::matches(in)) + { + BER_Decoder dec(in); + decode_from(dec); + } + else + { + std::string got_label; + DataSource_Memory ber(PEM_Code::decode(in, got_label)); + + if(got_label != PEM_label()) + { + bool is_alternate = false; + for(std::string alt_label : alternate_PEM_labels()) + { + if(got_label == alt_label) + { + is_alternate = true; + break; + } + } + + if(!is_alternate) + throw Decoding_Error("Unexpected PEM label for " + PEM_label() + " of " + got_label); + } + + BER_Decoder dec(ber); + decode_from(dec); + } + } + catch(Decoding_Error& e) + { + throw Decoding_Error(PEM_label() + " decoding failed: " + e.what()); + } + } + + +void X509_Object::encode_into(DER_Encoder& to) const + { + to.start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .raw_bytes(signed_body()) + .end_cons() + .encode(signature_algorithm()) + .encode(signature(), BIT_STRING) + .end_cons(); + } + +/* +* Read a BER encoded X.509 object +*/ +void X509_Object::decode_from(BER_Decoder& from) + { + from.start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .raw_bytes(m_tbs_bits) + .end_cons() + .decode(m_sig_algo) + .decode(m_sig, BIT_STRING) + .end_cons(); + + force_decode(); + } + +/* +* Return a PEM encoded X.509 object +*/ +std::string X509_Object::PEM_encode() const + { + return PEM_Code::encode(BER_encode(), PEM_label()); + } + +/* +* Return the TBS data +*/ +std::vector<uint8_t> X509_Object::tbs_data() const + { + return ASN1::put_in_sequence(m_tbs_bits); + } + +/* +* Return the hash used in generating the signature +*/ +std::string X509_Object::hash_used_for_signature() const + { + const OID& oid = m_sig_algo.get_oid(); + const std::vector<std::string> sig_info = split_on(OIDS::lookup(oid), '/'); + + if(sig_info.size() == 1 && sig_info[0] == "Ed25519") + return "SHA-512"; + else if(sig_info.size() != 2) + throw Internal_Error("Invalid name format found for " + oid.as_string()); + + if(sig_info[1] == "EMSA4") + { + return OIDS::lookup(decode_pss_params(signature_algorithm().get_parameters()).hash_algo.get_oid()); + } + else + { + const std::vector<std::string> pad_and_hash = + parse_algorithm_name(sig_info[1]); + + if(pad_and_hash.size() != 2) + { + throw Internal_Error("Invalid name format " + sig_info[1]); + } + + return pad_and_hash[1]; + } + } + +/* +* Check the signature on an object +*/ +bool X509_Object::check_signature(const Public_Key* pub_key) const + { + if(!pub_key) + throw Exception("No key provided for " + PEM_label() + " signature check"); + std::unique_ptr<const Public_Key> key(pub_key); + return check_signature(*key); + } + +bool X509_Object::check_signature(const Public_Key& pub_key) const + { + const Certificate_Status_Code code = verify_signature(pub_key); + return (code == Certificate_Status_Code::VERIFIED); + } + +Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key) const + { + const std::vector<std::string> sig_info = + split_on(OIDS::lookup(m_sig_algo.get_oid()), '/'); + + if(sig_info.size() < 1 || sig_info.size() > 2 || sig_info[0] != pub_key.algo_name()) + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + + std::string padding; + if(sig_info.size() == 2) + padding = sig_info[1]; + else if(sig_info[0] == "Ed25519") + padding = "Pure"; + else + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + + const Signature_Format format = + (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; + + if(padding == "EMSA4") + { + // "MUST contain RSASSA-PSS-params" + if(signature_algorithm().parameters.empty()) + { + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + } + + Pss_params pss_parameter = decode_pss_params(signature_algorithm().parameters); + + // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512 + const std::string hash_algo = OIDS::lookup(pss_parameter.hash_algo.oid); + if(hash_algo != "SHA-160" && + hash_algo != "SHA-224" && + hash_algo != "SHA-256" && + hash_algo != "SHA-384" && + hash_algo != "SHA-512") + { + return Certificate_Status_Code::UNTRUSTED_HASH; + } + + const std::string mgf_algo = OIDS::lookup(pss_parameter.mask_gen_algo.oid); + if(mgf_algo != "MGF1") + { + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + } + + // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm + // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512 + if(pss_parameter.mask_gen_hash.oid != pss_parameter.hash_algo.oid) + { + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + } + + if(pss_parameter.trailer_field != 1) + { + return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS; + } + + // salt_len is actually not used for verification. Length is inferred from the signature + padding += "(" + hash_algo + "," + mgf_algo + "," + std::to_string(pss_parameter.salt_len) + ")"; + } + + try + { + PK_Verifier verifier(pub_key, padding, format); + const bool valid = verifier.verify_message(tbs_data(), signature()); + + if(valid) + return Certificate_Status_Code::VERIFIED; + else + return Certificate_Status_Code::SIGNATURE_ERROR; + } + catch(Algorithm_Not_Found&) + { + return Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN; + } + catch(...) + { + // This shouldn't happen, fallback to generic signature error + return Certificate_Status_Code::SIGNATURE_ERROR; + } + } + +/* +* Apply the X.509 SIGNED macro +*/ +std::vector<uint8_t> X509_Object::make_signed(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& algo, + const secure_vector<uint8_t>& tbs_bits) + { + const std::vector<uint8_t> signature = signer->sign_message(tbs_bits, rng); + + std::vector<uint8_t> output; + DER_Encoder(output) + .start_cons(SEQUENCE) + .raw_bytes(tbs_bits) + .encode(algo) + .encode(signature, BIT_STRING) + .end_cons(); + + return output; + } + +namespace { + +std::string choose_sig_algo(AlgorithmIdentifier& sig_algo, + const Private_Key& key, + const std::string& hash_fn, + const std::string& user_specified) + { + const std::string algo_name = key.algo_name(); + std::string padding; + + // check algo_name and set default + if(algo_name == "RSA") + { + // set to EMSA3 for compatibility reasons, originally it was the only option + padding = "EMSA3(" + hash_fn + ")"; + } + else if(algo_name == "DSA" || + algo_name == "ECDSA" || + algo_name == "ECGDSA" || + algo_name == "ECKCDSA" || + algo_name == "GOST-34.10") + { + padding = "EMSA1(" + hash_fn + ")"; + } + else if(algo_name == "Ed25519") + { + padding = "Pure"; + } + else + { + throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name); + } + + if(user_specified.empty() == false) + { + padding = user_specified; + } + + if(padding != "Pure") + { + // try to construct an EMSA object from the padding options or default + std::unique_ptr<EMSA> emsa; + try + { + emsa.reset(get_emsa(padding)); + } + /* + * get_emsa will throw if opts contains {"padding",<valid_padding>} but + * <valid_padding> does not specify a hash function. + * Omitting it is valid since it needs to be identical to hash_fn. + * If it still throws, something happened that we cannot repair here, + * e.g. the algorithm/padding combination is not supported. + */ + catch(...) + { + emsa.reset(get_emsa(padding + "(" + hash_fn + ")")); + } + + if(!emsa) + { + throw Invalid_Argument("Could not parse padding scheme " + padding); + } + + sig_algo = emsa->config_for_x509(key, hash_fn); + return emsa->name(); + } + else + { + sig_algo = AlgorithmIdentifier(OIDS::lookup("Ed25519"), AlgorithmIdentifier::USE_EMPTY_PARAM); + return "Pure"; + } + } + +} + +/* +* Choose a signing format for the key +*/ +std::unique_ptr<PK_Signer> X509_Object::choose_sig_format(AlgorithmIdentifier& sig_algo, + const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& hash_fn, + const std::string& padding_algo) + { + const Signature_Format format = (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363; + + const std::string emsa = choose_sig_algo(sig_algo, key, hash_fn, padding_algo); + + return std::unique_ptr<PK_Signer>(new PK_Signer(key, rng, emsa, format)); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_obj.h b/src/libs/3rdparty/botan/src/lib/x509/x509_obj.h new file mode 100644 index 0000000000..a0c8e5b398 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_obj.h @@ -0,0 +1,145 @@ +/* +* X.509 SIGNED Object +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_OBJECT_H_ +#define BOTAN_X509_OBJECT_H_ + +#include <botan/asn1_obj.h> +#include <botan/alg_id.h> +#include <botan/cert_status.h> +#include <vector> + +namespace Botan { + +class Public_Key; +class Private_Key; +class RandomNumberGenerator; + +/** +* This class represents abstract X.509 signed objects as in the X.500 +* SIGNED macro +*/ +class BOTAN_PUBLIC_API(2,0) X509_Object : public ASN1_Object + { + public: + /** + * The underlying data that is to be or was signed + * @return data that is or was signed + */ + std::vector<uint8_t> tbs_data() const; + + /** + * @return signature on tbs_data() + */ + const std::vector<uint8_t>& signature() const { return m_sig; } + + /** + * @return signed body + */ + const std::vector<uint8_t>& signed_body() const { return m_tbs_bits; } + + /** + * @return signature algorithm that was used to generate signature + */ + const AlgorithmIdentifier& signature_algorithm() const { return m_sig_algo; } + + /** + * @return hash algorithm that was used to generate signature + */ + std::string hash_used_for_signature() const; + + /** + * Create a signed X509 object. + * @param signer the signer used to sign the object + * @param rng the random number generator to use + * @param alg_id the algorithm identifier of the signature scheme + * @param tbs the tbs bits to be signed + * @return signed X509 object + */ + static std::vector<uint8_t> make_signed(class PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& alg_id, + const secure_vector<uint8_t>& tbs); + + /** + * Check the signature on this data + * @param key the public key purportedly used to sign this data + * @return status of the signature - OK if verified or otherwise an indicator of + * the problem preventing verification. + */ + Certificate_Status_Code verify_signature(const Public_Key& key) const; + + /** + * Check the signature on this data + * @param key the public key purportedly used to sign this data + * @return true if the signature is valid, otherwise false + */ + bool check_signature(const Public_Key& key) const; + + /** + * Check the signature on this data + * @param key the public key purportedly used to sign this data + * the object will be deleted after use (this should have + * been a std::unique_ptr<Public_Key>) + * @return true if the signature is valid, otherwise false + */ + bool check_signature(const Public_Key* key) const; + + /** + * DER encode an X509_Object + * See @ref ASN1_Object::encode_into() + */ + void encode_into(class DER_Encoder& to) const override; + + /** + * Decode a BER encoded X509_Object + * See @ref ASN1_Object::decode_from() + */ + void decode_from(class BER_Decoder& from) override; + + /** + * @return PEM encoding of this + */ + std::string PEM_encode() const; + + X509_Object(const X509_Object&) = default; + X509_Object& operator=(const X509_Object&) = default; + + virtual std::string PEM_label() const = 0; + + virtual std::vector<std::string> alternate_PEM_labels() const + { return std::vector<std::string>(); } + + virtual ~X509_Object() = default; + + static std::unique_ptr<PK_Signer> + choose_sig_format(AlgorithmIdentifier& sig_algo, + const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& hash_fn, + const std::string& padding_algo); + + protected: + + X509_Object() = default; + + /** + * Decodes from src as either DER or PEM data, then calls force_decode() + */ + void load_data(DataSource& src); + + private: + virtual void force_decode() = 0; + + AlgorithmIdentifier m_sig_algo; + std::vector<uint8_t> m_tbs_bits; + std::vector<uint8_t> m_sig; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509cert.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509cert.cpp new file mode 100644 index 0000000000..ddfe5d5b2b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509cert.cpp @@ -0,0 +1,879 @@ +/* +* X.509 Certificates +* (C) 1999-2010,2015,2017 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509cert.h> +#include <botan/datastor.h> +#include <botan/pk_keys.h> +#include <botan/x509_ext.h> +#include <botan/ber_dec.h> +#include <botan/parsing.h> +#include <botan/bigint.h> +#include <botan/oids.h> +#include <botan/hash.h> +#include <botan/hex.h> +#include <algorithm> +#include <sstream> + +namespace Botan { + +struct X509_Certificate_Data + { + std::vector<uint8_t> m_serial; + AlgorithmIdentifier m_sig_algo_inner; + X509_DN m_issuer_dn; + X509_DN m_subject_dn; + std::vector<uint8_t> m_issuer_dn_bits; + std::vector<uint8_t> m_subject_dn_bits; + X509_Time m_not_before; + X509_Time m_not_after; + std::vector<uint8_t> m_subject_public_key_bits; + std::vector<uint8_t> m_subject_public_key_bits_seq; + std::vector<uint8_t> m_subject_public_key_bitstring; + std::vector<uint8_t> m_subject_public_key_bitstring_sha1; + AlgorithmIdentifier m_subject_public_key_algid; + + std::vector<uint8_t> m_v2_issuer_key_id; + std::vector<uint8_t> m_v2_subject_key_id; + Extensions m_v3_extensions; + + std::vector<OID> m_extended_key_usage; + std::vector<uint8_t> m_authority_key_id; + std::vector<uint8_t> m_subject_key_id; + std::vector<OID> m_cert_policies; + + std::vector<std::string> m_crl_distribution_points; + std::string m_ocsp_responder; + std::vector<std::string> m_ca_issuers; + + AlternativeName m_subject_alt_name; + AlternativeName m_issuer_alt_name; + NameConstraints m_name_constraints; + + Data_Store m_subject_ds; + Data_Store m_issuer_ds; + + size_t m_version = 0; + size_t m_path_len_constraint = 0; + Key_Constraints m_key_constraints = NO_CONSTRAINTS; + bool m_self_signed = false; + bool m_is_ca_certificate = false; + bool m_serial_negative = false; + }; + +std::string X509_Certificate::PEM_label() const + { + return "CERTIFICATE"; + } + +std::vector<std::string> X509_Certificate::alternate_PEM_labels() const + { + return { "X509 CERTIFICATE" }; + } + +X509_Certificate::X509_Certificate(DataSource& src) + { + load_data(src); + } + +X509_Certificate::X509_Certificate(const std::vector<uint8_t>& vec) + { + DataSource_Memory src(vec.data(), vec.size()); + load_data(src); + } + +X509_Certificate::X509_Certificate(const uint8_t data[], size_t len) + { + DataSource_Memory src(data, len); + load_data(src); + } + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) +X509_Certificate::X509_Certificate(const std::string& fsname) + { + DataSource_Stream src(fsname, true); + load_data(src); + } +#endif + +namespace { + +std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(const X509_Object& obj) + { + std::unique_ptr<X509_Certificate_Data> data(new X509_Certificate_Data); + + BigInt serial_bn; + BER_Object public_key; + BER_Object v3_exts_data; + + BER_Decoder(obj.signed_body()) + .decode_optional(data->m_version, ASN1_Tag(0), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + .decode(serial_bn) + .decode(data->m_sig_algo_inner) + .decode(data->m_issuer_dn) + .start_cons(SEQUENCE) + .decode(data->m_not_before) + .decode(data->m_not_after) + .end_cons() + .decode(data->m_subject_dn) + .get_next(public_key) + .decode_optional_string(data->m_v2_issuer_key_id, BIT_STRING, 1) + .decode_optional_string(data->m_v2_subject_key_id, BIT_STRING, 2) + .get_next(v3_exts_data) + .verify_end("TBSCertificate has extra data after extensions block"); + + if(data->m_version > 2) + throw Decoding_Error("Unknown X.509 cert version " + std::to_string(data->m_version)); + if(obj.signature_algorithm() != data->m_sig_algo_inner) + throw Decoding_Error("X.509 Certificate had differing algorithm identifers in inner and outer ID fields"); + + public_key.assert_is_a(SEQUENCE, CONSTRUCTED, "X.509 certificate public key"); + + // crude method to save the serial's sign; will get lost during decoding, otherwise + data->m_serial_negative = serial_bn.is_negative(); + + // for general sanity convert wire version (0 based) to standards version (v1 .. v3) + data->m_version += 1; + + data->m_serial = BigInt::encode(serial_bn); + data->m_subject_dn_bits = ASN1::put_in_sequence(data->m_subject_dn.get_bits()); + data->m_issuer_dn_bits = ASN1::put_in_sequence(data->m_issuer_dn.get_bits()); + + // validate_public_key_params(public_key.value); + AlgorithmIdentifier public_key_alg_id; + BER_Decoder(public_key).decode(public_key_alg_id).discard_remaining(); + + std::vector<std::string> public_key_info = + split_on(OIDS::oid2str(public_key_alg_id.get_oid()), '/'); + + if(!public_key_info.empty() && public_key_info[0] == "RSA") + { + // RFC4055: If PublicKeyAlgo = PSS or OAEP: limit the use of the public key exclusively to either RSASSA - PSS or RSAES - OAEP + if(public_key_info.size() >= 2) + { + if(public_key_info[1] == "EMSA4") + { + /* + When the RSA private key owner wishes to limit the use of the public + key exclusively to RSASSA-PSS, then the id-RSASSA-PSS object + identifier MUST be used in the algorithm field within the subject + public key information, and, if present, the parameters field MUST + contain RSASSA-PSS-params. + + All parameters in the signature structure algorithm identifier MUST + match the parameters in the key structure algorithm identifier + except the saltLength field. The saltLength field in the signature parameters + MUST be greater or equal to that in the key parameters field. + + ToDo: Allow salt length to be greater + */ + if(public_key_alg_id != obj.signature_algorithm()) + { + throw Decoding_Error("Algorithm identifier mismatch"); + } + } + if(public_key_info[1] == "OAEP") + { + throw Decoding_Error("Decoding subject public keys of type RSAES-OAEP is currently not supported"); + } + } + else + { + // oid = rsaEncryption -> parameters field MUST contain NULL + if(public_key_alg_id != AlgorithmIdentifier(public_key_alg_id.get_oid(), AlgorithmIdentifier::USE_NULL_PARAM)) + { + throw Decoding_Error("Parameters field MUST contain NULL"); + } + } + } + + data->m_subject_public_key_bits.assign(public_key.bits(), public_key.bits() + public_key.length()); + + data->m_subject_public_key_bits_seq = ASN1::put_in_sequence(data->m_subject_public_key_bits); + + BER_Decoder(data->m_subject_public_key_bits) + .decode(data->m_subject_public_key_algid) + .decode(data->m_subject_public_key_bitstring, BIT_STRING); + + if(v3_exts_data.is_a(3, ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))) + { + BER_Decoder(v3_exts_data).decode(data->m_v3_extensions).verify_end(); + } + else if(v3_exts_data.is_set()) + throw BER_Bad_Tag("Unknown tag in X.509 cert", v3_exts_data.tagging()); + + // Now cache some fields from the extensions + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Key_Usage>()) + { + data->m_key_constraints = ext->get_constraints(); + } + else + { + data->m_key_constraints = NO_CONSTRAINTS; + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Subject_Key_ID>()) + { + data->m_subject_key_id = ext->get_key_id(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Authority_Key_ID>()) + { + data->m_authority_key_id = ext->get_key_id(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Name_Constraints>()) + { + data->m_name_constraints = ext->get_name_constraints(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Basic_Constraints>()) + { + if(ext->get_is_ca() == true) + { + if(data->m_key_constraints == NO_CONSTRAINTS || + (data->m_key_constraints & KEY_CERT_SIGN)) + { + data->m_is_ca_certificate = true; + data->m_path_len_constraint = ext->get_path_limit(); + } + } + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Issuer_Alternative_Name>()) + { + data->m_issuer_alt_name = ext->get_alt_name(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Subject_Alternative_Name>()) + { + data->m_subject_alt_name = ext->get_alt_name(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Extended_Key_Usage>()) + { + data->m_extended_key_usage = ext->get_oids(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Certificate_Policies>()) + { + data->m_cert_policies = ext->get_policy_oids(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Authority_Information_Access>()) + { + data->m_ocsp_responder = ext->ocsp_responder(); + data->m_ca_issuers = ext->ca_issuers(); + } + + if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::CRL_Distribution_Points>()) + { + data->m_crl_distribution_points = ext->crl_distribution_urls(); + } + + // Check for self-signed vs self-issued certificates + if(data->m_subject_dn == data->m_issuer_dn) + { + if(data->m_subject_key_id.empty() == false && data->m_authority_key_id.empty() == false) + { + data->m_self_signed = (data->m_subject_key_id == data->m_authority_key_id); + } + else + { + try + { + std::unique_ptr<Public_Key> pub_key(X509::load_key(data->m_subject_public_key_bits_seq)); + + Certificate_Status_Code sig_status = obj.verify_signature(*pub_key); + + if(sig_status == Certificate_Status_Code::OK || + sig_status == Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN) + { + data->m_self_signed = true; + } + } + catch(...) + { + // ignore errors here to allow parsing to continue + } + } + } + + std::unique_ptr<HashFunction> sha1(HashFunction::create("SHA-1")); + if(sha1) + { + sha1->update(data->m_subject_public_key_bitstring); + data->m_subject_public_key_bitstring_sha1 = sha1->final_stdvec(); + // otherwise left as empty, and we will throw if subject_public_key_bitstring_sha1 is called + } + + data->m_subject_ds.add(data->m_subject_dn.contents()); + data->m_issuer_ds.add(data->m_issuer_dn.contents()); + data->m_v3_extensions.contents_to(data->m_subject_ds, data->m_issuer_ds); + + return data; + } + +} + +/* +* Decode the TBSCertificate data +*/ +void X509_Certificate::force_decode() + { + m_data.reset(); + + std::unique_ptr<X509_Certificate_Data> data = parse_x509_cert_body(*this); + + m_data.reset(data.release()); + } + +const X509_Certificate_Data& X509_Certificate::data() const + { + if(m_data == nullptr) + { + throw Invalid_State("X509_Certificate uninitialized"); + } + return *m_data.get(); + } + +uint32_t X509_Certificate::x509_version() const + { + return data().m_version; + } + +bool X509_Certificate::is_self_signed() const + { + return data().m_self_signed; + } + +const X509_Time& X509_Certificate::not_before() const + { + return data().m_not_before; + } + +const X509_Time& X509_Certificate::not_after() const + { + return data().m_not_after; + } + +const AlgorithmIdentifier& X509_Certificate::subject_public_key_algo() const + { + return data().m_subject_public_key_algid; + } + +const std::vector<uint8_t>& X509_Certificate::v2_issuer_key_id() const + { + return data().m_v2_issuer_key_id; + } + +const std::vector<uint8_t>& X509_Certificate::v2_subject_key_id() const + { + return data().m_v2_subject_key_id; + } + +const std::vector<uint8_t>& X509_Certificate::subject_public_key_bits() const + { + return data().m_subject_public_key_bits; + } + +const std::vector<uint8_t>& X509_Certificate::subject_public_key_info() const + { + return data().m_subject_public_key_bits_seq; + } + +const std::vector<uint8_t>& X509_Certificate::subject_public_key_bitstring() const + { + return data().m_subject_public_key_bitstring; + } + +const std::vector<uint8_t>& X509_Certificate::subject_public_key_bitstring_sha1() const + { + if(data().m_subject_public_key_bitstring_sha1.empty()) + throw Encoding_Error("X509_Certificate::subject_public_key_bitstring_sha1 called but SHA-1 disabled in build"); + + return data().m_subject_public_key_bitstring_sha1; + } + +const std::vector<uint8_t>& X509_Certificate::authority_key_id() const + { + return data().m_authority_key_id; + } + +const std::vector<uint8_t>& X509_Certificate::subject_key_id() const + { + return data().m_subject_key_id; + } + +const std::vector<uint8_t>& X509_Certificate::serial_number() const + { + return data().m_serial; + } + +bool X509_Certificate::is_serial_negative() const + { + return data().m_serial_negative; + } + + +const X509_DN& X509_Certificate::issuer_dn() const + { + return data().m_issuer_dn; + } + +const X509_DN& X509_Certificate::subject_dn() const + { + return data().m_subject_dn; + } + +const std::vector<uint8_t>& X509_Certificate::raw_issuer_dn() const + { + return data().m_issuer_dn_bits; + } + +const std::vector<uint8_t>& X509_Certificate::raw_subject_dn() const + { + return data().m_subject_dn_bits; + } + +bool X509_Certificate::is_CA_cert() const + { + return data().m_is_ca_certificate; + } + +uint32_t X509_Certificate::path_limit() const + { + return data().m_path_len_constraint; + } + +Key_Constraints X509_Certificate::constraints() const + { + return data().m_key_constraints; + } + +const std::vector<OID>& X509_Certificate::extended_key_usage() const + { + return data().m_extended_key_usage; + } + +const std::vector<OID>& X509_Certificate::certificate_policy_oids() const + { + return data().m_cert_policies; + } + +const NameConstraints& X509_Certificate::name_constraints() const + { + return data().m_name_constraints; + } + +const Extensions& X509_Certificate::v3_extensions() const + { + return data().m_v3_extensions; + } + +bool X509_Certificate::allowed_usage(Key_Constraints usage) const + { + if(constraints() == NO_CONSTRAINTS) + return true; + return ((constraints() & usage) == usage); + } + +bool X509_Certificate::allowed_extended_usage(const std::string& usage) const + { + return allowed_extended_usage(OIDS::str2oid(usage)); + } + +bool X509_Certificate::allowed_extended_usage(const OID& usage) const + { + const std::vector<OID>& ex = extended_key_usage(); + if(ex.empty()) + return true; + + if(std::find(ex.begin(), ex.end(), usage) != ex.end()) + return true; + + return false; + } + +bool X509_Certificate::allowed_usage(Usage_Type usage) const + { + // These follow suggestions in RFC 5280 4.2.1.12 + + switch(usage) + { + case Usage_Type::UNSPECIFIED: + return true; + + case Usage_Type::TLS_SERVER_AUTH: + return (allowed_usage(KEY_AGREEMENT) || allowed_usage(KEY_ENCIPHERMENT) || allowed_usage(DIGITAL_SIGNATURE)) && allowed_extended_usage("PKIX.ServerAuth"); + + case Usage_Type::TLS_CLIENT_AUTH: + return (allowed_usage(DIGITAL_SIGNATURE) || allowed_usage(KEY_AGREEMENT)) && allowed_extended_usage("PKIX.ClientAuth"); + + case Usage_Type::OCSP_RESPONDER: + return (allowed_usage(DIGITAL_SIGNATURE) || allowed_usage(NON_REPUDIATION)) && allowed_extended_usage("PKIX.OCSPSigning"); + + case Usage_Type::CERTIFICATE_AUTHORITY: + return is_CA_cert(); + } + + return false; + } + +bool X509_Certificate::has_constraints(Key_Constraints constraints) const + { + if(this->constraints() == NO_CONSTRAINTS) + { + return false; + } + + return ((this->constraints() & constraints) != 0); + } + +bool X509_Certificate::has_ex_constraint(const std::string& ex_constraint) const + { + return has_ex_constraint(OIDS::str2oid(ex_constraint)); + } + +bool X509_Certificate::has_ex_constraint(const OID& usage) const + { + const std::vector<OID>& ex = extended_key_usage(); + return (std::find(ex.begin(), ex.end(), usage) != ex.end()); + } + +/* +* Return if a certificate extension is marked critical +*/ +bool X509_Certificate::is_critical(const std::string& ex_name) const + { + return v3_extensions().critical_extension_set(OIDS::str2oid(ex_name)); + } + +std::string X509_Certificate::ocsp_responder() const + { + return data().m_ocsp_responder; + } + +std::vector<std::string> X509_Certificate::ca_issuers() const + { + return data().m_ca_issuers; + } + +std::string X509_Certificate::crl_distribution_point() const + { + // just returns the first (arbitrarily) + if(data().m_crl_distribution_points.size() > 0) + return data().m_crl_distribution_points[0]; + return ""; + } + +const AlternativeName& X509_Certificate::subject_alt_name() const + { + return data().m_subject_alt_name; + } + +const AlternativeName& X509_Certificate::issuer_alt_name() const + { + return data().m_issuer_alt_name; + } + +/* +* Return information about the subject +*/ +std::vector<std::string> +X509_Certificate::subject_info(const std::string& req) const + { + if(req == "Email") + return this->subject_info("RFC822"); + + if(subject_dn().has_field(req)) + return subject_dn().get_attribute(req); + + if(subject_alt_name().has_field(req)) + return subject_alt_name().get_attribute(req); + + // These will be removed later: + if(req == "X509.Certificate.v2.key_id") + return {hex_encode(this->v2_subject_key_id())}; + if(req == "X509v3.SubjectKeyIdentifier") + return {hex_encode(this->subject_key_id())}; + if(req == "X509.Certificate.dn_bits") + return {hex_encode(this->raw_subject_dn())}; + if(req == "X509.Certificate.start") + return {not_before().to_string()}; + if(req == "X509.Certificate.end") + return {not_after().to_string()}; + + if(req == "X509.Certificate.version") + return {std::to_string(x509_version())}; + if(req == "X509.Certificate.serial") + return {hex_encode(serial_number())}; + + return data().m_subject_ds.get(req); + } + +/* +* Return information about the issuer +*/ +std::vector<std::string> +X509_Certificate::issuer_info(const std::string& req) const + { + if(issuer_dn().has_field(req)) + return issuer_dn().get_attribute(req); + + if(issuer_alt_name().has_field(req)) + return issuer_alt_name().get_attribute(req); + + // These will be removed later: + if(req == "X509.Certificate.v2.key_id") + return {hex_encode(this->v2_issuer_key_id())}; + if(req == "X509v3.AuthorityKeyIdentifier") + return {hex_encode(this->authority_key_id())}; + if(req == "X509.Certificate.dn_bits") + return {hex_encode(this->raw_issuer_dn())}; + + return data().m_issuer_ds.get(req); + } + +/* +* Return the public key in this certificate +*/ +std::unique_ptr<Public_Key> X509_Certificate::load_subject_public_key() const + { + try + { + return std::unique_ptr<Public_Key>(X509::load_key(subject_public_key_info())); + } + catch(std::exception& e) + { + throw Decoding_Error("X509_Certificate::load_subject_public_key", e.what()); + } + } + +std::vector<uint8_t> X509_Certificate::raw_issuer_dn_sha256() const + { + std::unique_ptr<HashFunction> hash(HashFunction::create_or_throw("SHA-256")); + hash->update(raw_issuer_dn()); + return hash->final_stdvec(); + } + +std::vector<uint8_t> X509_Certificate::raw_subject_dn_sha256() const + { + std::unique_ptr<HashFunction> hash(HashFunction::create("SHA-256")); + hash->update(raw_subject_dn()); + return hash->final_stdvec(); + } + +namespace { + +/* +* Lookup each OID in the vector +*/ +std::vector<std::string> lookup_oids(const std::vector<OID>& oids) + { + std::vector<std::string> out; + + for(const OID& oid : oids) + { + out.push_back(OIDS::oid2str(oid)); + } + return out; + } + +} + +/* +* Return the list of extended key usage OIDs +*/ +std::vector<std::string> X509_Certificate::ex_constraints() const + { + return lookup_oids(extended_key_usage()); + } + +/* +* Return the list of certificate policies +*/ +std::vector<std::string> X509_Certificate::policies() const + { + return lookup_oids(certificate_policy_oids()); + } + +std::string X509_Certificate::fingerprint(const std::string& hash_name) const + { + return create_hex_fingerprint(this->BER_encode(), hash_name); + } + +bool X509_Certificate::matches_dns_name(const std::string& name) const + { + if(name.empty()) + return false; + + std::vector<std::string> issued_names = subject_info("DNS"); + + // Fall back to CN only if no DNS names are set (RFC 6125 sec 6.4.4) + if(issued_names.empty()) + issued_names = subject_info("Name"); + + for(size_t i = 0; i != issued_names.size(); ++i) + { + if(host_wildcard_match(issued_names[i], name)) + return true; + } + + return false; + } + +/* +* Compare two certificates for equality +*/ +bool X509_Certificate::operator==(const X509_Certificate& other) const + { + return (this->signature() == other.signature() && + this->signature_algorithm() == other.signature_algorithm() && + this->signed_body() == other.signed_body()); + } + +bool X509_Certificate::operator<(const X509_Certificate& other) const + { + /* If signature values are not equal, sort by lexicographic ordering of that */ + if(this->signature() != other.signature()) + { + return (this->signature() < other.signature()); + } + + // Then compare the signed contents + return this->signed_body() < other.signed_body(); + } + +/* +* X.509 Certificate Comparison +*/ +bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2) + { + return !(cert1 == cert2); + } + +std::string X509_Certificate::to_string() const + { + std::ostringstream out; + + out << "Version: " << this->x509_version() << "\n"; + out << "Subject: " << subject_dn() << "\n"; + out << "Issuer: " << issuer_dn() << "\n"; + out << "Issued: " << this->not_before().readable_string() << "\n"; + out << "Expires: " << this->not_after().readable_string() << "\n"; + + out << "Constraints:\n"; + Key_Constraints constraints = this->constraints(); + if(constraints == NO_CONSTRAINTS) + out << " None\n"; + else + { + if(constraints & DIGITAL_SIGNATURE) + out << " Digital Signature\n"; + if(constraints & NON_REPUDIATION) + out << " Non-Repudiation\n"; + if(constraints & KEY_ENCIPHERMENT) + out << " Key Encipherment\n"; + if(constraints & DATA_ENCIPHERMENT) + out << " Data Encipherment\n"; + if(constraints & KEY_AGREEMENT) + out << " Key Agreement\n"; + if(constraints & KEY_CERT_SIGN) + out << " Cert Sign\n"; + if(constraints & CRL_SIGN) + out << " CRL Sign\n"; + if(constraints & ENCIPHER_ONLY) + out << " Encipher Only\n"; + if(constraints & DECIPHER_ONLY) + out << " Decipher Only\n"; + } + + const std::vector<OID> policies = this->certificate_policy_oids(); + if(!policies.empty()) + { + out << "Policies: " << "\n"; + for(auto oid : policies) + out << " " << oid.as_string() << "\n"; + } + + std::vector<OID> ex_constraints = this->extended_key_usage(); + if(!ex_constraints.empty()) + { + out << "Extended Constraints:\n"; + for(size_t i = 0; i != ex_constraints.size(); i++) + out << " " << OIDS::oid2str(ex_constraints[i]) << "\n"; + } + + const NameConstraints& name_constraints = this->name_constraints(); + + if(!name_constraints.permitted().empty() || !name_constraints.excluded().empty()) + { + out << "Name Constraints:\n"; + + if(!name_constraints.permitted().empty()) + { + out << " Permit"; + for(auto st: name_constraints.permitted()) + { + out << " " << st.base(); + } + out << "\n"; + } + + if(!name_constraints.excluded().empty()) + { + out << " Exclude"; + for(auto st: name_constraints.excluded()) + { + out << " " << st.base(); + } + out << "\n"; + } + } + + if(!ocsp_responder().empty()) + out << "OCSP responder " << ocsp_responder() << "\n"; + + std::vector<std::string> ca_issuers = this->ca_issuers(); + if(!ca_issuers.empty()) + { + out << "CA Issuers:\n"; + for(size_t i = 0; i != ca_issuers.size(); i++) + out << " URI: " << ca_issuers[i] << "\n"; + } + + if(!crl_distribution_point().empty()) + out << "CRL " << crl_distribution_point() << "\n"; + + out << "Signature algorithm: " << + OIDS::oid2str(this->signature_algorithm().get_oid()) << "\n"; + + out << "Serial number: " << hex_encode(this->serial_number()) << "\n"; + + if(this->authority_key_id().size()) + out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n"; + + if(this->subject_key_id().size()) + out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n"; + + try + { + std::unique_ptr<Public_Key> pubkey(this->subject_public_key()); + out << "Public Key [" << pubkey->algo_name() << "-" << pubkey->key_length() << "]\n\n"; + out << X509::PEM_encode(*pubkey); + } + catch(Decoding_Error&) + { + const AlgorithmIdentifier& alg_id = this->subject_public_key_algo(); + out << "Failed to decode key with oid " << alg_id.get_oid().as_string() << "\n"; + } + + return out.str(); + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509cert.h b/src/libs/3rdparty/botan/src/lib/x509/x509cert.h new file mode 100644 index 0000000000..34be10e680 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509cert.h @@ -0,0 +1,464 @@ +/* +* X.509 Certificates +* (C) 1999-2007,2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_CERTS_H_ +#define BOTAN_X509_CERTS_H_ + +#include <botan/x509_obj.h> +#include <botan/x509_key.h> +#include <botan/asn1_time.h> +#include <botan/key_constraint.h> +#include <botan/name_constraint.h> +#include <memory> + +namespace Botan { + +class Public_Key; +class X509_DN; +class AlternativeName; +class Extensions; + +enum class Usage_Type + { + UNSPECIFIED, // no restrictions + TLS_SERVER_AUTH, + TLS_CLIENT_AUTH, + CERTIFICATE_AUTHORITY, + OCSP_RESPONDER + }; + +struct X509_Certificate_Data; + +/** +* This class represents an X.509 Certificate +*/ +class BOTAN_PUBLIC_API(2,0) X509_Certificate : public X509_Object + { + public: + /** + * Return a newly allocated copy of the public key associated + * with the subject of this certificate. This object is owned + * by the caller. + * + * @return public key + */ + Public_Key* subject_public_key() const + { + return load_subject_public_key().release(); + } + + /** + * Create a public key object associated with the public key bits in this + * certificate. If the public key bits was valid for X.509 encoding + * purposes but invalid algorithmically (for example, RSA with an even + * modulus) that will be detected at this point, and an exception will be + * thrown. + * + * @return subject public key of this certificate + */ + std::unique_ptr<Public_Key> load_subject_public_key() const; + + /** + * Get the public key associated with this certificate. This includes the + * outer AlgorithmIdentifier + * @return subject public key of this certificate + */ + const std::vector<uint8_t>& subject_public_key_bits() const; + + /** + * Get the SubjectPublicKeyInfo associated with this certificate. + * @return subject public key info of this certificate + */ + const std::vector<uint8_t>& subject_public_key_info() const; + + /** + * Return the algorithm identifier of the public key + */ + const AlgorithmIdentifier& subject_public_key_algo() const; + + /** + * Get the bit string of the public key associated with this certificate + * @return public key bits + */ + const std::vector<uint8_t>& subject_public_key_bitstring() const; + + /** + * Get the SHA-1 bit string of the public key associated with this certificate. + * This is used for OCSP among other protocols. + * This function will throw if SHA-1 is not available. + * @return hash of subject public key of this certificate + */ + const std::vector<uint8_t>& subject_public_key_bitstring_sha1() const; + + /** + * Get the certificate's issuer distinguished name (DN). + * @return issuer DN of this certificate + */ + const X509_DN& issuer_dn() const; + + /** + * Get the certificate's subject distinguished name (DN). + * @return subject DN of this certificate + */ + const X509_DN& subject_dn() const; + + /** + * Get a value for a specific subject_info parameter name. + * @param name the name of the parameter to look up. Possible names include + * "X509.Certificate.version", "X509.Certificate.serial", + * "X509.Certificate.start", "X509.Certificate.end", + * "X509.Certificate.v2.key_id", "X509.Certificate.public_key", + * "X509v3.BasicConstraints.path_constraint", + * "X509v3.BasicConstraints.is_ca", "X509v3.NameConstraints", + * "X509v3.ExtendedKeyUsage", "X509v3.CertificatePolicies", + * "X509v3.SubjectKeyIdentifier", "X509.Certificate.serial", + * "X520.CommonName", "X520.Organization", "X520.Country", + * "RFC822" (Email in SAN) or "PKCS9.EmailAddress" (Email in DN). + * @return value(s) of the specified parameter + */ + std::vector<std::string> subject_info(const std::string& name) const; + + /** + * Get a value for a specific subject_info parameter name. + * @param name the name of the parameter to look up. Possible names are + * "X509.Certificate.v2.key_id" or "X509v3.AuthorityKeyIdentifier". + * @return value(s) of the specified parameter + */ + std::vector<std::string> issuer_info(const std::string& name) const; + + /** + * Raw issuer DN bits + */ + const std::vector<uint8_t>& raw_issuer_dn() const; + + /** + * SHA-256 of Raw issuer DN + */ + std::vector<uint8_t> raw_issuer_dn_sha256() const; + + /** + * Raw subject DN + */ + const std::vector<uint8_t>& raw_subject_dn() const; + + /** + * SHA-256 of Raw subject DN + */ + std::vector<uint8_t> raw_subject_dn_sha256() const; + + /** + * Get the notBefore of the certificate as a string + * @return notBefore of the certificate + */ + std::string BOTAN_DEPRECATED("Use not_before().to_string()") start_time() const + { + return not_before().to_string(); + } + + /** + * Get the notAfter of the certificate as a string + * @return notAfter of the certificate + */ + std::string BOTAN_DEPRECATED("Use not_after().to_string()") end_time() const + { + return not_after().to_string(); + } + + /** + * Get the notBefore of the certificate as X509_Time + * @return notBefore of the certificate + */ + const X509_Time& not_before() const; + + /** + * Get the notAfter of the certificate as X509_Time + * @return notAfter of the certificate + */ + const X509_Time& not_after() const; + + /** + * Get the X509 version of this certificate object. + * @return X509 version + */ + uint32_t x509_version() const; + + /** + * Get the serial number of this certificate. + * @return certificates serial number + */ + const std::vector<uint8_t>& serial_number() const; + + /** + * Get the serial number's sign + * @return 1 iff the serial is negative. + */ + bool is_serial_negative() const; + + /** + * Get the DER encoded AuthorityKeyIdentifier of this certificate. + * @return DER encoded AuthorityKeyIdentifier + */ + const std::vector<uint8_t>& authority_key_id() const; + + /** + * Get the DER encoded SubjectKeyIdentifier of this certificate. + * @return DER encoded SubjectKeyIdentifier + */ + const std::vector<uint8_t>& subject_key_id() const; + + /** + * Check whether this certificate is self signed. + * If the DN issuer and subject agree, + * @return true if this certificate is self signed + */ + bool is_self_signed() const; + + /** + * Check whether this certificate is a CA certificate. + * @return true if this certificate is a CA certificate + */ + bool is_CA_cert() const; + + /** + * Returns true if the specified @param usage is set in the key usage extension + * or if no key usage constraints are set at all. + * To check if a certain key constraint is set in the certificate + * use @see X509_Certificate#has_constraints. + */ + bool allowed_usage(Key_Constraints usage) const; + + /** + * Returns true if the specified @param usage is set in the extended key usage extension + * or if no extended key usage constraints are set at all. + * To check if a certain extended key constraint is set in the certificate + * use @see X509_Certificate#has_ex_constraint. + */ + bool allowed_extended_usage(const std::string& usage) const; + + /** + * Returns true if the specified usage is set in the extended key usage extension, + * or if no extended key usage constraints are set at all. + * To check if a certain extended key constraint is set in the certificate + * use @see X509_Certificate#has_ex_constraint. + */ + bool allowed_extended_usage(const OID& usage) const; + + /** + * Returns true if the required key and extended key constraints are set in the certificate + * for the specified @param usage or if no key constraints are set in both the key usage + * and extended key usage extension. + */ + bool allowed_usage(Usage_Type usage) const; + + /** + * Returns true if the specified @param constraints are included in the key + * usage extension. + */ + bool has_constraints(Key_Constraints constraints) const; + + /** + * Returns true if and only if @param ex_constraint (referring to an + * extended key constraint, eg "PKIX.ServerAuth") is included in the + * extended key extension. + */ + bool BOTAN_DEPRECATED("Use version taking an OID") + has_ex_constraint(const std::string& ex_constraint) const; + + /** + * Returns true if and only if OID @param ex_constraint is + * included in the extended key extension. + */ + bool has_ex_constraint(const OID& ex_constraint) const; + + /** + * Get the path limit as defined in the BasicConstraints extension of + * this certificate. + * @return path limit + */ + uint32_t path_limit() const; + + /** + * Check whenever a given X509 Extension is marked critical in this + * certificate. + */ + bool is_critical(const std::string& ex_name) const; + + /** + * Get the key constraints as defined in the KeyUsage extension of this + * certificate. + * @return key constraints + */ + Key_Constraints constraints() const; + + /** + * Get the key constraints as defined in the ExtendedKeyUsage + * extension of this certificate. + * @return key constraints + */ + std::vector<std::string> + BOTAN_DEPRECATED("Use extended_key_usage") ex_constraints() const; + + /** + * Get the key usage as defined in the ExtendedKeyUsage extension + * of this certificate, or else an empty vector. + * @return key usage + */ + const std::vector<OID>& extended_key_usage() const; + + /** + * Get the name constraints as defined in the NameConstraints + * extension of this certificate. + * @return name constraints + */ + const NameConstraints& name_constraints() const; + + /** + * Get the policies as defined in the CertificatePolicies extension + * of this certificate. + * @return certificate policies + */ + std::vector<std::string> BOTAN_DEPRECATED("Use certificate_policy_oids") policies() const; + + const std::vector<OID>& certificate_policy_oids() const; + + /** + * Get all extensions of this certificate. + * @return certificate extensions + */ + const Extensions& v3_extensions() const; + + /** + * Return the v2 issuer key ID. v2 key IDs are almost never used, + * instead see v3_subject_key_id. + */ + const std::vector<uint8_t>& v2_issuer_key_id() const; + + /** + * Return the v2 subject key ID. v2 key IDs are almost never used, + * instead see v3_subject_key_id. + */ + const std::vector<uint8_t>& v2_subject_key_id() const; + + /** + * Return the subject alternative names (DNS, IP, ...) + */ + const AlternativeName& subject_alt_name() const; + + /** + * Return the issuer alternative names (DNS, IP, ...) + */ + const AlternativeName& issuer_alt_name() const; + + /** + * Return the listed address of an OCSP responder, or empty if not set + */ + std::string ocsp_responder() const; + + /** + * Return the listed addresses of ca issuers, or empty if not set + */ + std::vector<std::string> ca_issuers() const; + + /** + * Return the CRL distribution point, or empty if not set + */ + std::string crl_distribution_point() const; + + /** + * @return a free-form string describing the certificate + */ + std::string to_string() const; + + /** + * @return a fingerprint of the certificate + * @param hash_name hash function used to calculate the fingerprint + */ + std::string fingerprint(const std::string& hash_name = "SHA-1") const; + + /** + * Check if a certain DNS name matches up with the information in + * the cert + * @param name DNS name to match + */ + bool matches_dns_name(const std::string& name) const; + + /** + * Check to certificates for equality. + * @return true both certificates are (binary) equal + */ + bool operator==(const X509_Certificate& other) const; + + /** + * Impose an arbitrary (but consistent) ordering, eg to allow sorting + * a container of certificate objects. + * @return true if this is less than other by some unspecified criteria + */ + bool operator<(const X509_Certificate& other) const; + + /** + * Create a certificate from a data source providing the DER or + * PEM encoded certificate. + * @param source the data source + */ + explicit X509_Certificate(DataSource& source); + +#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) + /** + * Create a certificate from a file containing the DER or PEM + * encoded certificate. + * @param filename the name of the certificate file + */ + explicit X509_Certificate(const std::string& filename); +#endif + + /** + * Create a certificate from a buffer + * @param in the buffer containing the DER-encoded certificate + */ + explicit X509_Certificate(const std::vector<uint8_t>& in); + + /** + * Create a certificate from a buffer + * @param data the buffer containing the DER-encoded certificate + * @param length length of data in bytes + */ + X509_Certificate(const uint8_t data[], size_t length); + + /** + * Create an uninitialized certificate object. Any attempts to + * access this object will throw an exception. + */ + X509_Certificate() = default; + + X509_Certificate(const X509_Certificate& other) = default; + + X509_Certificate& operator=(const X509_Certificate& other) = default; + + private: + std::string PEM_label() const override; + + std::vector<std::string> alternate_PEM_labels() const override; + + void force_decode() override; + + const X509_Certificate_Data& data() const; + + std::shared_ptr<X509_Certificate_Data> m_data; + }; + +/** +* Check two certificates for inequality +* @param cert1 The first certificate +* @param cert2 The second certificate +* @return true if the arguments represent different certificates, +* false if they are binary identical +*/ +BOTAN_PUBLIC_API(2,0) bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509opt.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509opt.cpp new file mode 100644 index 0000000000..e31ead91f9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509opt.cpp @@ -0,0 +1,101 @@ +/* +* X.509 Certificate Options +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509self.h> +#include <botan/oids.h> +#include <botan/parsing.h> +#include <chrono> + +namespace Botan { + +/* +* Set when the certificate should become valid +*/ +void X509_Cert_Options::not_before(const std::string& time_string) + { + start = X509_Time(time_string, ASN1_Tag::UTC_OR_GENERALIZED_TIME); + } + +/* +* Set when the certificate should expire +*/ +void X509_Cert_Options::not_after(const std::string& time_string) + { + end = X509_Time(time_string, ASN1_Tag::UTC_OR_GENERALIZED_TIME); + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_constraints(Key_Constraints usage) + { + constraints = usage; + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_ex_constraint(const OID& oid) + { + ex_constraints.push_back(oid); + } + +/* +* Set key constraint information +*/ +void X509_Cert_Options::add_ex_constraint(const std::string& oid_str) + { + ex_constraints.push_back(OIDS::lookup(oid_str)); + } + +/* +* Mark this certificate for CA usage +*/ +void X509_Cert_Options::CA_key(size_t limit) + { + is_CA = true; + path_limit = limit; + } + +void X509_Cert_Options::set_padding_scheme(const std::string& scheme) + { + padding_scheme = scheme; + } + +/* +* Initialize the certificate options +*/ +X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts, + uint32_t expiration_time) + { + is_CA = false; + path_limit = 0; + constraints = NO_CONSTRAINTS; + // use default for chosen algorithm + padding_scheme = ""; + + auto now = std::chrono::system_clock::now(); + + start = X509_Time(now); + end = X509_Time(now + std::chrono::seconds(expiration_time)); + + if(initial_opts.empty()) + return; + + std::vector<std::string> parsed = split_on(initial_opts, '/'); + + if(parsed.size() > 4) + throw Invalid_Argument("X.509 cert options: Too many names: " + + initial_opts); + + if(parsed.size() >= 1) common_name = parsed[0]; + if(parsed.size() >= 2) country = parsed[1]; + if(parsed.size() >= 3) organization = parsed[2]; + if(parsed.size() == 4) org_unit = parsed[3]; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509path.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509path.cpp new file mode 100644 index 0000000000..e73fe12b60 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509path.cpp @@ -0,0 +1,1070 @@ +/* +* X.509 Certificate Path Validation +* (C) 2010,2011,2012,2014,2016 Jack Lloyd +* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509path.h> +#include <botan/x509_ext.h> +#include <botan/pk_keys.h> +#include <botan/ocsp.h> +#include <botan/oids.h> +#include <algorithm> +#include <chrono> +#include <vector> +#include <set> +#include <string> +#include <sstream> + +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + #include <future> + #include <botan/http_util.h> +#endif + +namespace Botan { + +/* +* PKIX path validation +*/ +CertificatePathStatusCodes +PKIX::check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + std::chrono::system_clock::time_point ref_time, + const std::string& hostname, + Usage_Type usage, + size_t min_signature_algo_strength, + const std::set<std::string>& trusted_hashes) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_chain cert_path empty"); + + const bool self_signed_ee_cert = (cert_path.size() == 1); + + X509_Time validation_time(ref_time); + + CertificatePathStatusCodes cert_status(cert_path.size()); + + if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname)) + cert_status[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH); + + if(!cert_path[0]->allowed_usage(usage)) + cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE); + + if(cert_path[0]->is_CA_cert() == false && + cert_path[0]->has_constraints(KEY_CERT_SIGN)) + { + /* + "If the keyCertSign bit is asserted, then the cA bit in the + basic constraints extension (Section 4.2.1.9) MUST also be + asserted." - RFC 5280 + + We don't bother doing this check on the rest of the path since they + must have the cA bit asserted or the validation will fail anyway. + */ + cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE); + } + + for(size_t i = 0; i != cert_path.size(); ++i) + { + std::set<Certificate_Status_Code>& status = cert_status.at(i); + + const bool at_self_signed_root = (i == cert_path.size() - 1); + + const std::shared_ptr<const X509_Certificate>& subject = cert_path[i]; + + const std::shared_ptr<const X509_Certificate>& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)]; + + if(at_self_signed_root && (issuer->is_self_signed() == false)) + { + status.insert(Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT); + } + + if(subject->issuer_dn() != issuer->subject_dn()) + { + status.insert(Certificate_Status_Code::CHAIN_NAME_MISMATCH); + } + + // Check the serial number + if(subject->is_serial_negative()) + { + status.insert(Certificate_Status_Code::CERT_SERIAL_NEGATIVE); + } + + // Check the subject's DN components' length + + for(const auto& dn_pair : subject->subject_dn().dn_info()) + { + const size_t dn_ub = X509_DN::lookup_ub(dn_pair.first); + // dn_pair = <OID,str> + if(dn_ub > 0 && dn_pair.second.size() > dn_ub) + { + status.insert(Certificate_Status_Code::DN_TOO_LONG); + } + } + + // Check all certs for valid time range + if(validation_time < subject->not_before()) + status.insert(Certificate_Status_Code::CERT_NOT_YET_VALID); + + if(validation_time > subject->not_after()) + status.insert(Certificate_Status_Code::CERT_HAS_EXPIRED); + + // Check issuer constraints + if(!issuer->is_CA_cert() && !self_signed_ee_cert) + status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER); + + std::unique_ptr<Public_Key> issuer_key(issuer->subject_public_key()); + + // Check the signature algorithm + if(OIDS::lookup(subject->signature_algorithm().oid).empty()) + { + status.insert(Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN); + } + // only perform the following checks if the signature algorithm is known + else + { + if(!issuer_key) + { + status.insert(Certificate_Status_Code::CERT_PUBKEY_INVALID); + } + else + { + const Certificate_Status_Code sig_status = subject->verify_signature(*issuer_key); + + if(sig_status != Certificate_Status_Code::VERIFIED) + status.insert(sig_status); + + if(issuer_key->estimated_strength() < min_signature_algo_strength) + status.insert(Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK); + } + + // Ignore untrusted hashes on self-signed roots + if(trusted_hashes.size() > 0 && !at_self_signed_root) + { + if(trusted_hashes.count(subject->hash_used_for_signature()) == 0) + status.insert(Certificate_Status_Code::UNTRUSTED_HASH); + } + } + + // Check cert extensions + Extensions extensions = subject->v3_extensions(); + const auto& extensions_vec = extensions.extensions(); + if(subject->x509_version() < 3 && !extensions_vec.empty()) + { + status.insert(Certificate_Status_Code::EXT_IN_V1_V2_CERT); + } + for(auto& extension : extensions_vec) + { + extension.first->validate(*subject, *issuer, cert_path, cert_status, i); + } + if(extensions.extensions().size() != extensions.get_extension_oids().size()) + { + status.insert(Certificate_Status_Code::DUPLICATE_CERT_EXTENSION); + } + } + + // path len check + size_t max_path_length = cert_path.size(); + for(size_t i = cert_path.size() - 1; i > 0 ; --i) + { + std::set<Certificate_Status_Code>& status = cert_status.at(i); + const std::shared_ptr<const X509_Certificate>& subject = cert_path[i]; + + /* + * If the certificate was not self-issued, verify that max_path_length is + * greater than zero and decrement max_path_length by 1. + */ + if(subject->subject_dn() != subject->issuer_dn()) + { + if(max_path_length > 0) + { + --max_path_length; + } + else + { + status.insert(Certificate_Status_Code::CERT_CHAIN_TOO_LONG); + } + } + + /* + * If pathLenConstraint is present in the certificate and is less than max_path_length, + * set max_path_length to the value of pathLenConstraint. + */ + if(subject->path_limit() != Cert_Extension::NO_CERT_PATH_LIMIT && subject->path_limit() < max_path_length) + { + max_path_length = subject->path_limit(); + } + } + + return cert_status; + } + +CertificatePathStatusCodes +PKIX::check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses, + const std::vector<Certificate_Store*>& trusted_certstores, + std::chrono::system_clock::time_point ref_time) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_ocsp cert_path empty"); + + CertificatePathStatusCodes cert_status(cert_path.size() - 1); + + for(size_t i = 0; i != cert_path.size() - 1; ++i) + { + std::set<Certificate_Status_Code>& status = cert_status.at(i); + + std::shared_ptr<const X509_Certificate> subject = cert_path.at(i); + std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1); + + if(i < ocsp_responses.size() && (ocsp_responses.at(i) != nullptr)) + { + try + { + Certificate_Status_Code ocsp_signature_status = ocsp_responses.at(i)->check_signature(trusted_certstores, cert_path); + + if(ocsp_signature_status == Certificate_Status_Code::OCSP_SIGNATURE_OK) + { + // Signature ok, so check the claimed status + Certificate_Status_Code ocsp_status = ocsp_responses.at(i)->status_for(*ca, *subject, ref_time); + status.insert(ocsp_status); + } + else + { + // Some signature problem + status.insert(ocsp_signature_status); + } + } + catch(Exception&) + { + status.insert(Certificate_Status_Code::OCSP_RESPONSE_INVALID); + } + } + } + + while(cert_status.size() > 0 && cert_status.back().empty()) + cert_status.pop_back(); + + return cert_status; + } + +CertificatePathStatusCodes +PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<std::shared_ptr<const X509_CRL>>& crls, + std::chrono::system_clock::time_point ref_time) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_crl cert_path empty"); + + CertificatePathStatusCodes cert_status(cert_path.size()); + const X509_Time validation_time(ref_time); + + for(size_t i = 0; i != cert_path.size() - 1; ++i) + { + std::set<Certificate_Status_Code>& status = cert_status.at(i); + + if(i < crls.size() && crls.at(i)) + { + std::shared_ptr<const X509_Certificate> subject = cert_path.at(i); + std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1); + + if(!ca->allowed_usage(CRL_SIGN)) + status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER); + + if(validation_time < crls[i]->this_update()) + status.insert(Certificate_Status_Code::CRL_NOT_YET_VALID); + + if(validation_time > crls[i]->next_update()) + status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED); + + if(crls[i]->check_signature(ca->subject_public_key()) == false) + status.insert(Certificate_Status_Code::CRL_BAD_SIGNATURE); + + status.insert(Certificate_Status_Code::VALID_CRL_CHECKED); + + if(crls[i]->is_revoked(*subject)) + status.insert(Certificate_Status_Code::CERT_IS_REVOKED); + + std::string dp = subject->crl_distribution_point(); + if(!dp.empty()) + { + if(dp != crls[i]->crl_issuing_distribution_point()) + { + status.insert(Certificate_Status_Code::NO_MATCHING_CRLDP); + } + } + + for(const auto& extension : crls[i]->extensions().extensions()) + { + // is the extension critical and unknown? + if(extension.second && OIDS::lookup(extension.first->oid_of()) == "") + { + /* NIST Certificate Path Valiadation Testing document: "When an implementation does not recognize a critical extension in the + * crlExtensions field, it shall assume that identified certificates have been revoked and are no longer valid" + */ + status.insert(Certificate_Status_Code::CERT_IS_REVOKED); + } + } + + } + } + + while(cert_status.size() > 0 && cert_status.back().empty()) + cert_status.pop_back(); + + return cert_status; + } + +CertificatePathStatusCodes +PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& certstores, + std::chrono::system_clock::time_point ref_time) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_crl cert_path empty"); + + if(certstores.empty()) + throw Invalid_Argument("PKIX::check_crl certstores empty"); + + std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size()); + + for(size_t i = 0; i != cert_path.size(); ++i) + { + BOTAN_ASSERT_NONNULL(cert_path[i]); + for(size_t c = 0; c != certstores.size(); ++c) + { + crls[i] = certstores[c]->find_crl_for(*cert_path[i]); + if(crls[i]) + break; + } + } + + return PKIX::check_crl(cert_path, crls, ref_time); + } + +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + +CertificatePathStatusCodes +PKIX::check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& trusted_certstores, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout, + bool ocsp_check_intermediate_CAs) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_ocsp_online cert_path empty"); + + std::vector<std::future<std::shared_ptr<const OCSP::Response>>> ocsp_response_futures; + + size_t to_ocsp = 1; + + if(ocsp_check_intermediate_CAs) + to_ocsp = cert_path.size() - 1; + if(cert_path.size() == 1) + to_ocsp = 0; + + for(size_t i = 0; i < to_ocsp; ++i) + { + const std::shared_ptr<const X509_Certificate>& subject = cert_path.at(i); + const std::shared_ptr<const X509_Certificate>& issuer = cert_path.at(i+1); + + if(subject->ocsp_responder() == "") + { + ocsp_response_futures.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr<const OCSP::Response> { + return std::make_shared<const OCSP::Response>(Certificate_Status_Code::OSCP_NO_REVOCATION_URL); + })); + } + else + { + ocsp_response_futures.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr<const OCSP::Response> { + OCSP::Request req(*issuer, BigInt::decode(subject->serial_number())); + + HTTP::Response http; + try + { + http = HTTP::POST_sync(subject->ocsp_responder(), + "application/ocsp-request", + req.BER_encode(), + /*redirects*/1, + timeout); + } + catch(std::exception& e) + { + // log e.what() ? + } + if (http.status_code() != 200) + return std::make_shared<const OCSP::Response>(Certificate_Status_Code::OSCP_SERVER_NOT_AVAILABLE); + // Check the MIME type? + + return std::make_shared<const OCSP::Response>(http.body()); + })); + } + } + + std::vector<std::shared_ptr<const OCSP::Response>> ocsp_responses; + + for(size_t i = 0; i < ocsp_response_futures.size(); ++i) + { + ocsp_responses.push_back(ocsp_response_futures[i].get()); + } + + return PKIX::check_ocsp(cert_path, ocsp_responses, trusted_certstores, ref_time); + } + +CertificatePathStatusCodes +PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& certstores, + Certificate_Store_In_Memory* crl_store, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout) + { + if(cert_path.empty()) + throw Invalid_Argument("PKIX::check_crl_online cert_path empty"); + if(certstores.empty()) + throw Invalid_Argument("PKIX::check_crl_online certstores empty"); + + std::vector<std::future<std::shared_ptr<const X509_CRL>>> future_crls; + std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size()); + + for(size_t i = 0; i != cert_path.size(); ++i) + { + const std::shared_ptr<const X509_Certificate>& cert = cert_path.at(i); + for(size_t c = 0; c != certstores.size(); ++c) + { + crls[i] = certstores[c]->find_crl_for(*cert); + if(crls[i]) + break; + } + + // TODO: check if CRL is expired and re-request? + + // Only request if we don't already have a CRL + if(crls[i]) + { + /* + We already have a CRL, so just insert this empty one to hold a place in the vector + so that indexes match up + */ + future_crls.emplace_back(std::future<std::shared_ptr<const X509_CRL>>()); + } + else if(cert->crl_distribution_point() == "") + { + // Avoid creating a thread for this case + future_crls.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr<const X509_CRL> { + throw Exception("No CRL distribution point for this certificate"); + })); + } + else + { + future_crls.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr<const X509_CRL> { + auto http = HTTP::GET_sync(cert->crl_distribution_point(), + /*redirects*/ 1, timeout); + + http.throw_unless_ok(); + // check the mime type? + return std::make_shared<const X509_CRL>(http.body()); + })); + } + } + + for(size_t i = 0; i != future_crls.size(); ++i) + { + if(future_crls[i].valid()) + { + try + { + crls[i] = future_crls[i].get(); + } + catch(std::exception& e) + { + // crls[i] left null + // todo: log exception e.what() ? + } + } + } + + const CertificatePathStatusCodes crl_status = PKIX::check_crl(cert_path, crls, ref_time); + + if(crl_store) + { + for(size_t i = 0; i != crl_status.size(); ++i) + { + if(crl_status[i].count(Certificate_Status_Code::VALID_CRL_CHECKED)) + { + // better be non-null, we supposedly validated it + BOTAN_ASSERT_NONNULL(crls[i]); + crl_store->add_crl(crls[i]); + } + } + } + + return crl_status; + } + +#endif + +Certificate_Status_Code +PKIX::build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& trusted_certstores, + const std::shared_ptr<const X509_Certificate>& end_entity, + const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra) + { + if(end_entity->is_self_signed()) + { + return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; + } + + /* + * This is an inelegant but functional way of preventing path loops + * (where C1 -> C2 -> C3 -> C1). We store a set of all the certificate + * fingerprints in the path. If there is a duplicate, we error out. + * TODO: save fingerprints in result struct? Maybe useful for blacklists, etc. + */ + std::set<std::string> certs_seen; + + cert_path.push_back(end_entity); + certs_seen.insert(end_entity->fingerprint("SHA-256")); + + Certificate_Store_In_Memory ee_extras; + for(size_t i = 0; i != end_entity_extra.size(); ++i) + ee_extras.add_certificate(end_entity_extra[i]); + + // iterate until we reach a root or cannot find the issuer + for(;;) + { + const X509_Certificate& last = *cert_path.back(); + const X509_DN issuer_dn = last.issuer_dn(); + const std::vector<uint8_t> auth_key_id = last.authority_key_id(); + + std::shared_ptr<const X509_Certificate> issuer; + bool trusted_issuer = false; + + for(Certificate_Store* store : trusted_certstores) + { + issuer = store->find_cert(issuer_dn, auth_key_id); + if(issuer) + { + trusted_issuer = true; + break; + } + } + + if(!issuer) + { + // fall back to searching supplemental certs + issuer = ee_extras.find_cert(issuer_dn, auth_key_id); + } + + if(!issuer) + return Certificate_Status_Code::CERT_ISSUER_NOT_FOUND; + + const std::string fprint = issuer->fingerprint("SHA-256"); + + if(certs_seen.count(fprint) > 0) // already seen? + { + return Certificate_Status_Code::CERT_CHAIN_LOOP; + } + + certs_seen.insert(fprint); + cert_path.push_back(issuer); + + if(issuer->is_self_signed()) + { + if(trusted_issuer) + { + return Certificate_Status_Code::OK; + } + else + { + return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; + } + } + } + } + +/** + * utilities for PKIX::build_all_certificate_paths + */ +namespace +{ +// <certificate, trusted?> +using cert_maybe_trusted = std::pair<std::shared_ptr<const X509_Certificate>,bool>; +} + +/** + * Build all possible certificate paths from the end certificate to self-signed trusted roots. + * + * All potentially valid paths are put into the cert_paths vector. If no potentially valid paths are found, + * one of the encountered errors is returned arbitrarily. + * + * todo add a path building function that returns detailed information on errors encountered while building + * the potentially numerous path candidates. + * + * Basically, a DFS is performed starting from the end certificate. A stack (vector) serves to control the DFS. + * At the beginning of each iteration, a pair is popped from the stack that contains (1) the next certificate + * to add to the path (2) a bool that indicates if the certificate is part of a trusted certstore. Ideally, we + * follow the unique issuer of the current certificate until a trusted root is reached. However, the issuer DN + + * authority key id need not be unique among the certificates used for building the path. In such a case, + * we consider all the matching issuers by pushing <IssuerCert, trusted?> on the stack for each of them. + * + */ +Certificate_Status_Code +PKIX::build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const X509_Certificate>>>& cert_paths_out, + const std::vector<Certificate_Store*>& trusted_certstores, + const std::shared_ptr<const X509_Certificate>& end_entity, + const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra) + { + if(!cert_paths_out.empty()) + { + throw Invalid_Argument("PKIX::build_all_certificate_paths: cert_paths_out must be empty"); + } + + if(end_entity->is_self_signed()) + { + return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST; + } + + /* + * Pile up error messages + */ + std::vector<Certificate_Status_Code> stats; + + Certificate_Store_In_Memory ee_extras; + for(size_t i = 0; i != end_entity_extra.size(); ++i) + { + ee_extras.add_certificate(end_entity_extra[i]); + } + + /* + * This is an inelegant but functional way of preventing path loops + * (where C1 -> C2 -> C3 -> C1). We store a set of all the certificate + * fingerprints in the path. If there is a duplicate, we error out. + * TODO: save fingerprints in result struct? Maybe useful for blacklists, etc. + */ + std::set<std::string> certs_seen; + + // new certs are added and removed from the path during the DFS + // it is copied into cert_paths_out when we encounter a trusted root + std::vector<std::shared_ptr<const X509_Certificate>> path_so_far; + + // todo can we assume that the end certificate is not trusted? + std::vector<cert_maybe_trusted> stack = { {end_entity, false} }; + + while(!stack.empty()) + { + // found a deletion marker that guides the DFS, backtracing + if(stack.back().first == nullptr) + { + stack.pop_back(); + std::string fprint = path_so_far.back()->fingerprint("SHA-256"); + certs_seen.erase(fprint); + path_so_far.pop_back(); + } + // process next cert on the path + else + { + std::shared_ptr<const X509_Certificate> last = stack.back().first; + bool trusted = stack.back().second; + stack.pop_back(); + + // certificate already seen? + const std::string fprint = last->fingerprint("SHA-256"); + if(certs_seen.count(fprint) == 1) + { + stats.push_back(Certificate_Status_Code::CERT_CHAIN_LOOP); + // the current path ended in a loop + continue; + } + + // the current path ends here + if(last->is_self_signed()) + { + // found a trust anchor + if(trusted) + { + cert_paths_out.push_back(path_so_far); + cert_paths_out.back().push_back(last); + + continue; + } + // found an untrustworthy root + else + { + stats.push_back(Certificate_Status_Code::CANNOT_ESTABLISH_TRUST); + continue; + } + } + + const X509_DN issuer_dn = last->issuer_dn(); + const std::vector<uint8_t> auth_key_id = last->authority_key_id(); + + // search for trusted issuers + std::vector<std::shared_ptr<const X509_Certificate>> trusted_issuers; + for(Certificate_Store* store : trusted_certstores) + { + auto new_issuers = store->find_all_certs(issuer_dn, auth_key_id); + trusted_issuers.insert(trusted_issuers.end(), new_issuers.begin(), new_issuers.end()); + } + + // search the supplemental certs + std::vector<std::shared_ptr<const X509_Certificate>> misc_issuers = + ee_extras.find_all_certs(issuer_dn, auth_key_id); + + // if we could not find any issuers, the current path ends here + if(trusted_issuers.size() + misc_issuers.size() == 0) + { + stats.push_back(Certificate_Status_Code::CERT_ISSUER_NOT_FOUND); + continue; + } + + // push the latest certificate onto the path_so_far + path_so_far.push_back(last); + certs_seen.emplace(fprint); + + // push a deletion marker on the stack for backtracing later + stack.push_back({std::shared_ptr<const X509_Certificate>(nullptr),false}); + + for(const auto trusted_cert : trusted_issuers) + { + stack.push_back({trusted_cert,true}); + } + + for(const auto misc : misc_issuers) + { + stack.push_back({misc,false}); + } + } + } + + // could not construct any potentially valid path + if(cert_paths_out.empty()) + { + if(stats.empty()) + throw Exception("X509 path building failed for unknown reasons"); + else + // arbitrarily return the first error + return stats[0]; + } + else + { + return Certificate_Status_Code::OK; + } + } + + +void PKIX::merge_revocation_status(CertificatePathStatusCodes& chain_status, + const CertificatePathStatusCodes& crl, + const CertificatePathStatusCodes& ocsp, + bool require_rev_on_end_entity, + bool require_rev_on_intermediates) + { + if(chain_status.empty()) + throw Invalid_Argument("PKIX::merge_revocation_status chain_status was empty"); + + for(size_t i = 0; i != chain_status.size() - 1; ++i) + { + bool had_crl = false, had_ocsp = false; + + if(i < crl.size() && crl[i].size() > 0) + { + for(auto&& code : crl[i]) + { + if(code == Certificate_Status_Code::VALID_CRL_CHECKED) + { + had_crl = true; + } + chain_status[i].insert(code); + } + } + + if(i < ocsp.size() && ocsp[i].size() > 0) + { + for(auto&& code : ocsp[i]) + { + if(code == Certificate_Status_Code::OCSP_RESPONSE_GOOD || + code == Certificate_Status_Code::OSCP_NO_REVOCATION_URL || // softfail + code == Certificate_Status_Code::OSCP_SERVER_NOT_AVAILABLE) // softfail + { + had_ocsp = true; + } + + chain_status[i].insert(code); + } + } + + if(had_crl == false && had_ocsp == false) + { + if((require_rev_on_end_entity && i == 0) || + (require_rev_on_intermediates && i > 0)) + { + chain_status[i].insert(Certificate_Status_Code::NO_REVOCATION_DATA); + } + } + } + } + +Certificate_Status_Code PKIX::overall_status(const CertificatePathStatusCodes& cert_status) + { + if(cert_status.empty()) + throw Invalid_Argument("PKIX::overall_status empty cert status"); + + Certificate_Status_Code overall_status = Certificate_Status_Code::OK; + + // take the "worst" error as overall + for(const std::set<Certificate_Status_Code>& s : cert_status) + { + if(!s.empty()) + { + auto worst = *s.rbegin(); + // Leave informative OCSP/CRL confirmations on cert-level status only + if(worst >= Certificate_Status_Code::FIRST_ERROR_STATUS && worst > overall_status) + { + overall_status = worst; + } + } + } + return overall_status; + } + +Path_Validation_Result x509_path_validate( + const std::vector<X509_Certificate>& end_certs, + const Path_Validation_Restrictions& restrictions, + const std::vector<Certificate_Store*>& trusted_roots, + const std::string& hostname, + Usage_Type usage, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds ocsp_timeout, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp) + { + if(end_certs.empty()) + { + throw Invalid_Argument("x509_path_validate called with no subjects"); + } + + std::shared_ptr<const X509_Certificate> end_entity(std::make_shared<const X509_Certificate>(end_certs[0])); + std::vector<std::shared_ptr<const X509_Certificate>> end_entity_extra; + for(size_t i = 1; i < end_certs.size(); ++i) + { + end_entity_extra.push_back(std::make_shared<const X509_Certificate>(end_certs[i])); + } + + std::vector<std::vector<std::shared_ptr<const X509_Certificate>>> cert_paths; + Certificate_Status_Code path_building_result = PKIX::build_all_certificate_paths(cert_paths, trusted_roots, end_entity, end_entity_extra); + + // If we cannot successfully build a chain to a trusted self-signed root, stop now + if(path_building_result != Certificate_Status_Code::OK) + { + return Path_Validation_Result(path_building_result); + } + + std::vector<Path_Validation_Result> error_results; + // Try validating all the potentially valid paths and return the first one to validate properly + for(auto cert_path : cert_paths) + { + CertificatePathStatusCodes status = + PKIX::check_chain(cert_path, ref_time, + hostname, usage, + restrictions.minimum_key_strength(), + restrictions.trusted_hashes()); + + CertificatePathStatusCodes crl_status = + PKIX::check_crl(cert_path, trusted_roots, ref_time); + + CertificatePathStatusCodes ocsp_status; + + if(ocsp_resp.size() > 0) + { + ocsp_status = PKIX::check_ocsp(cert_path, ocsp_resp, trusted_roots, ref_time); + } + + if(ocsp_status.empty() && ocsp_timeout != std::chrono::milliseconds(0)) + { +#if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_HTTP_UTIL) + ocsp_status = PKIX::check_ocsp_online(cert_path, trusted_roots, ref_time, + ocsp_timeout, restrictions.ocsp_all_intermediates()); +#else + ocsp_status.resize(1); + ocsp_status[0].insert(Certificate_Status_Code::OCSP_NO_HTTP); +#endif + } + + PKIX::merge_revocation_status(status, crl_status, ocsp_status, + restrictions.require_revocation_information(), + restrictions.ocsp_all_intermediates()); + + Path_Validation_Result pvd(status, std::move(cert_path)); + if(pvd.successful_validation()) + { + return pvd; + } + else + { + error_results.push_back(std::move(pvd)); + } + } + return error_results[0]; + } + +Path_Validation_Result x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const std::vector<Certificate_Store*>& trusted_roots, + const std::string& hostname, + Usage_Type usage, + std::chrono::system_clock::time_point when, + std::chrono::milliseconds ocsp_timeout, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp) + { + std::vector<X509_Certificate> certs; + certs.push_back(end_cert); + return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); + } + +Path_Validation_Result x509_path_validate( + const std::vector<X509_Certificate>& end_certs, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store, + const std::string& hostname, + Usage_Type usage, + std::chrono::system_clock::time_point when, + std::chrono::milliseconds ocsp_timeout, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp) + { + std::vector<Certificate_Store*> trusted_roots; + trusted_roots.push_back(const_cast<Certificate_Store*>(&store)); + + return x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); + } + +Path_Validation_Result x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store, + const std::string& hostname, + Usage_Type usage, + std::chrono::system_clock::time_point when, + std::chrono::milliseconds ocsp_timeout, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp) + { + std::vector<X509_Certificate> certs; + certs.push_back(end_cert); + + std::vector<Certificate_Store*> trusted_roots; + trusted_roots.push_back(const_cast<Certificate_Store*>(&store)); + + return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp); + } + +Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev, + size_t key_strength, + bool ocsp_intermediates) : + m_require_revocation_information(require_rev), + m_ocsp_all_intermediates(ocsp_intermediates), + m_minimum_key_strength(key_strength) + { + if(key_strength <= 80) + m_trusted_hashes.insert("SHA-160"); + + m_trusted_hashes.insert("SHA-224"); + m_trusted_hashes.insert("SHA-256"); + m_trusted_hashes.insert("SHA-384"); + m_trusted_hashes.insert("SHA-512"); + } + +namespace { +CertificatePathStatusCodes find_warnings(const CertificatePathStatusCodes& all_statuses) + { + CertificatePathStatusCodes warnings; + for(const auto& status_set_i : all_statuses) + { + std::set<Certificate_Status_Code> warning_set_i; + for(const auto& code : status_set_i) + { + if(code >= Certificate_Status_Code::FIRST_WARNING_STATUS && + code < Certificate_Status_Code::FIRST_ERROR_STATUS) + { + warning_set_i.insert(code); + } + } + warnings.push_back(warning_set_i); + } + return warnings; + } +} + +Path_Validation_Result::Path_Validation_Result(CertificatePathStatusCodes status, + std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain) : + m_all_status(status), + m_warnings(find_warnings(m_all_status)), + m_cert_path(cert_chain), + m_overall(PKIX::overall_status(m_all_status)) + { + } + +const X509_Certificate& Path_Validation_Result::trust_root() const + { + if(m_cert_path.empty()) + throw Exception("Path_Validation_Result::trust_root no path set"); + if(result() != Certificate_Status_Code::VERIFIED) + throw Exception("Path_Validation_Result::trust_root meaningless with invalid status"); + + return *m_cert_path[m_cert_path.size()-1]; + } + +std::set<std::string> Path_Validation_Result::trusted_hashes() const + { + std::set<std::string> hashes; + for(size_t i = 0; i != m_cert_path.size(); ++i) + hashes.insert(m_cert_path[i]->hash_used_for_signature()); + return hashes; + } + +bool Path_Validation_Result::successful_validation() const + { + return (result() == Certificate_Status_Code::VERIFIED || + result() == Certificate_Status_Code::OCSP_RESPONSE_GOOD || + result() == Certificate_Status_Code::VALID_CRL_CHECKED); + } + +bool Path_Validation_Result::no_warnings() const + { + for(auto status_set_i : m_warnings) + if(!status_set_i.empty()) + return false; + return true; + } + +CertificatePathStatusCodes Path_Validation_Result::warnings() const + { + return m_warnings; + } + +std::string Path_Validation_Result::result_string() const + { + return status_string(result()); + } + +const char* Path_Validation_Result::status_string(Certificate_Status_Code code) + { + if(const char* s = to_string(code)) + return s; + + return "Unknown error"; + } + +std::string Path_Validation_Result::warnings_string() const + { + const std::string sep(", "); + std::string res; + for(size_t i = 0; i < m_warnings.size(); i++) + { + for(auto code : m_warnings[i]) + res += "[" + std::to_string(i) + "] " + status_string(code) + sep; + } + // remove last sep + if(res.size() >= sep.size()) + res = res.substr(0, res.size() - sep.size()); + return res; + } +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509path.h b/src/libs/3rdparty/botan/src/lib/x509/x509path.h new file mode 100644 index 0000000000..79ae02a10e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509path.h @@ -0,0 +1,454 @@ +/* +* X.509 Cert Path Validation +* (C) 2010-2011 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_CERT_PATH_VALIDATION_H_ +#define BOTAN_X509_CERT_PATH_VALIDATION_H_ + +#include <botan/cert_status.h> +#include <botan/x509cert.h> +#include <botan/certstor.h> +#include <botan/ocsp.h> +#include <functional> +#include <set> +#include <chrono> + +#if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_HTTP_UTIL) + #define BOTAN_HAS_ONLINE_REVOCATION_CHECKS +#endif + +namespace Botan { + +/** +* This type represents the validation status of an entire certificate path. +* There is one set of status codes for each certificate in the path. +*/ +typedef std::vector<std::set<Certificate_Status_Code>> CertificatePathStatusCodes; + +/** +* Specifies restrictions on the PKIX path validation +*/ +class BOTAN_PUBLIC_API(2,0) Path_Validation_Restrictions final + { + public: + /** + * @param require_rev if true, revocation information is required + + * @param minimum_key_strength is the minimum strength (in terms of + * operations, eg 80 means 2^80) of a signature. Signatures weaker than + * this are rejected. If more than 80, SHA-1 signatures are also + * rejected. If possible use at least setting 110. + * + * 80 bit strength requires 1024 bit RSA + * 110 bit strength requires 2k bit RSA + * 128 bit strength requires ~3k bit RSA or P-256 + * @param ocsp_all_intermediates Make OCSP requests for all CAs as + * well as end entity (if OCSP enabled in path validation request) + */ + Path_Validation_Restrictions(bool require_rev = false, + size_t minimum_key_strength = 110, + bool ocsp_all_intermediates = false); + + /** + * @param require_rev if true, revocation information is required + * @param minimum_key_strength is the minimum strength (in terms of + * operations, eg 80 means 2^80) of a signature. Signatures + * weaker than this are rejected. + * @param ocsp_all_intermediates Make OCSP requests for all CAs as + * well as end entity (if OCSP enabled in path validation request) + * @param trusted_hashes a set of trusted hashes. Any signatures + * created using a hash other than one of these will be + * rejected. + */ + Path_Validation_Restrictions(bool require_rev, + size_t minimum_key_strength, + bool ocsp_all_intermediates, + const std::set<std::string>& trusted_hashes) : + m_require_revocation_information(require_rev), + m_ocsp_all_intermediates(ocsp_all_intermediates), + m_trusted_hashes(trusted_hashes), + m_minimum_key_strength(minimum_key_strength) {} + + /** + * @return whether revocation information is required + */ + bool require_revocation_information() const + { return m_require_revocation_information; } + + /** + * @return whether all intermediate CAs should also be OCSPed. If false + * then only end entity OCSP is required/requested. + */ + bool ocsp_all_intermediates() const + { return m_ocsp_all_intermediates; } + + /** + * @return trusted signature hash functions + */ + const std::set<std::string>& trusted_hashes() const + { return m_trusted_hashes; } + + /** + * @return minimum required key strength + */ + size_t minimum_key_strength() const + { return m_minimum_key_strength; } + + private: + bool m_require_revocation_information; + bool m_ocsp_all_intermediates; + std::set<std::string> m_trusted_hashes; + size_t m_minimum_key_strength; + }; + +/** +* Represents the result of a PKIX path validation +*/ +class BOTAN_PUBLIC_API(2,0) Path_Validation_Result final + { + public: + typedef Certificate_Status_Code Code; + + /** + * @return the set of hash functions you are implicitly + * trusting by trusting this result. + */ + std::set<std::string> trusted_hashes() const; + + /** + * @return the trust root of the validation if successful + * throws an exception if the validation failed + */ + const X509_Certificate& trust_root() const; + + /** + * @return the full path from subject to trust root + * This path may be empty + */ + const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path() const { return m_cert_path; } + + /** + * @return true iff the validation was successful + */ + bool successful_validation() const; + + /** + * @return true iff no warnings occured during validation + */ + bool no_warnings() const; + + /** + * @return overall validation result code + */ + Certificate_Status_Code result() const { return m_overall; } + + /** + * @return a set of status codes for each certificate in the chain + */ + const CertificatePathStatusCodes& all_statuses() const + { return m_all_status; } + + /** + * @return the subset of status codes that are warnings + */ + CertificatePathStatusCodes warnings() const; + + /** + * @return string representation of the validation result + */ + std::string result_string() const; + + /** + * @return string representation of the warnings + */ + std::string warnings_string() const; + + /** + * @param code validation status code + * @return corresponding validation status message + */ + static const char* status_string(Certificate_Status_Code code); + + /** + * Create a Path_Validation_Result + * @param status list of validation status codes + * @param cert_chain the certificate chain that was validated + */ + Path_Validation_Result(CertificatePathStatusCodes status, + std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain); + + /** + * Create a Path_Validation_Result + * @param status validation status code + */ + explicit Path_Validation_Result(Certificate_Status_Code status) : m_overall(status) {} + + private: + CertificatePathStatusCodes m_all_status; + CertificatePathStatusCodes m_warnings; + std::vector<std::shared_ptr<const X509_Certificate>> m_cert_path; + Certificate_Status_Code m_overall; + }; + +/** +* PKIX Path Validation +* @param end_certs certificate chain to validate (with end entity certificate in end_certs[0]) +* @param restrictions path validation restrictions +* @param trusted_roots list of certificate stores that contain trusted certificates +* @param hostname if not empty, compared against the DNS name in end_certs[0] +* @param usage if not set to UNSPECIFIED, compared against the key usage in end_certs[0] +* @param validation_time what reference time to use for validation +* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) +* @return result of the path validation +* note: when enabled, OCSP check is softfail by default: if the OCSP server is not +* reachable, Path_Validation_Result::successful_validation() will return true. +* Hardfail OCSP check can be achieve by also calling Path_Validation_Result::no_warnings(). +*/ +Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate( + const std::vector<X509_Certificate>& end_certs, + const Path_Validation_Restrictions& restrictions, + const std::vector<Certificate_Store*>& trusted_roots, + const std::string& hostname = "", + Usage_Type usage = Usage_Type::UNSPECIFIED, + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {}); + +/** +* PKIX Path Validation +* @param end_cert certificate to validate +* @param restrictions path validation restrictions +* @param trusted_roots list of stores that contain trusted certificates +* @param hostname if not empty, compared against the DNS name in end_cert +* @param usage if not set to UNSPECIFIED, compared against the key usage in end_cert +* @param validation_time what reference time to use for validation +* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) +* @return result of the path validation +*/ +Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const std::vector<Certificate_Store*>& trusted_roots, + const std::string& hostname = "", + Usage_Type usage = Usage_Type::UNSPECIFIED, + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {}); + +/** +* PKIX Path Validation +* @param end_cert certificate to validate +* @param restrictions path validation restrictions +* @param store store that contains trusted certificates +* @param hostname if not empty, compared against the DNS name in end_cert +* @param usage if not set to UNSPECIFIED, compared against the key usage in end_cert +* @param validation_time what reference time to use for validation +* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) +* @return result of the path validation +*/ +Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate( + const X509_Certificate& end_cert, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store, + const std::string& hostname = "", + Usage_Type usage = Usage_Type::UNSPECIFIED, + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {}); + +/** +* PKIX Path Validation +* @param end_certs certificate chain to validate +* @param restrictions path validation restrictions +* @param store store that contains trusted certificates +* @param hostname if not empty, compared against the DNS name in end_certs[0] +* @param usage if not set to UNSPECIFIED, compared against the key usage in end_certs[0] +* @param validation_time what reference time to use for validation +* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check +* @param ocsp_resp additional OCSP responses to consider (eg from peer) +* @return result of the path validation +*/ +Path_Validation_Result BOTAN_PUBLIC_API(2,0) x509_path_validate( + const std::vector<X509_Certificate>& end_certs, + const Path_Validation_Restrictions& restrictions, + const Certificate_Store& store, + const std::string& hostname = "", + Usage_Type usage = Usage_Type::UNSPECIFIED, + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = {}); + + +/** +* namespace PKIX holds the building blocks that are called by x509_path_validate. +* This allows custom validation logic to be written by applications and makes +* for easier testing, but unless you're positive you know what you're doing you +* probably want to just call x509_path_validate instead. +*/ +namespace PKIX { + +Certificate_Status_Code +build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const X509_Certificate>>>& cert_paths, + const std::vector<Certificate_Store*>& trusted_certstores, + const std::shared_ptr<const X509_Certificate>& end_entity, + const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra); + + +/** +* Build certificate path +* @param cert_path_out output parameter, cert_path will be appended to this vector +* @param trusted_certstores list of certificate stores that contain trusted certificates +* @param end_entity the cert to be validated +* @param end_entity_extra optional list of additional untrusted certs for path building +* @return result of the path building operation (OK or error) +*/ +Certificate_Status_Code +BOTAN_PUBLIC_API(2,0) build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>>& cert_path_out, + const std::vector<Certificate_Store*>& trusted_certstores, + const std::shared_ptr<const X509_Certificate>& end_entity, + const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra); + +/** +* Check the certificate chain, but not any revocation data +* +* @param cert_path path built by build_certificate_path with OK result +* @param ref_time whatever time you want to perform the validation +* against (normally current system clock) +* @param hostname the hostname +* @param usage end entity usage checks +* @param min_signature_algo_strength 80 or 110 typically +* Note 80 allows 1024 bit RSA and SHA-1. 110 allows 2048 bit RSA and SHA-2. +* Using 128 requires ECC (P-256) or ~3000 bit RSA keys. +* @param trusted_hashes set of trusted hash functions, empty means accept any +* hash we have an OID for +* @return vector of results on per certificate in the path, each containing a set of +* results. If all codes in the set are < Certificate_Status_Code::FIRST_ERROR_STATUS, +* then the result for that certificate is successful. If all results are +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2,0) check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + std::chrono::system_clock::time_point ref_time, + const std::string& hostname, + Usage_Type usage, + size_t min_signature_algo_strength, + const std::set<std::string>& trusted_hashes); + +/** +* Check OCSP responses for revocation information +* @param cert_path path already validated by check_chain +* @param ocsp_responses the OCSP responses to consider +* @param certstores trusted roots +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @return revocation status +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2,0) check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses, + const std::vector<Certificate_Store*>& certstores, + std::chrono::system_clock::time_point ref_time); + +/** +* Check CRLs for revocation information +* @param cert_path path already validated by check_chain +* @param crls the list of CRLs to check, it is assumed that crls[i] (if not null) +* is the associated CRL for the subject in cert_path[i]. +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @return revocation status +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<std::shared_ptr<const X509_CRL>>& crls, + std::chrono::system_clock::time_point ref_time); + +/** +* Check CRLs for revocation information +* @param cert_path path already validated by check_chain +* @param certstores a list of certificate stores to query for the CRL +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @return revocation status +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2,0) check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& certstores, + std::chrono::system_clock::time_point ref_time); + +#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS) + +/** +* Check OCSP using online (HTTP) access. Current version creates a thread and +* network connection per OCSP request made. +* +* @param cert_path path already validated by check_chain +* @param trusted_certstores a list of certstores with trusted certs +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @param timeout for timing out the responses, though actually this function +* may block for up to timeout*cert_path.size()*C for some small C. +* @param ocsp_check_intermediate_CAs if true also performs OCSP on any intermediate +* CA certificates. If false, only does OCSP on the end entity cert. +* @return revocation status +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2,0) check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& trusted_certstores, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout, + bool ocsp_check_intermediate_CAs); + +/** +* Check CRL using online (HTTP) access. Current version creates a thread and +* network connection per CRL access. + +* @param cert_path path already validated by check_chain +* @param trusted_certstores a list of certstores with trusted certs +* @param certstore_to_recv_crls optional (nullptr to disable), all CRLs +* retreived will be saved to this cert store. +* @param ref_time whatever time you want to perform the validation against +* (normally current system clock) +* @param timeout for timing out the responses, though actually this function +* may block for up to timeout*cert_path.size()*C for some small C. +* @return revocation status +*/ +CertificatePathStatusCodes +BOTAN_PUBLIC_API(2,0) check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, + const std::vector<Certificate_Store*>& trusted_certstores, + Certificate_Store_In_Memory* certstore_to_recv_crls, + std::chrono::system_clock::time_point ref_time, + std::chrono::milliseconds timeout); + +#endif + +/** +* Find overall status (OK, error) of a validation +* @param cert_status result of merge_revocation_status or check_chain +*/ +Certificate_Status_Code BOTAN_PUBLIC_API(2,0) overall_status(const CertificatePathStatusCodes& cert_status); + +/** +* Merge the results from CRL and/or OCSP checks into chain_status +* @param chain_status the certificate status +* @param crl_status results from check_crl +* @param ocsp_status results from check_ocsp +* @param require_rev_on_end_entity require valid CRL or OCSP on end-entity cert +* @param require_rev_on_intermediates require valid CRL or OCSP on all intermediate certificates +*/ +void BOTAN_PUBLIC_API(2,0) merge_revocation_status(CertificatePathStatusCodes& chain_status, + const CertificatePathStatusCodes& crl_status, + const CertificatePathStatusCodes& ocsp_status, + bool require_rev_on_end_entity, + bool require_rev_on_intermediates); + +} + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509self.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509self.cpp new file mode 100644 index 0000000000..32f21c1015 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509self.cpp @@ -0,0 +1,147 @@ +/* +* PKCS #10/Self Signed Cert Creation +* (C) 1999-2008,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509self.h> +#include <botan/x509_ext.h> +#include <botan/x509_ca.h> +#include <botan/der_enc.h> +#include <botan/pubkey.h> +#include <botan/oids.h> +#include <botan/hash.h> + +namespace Botan { + +namespace { + +/* +* Load information from the X509_Cert_Options +*/ +void load_info(const X509_Cert_Options& opts, X509_DN& subject_dn, + AlternativeName& subject_alt) + { + subject_dn.add_attribute("X520.CommonName", opts.common_name); + subject_dn.add_attribute("X520.Country", opts.country); + subject_dn.add_attribute("X520.State", opts.state); + subject_dn.add_attribute("X520.Locality", opts.locality); + subject_dn.add_attribute("X520.Organization", opts.organization); + subject_dn.add_attribute("X520.OrganizationalUnit", opts.org_unit); + subject_dn.add_attribute("X520.SerialNumber", opts.serial_number); + subject_alt = AlternativeName(opts.email, opts.uri, opts.dns, opts.ip); + subject_alt.add_othername(OIDS::lookup("PKIX.XMPPAddr"), + opts.xmpp, UTF8_STRING); + + for(auto dns : opts.more_dns) + subject_alt.add_attribute("DNS", dns); + } +} + +namespace X509 { + +/* +* Create a new self-signed X.509 certificate +*/ +X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + AlgorithmIdentifier sig_algo; + X509_DN subject_dn; + AlternativeName subject_alt; + + // for now, only the padding option is used + std::map<std::string,std::string> sig_opts = { {"padding",opts.padding_scheme} }; + + const std::vector<uint8_t> pub_key = X509::BER_encode(key); + std::unique_ptr<PK_Signer> signer(choose_sig_format(key, sig_opts, rng, hash_fn, sig_algo)); + load_info(opts, subject_dn, subject_alt); + + Extensions extensions = opts.extensions; + + Key_Constraints constraints; + if(opts.is_CA) + { + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + } + else + { + verify_cert_constraints_valid_for_key_type(key, opts.constraints); + constraints = opts.constraints; + } + + extensions.add_new( + new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit), + true); + + if(constraints != NO_CONSTRAINTS) + { + extensions.add_new(new Cert_Extension::Key_Usage(constraints), true); + } + + std::unique_ptr<Cert_Extension::Subject_Key_ID> skid(new Cert_Extension::Subject_Key_ID(pub_key, hash_fn)); + + extensions.add_new(new Cert_Extension::Authority_Key_ID(skid->get_key_id())); + extensions.add_new(skid.release()); + + extensions.add_new( + new Cert_Extension::Subject_Alternative_Name(subject_alt)); + + extensions.add_new( + new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + + return X509_CA::make_cert(signer.get(), rng, sig_algo, pub_key, + opts.start, opts.end, + subject_dn, subject_dn, + extensions); + } + +/* +* Create a PKCS #10 certificate request +*/ +PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng) + { + X509_DN subject_dn; + AlternativeName subject_alt; + load_info(opts, subject_dn, subject_alt); + + Key_Constraints constraints; + if(opts.is_CA) + { + constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN); + } + else + { + verify_cert_constraints_valid_for_key_type(key, opts.constraints); + constraints = opts.constraints; + } + + Extensions extensions = opts.extensions; + + extensions.add_new(new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit)); + + if(constraints != NO_CONSTRAINTS) + { + extensions.add_new(new Cert_Extension::Key_Usage(constraints)); + } + extensions.add_new(new Cert_Extension::Extended_Key_Usage(opts.ex_constraints)); + extensions.add_new(new Cert_Extension::Subject_Alternative_Name(subject_alt)); + + return PKCS10_Request::create(key, + subject_dn, + extensions, + hash_fn, + rng, + opts.padding_scheme, + opts.challenge); + } + +} + +} diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509self.h b/src/libs/3rdparty/botan/src/lib/x509/x509self.h new file mode 100644 index 0000000000..7d061acbb3 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509self.h @@ -0,0 +1,215 @@ +/* +* X.509 Self-Signed Certificate +* (C) 1999-2007 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_X509_SELF_H_ +#define BOTAN_X509_SELF_H_ + +#include <botan/x509cert.h> +#include <botan/x509_ext.h> +#include <botan/pkcs10.h> +#include <botan/asn1_time.h> + +namespace Botan { + +class RandomNumberGenerator; +class Private_Key; + +/** +* Options for X.509 certificates. +*/ +class BOTAN_PUBLIC_API(2,0) X509_Cert_Options final + { + public: + /** + * the subject common name + */ + std::string common_name; + + /** + * the subject counry + */ + std::string country; + + /** + * the subject organization + */ + std::string organization; + + /** + * the subject organizational unit + */ + std::string org_unit; + + /** + * the subject locality + */ + std::string locality; + + /** + * the subject state + */ + std::string state; + + /** + * the subject serial number + */ + std::string serial_number; + + /** + * the subject email adress + */ + std::string email; + + /** + * the subject URI + */ + std::string uri; + + /** + * the subject IPv4 address + */ + std::string ip; + + /** + * the subject DNS + */ + std::string dns; + + std::vector<std::string> more_dns; + + /** + * the subject XMPP + */ + std::string xmpp; + + /** + * the subject challenge password + */ + std::string challenge; + + /** + * the subject notBefore + */ + X509_Time start; + /** + * the subject notAfter + */ + X509_Time end; + + /** + * Indicates whether the certificate request + */ + bool is_CA; + + /** + * Indicates the BasicConstraints path limit + */ + size_t path_limit; + + std::string padding_scheme; + + /** + * The key constraints for the subject public key + */ + Key_Constraints constraints; + + /** + * The key extended constraints for the subject public key + */ + std::vector<OID> ex_constraints; + + /** + * Additional X.509 extensions + */ + Extensions extensions; + + /** + * Mark the certificate as a CA certificate and set the path limit. + * @param limit the path limit to be set in the BasicConstraints extension. + */ + void CA_key(size_t limit = 1); + + /** + * Choose a padding scheme different from the default for the key used. + */ + void set_padding_scheme(const std::string& scheme); + + /** + * Set the notBefore of the certificate. + * @param time the notBefore value of the certificate + */ + void not_before(const std::string& time); + + /** + * Set the notAfter of the certificate. + * @param time the notAfter value of the certificate + */ + void not_after(const std::string& time); + + /** + * Add the key constraints of the KeyUsage extension. + * @param constr the constraints to set + */ + void add_constraints(Key_Constraints constr); + + /** + * Add constraints to the ExtendedKeyUsage extension. + * @param oid the oid to add + */ + void add_ex_constraint(const OID& oid); + + /** + * Add constraints to the ExtendedKeyUsage extension. + * @param name the name to look up the oid to add + */ + void add_ex_constraint(const std::string& name); + + /** + * Construct a new options object + * @param opts define the common name of this object. An example for this + * parameter would be "common_name/country/organization/organizational_unit". + * @param expire_time the expiration time (from the current clock in seconds) + */ + X509_Cert_Options(const std::string& opts = "", + uint32_t expire_time = 365 * 24 * 60 * 60); + }; + +namespace X509 { + +/** +* Create a self-signed X.509 certificate. +* @param opts the options defining the certificate to create +* @param key the private key used for signing, i.e. the key +* associated with this self-signed certificate +* @param hash_fn the hash function to use +* @param rng the rng to use +* @return newly created self-signed certificate +*/ +BOTAN_PUBLIC_API(2,0) X509_Certificate +create_self_signed_cert(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +/** +* Create a PKCS#10 certificate request. +* @param opts the options defining the request to create +* @param key the key used to sign this request +* @param rng the rng to use +* @param hash_fn the hash function to use +* @return newly created PKCS#10 request +*/ +BOTAN_PUBLIC_API(2,0) PKCS10_Request create_cert_req(const X509_Cert_Options& opts, + const Private_Key& key, + const std::string& hash_fn, + RandomNumberGenerator& rng); + +} + +} + +#endif |