diff options
author | lloyd <[email protected]> | 2015-03-23 02:14:48 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2015-03-23 02:14:48 +0000 |
commit | e9283c9817949aa27ae97f0c9ec06745fb62240d (patch) | |
tree | 8cbdb20e07b5b74e734ded250363776bff1daf04 | |
parent | ce679ca4fc75c7f7ffa36d4364392fe0dd2b1294 (diff) |
Move the signature padding schemes to the PK operation classes,
as was previously done with encrypt/decrypt ops.
One feature dropped on the floor here is previously PK_Signer by
default did verification of signatures before releasing them as an
measure against fault attacks. However in addition to being expensive
this turned out to be difficult to implement with the new scheme.
-rw-r--r-- | src/cmd/speed_pk.cpp | 9 | ||||
-rw-r--r-- | src/lib/pubkey/dsa/dsa.cpp | 16 | ||||
-rw-r--r-- | src/lib/pubkey/ecdsa/ecdsa.cpp | 32 | ||||
-rw-r--r-- | src/lib/pubkey/gost_3410/gost_3410.cpp | 34 | ||||
-rw-r--r-- | src/lib/pubkey/info.txt | 1 | ||||
-rw-r--r-- | src/lib/pubkey/nr/nr.cpp | 34 | ||||
-rw-r--r-- | src/lib/pubkey/pk_ops.cpp | 58 | ||||
-rw-r--r-- | src/lib/pubkey/pk_ops.h | 150 | ||||
-rw-r--r-- | src/lib/pubkey/pk_ops_impl.h | 146 | ||||
-rw-r--r-- | src/lib/pubkey/pk_utils.h | 2 | ||||
-rw-r--r-- | src/lib/pubkey/pubkey.cpp | 210 | ||||
-rw-r--r-- | src/lib/pubkey/pubkey.h | 27 | ||||
-rw-r--r-- | src/lib/pubkey/rsa/rsa.cpp | 20 | ||||
-rw-r--r-- | src/lib/pubkey/rw/rw.cpp | 20 |
14 files changed, 393 insertions, 366 deletions
diff --git a/src/cmd/speed_pk.cpp b/src/cmd/speed_pk.cpp index 313892a23..ed3349cd5 100644 --- a/src/cmd/speed_pk.cpp +++ b/src/cmd/speed_pk.cpp @@ -80,9 +80,6 @@ using namespace Botan; #include <memory> #include <set> -#define BENCH_FAULT_PROT DISABLE_FAULT_PROTECTION -//#define BENCH_FAULT_PROT ENABLE_FAULT_PROTECTION - namespace { const char* ec_domains[] = { @@ -347,7 +344,7 @@ void benchmark_ecdsa(RandomNumberGenerator& rng, ECDSA_PrivateKey key(rng, params); keygen_timer.stop(); - PK_Signer sig(key, padding, IEEE_1363, BENCH_FAULT_PROT); + PK_Signer sig(key, padding, IEEE_1363); PK_Verifier ver(key, padding); benchmark_sig_ver(ver, sig, verify_timer, @@ -389,7 +386,7 @@ void benchmark_gost_3410(RandomNumberGenerator& rng, GOST_3410_PrivateKey key(rng, params); keygen_timer.stop(); - PK_Signer sig(key, padding, IEEE_1363, BENCH_FAULT_PROT); + PK_Signer sig(key, padding, IEEE_1363); PK_Verifier ver(key, padding); benchmark_sig_ver(ver, sig, verify_timer, @@ -496,7 +493,7 @@ void benchmark_dsa_nr(RandomNumberGenerator& rng, algo_name = key.algo_name(); keygen_timer.stop(); - PK_Signer sig(key, padding, IEEE_1363, BENCH_FAULT_PROT); + PK_Signer sig(key, padding, IEEE_1363); PK_Verifier ver(key, padding); benchmark_sig_ver(ver, sig, verify_timer, diff --git a/src/lib/pubkey/dsa/dsa.cpp b/src/lib/pubkey/dsa/dsa.cpp index ca5e93f4e..90cc18fdc 100644 --- a/src/lib/pubkey/dsa/dsa.cpp +++ b/src/lib/pubkey/dsa/dsa.cpp @@ -74,11 +74,12 @@ namespace { /** * Object that can create a DSA signature */ -class DSA_Signature_Operation : public PK_Ops::Signature +class DSA_Signature_Operation : public PK_Ops::Signature_with_EMSA { public: typedef DSA_PrivateKey Key_Type; DSA_Signature_Operation(const DSA_PrivateKey& dsa, const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), q(dsa.group_q()), x(dsa.get_x()), powermod_g_p(dsa.group_g(), dsa.group_p()), @@ -91,8 +92,8 @@ class DSA_Signature_Operation : public PK_Ops::Signature size_t message_part_size() const override { return q.bytes(); } size_t max_input_bits() const override { return q.bits(); } - secure_vector<byte> sign(const byte msg[], size_t msg_len, - RandomNumberGenerator& rng) override; + secure_vector<byte> raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) override; private: const BigInt& q; const BigInt& x; @@ -102,8 +103,8 @@ class DSA_Signature_Operation : public PK_Ops::Signature }; secure_vector<byte> -DSA_Signature_Operation::sign(const byte msg[], size_t msg_len, - RandomNumberGenerator&) +DSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator&) { BigInt i(msg, msg_len); @@ -132,12 +133,13 @@ DSA_Signature_Operation::sign(const byte msg[], size_t msg_len, /** * Object that can verify a DSA signature */ -class DSA_Verification_Operation : public PK_Ops::Verification +class DSA_Verification_Operation : public PK_Ops::Verification_with_EMSA { public: typedef DSA_PublicKey Key_Type; DSA_Verification_Operation(const DSA_PublicKey& dsa, - const std::string&) : + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), q(dsa.group_q()), y(dsa.get_y()) { powermod_g_p = Fixed_Base_Power_Mod(dsa.group_g(), dsa.group_p()); diff --git a/src/lib/pubkey/ecdsa/ecdsa.cpp b/src/lib/pubkey/ecdsa/ecdsa.cpp index d2ad82b94..2518a14fe 100644 --- a/src/lib/pubkey/ecdsa/ecdsa.cpp +++ b/src/lib/pubkey/ecdsa/ecdsa.cpp @@ -32,13 +32,14 @@ namespace { /** * ECDSA signature operation */ -class ECDSA_Signature_Operation : public PK_Ops::Signature +class ECDSA_Signature_Operation : public PK_Ops::Signature_with_EMSA { public: typedef ECDSA_PrivateKey Key_Type; ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa, const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), base_point(ecdsa.domain().get_base_point()), order(ecdsa.domain().get_order()), x(ecdsa.private_value()), @@ -47,12 +48,12 @@ class ECDSA_Signature_Operation : public PK_Ops::Signature { } - secure_vector<byte> sign(const byte msg[], size_t msg_len, - RandomNumberGenerator& rng); + secure_vector<byte> raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) override; - size_t message_parts() const { return 2; } - size_t message_part_size() const { return order.bytes(); } - size_t max_input_bits() const { return order.bits(); } + size_t message_parts() const override { return 2; } + size_t message_part_size() const override { return order.bytes(); } + size_t max_input_bits() const override { return order.bits(); } private: const PointGFp& base_point; @@ -63,8 +64,8 @@ class ECDSA_Signature_Operation : public PK_Ops::Signature }; secure_vector<byte> -ECDSA_Signature_Operation::sign(const byte msg[], size_t msg_len, - RandomNumberGenerator&) +ECDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator&) { const BigInt m(msg, msg_len); @@ -87,12 +88,13 @@ ECDSA_Signature_Operation::sign(const byte msg[], size_t msg_len, /** * ECDSA verification operation */ -class ECDSA_Verification_Operation : public PK_Ops::Verification +class ECDSA_Verification_Operation : public PK_Ops::Verification_with_EMSA { public: typedef ECDSA_PublicKey Key_Type; ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, - const std::string&) : + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), m_base_point(ecdsa.domain().get_base_point()), m_public_point(ecdsa.public_point()), m_order(ecdsa.domain().get_order()), @@ -101,14 +103,14 @@ class ECDSA_Verification_Operation : public PK_Ops::Verification //m_public_point.precompute_multiples(); } - size_t message_parts() const { return 2; } - size_t message_part_size() const { return m_order.bytes(); } - size_t max_input_bits() const { return m_order.bits(); } + size_t message_parts() const override { return 2; } + size_t message_part_size() const override { return m_order.bytes(); } + size_t max_input_bits() const override { return m_order.bits(); } - bool with_recovery() const { return false; } + bool with_recovery() const override { return false; } bool verify(const byte msg[], size_t msg_len, - const byte sig[], size_t sig_len); + const byte sig[], size_t sig_len) override; private: const PointGFp& m_base_point; const PointGFp& m_public_point; diff --git a/src/lib/pubkey/gost_3410/gost_3410.cpp b/src/lib/pubkey/gost_3410/gost_3410.cpp index 497712fd9..8eb711617 100644 --- a/src/lib/pubkey/gost_3410/gost_3410.cpp +++ b/src/lib/pubkey/gost_3410/gost_3410.cpp @@ -94,21 +94,23 @@ BigInt decode_le(const byte msg[], size_t msg_len) /** * GOST-34.10 signature operation */ -class GOST_3410_Signature_Operation : public PK_Ops::Signature +class GOST_3410_Signature_Operation : public PK_Ops::Signature_with_EMSA { public: typedef GOST_3410_PrivateKey Key_Type; - GOST_3410_Signature_Operation(const GOST_3410_PrivateKey& gost_3410, const std::string&): + GOST_3410_Signature_Operation(const GOST_3410_PrivateKey& gost_3410, + const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), base_point(gost_3410.domain().get_base_point()), order(gost_3410.domain().get_order()), x(gost_3410.private_value()) {} - size_t message_parts() const { return 2; } - size_t message_part_size() const { return order.bytes(); } - size_t max_input_bits() const { return order.bits(); } + size_t message_parts() const override { return 2; } + size_t message_part_size() const override { return order.bytes(); } + size_t max_input_bits() const override { return order.bits(); } - secure_vector<byte> sign(const byte msg[], size_t msg_len, - RandomNumberGenerator& rng); + secure_vector<byte> raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) override; private: const PointGFp& base_point; @@ -117,8 +119,8 @@ class GOST_3410_Signature_Operation : public PK_Ops::Signature }; secure_vector<byte> -GOST_3410_Signature_Operation::sign(const byte msg[], size_t msg_len, - RandomNumberGenerator& rng) +GOST_3410_Signature_Operation::raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) { BigInt k; do @@ -150,21 +152,23 @@ GOST_3410_Signature_Operation::sign(const byte msg[], size_t msg_len, /** * GOST-34.10 verification operation */ -class GOST_3410_Verification_Operation : public PK_Ops::Verification +class GOST_3410_Verification_Operation : public PK_Ops::Verification_with_EMSA { public: typedef GOST_3410_PublicKey Key_Type; - GOST_3410_Verification_Operation(const GOST_3410_PublicKey& gost, const std::string&) : + GOST_3410_Verification_Operation(const GOST_3410_PublicKey& gost, + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), base_point(gost.domain().get_base_point()), public_point(gost.public_point()), order(gost.domain().get_order()) {} - size_t message_parts() const { return 2; } - size_t message_part_size() const { return order.bytes(); } - size_t max_input_bits() const { return order.bits(); } + size_t message_parts() const override { return 2; } + size_t message_part_size() const override { return order.bytes(); } + size_t max_input_bits() const override { return order.bits(); } - bool with_recovery() const { return false; } + bool with_recovery() const override { return false; } bool verify(const byte msg[], size_t msg_len, const byte sig[], size_t sig_len); diff --git a/src/lib/pubkey/info.txt b/src/lib/pubkey/info.txt index 4bb6288f9..055ebc320 100644 --- a/src/lib/pubkey/info.txt +++ b/src/lib/pubkey/info.txt @@ -24,6 +24,7 @@ workfactor.h <header:internal> pk_algs.h pk_utils.h +pk_ops_impl.h </header:internal> <requires> diff --git a/src/lib/pubkey/nr/nr.cpp b/src/lib/pubkey/nr/nr.cpp index 6e3a8f0c1..ed90c2345 100644 --- a/src/lib/pubkey/nr/nr.cpp +++ b/src/lib/pubkey/nr/nr.cpp @@ -78,11 +78,12 @@ namespace { /** * Nyberg-Rueppel signature operation */ -class NR_Signature_Operation : public PK_Ops::Signature +class NR_Signature_Operation : public PK_Ops::Signature_with_EMSA { public: typedef NR_PrivateKey Key_Type; - NR_Signature_Operation(const NR_PrivateKey& nr, const std::string&) : + NR_Signature_Operation(const NR_PrivateKey& nr, const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), q(nr.group_q()), x(nr.get_x()), powermod_g_p(nr.group_g(), nr.group_p()), @@ -90,12 +91,12 @@ class NR_Signature_Operation : public PK_Ops::Signature { } - size_t message_parts() const { return 2; } - size_t message_part_size() const { return q.bytes(); } - size_t max_input_bits() const { return (q.bits() - 1); } + size_t message_parts() const override { return 2; } + size_t message_part_size() const override { return q.bytes(); } + size_t max_input_bits() const override { return (q.bits() - 1); } - secure_vector<byte> sign(const byte msg[], size_t msg_len, - RandomNumberGenerator& rng); + secure_vector<byte> raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) override; private: const BigInt& q; const BigInt& x; @@ -104,8 +105,8 @@ class NR_Signature_Operation : public PK_Ops::Signature }; secure_vector<byte> -NR_Signature_Operation::sign(const byte msg[], size_t msg_len, - RandomNumberGenerator& rng) +NR_Signature_Operation::raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) { rng.add_entropy(msg, msg_len); @@ -137,11 +138,12 @@ NR_Signature_Operation::sign(const byte msg[], size_t msg_len, /** * Nyberg-Rueppel verification operation */ -class NR_Verification_Operation : public PK_Ops::Verification +class NR_Verification_Operation : public PK_Ops::Verification_with_EMSA { public: typedef NR_PublicKey Key_Type; - NR_Verification_Operation(const NR_PublicKey& nr, const std::string&) : + NR_Verification_Operation(const NR_PublicKey& nr, const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), q(nr.group_q()), y(nr.get_y()) { powermod_g_p = Fixed_Base_Power_Mod(nr.group_g(), nr.group_p()); @@ -150,13 +152,13 @@ class NR_Verification_Operation : public PK_Ops::Verification mod_q = Modular_Reducer(nr.group_q()); } - size_t message_parts() const { return 2; } - size_t message_part_size() const { return q.bytes(); } - size_t max_input_bits() const { return (q.bits() - 1); } + size_t message_parts() const override { return 2; } + size_t message_part_size() const override { return q.bytes(); } + size_t max_input_bits() const override { return (q.bits() - 1); } - bool with_recovery() const { return true; } + bool with_recovery() const override { return true; } - secure_vector<byte> verify_mr(const byte msg[], size_t msg_len); + secure_vector<byte> verify_mr(const byte msg[], size_t msg_len) override; private: const BigInt& q; const BigInt& y; diff --git a/src/lib/pubkey/pk_ops.cpp b/src/lib/pubkey/pk_ops.cpp index 718cd3998..f78861b9f 100644 --- a/src/lib/pubkey/pk_ops.cpp +++ b/src/lib/pubkey/pk_ops.cpp @@ -5,7 +5,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include <botan/pk_ops.h> +#include <botan/internal/pk_ops_impl.h> #include <botan/eme.h> #include <botan/kdf.h> #include <botan/emsa.h> @@ -17,7 +17,7 @@ PK_Ops::Encryption_with_EME::Encryption_with_EME(const std::string& eme) { m_eme.reset(get_eme(eme)); if(!m_eme.get()) - throw std::runtime_error("EME " + eme + " not found"); + throw Algorithm_Not_Found(eme); } PK_Ops::Encryption_with_EME::~Encryption_with_EME() {} @@ -44,7 +44,7 @@ PK_Ops::Decryption_with_EME::Decryption_with_EME(const std::string& eme) { m_eme.reset(get_eme(eme)); if(!m_eme.get()) - throw std::runtime_error("EME " + eme + " not found"); + throw Algorithm_Not_Found(eme); } PK_Ops::Decryption_with_EME::~Decryption_with_EME() {} @@ -77,4 +77,56 @@ secure_vector<byte> PK_Ops::Key_Agreement_with_KDF::agree(size_t key_len, return z; } +PK_Ops::Signature_with_EMSA::Signature_with_EMSA(const std::string& emsa) + { + m_emsa.reset(get_emsa(emsa)); + if(!m_emsa) + throw Algorithm_Not_Found(emsa); + } + +PK_Ops::Signature_with_EMSA::~Signature_with_EMSA() {} + +void PK_Ops::Signature_with_EMSA::update(const byte msg[], size_t msg_len) + { + m_emsa->update(msg, msg_len); + } + +secure_vector<byte> PK_Ops::Signature_with_EMSA::sign(RandomNumberGenerator& rng) + { + const secure_vector<byte> msg = m_emsa->raw_data(); + const auto padded = m_emsa->encoding_of(msg, this->max_input_bits(), rng); + return raw_sign(&padded[0], padded.size(), rng); + } + +PK_Ops::Verification_with_EMSA::Verification_with_EMSA(const std::string& emsa) + { + m_emsa.reset(get_emsa(emsa)); + if(!m_emsa) + throw Algorithm_Not_Found(emsa); + } + +PK_Ops::Verification_with_EMSA::~Verification_with_EMSA() {} + +void PK_Ops::Verification_with_EMSA::update(const byte msg[], size_t msg_len) + { + m_emsa->update(msg, msg_len); + } + +bool PK_Ops::Verification_with_EMSA::is_valid_signature(const byte sig[], size_t sig_len) + { + const secure_vector<byte> msg = m_emsa->raw_data(); + + if(with_recovery()) + { + secure_vector<byte> 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<byte> encoded = m_emsa->encoding_of(msg, max_input_bits(), rng); + return verify(&encoded[0], encoded.size(), sig, sig_len); + } + } + } diff --git a/src/lib/pubkey/pk_ops.h b/src/lib/pubkey/pk_ops.h index 754bcf82d..3a2a8bdb5 100644 --- a/src/lib/pubkey/pk_ops.h +++ b/src/lib/pubkey/pk_ops.h @@ -21,7 +21,7 @@ class EMSA; namespace PK_Ops { template<typename Key> -struct PK_Spec +class PK_Spec { public: PK_Spec(const Key& key, const std::string& pad) : @@ -38,6 +38,9 @@ struct PK_Spec const std::string m_pad; }; +typedef PK_Spec<Public_Key> PK_Spec_Public_Key; +typedef PK_Spec<Private_Key> PK_Spec_Private_Key; + /** * Public key encryption interface */ @@ -48,68 +51,53 @@ class BOTAN_DLL Encryption virtual secure_vector<byte> encrypt(const byte msg[], size_t msg_len, RandomNumberGenerator& rng) = 0; - typedef PK_Spec<Public_Key> Spec; + typedef PK_Spec_Public_Key Spec; virtual ~Encryption() {} }; -class BOTAN_DLL Encryption_with_EME : public Encryption - { - public: - size_t max_input_bits() const override; - - secure_vector<byte> encrypt(const byte msg[], size_t msg_len, - RandomNumberGenerator& rng) override; - - ~Encryption_with_EME(); - protected: - Encryption_with_EME(const std::string& eme); - private: - virtual size_t max_raw_input_bits() const = 0; - - virtual secure_vector<byte> raw_encrypt(const byte msg[], size_t len, - RandomNumberGenerator& rng) = 0; - std::unique_ptr<EME> m_eme; - }; - /** * Public key decryption interface */ class BOTAN_DLL Decryption { public: + typedef PK_Spec_Private_Key Spec; + virtual size_t max_input_bits() const = 0; virtual secure_vector<byte> decrypt(const byte msg[], size_t msg_len) = 0; - typedef PK_Spec<Private_Key> Spec; - virtual ~Decryption() {} }; -class BOTAN_DLL Decryption_with_EME : public Decryption +/** +* Public key signature verification interface +*/ +class BOTAN_DLL Verification { public: - size_t max_input_bits() const override; + typedef PK_Spec_Public_Key Spec; - secure_vector<byte> decrypt(const byte msg[], size_t msg_len) override; + /* + * 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 byte msg[], size_t msg_len) = 0; - ~Decryption_with_EME(); - protected: - Decryption_with_EME(const std::string& eme); - private: - virtual size_t max_raw_input_bits() const = 0; - virtual secure_vector<byte> raw_decrypt(const byte msg[], size_t len) = 0; - std::unique_ptr<EME> m_eme; - }; + /* + * Perform a signature operation + * @param rng a random number generator + */ + virtual bool is_valid_signature(const byte sig[], size_t sig_len) = 0; + /** + * 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; -/** -* Public key signature creation interface -*/ -class BOTAN_DLL Signature - { - public: /** * Find out the number of message parts supported by this scheme. * @return number of message parts @@ -122,37 +110,16 @@ class BOTAN_DLL Signature */ virtual size_t message_part_size() const { return 0; } - /** - * 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; - - /* - * Perform a signature operation - * @param msg the message - * @param msg_len the length of msg in bytes - * @param rng a random number generator - */ - virtual secure_vector<byte> sign(const byte msg[], size_t msg_len, - RandomNumberGenerator& rng) = 0; - - typedef PK_Spec<Private_Key> Spec; - - virtual ~Signature() {} + virtual ~Verification() {} }; /** -* Public key signature verification interface +* Public key signature creation interface */ -class BOTAN_DLL Verification +class BOTAN_DLL Signature { public: - /** - * 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; + typedef PK_Spec_Private_Key Spec; /** * Find out the number of message parts supported by this scheme. @@ -166,42 +133,20 @@ class BOTAN_DLL Verification */ virtual size_t message_part_size() const { return 0; } - /** - * @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 + * Add more data to the message currently being signed * @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 byte[], size_t, - const byte[], size_t) - { - throw Invalid_State("Message recovery required"); - } + virtual void update(const byte msg[], size_t msg_len) = 0; /* - * 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 + * Perform a signature operation + * @param rng a random number generator */ - virtual secure_vector<byte> verify_mr(const byte[], - size_t) - { - throw Invalid_State("Message recovery not supported"); - } + virtual secure_vector<byte> sign(RandomNumberGenerator& rng) = 0; - typedef PK_Spec<Public_Key> Spec; - - virtual ~Verification() {} + virtual ~Signature() {} }; /** @@ -210,30 +155,15 @@ class BOTAN_DLL Verification class BOTAN_DLL Key_Agreement { public: + typedef PK_Spec_Private_Key Spec; + virtual secure_vector<byte> agree(size_t key_len, const byte other_key[], size_t other_key_len, const byte salt[], size_t salt_len) = 0; - typedef PK_Spec<Private_Key> Spec; - virtual ~Key_Agreement() {} }; -class BOTAN_DLL Key_Agreement_with_KDF : public Key_Agreement - { - public: - secure_vector<byte> agree(size_t key_len, - const byte other_key[], size_t other_key_len, - const byte salt[], size_t salt_len) override; - - protected: - Key_Agreement_with_KDF(const std::string& kdf); - ~Key_Agreement_with_KDF(); - private: - virtual secure_vector<byte> raw_agree(const byte w[], size_t w_len) = 0; - std::unique_ptr<KDF> m_kdf; - }; - } } diff --git a/src/lib/pubkey/pk_ops_impl.h b/src/lib/pubkey/pk_ops_impl.h new file mode 100644 index 000000000..f27de4af4 --- /dev/null +++ b/src/lib/pubkey/pk_ops_impl.h @@ -0,0 +1,146 @@ +/* +* (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> + +namespace Botan { + +namespace PK_Ops { + +class Encryption_with_EME : public Encryption + { + public: + size_t max_input_bits() const override; + + secure_vector<byte> encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + + ~Encryption_with_EME(); + protected: + Encryption_with_EME(const std::string& eme); + private: + virtual size_t max_raw_input_bits() const = 0; + + virtual secure_vector<byte> raw_encrypt(const byte msg[], size_t len, + RandomNumberGenerator& rng) = 0; + std::unique_ptr<EME> m_eme; + }; + +class Decryption_with_EME : public Decryption + { + public: + size_t max_input_bits() const override; + + secure_vector<byte> decrypt(const byte msg[], size_t msg_len) override; + + ~Decryption_with_EME(); + protected: + Decryption_with_EME(const std::string& eme); + private: + virtual size_t max_raw_input_bits() const = 0; + virtual secure_vector<byte> raw_decrypt(const byte msg[], size_t len) = 0; + std::unique_ptr<EME> m_eme; + }; + +class Verification_with_EMSA : public Verification + { + public: + void update(const byte msg[], size_t msg_len) override; + bool is_valid_signature(const byte sig[], size_t sig_len) override; + + bool do_check(const secure_vector<byte>& msg, + const byte sig[], size_t sig_len); + + protected: + + Verification_with_EMSA(const std::string& emsa); + ~Verification_with_EMSA(); + + /** + * @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 byte[], size_t, + const byte[], 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<byte> verify_mr(const byte[], size_t) + { + throw Invalid_State("Message recovery not supported"); + } + + private: + std::unique_ptr<EMSA> m_emsa; + }; + +class Signature_with_EMSA : public Signature + { + public: + void update(const byte msg[], size_t msg_len) override; + + secure_vector<byte> sign(RandomNumberGenerator& rng) override; + protected: + Signature_with_EMSA(const std::string& emsa); + ~Signature_with_EMSA(); + 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<byte>& msg, + const std::vector<byte>& sig) const; + + virtual secure_vector<byte> raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) = 0; + + std::unique_ptr<EMSA> m_emsa; + }; + +class Key_Agreement_with_KDF : public Key_Agreement + { + public: + secure_vector<byte> agree(size_t key_len, + const byte other_key[], size_t other_key_len, + const byte salt[], size_t salt_len) override; + + protected: + Key_Agreement_with_KDF(const std::string& kdf); + ~Key_Agreement_with_KDF(); + private: + virtual secure_vector<byte> raw_agree(const byte w[], size_t w_len) = 0; + std::unique_ptr<KDF> m_kdf; + }; + +} + +} + +#endif diff --git a/src/lib/pubkey/pk_utils.h b/src/lib/pubkey/pk_utils.h index 2d643d862..14c304ac5 100644 --- a/src/lib/pubkey/pk_utils.h +++ b/src/lib/pubkey/pk_utils.h @@ -9,7 +9,7 @@ #define BOTAN_PK_UTILS_H__ #include <botan/internal/algo_registry.h> -#include <botan/pk_ops.h> +#include <botan/internal/pk_ops_impl.h> #include <botan/numthry.h> #include <algorithm> diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp index a2bb44e5c..1d32697f5 100644 --- a/src/lib/pubkey/pubkey.cpp +++ b/src/lib/pubkey/pubkey.cpp @@ -5,18 +5,10 @@ */ #include <botan/pubkey.h> +#include <botan/internal/algo_registry.h> #include <botan/der_enc.h> #include <botan/ber_dec.h> #include <botan/bigint.h> -#include <botan/parsing.h> -#include <botan/internal/algo_registry.h> -#include <botan/internal/bit_ops.h> - -#if defined(BOTAN_HAS_SYSTEM_RNG) - #include <botan/system_rng.h> -#else - #include <botan/auto_rng.h> -#endif namespace Botan { @@ -73,132 +65,88 @@ SymmetricKey PK_Key_Agreement::derive_key(size_t key_len, return m_op->agree(key_len, in, in_len, salt, salt_len); } -/* -* PK_Signer Constructor -*/ -PK_Signer::PK_Signer(const Private_Key& key, - const std::string& emsa, - Signature_Format format, - Fault_Protection prot) - { - m_op.reset(get_pk_op<PK_Ops::Signature>(key, emsa)); - - if(prot == ENABLE_FAULT_PROTECTION) - m_verify_op.reset(get_pk_op<PK_Ops::Verification>(key, emsa)); - - if(!m_op || (prot == ENABLE_FAULT_PROTECTION && !m_verify_op)) - throw Lookup_Error("Signing with " + key.algo_name() + " not supported"); - - m_emsa.reset(get_emsa(emsa)); - m_sig_format = format; - } +namespace { -/* -* Sign a message -*/ -std::vector<byte> PK_Signer::sign_message(const byte msg[], size_t length, - RandomNumberGenerator& rng) +std::vector<byte> der_encode_signature(const std::vector<byte>& sig, size_t parts) { - update(msg, length); - return signature(rng); - } + if(sig.size() % parts) + throw Encoding_Error("PK_Signer: strange signature size found"); + const size_t SIZE_OF_PART = sig.size() / parts; -/* -* Add more to the message to be signed -*/ -void PK_Signer::update(const byte in[], size_t length) - { - m_emsa->update(in, length); + std::vector<BigInt> sig_parts(parts); + for(size_t j = 0; j != sig_parts.size(); ++j) + sig_parts[j].binary_decode(&sig[SIZE_OF_PART*j], SIZE_OF_PART); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(sig_parts) + .end_cons() + .get_contents_unlocked(); } -/* -* Check the signature we just created, to help prevent fault attacks -*/ -bool PK_Signer::self_test_signature(const std::vector<byte>& msg, - const std::vector<byte>& sig) const +std::vector<byte> der_decode_signature(const byte sig[], size_t len, + size_t part_size, size_t parts) { - if(!m_verify_op) - return true; // checking disabled, assume ok + std::vector<byte> real_sig; + BER_Decoder decoder(sig, len); + BER_Decoder ber_sig = decoder.start_cons(SEQUENCE); - if(m_verify_op->with_recovery()) + size_t count = 0; + while(ber_sig.more_items()) { - std::vector<byte> recovered = - unlock(m_verify_op->verify_mr(&sig[0], sig.size())); + BigInt sig_part; + ber_sig.decode(sig_part); + real_sig += BigInt::encode_1363(sig_part, part_size); + ++count; + } - if(msg.size() > recovered.size()) - { - size_t extra_0s = msg.size() - recovered.size(); + if(count != parts) + throw Decoding_Error("PK_Verifier: signature size invalid"); + return real_sig; + } - for(size_t i = 0; i != extra_0s; ++i) - if(msg[i] != 0) - return false; +} - return same_mem(&msg[extra_0s], &recovered[0], recovered.size()); - } +PK_Signer::PK_Signer(const Private_Key& key, + const std::string& emsa, + Signature_Format format) + { + m_op.reset(get_pk_op<PK_Ops::Signature>(key, emsa)); + if(!m_op) + throw Lookup_Error("Signing with " + key.algo_name() + "/" + emsa + " not supported"); + m_sig_format = format; + } - return (recovered == msg); - } - else - return m_verify_op->verify(&msg[0], msg.size(), - &sig[0], sig.size()); +void PK_Signer::update(const byte in[], size_t length) + { + m_op->update(in, length); } -/* -* Create a signature -*/ std::vector<byte> PK_Signer::signature(RandomNumberGenerator& rng) { - std::vector<byte> encoded = unlock(m_emsa->encoding_of(m_emsa->raw_data(), - m_op->max_input_bits(), - rng)); - - std::vector<byte> plain_sig = unlock(m_op->sign(&encoded[0], encoded.size(), rng)); - - BOTAN_ASSERT(self_test_signature(encoded, plain_sig), "Signature was consistent"); + const std::vector<byte> plain_sig = unlock(m_op->sign(rng)); + const size_t parts = m_op->message_parts(); - if(m_op->message_parts() == 1 || m_sig_format == IEEE_1363) + if(parts == 1 || m_sig_format == IEEE_1363) return plain_sig; - - if(m_sig_format == DER_SEQUENCE) - { - if(plain_sig.size() % m_op->message_parts()) - throw Encoding_Error("PK_Signer: strange signature size found"); - const size_t SIZE_OF_PART = plain_sig.size() / m_op->message_parts(); - - std::vector<BigInt> sig_parts(m_op->message_parts()); - for(size_t j = 0; j != sig_parts.size(); ++j) - sig_parts[j].binary_decode(&plain_sig[SIZE_OF_PART*j], SIZE_OF_PART); - - return DER_Encoder() - .start_cons(SEQUENCE) - .encode_list(sig_parts) - .end_cons() - .get_contents_unlocked(); - } + else if(m_sig_format == DER_SEQUENCE) + return der_encode_signature(plain_sig, parts); else throw Encoding_Error("PK_Signer: Unknown signature format " + std::to_string(m_sig_format)); } -/* -* PK_Verifier Constructor -*/ PK_Verifier::PK_Verifier(const Public_Key& key, const std::string& emsa_name, Signature_Format format) { m_op.reset(get_pk_op<PK_Ops::Verification>(key, emsa_name)); - if(!m_op) throw Lookup_Error("Verification with " + key.algo_name() + " not supported"); - m_emsa.reset(get_emsa(emsa_name)); m_sig_format = format; } -/* -* Set the signature format -*/ void PK_Verifier::set_input_format(Signature_Format format) { if(m_op->message_parts() == 1 && format != IEEE_1363) @@ -206,9 +154,6 @@ void PK_Verifier::set_input_format(Signature_Format format) m_sig_format = format; } -/* -* Verify a message -*/ bool PK_Verifier::verify_message(const byte msg[], size_t msg_length, const byte sig[], size_t sig_length) { @@ -216,42 +161,25 @@ bool PK_Verifier::verify_message(const byte msg[], size_t msg_length, return check_signature(sig, sig_length); } -/* -* Append to the message -*/ void PK_Verifier::update(const byte in[], size_t length) { - m_emsa->update(in, length); + m_op->update(in, length); } -/* -* Check a signature -*/ bool PK_Verifier::check_signature(const byte sig[], size_t length) { try { if(m_sig_format == IEEE_1363) - return validate_signature(m_emsa->raw_data(), sig, length); + { + return m_op->is_valid_signature(sig, length); + } else if(m_sig_format == DER_SEQUENCE) { - BER_Decoder decoder(sig, length); - BER_Decoder ber_sig = decoder.start_cons(SEQUENCE); - - size_t count = 0; - std::vector<byte> real_sig; - while(ber_sig.more_items()) - { - BigInt sig_part; - ber_sig.decode(sig_part); - real_sig += BigInt::encode_1363(sig_part, m_op->message_part_size()); - ++count; - } - - if(count != m_op->message_parts()) - throw Decoding_Error("PK_Verifier: signature size invalid"); - - return validate_signature(m_emsa->raw_data(), - &real_sig[0], real_sig.size()); + std::vector<byte> real_sig = der_decode_signature(sig, length, + m_op->message_part_size(), + m_op->message_parts()); + + return m_op->is_valid_signature(&real_sig[0], real_sig.size()); } else throw Decoding_Error("PK_Verifier: Unknown signature format " + @@ -260,26 +188,4 @@ bool PK_Verifier::check_signature(const byte sig[], size_t length) catch(Invalid_Argument) { return false; } } -/* -* Verify a signature -*/ -bool PK_Verifier::validate_signature(const secure_vector<byte>& msg, - const byte sig[], size_t sig_len) - { - if(m_op->with_recovery()) - { - secure_vector<byte> output_of_key = m_op->verify_mr(sig, sig_len); - return m_emsa->verify(output_of_key, msg, m_op->max_input_bits()); - } - else - { - Null_RNG rng; - - secure_vector<byte> encoded = - m_emsa->encoding_of(msg, m_op->max_input_bits(), rng); - - return m_op->verify(&encoded[0], encoded.size(), sig, sig_len); - } - } - } diff --git a/src/lib/pubkey/pubkey.h b/src/lib/pubkey/pubkey.h index ffb00979d..54c55c597 100644 --- a/src/lib/pubkey/pubkey.h +++ b/src/lib/pubkey/pubkey.h @@ -24,14 +24,6 @@ namespace Botan { enum Signature_Format { IEEE_1363, DER_SEQUENCE }; /** -* Enum marking if protection against fault attacks should be used -*/ -enum Fault_Protection { - ENABLE_FAULT_PROTECTION, - DISABLE_FAULT_PROTECTION -}; - -/** * Public Key Encryptor */ class BOTAN_DLL PK_Encryptor @@ -136,7 +128,11 @@ class BOTAN_DLL PK_Signer * @return signature */ std::vector<byte> sign_message(const byte in[], size_t length, - RandomNumberGenerator& rng); + RandomNumberGenerator& rng) + { + this->update(in, length); + return this->signature(rng); + } /** * Sign a message. @@ -191,19 +187,12 @@ class BOTAN_DLL PK_Signer * @param emsa the EMSA to use * An example would be "EMSA1(SHA-224)". * @param format the signature format to use - * @param prot says if fault protection should be enabled */ PK_Signer(const Private_Key& key, const std::string& emsa, - Signature_Format format = IEEE_1363, - Fault_Protection prot = ENABLE_FAULT_PROTECTION); + Signature_Format format = IEEE_1363); private: - bool self_test_signature(const std::vector<byte>& msg, - const std::vector<byte>& sig) const; - std::unique_ptr<PK_Ops::Signature> m_op; - std::unique_ptr<PK_Ops::Verification> m_verify_op; - std::unique_ptr<EMSA> m_emsa; Signature_Format m_sig_format; }; @@ -299,11 +288,7 @@ class BOTAN_DLL PK_Verifier const std::string& emsa, Signature_Format format = IEEE_1363); private: - bool validate_signature(const secure_vector<byte>& msg, - const byte sig[], size_t sig_len); - std::unique_ptr<PK_Ops::Verification> m_op; - std::unique_ptr<EMSA> m_emsa; Signature_Format m_sig_format; }; diff --git a/src/lib/pubkey/rsa/rsa.cpp b/src/lib/pubkey/rsa/rsa.cpp index 464055cd7..13425a46f 100644 --- a/src/lib/pubkey/rsa/rsa.cpp +++ b/src/lib/pubkey/rsa/rsa.cpp @@ -112,7 +112,7 @@ class RSA_Private_Operation Blinder m_blinder; }; -class RSA_Signature_Operation : public PK_Ops::Signature, +class RSA_Signature_Operation : public PK_Ops::Signature_with_EMSA, private RSA_Private_Operation { public: @@ -120,20 +120,18 @@ class RSA_Signature_Operation : public PK_Ops::Signature, size_t max_input_bits() const override { return get_max_input_bits(); }; - RSA_Signature_Operation(const RSA_PrivateKey& rsa, const std::string&) : + RSA_Signature_Operation(const RSA_PrivateKey& rsa, const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), RSA_Private_Operation(rsa) { } - secure_vector<byte> sign(const byte msg[], size_t msg_len, - RandomNumberGenerator&) override + secure_vector<byte> raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator&) override { - /* We don't check signatures against powermod_e_n here because - PK_Signer checks verification consistency for all signature - algorithms. - */ const BigInt m(msg, msg_len); const BigInt x = blinded_private_op(m); + BOTAN_ASSERT(m == m_powermod_e_n(x), "RSA sign consistency check"); return BigInt::encode_1363(x, n.bytes()); } }; @@ -161,7 +159,6 @@ class RSA_Decryption_Operation : public PK_Ops::Decryption_with_EME, } }; - /** * RSA public (encrypt/verify) operation */ @@ -208,7 +205,7 @@ class RSA_Encryption_Operation : public PK_Ops::Encryption_with_EME, } }; -class RSA_Verify_Operation : public PK_Ops::Verification, +class RSA_Verify_Operation : public PK_Ops::Verification_with_EMSA, private RSA_Public_Operation { public: @@ -216,7 +213,8 @@ class RSA_Verify_Operation : public PK_Ops::Verification, size_t max_input_bits() const override { return get_max_input_bits(); }; - RSA_Verify_Operation(const RSA_PublicKey& rsa, const std::string&) : + RSA_Verify_Operation(const RSA_PublicKey& rsa, const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), RSA_Public_Operation(rsa) { } diff --git a/src/lib/pubkey/rw/rw.cpp b/src/lib/pubkey/rw/rw.cpp index 32ba398b0..b706d6730 100644 --- a/src/lib/pubkey/rw/rw.cpp +++ b/src/lib/pubkey/rw/rw.cpp @@ -67,13 +67,14 @@ namespace { /** * Rabin-Williams Signature Operation */ -class RW_Signature_Operation : public PK_Ops::Signature +class RW_Signature_Operation : public PK_Ops::Signature_with_EMSA { public: typedef RW_PrivateKey Key_Type; RW_Signature_Operation(const RW_PrivateKey& rw, - const std::string&) : + const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), n(rw.get_n()), e(rw.get_e()), q(rw.get_q()), @@ -87,10 +88,10 @@ class RW_Signature_Operation : public PK_Ops::Signature { } - size_t max_input_bits() const { return (n.bits() - 1); } + size_t max_input_bits() const override { return (n.bits() - 1); } - secure_vector<byte> sign(const byte msg[], size_t msg_len, - RandomNumberGenerator& rng); + secure_vector<byte> raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) override; private: const BigInt& n; const BigInt& e; @@ -103,8 +104,8 @@ class RW_Signature_Operation : public PK_Ops::Signature }; secure_vector<byte> -RW_Signature_Operation::sign(const byte msg[], size_t msg_len, - RandomNumberGenerator&) +RW_Signature_Operation::raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator&) { BigInt i(msg, msg_len); @@ -130,12 +131,13 @@ RW_Signature_Operation::sign(const byte msg[], size_t msg_len, /** * Rabin-Williams Verification Operation */ -class RW_Verification_Operation : public PK_Ops::Verification +class RW_Verification_Operation : public PK_Ops::Verification_with_EMSA { public: typedef RW_PublicKey Key_Type; - RW_Verification_Operation(const RW_PublicKey& rw, const std::string&) : + RW_Verification_Operation(const RW_PublicKey& rw, const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), n(rw.get_n()), powermod_e_n(rw.get_e(), rw.get_n()) {} |