diff options
author | Jack Lloyd <[email protected]> | 2016-09-17 14:20:03 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-09-17 14:20:03 -0400 |
commit | d734198074d0290631e27d1fb27dce45f0676d58 (patch) | |
tree | faed46aaae836e44e972a4e6d5bdea06b0729034 | |
parent | 272fcf00572432f64085b10132e364740d7eb093 (diff) | |
parent | 2b7f2d52d032ad56526d38e7f65bd966ac59325a (diff) |
Merge GH #623 Merge algorithm impl types
If CPU specific optimizations are available they are always used,
without requiring the application to use the application registry to
ensure they get the optimal type.
See also GH #477
64 files changed, 875 insertions, 805 deletions
diff --git a/doc/news.rst b/doc/news.rst index fce6bfee8..012ad81fa 100644 --- a/doc/news.rst +++ b/doc/news.rst @@ -20,6 +20,22 @@ Version 1.11.32, Not Yet Released * Add a new TLS Callbacks interface. Compatability with previous versions is maintained. The documentation has been updated accordingly. GH #457 and #567 +* How the library presents optimized algorithm implementations has changed. For + example with the algorithm AES-128, previously there were three BlockCipher + classes AES_128, AES_128_SSSE3, and AES_128_NI which used (resp) a table-based + implementation vulnerable to side channels, a constant time version using + SSSE3 SIMD extensions on modern x86, and x86 AES-NI instructions. Using the + correct version at runtime required using `BlockCipher::create`. Now, only the + class AES_128 is presented, and the best available version is always used + based on CPUID checks. The tests have been extended to selectively disable + CPUID bits to ensure all available versions are tested. + + Removes API classes AES_128_NI, AES_192_NI, AES_256_NI, AES_128_SSSE3, + AES_192_SSSE3 AES_256_SSSE3, IDEA_SSE2, Noekeon_SIMD, Serpent_SIMD, + Threefish_512_AVX2, SHA_160_SSE2 + + GH #477 #623 + * The deprecated algorithms Rabin-Williams, Nyberg-Rueppel, MARS, RC2, RC5, RC6, SAFER-SK, TEA, MD2, HAS-160, and RIPEMD-128 have been removed. GH #580 diff --git a/src/lib/block/aes/aes.cpp b/src/lib/block/aes/aes.cpp index 6ec21cb0c..39f5bd0db 100644 --- a/src/lib/block/aes/aes.cpp +++ b/src/lib/block/aes/aes.cpp @@ -416,20 +416,85 @@ void aes_key_schedule(const byte key[], size_t length, copy_mem(DK.data(), XDK.data(), DK.size()); } +const char* aes_provider() + { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return "aesni"; + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return "ssse3"; + } +#endif + + return "base"; + } + } +std::string AES_128::provider() const { return aes_provider(); } +std::string AES_192::provider() const { return aes_provider(); } +std::string AES_256::provider() const { return aes_provider(); } + void AES_128::encrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_encrypt_n(in, out, blocks); + } +#endif + aes_encrypt_n(in, out, blocks, m_EK, m_ME); } void AES_128::decrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_decrypt_n(in, out, blocks); + } +#endif + aes_decrypt_n(in, out, blocks, m_DK, m_MD); } void AES_128::key_schedule(const byte key[], size_t length) { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_key_schedule(key, length); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_key_schedule(key, length); + } +#endif + aes_key_schedule(key, length, m_EK, m_DK, m_ME, m_MD); } @@ -443,16 +508,58 @@ void AES_128::clear() void AES_192::encrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_encrypt_n(in, out, blocks); + } +#endif + aes_encrypt_n(in, out, blocks, m_EK, m_ME); } void AES_192::decrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_decrypt_n(in, out, blocks); + } +#endif + aes_decrypt_n(in, out, blocks, m_DK, m_MD); } void AES_192::key_schedule(const byte key[], size_t length) { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_key_schedule(key, length); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_key_schedule(key, length); + } +#endif + aes_key_schedule(key, length, m_EK, m_DK, m_ME, m_MD); } @@ -466,16 +573,58 @@ void AES_192::clear() void AES_256::encrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_encrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_encrypt_n(in, out, blocks); + } +#endif + aes_encrypt_n(in, out, blocks, m_EK, m_ME); } void AES_256::decrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_decrypt_n(in, out, blocks); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_decrypt_n(in, out, blocks); + } +#endif + aes_decrypt_n(in, out, blocks, m_DK, m_MD); } void AES_256::key_schedule(const byte key[], size_t length) { +#if defined(BOTAN_HAS_AES_NI) + if(CPUID::has_aes_ni()) + { + return aesni_key_schedule(key, length); + } +#endif + +#if defined(BOTAN_HAS_AES_SSSE3) + if(CPUID::has_ssse3()) + { + return ssse3_key_schedule(key, length); + } +#endif + aes_key_schedule(key, length, m_EK, m_DK, m_ME, m_MD); } diff --git a/src/lib/block/aes/aes.h b/src/lib/block/aes/aes.h index a058adcf1..6bd38cada 100644 --- a/src/lib/block/aes/aes.h +++ b/src/lib/block/aes/aes.h @@ -23,11 +23,24 @@ class BOTAN_DLL AES_128 final : public Block_Cipher_Fixed_Params<16, 16> void clear() override; + std::string provider() const override; std::string name() const override { return "AES-128"; } BlockCipher* clone() const override { return new AES_128; } private: void key_schedule(const byte key[], size_t length) override; +#if defined(BOTAN_HAS_AES_SSSE3) + void ssse3_encrypt_n(const byte in[], byte out[], size_t blocks) const; + void ssse3_decrypt_n(const byte in[], byte out[], size_t blocks) const; + void ssse3_key_schedule(const byte key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_NI) + void aesni_encrypt_n(const byte in[], byte out[], size_t blocks) const; + void aesni_decrypt_n(const byte in[], byte out[], size_t blocks) const; + void aesni_key_schedule(const byte key[], size_t length); +#endif + secure_vector<u32bit> m_EK, m_DK; secure_vector<byte> m_ME, m_MD; }; @@ -43,9 +56,22 @@ class BOTAN_DLL AES_192 final : public Block_Cipher_Fixed_Params<16, 24> void clear() override; + std::string provider() const override; std::string name() const override { return "AES-192"; } BlockCipher* clone() const override { return new AES_192; } private: +#if defined(BOTAN_HAS_AES_SSSE3) + void ssse3_encrypt_n(const byte in[], byte out[], size_t blocks) const; + void ssse3_decrypt_n(const byte in[], byte out[], size_t blocks) const; + void ssse3_key_schedule(const byte key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_NI) + void aesni_encrypt_n(const byte in[], byte out[], size_t blocks) const; + void aesni_decrypt_n(const byte in[], byte out[], size_t blocks) const; + void aesni_key_schedule(const byte key[], size_t length); +#endif + void key_schedule(const byte key[], size_t length) override; secure_vector<u32bit> m_EK, m_DK; @@ -63,9 +89,23 @@ class BOTAN_DLL AES_256 final : public Block_Cipher_Fixed_Params<16, 32> void clear() override; + std::string provider() const override; + std::string name() const override { return "AES-256"; } BlockCipher* clone() const override { return new AES_256; } private: +#if defined(BOTAN_HAS_AES_SSSE3) + void ssse3_encrypt_n(const byte in[], byte out[], size_t blocks) const; + void ssse3_decrypt_n(const byte in[], byte out[], size_t blocks) const; + void ssse3_key_schedule(const byte key[], size_t length); +#endif + +#if defined(BOTAN_HAS_AES_NI) + void aesni_encrypt_n(const byte in[], byte out[], size_t blocks) const; + void aesni_decrypt_n(const byte in[], byte out[], size_t blocks) const; + void aesni_key_schedule(const byte key[], size_t length); +#endif + void key_schedule(const byte key[], size_t length) override; secure_vector<u32bit> m_EK, m_DK; diff --git a/src/lib/block/aes_ni/aes_ni.cpp b/src/lib/block/aes_ni/aes_ni.cpp index 51b30881f..3377f9d61 100644 --- a/src/lib/block/aes_ni/aes_ni.cpp +++ b/src/lib/block/aes_ni/aes_ni.cpp @@ -5,9 +5,8 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include <botan/aes_ni.h> +#include <botan/aes.h> #include <botan/loadstor.h> -#include <botan/cpuid.h> #include <wmmintrin.h> namespace Botan { @@ -104,7 +103,7 @@ __m128i aes_256_key_expansion(__m128i key, __m128i key2) /* * AES-128 Encryption */ -void AES_128_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_128::aesni_encrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -180,7 +179,7 @@ void AES_128_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-128 Decryption */ -void AES_128_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_128::aesni_decrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -256,7 +255,7 @@ void AES_128_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-128 Key Schedule */ -void AES_128_NI::key_schedule(const byte key[], size_t) +void AES_128::aesni_key_schedule(const byte key[], size_t) { m_EK.resize(44); m_DK.resize(44); @@ -306,18 +305,9 @@ void AES_128_NI::key_schedule(const byte key[], size_t) } /* -* Clear memory of sensitive data -*/ -void AES_128_NI::clear() - { - zap(m_EK); - zap(m_DK); - } - -/* * AES-192 Encryption */ -void AES_192_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_192::aesni_encrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -399,7 +389,7 @@ void AES_192_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-192 Decryption */ -void AES_192_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_192::aesni_decrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -481,7 +471,7 @@ void AES_192_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-192 Key Schedule */ -void AES_192_NI::key_schedule(const byte key[], size_t) +void AES_192::aesni_key_schedule(const byte key[], size_t) { m_EK.resize(52); m_DK.resize(52); @@ -528,18 +518,9 @@ void AES_192_NI::key_schedule(const byte key[], size_t) } /* -* Clear memory of sensitive data -*/ -void AES_192_NI::clear() - { - zap(m_EK); - zap(m_DK); - } - -/* * AES-256 Encryption */ -void AES_256_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_256::aesni_encrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -627,7 +608,7 @@ void AES_256_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-256 Decryption */ -void AES_256_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_256::aesni_decrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -715,7 +696,7 @@ void AES_256_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-256 Key Schedule */ -void AES_256_NI::key_schedule(const byte key[], size_t) +void AES_256::aesni_key_schedule(const byte key[], size_t) { m_EK.resize(60); m_DK.resize(60); @@ -779,15 +760,6 @@ void AES_256_NI::key_schedule(const byte key[], size_t) _mm_storeu_si128(DK_mm + 14, K0); } -/* -* Clear memory of sensitive data -*/ -void AES_256_NI::clear() - { - zap(m_EK); - zap(m_DK); - } - #undef AES_ENC_4_ROUNDS #undef AES_ENC_4_LAST_ROUNDS #undef AES_DEC_4_ROUNDS diff --git a/src/lib/block/aes_ni/aes_ni.h b/src/lib/block/aes_ni/aes_ni.h deleted file mode 100644 index 296fd7fcc..000000000 --- a/src/lib/block/aes_ni/aes_ni.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -* AES using AES-NI instructions -* (C) 2009 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_AES_NI_H__ -#define BOTAN_AES_NI_H__ - -#include <botan/block_cipher.h> - -namespace Botan { - -/** -* AES-128 using AES-NI -*/ -class BOTAN_DLL AES_128_NI final : public Block_Cipher_Fixed_Params<16, 16> - { - public: - size_t parallelism() const override { return 4; } - - void encrypt_n(const byte in[], byte out[], size_t blocks) const override; - void decrypt_n(const byte in[], byte out[], size_t blocks) const override; - - void clear() override; - std::string name() const override { return "AES-128"; } - BlockCipher* clone() const override { return new AES_128_NI; } - private: - void key_schedule(const byte[], size_t) override; - - secure_vector<u32bit> m_EK, m_DK; - }; - -/** -* AES-192 using AES-NI -*/ -class BOTAN_DLL AES_192_NI final : public Block_Cipher_Fixed_Params<16, 24> - { - public: - size_t parallelism() const override { return 4; } - - void encrypt_n(const byte in[], byte out[], size_t blocks) const override; - void decrypt_n(const byte in[], byte out[], size_t blocks) const override; - - void clear() override; - std::string name() const override { return "AES-192"; } - BlockCipher* clone() const override { return new AES_192_NI; } - private: - void key_schedule(const byte[], size_t) override; - - secure_vector<u32bit> m_EK, m_DK; - }; - -/** -* AES-256 using AES-NI -*/ -class BOTAN_DLL AES_256_NI final : public Block_Cipher_Fixed_Params<16, 32> - { - public: - size_t parallelism() const override { return 4; } - - void encrypt_n(const byte in[], byte out[], size_t blocks) const override; - void decrypt_n(const byte in[], byte out[], size_t blocks) const override; - - void clear() override; - std::string name() const override { return "AES-256"; } - BlockCipher* clone() const override { return new AES_256_NI; } - private: - void key_schedule(const byte[], size_t) override; - - secure_vector<u32bit> m_EK, m_DK; - }; - -} - -#endif diff --git a/src/lib/block/aes_ssse3/aes_ssse3.cpp b/src/lib/block/aes_ssse3/aes_ssse3.cpp index 54e8fcbd8..eda39a7cc 100644 --- a/src/lib/block/aes_ssse3/aes_ssse3.cpp +++ b/src/lib/block/aes_ssse3/aes_ssse3.cpp @@ -10,8 +10,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include <botan/aes_ssse3.h> -#include <botan/cpuid.h> +#include <botan/aes.h> #include <botan/internal/ct_utils.h> #include <tmmintrin.h> @@ -337,7 +336,7 @@ __m128i aes_ssse3_decrypt(__m128i B, const __m128i* keys, size_t rounds) /* * AES-128 Encryption */ -void AES_128_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_128::ssse3_encrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -359,7 +358,7 @@ void AES_128_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-128 Decryption */ -void AES_128_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_128::ssse3_decrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -381,7 +380,7 @@ void AES_128_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-128 Key Schedule */ -void AES_128_SSSE3::key_schedule(const byte keyb[], size_t) +void AES_128::ssse3_key_schedule(const byte keyb[], size_t) { __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, 0x1F8391B9, 0xAF9DEEB6); @@ -416,16 +415,10 @@ void AES_128_SSSE3::key_schedule(const byte keyb[], size_t) _mm_storeu_si128(DK_mm, aes_schedule_mangle_last_dec(key)); } -void AES_128_SSSE3::clear() - { - zap(m_EK); - zap(m_DK); - } - /* * AES-192 Encryption */ -void AES_192_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_192::ssse3_encrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -447,7 +440,7 @@ void AES_192_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-192 Decryption */ -void AES_192_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_192::ssse3_decrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -469,7 +462,7 @@ void AES_192_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-192 Key Schedule */ -void AES_192_SSSE3::key_schedule(const byte keyb[], size_t) +void AES_192::ssse3_key_schedule(const byte keyb[], size_t) { __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, 0x1F8391B9, 0xAF9DEEB6); @@ -533,16 +526,10 @@ void AES_192_SSSE3::key_schedule(const byte keyb[], size_t) } } -void AES_192_SSSE3::clear() - { - zap(m_EK); - zap(m_DK); - } - /* * AES-256 Encryption */ -void AES_256_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_256::ssse3_encrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -564,7 +551,7 @@ void AES_256_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-256 Decryption */ -void AES_256_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_256::ssse3_decrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -586,7 +573,7 @@ void AES_256_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-256 Key Schedule */ -void AES_256_SSSE3::key_schedule(const byte keyb[], size_t) +void AES_256::ssse3_key_schedule(const byte keyb[], size_t) { __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, 0x1F8391B9, 0xAF9DEEB6); @@ -629,10 +616,4 @@ void AES_256_SSSE3::key_schedule(const byte keyb[], size_t) _mm_storeu_si128(DK_mm + 0, aes_schedule_mangle_last_dec(key2)); } -void AES_256_SSSE3::clear() - { - zap(m_EK); - zap(m_DK); - } - } diff --git a/src/lib/block/aes_ssse3/aes_ssse3.h b/src/lib/block/aes_ssse3/aes_ssse3.h deleted file mode 100644 index 8e6c40dcd..000000000 --- a/src/lib/block/aes_ssse3/aes_ssse3.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -* AES using SSSE3 -* (C) 2010 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_AES_SSSE3_H__ -#define BOTAN_AES_SSSE3_H__ - -#include <botan/block_cipher.h> - -namespace Botan { - -/** -* AES-128 using SSSE3 -*/ -class BOTAN_DLL AES_128_SSSE3 final : public Block_Cipher_Fixed_Params<16, 16> - { - public: - void encrypt_n(const byte in[], byte out[], size_t blocks) const override; - void decrypt_n(const byte in[], byte out[], size_t blocks) const override; - - void clear() override; - std::string name() const override { return "AES-128"; } - BlockCipher* clone() const override { return new AES_128_SSSE3; } - private: - void key_schedule(const byte[], size_t) override; - - secure_vector<u32bit> m_EK, m_DK; - }; - -/** -* AES-192 using SSSE3 -*/ -class BOTAN_DLL AES_192_SSSE3 final : public Block_Cipher_Fixed_Params<16, 24> - { - public: - void encrypt_n(const byte in[], byte out[], size_t blocks) const override; - void decrypt_n(const byte in[], byte out[], size_t blocks) const override; - - void clear() override; - std::string name() const override { return "AES-192"; } - BlockCipher* clone() const override { return new AES_192_SSSE3; } - private: - void key_schedule(const byte[], size_t) override; - - secure_vector<u32bit> m_EK, m_DK; - }; - -/** -* AES-256 using SSSE3 -*/ -class BOTAN_DLL AES_256_SSSE3 final : public Block_Cipher_Fixed_Params<16, 32> - { - public: - void encrypt_n(const byte in[], byte out[], size_t blocks) const override; - void decrypt_n(const byte in[], byte out[], size_t blocks) const override; - - void clear() override; - std::string name() const override { return "AES-256"; } - BlockCipher* clone() const override { return new AES_256_SSSE3; } - private: - void key_schedule(const byte[], size_t) override; - - secure_vector<u32bit> m_EK, m_DK; - }; - -} - -#endif diff --git a/src/lib/block/block_cipher.cpp b/src/lib/block/block_cipher.cpp index 230d9e3a0..2388057c6 100644 --- a/src/lib/block/block_cipher.cpp +++ b/src/lib/block/block_cipher.cpp @@ -13,14 +13,6 @@ #include <botan/aes.h> #endif -#if defined(BOTAN_HAS_AES_SSSE3) - #include <botan/aes_ssse3.h> -#endif - -#if defined(BOTAN_HAS_AES_NI) - #include <botan/aes_ni.h> -#endif - #if defined(BOTAN_HAS_BLOWFISH) #include <botan/blowfish.h> #endif @@ -51,10 +43,6 @@ #include <botan/idea.h> #endif -#if defined(BOTAN_HAS_IDEA_SSE2) - #include <botan/idea_sse2.h> -#endif - #if defined(BOTAN_HAS_KASUMI) #include <botan/kasumi.h> #endif @@ -71,10 +59,6 @@ #include <botan/noekeon.h> #endif -#if defined(BOTAN_HAS_NOEKEON_SIMD) - #include <botan/noekeon_simd.h> -#endif - #if defined(BOTAN_HAS_SEED) #include <botan/seed.h> #endif @@ -83,10 +67,6 @@ #include <botan/serpent.h> #endif -#if defined(BOTAN_HAS_SERPENT_SIMD) - #include <botan/serp_simd.h> -#endif - #if defined(BOTAN_HAS_TWOFISH) #include <botan/twofish.h> #endif @@ -95,18 +75,10 @@ #include <botan/threefish.h> #endif -#if defined(BOTAN_HAS_THREEFISH_512_AVX2) - #include <botan/threefish_avx2.h> -#endif - #if defined(BOTAN_HAS_XTEA) #include <botan/xtea.h> #endif -#if defined(BOTAN_HAS_XTEA_SIMD) - #include <botan/xtea_simd.h> -#endif - namespace Botan { BlockCipher::~BlockCipher() {} @@ -143,21 +115,6 @@ BOTAN_REGISTER_BLOCK_CIPHER_NAMED_NOARGS(AES_192, "AES-192"); BOTAN_REGISTER_BLOCK_CIPHER_NAMED_NOARGS(AES_256, "AES-256"); #endif -#if defined(BOTAN_HAS_AES_NI) -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_aes_ni(), AES_128_NI, "AES-128", "aes_ni", 200); -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_aes_ni(), AES_192_NI, "AES-192", "aes_ni", 200); -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_aes_ni(), AES_256_NI, "AES-256", "aes_ni", 200); -#endif - -#if defined(BOTAN_HAS_AES_SSSE3) -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_ssse3(), AES_128_SSSE3, "AES-128", - "ssse3", BOTAN_SIMD_ALGORITHM_PRIO); -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_ssse3(), AES_192_SSSE3, "AES-192", - "ssse3", BOTAN_SIMD_ALGORITHM_PRIO); -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_ssse3(), AES_256_SSSE3, "AES-256", - "ssse3", BOTAN_SIMD_ALGORITHM_PRIO); -#endif - #if defined(BOTAN_HAS_BLOWFISH) BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(Blowfish); #endif @@ -187,11 +144,6 @@ BOTAN_REGISTER_BLOCK_CIPHER_NAMED_1STR(GOST_28147_89, "GOST-28147-89", "R3411_94 BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(IDEA); #endif -#if defined(BOTAN_HAS_IDEA_SSE2) -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_sse2(), IDEA_SSE2, "IDEA", - "sse2", BOTAN_SIMD_ALGORITHM_PRIO); -#endif - #if defined(BOTAN_HAS_KASUMI) BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(KASUMI); #endif @@ -204,11 +156,6 @@ BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(MISTY1); BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(Noekeon); #endif -#if defined(BOTAN_HAS_NOEKEON_SIMD) -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_simd_32(), Noekeon_SIMD, "Noekeon", - "simd32", BOTAN_SIMD_ALGORITHM_PRIO); -#endif - #if defined(BOTAN_HAS_SEED) BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(SEED); #endif @@ -217,11 +164,6 @@ BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(SEED); BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(Serpent); #endif -#if defined(BOTAN_HAS_SERPENT_SIMD) -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_simd_32(), Serpent_SIMD, "Serpent", - "simd32", BOTAN_SIMD_ALGORITHM_PRIO); -#endif - #if defined(BOTAN_HAS_TWOFISH) BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(Twofish); #endif @@ -230,20 +172,10 @@ BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(Twofish); BOTAN_REGISTER_BLOCK_CIPHER_NAMED_NOARGS(Threefish_512, "Threefish-512"); #endif -#if defined(BOTAN_HAS_THREEFISH_512_AVX2) -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_avx2(), Threefish_512_AVX2, "Threefish-512", - "avx2", BOTAN_SIMD_ALGORITHM_PRIO); -#endif - #if defined(BOTAN_HAS_XTEA) BOTAN_REGISTER_BLOCK_CIPHER_NOARGS(XTEA); #endif -#if defined(BOTAN_HAS_XTEA_SIMD) -BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(CPUID::has_simd_32(), XTEA_SIMD, "XTEA", - "simd32", BOTAN_SIMD_ALGORITHM_PRIO); -#endif - #if defined(BOTAN_HAS_CASCADE) BOTAN_REGISTER_NAMED_T(BlockCipher, "Cascade", Cascade_Cipher, Cascade_Cipher::make); #endif diff --git a/src/lib/block/block_cipher.h b/src/lib/block/block_cipher.h index 0f4c2c1c5..b16468958 100644 --- a/src/lib/block/block_cipher.h +++ b/src/lib/block/block_cipher.h @@ -10,6 +10,7 @@ #include <botan/scan_name.h> #include <botan/sym_algo.h> +#include <string> namespace Botan { @@ -53,6 +54,12 @@ class BOTAN_DLL BlockCipher : public SymmetricAlgorithm } /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + + /** * Encrypt a block. * @param in The plaintext block to be encrypted as a byte array. * Must be of length block_size(). diff --git a/src/lib/block/idea/idea.cpp b/src/lib/block/idea/idea.cpp index 4182c59a7..85cc5e757 100644 --- a/src/lib/block/idea/idea.cpp +++ b/src/lib/block/idea/idea.cpp @@ -7,6 +7,7 @@ #include <botan/idea.h> #include <botan/loadstor.h> +#include <botan/cpuid.h> #include <botan/internal/ct_utils.h> namespace Botan { @@ -108,11 +109,36 @@ void idea_op(const byte in[], byte out[], size_t blocks, const u16bit K[52]) } +std::string IDEA::provider() const + { +#if defined(BOTAN_HAS_IDEA_SSE2) + if(CPUID::has_sse2()) + { + return "sse2"; + } +#endif + + return "base"; + } + /* * IDEA Encryption */ void IDEA::encrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_IDEA_SSE2) + if(CPUID::has_sse2()) + { + while(blocks >= 8) + { + sse2_idea_op_8(in, out, m_EK.data()); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + } +#endif + idea_op(in, out, blocks, m_EK.data()); } @@ -121,6 +147,19 @@ void IDEA::encrypt_n(const byte in[], byte out[], size_t blocks) const */ void IDEA::decrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_IDEA_SSE2) + if(CPUID::has_sse2()) + { + while(blocks >= 8) + { + sse2_idea_op_8(in, out, m_DK.data()); + in += 8 * BLOCK_SIZE; + out += 8 * BLOCK_SIZE; + blocks -= 8; + } + } +#endif + idea_op(in, out, blocks, m_DK.data()); } diff --git a/src/lib/block/idea/idea.h b/src/lib/block/idea/idea.h index 59f98da9e..eb391a0c8 100644 --- a/src/lib/block/idea/idea.h +++ b/src/lib/block/idea/idea.h @@ -15,27 +15,22 @@ namespace Botan { /** * IDEA */ -class BOTAN_DLL IDEA : public Block_Cipher_Fixed_Params<8, 16> +class BOTAN_DLL IDEA final : public Block_Cipher_Fixed_Params<8, 16> { public: void encrypt_n(const byte in[], byte out[], size_t blocks) const override; void decrypt_n(const byte in[], byte out[], size_t blocks) const override; void clear() override; + + std::string provider() const override; std::string name() const override { return "IDEA"; } BlockCipher* clone() const override { return new IDEA; } - protected: - /** - * @return const reference to encryption subkeys - */ - const secure_vector<u16bit>& get_EK() const { return m_EK; } - - /** - * @return const reference to decryption subkeys - */ - const secure_vector<u16bit>& get_DK() const { return m_DK; } - private: +#if defined(BOTAN_HAS_IDEA_SSE2) + void sse2_idea_op_8(const byte in[64], byte out[64], const u16bit EK[52]) const; +#endif + void key_schedule(const byte[], size_t) override; secure_vector<u16bit> m_EK, m_DK; diff --git a/src/lib/block/idea_sse2/idea_sse2.cpp b/src/lib/block/idea_sse2/idea_sse2.cpp index c7d846e8b..4debfc95a 100644 --- a/src/lib/block/idea_sse2/idea_sse2.cpp +++ b/src/lib/block/idea_sse2/idea_sse2.cpp @@ -5,8 +5,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include <botan/idea_sse2.h> -#include <botan/cpuid.h> +#include <botan/idea.h> #include <botan/internal/ct_utils.h> #include <emmintrin.h> @@ -126,10 +125,12 @@ void transpose_out(__m128i& B0, __m128i& B1, __m128i& B2, __m128i& B3) B3 = _mm_unpackhi_epi32(T2, T3); } +} + /* -* IDEA encryption/decryption in SSE2 +* 8 wide IDEA encryption/decryption in SSE2 */ -void idea_op_8(const byte in[64], byte out[64], const u16bit EK[52]) +void IDEA::sse2_idea_op_8(const byte in[64], byte out[64], const u16bit EK[52]) const { CT::poison(in, 64); CT::poison(out, 64); @@ -201,43 +202,3 @@ void idea_op_8(const byte in[64], byte out[64], const u16bit EK[52]) } } - -/* -* IDEA Encryption -*/ -void IDEA_SSE2::encrypt_n(const byte in[], byte out[], size_t blocks) const - { - const u16bit* KS = &this->get_EK()[0]; - - while(blocks >= 8) - { - idea_op_8(in, out, KS); - in += 8 * BLOCK_SIZE; - out += 8 * BLOCK_SIZE; - blocks -= 8; - } - - if(blocks) - IDEA::encrypt_n(in, out, blocks); - } - -/* -* IDEA Decryption -*/ -void IDEA_SSE2::decrypt_n(const byte in[], byte out[], size_t blocks) const - { - const u16bit* KS = &this->get_DK()[0]; - - while(blocks >= 8) - { - idea_op_8(in, out, KS); - in += 8 * BLOCK_SIZE; - out += 8 * BLOCK_SIZE; - blocks -= 8; - } - - if(blocks) - IDEA::decrypt_n(in, out, blocks); - } - -} diff --git a/src/lib/block/idea_sse2/idea_sse2.h b/src/lib/block/idea_sse2/idea_sse2.h deleted file mode 100644 index 9e0df9925..000000000 --- a/src/lib/block/idea_sse2/idea_sse2.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -* IDEA in SSE2 -* (C) 2009 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_IDEA_SSE2_H__ -#define BOTAN_IDEA_SSE2_H__ - -#include <botan/idea.h> - -namespace Botan { - -/** -* IDEA in SSE2 -*/ -class BOTAN_DLL IDEA_SSE2 final : public IDEA - { - public: - size_t parallelism() const override { return 8; } - - void encrypt_n(const byte in[], byte out[], size_t blocks) const override; - void decrypt_n(const byte in[], byte out[], size_t blocks) const override; - - BlockCipher* clone() const override { return new IDEA_SSE2; } - }; - -} - -#endif diff --git a/src/lib/block/noekeon/noekeon.cpp b/src/lib/block/noekeon/noekeon.cpp index 01f7491f3..eac0979a4 100644 --- a/src/lib/block/noekeon/noekeon.cpp +++ b/src/lib/block/noekeon/noekeon.cpp @@ -7,6 +7,7 @@ #include <botan/noekeon.h> #include <botan/loadstor.h> +#include <botan/cpuid.h> namespace Botan { @@ -72,6 +73,18 @@ inline void gamma(u32bit& A0, u32bit& A1, u32bit& A2, u32bit& A3) } +std::string Noekeon::provider() const + { +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(CPUID::has_simd_32()) + { + return "simd"; + } +#endif + + return "base"; + } + /* * Noekeon Round Constants */ @@ -85,6 +98,19 @@ const byte Noekeon::RC[] = { */ void Noekeon::encrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(CPUID::has_simd_32()) + { + while(blocks >= 4) + { + simd_encrypt_4(in, out); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + } +#endif + for(size_t i = 0; i != blocks; ++i) { u32bit A0 = load_be<u32bit>(in, 0); @@ -123,6 +149,32 @@ void Noekeon::encrypt_n(const byte in[], byte out[], size_t blocks) const */ void Noekeon::decrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(CPUID::has_simd_32()) + { + /* + const size_t blocks4 = blocks / 4; + const size_t blocks_left = blocks % 4; + + in += blocks4 * BLOCK_SIZE; + out += blocks4 * BLOCK_SIZE; + blocks = blocks % 4; + + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks4; ++i) + { + simd_encrypt_4(in + i*4*BLOCK_SIZE, out + i*4*BLOCK_SIZE); + } + */ + while(blocks >= 4) + { + simd_decrypt_4(in, out); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + } +#endif + for(size_t i = 0; i != blocks; ++i) { u32bit A0 = load_be<u32bit>(in, 0); diff --git a/src/lib/block/noekeon/noekeon.h b/src/lib/block/noekeon/noekeon.h index 4a3b9de0c..b0aa4218c 100644 --- a/src/lib/block/noekeon/noekeon.h +++ b/src/lib/block/noekeon/noekeon.h @@ -15,32 +15,27 @@ namespace Botan { /** * Noekeon */ -class BOTAN_DLL Noekeon : public Block_Cipher_Fixed_Params<16, 16> +class BOTAN_DLL Noekeon final : public Block_Cipher_Fixed_Params<16, 16> { public: void encrypt_n(const byte in[], byte out[], size_t blocks) const override; void decrypt_n(const byte in[], byte out[], size_t blocks) const override; + std::string provider() const override; void clear() override; std::string name() const override { return "Noekeon"; } BlockCipher* clone() const override { return new Noekeon; } - protected: + private: +#if defined(BOTAN_HAS_NOEKEON_SIMD) + void simd_encrypt_4(const byte in[], byte out[]) const; + void simd_decrypt_4(const byte in[], byte out[]) const; +#endif + /** * The Noekeon round constants */ static const byte RC[17]; - /** - * @return const reference to encryption subkeys - */ - const secure_vector<u32bit>& get_EK() const { return m_EK; } - - /** - * @return const reference to decryption subkeys - */ - const secure_vector<u32bit>& get_DK() const { return m_DK; } - - private: void key_schedule(const byte[], size_t) override; secure_vector<u32bit> m_EK, m_DK; }; diff --git a/src/lib/block/noekeon_simd/info.txt b/src/lib/block/noekeon_simd/info.txt index 3b92eb206..45ff93467 100644 --- a/src/lib/block/noekeon_simd/info.txt +++ b/src/lib/block/noekeon_simd/info.txt @@ -1,4 +1,4 @@ -define NOEKEON_SIMD 20131128 +define NOEKEON_SIMD 20160903 <requires> noekeon diff --git a/src/lib/block/noekeon_simd/noekeon_simd.cpp b/src/lib/block/noekeon_simd/noekeon_simd.cpp index 07fcf19ff..e37412b5f 100644 --- a/src/lib/block/noekeon_simd/noekeon_simd.cpp +++ b/src/lib/block/noekeon_simd/noekeon_simd.cpp @@ -5,7 +5,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include <botan/noekeon_simd.h> +#include <botan/noekeon.h> #include <botan/internal/simd_32.h> namespace Botan { @@ -63,115 +63,91 @@ namespace Botan { /* * Noekeon Encryption */ -void Noekeon_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const +void Noekeon::simd_encrypt_4(const byte in[], byte out[]) const { - const secure_vector<u32bit>& EK = this->get_EK(); + const SIMD_32 K0 = SIMD_32(m_EK[0]); + const SIMD_32 K1 = SIMD_32(m_EK[1]); + const SIMD_32 K2 = SIMD_32(m_EK[2]); + const SIMD_32 K3 = SIMD_32(m_EK[3]); - SIMD_32 K0 = SIMD_32(EK[0]); - SIMD_32 K1 = SIMD_32(EK[1]); - SIMD_32 K2 = SIMD_32(EK[2]); - SIMD_32 K3 = SIMD_32(EK[3]); + SIMD_32 A0 = SIMD_32::load_be(in ); + SIMD_32 A1 = SIMD_32::load_be(in + 16); + SIMD_32 A2 = SIMD_32::load_be(in + 32); + SIMD_32 A3 = SIMD_32::load_be(in + 48); - while(blocks >= 4) - { - SIMD_32 A0 = SIMD_32::load_be(in ); - SIMD_32 A1 = SIMD_32::load_be(in + 16); - SIMD_32 A2 = SIMD_32::load_be(in + 32); - SIMD_32 A3 = SIMD_32::load_be(in + 48); - - SIMD_32::transpose(A0, A1, A2, A3); - - for(size_t i = 0; i != 16; ++i) - { - A0 ^= SIMD_32(RC[i]); - - NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); - - A1.rotate_left(1); - A2.rotate_left(5); - A3.rotate_left(2); + SIMD_32::transpose(A0, A1, A2, A3); - NOK_SIMD_GAMMA(A0, A1, A2, A3); - - A1.rotate_right(1); - A2.rotate_right(5); - A3.rotate_right(2); - } + for(size_t i = 0; i != 16; ++i) + { + A0 ^= SIMD_32(RC[i]); - A0 ^= SIMD_32(RC[16]); NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); - SIMD_32::transpose(A0, A1, A2, A3); + A1.rotate_left(1); + A2.rotate_left(5); + A3.rotate_left(2); - A0.store_be(out); - A1.store_be(out + 16); - A2.store_be(out + 32); - A3.store_be(out + 48); + NOK_SIMD_GAMMA(A0, A1, A2, A3); - in += 64; - out += 64; - blocks -= 4; + A1.rotate_right(1); + A2.rotate_right(5); + A3.rotate_right(2); } - if(blocks) - Noekeon::encrypt_n(in, out, blocks); + A0 ^= SIMD_32(RC[16]); + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + SIMD_32::transpose(A0, A1, A2, A3); + + A0.store_be(out); + A1.store_be(out + 16); + A2.store_be(out + 32); + A3.store_be(out + 48); } /* * Noekeon Encryption */ -void Noekeon_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const +void Noekeon::simd_decrypt_4(const byte in[], byte out[]) const { - const secure_vector<u32bit>& DK = this->get_DK(); + const SIMD_32 K0 = SIMD_32(m_DK[0]); + const SIMD_32 K1 = SIMD_32(m_DK[1]); + const SIMD_32 K2 = SIMD_32(m_DK[2]); + const SIMD_32 K3 = SIMD_32(m_DK[3]); - SIMD_32 K0 = SIMD_32(DK[0]); - SIMD_32 K1 = SIMD_32(DK[1]); - SIMD_32 K2 = SIMD_32(DK[2]); - SIMD_32 K3 = SIMD_32(DK[3]); + SIMD_32 A0 = SIMD_32::load_be(in ); + SIMD_32 A1 = SIMD_32::load_be(in + 16); + SIMD_32 A2 = SIMD_32::load_be(in + 32); + SIMD_32 A3 = SIMD_32::load_be(in + 48); - while(blocks >= 4) - { - SIMD_32 A0 = SIMD_32::load_be(in ); - SIMD_32 A1 = SIMD_32::load_be(in + 16); - SIMD_32 A2 = SIMD_32::load_be(in + 32); - SIMD_32 A3 = SIMD_32::load_be(in + 48); - - SIMD_32::transpose(A0, A1, A2, A3); - - for(size_t i = 0; i != 16; ++i) - { - NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + SIMD_32::transpose(A0, A1, A2, A3); - A0 ^= SIMD_32(RC[16-i]); - - A1.rotate_left(1); - A2.rotate_left(5); - A3.rotate_left(2); + for(size_t i = 0; i != 16; ++i) + { + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); - NOK_SIMD_GAMMA(A0, A1, A2, A3); + A0 ^= SIMD_32(RC[16-i]); - A1.rotate_right(1); - A2.rotate_right(5); - A3.rotate_right(2); - } + A1.rotate_left(1); + A2.rotate_left(5); + A3.rotate_left(2); - NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); - A0 ^= SIMD_32(RC[0]); + NOK_SIMD_GAMMA(A0, A1, A2, A3); - SIMD_32::transpose(A0, A1, A2, A3); + A1.rotate_right(1); + A2.rotate_right(5); + A3.rotate_right(2); + } - A0.store_be(out); - A1.store_be(out + 16); - A2.store_be(out + 32); - A3.store_be(out + 48); + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + A0 ^= SIMD_32(RC[0]); - in += 64; - out += 64; - blocks -= 4; - } + SIMD_32::transpose(A0, A1, A2, A3); - if(blocks) - Noekeon::decrypt_n(in, out, blocks); + A0.store_be(out); + A1.store_be(out + 16); + A2.store_be(out + 32); + A3.store_be(out + 48); } } diff --git a/src/lib/block/noekeon_simd/noekeon_simd.h b/src/lib/block/noekeon_simd/noekeon_simd.h deleted file mode 100644 index 7907fc4ca..000000000 --- a/src/lib/block/noekeon_simd/noekeon_simd.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -* Noekeon in SIMD -* (C) 2010 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_NOEKEON_SIMD_H__ -#define BOTAN_NOEKEON_SIMD_H__ - -#include <botan/noekeon.h> - -namespace Botan { - -/** -* Noekeon implementation using SIMD operations -*/ -class BOTAN_DLL Noekeon_SIMD final : public Noekeon - { - public: - size_t parallelism() const override { return 4; } - - void encrypt_n(const byte in[], byte out[], size_t blocks) const override; - void decrypt_n(const byte in[], byte out[], size_t blocks) const override; - - BlockCipher* clone() const override { return new Noekeon_SIMD; } - }; - -} - -#endif diff --git a/src/lib/block/serpent/serpent.cpp b/src/lib/block/serpent/serpent.cpp index c35e3e338..07088211d 100644 --- a/src/lib/block/serpent/serpent.cpp +++ b/src/lib/block/serpent/serpent.cpp @@ -9,6 +9,10 @@ #include <botan/loadstor.h> #include <botan/internal/serpent_sbox.h> +#if defined(BOTAN_HAS_SERPENT_SIMD) + #include <botan/cpuid.h> +#endif + namespace Botan { namespace { @@ -53,6 +57,19 @@ inline void i_transform(u32bit& B0, u32bit& B1, u32bit& B2, u32bit& B3) */ void Serpent::encrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_SERPENT_SIMD) + if(CPUID::has_simd_32()) + { + while(blocks >= 4) + { + simd_encrypt_4(in, out); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + } +#endif + for(size_t i = 0; i != blocks; ++i) { u32bit B0 = load_le<u32bit>(in, 0); @@ -105,6 +122,19 @@ void Serpent::encrypt_n(const byte in[], byte out[], size_t blocks) const */ void Serpent::decrypt_n(const byte in[], byte out[], size_t blocks) const { +#if defined(BOTAN_HAS_SERPENT_SIMD) + if(CPUID::has_simd_32()) + { + while(blocks >= 4) + { + simd_decrypt_4(in, out); + in += 4 * BLOCK_SIZE; + out += 4 * BLOCK_SIZE; + blocks -= 4; + } + } +#endif + for(size_t i = 0; i != blocks; ++i) { u32bit B0 = load_le<u32bit>(in, 0); @@ -201,4 +231,16 @@ void Serpent::clear() zap(m_round_key); } +std::string Serpent::provider() const + { +#if defined(BOTAN_HAS_SERPENT_SIMD) + if(CPUID::has_simd_32()) + { + return "simd"; + } +#endif + + return "base"; + } + } diff --git a/src/lib/block/serpent/serpent.h b/src/lib/block/serpent/serpent.h index b9864cf89..218772e0c 100644 --- a/src/lib/block/serpent/serpent.h +++ b/src/lib/block/serpent/serpent.h @@ -13,18 +13,35 @@ namespace Botan { /** -* Serpent, an AES finalist +* Serpent is the most conservative of the AES finalists +* http://www.cl.cam.ac.uk/~rja14/serpent.html */ -class BOTAN_DLL Serpent : public Block_Cipher_Fixed_Params<16, 16, 32, 8> +class BOTAN_DLL Serpent final : public Block_Cipher_Fixed_Params<16, 16, 32, 8> { public: void encrypt_n(const byte in[], byte out[], size_t blocks) const override; void decrypt_n(const byte in[], byte out[], size_t blocks) const override; void clear() override; + std::string provider() const override; std::string name() const override { return "Serpent"; } BlockCipher* clone() const override { return new Serpent; } + + size_t parallelism() const override { return 4; } + protected: +#if defined(BOTAN_HAS_SERPENT_SIMD) + /** + * Encrypt 4 blocks in parallel using SSE2 or AltiVec + */ + void simd_encrypt_4(const byte in[64], byte out[64]) const; + + /** + * Decrypt 4 blocks in parallel using SSE2 or AltiVec + */ + void simd_decrypt_4(const byte in[64], byte out[64]) const; +#endif + /** * For use by subclasses using SIMD, asm, etc * @return const reference to the key schedule diff --git a/src/lib/block/serpent_simd/info.txt b/src/lib/block/serpent_simd/info.txt index acb0b76d8..eedc92757 100644 --- a/src/lib/block/serpent_simd/info.txt +++ b/src/lib/block/serpent_simd/info.txt @@ -1,14 +1,6 @@ -define SERPENT_SIMD 20131128 +define SERPENT_SIMD 20160903 <requires> serpent simd </requires> - -<source> -serp_simd.cpp -</source> - -<header:public> -serp_simd.h -</header:public> diff --git a/src/lib/block/serpent_simd/serp_simd.cpp b/src/lib/block/serpent_simd/serp_simd.cpp index 02fe7d6d9..7571e5511 100644 --- a/src/lib/block/serpent_simd/serp_simd.cpp +++ b/src/lib/block/serpent_simd/serp_simd.cpp @@ -5,7 +5,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include <botan/serp_simd.h> +#include <botan/serpent.h> #include <botan/internal/serpent_sbox.h> #include <botan/internal/simd_32.h> @@ -15,10 +15,10 @@ namespace { #define key_xor(round, B0, B1, B2, B3) \ do { \ - B0 ^= SIMD_32(keys[4*round ]); \ - B1 ^= SIMD_32(keys[4*round+1]); \ - B2 ^= SIMD_32(keys[4*round+2]); \ - B3 ^= SIMD_32(keys[4*round+3]); \ + B0 ^= SIMD_32(m_round_key[4*round ]); \ + B1 ^= SIMD_32(m_round_key[4*round+1]); \ + B2 ^= SIMD_32(m_round_key[4*round+2]); \ + B3 ^= SIMD_32(m_round_key[4*round+3]); \ } while(0); /* @@ -52,12 +52,12 @@ namespace { B0.rotate_right(13); \ } while(0); +} + /* * SIMD Serpent Encryption of 4 blocks in parallel */ -void serpent_encrypt_4(const byte in[64], - byte out[64], - const u32bit keys[132]) +void Serpent::simd_encrypt_4(const byte in[64], byte out[64]) const { SIMD_32 B0 = SIMD_32::load_le(in); SIMD_32 B1 = SIMD_32::load_le(in + 16); @@ -113,9 +113,7 @@ void serpent_encrypt_4(const byte in[64], /* * SIMD Serpent Decryption of 4 blocks in parallel */ -void serpent_decrypt_4(const byte in[64], - byte out[64], - const u32bit keys[132]) +void Serpent::simd_decrypt_4(const byte in[64], byte out[64]) const { SIMD_32 B0 = SIMD_32::load_le(in); SIMD_32 B1 = SIMD_32::load_le(in + 16); @@ -168,48 +166,8 @@ void serpent_decrypt_4(const byte in[64], B3.store_le(out + 48); } -} - #undef key_xor #undef transform #undef i_transform -/* -* Serpent Encryption -*/ -void Serpent_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const - { - const u32bit* KS = &(this->get_round_keys()[0]); - - while(blocks >= 4) - { - serpent_encrypt_4(in, out, KS); - in += 4 * BLOCK_SIZE; - out += 4 * BLOCK_SIZE; - blocks -= 4; - } - - if(blocks) - Serpent::encrypt_n(in, out, blocks); - } - -/* -* Serpent Decryption -*/ -void Serpent_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const - { - const u32bit* KS = &(this->get_round_keys()[0]); - - while(blocks >= 4) - { - serpent_decrypt_4(in, out, KS); - in += 4 * BLOCK_SIZE; - out += 4 * BLOCK_SIZE; - blocks -= 4; - } - - if(blocks) - Serpent::decrypt_n(in, out, blocks); - } - } diff --git a/src/lib/block/serpent_simd/serp_simd.h b/src/lib/block/serpent_simd/serp_simd.h deleted file mode 100644 index e10d4cfe2..000000000 --- a/src/lib/block/serpent_simd/serp_simd.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -* Serpent (SIMD) -* (C) 2009 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_SERPENT_SIMD_H__ -#define BOTAN_SERPENT_SIMD_H__ - -#include <botan/serpent.h> - -namespace Botan { - -/** -* Serpent implementation using SIMD -*/ -class BOTAN_DLL Serpent_SIMD final : public Serpent - { - public: - size_t parallelism() const override { return 4; } - - void encrypt_n(const byte in[], byte out[], size_t blocks) const override; - void decrypt_n(const byte in[], byte out[], size_t blocks) const override; - - BlockCipher* clone() const override { return new Serpent_SIMD; } - }; - -} - -#endif diff --git a/src/lib/block/threefish/threefish.cpp b/src/lib/block/threefish/threefish.cpp index c8e2aff85..f592021fb 100644 --- a/src/lib/block/threefish/threefish.cpp +++ b/src/lib/block/threefish/threefish.cpp @@ -1,12 +1,13 @@ /* * Threefish-512 -* (C) 2013,2014 Jack Lloyd +* (C) 2013,2014,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include <botan/threefish.h> #include <botan/loadstor.h> +#include <botan/cpuid.h> namespace Botan { @@ -97,11 +98,30 @@ void Threefish_512::skein_feedfwd(const secure_vector<u64bit>& M, m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22; } +std::string Threefish_512::provider() const + { +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + if(CPUID::has_avx2()) + { + return "avx2"; + } +#endif + + return "base"; + } + void Threefish_512::encrypt_n(const byte in[], byte out[], size_t blocks) const { BOTAN_ASSERT(m_K.size() == 9, "Key was set"); BOTAN_ASSERT(m_T.size() == 3, "Tweak was set"); +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + if(CPUID::has_avx2()) + { + return avx2_encrypt_n(in, out, blocks); + } +#endif + for(size_t i = 0; i != blocks; ++i) { u64bit X0 = load_le<u64bit>(in, 0); @@ -141,6 +161,13 @@ void Threefish_512::decrypt_n(const byte in[], byte out[], size_t blocks) const BOTAN_ASSERT(m_K.size() == 9, "Key was set"); BOTAN_ASSERT(m_T.size() == 3, "Tweak was set"); +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + if(CPUID::has_avx2()) + { + return avx2_decrypt_n(in, out, blocks); + } +#endif + #define THREEFISH_ROUND(X0,X1,X2,X3,X4,X5,X6,X7,ROT1,ROT2,ROT3,ROT4) \ do { \ X4 ^= X0; \ diff --git a/src/lib/block/threefish/threefish.h b/src/lib/block/threefish/threefish.h index 373600885..b02239c93 100644 --- a/src/lib/block/threefish/threefish.h +++ b/src/lib/block/threefish/threefish.h @@ -15,7 +15,7 @@ namespace Botan { /** * Threefish-512 */ -class BOTAN_DLL Threefish_512 : public Block_Cipher_Fixed_Params<64, 64> +class BOTAN_DLL Threefish_512 final : public Block_Cipher_Fixed_Params<64, 64> { public: void encrypt_n(const byte in[], byte out[], size_t blocks) const override; @@ -24,12 +24,19 @@ class BOTAN_DLL Threefish_512 : public Block_Cipher_Fixed_Params<64, 64> void set_tweak(const byte tweak[], size_t len); void clear() override; + std::string provider() const override; std::string name() const override { return "Threefish-512"; } BlockCipher* clone() const override { return new Threefish_512; } protected: const secure_vector<u64bit>& get_T() const { return m_T; } const secure_vector<u64bit>& get_K() const { return m_K; } private: + +#if defined(BOTAN_HAS_THREEFISH_512_AVX2) + void avx2_encrypt_n(const byte in[], byte out[], size_t blocks) const; + void avx2_decrypt_n(const byte in[], byte out[], size_t blocks) const; +#endif + void key_schedule(const byte key[], size_t key_len) override; // Interface for Skein diff --git a/src/lib/block/threefish_avx2/info.txt b/src/lib/block/threefish_avx2/info.txt index 4a3275092..907253c64 100644 --- a/src/lib/block/threefish_avx2/info.txt +++ b/src/lib/block/threefish_avx2/info.txt @@ -1,4 +1,4 @@ -define THREEFISH_512_AVX2 20131224 +define THREEFISH_512_AVX2 20160903 need_isa avx2 diff --git a/src/lib/block/threefish_avx2/threefish_avx2.cpp b/src/lib/block/threefish_avx2/threefish_avx2.cpp index 9b808a221..e0321812a 100644 --- a/src/lib/block/threefish_avx2/threefish_avx2.cpp +++ b/src/lib/block/threefish_avx2/threefish_avx2.cpp @@ -5,8 +5,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include <botan/threefish_avx2.h> -#include <botan/cpuid.h> +#include <botan/threefish.h> #include <immintrin.h> namespace Botan { @@ -38,7 +37,8 @@ inline void rotate_keys(__m256i& R0, __m256i& R1, __m256i R2) { /* Behold. The key schedule progresses like so. The values - loop back to the originals after the rounds are complete. + loop back to the originals after the rounds are complete + so we don't need to reload for starting the next block. R0 R1 R2 K1,K2,K3 (7,5,3,1),(8,6,4,2),(0,7,5,3) @@ -71,7 +71,7 @@ inline void rotate_keys(__m256i& R0, __m256i& R1, __m256i R2) } -void Threefish_512_AVX2::encrypt_n(const byte in[], byte out[], size_t blocks) const +void Threefish_512::avx2_encrypt_n(const byte in[], byte out[], size_t blocks) const { const u64bit* K = &get_K()[0]; const u64bit* T_64 = &get_T()[0]; @@ -245,7 +245,7 @@ void Threefish_512_AVX2::encrypt_n(const byte in[], byte out[], size_t blocks) c #undef THREEFISH_INJECT_KEY_2 } -void Threefish_512_AVX2::decrypt_n(const byte in[], byte out[], size_t blocks) const +void Threefish_512::avx2_decrypt_n(const byte in[], byte out[], size_t blocks) const { const u64bit* K = &get_K()[0]; const u64bit* T_64 = &get_T()[0]; diff --git a/src/lib/block/threefish_avx2/threefish_avx2.h b/src/lib/block/threefish_avx2/threefish_avx2.h deleted file mode 100644 index fbf2f9d8a..000000000 --- a/src/lib/block/threefish_avx2/threefish_avx2.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -* Threefish-512 in AVX2 -* (C) 2013 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_THREEFISH_AVX2_H__ -#define BOTAN_THREEFISH_AVX2_H__ - -#include <botan/threefish.h> - -namespace Botan { - -/** -* Threefish-512 -*/ -class BOTAN_DLL Threefish_512_AVX2 final : public Threefish_512 - { - private: - void encrypt_n(const byte in[], byte out[], size_t blocks) const override; - void decrypt_n(const byte in[], byte out[], size_t blocks) const override; - - /* TODO: - void skein_feedfwd(const secure_vector<u64bit>& M, - const secure_vector<u64bit>& T) override; - */ - - BlockCipher* clone() const override { return new Threefish_512_AVX2; } - }; - -} - -#endif diff --git a/src/lib/hash/hash.cpp b/src/lib/hash/hash.cpp index 42a7666b6..5a31763d1 100644 --- a/src/lib/hash/hash.cpp +++ b/src/lib/hash/hash.cpp @@ -45,10 +45,6 @@ #include <botan/sha160.h> #endif -#if defined(BOTAN_HAS_SHA1_SSE2) - #include <botan/sha1_sse2.h> -#endif - #if defined(BOTAN_HAS_SHA2_32) #include <botan/sha2_32.h> #endif @@ -155,11 +151,6 @@ BOTAN_REGISTER_HASH_NAMED_NOARGS(RIPEMD_160, "RIPEMD-160"); BOTAN_REGISTER_HASH_NAMED_NOARGS(SHA_160, "SHA-160"); #endif -#if defined(BOTAN_HAS_SHA1_SSE2) -BOTAN_REGISTER_HASH_NOARGS_IF(CPUID::has_sse2(), SHA_160_SSE2, "SHA-160", - "sse2", BOTAN_SIMD_ALGORITHM_PRIO); -#endif - #if defined(BOTAN_HAS_SHA2_32) BOTAN_REGISTER_HASH_NAMED_NOARGS(SHA_224, "SHA-224"); BOTAN_REGISTER_HASH_NAMED_NOARGS(SHA_256, "SHA-256"); diff --git a/src/lib/hash/hash.h b/src/lib/hash/hash.h index ac1c22a65..08b5d5243 100644 --- a/src/lib/hash/hash.h +++ b/src/lib/hash/hash.h @@ -40,6 +40,12 @@ class BOTAN_DLL HashFunction : public Buffered_Computation */ virtual HashFunction* clone() const = 0; + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + HashFunction(); virtual ~HashFunction(); diff --git a/src/lib/hash/sha1/sha160.cpp b/src/lib/hash/sha1/sha160.cpp index 21e87465a..87738fb00 100644 --- a/src/lib/hash/sha1/sha160.cpp +++ b/src/lib/hash/sha1/sha160.cpp @@ -6,6 +6,7 @@ */ #include <botan/sha160.h> +#include <botan/cpuid.h> namespace Botan { @@ -60,9 +61,19 @@ void SHA_160::compress_n(const byte input[], size_t blocks) { using namespace SHA1_F; +#if defined(BOTAN_HAS_SHA1_SSE2) + if(CPUID::has_sse2()) + { + return sse2_compress_n(m_digest, input, blocks); + } + +#endif + u32bit A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3], E = m_digest[4]; + m_W.resize(80); + for(size_t i = 0; i != blocks; ++i) { load_be(m_W.data(), input, 16); diff --git a/src/lib/hash/sha1/sha160.h b/src/lib/hash/sha1/sha160.h index b4a161c14..d7860834f 100644 --- a/src/lib/hash/sha1/sha160.h +++ b/src/lib/hash/sha1/sha160.h @@ -1,6 +1,6 @@ /* * SHA-160 -* (C) 1999-2007 Jack Lloyd +* (C) 1999-2007,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -15,7 +15,7 @@ namespace Botan { /** * NIST's SHA-160 */ -class BOTAN_DLL SHA_160 : public MDx_HashFunction +class BOTAN_DLL SHA_160 final : public MDx_HashFunction { public: std::string name() const override { return "SHA-160"; } @@ -24,37 +24,36 @@ class BOTAN_DLL SHA_160 : public MDx_HashFunction void clear() override; - SHA_160() : MDx_HashFunction(64, true, true), m_digest(5), m_W(80) - { - clear(); - } - protected: - /** - * Set a custom size for the W array. Normally 80, but some - * subclasses need slightly more for best performance/internal - * constraints - * @param W_size how big to make W - */ - explicit SHA_160(size_t W_size) : - MDx_HashFunction(64, true, true), m_digest(5), m_W(W_size) + SHA_160() : MDx_HashFunction(64, true, true), m_digest(5) { clear(); } + private: void compress_n(const byte[], size_t blocks) override; + +#if defined(BOTAN_HAS_SHA1_SSE2) + static void sse2_compress_n(secure_vector<u32bit>& digest, + const byte blocks[], + size_t block_count); +#endif + + void copy_out(byte[]) override; /** - * The digest value, exposed for use by subclasses (asm, SSE2) + * The digest value */ secure_vector<u32bit> m_digest; /** - * The message buffer, exposed for use by subclasses (asm, SSE2) + * The message buffer */ secure_vector<u32bit> m_W; }; +typedef SHA_160 SHA_1; + } #endif diff --git a/src/lib/hash/sha1_sse2/info.txt b/src/lib/hash/sha1_sse2/info.txt index 78f5540e7..e352364ec 100644 --- a/src/lib/hash/sha1_sse2/info.txt +++ b/src/lib/hash/sha1_sse2/info.txt @@ -1,4 +1,4 @@ -define SHA1_SSE2 20131128 +define SHA1_SSE2 20160803 need_isa sse2 diff --git a/src/lib/hash/sha1_sse2/sha1_sse2.cpp b/src/lib/hash/sha1_sse2/sha1_sse2.cpp index 14ad88bc4..2ece541b0 100644 --- a/src/lib/hash/sha1_sse2/sha1_sse2.cpp +++ b/src/lib/hash/sha1_sse2/sha1_sse2.cpp @@ -7,8 +7,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include <botan/sha1_sse2.h> -#include <botan/cpuid.h> +#include <botan/sha160.h> #include <emmintrin.h> namespace Botan { @@ -152,7 +151,8 @@ inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) /* * SHA-160 Compression Function using SSE for message expansion */ -void SHA_160_SSE2::compress_n(const byte input_bytes[], size_t blocks) +//static +void SHA_160::sse2_compress_n(secure_vector<uint32_t>& digest, const byte input[], size_t blocks) { using namespace SHA1_SSE2_F; @@ -161,13 +161,13 @@ void SHA_160_SSE2::compress_n(const byte input_bytes[], size_t blocks) const __m128i K40_59 = _mm_set1_epi32(0x8F1BBCDC); const __m128i K60_79 = _mm_set1_epi32(0xCA62C1D6); - u32bit A = m_digest[0], - B = m_digest[1], - C = m_digest[2], - D = m_digest[3], - E = m_digest[4]; + u32bit A = digest[0], + B = digest[1], + C = digest[2], + D = digest[3], + E = digest[4]; - const __m128i* input = reinterpret_cast<const __m128i*>(input_bytes); + const __m128i* input_mm = reinterpret_cast<const __m128i*>(input); for(size_t i = 0; i != blocks; ++i) { @@ -178,16 +178,16 @@ void SHA_160_SSE2::compress_n(const byte input_bytes[], size_t blocks) v4si P0, P1, P2, P3; - __m128i W0 = _mm_loadu_si128(&input[0]); + __m128i W0 = _mm_loadu_si128(&input_mm[0]); prep00_15(P0, W0); - __m128i W1 = _mm_loadu_si128(&input[1]); + __m128i W1 = _mm_loadu_si128(&input_mm[1]); prep00_15(P1, W1); - __m128i W2 = _mm_loadu_si128(&input[2]); + __m128i W2 = _mm_loadu_si128(&input_mm[2]); prep00_15(P2, W2); - __m128i W3 = _mm_loadu_si128(&input[3]); + __m128i W3 = _mm_loadu_si128(&input_mm[3]); prep00_15(P3, W3); /* @@ -316,13 +316,13 @@ void SHA_160_SSE2::compress_n(const byte input_bytes[], size_t blocks) F4(C, D, E, A, B, GET_P_32(P3, 2)); F4(B, C, D, E, A, GET_P_32(P3, 3)); - A = (m_digest[0] += A); - B = (m_digest[1] += B); - C = (m_digest[2] += C); - D = (m_digest[3] += D); - E = (m_digest[4] += E); + A = (digest[0] += A); + B = (digest[1] += B); + C = (digest[2] += C); + D = (digest[3] += D); + E = (digest[4] += E); - input += (hash_block_size() / 16); + input_mm += (64 / 16); } #undef GET_P_32 diff --git a/src/lib/hash/sha1_sse2/sha1_sse2.h b/src/lib/hash/sha1_sse2/sha1_sse2.h deleted file mode 100644 index a38600762..000000000 --- a/src/lib/hash/sha1_sse2/sha1_sse2.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -* SHA-160 -* (C) 1999-2007 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_SHA_160_SSE2_H__ -#define BOTAN_SHA_160_SSE2_H__ - -#include <botan/sha160.h> - -namespace Botan { - -/** -* SHA-160 using SSE2 for the message expansion -*/ -class BOTAN_DLL SHA_160_SSE2 final : public SHA_160 - { - public: - HashFunction* clone() const override { return new SHA_160_SSE2; } - SHA_160_SSE2() : SHA_160(0) {} // no W needed - private: - void compress_n(const byte[], size_t blocks) override; - }; - -} - -#endif diff --git a/src/lib/mac/mac.h b/src/lib/mac/mac.h index fe3388f3b..ae8ea5405 100644 --- a/src/lib/mac/mac.h +++ b/src/lib/mac/mac.h @@ -51,6 +51,13 @@ class BOTAN_DLL MessageAuthenticationCode : public Buffered_Computation, * Get a new object representing the same algorithm as *this */ virtual MessageAuthenticationCode* clone() const = 0; + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + }; typedef MessageAuthenticationCode MAC; diff --git a/src/lib/modes/aead/gcm/gcm.cpp b/src/lib/modes/aead/gcm/gcm.cpp index e23551cb4..e4a07af82 100644 --- a/src/lib/modes/aead/gcm/gcm.cpp +++ b/src/lib/modes/aead/gcm/gcm.cpp @@ -185,6 +185,16 @@ std::string GCM_Mode::name() const return (m_cipher_name + "/GCM"); } +std::string GCM_Mode::provider() const + { +#if defined(BOTAN_HAS_GCM_CLMUL) + if(CPUID::has_clmul()) + return "clmul"; +#endif + + return "base"; + } + size_t GCM_Mode::update_granularity() const { return m_BS; diff --git a/src/lib/modes/aead/gcm/gcm.h b/src/lib/modes/aead/gcm/gcm.h index ba0d6cad8..3c8bdea3f 100644 --- a/src/lib/modes/aead/gcm/gcm.h +++ b/src/lib/modes/aead/gcm/gcm.h @@ -36,6 +36,8 @@ class BOTAN_DLL GCM_Mode : public AEAD_Mode size_t tag_size() const override { return m_tag_size; } void clear() override; + + std::string provider() const override; protected: GCM_Mode(BlockCipher* cipher, size_t tag_size); diff --git a/src/lib/modes/cipher_mode.h b/src/lib/modes/cipher_mode.h index 73a5f7d96..e98f014b7 100644 --- a/src/lib/modes/cipher_mode.h +++ b/src/lib/modes/cipher_mode.h @@ -113,14 +113,6 @@ class BOTAN_DLL Cipher_Mode */ virtual bool valid_nonce_length(size_t nonce_len) const = 0; - /** - * Return some short name describing the provider of this tranformation. - * Useful in cases where multiple implementations are available (eg, - * different implementations of AES). Default "core" is used for the - * 'standard' implementation included in the library. - */ - virtual std::string provider() const { return "core"; } - virtual std::string name() const = 0; virtual void clear() = 0; @@ -174,6 +166,12 @@ class BOTAN_DLL Cipher_Mode key_schedule(key, length); } + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + private: virtual void key_schedule(const byte key[], size_t length) = 0; }; diff --git a/src/lib/prov/openssl/openssl_block.cpp b/src/lib/prov/openssl/openssl_block.cpp index c868e8977..8f5ae89b1 100644 --- a/src/lib/prov/openssl/openssl_block.cpp +++ b/src/lib/prov/openssl/openssl_block.cpp @@ -25,6 +25,7 @@ class OpenSSL_BlockCipher : public BlockCipher ~OpenSSL_BlockCipher(); void clear() override; + std::string provider() const override { return "openssl"; } std::string name() const override { return m_cipher_name; } BlockCipher* clone() const override; diff --git a/src/lib/prov/openssl/openssl_hash.cpp b/src/lib/prov/openssl/openssl_hash.cpp index c14c551e4..15aebeb94 100644 --- a/src/lib/prov/openssl/openssl_hash.cpp +++ b/src/lib/prov/openssl/openssl_hash.cpp @@ -23,6 +23,7 @@ class OpenSSL_HashFunction : public HashFunction EVP_DigestInit_ex(&m_md, algo, nullptr); } + std::string provider() const override { return "openssl"; } std::string name() const override { return m_name; } HashFunction* clone() const override diff --git a/src/lib/prov/openssl/openssl_rc4.cpp b/src/lib/prov/openssl/openssl_rc4.cpp index d6246e4ab..2e9f8aab7 100644 --- a/src/lib/prov/openssl/openssl_rc4.cpp +++ b/src/lib/prov/openssl/openssl_rc4.cpp @@ -24,6 +24,8 @@ class OpenSSL_RC4 : public StreamCipher public: void clear() override { clear_mem(&m_rc4, 1); } + std::string provider() const override { return "openssl"; } + std::string name() const override { switch(m_skip) diff --git a/src/lib/pubkey/dh/dh.cpp b/src/lib/pubkey/dh/dh.cpp index 8ed79aa3d..763e1f20b 100644 --- a/src/lib/pubkey/dh/dh.cpp +++ b/src/lib/pubkey/dh/dh.cpp @@ -58,7 +58,7 @@ DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, } else { - load_check(rng); + //load_check(rng); } } @@ -73,7 +73,7 @@ DH_PrivateKey::DH_PrivateKey(const AlgorithmIdentifier& alg_id, if(m_y == 0) m_y = power_mod(group_g(), m_x, group_p()); - load_check(rng); + //load_check(rng); } /* diff --git a/src/lib/stream/chacha/chacha.cpp b/src/lib/stream/chacha/chacha.cpp index c35363112..6101281a0 100644 --- a/src/lib/stream/chacha/chacha.cpp +++ b/src/lib/stream/chacha/chacha.cpp @@ -17,6 +17,18 @@ ChaCha::ChaCha(size_t rounds) : m_rounds(rounds) throw Invalid_Argument("ChaCha only supports 8, 12 or 20 rounds"); } +std::string ChaCha::provider() const + { +#if defined(BOTAN_HAS_CHACHA_SSE2) + if(CPUID::has_sse2()) + { + return "sse2"; + } +#endif + + return "base"; + } + //static void ChaCha::chacha_x4(byte output[64*4], u32bit input[16], size_t rounds) { diff --git a/src/lib/stream/chacha/chacha.h b/src/lib/stream/chacha/chacha.h index 7e9e54768..eafeac2fd 100644 --- a/src/lib/stream/chacha/chacha.h +++ b/src/lib/stream/chacha/chacha.h @@ -26,6 +26,8 @@ class BOTAN_DLL ChaCha final : public StreamCipher */ ChaCha(size_t rounds = 20); + std::string provider() const override; + void cipher(const byte in[], byte out[], size_t length) override; void set_iv(const byte iv[], size_t iv_len) override; diff --git a/src/lib/stream/stream_cipher.h b/src/lib/stream/stream_cipher.h index e08bee0ce..b24a99e39 100644 --- a/src/lib/stream/stream_cipher.h +++ b/src/lib/stream/stream_cipher.h @@ -86,6 +86,12 @@ class BOTAN_DLL StreamCipher : public SymmetricAlgorithm */ virtual void seek(u64bit offset) = 0; + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + StreamCipher(); virtual ~StreamCipher(); }; diff --git a/src/lib/utils/cpuid.cpp b/src/lib/utils/cpuid.cpp index d3def91ed..3fafadab7 100644 --- a/src/lib/utils/cpuid.cpp +++ b/src/lib/utils/cpuid.cpp @@ -73,9 +73,8 @@ namespace Botan { -u64bit CPUID::g_x86_processor_flags[2] = { 0, 0 }; +u64bit CPUID::g_processor_flags[2] = { 0, 0 }; size_t CPUID::g_cache_line_size = BOTAN_TARGET_CPU_DEFAULT_CACHE_LINE_SIZE; -bool CPUID::g_altivec_capable = false; bool CPUID::g_initialized = false; namespace { @@ -173,13 +172,14 @@ void CPUID::print(std::ostream& o) o << "CPUID flags: "; #define CPUID_PRINT(flag) do { if(has_##flag()) o << #flag << " "; } while(0) + +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) CPUID_PRINT(sse2); CPUID_PRINT(ssse3); CPUID_PRINT(sse41); CPUID_PRINT(sse42); CPUID_PRINT(avx2); CPUID_PRINT(avx512f); - CPUID_PRINT(altivec); CPUID_PRINT(rdtsc); CPUID_PRINT(bmi2); @@ -189,18 +189,25 @@ void CPUID::print(std::ostream& o) CPUID_PRINT(rdseed); CPUID_PRINT(intel_sha); CPUID_PRINT(adx); +#endif + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + CPUID_PRINT(altivec); +#endif + #undef CPUID_PRINT o << "\n"; } void CPUID::initialize() { - if(g_initialized) - return; + clear_mem(g_processor_flags, 2); #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) - if(altivec_check_sysctl() || altivec_check_pvr_emul()) - g_altivec_capable = true; + if(altivec_check_sysctl() || altivec_check_pvr_emul()) + { + g_processor_flags[0] |= CPUID_ALTIVEC_BIT; + } #endif #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) @@ -220,7 +227,7 @@ void CPUID::initialize() X86_CPUID(1, cpuid); - g_x86_processor_flags[0] = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[3]; + g_processor_flags[0] = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[3]; if(is_intel) g_cache_line_size = 8 * get_byte(2, cpuid[1]); @@ -229,7 +236,7 @@ void CPUID::initialize() { clear_mem(cpuid, 4); X86_CPUID_SUBLEVEL(7, 0, cpuid); - g_x86_processor_flags[1] = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[1]; + g_processor_flags[1] = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[1]; } if(is_amd) @@ -245,8 +252,8 @@ void CPUID::initialize() * If we don't have access to CPUID, we can still safely assume that * any x86-64 processor has SSE2 and RDTSC */ - if(g_x86_processor_flags[0] == 0) - g_x86_processor_flags[0] = (1 << CPUID_SSE2_BIT) | (1 << CPUID_RDTSC_BIT); + if(g_processor_flags[0] == 0) + g_processor_flags[0] = (1 << CPUID_SSE2_BIT) | (1 << CPUID_RDTSC_BIT); #endif g_initialized = true; diff --git a/src/lib/utils/cpuid.h b/src/lib/utils/cpuid.h index 3781b6f8e..4e276fabe 100644 --- a/src/lib/utils/cpuid.h +++ b/src/lib/utils/cpuid.h @@ -15,6 +15,8 @@ namespace Botan { /** * A class handling runtime CPU feature detection +* +* Currently this class supports only x86 (via CPUID) and PowerPC (AltiVec detection) */ class BOTAN_DLL CPUID { @@ -24,6 +26,10 @@ class BOTAN_DLL CPUID */ static void initialize(); + static bool has_simd_32(); + + static void print(std::ostream& o); + /** * Return a best guess of the cache line size */ @@ -36,136 +42,152 @@ class BOTAN_DLL CPUID return g_cache_line_size; } + enum CPUID_bits { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + // This matches the layout of cpuid(1) + CPUID_RDTSC_BIT = 4, + CPUID_SSE2_BIT = 26, + CPUID_CLMUL_BIT = 33, + CPUID_SSSE3_BIT = 41, + CPUID_SSE41_BIT = 51, + CPUID_SSE42_BIT = 52, + CPUID_AESNI_BIT = 57, + CPUID_RDRAND_BIT = 62, + + CPUID_AVX2_BIT = 64+5, + CPUID_BMI2_BIT = 64+8, + CPUID_AVX512F_BIT = 64+16, + CPUID_RDSEED_BIT = 64+18, + CPUID_ADX_BIT = 64+19, + CPUID_SHA_BIT = 64+29, +#endif + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + CPUID_ALTIVEC_BIT = 0 +#endif + + // TODO: ARMv8 feature detection + }; + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) /** * Check if the processor supports AltiVec/VMX */ static bool has_altivec() - { - if(!g_initialized) - { - initialize(); - } + { return has_cpuid_bit(CPUID_ALTIVEC_BIT); } +#endif - return g_altivec_capable; - } +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) /** * Check if the processor supports RDTSC */ static bool has_rdtsc() - { return x86_processor_flags_has(CPUID_RDTSC_BIT); } + { return has_cpuid_bit(CPUID_RDTSC_BIT); } /** * Check if the processor supports SSE2 */ static bool has_sse2() - { return x86_processor_flags_has(CPUID_SSE2_BIT); } + { return has_cpuid_bit(CPUID_SSE2_BIT); } /** * Check if the processor supports SSSE3 */ static bool has_ssse3() - { return x86_processor_flags_has(CPUID_SSSE3_BIT); } + { return has_cpuid_bit(CPUID_SSSE3_BIT); } /** * Check if the processor supports SSE4.1 */ static bool has_sse41() - { return x86_processor_flags_has(CPUID_SSE41_BIT); } + { return has_cpuid_bit(CPUID_SSE41_BIT); } /** * Check if the processor supports SSE4.2 */ static bool has_sse42() - { return x86_processor_flags_has(CPUID_SSE42_BIT); } + { return has_cpuid_bit(CPUID_SSE42_BIT); } /** * Check if the processor supports AVX2 */ static bool has_avx2() - { return x86_processor_flags_has(CPUID_AVX2_BIT); } + { return has_cpuid_bit(CPUID_AVX2_BIT); } /** * Check if the processor supports AVX-512F */ static bool has_avx512f() - { return x86_processor_flags_has(CPUID_AVX512F_BIT); } + { return has_cpuid_bit(CPUID_AVX512F_BIT); } /** * Check if the processor supports BMI2 */ static bool has_bmi2() - { return x86_processor_flags_has(CPUID_BMI2_BIT); } + { return has_cpuid_bit(CPUID_BMI2_BIT); } /** * Check if the processor supports AES-NI */ static bool has_aes_ni() - { return x86_processor_flags_has(CPUID_AESNI_BIT); } + { return has_cpuid_bit(CPUID_AESNI_BIT); } /** * Check if the processor supports CLMUL */ static bool has_clmul() - { return x86_processor_flags_has(CPUID_CLMUL_BIT); } + { return has_cpuid_bit(CPUID_CLMUL_BIT); } /** * Check if the processor supports Intel SHA extension */ static bool has_intel_sha() - { return x86_processor_flags_has(CPUID_SHA_BIT); } + { return has_cpuid_bit(CPUID_SHA_BIT); } /** * Check if the processor supports ADX extension */ static bool has_adx() - { return x86_processor_flags_has(CPUID_ADX_BIT); } + { return has_cpuid_bit(CPUID_ADX_BIT); } /** * Check if the processor supports RDRAND */ static bool has_rdrand() - { return x86_processor_flags_has(CPUID_RDRAND_BIT); } + { return has_cpuid_bit(CPUID_RDRAND_BIT); } /** * Check if the processor supports RDSEED */ static bool has_rdseed() - { return x86_processor_flags_has(CPUID_RDSEED_BIT); } - - static bool has_simd_32(); - - static void print(std::ostream& o); - private: - enum CPUID_bits { - CPUID_RDTSC_BIT = 4, - CPUID_SSE2_BIT = 26, - CPUID_CLMUL_BIT = 33, - CPUID_SSSE3_BIT = 41, - CPUID_SSE41_BIT = 51, - CPUID_SSE42_BIT = 52, - CPUID_AESNI_BIT = 57, - CPUID_RDRAND_BIT = 62, + { return has_cpuid_bit(CPUID_RDSEED_BIT); } +#endif - CPUID_AVX2_BIT = 64+5, - CPUID_BMI2_BIT = 64+8, - CPUID_AVX512F_BIT = 64+16, - CPUID_RDSEED_BIT = 64+18, - CPUID_ADX_BIT = 64+19, - CPUID_SHA_BIT = 64+29, - }; + /* + * Clear a CPUID bit + * Call CPUID::initialize to reset + */ + static void clear_cpuid_bit(CPUID_bits bit) + { + BOTAN_ASSERT(bit < 128, "CPUID bit within bounds"); + const uint64_t mask = ~(static_cast<uint64_t>(1) << (bit % 64)); + g_processor_flags[bit/64] &= mask; + } - static bool x86_processor_flags_has(u64bit bit) + static bool has_cpuid_bit(CPUID_bits elem) { if(!g_initialized) initialize(); - return ((g_x86_processor_flags[bit/64] >> (bit % 64)) & 1); + const size_t bit = static_cast<size_t>(elem); + BOTAN_ASSERT(bit < 128, "CPUID bit within bounds"); + return ((g_processor_flags[bit/64] >> (bit % 64)) & 1); } + private: static bool g_initialized; - static u64bit g_x86_processor_flags[2]; static size_t g_cache_line_size; - static bool g_altivec_capable; + static u64bit g_processor_flags[2]; }; } diff --git a/src/tests/data/aead/gcm.vec b/src/tests/data/aead/gcm.vec index 516e828ec..be8250792 100644 --- a/src/tests/data/aead/gcm.vec +++ b/src/tests/data/aead/gcm.vec @@ -1,3 +1,6 @@ + +#test cpuid aesni ssse3 clmul + [AES-128/GCM] # Nist | Test Case 1 Key = 00000000000000000000000000000000 diff --git a/src/tests/data/block/aes.vec b/src/tests/data/block/aes.vec index 4e0b7399c..50d9cc469 100644 --- a/src/tests/data/block/aes.vec +++ b/src/tests/data/block/aes.vec @@ -1,3 +1,6 @@ + +#test cpuid aesni ssse3 + [AES-128] Key = 000102030405060708090A0B0C0D0E0F In = 00112233445566778899AABBCCDDEEFF diff --git a/src/tests/data/block/idea.vec b/src/tests/data/block/idea.vec index 705d02d68..eee5ef5e9 100644 --- a/src/tests/data/block/idea.vec +++ b/src/tests/data/block/idea.vec @@ -1,3 +1,6 @@ + +#test cpuid sse2 + [IDEA] Key = ED1BCC9E9267925F3132BA3A8CF9B764 In = 7409000000000000 diff --git a/src/tests/data/block/noekeon.vec b/src/tests/data/block/noekeon.vec index 2921301c1..08e7cabf3 100644 --- a/src/tests/data/block/noekeon.vec +++ b/src/tests/data/block/noekeon.vec @@ -1,3 +1,6 @@ + +#cpuid simd32 + [Noekeon] Key = 00000000000000000000000000000000 In = 00000000000000000000000000000000 diff --git a/src/tests/data/block/serpent.vec b/src/tests/data/block/serpent.vec index 623ee6be8..8a40c54b7 100644 --- a/src/tests/data/block/serpent.vec +++ b/src/tests/data/block/serpent.vec @@ -1,3 +1,6 @@ + +#test cpuid simd + [Serpent] Key = 00000000000000000000000000000000 In = D29D576FCEA3A3A7ED9099F29273D78E2D62A890CEA3A3A7ED9099F29273D78ED29D576F315C5C58ED9099F29273D78E2D62A890315C5C58ED9099F29273D78ED29D576FCEA3A3A7126F660D9273D78E2D62A890CEA3A3A7126F660D9273D78ED29D576F315C5C58126F660D9273D78E2D62A890315C5C58126F660D9273D78ED29D576FCEA3A3A7ED9099F26D8C28712D62A890CEA3A3A7ED9099F26D8C2871D29D576F315C5C58ED9099F26D8C28712D62A890315C5C58ED9099F26D8C2871D29D576FCEA3A3A7126F660D6D8C28712D62A890CEA3A3A7126F660D6D8C2871D29D576F315C5C58126F660D6D8C2871 diff --git a/src/tests/data/block/threefish.vec b/src/tests/data/block/threefish.vec index b4e9d8229..dfaccb7ff 100644 --- a/src/tests/data/block/threefish.vec +++ b/src/tests/data/block/threefish.vec @@ -1,3 +1,6 @@ + +#test cpuid avx2 + [Threefish-512] Key = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 In = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/src/tests/data/hash/sha1.vec b/src/tests/data/hash/sha1.vec index f5fd82340..e86650f30 100644 --- a/src/tests/data/hash/sha1.vec +++ b/src/tests/data/hash/sha1.vec @@ -1,3 +1,5 @@ +#test cpuid sse2 + [SHA-160] In = Out = DA39A3EE5E6B4B0D3255BFEF95601890AFD80709 diff --git a/src/tests/data/stream/chacha.vec b/src/tests/data/stream/chacha.vec index 47d3aa7fe..f7ba701ba 100644 --- a/src/tests/data/stream/chacha.vec +++ b/src/tests/data/stream/chacha.vec @@ -1,3 +1,6 @@ + +#test cpuid sse2 + [ChaCha(8)] # Tests got from the original implementation of Daniel J. Bernstein diff --git a/src/tests/main.cpp b/src/tests/main.cpp index 07aaac519..b771d9614 100644 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -228,8 +228,14 @@ class Test_Runner : public Botan_CLI::Command { for(auto&& test_name : tests_to_run) { - const auto results = Botan_Tests::Test::run_test(test_name, false); - out << report_out(results, tests_failed, tests_ran) << std::flush; + try { + const auto results = Botan_Tests::Test::run_test(test_name, false); + out << report_out(results, tests_failed, tests_ran) << std::flush; + } + catch(std::exception& e) + { + out << "Test " << test_name << " failed with exception " << e.what() << std::flush; + } } } else @@ -250,7 +256,15 @@ class Test_Runner : public Botan_CLI::Command for(auto&& test_name : tests_to_run) { auto run_it = [test_name] { - return Botan_Tests::Test::run_test(test_name, false); + try { + return Botan_Tests::Test::run_test(test_name, false); + } + catch(std::exception& e) + { + Botan_Tests::Test::Result r(test_name); + r.test_failure("Exception thrown", e.what()); + return std::vector<Botan_Tests::Test::Result>{r}; + } }; fut_results.push_back(std::async(std::launch::async, run_it)); diff --git a/src/tests/test_block.cpp b/src/tests/test_block.cpp index 0863cb891..acbe6702b 100644 --- a/src/tests/test_block.cpp +++ b/src/tests/test_block.cpp @@ -30,16 +30,18 @@ class Block_Cipher_Tests : public Text_Based_Test return result; } - for(auto&& provider: providers) + for(auto&& provider_ask : providers) { - std::unique_ptr<Botan::BlockCipher> cipher(Botan::BlockCipher::create(algo, provider)); + std::unique_ptr<Botan::BlockCipher> cipher(Botan::BlockCipher::create(algo, provider_ask)); if(!cipher) { - result.note_missing(algo + " from " + provider); + result.note_missing(algo + " from " + provider_ask); continue; } + const std::string provider(cipher->provider()); + result.test_is_nonempty("provider", provider); result.test_eq(provider, cipher->name(), algo); result.test_gte(provider, cipher->parallelism(), 1); result.test_gte(provider, cipher->block_size(), 8); diff --git a/src/tests/test_hash.cpp b/src/tests/test_hash.cpp index 811e95727..aca9d7ef6 100644 --- a/src/tests/test_hash.cpp +++ b/src/tests/test_hash.cpp @@ -36,16 +36,18 @@ class Hash_Function_Tests : public Text_Based_Test return result; } - for(auto&& provider: providers) + for(auto&& provider_ask : providers) { - std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(algo, provider)); + std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(algo, provider_ask)); if(!hash) { - result.note_missing(algo + " from " + provider); + result.note_missing(algo + " from " + provider_ask); continue; } + const std::string provider(hash->provider()); + result.test_is_nonempty("provider", provider); result.test_eq(provider, hash->name(), algo); hash->update(input); diff --git a/src/tests/test_mac.cpp b/src/tests/test_mac.cpp index c7efb7f08..6183e88f7 100644 --- a/src/tests/test_mac.cpp +++ b/src/tests/test_mac.cpp @@ -38,16 +38,19 @@ class Message_Auth_Tests : public Text_Based_Test return result; } - for(auto&& provider: providers) + for(auto&& provider_ask : providers) { - std::unique_ptr<Botan::MessageAuthenticationCode> mac(Botan::MessageAuthenticationCode::create(algo, provider)); + std::unique_ptr<Botan::MessageAuthenticationCode> mac(Botan::MessageAuthenticationCode::create(algo, provider_ask)); if(!mac) { - result.note_missing(algo + " from " + provider); + result.note_missing(algo + " from " + provider_ask); continue; } + const std::string provider(mac->provider()); + + result.test_is_nonempty("provider", provider); result.test_eq(provider, mac->name(), algo); mac->set_key(key); diff --git a/src/tests/test_modes.cpp b/src/tests/test_modes.cpp index 66f537346..ada4d5b82 100644 --- a/src/tests/test_modes.cpp +++ b/src/tests/test_modes.cpp @@ -39,6 +39,7 @@ class Cipher_Mode_Tests : public Text_Based_Test return result; } + result.test_is_nonempty("provider", enc->provider()); result.test_eq("name", enc->name(), algo); result.test_eq("mode not authenticated", enc->authenticated(), false); diff --git a/src/tests/test_stream.cpp b/src/tests/test_stream.cpp index be7b9a548..6097fd3e8 100644 --- a/src/tests/test_stream.cpp +++ b/src/tests/test_stream.cpp @@ -41,16 +41,18 @@ class Stream_Cipher_Tests : public Text_Based_Test return result; } - for(auto&& provider: providers) + for(auto&& provider_ask : providers) { - std::unique_ptr<Botan::StreamCipher> cipher(Botan::StreamCipher::create(algo, provider)); + std::unique_ptr<Botan::StreamCipher> cipher(Botan::StreamCipher::create(algo, provider_ask)); if(!cipher) { - result.note_missing(algo + " from " + provider); + result.note_missing(algo + " from " + provider_ask); continue; } + const std::string provider(cipher->provider()); + result.test_is_nonempty("provider", provider); result.test_eq(provider, cipher->name(), algo); cipher->set_key(key); diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp index a6f96144c..b47f2a7ab 100644 --- a/src/tests/tests.cpp +++ b/src/tests/tests.cpp @@ -175,6 +175,13 @@ bool Test::Result::test_eq(const char* producer, const std::string& what, return test_failure(err.str()); } +bool Test::Result::test_is_nonempty(const std::string& what_is_it, const std::string& to_examine) + { + if(to_examine.empty()) + return test_failure(what_is_it + " was empty"); + return test_success(); + } + bool Test::Result::test_eq(const std::string& what, const std::string& produced, const std::string& expected) { return test_is_eq(what, produced, expected); @@ -527,21 +534,21 @@ Text_Based_Test::Text_Based_Test(const std::string& algo, std::vector<uint8_t> Text_Based_Test::get_req_bin(const VarMap& vars, const std::string& key) const - { - auto i = vars.find(key); - if(i == vars.end()) - throw Test_Error("Test missing variable " + key); + { + auto i = vars.find(key); + if(i == vars.end()) + throw Test_Error("Test missing variable " + key); - try - { - return Botan::hex_decode(i->second); - } - catch(std::exception&) - { - throw Test_Error("Test invalid hex input '" + i->second + "'" + - + " for key " + key); - } + try + { + return Botan::hex_decode(i->second); } + catch(std::exception&) + { + throw Test_Error("Test invalid hex input '" + i->second + "'" + + + " for key " + key); + } + } std::string Text_Based_Test::get_opt_str(const VarMap& vars, const std::string& key, const std::string& def_value) const @@ -646,9 +653,17 @@ std::string Text_Based_Test::get_next_line() } m_cur.reset(new std::ifstream(m_srcs[0])); + m_cur_src_name = m_srcs[0]; + + // Reinit cpuid on new file if needed + if(m_cpu_flags.empty() == false) + { + m_cpu_flags.clear(); + Botan::CPUID::initialize(); + } if(!m_cur->good()) - throw Test_Error("Could not open input file '" + m_srcs[0]); + throw Test_Error("Could not open input file '" + m_cur_src_name); m_srcs.pop_front(); } @@ -662,7 +677,12 @@ std::string Text_Based_Test::get_next_line() continue; if(line[0] == '#') - continue; + { + if(line.compare(0, 6, "#test ") == 0) + return line; + else + continue; + } return line; } @@ -685,6 +705,42 @@ std::string strip_ws(const std::string& in) return in.substr(first_c, last_c - first_c + 1); } +std::vector<Botan::CPUID::CPUID_bits> map_cpuid_string(const std::string& tok) + { +#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) + if(tok == "sse2" || tok == "simd") + return {Botan::CPUID::CPUID_SSE2_BIT}; + if(tok == "ssse3") + return {Botan::CPUID::CPUID_SSSE3_BIT}; + if(tok == "aesni") + return {Botan::CPUID::CPUID_AESNI_BIT}; + if(tok == "clmul") + return {Botan::CPUID::CPUID_CLMUL_BIT}; + if(tok == "avx2") + return {Botan::CPUID::CPUID_AVX2_BIT}; +#endif + +#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) + if(tok == "altivec" || tok == "simd") + return {Botan::CPUID::CPUID_ALTIVEC_BIT}; +#endif + + return {}; + } + +std::vector<Botan::CPUID::CPUID_bits> +parse_cpuid_bits(const std::vector<std::string>& tok) + { + std::vector<Botan::CPUID::CPUID_bits> bits; + for(size_t i = 1; i < tok.size(); ++i) + { + const std::vector<Botan::CPUID::CPUID_bits> more = map_cpuid_string(tok[i]); + bits.insert(bits.end(), more.begin(), more.end()); + } + + return bits; + } + } std::vector<Test::Result> Text_Based_Test::run() @@ -701,6 +757,23 @@ std::vector<Test::Result> Text_Based_Test::run() if(line.empty()) // EOF break; + if(line.compare(0, 6, "#test ") == 0) + { + std::vector<std::string> pragma_tokens = Botan::split_on(line.substr(6), ' '); + + if(pragma_tokens.empty()) + throw Test_Error("Empty pragma found in " + m_cur_src_name); + + if(pragma_tokens[0] != "cpuid") + throw Test_Error("Unknown test pragma '" + line + "' in " + m_cur_src_name); + + m_cpu_flags = parse_cpuid_bits(pragma_tokens); + + continue; + } + else if(line[0] == '#') + throw Test_Error("Unknown test pragma '" + line + "' in " + m_cur_src_name); + if(line[0] == '[' && line[line.size()-1] == ']') { header = line.substr(1, line.size() - 2); @@ -736,7 +809,21 @@ std::vector<Test::Result> Text_Based_Test::run() ++test_cnt; uint64_t start = Test::timestamp(); + Test::Result result = run_one_test(header, vars); + if(m_cpu_flags.size() > 0) + { + for(auto&& cpuid_bit : m_cpu_flags) + { + if(Botan::CPUID::has_cpuid_bit(cpuid_bit)) + { + Botan::CPUID::clear_cpuid_bit(cpuid_bit); + // now re-run the test + result.merge(run_one_test(header, vars)); + } + } + Botan::CPUID::initialize(); + } result.set_ns_consumed(Test::timestamp() - start); if(result.tests_failed()) diff --git a/src/tests/tests.h b/src/tests/tests.h index 39aaf67cd..1ceb24f48 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -12,6 +12,7 @@ #include <botan/rng.h> #include <botan/hex.h> #include <botan/symkey.h> +#include <botan/cpuid.h> #if defined(BOTAN_HAS_BIGINT) #include <botan/bigint.h> @@ -170,6 +171,8 @@ class Test bool test_eq(const std::string& what, const char* produced, const char* expected); + bool test_is_nonempty(const std::string& what_is_it, const std::string& to_examine); + bool test_eq(const std::string& what, const std::string& produced, const std::string& expected); @@ -442,7 +445,9 @@ class Text_Based_Test : public Test bool m_first = true; std::unique_ptr<std::ifstream> m_cur; + std::string m_cur_src_name; std::deque<std::string> m_srcs; + std::vector<Botan::CPUID::CPUID_bits> m_cpu_flags; }; } |