diff options
author | lloyd <[email protected]> | 2014-01-01 21:20:55 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2014-01-01 21:20:55 +0000 |
commit | 197dc467dec28a04c3b2f30da7cef122dfbb13e9 (patch) | |
tree | cdbd3ddaec051c72f0a757db461973d90c37b97a /lib/engine | |
parent | 62faac373c07cfe10bc8c309e89ebdd30d8e5eaa (diff) |
Shuffle things around. Add NIST X.509 test to build.
Diffstat (limited to 'lib/engine')
41 files changed, 3861 insertions, 0 deletions
diff --git a/lib/engine/aes_isa_eng/aes_isa_engine.cpp b/lib/engine/aes_isa_eng/aes_isa_engine.cpp new file mode 100644 index 000000000..956a1ce38 --- /dev/null +++ b/lib/engine/aes_isa_eng/aes_isa_engine.cpp @@ -0,0 +1,36 @@ +/* +* Engine for AES instructions +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/aes_isa_engine.h> +#include <botan/cpuid.h> + +#if defined(BOTAN_HAS_AES_NI) + #include <botan/aes_ni.h> +#endif + +namespace Botan { + +BlockCipher* +AES_ISA_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + if(request.algo_name() == "AES-128") + return new AES_128_NI; + if(request.algo_name() == "AES-192") + return new AES_192_NI; + if(request.algo_name() == "AES-256") + return new AES_256_NI; + } +#endif + + return nullptr; + } + +} diff --git a/lib/engine/aes_isa_eng/aes_isa_engine.h b/lib/engine/aes_isa_eng/aes_isa_engine.h new file mode 100644 index 000000000..3c4d3e936 --- /dev/null +++ b/lib/engine/aes_isa_eng/aes_isa_engine.h @@ -0,0 +1,30 @@ +/* +* Engine for AES instructions +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AES_ISA_ENGINE_H__ +#define BOTAN_AES_ISA_ENGINE_H__ + +#include <botan/engine.h> + +namespace Botan { + +/** +* Engine for implementations that hook into CPU-specific +* AES implementations (eg AES-NI, VIA C7, or AMD Geode) +*/ +class AES_ISA_Engine : public Engine + { + public: + std::string provider_name() const { return "aes_isa"; } + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const; + }; + +} + +#endif diff --git a/lib/engine/aes_isa_eng/info.txt b/lib/engine/aes_isa_eng/info.txt new file mode 100644 index 000000000..4284e75bd --- /dev/null +++ b/lib/engine/aes_isa_eng/info.txt @@ -0,0 +1,11 @@ +define ENGINE_AES_ISA 20131128 + +load_on dep + +<source> +aes_isa_engine.cpp +</source> + +<header:internal> +aes_isa_engine.h +</header:internal> diff --git a/lib/engine/asm_engine/asm_engine.cpp b/lib/engine/asm_engine/asm_engine.cpp new file mode 100644 index 000000000..a43a3302d --- /dev/null +++ b/lib/engine/asm_engine/asm_engine.cpp @@ -0,0 +1,72 @@ +/* +* Assembly Implementation Engine +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/asm_engine.h> + +#if defined(BOTAN_HAS_SERPENT_X86_32) + #include <botan/serp_x86_32.h> +#endif + +#if defined(BOTAN_HAS_MD4_X86_32) + #include <botan/md4_x86_32.h> +#endif + +#if defined(BOTAN_HAS_MD5_X86_32) + #include <botan/md5_x86_32.h> +#endif + +#if defined(BOTAN_HAS_SHA1_X86_64) + #include <botan/sha1_x86_64.h> +#endif + +#if defined(BOTAN_HAS_SHA1_X86_32) + #include <botan/sha1_x86_32.h> +#endif + +namespace Botan { + +BlockCipher* +Assembler_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { + if(request.algo_name() == "Serpent") + { +#if defined(BOTAN_HAS_SERPENT_X86_32) + return new Serpent_X86_32; +#endif + } + + return nullptr; + } + +HashFunction* +Assembler_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_MD4_X86_32) + if(request.algo_name() == "MD4") + return new MD4_X86_32; +#endif + +#if defined(BOTAN_HAS_MD5_X86_32) + if(request.algo_name() == "MD5") + return new MD5_X86_32; +#endif + + if(request.algo_name() == "SHA-160") + { +#if defined(BOTAN_HAS_SHA1_X86_64) + return new SHA_160_X86_64; +#elif defined(BOTAN_HAS_SHA1_X86_32) + return new SHA_160_X86_32; +#endif + } + + return nullptr; + } + +} diff --git a/lib/engine/asm_engine/asm_engine.h b/lib/engine/asm_engine/asm_engine.h new file mode 100644 index 000000000..40fe5342f --- /dev/null +++ b/lib/engine/asm_engine/asm_engine.h @@ -0,0 +1,32 @@ +/* +* Assembly Implementation Engine +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X86_32_ASM_ENGINE_H__ +#define BOTAN_X86_32_ASM_ENGINE_H__ + +#include <botan/engine.h> + +namespace Botan { + +/** +* Engine for x86-32 specific implementations +*/ +class Assembler_Engine : public Engine + { + public: + std::string provider_name() const { return "asm"; } + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const; + + HashFunction* find_hash(const SCAN_Name& request, + Algorithm_Factory&) const; + }; + +} + +#endif diff --git a/lib/engine/asm_engine/info.txt b/lib/engine/asm_engine/info.txt new file mode 100644 index 000000000..185656e3d --- /dev/null +++ b/lib/engine/asm_engine/info.txt @@ -0,0 +1,11 @@ +define ENGINE_ASSEMBLER 20131128 + +load_on dep + +<source> +asm_engine.cpp +</source> + +<header:internal> +asm_engine.h +</header:internal> diff --git a/lib/engine/core_engine/core_engine.h b/lib/engine/core_engine/core_engine.h new file mode 100644 index 000000000..ca660d21b --- /dev/null +++ b/lib/engine/core_engine/core_engine.h @@ -0,0 +1,71 @@ +/* +* Core Engine +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CORE_ENGINE_H__ +#define BOTAN_CORE_ENGINE_H__ + +#include <botan/engine.h> + +namespace Botan { + +/** +* Core Engine +*/ +class Core_Engine : public Engine + { + public: + std::string provider_name() const override { return "core"; } + + PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Verification* get_verify_op(const Public_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Encryption* get_encryption_op(const Public_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Decryption* get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + Modular_Exponentiator* mod_exp(const BigInt& n, + Power_Mod::Usage_Hints) const override; + + Keyed_Filter* get_cipher(const std::string&, Cipher_Dir, + Algorithm_Factory&); + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const override; + + StreamCipher* find_stream_cipher(const SCAN_Name&, + Algorithm_Factory&) const override; + + HashFunction* find_hash(const SCAN_Name& request, + Algorithm_Factory&) const override; + + MessageAuthenticationCode* find_mac(const SCAN_Name& request, + Algorithm_Factory&) const override; + + PBKDF* find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override; + }; + +/** +* Create a cipher mode filter object +* @param block_cipher a block cipher object +* @param direction are we encrypting or decrypting? +* @param mode the name of the cipher mode to use +* @param padding the mode padding to use (only used for ECB, CBC) +*/ +Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher, + Cipher_Dir direction, + const std::string& mode, + const std::string& padding); + +} + +#endif diff --git a/lib/engine/core_engine/core_modes.cpp b/lib/engine/core_engine/core_modes.cpp new file mode 100644 index 000000000..6524d9c16 --- /dev/null +++ b/lib/engine/core_engine/core_modes.cpp @@ -0,0 +1,279 @@ +/* +* Core Engine +* (C) 1999-2007,2011,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/core_engine.h> +#include <botan/parsing.h> +#include <botan/filters.h> +#include <botan/algo_factory.h> +#include <botan/mode_pad.h> +#include <memory> + +#if defined(BOTAN_HAS_MODE_CFB) + #include <botan/cfb.h> +#endif + +#if defined(BOTAN_HAS_MODE_ECB) + #include <botan/ecb.h> +#endif + +#if defined(BOTAN_HAS_MODE_CBC) + #include <botan/cbc.h> +#endif + +#if defined(BOTAN_HAS_MODE_XTS) + #include <botan/xts.h> +#endif + +#if defined(BOTAN_HAS_OFB) + #include <botan/ofb.h> +#endif + +#if defined(BOTAN_HAS_CTR_BE) + #include <botan/ctr.h> +#endif + +#if defined(BOTAN_HAS_AEAD_FILTER) + +#include <botan/aead_filt.h> + +#if defined(BOTAN_HAS_AEAD_CCM) + #include <botan/ccm.h> +#endif + +#if defined(BOTAN_HAS_AEAD_EAX) + #include <botan/eax.h> +#endif + +#if defined(BOTAN_HAS_AEAD_OCB) + #include <botan/ocb.h> +#endif + +#if defined(BOTAN_HAS_AEAD_GCM) + #include <botan/gcm.h> +#endif + +#endif + +namespace Botan { + +namespace { + +/** +* Get a block cipher padding method by name +*/ +BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec, + const std::string& def_if_empty) + { +#if defined(BOTAN_HAS_CIPHER_MODE_PADDING) + if(algo_spec == "NoPadding" || (algo_spec == "" && def_if_empty == "NoPadding")) + return new Null_Padding; + + if(algo_spec == "PKCS7" || (algo_spec == "" && def_if_empty == "PKCS7")) + return new PKCS7_Padding; + + if(algo_spec == "OneAndZeros") + return new OneAndZeros_Padding; + + if(algo_spec == "X9.23") + return new ANSI_X923_Padding; + +#endif + + throw Algorithm_Not_Found(algo_spec); + } + +} + +Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher, + Cipher_Dir direction, + const std::string& mode, + const std::string& padding) + { +#if defined(BOTAN_HAS_OFB) + if(mode == "OFB") + return new StreamCipher_Filter(new OFB(block_cipher->clone())); +#endif + +#if defined(BOTAN_HAS_CTR_BE) + if(mode == "CTR-BE") + return new StreamCipher_Filter(new CTR_BE(block_cipher->clone())); +#endif + +#if defined(BOTAN_HAS_MODE_ECB) + if(mode == "ECB" || mode == "") + { + if(direction == ENCRYPTION) + return new Transformation_Filter( + new ECB_Encryption(block_cipher->clone(), get_bc_pad(padding, "NoPadding"))); + else + return new Transformation_Filter( + new ECB_Decryption(block_cipher->clone(), get_bc_pad(padding, "NoPadding"))); + } +#endif + + if(mode == "CBC") + { +#if defined(BOTAN_HAS_MODE_CBC) + if(padding == "CTS") + { + if(direction == ENCRYPTION) + return new Transformation_Filter(new CTS_Encryption(block_cipher->clone())); + else + return new Transformation_Filter(new CTS_Decryption(block_cipher->clone())); + } + + if(direction == ENCRYPTION) + return new Transformation_Filter( + new CBC_Encryption(block_cipher->clone(), get_bc_pad(padding, "PKCS7"))); + else + return new Transformation_Filter( + new CBC_Decryption(block_cipher->clone(), get_bc_pad(padding, "PKCS7"))); +#else + return nullptr; +#endif + } + +#if defined(BOTAN_HAS_MODE_XTS) + if(mode == "XTS") + { + if(direction == ENCRYPTION) + return new Transformation_Filter(new XTS_Encryption(block_cipher->clone())); + else + return new Transformation_Filter(new XTS_Decryption(block_cipher->clone())); + } +#endif + + if(mode.find("CFB") != std::string::npos || + mode.find("EAX") != std::string::npos || + mode.find("GCM") != std::string::npos || + mode.find("OCB") != std::string::npos || + mode.find("CCM") != std::string::npos) + { + std::vector<std::string> algo_info = parse_algorithm_name(mode); + const std::string mode_name = algo_info[0]; + + size_t bits = 8 * block_cipher->block_size(); + if(algo_info.size() > 1) + bits = to_u32bit(algo_info[1]); + +#if defined(BOTAN_HAS_MODE_CFB) + if(mode_name == "CFB") + { + if(direction == ENCRYPTION) + return new Transformation_Filter(new CFB_Encryption(block_cipher->clone(), bits)); + else + return new Transformation_Filter(new CFB_Decryption(block_cipher->clone(), bits)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_FILTER) + + if(bits % 8 != 0) + throw std::invalid_argument("AEAD interface does not support non-octet length tags"); + + const size_t tag_size = bits / 8; + +#if defined(BOTAN_HAS_AEAD_CCM) + if(mode_name == "CCM") + { + const size_t L = (algo_info.size() == 3) ? to_u32bit(algo_info[2]) : 3; + if(direction == ENCRYPTION) + return new AEAD_Filter(new CCM_Encryption(block_cipher->clone(), tag_size, L)); + else + return new AEAD_Filter(new CCM_Decryption(block_cipher->clone(), tag_size, L)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_EAX) + if(mode_name == "EAX") + { + if(direction == ENCRYPTION) + return new AEAD_Filter(new EAX_Encryption(block_cipher->clone(), tag_size)); + else + return new AEAD_Filter(new EAX_Decryption(block_cipher->clone(), tag_size)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_OCB) + if(mode_name == "OCB") + { + if(direction == ENCRYPTION) + return new AEAD_Filter(new OCB_Encryption(block_cipher->clone(), tag_size)); + else + return new AEAD_Filter(new OCB_Decryption(block_cipher->clone(), tag_size)); + } +#endif + +#if defined(BOTAN_HAS_AEAD_GCM) + if(mode_name == "GCM") + { + if(direction == ENCRYPTION) + return new AEAD_Filter(new GCM_Encryption(block_cipher->clone(), tag_size)); + else + return new AEAD_Filter(new GCM_Decryption(block_cipher->clone(), tag_size)); + } +#endif + +#endif + } + + return nullptr; + } + +/* +* Get a cipher object +*/ +Keyed_Filter* Core_Engine::get_cipher(const std::string& algo_spec, + Cipher_Dir direction, + Algorithm_Factory& af) + { + std::vector<std::string> algo_parts = split_on(algo_spec, '/'); + if(algo_parts.empty()) + throw Invalid_Algorithm_Name(algo_spec); + + const std::string cipher_name = algo_parts[0]; + + // check if it is a stream cipher first (easy case) + const StreamCipher* stream_cipher = af.prototype_stream_cipher(cipher_name); + if(stream_cipher) + return new StreamCipher_Filter(stream_cipher->clone()); + + const BlockCipher* block_cipher = af.prototype_block_cipher(cipher_name); + if(!block_cipher) + return nullptr; + + if(algo_parts.size() >= 4) + return nullptr; // 4 part mode, not something we know about + + if(algo_parts.size() < 2) + throw Lookup_Error("Cipher specification '" + algo_spec + + "' is missing mode identifier"); + + std::string mode = algo_parts[1]; + + std::string padding; + if(algo_parts.size() == 3) + padding = algo_parts[2]; + else + padding = (mode == "CBC") ? "PKCS7" : "NoPadding"; + + if(mode == "ECB" && padding == "CTS") + return nullptr; + else if((mode != "CBC" && mode != "ECB") && padding != "NoPadding") + throw Invalid_Algorithm_Name(algo_spec); + + Keyed_Filter* filt = get_cipher_mode(block_cipher, direction, mode, padding); + if(filt) + return filt; + + if(padding != "NoPadding") + throw Algorithm_Not_Found(cipher_name + "/" + mode + "/" + padding); + else + throw Algorithm_Not_Found(cipher_name + "/" + mode); + } + +} diff --git a/lib/engine/core_engine/def_pk_ops.cpp b/lib/engine/core_engine/def_pk_ops.cpp new file mode 100644 index 000000000..e99945633 --- /dev/null +++ b/lib/engine/core_engine/def_pk_ops.cpp @@ -0,0 +1,170 @@ +/* +* PK Operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/core_engine.h> + +#if defined(BOTAN_HAS_RSA) + #include <botan/rsa.h> +#endif + +#if defined(BOTAN_HAS_RW) + #include <botan/rw.h> +#endif + +#if defined(BOTAN_HAS_DSA) + #include <botan/dsa.h> +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include <botan/ecdsa.h> +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + #include <botan/elgamal.h> +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + #include <botan/gost_3410.h> +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + #include <botan/nr.h> +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include <botan/dh.h> +#endif + +#if defined(BOTAN_HAS_ECDH) + #include <botan/ecdh.h> +#endif + +namespace Botan { + +PK_Ops::Encryption* +Core_Engine::get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key)) + return new RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(const ElGamal_PublicKey* s = dynamic_cast<const ElGamal_PublicKey*>(&key)) + return new ElGamal_Encryption_Operation(*s); +#endif + + return nullptr; + } + +PK_Ops::Decryption* +Core_Engine::get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key)) + return new RSA_Private_Operation(*s, rng); +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + if(const ElGamal_PrivateKey* s = dynamic_cast<const ElGamal_PrivateKey*>(&key)) + return new ElGamal_Decryption_Operation(*s, rng); +#endif + + return nullptr; + } + +PK_Ops::Key_Agreement* +Core_Engine::get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const + { +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(const DH_PrivateKey* dh = dynamic_cast<const DH_PrivateKey*>(&key)) + return new DH_KA_Operation(*dh, rng); +#endif + +#if defined(BOTAN_HAS_ECDH) + if(const ECDH_PrivateKey* ecdh = dynamic_cast<const ECDH_PrivateKey*>(&key)) + return new ECDH_KA_Operation(*ecdh); +#endif + + return nullptr; + } + +PK_Ops::Signature* +Core_Engine::get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key)) + return new RSA_Private_Operation(*s, rng); +#endif + +#if defined(BOTAN_HAS_RW) + if(const RW_PrivateKey* s = dynamic_cast<const RW_PrivateKey*>(&key)) + return new RW_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PrivateKey* s = dynamic_cast<const DSA_PrivateKey*>(&key)) + return new DSA_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(const ECDSA_PrivateKey* s = dynamic_cast<const ECDSA_PrivateKey*>(&key)) + return new ECDSA_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(const GOST_3410_PrivateKey* s = + dynamic_cast<const GOST_3410_PrivateKey*>(&key)) + return new GOST_3410_Signature_Operation(*s); +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(const NR_PrivateKey* s = dynamic_cast<const NR_PrivateKey*>(&key)) + return new NR_Signature_Operation(*s); +#endif + + return nullptr; + } + +PK_Ops::Verification* +Core_Engine::get_verify_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key)) + return new RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_RW) + if(const RW_PublicKey* s = dynamic_cast<const RW_PublicKey*>(&key)) + return new RW_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PublicKey* s = dynamic_cast<const DSA_PublicKey*>(&key)) + return new DSA_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(const ECDSA_PublicKey* s = dynamic_cast<const ECDSA_PublicKey*>(&key)) + return new ECDSA_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_GOST_34_10_2001) + if(const GOST_3410_PublicKey* s = + dynamic_cast<const GOST_3410_PublicKey*>(&key)) + return new GOST_3410_Verification_Operation(*s); +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(const NR_PublicKey* s = dynamic_cast<const NR_PublicKey*>(&key)) + return new NR_Verification_Operation(*s); +#endif + + return nullptr; + } + +} diff --git a/lib/engine/core_engine/def_powm.cpp b/lib/engine/core_engine/def_powm.cpp new file mode 100644 index 000000000..56a4b6844 --- /dev/null +++ b/lib/engine/core_engine/def_powm.cpp @@ -0,0 +1,24 @@ +/* +* Modular Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/core_engine.h> +#include <botan/internal/def_powm.h> + +namespace Botan { + +/* +* Choose a modular exponentation algorithm +*/ +Modular_Exponentiator* +Core_Engine::mod_exp(const BigInt& n, Power_Mod::Usage_Hints hints) const + { + if(n.is_odd()) + return new Montgomery_Exponentiator(n, hints); + return new Fixed_Window_Exponentiator(n, hints); + } + +} diff --git a/lib/engine/core_engine/info.txt b/lib/engine/core_engine/info.txt new file mode 100644 index 000000000..44843e26a --- /dev/null +++ b/lib/engine/core_engine/info.txt @@ -0,0 +1,24 @@ +define CORE_ENGINE 20131128 + +<header:internal> +core_engine.h +</header:internal> + +<source> +core_modes.cpp +def_pk_ops.cpp +def_powm.cpp +lookup_block.cpp +lookup_hash.cpp +lookup_mac.cpp +lookup_stream.cpp +lookup_pbkdf.cpp +</source> + +<requires> +algo_factory +filters +libstate +mode_pad +numbertheory +</requires> diff --git a/lib/engine/core_engine/lookup_block.cpp b/lib/engine/core_engine/lookup_block.cpp new file mode 100644 index 000000000..0a9c02311 --- /dev/null +++ b/lib/engine/core_engine/lookup_block.cpp @@ -0,0 +1,298 @@ +/* +* Block Cipher Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/core_engine.h> +#include <botan/scan_name.h> +#include <botan/algo_factory.h> + +#if defined(BOTAN_HAS_AES) + #include <botan/aes.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) + #include <botan/cast128.h> + #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_LUBY_RACKOFF) + #include <botan/lubyrack.h> +#endif + +#if defined(BOTAN_HAS_MARS) + #include <botan/mars.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_RC2) + #include <botan/rc2.h> +#endif + +#if defined(BOTAN_HAS_RC5) + #include <botan/rc5.h> +#endif + +#if defined(BOTAN_HAS_RC6) + #include <botan/rc6.h> +#endif + +#if defined(BOTAN_HAS_SAFER) + #include <botan/safer_sk.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_SKIPJACK) + #include <botan/skipjack.h> +#endif + +#if defined(BOTAN_HAS_SQUARE) + #include <botan/square.h> +#endif + +#if defined(BOTAN_HAS_TEA) + #include <botan/tea.h> +#endif + +#if defined(BOTAN_HAS_TWOFISH) + #include <botan/twofish.h> +#endif + +#if defined(BOTAN_HAS_THREEFISH_512) + #include <botan/threefish.h> +#endif + +#if defined(BOTAN_HAS_XTEA) + #include <botan/xtea.h> +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +BlockCipher* Core_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory& af) const + { + +#if defined(BOTAN_HAS_AES) + if(request.algo_name() == "AES-128") + return new AES_128; + if(request.algo_name() == "AES-192") + return new AES_192; + if(request.algo_name() == "AES-256") + return new AES_256; +#endif + +#if defined(BOTAN_HAS_BLOWFISH) + if(request.algo_name() == "Blowfish") + return new Blowfish; +#endif + +#if defined(BOTAN_HAS_CAMELLIA) + if(request.algo_name() == "Camellia-128") + return new Camellia_128; + if(request.algo_name() == "Camellia-192") + return new Camellia_192; + if(request.algo_name() == "Camellia-256") + return new Camellia_256; +#endif + +#if defined(BOTAN_HAS_CAST) + if(request.algo_name() == "CAST-128") + return new CAST_128; + if(request.algo_name() == "CAST-256") + return new CAST_256; +#endif + +#if defined(BOTAN_HAS_DES) + if(request.algo_name() == "DES") + return new DES; + if(request.algo_name() == "DESX") + return new DESX; + if(request.algo_name() == "TripleDES") + return new TripleDES; +#endif + +#if defined(BOTAN_HAS_GOST_28147_89) + if(request.algo_name() == "GOST-28147-89") + return new GOST_28147_89(request.arg(0, "R3411_94_TestParam")); +#endif + +#if defined(BOTAN_HAS_IDEA) + if(request.algo_name() == "IDEA") + return new IDEA; +#endif + +#if defined(BOTAN_HAS_KASUMI) + if(request.algo_name() == "KASUMI") + return new KASUMI; +#endif + +#if defined(BOTAN_HAS_MARS) + if(request.algo_name() == "MARS") + return new MARS; +#endif + +#if defined(BOTAN_HAS_MISTY1) + if(request.algo_name() == "MISTY1") + return new MISTY1(request.arg_as_integer(0, 8)); +#endif + +#if defined(BOTAN_HAS_NOEKEON) + if(request.algo_name() == "Noekeon") + return new Noekeon; +#endif + +#if defined(BOTAN_HAS_RC2) + if(request.algo_name() == "RC2") + return new RC2; +#endif + +#if defined(BOTAN_HAS_RC5) + if(request.algo_name() == "RC5") + return new RC5(request.arg_as_integer(0, 12)); +#endif + +#if defined(BOTAN_HAS_RC6) + if(request.algo_name() == "RC6") + return new RC6; +#endif + +#if defined(BOTAN_HAS_SAFER) + if(request.algo_name() == "SAFER-SK") + return new SAFER_SK(request.arg_as_integer(0, 10)); +#endif + +#if defined(BOTAN_HAS_SEED) + if(request.algo_name() == "SEED") + return new SEED; +#endif + +#if defined(BOTAN_HAS_SERPENT) + if(request.algo_name() == "Serpent") + return new Serpent; +#endif + +#if defined(BOTAN_HAS_SKIPJACK) + if(request.algo_name() == "Skipjack") + return new Skipjack; +#endif + +#if defined(BOTAN_HAS_SQUARE) + if(request.algo_name() == "Square") + return new Square; +#endif + +#if defined(BOTAN_HAS_TEA) + if(request.algo_name() == "TEA") + return new TEA; +#endif + +#if defined(BOTAN_HAS_TWOFISH) + if(request.algo_name() == "Twofish") + return new Twofish; +#endif + +#if defined(BOTAN_HAS_TWOFISH) + if(request.algo_name() == "Threefish-512") + return new Threefish_512; +#endif + +#if defined(BOTAN_HAS_XTEA) + if(request.algo_name() == "XTEA") + return new XTEA; +#endif + +#if defined(BOTAN_HAS_LUBY_RACKOFF) + if(request.algo_name() == "Luby-Rackoff" && request.arg_count() == 1) + { + const HashFunction* hash = af.prototype_hash_function(request.arg(0)); + + if(hash) + return new LubyRackoff(hash->clone()); + } +#endif + +#if defined(BOTAN_HAS_CASCADE) + if(request.algo_name() == "Cascade" && request.arg_count() == 2) + { + const BlockCipher* c1 = af.prototype_block_cipher(request.arg(0)); + const BlockCipher* c2 = af.prototype_block_cipher(request.arg(1)); + + if(c1 && c2) + return new Cascade_Cipher(c1->clone(), c2->clone()); + } +#endif + +#if defined(BOTAN_HAS_LION) + if(request.algo_name() == "Lion" && request.arg_count_between(2, 3)) + { + const size_t block_size = request.arg_as_integer(2, 1024); + + const HashFunction* hash = + af.prototype_hash_function(request.arg(0)); + + const StreamCipher* stream_cipher = + af.prototype_stream_cipher(request.arg(1)); + + if(!hash || !stream_cipher) + return nullptr; + + return new Lion(hash->clone(), stream_cipher->clone(), block_size); + } +#endif + + return nullptr; + } + +} diff --git a/lib/engine/core_engine/lookup_hash.cpp b/lib/engine/core_engine/lookup_hash.cpp new file mode 100644 index 000000000..7a9a0148d --- /dev/null +++ b/lib/engine/core_engine/lookup_hash.cpp @@ -0,0 +1,238 @@ +/* +* Hash Algorithms Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/core_engine.h> +#include <botan/scan_name.h> +#include <botan/algo_factory.h> +#include <memory> + +#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_BMW_512) + #include <botan/bmw_512.h> +#endif + +#if defined(BOTAN_HAS_GOST_34_11) + #include <botan/gost_3411.h> +#endif + +#if defined(BOTAN_HAS_HAS_160) + #include <botan/has160.h> +#endif + +#if defined(BOTAN_HAS_KECCAK) + #include <botan/keccak.h> +#endif + +#if defined(BOTAN_HAS_MD2) + #include <botan/md2.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_128) + #include <botan/rmd128.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_SKEIN_512) + #include <botan/skein_512.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 + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +HashFunction* Core_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory& af) const + { +#if defined(BOTAN_HAS_ADLER32) + if(request.algo_name() == "Adler32") + return new Adler32; +#endif + +#if defined(BOTAN_HAS_CRC24) + if(request.algo_name() == "CRC24") + return new CRC24; +#endif + +#if defined(BOTAN_HAS_CRC32) + if(request.algo_name() == "CRC32") + return new CRC32; +#endif + +#if defined(BOTAN_HAS_BMW_512) + if(request.algo_name() == "BMW-512") + return new BMW_512; +#endif + +#if defined(BOTAN_HAS_GOST_34_11) + if(request.algo_name() == "GOST-R-34.11-94") + return new GOST_34_11; +#endif + +#if defined(BOTAN_HAS_HAS_160) + if(request.algo_name() == "HAS-160") + return new HAS_160; +#endif + +#if defined(BOTAN_HAS_KECCAK) + if(request.algo_name() == "Keccak-1600") + return new Keccak_1600(request.arg_as_integer(0, 512)); +#endif + +#if defined(BOTAN_HAS_MD2) + if(request.algo_name() == "MD2") + return new MD2; +#endif + +#if defined(BOTAN_HAS_MD4) + if(request.algo_name() == "MD4") + return new MD4; +#endif + +#if defined(BOTAN_HAS_MD5) + if(request.algo_name() == "MD5") + return new MD5; +#endif + +#if defined(BOTAN_HAS_RIPEMD_128) + if(request.algo_name() == "RIPEMD-128") + return new RIPEMD_128; +#endif + +#if defined(BOTAN_HAS_RIPEMD_160) + if(request.algo_name() == "RIPEMD-160") + return new RIPEMD_160; +#endif + +#if defined(BOTAN_HAS_SHA1) + if(request.algo_name() == "SHA-160") + return new SHA_160; +#endif + +#if defined(BOTAN_HAS_SHA2_32) + if(request.algo_name() == "SHA-224") + return new SHA_224; + if(request.algo_name() == "SHA-256") + return new SHA_256; +#endif + +#if defined(BOTAN_HAS_SHA2_64) + if(request.algo_name() == "SHA-384") + return new SHA_384; + if(request.algo_name() == "SHA-512") + return new SHA_512; +#endif + +#if defined(BOTAN_HAS_TIGER) + if(request.algo_name() == "Tiger") + return new Tiger(request.arg_as_integer(0, 24), // hash output + request.arg_as_integer(1, 3)); // # passes +#endif + +#if defined(BOTAN_HAS_SKEIN_512) + if(request.algo_name() == "Skein-512") + return new Skein_512(request.arg_as_integer(0, 512), + request.arg(1, "")); +#endif + +#if defined(BOTAN_HAS_WHIRLPOOL) + if(request.algo_name() == "Whirlpool") + return new Whirlpool; +#endif + +#if defined(BOTAN_HAS_COMB4P) + if(request.algo_name() == "Comb4P" && request.arg_count() == 2) + { + const HashFunction* h1 = af.prototype_hash_function(request.arg(0)); + const HashFunction* h2 = af.prototype_hash_function(request.arg(1)); + + if(h1 && h2) + return new Comb4P(h1->clone(), h2->clone()); + } +#endif + +#if defined(BOTAN_HAS_PARALLEL_HASH) + + if(request.algo_name() == "Parallel") + { + std::vector<const HashFunction*> hash_prototypes; + + /* First pass, just get the prototypes (no memory allocation). Then + if all were found, replace each prototype with a newly created clone + */ + for(size_t i = 0; i != request.arg_count(); ++i) + { + const HashFunction* hash = af.prototype_hash_function(request.arg(i)); + if(!hash) + return nullptr; + + hash_prototypes.push_back(hash); + } + + std::vector<HashFunction*> hashes; + for(size_t i = 0; i != hash_prototypes.size(); ++i) + hashes.push_back(hash_prototypes[i]->clone()); + + return new Parallel(hashes); + } + +#endif + + return nullptr; + } + +} diff --git a/lib/engine/core_engine/lookup_mac.cpp b/lib/engine/core_engine/lookup_mac.cpp new file mode 100644 index 000000000..32275b559 --- /dev/null +++ b/lib/engine/core_engine/lookup_mac.cpp @@ -0,0 +1,70 @@ +/* +* MAC Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/core_engine.h> +#include <botan/scan_name.h> +#include <botan/algo_factory.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_HMAC) + #include <botan/hmac.h> +#endif + +#if defined(BOTAN_HAS_SSL3_MAC) + #include <botan/ssl3_mac.h> +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + #include <botan/x919_mac.h> +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +MessageAuthenticationCode* +Core_Engine::find_mac(const SCAN_Name& request, + Algorithm_Factory& af) const + { + +#if defined(BOTAN_HAS_CBC_MAC) + if(request.algo_name() == "CBC-MAC" && request.arg_count() == 1) + return new CBC_MAC(af.make_block_cipher(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_CMAC) + if(request.algo_name() == "CMAC" && request.arg_count() == 1) + return new CMAC(af.make_block_cipher(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_HMAC) + if(request.algo_name() == "HMAC" && request.arg_count() == 1) + return new HMAC(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_SSL3_MAC) + if(request.algo_name() == "SSL3-MAC" && request.arg_count() == 1) + return new SSL3_MAC(af.make_hash_function(request.arg(0))); +#endif + +#if defined(BOTAN_HAS_ANSI_X919_MAC) + if(request.algo_name() == "X9.19-MAC" && request.arg_count() == 0) + return new ANSI_X919_MAC(af.make_block_cipher("DES")); +#endif + + return nullptr; + } + +} diff --git a/lib/engine/core_engine/lookup_pbkdf.cpp b/lib/engine/core_engine/lookup_pbkdf.cpp new file mode 100644 index 000000000..bfd2c8bc2 --- /dev/null +++ b/lib/engine/core_engine/lookup_pbkdf.cpp @@ -0,0 +1,43 @@ +/* +* PBKDF Lookup +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/core_engine.h> +#include <botan/scan_name.h> +#include <botan/algo_factory.h> + +#if defined(BOTAN_HAS_PBKDF1) + #include <botan/pbkdf1.h> +#endif + +#if defined(BOTAN_HAS_PBKDF2) + #include <botan/pbkdf2.h> +#endif + +namespace Botan { + +PBKDF* Core_Engine::find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const + { +#if defined(BOTAN_HAS_PBKDF1) + if(algo_spec.algo_name() == "PBKDF1" && algo_spec.arg_count() == 1) + return new PKCS5_PBKDF1(af.make_hash_function(algo_spec.arg(0))); +#endif + +#if defined(BOTAN_HAS_PBKDF2) + if(algo_spec.algo_name() == "PBKDF2" && algo_spec.arg_count() == 1) + { + if(const MessageAuthenticationCode* mac_proto = af.prototype_mac(algo_spec.arg(0))) + return new PKCS5_PBKDF2(mac_proto->clone()); + + return new PKCS5_PBKDF2(af.make_mac("HMAC(" + algo_spec.arg(0) + ")")); + } +#endif + + return nullptr; + } + +} diff --git a/lib/engine/core_engine/lookup_stream.cpp b/lib/engine/core_engine/lookup_stream.cpp new file mode 100644 index 000000000..b26bbedcd --- /dev/null +++ b/lib/engine/core_engine/lookup_stream.cpp @@ -0,0 +1,43 @@ +/* +* Stream Cipher Lookup +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/core_engine.h> +#include <botan/scan_name.h> + +#if defined(BOTAN_HAS_RC4) + #include <botan/rc4.h> +#endif + +#if defined(BOTAN_HAS_SALSA20) + #include <botan/salsa20.h> +#endif + +namespace Botan { + +/* +* Look for an algorithm with this name +*/ +StreamCipher* +Core_Engine::find_stream_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_RC4) + if(request.algo_name() == "RC4") + return new RC4(request.arg_as_integer(0, 0)); + if(request.algo_name() == "RC4_drop") + return new RC4(768); +#endif + +#if defined(BOTAN_HAS_SALSA20) + if(request.algo_name() == "Salsa20") + return new Salsa20; +#endif + + return nullptr; + } + +} diff --git a/lib/engine/dyn_engine/dyn_engine.cpp b/lib/engine/dyn_engine/dyn_engine.cpp new file mode 100644 index 000000000..078ec4b83 --- /dev/null +++ b/lib/engine/dyn_engine/dyn_engine.cpp @@ -0,0 +1,63 @@ +/** +* Dynamically Loaded Engine +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/dyn_engine.h> +#include <botan/internal/dyn_load.h> + +namespace Botan { + +namespace { + +extern "C" { + typedef Engine* (*creator_func)(void); + typedef u32bit (*module_version_func)(void); +} + +} + +Dynamically_Loaded_Engine::Dynamically_Loaded_Engine( + const std::string& library_path) : + engine(nullptr) + { + lib = new Dynamically_Loaded_Library(library_path); + + try + { + module_version_func get_version = + lib->resolve<module_version_func>("module_version"); + + const u32bit mod_version = get_version(); + + if(mod_version != 20101003) + throw std::runtime_error("Incompatible version in " + + library_path + " of " + + std::to_string(mod_version)); + + creator_func creator = + lib->resolve<creator_func>("create_engine"); + + engine = creator(); + + if(!engine) + throw std::runtime_error("Creator function in " + + library_path + " failed"); + } + catch(...) + { + delete lib; + lib = nullptr; + throw; + } + } + +Dynamically_Loaded_Engine::~Dynamically_Loaded_Engine() + { + delete engine; + delete lib; + } + +} diff --git a/lib/engine/dyn_engine/dyn_engine.h b/lib/engine/dyn_engine/dyn_engine.h new file mode 100644 index 000000000..39e13ab36 --- /dev/null +++ b/lib/engine/dyn_engine/dyn_engine.h @@ -0,0 +1,115 @@ +/** +* Dynamically Loaded Engine +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DYN_LOADED_ENGINE_H__ +#define BOTAN_DYN_LOADED_ENGINE_H__ + +#include <botan/engine.h> + +namespace Botan { + +/** +* Dynamically_Loaded_Engine just proxies the requests to the underlying +* Engine object, and handles load/unload details +*/ +class BOTAN_DLL Dynamically_Loaded_Engine : public Engine + { + public: + /** + * @param lib_path full pathname to DLL to load + */ + Dynamically_Loaded_Engine(const std::string& lib_path); + + Dynamically_Loaded_Engine(const Dynamically_Loaded_Engine&) = delete; + + Dynamically_Loaded_Engine& operator=(const Dynamically_Loaded_Engine&) = delete; + + ~Dynamically_Loaded_Engine(); + + std::string provider_name() const override { return engine->provider_name(); } + + BlockCipher* find_block_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override + { + return engine->find_block_cipher(algo_spec, af); + } + + StreamCipher* find_stream_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override + { + return engine->find_stream_cipher(algo_spec, af); + } + + HashFunction* find_hash(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override + { + return engine->find_hash(algo_spec, af); + } + + MessageAuthenticationCode* find_mac(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override + { + return engine->find_mac(algo_spec, af); + } + + PBKDF* find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const override + { + return engine->find_pbkdf(algo_spec, af); + } + + Modular_Exponentiator* mod_exp(const BigInt& n, + Power_Mod::Usage_Hints hints) const override + { + return engine->mod_exp(n, hints); + } + + Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir dir, + Algorithm_Factory& af) + { + return engine->get_cipher(algo_spec, dir, af); + } + + PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const override + { + return engine->get_key_agreement_op(key, rng); + } + + PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const override + { + return engine->get_signature_op(key, rng); + } + + PK_Ops::Verification* + get_verify_op(const Public_Key& key, RandomNumberGenerator& rng) const override + { + return engine->get_verify_op(key, rng); + } + + PK_Ops::Encryption* + get_encryption_op(const Public_Key& key, RandomNumberGenerator& rng) const override + { + return engine->get_encryption_op(key, rng); + } + + PK_Ops::Decryption* + get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const override + { + return engine->get_decryption_op(key, rng); + } + + private: + class Dynamically_Loaded_Library* lib; + Engine* engine; + }; + +} + +#endif diff --git a/lib/engine/dyn_engine/info.txt b/lib/engine/dyn_engine/info.txt new file mode 100644 index 000000000..54379f501 --- /dev/null +++ b/lib/engine/dyn_engine/info.txt @@ -0,0 +1,14 @@ +define DYNAMICALLY_LOADED_ENGINE 20131128 + +<header:public> +dyn_engine.h +</header:public> + +<source> +dyn_engine.cpp +</source> + +<requires> +engine +dyn_load +</requires> diff --git a/lib/engine/engine.cpp b/lib/engine/engine.cpp new file mode 100644 index 000000000..a50f1e7b2 --- /dev/null +++ b/lib/engine/engine.cpp @@ -0,0 +1,91 @@ +/* +* Engine +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/engine.h> + +namespace Botan { + +BlockCipher* +Engine::find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const + { + return nullptr; + } + +StreamCipher* +Engine::find_stream_cipher(const SCAN_Name&, + Algorithm_Factory&) const + { + return nullptr; + } + +HashFunction* +Engine::find_hash(const SCAN_Name&, + Algorithm_Factory&) const + { + return nullptr; + } + +MessageAuthenticationCode* +Engine::find_mac(const SCAN_Name&, + Algorithm_Factory&) const + { + return nullptr; + } + +PBKDF* +Engine::find_pbkdf(const SCAN_Name&, + Algorithm_Factory&) const + { + return nullptr; + } + +Modular_Exponentiator* +Engine::mod_exp(const BigInt&, + Power_Mod::Usage_Hints) const + { + return nullptr; + } + +Keyed_Filter* Engine::get_cipher(const std::string&, + Cipher_Dir, + Algorithm_Factory&) + { + return nullptr; + } + +PK_Ops::Key_Agreement* +Engine::get_key_agreement_op(const Private_Key&, RandomNumberGenerator&) const + { + return nullptr; + } + +PK_Ops::Signature* +Engine::get_signature_op(const Private_Key&, RandomNumberGenerator&) const + { + return nullptr; + } + +PK_Ops::Verification* +Engine::get_verify_op(const Public_Key&, RandomNumberGenerator&) const + { + return nullptr; + } + +PK_Ops::Encryption* +Engine::get_encryption_op(const Public_Key&, RandomNumberGenerator&) const + { + return nullptr; + } + +PK_Ops::Decryption* +Engine::get_decryption_op(const Private_Key&, RandomNumberGenerator&) const + { + return nullptr; + } + +} diff --git a/lib/engine/engine.h b/lib/engine/engine.h new file mode 100644 index 000000000..a03a6e1ec --- /dev/null +++ b/lib/engine/engine.h @@ -0,0 +1,150 @@ +/* +* Engine +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENGINE_H__ +#define BOTAN_ENGINE_H__ + +#include <botan/scan_name.h> +#include <botan/block_cipher.h> +#include <botan/stream_cipher.h> +#include <botan/hash.h> +#include <botan/mac.h> +#include <botan/pbkdf.h> +#include <botan/pow_mod.h> +#include <botan/pk_keys.h> +#include <botan/pk_ops.h> + +namespace Botan { + +class Algorithm_Factory; +class Keyed_Filter; +class RandomNumberGenerator; + +/** +* Base class for all engines. All non-pure virtual functions simply +* return NULL, indicating the algorithm in question is not +* supported. Subclasses can reimplement whichever function(s) +* they want to hook in a particular type. +*/ +class BOTAN_DLL Engine + { + public: + virtual ~Engine() {} + + /** + * @return name of this engine + */ + virtual std::string provider_name() const = 0; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual BlockCipher* + find_block_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual StreamCipher* + find_stream_cipher(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual HashFunction* + find_hash(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual MessageAuthenticationCode* + find_mac(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param algo_spec the algorithm name/specification + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual PBKDF* find_pbkdf(const SCAN_Name& algo_spec, + Algorithm_Factory& af) const; + + /** + * @param n the modulus + * @param hints any use hints + * @return newly allocated object, or NULL + */ + virtual Modular_Exponentiator* + mod_exp(const BigInt& n, + Power_Mod::Usage_Hints hints) const; + + /** + * Return a new cipher object + * @param algo_spec the algorithm name/specification + * @param dir specifies if encryption or decryption is desired + * @param af an algorithm factory object + * @return newly allocated object, or NULL + */ + virtual Keyed_Filter* get_cipher(const std::string& algo_spec, + Cipher_Dir dir, + Algorithm_Factory& af); + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Verification* + get_verify_op(const Public_Key& key, RandomNumberGenerator& rng) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Encryption* + get_encryption_op(const Public_Key& key, RandomNumberGenerator& rng) const; + + /** + * Return a new operator object for this key, if possible + * @param key the key we want an operator for + * @return newly allocated operator object, or NULL + */ + virtual PK_Ops::Decryption* + get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const; + }; + +} + +#endif diff --git a/lib/engine/gnump/gmp_mem.cpp b/lib/engine/gnump/gmp_mem.cpp new file mode 100644 index 000000000..b5a5a303e --- /dev/null +++ b/lib/engine/gnump/gmp_mem.cpp @@ -0,0 +1,83 @@ +/* +* GNU MP Memory Handlers +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/gnump_engine.h> +#include <cstring> +#include <atomic> +#include <gmp.h> + +namespace Botan { + +namespace { + +/* +* For keeping track of existing GMP_Engines and only +* resetting the memory when none are in use. +*/ +std::atomic<size_t> gmp_alloc_refcnt(0); + +/* +* Allocation Function for GNU MP +*/ +void* gmp_malloc(size_t n) + { + // Maintain alignment, mlock goes for sizeof(T) alignment + if(n % 8 == 0) + return secure_allocator<u64bit>().allocate(n / 8); + else if(n % 4 == 0) + return secure_allocator<u32bit>().allocate(n / 4); + else if(n % 2 == 0) + return secure_allocator<u16bit>().allocate(n / 2); + + return secure_allocator<byte>().allocate(n); + } + +/* +* Deallocation Function for GNU MP +*/ +void gmp_free(void* ptr, size_t n) + { + secure_allocator<byte>().deallocate(static_cast<byte*>(ptr), n); + } + +/* +* Reallocation Function for GNU MP +*/ +void* gmp_realloc(void* ptr, size_t old_n, size_t new_n) + { + void* new_buf = gmp_malloc(new_n); + std::memcpy(new_buf, ptr, std::min(old_n, new_n)); + gmp_free(ptr, old_n); + return new_buf; + } + +} + +/* +* GMP_Engine Constructor +*/ +GMP_Engine::GMP_Engine() + { + /* + if(gmp_alloc_refcnt == 0) + mp_set_memory_functions(gmp_malloc, gmp_realloc, gmp_free); + + gmp_alloc_refcnt++; + */ + } + +GMP_Engine::~GMP_Engine() + { + /* + --gmp_alloc_refcnt; + + if(gmp_alloc_refcnt == 0) + mp_set_memory_functions(NULL, NULL, NULL); + */ + } + +} diff --git a/lib/engine/gnump/gmp_powm.cpp b/lib/engine/gnump/gmp_powm.cpp new file mode 100644 index 000000000..70c2b2f5e --- /dev/null +++ b/lib/engine/gnump/gmp_powm.cpp @@ -0,0 +1,53 @@ +/* +* GMP Modular Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/gnump_engine.h> +#include <botan/internal/gmp_wrap.h> + +namespace Botan { + +namespace { + +/* +* GMP Modular Exponentiator +*/ +class GMP_Modular_Exponentiator : public Modular_Exponentiator + { + public: + void set_base(const BigInt& b) { base = b; } + void set_exponent(const BigInt& e) { exp = e; } + BigInt execute() const; + Modular_Exponentiator* copy() const + { return new GMP_Modular_Exponentiator(*this); } + + GMP_Modular_Exponentiator(const BigInt& n) : mod(n) {} + private: + GMP_MPZ base, exp, mod; + }; + +/* +* Compute the result +*/ +BigInt GMP_Modular_Exponentiator::execute() const + { + GMP_MPZ r; + mpz_powm(r.value, base.value, exp.value, mod.value); + return r.to_bigint(); + } + +} + +/* +* Return the GMP-based modular exponentiator +*/ +Modular_Exponentiator* GMP_Engine::mod_exp(const BigInt& n, + Power_Mod::Usage_Hints) const + { + return new GMP_Modular_Exponentiator(n); + } + +} diff --git a/lib/engine/gnump/gmp_wrap.cpp b/lib/engine/gnump/gmp_wrap.cpp new file mode 100644 index 000000000..974593d02 --- /dev/null +++ b/lib/engine/gnump/gmp_wrap.cpp @@ -0,0 +1,101 @@ +/* +* GMP Wrapper +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/gmp_wrap.h> + +#define GNU_MP_VERSION_CODE_FOR(a,b,c) ((a << 16) | (b << 8) | (c)) + +#define GNU_MP_VERSION_CODE \ + GNU_MP_VERSION_CODE_FOR(__GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, \ + __GNU_MP_VERSION_PATCHLEVEL) + +#if GNU_MP_VERSION_CODE < GNU_MP_VERSION_CODE_FOR(4,1,0) + #error Your GNU MP install is too old, upgrade to 4.1 or later +#endif + +namespace Botan { + +/* +* GMP_MPZ Constructor +*/ +GMP_MPZ::GMP_MPZ(const BigInt& in) + { + mpz_init(value); + if(in != 0) + mpz_import(value, in.sig_words(), -1, sizeof(word), 0, 0, in.data()); + } + +/* +* GMP_MPZ Constructor +*/ +GMP_MPZ::GMP_MPZ(const byte in[], size_t length) + { + mpz_init(value); + mpz_import(value, length, 1, 1, 0, 0, in); + } + +/* +* GMP_MPZ Copy Constructor +*/ +GMP_MPZ::GMP_MPZ(const GMP_MPZ& other) + { + mpz_init_set(value, other.value); + } + +/* +* GMP_MPZ Destructor +*/ +GMP_MPZ::~GMP_MPZ() + { + mpz_clear(value); + } + +/* +* GMP_MPZ Assignment Operator +*/ +GMP_MPZ& GMP_MPZ::operator=(const GMP_MPZ& other) + { + mpz_set(value, other.value); + return (*this); + } + +/* +* Export the mpz_t as a bytestring +*/ +void GMP_MPZ::encode(byte out[], size_t length) const + { + size_t dummy = 0; + mpz_export(out + (length - bytes()), &dummy, 1, 1, 0, 0, value); + } + +/* +* Return the number of significant bytes +*/ +size_t GMP_MPZ::bytes() const + { + return ((mpz_sizeinbase(value, 2) + 7) / 8); + } + +/* +* GMP to BigInt Conversions +*/ +BigInt GMP_MPZ::to_bigint() const + { + BigInt out(BigInt::Positive, (bytes() + sizeof(word) - 1) / sizeof(word)); + size_t dummy = 0; + + word* reg = out.mutable_data(); + + mpz_export(reg, &dummy, -1, sizeof(word), 0, 0, value); + + if(mpz_sgn(value) < 0) + out.flip_sign(); + + return out; + } + +} diff --git a/lib/engine/gnump/gmp_wrap.h b/lib/engine/gnump/gmp_wrap.h new file mode 100644 index 000000000..291d65a01 --- /dev/null +++ b/lib/engine/gnump/gmp_wrap.h @@ -0,0 +1,41 @@ +/* +* GMP MPZ Wrapper +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GMP_MPZ_WRAP_H__ +#define BOTAN_GMP_MPZ_WRAP_H__ + +#include <botan/bigint.h> +#include <gmp.h> + +namespace Botan { + +/** +* Lightweight GMP mpz_t wrapper. For internal use only. +*/ +class GMP_MPZ + { + public: + mpz_t value; + + BigInt to_bigint() const; + void encode(byte[], size_t) const; + size_t bytes() const; + + secure_vector<byte> to_bytes() const + { return BigInt::encode_locked(to_bigint()); } + + GMP_MPZ& operator=(const GMP_MPZ&); + + GMP_MPZ(const GMP_MPZ&); + GMP_MPZ(const BigInt& = 0); + GMP_MPZ(const byte[], size_t); + ~GMP_MPZ(); + }; + +} + +#endif diff --git a/lib/engine/gnump/gnump_engine.h b/lib/engine/gnump/gnump_engine.h new file mode 100644 index 000000000..ccc723514 --- /dev/null +++ b/lib/engine/gnump/gnump_engine.h @@ -0,0 +1,44 @@ +/* +* GMP Engine +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENGINE_GMP_H__ +#define BOTAN_ENGINE_GMP_H__ + +#include <botan/engine.h> + +namespace Botan { + +/** +* Engine using GNU MP +*/ +class GMP_Engine : public Engine + { + public: + GMP_Engine(); + ~GMP_Engine(); + + std::string provider_name() const override { return "gmp"; } + + PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator&) const override; + + PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator&) const override; + + PK_Ops::Verification* get_verify_op(const Public_Key& key, RandomNumberGenerator&) const override; + + PK_Ops::Encryption* get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const override; + + PK_Ops::Decryption* get_decryption_op(const Private_Key& key, RandomNumberGenerator&) const override; + + Modular_Exponentiator* mod_exp(const BigInt&, + Power_Mod::Usage_Hints) const override; + }; + +} + +#endif diff --git a/lib/engine/gnump/gnump_pk.cpp b/lib/engine/gnump/gnump_pk.cpp new file mode 100644 index 000000000..29e172d47 --- /dev/null +++ b/lib/engine/gnump/gnump_pk.cpp @@ -0,0 +1,338 @@ +/* +* GnuMP PK operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/gnump_engine.h> +#include <botan/internal/gmp_wrap.h> +#include <gmp.h> + +/* GnuMP 5.0 and later have a side-channel resistent powm */ +#if defined(HAVE_MPZ_POWM_SEC) + #undef mpz_powm + #define mpz_powm mpz_powm_sec +#endif + +#if defined(BOTAN_HAS_RSA) + #include <botan/rsa.h> +#endif + +#if defined(BOTAN_HAS_DSA) + #include <botan/dsa.h> +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include <botan/dh.h> +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) +class GMP_DH_KA_Operation : public PK_Ops::Key_Agreement + { + public: + GMP_DH_KA_Operation(const DH_PrivateKey& dh) : + x(dh.get_x()), p(dh.group_p()) {} + + secure_vector<byte> agree(const byte w[], size_t w_len) + { + GMP_MPZ z(w, w_len); + mpz_powm(z.value, z.value, x.value, p.value); + return z.to_bytes(); + } + + private: + GMP_MPZ x, p; + }; +#endif + +#if defined(BOTAN_HAS_DSA) + +class GMP_DSA_Signature_Operation : public PK_Ops::Signature + { + public: + GMP_DSA_Signature_Operation(const DSA_PrivateKey& dsa) : + x(dsa.get_x()), + p(dsa.group_p()), + q(dsa.group_q()), + g(dsa.group_g()), + q_bits(dsa.group_q().bits()) {} + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return (q_bits + 7) / 8; } + size_t max_input_bits() const { return q_bits; } + + secure_vector<byte> sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const GMP_MPZ x, p, q, g; + size_t q_bits; + }; + +secure_vector<byte> +GMP_DSA_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const size_t q_bytes = (q_bits + 7) / 8; + + rng.add_entropy(msg, msg_len); + + BigInt k_bn; + do + k_bn.randomize(rng, q_bits); + while(k_bn >= q.to_bigint()); + + GMP_MPZ i(msg, msg_len); + GMP_MPZ k(k_bn); + + GMP_MPZ r; + mpz_powm(r.value, g.value, k.value, p.value); + mpz_mod(r.value, r.value, q.value); + + mpz_invert(k.value, k.value, q.value); + + GMP_MPZ s; + mpz_mul(s.value, x.value, r.value); + mpz_add(s.value, s.value, i.value); + mpz_mul(s.value, s.value, k.value); + mpz_mod(s.value, s.value, q.value); + + if(mpz_cmp_ui(r.value, 0) == 0 || mpz_cmp_ui(s.value, 0) == 0) + throw Internal_Error("GMP_DSA_Op::sign: r or s was zero"); + + secure_vector<byte> output(2*q_bytes); + r.encode(&output[0], q_bytes); + s.encode(&output[q_bytes], q_bytes); + return output; + } + +class GMP_DSA_Verification_Operation : public PK_Ops::Verification + { + public: + GMP_DSA_Verification_Operation(const DSA_PublicKey& dsa) : + y(dsa.get_y()), + p(dsa.group_p()), + q(dsa.group_q()), + g(dsa.group_g()), + q_bits(dsa.group_q().bits()) {} + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return (q_bits + 7) / 8; } + size_t max_input_bits() const { return q_bits; } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const GMP_MPZ y, p, q, g; + size_t q_bits; + }; + +bool GMP_DSA_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + const size_t q_bytes = q.bytes(); + + if(sig_len != 2*q_bytes || msg_len > q_bytes) + return false; + + GMP_MPZ r(sig, q_bytes); + GMP_MPZ s(sig + q_bytes, q_bytes); + GMP_MPZ i(msg, msg_len); + + if(mpz_cmp_ui(r.value, 0) <= 0 || mpz_cmp(r.value, q.value) >= 0) + return false; + if(mpz_cmp_ui(s.value, 0) <= 0 || mpz_cmp(s.value, q.value) >= 0) + return false; + + if(mpz_invert(s.value, s.value, q.value) == 0) + return false; + + GMP_MPZ si; + mpz_mul(si.value, s.value, i.value); + mpz_mod(si.value, si.value, q.value); + mpz_powm(si.value, g.value, si.value, p.value); + + GMP_MPZ sr; + mpz_mul(sr.value, s.value, r.value); + mpz_mod(sr.value, sr.value, q.value); + mpz_powm(sr.value, y.value, sr.value, p.value); + + mpz_mul(si.value, si.value, sr.value); + mpz_mod(si.value, si.value, p.value); + mpz_mod(si.value, si.value, q.value); + + if(mpz_cmp(si.value, r.value) == 0) + return true; + return false; + } + +#endif + +#if defined(BOTAN_HAS_RSA) + +class GMP_RSA_Private_Operation : public PK_Ops::Signature, + public PK_Ops::Decryption + { + public: + GMP_RSA_Private_Operation(const RSA_PrivateKey& rsa) : + mod(rsa.get_n()), + p(rsa.get_p()), + q(rsa.get_q()), + d1(rsa.get_d1()), + d2(rsa.get_d2()), + c(rsa.get_c()), + n_bits(rsa.get_n().bits()) + {} + + size_t max_input_bits() const { return (n_bits - 1); } + + secure_vector<byte> sign(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + BigInt x = private_op(m); + return BigInt::encode_1363(x, (n_bits + 7) / 8); + } + + secure_vector<byte> decrypt(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(private_op(m)); + } + + private: + BigInt private_op(const BigInt& m) const; + + GMP_MPZ mod, p, q, d1, d2, c; + size_t n_bits; + }; + +BigInt GMP_RSA_Private_Operation::private_op(const BigInt& m) const + { + GMP_MPZ j1, j2, h(m); + + mpz_powm(j1.value, h.value, d1.value, p.value); + mpz_powm(j2.value, h.value, d2.value, q.value); + mpz_sub(h.value, j1.value, j2.value); + mpz_mul(h.value, h.value, c.value); + mpz_mod(h.value, h.value, p.value); + mpz_mul(h.value, h.value, q.value); + mpz_add(h.value, h.value, j2.value); + return h.to_bigint(); + } + +class GMP_RSA_Public_Operation : public PK_Ops::Verification, + public PK_Ops::Encryption + { + public: + GMP_RSA_Public_Operation(const RSA_PublicKey& rsa) : + n(rsa.get_n()), e(rsa.get_e()), mod(rsa.get_n()) + {} + + size_t max_input_bits() const { return (n.bits() - 1); } + bool with_recovery() const { return true; } + + secure_vector<byte> encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + return BigInt::encode_1363(public_op(m), n.bytes()); + } + + secure_vector<byte> verify_mr(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(public_op(m)); + } + + private: + BigInt public_op(const BigInt& m) const + { + if(m >= n) + throw Invalid_Argument("RSA public op - input is too large"); + + GMP_MPZ m_gmp(m); + mpz_powm(m_gmp.value, m_gmp.value, e.value, mod.value); + return m_gmp.to_bigint(); + } + + const BigInt& n; + const GMP_MPZ e, mod; + }; + +#endif + +} + +PK_Ops::Key_Agreement* +GMP_Engine::get_key_agreement_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(const DH_PrivateKey* dh = dynamic_cast<const DH_PrivateKey*>(&key)) + return new GMP_DH_KA_Operation(*dh); +#endif + + return nullptr; + } + +PK_Ops::Signature* +GMP_Engine::get_signature_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key)) + return new GMP_RSA_Private_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PrivateKey* s = dynamic_cast<const DSA_PrivateKey*>(&key)) + return new GMP_DSA_Signature_Operation(*s); +#endif + + return nullptr; + } + +PK_Ops::Verification* +GMP_Engine::get_verify_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key)) + return new GMP_RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PublicKey* s = dynamic_cast<const DSA_PublicKey*>(&key)) + return new GMP_DSA_Verification_Operation(*s); +#endif + + return nullptr; + } + +PK_Ops::Encryption* +GMP_Engine::get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key)) + return new GMP_RSA_Public_Operation(*s); +#endif + + return nullptr; + } + +PK_Ops::Decryption* +GMP_Engine::get_decryption_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key)) + return new GMP_RSA_Private_Operation(*s); +#endif + + return nullptr; + } + +} diff --git a/lib/engine/gnump/info.txt b/lib/engine/gnump/info.txt new file mode 100644 index 000000000..ad03339e4 --- /dev/null +++ b/lib/engine/gnump/info.txt @@ -0,0 +1,23 @@ +define ENGINE_GNU_MP 20131128 + +load_on request + +<libs> +all -> gmp +</libs> + +<header:internal> +gnump_engine.h +gmp_wrap.h +</header:internal> + +<source> +gmp_mem.cpp +gmp_powm.cpp +gmp_wrap.cpp +gnump_pk.cpp +</source> + +<requires> +bigint +</requires> diff --git a/lib/engine/info.txt b/lib/engine/info.txt new file mode 100644 index 000000000..800a007a1 --- /dev/null +++ b/lib/engine/info.txt @@ -0,0 +1,20 @@ +define ENGINES 20131128 + +<header:public> +engine.h +</header:public> + +<source> +engine.cpp +</source> + +<requires> +block +hash +libstate +mac +numbertheory +pbkdf +pubkey +stream +</requires> diff --git a/lib/engine/openssl/bn_powm.cpp b/lib/engine/openssl/bn_powm.cpp new file mode 100644 index 000000000..ac06fbe77 --- /dev/null +++ b/lib/engine/openssl/bn_powm.cpp @@ -0,0 +1,54 @@ +/* +* OpenSSL Modular Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/openssl_engine.h> +#include <botan/internal/bn_wrap.h> + +namespace Botan { + +namespace { + +/* +* OpenSSL Modular Exponentiator +*/ +class OpenSSL_Modular_Exponentiator : public Modular_Exponentiator + { + public: + void set_base(const BigInt& b) { base = b; } + void set_exponent(const BigInt& e) { exp = e; } + BigInt execute() const; + Modular_Exponentiator* copy() const + { return new OpenSSL_Modular_Exponentiator(*this); } + + OpenSSL_Modular_Exponentiator(const BigInt& n) : mod(n) {} + private: + OSSL_BN base, exp, mod; + OSSL_BN_CTX ctx; + }; + +/* +* Compute the result +*/ +BigInt OpenSSL_Modular_Exponentiator::execute() const + { + OSSL_BN r; + BN_mod_exp(r.ptr(), base.ptr(), exp.ptr(), mod.ptr(), ctx.ptr()); + return r.to_bigint(); + } + +} + +/* +* Return the OpenSSL-based modular exponentiator +*/ +Modular_Exponentiator* OpenSSL_Engine::mod_exp(const BigInt& n, + Power_Mod::Usage_Hints) const + { + return new OpenSSL_Modular_Exponentiator(n); + } + +} diff --git a/lib/engine/openssl/bn_wrap.cpp b/lib/engine/openssl/bn_wrap.cpp new file mode 100644 index 000000000..0a7e42368 --- /dev/null +++ b/lib/engine/openssl/bn_wrap.cpp @@ -0,0 +1,116 @@ +/* +* OpenSSL BN Wrapper +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/bn_wrap.h> + +namespace Botan { + +/* +* OSSL_BN Constructor +*/ +OSSL_BN::OSSL_BN(const BigInt& in) + { + m_bn = BN_new(); + secure_vector<byte> encoding = BigInt::encode_locked(in); + if(in != 0) + BN_bin2bn(&encoding[0], encoding.size(), m_bn); + } + +/* +* OSSL_BN Constructor +*/ +OSSL_BN::OSSL_BN(const byte in[], size_t length) + { + m_bn = BN_new(); + BN_bin2bn(in, length, m_bn); + } + +/* +* OSSL_BN Copy Constructor +*/ +OSSL_BN::OSSL_BN(const OSSL_BN& other) + { + m_bn = BN_dup(other.m_bn); + } + +/* +* OSSL_BN Destructor +*/ +OSSL_BN::~OSSL_BN() + { + BN_clear_free(m_bn); + } + +/* +* OSSL_BN Assignment Operator +*/ +OSSL_BN& OSSL_BN::operator=(const OSSL_BN& other) + { + BN_copy(m_bn, other.m_bn); + return (*this); + } + +/* +* Export the BIGNUM as a bytestring +*/ +void OSSL_BN::encode(byte out[], size_t length) const + { + BN_bn2bin(m_bn, out + (length - bytes())); + } + +/* +* Return the number of significant bytes +*/ +size_t OSSL_BN::bytes() const + { + return BN_num_bytes(m_bn); + } + +/* +* OpenSSL to BigInt Conversions +*/ +BigInt OSSL_BN::to_bigint() const + { + secure_vector<byte> out(bytes()); + BN_bn2bin(m_bn, &out[0]); + return BigInt::decode(out); + } + +/* +* OSSL_BN_CTX Constructor +*/ +OSSL_BN_CTX::OSSL_BN_CTX() + { + m_ctx = BN_CTX_new(); + } + +/* +* OSSL_BN_CTX Copy Constructor +*/ +OSSL_BN_CTX::OSSL_BN_CTX(const OSSL_BN_CTX&) + { + m_ctx = BN_CTX_new(); + } + +/* +* OSSL_BN_CTX Destructor +*/ +OSSL_BN_CTX::~OSSL_BN_CTX() + { + BN_CTX_free(m_ctx); + } + +/* +* OSSL_BN_CTX Assignment Operator +*/ +OSSL_BN_CTX& OSSL_BN_CTX::operator=(const OSSL_BN_CTX&) + { + m_ctx = BN_CTX_new(); + return (*this); + } + +} diff --git a/lib/engine/openssl/bn_wrap.h b/lib/engine/openssl/bn_wrap.h new file mode 100644 index 000000000..12bcec152 --- /dev/null +++ b/lib/engine/openssl/bn_wrap.h @@ -0,0 +1,60 @@ +/* +* OpenSSL BN Wrapper +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OPENSSL_BN_WRAP_H__ +#define BOTAN_OPENSSL_BN_WRAP_H__ + +#include <botan/bigint.h> +#include <openssl/bn.h> + +namespace Botan { + +/** +* Lightweight OpenSSL BN wrapper. For internal use only. +*/ +class OSSL_BN + { + public: + BigInt to_bigint() const; + void encode(byte[], size_t) const; + size_t bytes() const; + + secure_vector<byte> to_bytes() const + { return BigInt::encode_locked(to_bigint()); } + + OSSL_BN& operator=(const OSSL_BN&); + + OSSL_BN(const OSSL_BN&); + OSSL_BN(const BigInt& = 0); + OSSL_BN(const byte[], size_t); + ~OSSL_BN(); + + BIGNUM* ptr() const { return m_bn; } + private: + BIGNUM* m_bn; + }; + +/** +* Lightweight OpenSSL BN_CTX wrapper. For internal use only. +*/ +class OSSL_BN_CTX + { + public: + OSSL_BN_CTX& operator=(const OSSL_BN_CTX&); + + OSSL_BN_CTX(); + OSSL_BN_CTX(const OSSL_BN_CTX&); + ~OSSL_BN_CTX(); + + BN_CTX* ptr() const { return m_ctx; } + private: + BN_CTX* m_ctx; + }; + +} + +#endif diff --git a/lib/engine/openssl/info.txt b/lib/engine/openssl/info.txt new file mode 100644 index 000000000..d500816d5 --- /dev/null +++ b/lib/engine/openssl/info.txt @@ -0,0 +1,25 @@ +define ENGINE_OPENSSL 20131128 + +load_on request + +<libs> +all -> crypto +</libs> + +<header:internal> +openssl_engine.h +bn_wrap.h +</header:internal> + +<source> +bn_powm.cpp +bn_wrap.cpp +ossl_arc4.cpp +ossl_bc.cpp +ossl_md.cpp +ossl_pk.cpp +</source> + +<requires> +bigint +</requires> diff --git a/lib/engine/openssl/openssl_engine.h b/lib/engine/openssl/openssl_engine.h new file mode 100644 index 000000000..90f315c00 --- /dev/null +++ b/lib/engine/openssl/openssl_engine.h @@ -0,0 +1,49 @@ +/* +* OpenSSL Engine +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENGINE_OPENSSL_H__ +#define BOTAN_ENGINE_OPENSSL_H__ + +#include <botan/engine.h> + +namespace Botan { + +/** +* OpenSSL Engine +*/ +class OpenSSL_Engine : public Engine + { + public: + std::string provider_name() const override { return "openssl"; } + + PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Verification* get_verify_op(const Public_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Encryption* get_encryption_op(const Public_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Decryption* get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + Modular_Exponentiator* mod_exp(const BigInt&, + Power_Mod::Usage_Hints) const override; + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const override; + + StreamCipher* find_stream_cipher(const SCAN_Name&, + Algorithm_Factory&) const override; + + HashFunction* find_hash(const SCAN_Name&, Algorithm_Factory&) const override; + }; + +} + +#endif diff --git a/lib/engine/openssl/ossl_arc4.cpp b/lib/engine/openssl/ossl_arc4.cpp new file mode 100644 index 000000000..0eb404af1 --- /dev/null +++ b/lib/engine/openssl/ossl_arc4.cpp @@ -0,0 +1,89 @@ +/* +* OpenSSL RC4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/openssl_engine.h> +#include <botan/parsing.h> +#include <openssl/rc4.h> + +namespace Botan { + +namespace { + +/** +* RC4 as implemented by OpenSSL +*/ +class RC4_OpenSSL : public StreamCipher + { + public: + void clear() { clear_mem(&state, 1); } + + std::string name() const; + StreamCipher* clone() const { return new RC4_OpenSSL(SKIP); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(1, 32); + } + + + RC4_OpenSSL(size_t s = 0) : SKIP(s) { clear(); } + ~RC4_OpenSSL() { clear(); } + private: + void cipher(const byte[], byte[], size_t); + void key_schedule(const byte[], size_t); + + const size_t SKIP; + RC4_KEY state; + }; + +/* +* Return the name of this type +*/ +std::string RC4_OpenSSL::name() const + { + if(SKIP == 0) return "RC4"; + if(SKIP == 256) return "MARK-4"; + else return "RC4_skip(" + std::to_string(SKIP) + ")"; + } + +/* +* RC4 Key Schedule +*/ +void RC4_OpenSSL::key_schedule(const byte key[], size_t length) + { + RC4_set_key(&state, length, key); + byte dummy = 0; + for(size_t i = 0; i != SKIP; ++i) + RC4(&state, 1, &dummy, &dummy); + } + +/* +* RC4 Encryption +*/ +void RC4_OpenSSL::cipher(const byte in[], byte out[], size_t length) + { + RC4(&state, length, in, out); + } + +} + +/** +* Look for an OpenSSL-supported stream cipher (RC4) +*/ +StreamCipher* +OpenSSL_Engine::find_stream_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { + if(request.algo_name() == "RC4") + return new RC4_OpenSSL(request.arg_as_integer(0, 0)); + if(request.algo_name() == "RC4_drop") + return new RC4_OpenSSL(768); + + return 0; + } + +} diff --git a/lib/engine/openssl/ossl_bc.cpp b/lib/engine/openssl/ossl_bc.cpp new file mode 100644 index 000000000..b3b509c36 --- /dev/null +++ b/lib/engine/openssl/ossl_bc.cpp @@ -0,0 +1,248 @@ +/* +* OpenSSL Block Cipher +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/openssl_engine.h> +#include <openssl/evp.h> + +namespace Botan { + +namespace { + +/* +* EVP Block Cipher +*/ +class EVP_BlockCipher : public BlockCipher + { + public: + void clear(); + std::string name() const { return cipher_name; } + BlockCipher* clone() const; + + size_t block_size() const { return block_sz; } + + EVP_BlockCipher(const EVP_CIPHER*, const std::string&); + + EVP_BlockCipher(const EVP_CIPHER*, const std::string&, + size_t, size_t, size_t); + + Key_Length_Specification key_spec() const { return cipher_key_spec; } + + ~EVP_BlockCipher(); + private: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + void key_schedule(const byte[], size_t); + + size_t block_sz; + Key_Length_Specification cipher_key_spec; + std::string cipher_name; + mutable EVP_CIPHER_CTX encrypt, decrypt; + }; + +/* +* EVP Block Cipher Constructor +*/ +EVP_BlockCipher::EVP_BlockCipher(const EVP_CIPHER* algo, + const std::string& algo_name) : + block_sz(EVP_CIPHER_block_size(algo)), + cipher_key_spec(EVP_CIPHER_key_length(algo)), + cipher_name(algo_name) + { + if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE) + throw Invalid_Argument("EVP_BlockCipher: Non-ECB EVP was passed in"); + + EVP_CIPHER_CTX_init(&encrypt); + EVP_CIPHER_CTX_init(&decrypt); + + EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0); + EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0); + + EVP_CIPHER_CTX_set_padding(&encrypt, 0); + EVP_CIPHER_CTX_set_padding(&decrypt, 0); + } + +/* +* EVP Block Cipher Constructor +*/ +EVP_BlockCipher::EVP_BlockCipher(const EVP_CIPHER* algo, + const std::string& algo_name, + size_t key_min, size_t key_max, + size_t key_mod) : + block_sz(EVP_CIPHER_block_size(algo)), + cipher_key_spec(key_min, key_max, key_mod), + cipher_name(algo_name) + { + if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE) + throw Invalid_Argument("EVP_BlockCipher: Non-ECB EVP was passed in"); + + EVP_CIPHER_CTX_init(&encrypt); + EVP_CIPHER_CTX_init(&decrypt); + + EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0); + EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0); + + EVP_CIPHER_CTX_set_padding(&encrypt, 0); + EVP_CIPHER_CTX_set_padding(&decrypt, 0); + } + +/* +* EVP Block Cipher Destructor +*/ +EVP_BlockCipher::~EVP_BlockCipher() + { + EVP_CIPHER_CTX_cleanup(&encrypt); + EVP_CIPHER_CTX_cleanup(&decrypt); + } + +/* +* Encrypt a block +*/ +void EVP_BlockCipher::encrypt_n(const byte in[], byte out[], + size_t blocks) const + { + int out_len = 0; + EVP_EncryptUpdate(&encrypt, out, &out_len, in, blocks * block_sz); + } + +/* +* Decrypt a block +*/ +void EVP_BlockCipher::decrypt_n(const byte in[], byte out[], + size_t blocks) const + { + int out_len = 0; + EVP_DecryptUpdate(&decrypt, out, &out_len, in, blocks * block_sz); + } + +/* +* Set the key +*/ +void EVP_BlockCipher::key_schedule(const byte key[], size_t length) + { + secure_vector<byte> full_key(key, key + length); + + if(cipher_name == "TripleDES" && length == 16) + { + full_key += std::make_pair(key, 8); + } + else + if(EVP_CIPHER_CTX_set_key_length(&encrypt, length) == 0 || + EVP_CIPHER_CTX_set_key_length(&decrypt, length) == 0) + throw Invalid_Argument("EVP_BlockCipher: Bad key length for " + + cipher_name); + + if(cipher_name == "RC2") + { + EVP_CIPHER_CTX_ctrl(&encrypt, EVP_CTRL_SET_RC2_KEY_BITS, length*8, 0); + EVP_CIPHER_CTX_ctrl(&decrypt, EVP_CTRL_SET_RC2_KEY_BITS, length*8, 0); + } + + EVP_EncryptInit_ex(&encrypt, 0, 0, &full_key[0], 0); + EVP_DecryptInit_ex(&decrypt, 0, 0, &full_key[0], 0); + } + +/* +* Return a clone of this object +*/ +BlockCipher* EVP_BlockCipher::clone() const + { + return new EVP_BlockCipher(EVP_CIPHER_CTX_cipher(&encrypt), + cipher_name, + cipher_key_spec.minimum_keylength(), + cipher_key_spec.maximum_keylength(), + cipher_key_spec.keylength_multiple()); + } + +/* +* Clear memory of sensitive data +*/ +void EVP_BlockCipher::clear() + { + const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(&encrypt); + + EVP_CIPHER_CTX_cleanup(&encrypt); + EVP_CIPHER_CTX_cleanup(&decrypt); + EVP_CIPHER_CTX_init(&encrypt); + EVP_CIPHER_CTX_init(&decrypt); + EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0); + EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0); + EVP_CIPHER_CTX_set_padding(&encrypt, 0); + EVP_CIPHER_CTX_set_padding(&decrypt, 0); + } + +} + +/* +* Look for an algorithm with this name +*/ +BlockCipher* +OpenSSL_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#define HANDLE_EVP_CIPHER(NAME, EVP) \ + if(request.algo_name() == NAME && request.arg_count() == 0) \ + return new EVP_BlockCipher(EVP, NAME); + +#define HANDLE_EVP_CIPHER_KEYLEN(NAME, EVP, MIN, MAX, MOD) \ + if(request.algo_name() == NAME && request.arg_count() == 0) \ + return new EVP_BlockCipher(EVP, NAME, MIN, MAX, MOD); + +#if !defined(OPENSSL_NO_AES) + /* + Using OpenSSL's AES causes crashes inside EVP on x86-64 with OpenSSL 0.9.8g + cause is unknown + */ + HANDLE_EVP_CIPHER("AES-128", EVP_aes_128_ecb()); + HANDLE_EVP_CIPHER("AES-192", EVP_aes_192_ecb()); + HANDLE_EVP_CIPHER("AES-256", EVP_aes_256_ecb()); +#endif + +#if !defined(OPENSSL_NO_DES) + HANDLE_EVP_CIPHER("DES", EVP_des_ecb()); + HANDLE_EVP_CIPHER_KEYLEN("TripleDES", EVP_des_ede3_ecb(), 16, 24, 8); +#endif + +#if !defined(OPENSSL_NO_BF) + HANDLE_EVP_CIPHER_KEYLEN("Blowfish", EVP_bf_ecb(), 1, 56, 1); +#endif + +#if !defined(OPENSSL_NO_CAST) + HANDLE_EVP_CIPHER_KEYLEN("CAST-128", EVP_cast5_ecb(), 1, 16, 1); +#endif + +#if !defined(OPENSSL_NO_CAMELLIA) + HANDLE_EVP_CIPHER("Camellia-128", EVP_camellia_128_ecb()); + HANDLE_EVP_CIPHER("Camellia-192", EVP_camellia_192_ecb()); + HANDLE_EVP_CIPHER("Camellia-256", EVP_camellia_256_ecb()); +#endif + +#if !defined(OPENSSL_NO_RC2) + HANDLE_EVP_CIPHER_KEYLEN("RC2", EVP_rc2_ecb(), 1, 32, 1); +#endif + +#if !defined(OPENSSL_NO_RC5) && 0 + if(request.algo_name() == "RC5") + if(request.arg_as_integer(0, 12) == 12) + return new EVP_BlockCipher(EVP_rc5_32_12_16_ecb(), + "RC5(12)", 1, 32, 1); +#endif + +#if !defined(OPENSSL_NO_IDEA) && 0 + HANDLE_EVP_CIPHER("IDEA", EVP_idea_ecb()); +#endif + +#if !defined(OPENSSL_NO_SEED) + HANDLE_EVP_CIPHER("SEED", EVP_seed_ecb()); +#endif + +#undef HANDLE_EVP_CIPHER +#undef HANDLE_EVP_CIPHER_KEYLEN + + return 0; + } + +} diff --git a/lib/engine/openssl/ossl_md.cpp b/lib/engine/openssl/ossl_md.cpp new file mode 100644 index 000000000..e09a68a8e --- /dev/null +++ b/lib/engine/openssl/ossl_md.cpp @@ -0,0 +1,150 @@ +/* +* OpenSSL Hash Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/openssl_engine.h> +#include <openssl/evp.h> + +namespace Botan { + +namespace { + +/* +* EVP Hash Function +*/ +class EVP_HashFunction : public HashFunction + { + public: + void clear(); + std::string name() const { return algo_name; } + HashFunction* clone() const; + + size_t output_length() const + { + return EVP_MD_size(EVP_MD_CTX_md(&md)); + } + + size_t hash_block_size() const + { + return EVP_MD_block_size(EVP_MD_CTX_md(&md)); + } + + EVP_HashFunction(const EVP_MD*, const std::string&); + ~EVP_HashFunction(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + + std::string algo_name; + EVP_MD_CTX md; + }; + +/* +* Update an EVP Hash Calculation +*/ +void EVP_HashFunction::add_data(const byte input[], size_t length) + { + EVP_DigestUpdate(&md, input, length); + } + +/* +* Finalize an EVP Hash Calculation +*/ +void EVP_HashFunction::final_result(byte output[]) + { + EVP_DigestFinal_ex(&md, output, 0); + const EVP_MD* algo = EVP_MD_CTX_md(&md); + EVP_DigestInit_ex(&md, algo, 0); + } + +/* +* Clear memory of sensitive data +*/ +void EVP_HashFunction::clear() + { + const EVP_MD* algo = EVP_MD_CTX_md(&md); + EVP_DigestInit_ex(&md, algo, 0); + } + +/* +* Return a clone of this object +*/ +HashFunction* EVP_HashFunction::clone() const + { + const EVP_MD* algo = EVP_MD_CTX_md(&md); + return new EVP_HashFunction(algo, name()); + } + +/* +* Create an EVP hash function +*/ +EVP_HashFunction::EVP_HashFunction(const EVP_MD* algo, + const std::string& name) : + algo_name(name) + { + EVP_MD_CTX_init(&md); + EVP_DigestInit_ex(&md, algo, 0); + } + +/* +* Destroy an EVP hash function +*/ +EVP_HashFunction::~EVP_HashFunction() + { + EVP_MD_CTX_cleanup(&md); + } + +} + +/* +* Look for an algorithm with this name +*/ +HashFunction* OpenSSL_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if !defined(OPENSSL_NO_SHA) + if(request.algo_name() == "SHA-160") + return new EVP_HashFunction(EVP_sha1(), "SHA-160"); +#endif + +#if !defined(OPENSSL_NO_SHA256) + if(request.algo_name() == "SHA-224") + return new EVP_HashFunction(EVP_sha224(), "SHA-224"); + if(request.algo_name() == "SHA-256") + return new EVP_HashFunction(EVP_sha256(), "SHA-256"); +#endif + +#if !defined(OPENSSL_NO_SHA512) + if(request.algo_name() == "SHA-384") + return new EVP_HashFunction(EVP_sha384(), "SHA-384"); + if(request.algo_name() == "SHA-512") + return new EVP_HashFunction(EVP_sha512(), "SHA-512"); +#endif + +#if !defined(OPENSSL_NO_MD2) + if(request.algo_name() == "MD2") + return new EVP_HashFunction(EVP_md2(), "MD2"); +#endif + +#if !defined(OPENSSL_NO_MD4) + if(request.algo_name() == "MD4") + return new EVP_HashFunction(EVP_md4(), "MD4"); +#endif + +#if !defined(OPENSSL_NO_MD5) + if(request.algo_name() == "MD5") + return new EVP_HashFunction(EVP_md5(), "MD5"); +#endif + +#if !defined(OPENSSL_NO_RIPEMD) + if(request.algo_name() == "RIPEMD-160") + return new EVP_HashFunction(EVP_ripemd160(), "RIPEMD-160"); +#endif + + return 0; + } + +} diff --git a/lib/engine/openssl/ossl_pk.cpp b/lib/engine/openssl/ossl_pk.cpp new file mode 100644 index 000000000..cbe03d7b3 --- /dev/null +++ b/lib/engine/openssl/ossl_pk.cpp @@ -0,0 +1,338 @@ +/* +* OpenSSL PK operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/openssl_engine.h> +#include <botan/internal/bn_wrap.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_ECDSA) + #include <botan/ecdsa.h> + #include <openssl/ecdsa.h> +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include <botan/dh.h> +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) +class OSSL_DH_KA_Operation : public PK_Ops::Key_Agreement + { + public: + OSSL_DH_KA_Operation(const DH_PrivateKey& dh) : + x(dh.get_x()), p(dh.group_p()) {} + + secure_vector<byte> agree(const byte w[], size_t w_len) + { + OSSL_BN i(w, w_len), r; + BN_mod_exp(r.ptr(), i.ptr(), x.ptr(), p.ptr(), ctx.ptr()); + return r.to_bytes(); + } + + private: + const OSSL_BN x, p; + OSSL_BN_CTX ctx; + }; +#endif + +#if defined(BOTAN_HAS_DSA) + +class OSSL_DSA_Signature_Operation : public PK_Ops::Signature + { + public: + OSSL_DSA_Signature_Operation(const DSA_PrivateKey& dsa) : + x(dsa.get_x()), + p(dsa.group_p()), + q(dsa.group_q()), + g(dsa.group_g()), + q_bits(dsa.group_q().bits()) {} + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return (q_bits + 7) / 8; } + size_t max_input_bits() const { return q_bits; } + + secure_vector<byte> sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const OSSL_BN x, p, q, g; + const OSSL_BN_CTX ctx; + size_t q_bits; + }; + +secure_vector<byte> +OSSL_DSA_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const size_t q_bytes = (q_bits + 7) / 8; + + rng.add_entropy(msg, msg_len); + + BigInt k_bn; + do + k_bn.randomize(rng, q_bits); + while(k_bn >= q.to_bigint()); + + OSSL_BN i(msg, msg_len); + OSSL_BN k(k_bn); + + OSSL_BN r; + BN_mod_exp(r.ptr(), g.ptr(), k.ptr(), p.ptr(), ctx.ptr()); + BN_nnmod(r.ptr(), r.ptr(), q.ptr(), ctx.ptr()); + + BN_mod_inverse(k.ptr(), k.ptr(), q.ptr(), ctx.ptr()); + + OSSL_BN s; + BN_mul(s.ptr(), x.ptr(), r.ptr(), ctx.ptr()); + BN_add(s.ptr(), s.ptr(), i.ptr()); + BN_mod_mul(s.ptr(), s.ptr(), k.ptr(), q.ptr(), ctx.ptr()); + + if(BN_is_zero(r.ptr()) || BN_is_zero(s.ptr())) + throw Internal_Error("OpenSSL_DSA_Op::sign: r or s was zero"); + + secure_vector<byte> output(2*q_bytes); + r.encode(&output[0], q_bytes); + s.encode(&output[q_bytes], q_bytes); + return output; + } + +class OSSL_DSA_Verification_Operation : public PK_Ops::Verification + { + public: + OSSL_DSA_Verification_Operation(const DSA_PublicKey& dsa) : + y(dsa.get_y()), + p(dsa.group_p()), + q(dsa.group_q()), + g(dsa.group_g()), + q_bits(dsa.group_q().bits()) {} + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return (q_bits + 7) / 8; } + size_t max_input_bits() const { return q_bits; } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const OSSL_BN y, p, q, g; + const OSSL_BN_CTX ctx; + size_t q_bits; + }; + +bool OSSL_DSA_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + const size_t q_bytes = q.bytes(); + + if(sig_len != 2*q_bytes || msg_len > q_bytes) + return false; + + OSSL_BN r(sig, q_bytes); + OSSL_BN s(sig + q_bytes, q_bytes); + OSSL_BN i(msg, msg_len); + + if(BN_is_zero(r.ptr()) || BN_cmp(r.ptr(), q.ptr()) >= 0) + return false; + if(BN_is_zero(s.ptr()) || BN_cmp(s.ptr(), q.ptr()) >= 0) + return false; + + if(BN_mod_inverse(s.ptr(), s.ptr(), q.ptr(), ctx.ptr()) == 0) + return false; + + OSSL_BN si; + BN_mod_mul(si.ptr(), s.ptr(), i.ptr(), q.ptr(), ctx.ptr()); + BN_mod_exp(si.ptr(), g.ptr(), si.ptr(), p.ptr(), ctx.ptr()); + + OSSL_BN sr; + BN_mod_mul(sr.ptr(), s.ptr(), r.ptr(), q.ptr(), ctx.ptr()); + BN_mod_exp(sr.ptr(), y.ptr(), sr.ptr(), p.ptr(), ctx.ptr()); + + BN_mod_mul(si.ptr(), si.ptr(), sr.ptr(), p.ptr(), ctx.ptr()); + BN_nnmod(si.ptr(), si.ptr(), q.ptr(), ctx.ptr()); + + if(BN_cmp(si.ptr(), r.ptr()) == 0) + return true; + return false; + + return false; + } + +#endif + +#if defined(BOTAN_HAS_RSA) + +class OSSL_RSA_Private_Operation : public PK_Ops::Signature, + public PK_Ops::Decryption + { + public: + OSSL_RSA_Private_Operation(const RSA_PrivateKey& rsa) : + mod(rsa.get_n()), + p(rsa.get_p()), + q(rsa.get_q()), + d1(rsa.get_d1()), + d2(rsa.get_d2()), + c(rsa.get_c()), + n_bits(rsa.get_n().bits()) + {} + + size_t max_input_bits() const { return (n_bits - 1); } + + secure_vector<byte> sign(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + BigInt x = private_op(m); + return BigInt::encode_1363(x, (n_bits + 7) / 8); + } + + secure_vector<byte> decrypt(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(private_op(m)); + } + + private: + BigInt private_op(const BigInt& m) const; + + const OSSL_BN mod, p, q, d1, d2, c; + const OSSL_BN_CTX ctx; + size_t n_bits; + }; + +BigInt OSSL_RSA_Private_Operation::private_op(const BigInt& m) const + { + OSSL_BN j1, j2, h(m); + + BN_mod_exp(j1.ptr(), h.ptr(), d1.ptr(), p.ptr(), ctx.ptr()); + BN_mod_exp(j2.ptr(), h.ptr(), d2.ptr(), q.ptr(), ctx.ptr()); + BN_sub(h.ptr(), j1.ptr(), j2.ptr()); + BN_mod_mul(h.ptr(), h.ptr(), c.ptr(), p.ptr(), ctx.ptr()); + BN_mul(h.ptr(), h.ptr(), q.ptr(), ctx.ptr()); + BN_add(h.ptr(), h.ptr(), j2.ptr()); + return h.to_bigint(); + } + +class OSSL_RSA_Public_Operation : public PK_Ops::Verification, + public PK_Ops::Encryption + { + public: + OSSL_RSA_Public_Operation(const RSA_PublicKey& rsa) : + n(rsa.get_n()), e(rsa.get_e()), mod(rsa.get_n()) + {} + + size_t max_input_bits() const { return (n.bits() - 1); } + bool with_recovery() const { return true; } + + secure_vector<byte> encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + return BigInt::encode_1363(public_op(m), n.bytes()); + } + + secure_vector<byte> verify_mr(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(public_op(m)); + } + + private: + BigInt public_op(const BigInt& m) const + { + if(m >= n) + throw Invalid_Argument("RSA public op - input is too large"); + + OSSL_BN m_bn(m), r; + BN_mod_exp(r.ptr(), m_bn.ptr(), e.ptr(), mod.ptr(), ctx.ptr()); + return r.to_bigint(); + } + + const BigInt& n; + const OSSL_BN e, mod; + const OSSL_BN_CTX ctx; + }; + +#endif + +} + +PK_Ops::Key_Agreement* +OpenSSL_Engine::get_key_agreement_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(const DH_PrivateKey* dh = dynamic_cast<const DH_PrivateKey*>(&key)) + return new OSSL_DH_KA_Operation(*dh); +#endif + + return 0; + } + +PK_Ops::Signature* +OpenSSL_Engine::get_signature_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key)) + return new OSSL_RSA_Private_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PrivateKey* s = dynamic_cast<const DSA_PrivateKey*>(&key)) + return new OSSL_DSA_Signature_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Verification* +OpenSSL_Engine::get_verify_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key)) + return new OSSL_RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PublicKey* s = dynamic_cast<const DSA_PublicKey*>(&key)) + return new OSSL_DSA_Verification_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Encryption* +OpenSSL_Engine::get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key)) + return new OSSL_RSA_Public_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Decryption* +OpenSSL_Engine::get_decryption_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key)) + return new OSSL_RSA_Private_Operation(*s); +#endif + + return 0; + } + +} diff --git a/lib/engine/simd_engine/info.txt b/lib/engine/simd_engine/info.txt new file mode 100644 index 000000000..2063c9dfe --- /dev/null +++ b/lib/engine/simd_engine/info.txt @@ -0,0 +1,15 @@ +define ENGINE_SIMD 20131128 + +load_on dep + +<source> +simd_engine.cpp +</source> + +<header:internal> +simd_engine.h +</header:internal> + +<requires> +simd +</requires> diff --git a/lib/engine/simd_engine/simd_engine.cpp b/lib/engine/simd_engine/simd_engine.cpp new file mode 100644 index 000000000..75463a4b1 --- /dev/null +++ b/lib/engine/simd_engine/simd_engine.cpp @@ -0,0 +1,97 @@ +/* +* SIMD Engine +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/simd_engine.h> +#include <botan/internal/simd_32.h> +#include <botan/cpuid.h> + +#if defined(BOTAN_HAS_AES_SSSE3) + #include <botan/aes_ssse3.h> +#endif + +#if defined(BOTAN_HAS_SERPENT_SIMD) + #include <botan/serp_simd.h> +#endif + +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + #include <botan/threefish_avx2.h> +#endif + +#if defined(BOTAN_HAS_NOEKEON_SIMD) + #include <botan/noekeon_simd.h> +#endif + +#if defined(BOTAN_HAS_XTEA_SIMD) + #include <botan/xtea_simd.h> +#endif + +#if defined(BOTAN_HAS_IDEA_SSE2) + #include <botan/idea_sse2.h> +#endif + +#if defined(BOTAN_HAS_SHA1_SSE2) + #include <botan/sha1_sse2.h> +#endif + +namespace Botan { + +BlockCipher* +SIMD_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_AES_SSSE3) + if(request.algo_name() == "AES-128" && CPUID::has_ssse3()) + return new AES_128_SSSE3; + if(request.algo_name() == "AES-192" && CPUID::has_ssse3()) + return new AES_192_SSSE3; + if(request.algo_name() == "AES-256" && CPUID::has_ssse3()) + return new AES_256_SSSE3; +#endif + +#if defined(BOTAN_HAS_IDEA_SSE2) + if(request.algo_name() == "IDEA" && CPUID::has_sse2()) + return new IDEA_SSE2; +#endif + +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(request.algo_name() == "Noekeon" && SIMD_32::enabled()) + return new Noekeon_SIMD; +#endif + +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + if(request.algo_name() == "Threefish-512" && CPUID::has_avx2()) + return new Threefish_512_AVX2; +#endif + +#if defined(BOTAN_HAS_SERPENT_SIMD) + if(request.algo_name() == "Serpent" && SIMD_32::enabled()) + return new Serpent_SIMD; +#endif + +#if defined(BOTAN_HAS_XTEA_SIMD) + if(request.algo_name() == "XTEA" && SIMD_32::enabled()) + return new XTEA_SIMD; +#endif + + return nullptr; + } + +HashFunction* +SIMD_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if defined(BOTAN_HAS_SHA1_SSE2) + if(request.algo_name() == "SHA-160" && CPUID::has_sse2()) + return new SHA_160_SSE2; +#endif + + BOTAN_UNUSED(request); + + return nullptr; + } + +} diff --git a/lib/engine/simd_engine/simd_engine.h b/lib/engine/simd_engine/simd_engine.h new file mode 100644 index 000000000..66c8886f1 --- /dev/null +++ b/lib/engine/simd_engine/simd_engine.h @@ -0,0 +1,32 @@ +/* +* SIMD Assembly Engine +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SIMD_ENGINE_H__ +#define BOTAN_SIMD_ENGINE_H__ + +#include <botan/engine.h> + +namespace Botan { + +/** +* Engine for implementations that use some kind of SIMD +*/ +class SIMD_Engine : public Engine + { + public: + std::string provider_name() const { return "simd"; } + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const; + + HashFunction* find_hash(const SCAN_Name& request, + Algorithm_Factory&) const; + }; + +} + +#endif |