diff options
author | Jack Lloyd <[email protected]> | 2017-10-26 20:31:30 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-10-26 22:26:15 -0400 |
commit | e6d45052efedfe49e99adb6318aaf56e0a9e8d7b (patch) | |
tree | c6c3ccd3cff3d04285940bf1d518c809e0653947 /src | |
parent | 315b002ecf00f6b6bb0f0d5200d1f39a83527e8f (diff) |
Add checks that keyed algorithms are actually keyed before use
Previously calling update or encrypt without calling set_key first
would result in invalid outputs or else crashing.
Diffstat (limited to 'src')
40 files changed, 287 insertions, 30 deletions
diff --git a/src/lib/base/sym_algo.h b/src/lib/base/sym_algo.h index a596f5932..a0ebac626 100644 --- a/src/lib/base/sym_algo.h +++ b/src/lib/base/sym_algo.h @@ -91,6 +91,13 @@ class BOTAN_PUBLIC_API(2,0) SymmetricAlgorithm */ virtual std::string name() const = 0; + protected: + void verify_key_set(bool cond) const + { + if(cond == false) + throw Key_Not_Set(name()); + } + private: /** * Run the key schedule diff --git a/src/lib/block/aes/aes.cpp b/src/lib/block/aes/aes.cpp index 8a82ad942..9c375c362 100644 --- a/src/lib/block/aes/aes.cpp +++ b/src/lib/block/aes/aes.cpp @@ -452,6 +452,8 @@ size_t AES_256::parallelism() const { return aes_parallelism(); } void AES_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + #if defined(BOTAN_HAS_AES_NI) if(CPUID::has_aes_ni()) { @@ -478,6 +480,8 @@ void AES_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const void AES_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_DK.empty() == false); + #if defined(BOTAN_HAS_AES_NI) if(CPUID::has_aes_ni()) { @@ -531,6 +535,8 @@ void AES_128::clear() void AES_192::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + #if defined(BOTAN_HAS_AES_NI) if(CPUID::has_aes_ni()) { @@ -557,6 +563,8 @@ void AES_192::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const void AES_192::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_DK.empty() == false); + #if defined(BOTAN_HAS_AES_NI) if(CPUID::has_aes_ni()) { @@ -610,6 +618,8 @@ void AES_192::clear() void AES_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + #if defined(BOTAN_HAS_AES_NI) if(CPUID::has_aes_ni()) { @@ -636,6 +646,8 @@ void AES_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const void AES_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_DK.empty() == false); + #if defined(BOTAN_HAS_AES_NI) if(CPUID::has_aes_ni()) { diff --git a/src/lib/block/blowfish/blowfish.cpp b/src/lib/block/blowfish/blowfish.cpp index 68d73cafd..c2634bba4 100644 --- a/src/lib/block/blowfish/blowfish.cpp +++ b/src/lib/block/blowfish/blowfish.cpp @@ -197,6 +197,8 @@ const uint32_t S_INIT[1024] = { */ void Blowfish::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_S.empty() == false); + const uint32_t* S1 = &m_S[0]; const uint32_t* S2 = &m_S[256]; const uint32_t* S3 = &m_S[512]; @@ -229,6 +231,8 @@ void Blowfish::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void Blowfish::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_S.empty() == false); + const uint32_t* S1 = &m_S[0]; const uint32_t* S2 = &m_S[256]; const uint32_t* S3 = &m_S[512]; diff --git a/src/lib/block/camellia/camellia.cpp b/src/lib/block/camellia/camellia.cpp index 89db6f8b9..9281cd859 100644 --- a/src/lib/block/camellia/camellia.cpp +++ b/src/lib/block/camellia/camellia.cpp @@ -854,31 +854,37 @@ void key_schedule(secure_vector<uint64_t>& SK, const uint8_t key[], size_t lengt void Camellia_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_SK.empty() == false); Camellia_F::encrypt(in, out, blocks, m_SK, 9); } void Camellia_192::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_SK.empty() == false); Camellia_F::encrypt(in, out, blocks, m_SK, 12); } void Camellia_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_SK.empty() == false); Camellia_F::encrypt(in, out, blocks, m_SK, 12); } void Camellia_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_SK.empty() == false); Camellia_F::decrypt(in, out, blocks, m_SK, 9); } void Camellia_192::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_SK.empty() == false); Camellia_F::decrypt(in, out, blocks, m_SK, 12); } void Camellia_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_SK.empty() == false); Camellia_F::decrypt(in, out, blocks, m_SK, 12); } diff --git a/src/lib/block/cast/cast128.cpp b/src/lib/block/cast/cast128.cpp index 5ad732eb3..f7910f034 100644 --- a/src/lib/block/cast/cast128.cpp +++ b/src/lib/block/cast/cast128.cpp @@ -50,6 +50,8 @@ inline uint32_t R3(uint32_t R, uint32_t MK, uint8_t RK) */ void CAST_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_RK.empty() == false); + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { uint32_t L, R; @@ -81,6 +83,8 @@ void CAST_128::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void CAST_128::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_RK.empty() == false); + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { uint32_t L, R; diff --git a/src/lib/block/cast/cast256.cpp b/src/lib/block/cast/cast256.cpp index b4aa49166..cd5175dd7 100644 --- a/src/lib/block/cast/cast256.cpp +++ b/src/lib/block/cast/cast256.cpp @@ -50,6 +50,8 @@ void round3(uint32_t& out, uint32_t in, uint32_t MK, uint32_t RK) */ void CAST_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_RK.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint32_t A = load_be<uint32_t>(in, 0); @@ -94,6 +96,8 @@ void CAST_256::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void CAST_256::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_RK.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint32_t A = load_be<uint32_t>(in, 0); diff --git a/src/lib/block/des/des.cpp b/src/lib/block/des/des.cpp index 15c2adb66..2881cfa9a 100644 --- a/src/lib/block/des/des.cpp +++ b/src/lib/block/des/des.cpp @@ -144,6 +144,8 @@ void des_decrypt(uint32_t& L, uint32_t& R, */ void DES::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_round_key.empty() == false); + for(size_t i = 0; i < blocks; ++i) { uint64_t T = (DES_IPTAB1[in[8*i+0]] ) | (DES_IPTAB1[in[8*i+1]] << 1) | @@ -171,6 +173,8 @@ void DES::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void DES::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_round_key.empty() == false); + for(size_t i = 0; i < blocks; ++i) { uint64_t T = (DES_IPTAB1[in[BLOCK_SIZE*i+0]] ) | (DES_IPTAB1[in[BLOCK_SIZE*i+1]] << 1) | @@ -213,6 +217,8 @@ void DES::clear() */ void TripleDES::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_round_key.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint64_t T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | @@ -246,6 +252,8 @@ void TripleDES::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) cons */ void TripleDES::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_round_key.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint64_t T = (DES_IPTAB1[in[0]] ) | (DES_IPTAB1[in[1]] << 1) | diff --git a/src/lib/block/des/desx.cpp b/src/lib/block/des/desx.cpp index 7c9995523..e869b3ebf 100644 --- a/src/lib/block/des/desx.cpp +++ b/src/lib/block/des/desx.cpp @@ -14,6 +14,8 @@ namespace Botan { */ void DESX::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_K1.empty() == false); + for(size_t i = 0; i != blocks; ++i) { xor_buf(out, in, m_K1.data(), BLOCK_SIZE); @@ -30,6 +32,8 @@ void DESX::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void DESX::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_K1.empty() == false); + for(size_t i = 0; i != blocks; ++i) { xor_buf(out, in, m_K2.data(), BLOCK_SIZE); diff --git a/src/lib/block/gost_28147/gost_28147.cpp b/src/lib/block/gost_28147/gost_28147.cpp index ffe9b5d66..b46d162de 100644 --- a/src/lib/block/gost_28147/gost_28147.cpp +++ b/src/lib/block/gost_28147/gost_28147.cpp @@ -111,6 +111,8 @@ std::string GOST_28147_89::name() const */ void GOST_28147_89::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint32_t N1 = load_le<uint32_t>(in, 0); @@ -141,6 +143,8 @@ void GOST_28147_89::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) */ void GOST_28147_89::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint32_t N1 = load_le<uint32_t>(in, 0); diff --git a/src/lib/block/idea/idea.cpp b/src/lib/block/idea/idea.cpp index c0364b325..26bd24690 100644 --- a/src/lib/block/idea/idea.cpp +++ b/src/lib/block/idea/idea.cpp @@ -137,6 +137,8 @@ std::string IDEA::provider() const */ void IDEA::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + #if defined(BOTAN_HAS_IDEA_SSE2) if(CPUID::has_sse2()) { @@ -158,6 +160,8 @@ void IDEA::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void IDEA::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_DK.empty() == false); + #if defined(BOTAN_HAS_IDEA_SSE2) if(CPUID::has_sse2()) { diff --git a/src/lib/block/kasumi/kasumi.cpp b/src/lib/block/kasumi/kasumi.cpp index a9b5d8274..a40a9d9d5 100644 --- a/src/lib/block/kasumi/kasumi.cpp +++ b/src/lib/block/kasumi/kasumi.cpp @@ -110,6 +110,8 @@ uint16_t FI(uint16_t I, uint16_t K) */ void KASUMI::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint16_t B0 = load_be<uint16_t>(in, 0); @@ -154,6 +156,8 @@ void KASUMI::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void KASUMI::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint16_t B0 = load_be<uint16_t>(in, 0); diff --git a/src/lib/block/lion/lion.cpp b/src/lib/block/lion/lion.cpp index 7959de585..cd7d25d9c 100644 --- a/src/lib/block/lion/lion.cpp +++ b/src/lib/block/lion/lion.cpp @@ -14,6 +14,8 @@ namespace Botan { */ void Lion::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_key1.empty() == false); + const size_t LEFT_SIZE = left_size(); const size_t RIGHT_SIZE = right_size(); @@ -44,6 +46,8 @@ void Lion::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void Lion::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_key1.empty() == false); + const size_t LEFT_SIZE = left_size(); const size_t RIGHT_SIZE = right_size(); @@ -77,6 +81,11 @@ void Lion::key_schedule(const uint8_t key[], size_t length) clear(); const size_t half = length / 2; + + m_key1.resize(left_size()); + m_key2.resize(left_size()); + clear_mem(m_key1.data(), m_key1.size()); + clear_mem(m_key2.data(), m_key2.size()); copy_mem(m_key1.data(), key, half); copy_mem(m_key2.data(), key + half, half); } @@ -104,8 +113,8 @@ BlockCipher* Lion::clone() const */ void Lion::clear() { - zeroise(m_key1); - zeroise(m_key2); + zap(m_key1); + zap(m_key2); m_hash->clear(); m_cipher->clear(); } @@ -123,9 +132,6 @@ Lion::Lion(HashFunction* hash, StreamCipher* cipher, size_t bs) : if(!m_cipher->valid_keylength(left_size())) throw Invalid_Argument(name() + ": This stream/hash combo is invalid"); - - m_key1.resize(left_size()); - m_key2.resize(left_size()); } } diff --git a/src/lib/block/misty1/misty1.cpp b/src/lib/block/misty1/misty1.cpp index eaef86c8c..e7ebffa6e 100644 --- a/src/lib/block/misty1/misty1.cpp +++ b/src/lib/block/misty1/misty1.cpp @@ -103,6 +103,8 @@ uint16_t FI(uint16_t input, uint16_t key7, uint16_t key9) */ void MISTY1::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint16_t B0 = load_be<uint16_t>(in, 0); @@ -153,6 +155,8 @@ void MISTY1::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void MISTY1::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_DK.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint16_t B0 = load_be<uint16_t>(in, 2); diff --git a/src/lib/block/noekeon/noekeon.cpp b/src/lib/block/noekeon/noekeon.cpp index a7f60a0fd..5fd5be82a 100644 --- a/src/lib/block/noekeon/noekeon.cpp +++ b/src/lib/block/noekeon/noekeon.cpp @@ -110,6 +110,8 @@ const uint8_t Noekeon::RC[] = { */ void Noekeon::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + #if defined(BOTAN_HAS_NOEKEON_SIMD) if(CPUID::has_simd_32()) { @@ -161,6 +163,8 @@ void Noekeon::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void Noekeon::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_DK.empty() == false); + #if defined(BOTAN_HAS_NOEKEON_SIMD) if(CPUID::has_simd_32()) { diff --git a/src/lib/block/seed/seed.cpp b/src/lib/block/seed/seed.cpp index 700283042..81194e44a 100644 --- a/src/lib/block/seed/seed.cpp +++ b/src/lib/block/seed/seed.cpp @@ -208,6 +208,8 @@ inline uint32_t SEED_G(uint32_t X) */ void SEED::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_K.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint32_t B0 = load_be<uint32_t>(in, 0); @@ -246,6 +248,8 @@ void SEED::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void SEED::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_K.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint32_t B0 = load_be<uint32_t>(in, 0); diff --git a/src/lib/block/serpent/serpent.cpp b/src/lib/block/serpent/serpent.cpp index 6e1d79766..39968e87e 100644 --- a/src/lib/block/serpent/serpent.cpp +++ b/src/lib/block/serpent/serpent.cpp @@ -57,6 +57,8 @@ inline void i_transform(uint32_t& B0, uint32_t& B1, uint32_t& B2, uint32_t& B3) */ void Serpent::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_round_key.empty() == false); + #if defined(BOTAN_HAS_SERPENT_SIMD) if(CPUID::has_simd_32()) { @@ -117,6 +119,8 @@ void Serpent::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void Serpent::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_round_key.empty() == false); + #if defined(BOTAN_HAS_SERPENT_SIMD) if(CPUID::has_simd_32()) { diff --git a/src/lib/block/shacal2/shacal2.cpp b/src/lib/block/shacal2/shacal2.cpp index 12c87c426..dd4224ed4 100644 --- a/src/lib/block/shacal2/shacal2.cpp +++ b/src/lib/block/shacal2/shacal2.cpp @@ -44,6 +44,8 @@ inline void SHACAL2_Rev(uint32_t A, uint32_t B, uint32_t C, uint32_t& D, */ void SHACAL2::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_RK.empty() == false); + #if defined(BOTAN_HAS_SHACAL2_X86) if(CPUID::has_intel_sha()) { @@ -99,6 +101,8 @@ void SHACAL2::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void SHACAL2::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_RK.empty() == false); + #if defined(BOTAN_HAS_SHACAL2_SIMD) if(CPUID::has_simd_32()) { diff --git a/src/lib/block/sm4/sm4.cpp b/src/lib/block/sm4/sm4.cpp index 2902d514c..7c409d40f 100644 --- a/src/lib/block/sm4/sm4.cpp +++ b/src/lib/block/sm4/sm4.cpp @@ -124,6 +124,8 @@ inline uint32_t SM4_Tp(uint32_t b) */ void SM4::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_RK.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint32_t B0 = load_be<uint32_t>(in, 0); @@ -152,6 +154,8 @@ void SM4::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void SM4::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_RK.empty() == false); + for(size_t i = 0; i != blocks; ++i) { uint32_t B0 = load_be<uint32_t>(in, 0); diff --git a/src/lib/block/threefish/threefish.cpp b/src/lib/block/threefish/threefish.cpp index 804d6003a..60f793d64 100644 --- a/src/lib/block/threefish/threefish.cpp +++ b/src/lib/block/threefish/threefish.cpp @@ -124,8 +124,7 @@ std::string Threefish_512::provider() const void Threefish_512::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { - BOTAN_ASSERT(m_K.size() == 9, "Key was set"); - BOTAN_ASSERT(m_T.size() == 3, "Tweak was set"); + verify_key_set(m_K.empty() == false); #if defined(BOTAN_HAS_THREEFISH_512_AVX2) if(CPUID::has_avx2()) @@ -161,8 +160,7 @@ void Threefish_512::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) void Threefish_512::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { - BOTAN_ASSERT(m_K.size() == 9, "Key was set"); - BOTAN_ASSERT(m_T.size() == 3, "Tweak was set"); + verify_key_set(m_K.empty() == false); #if defined(BOTAN_HAS_THREEFISH_512_AVX2) if(CPUID::has_avx2()) diff --git a/src/lib/block/twofish/twofish.cpp b/src/lib/block/twofish/twofish.cpp index 3a09af8da..496c31a36 100644 --- a/src/lib/block/twofish/twofish.cpp +++ b/src/lib/block/twofish/twofish.cpp @@ -19,6 +19,8 @@ namespace Botan { */ void Twofish::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_SB.empty() == false); + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { uint32_t A, B, C, D; @@ -70,6 +72,8 @@ void Twofish::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void Twofish::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_SB.empty() == false); + BOTAN_PARALLEL_FOR(size_t i = 0; i < blocks; ++i) { uint32_t A, B, C, D; diff --git a/src/lib/block/xtea/xtea.cpp b/src/lib/block/xtea/xtea.cpp index b53de448b..679ad4cfb 100644 --- a/src/lib/block/xtea/xtea.cpp +++ b/src/lib/block/xtea/xtea.cpp @@ -15,6 +15,8 @@ namespace Botan { */ void XTEA::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + const uint32_t* EK = &m_EK[0]; const size_t blocks4 = blocks / 4; @@ -61,6 +63,8 @@ void XTEA::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const */ void XTEA::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + verify_key_set(m_EK.empty() == false); + const uint32_t* EK = &m_EK[0]; const size_t blocks4 = blocks / 4; diff --git a/src/lib/mac/cbc_mac/cbc_mac.cpp b/src/lib/mac/cbc_mac/cbc_mac.cpp index b272fe3bc..ba403b564 100644 --- a/src/lib/mac/cbc_mac/cbc_mac.cpp +++ b/src/lib/mac/cbc_mac/cbc_mac.cpp @@ -14,6 +14,8 @@ namespace Botan { */ void CBC_MAC::add_data(const uint8_t input[], size_t length) { + verify_key_set(m_state.empty() == false); + size_t xored = std::min(output_length() - m_position, length); xor_buf(&m_state[m_position], input, xored); m_position += xored; @@ -41,6 +43,8 @@ void CBC_MAC::add_data(const uint8_t input[], size_t length) */ void CBC_MAC::final_result(uint8_t mac[]) { + verify_key_set(m_state.empty() == false); + if(m_position) m_cipher->encrypt(m_state); @@ -54,6 +58,7 @@ void CBC_MAC::final_result(uint8_t mac[]) */ void CBC_MAC::key_schedule(const uint8_t key[], size_t length) { + m_state.resize(m_cipher->block_size()); m_cipher->set_key(key, length); } @@ -63,7 +68,7 @@ void CBC_MAC::key_schedule(const uint8_t key[], size_t length) void CBC_MAC::clear() { m_cipher->clear(); - zeroise(m_state); + zap(m_state); m_position = 0; } @@ -87,7 +92,7 @@ MessageAuthenticationCode* CBC_MAC::clone() const * CBC-MAC Constructor */ CBC_MAC::CBC_MAC(BlockCipher* cipher) : - m_cipher(cipher), m_state(cipher->block_size()) + m_cipher(cipher) { } diff --git a/src/lib/mac/hmac/hmac.cpp b/src/lib/mac/hmac/hmac.cpp index 32f62f0c2..244946d88 100644 --- a/src/lib/mac/hmac/hmac.cpp +++ b/src/lib/mac/hmac/hmac.cpp @@ -15,6 +15,7 @@ namespace Botan { */ void HMAC::add_data(const uint8_t input[], size_t length) { + verify_key_set(m_ikey.empty() == false); m_hash->update(input, length); } @@ -23,6 +24,7 @@ void HMAC::add_data(const uint8_t input[], size_t length) */ void HMAC::final_result(uint8_t mac[]) { + verify_key_set(m_okey.empty() == false); m_hash->final(mac); m_hash->update(m_okey); m_hash->update(mac, output_length()); diff --git a/src/lib/mac/poly1305/poly1305.cpp b/src/lib/mac/poly1305/poly1305.cpp index 9fe0bad0a..639aa88c0 100644 --- a/src/lib/mac/poly1305/poly1305.cpp +++ b/src/lib/mac/poly1305/poly1305.cpp @@ -155,7 +155,7 @@ void Poly1305::key_schedule(const uint8_t key[], size_t) void Poly1305::add_data(const uint8_t input[], size_t length) { - BOTAN_ASSERT_EQUAL(m_poly.size(), 8, "Initialized"); + verify_key_set(m_poly.size() == 8); if(m_buf_pos) { @@ -182,7 +182,7 @@ void Poly1305::add_data(const uint8_t input[], size_t length) void Poly1305::final_result(uint8_t out[]) { - BOTAN_ASSERT_EQUAL(m_poly.size(), 8, "Initialized"); + verify_key_set(m_poly.size() == 8); if(m_buf_pos != 0) { diff --git a/src/lib/mac/siphash/siphash.cpp b/src/lib/mac/siphash/siphash.cpp index 255a35493..80acc4d60 100644 --- a/src/lib/mac/siphash/siphash.cpp +++ b/src/lib/mac/siphash/siphash.cpp @@ -39,6 +39,8 @@ void SipRounds(uint64_t M, secure_vector<uint64_t>& V, size_t r) void SipHash::add_data(const uint8_t input[], size_t length) { + verify_key_set(m_V.empty() == false); + // SipHash counts the message length mod 256 m_words += static_cast<uint8_t>(length); @@ -76,6 +78,8 @@ void SipHash::add_data(const uint8_t input[], size_t length) void SipHash::final_result(uint8_t mac[]) { + verify_key_set(m_V.empty() == false); + m_mbuf = (m_mbuf >> (64-m_mbuf_pos*8)) | (static_cast<uint64_t>(m_words) << 56); SipRounds(m_mbuf, m_V, m_C); @@ -103,7 +107,7 @@ void SipHash::key_schedule(const uint8_t key[], size_t) void SipHash::clear() { - m_V.clear(); + zap(m_V); m_mbuf = 0; m_mbuf_pos = 0; m_words = 0; diff --git a/src/lib/mac/x919_mac/x919_mac.cpp b/src/lib/mac/x919_mac/x919_mac.cpp index 189108377..ef1e78602 100644 --- a/src/lib/mac/x919_mac/x919_mac.cpp +++ b/src/lib/mac/x919_mac/x919_mac.cpp @@ -14,6 +14,8 @@ namespace Botan { */ void ANSI_X919_MAC::add_data(const uint8_t input[], size_t length) { + verify_key_set(m_state.empty() == false); + size_t xored = std::min(8 - m_position, length); xor_buf(&m_state[m_position], input, xored); m_position += xored; @@ -53,6 +55,8 @@ void ANSI_X919_MAC::final_result(uint8_t mac[]) */ void ANSI_X919_MAC::key_schedule(const uint8_t key[], size_t length) { + m_state.resize(8); + m_des1->set_key(key, 8); if(length == 16) @@ -68,7 +72,7 @@ void ANSI_X919_MAC::clear() { m_des1->clear(); m_des2->clear(); - zeroise(m_state); + zap(m_state); m_position = 0; } @@ -88,7 +92,7 @@ MessageAuthenticationCode* ANSI_X919_MAC::clone() const ANSI_X919_MAC::ANSI_X919_MAC() : m_des1(BlockCipher::create("DES")), m_des2(BlockCipher::create("DES")), - m_state(8), m_position(0) + m_position(0) { } diff --git a/src/lib/modes/aead/gcm/ghash.cpp b/src/lib/modes/aead/gcm/ghash.cpp index 51477f43a..482eec335 100644 --- a/src/lib/modes/aead/gcm/ghash.cpp +++ b/src/lib/modes/aead/gcm/ghash.cpp @@ -199,7 +199,7 @@ void GHASH::set_associated_data(const uint8_t input[], size_t length) void GHASH::update_associated_data(const uint8_t ad[], size_t length) { - BOTAN_ASSERT(m_ghash.size() == GCM_BS, "Key was set"); + verify_key_set(m_ghash.size() == GCM_BS); m_ad_len += length; ghash_update(m_ghash, ad, length); } diff --git a/src/lib/prov/openssl/openssl_block.cpp b/src/lib/prov/openssl/openssl_block.cpp index 33cd9b8cc..3cf203961 100644 --- a/src/lib/prov/openssl/openssl_block.cpp +++ b/src/lib/prov/openssl/openssl_block.cpp @@ -36,6 +36,7 @@ class OpenSSL_BlockCipher final : public BlockCipher void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override { + verify_key_set(m_key_set); int out_len = 0; if(!EVP_EncryptUpdate(m_encrypt, out, &out_len, in, blocks * m_block_sz)) throw OpenSSL_Error("EVP_EncryptUpdate"); @@ -43,6 +44,7 @@ class OpenSSL_BlockCipher final : public BlockCipher void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override { + verify_key_set(m_key_set); int out_len = 0; if(!EVP_DecryptUpdate(m_decrypt, out, &out_len, in, blocks * m_block_sz)) throw OpenSSL_Error("EVP_DecryptUpdate"); @@ -55,13 +57,15 @@ class OpenSSL_BlockCipher final : public BlockCipher std::string m_cipher_name; EVP_CIPHER_CTX *m_encrypt; EVP_CIPHER_CTX *m_decrypt; + bool m_key_set; }; OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name, const EVP_CIPHER* algo) : m_block_sz(EVP_CIPHER_block_size(algo)), m_cipher_key_spec(EVP_CIPHER_key_length(algo)), - m_cipher_name(algo_name) + m_cipher_name(algo_name), + m_key_set(false) { if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE) throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in"); @@ -92,7 +96,8 @@ OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name, size_t key_mod) : m_block_sz(EVP_CIPHER_block_size(algo)), m_cipher_key_spec(key_min, key_max, key_mod), - m_cipher_name(algo_name) + m_cipher_name(algo_name), + m_key_set(false) { if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE) throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in"); @@ -134,15 +139,19 @@ void OpenSSL_BlockCipher::key_schedule(const uint8_t key[], size_t length) full_key += std::make_pair(key, 8); } else + { if(EVP_CIPHER_CTX_set_key_length(m_encrypt, length) == 0 || EVP_CIPHER_CTX_set_key_length(m_decrypt, length) == 0) throw Invalid_Argument("OpenSSL_BlockCipher: Bad key length for " + m_cipher_name); + } if(!EVP_EncryptInit_ex(m_encrypt, nullptr, nullptr, full_key.data(), nullptr)) throw OpenSSL_Error("EVP_EncryptInit_ex"); if(!EVP_DecryptInit_ex(m_decrypt, nullptr, nullptr, full_key.data(), nullptr)) throw OpenSSL_Error("EVP_DecryptInit_ex"); + + m_key_set = true; } /* @@ -164,6 +173,8 @@ void OpenSSL_BlockCipher::clear() { const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(m_encrypt); + m_key_set = false; + if(!EVP_CIPHER_CTX_cleanup(m_encrypt)) throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup encrypt"); if(!EVP_CIPHER_CTX_cleanup(m_decrypt)) diff --git a/src/lib/prov/openssl/openssl_rc4.cpp b/src/lib/prov/openssl/openssl_rc4.cpp index 5fb2a68f5..b24760f45 100644 --- a/src/lib/prov/openssl/openssl_rc4.cpp +++ b/src/lib/prov/openssl/openssl_rc4.cpp @@ -21,7 +21,7 @@ namespace { class OpenSSL_RC4 final : public StreamCipher { public: - void clear() override { clear_mem(&m_rc4, 1); } + void clear() override { clear_mem(&m_rc4, 1); m_key_set = false; } std::string provider() const override { return "openssl"; } @@ -61,6 +61,7 @@ class OpenSSL_RC4 final : public StreamCipher private: void cipher(const uint8_t in[], uint8_t out[], size_t length) override { + verify_key_set(m_key_set); ::RC4(&m_rc4, length, in, out); } @@ -70,10 +71,12 @@ class OpenSSL_RC4 final : public StreamCipher uint8_t d = 0; for(size_t i = 0; i != m_skip; ++i) ::RC4(&m_rc4, 1, &d, &d); + m_key_set = true; } size_t m_skip; RC4_KEY m_rc4; + bool m_key_set; }; } diff --git a/src/lib/stream/chacha/chacha.cpp b/src/lib/stream/chacha/chacha.cpp index 0bbb47bcb..52e5eaaf4 100644 --- a/src/lib/stream/chacha/chacha.cpp +++ b/src/lib/stream/chacha/chacha.cpp @@ -116,6 +116,8 @@ void ChaCha::chacha_x4(uint8_t output[64*4], uint32_t input[16], size_t rounds) */ void ChaCha::cipher(const uint8_t in[], uint8_t out[], size_t length) { + verify_key_set(m_state.empty() == false); + while(length >= m_buffer.size() - m_position) { xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); diff --git a/src/lib/stream/ctr/ctr.cpp b/src/lib/stream/ctr/ctr.cpp index 99a589bb9..463119caf 100644 --- a/src/lib/stream/ctr/ctr.cpp +++ b/src/lib/stream/ctr/ctr.cpp @@ -17,7 +17,6 @@ CTR_BE::CTR_BE(BlockCipher* ciph) : m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size), m_counter(m_cipher->parallel_bytes()), m_pad(m_counter.size()), - m_iv(m_cipher->block_size()), m_pad_pos(0) { } @@ -29,7 +28,6 @@ CTR_BE::CTR_BE(BlockCipher* cipher, size_t ctr_size) : m_ctr_blocks(m_cipher->parallel_bytes() / m_block_size), m_counter(m_cipher->parallel_bytes()), m_pad(m_counter.size()), - m_iv(m_cipher->block_size()), m_pad_pos(0) { if(m_ctr_size < 4 || m_ctr_size > m_block_size) @@ -41,7 +39,7 @@ void CTR_BE::clear() m_cipher->clear(); zeroise(m_pad); zeroise(m_counter); - zeroise(m_iv); + zap(m_iv); m_pad_pos = 0; } @@ -64,6 +62,8 @@ std::string CTR_BE::name() const void CTR_BE::cipher(const uint8_t in[], uint8_t out[], size_t length) { + verify_key_set(m_iv.empty() == false); + const uint8_t* pad_bits = &m_pad[0]; const size_t pad_size = m_pad.size(); @@ -105,6 +105,7 @@ void CTR_BE::set_iv(const uint8_t iv[], size_t iv_len) if(!valid_iv_length(iv_len)) throw Invalid_IV_Length(name(), iv_len); + m_iv.resize(m_cipher->block_size()); zeroise(m_iv); buffer_insert(m_iv, 0, iv, iv_len); diff --git a/src/lib/stream/rc4/rc4.cpp b/src/lib/stream/rc4/rc4.cpp index 208b2f560..60565d445 100644 --- a/src/lib/stream/rc4/rc4.cpp +++ b/src/lib/stream/rc4/rc4.cpp @@ -15,6 +15,8 @@ namespace Botan { */ void RC4::cipher(const uint8_t in[], uint8_t out[], size_t length) { + verify_key_set(m_state.empty() == false); + while(length >= m_buffer.size() - m_position) { xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); diff --git a/src/lib/stream/salsa20/salsa20.cpp b/src/lib/stream/salsa20/salsa20.cpp index e27b2d2bb..3f93cee94 100644 --- a/src/lib/stream/salsa20/salsa20.cpp +++ b/src/lib/stream/salsa20/salsa20.cpp @@ -103,6 +103,8 @@ void salsa20(uint8_t output[64], const uint32_t input[16]) */ void Salsa20::cipher(const uint8_t in[], uint8_t out[], size_t length) { + verify_key_set(m_state.empty() == false); + while(length >= m_buffer.size() - m_position) { xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); diff --git a/src/lib/stream/shake_cipher/shake_cipher.cpp b/src/lib/stream/shake_cipher/shake_cipher.cpp index 4f79777f4..72a8fd885 100644 --- a/src/lib/stream/shake_cipher/shake_cipher.cpp +++ b/src/lib/stream/shake_cipher/shake_cipher.cpp @@ -12,13 +12,13 @@ namespace Botan { SHAKE_128_Cipher::SHAKE_128_Cipher() : - m_state(25), - m_buffer((1600 - 256) / 8), m_buf_pos(0) {} void SHAKE_128_Cipher::cipher(const uint8_t in[], uint8_t out[], size_t length) { + verify_key_set(m_state.empty() == false); + while(length >= m_buffer.size() - m_buf_pos) { xor_buf(out, in, &m_buffer[m_buf_pos], m_buffer.size() - m_buf_pos); @@ -37,6 +37,8 @@ void SHAKE_128_Cipher::cipher(const uint8_t in[], uint8_t out[], size_t length) void SHAKE_128_Cipher::key_schedule(const uint8_t key[], size_t length) { + m_state.resize(25); + m_buffer.resize((1600 - 256) / 8); zeroise(m_state); for(size_t i = 0; i < length/8; ++i) @@ -53,8 +55,8 @@ void SHAKE_128_Cipher::key_schedule(const uint8_t key[], size_t length) void SHAKE_128_Cipher::clear() { - zeroise(m_state); - zeroise(m_buffer); + zap(m_state); + zap(m_buffer); m_buf_pos = 0; } diff --git a/src/lib/utils/exceptn.cpp b/src/lib/utils/exceptn.cpp index 240742602..3fa7dfd3e 100644 --- a/src/lib/utils/exceptn.cpp +++ b/src/lib/utils/exceptn.cpp @@ -44,6 +44,10 @@ Invalid_IV_Length::Invalid_IV_Length(const std::string& mode, size_t bad_len) : " is invalid for " + mode) {} +Key_Not_Set::Key_Not_Set(const std::string& algo) : + Invalid_State("Key not set in " + algo) + {} + Policy_Violation::Policy_Violation(const std::string& err) : Invalid_State("Policy violation: " + err) {} diff --git a/src/lib/utils/exceptn.h b/src/lib/utils/exceptn.h index b9b94a8f8..e82889b5a 100644 --- a/src/lib/utils/exceptn.h +++ b/src/lib/utils/exceptn.h @@ -62,6 +62,12 @@ class BOTAN_PUBLIC_API(2,0) Invalid_State : public Exception explicit Invalid_State(const std::string& err) : Exception(err) {} }; +class BOTAN_PUBLIC_API(2,4) Key_Not_Set : public Invalid_State + { + public: + explicit Key_Not_Set(const std::string& algo); + }; + /** * Lookup_Error Exception */ diff --git a/src/tests/test_block.cpp b/src/tests/test_block.cpp index 535556a90..02115b66a 100644 --- a/src/tests/test_block.cpp +++ b/src/tests/test_block.cpp @@ -53,8 +53,31 @@ class Block_Cipher_Tests final : public Text_Based_Test result.test_gte(provider, cipher->block_size(), 8); result.test_gte(provider, cipher->parallel_bytes(), cipher->block_size() * cipher->parallelism()); + // Test that trying to encrypt or decrypt with now key set throws Botan::Invalid_State + try + { + std::vector<uint8_t> block(cipher->block_size()); + cipher->encrypt(block); + result.test_failure("Was able to encrypt without a key being set"); + } + catch(Botan::Invalid_State&) + { + result.test_success("Trying to encrypt with no key set fails"); + } + + try + { + std::vector<uint8_t> block(cipher->block_size()); + cipher->decrypt(block); + result.test_failure("Was able to decrypt without a key being set"); + } + catch(Botan::Invalid_State&) + { + result.test_success("Trying to encrypt with no key set fails"); + } + // Test to make sure clear() resets what we need it to - cipher->set_key(Test::rng().random_vec(cipher->key_spec().minimum_keylength())); + cipher->set_key(Test::rng().random_vec(cipher->key_spec().maximum_keylength())); Botan::secure_vector<uint8_t> garbage = Test::rng().random_vec(cipher->block_size()); cipher->encrypt(garbage); cipher->clear(); @@ -89,6 +112,28 @@ class Block_Cipher_Tests final : public Text_Based_Test result.test_eq(provider, "decrypt", buf, input); + try + { + std::vector<uint8_t> block(cipher->block_size()); + cipher->encrypt(block); + result.test_failure("Was able to encrypt without a key being set"); + } + catch(Botan::Invalid_State&) + { + result.test_success("Trying to encrypt with no key set (after clear) fails"); + } + + try + { + std::vector<uint8_t> block(cipher->block_size()); + cipher->decrypt(block); + result.test_failure("Was able to decrypt without a key being set"); + } + catch(Botan::Invalid_State&) + { + result.test_success("Trying to decrypt with no key set (after clear) fails"); + } + } return result; diff --git a/src/tests/test_hash.cpp b/src/tests/test_hash.cpp index 2116cade4..39b13de32 100644 --- a/src/tests/test_hash.cpp +++ b/src/tests/test_hash.cpp @@ -68,7 +68,6 @@ class Hash_Function_Tests final : public Text_Based_Test result.test_eq(provider, "hashing after clear", hash->final(), expected); - // TODO: feed in random pieces to fully test buffering if(input.size() > 5) { hash->update(input[0]); @@ -77,7 +76,17 @@ class Hash_Function_Tests final : public Text_Based_Test // verify fork copy doesn't affect original computation fork->update(&input[1], input.size() - 2); - hash->update(&input[1], input.size() - 1); + size_t so_far = 1; + while(so_far < input.size()) + { + size_t take = Test::rng().next_byte() % (input.size() - so_far); + + if(input.size() - so_far == 1) + take = 1; + + hash->update(&input[so_far], take); + so_far += take; + } result.test_eq(provider, "hashing split", hash->final(), expected); fork->update(&input[input.size() - 1], 1); diff --git a/src/tests/test_mac.cpp b/src/tests/test_mac.cpp index f4e3e4268..18ba82b30 100644 --- a/src/tests/test_mac.cpp +++ b/src/tests/test_mac.cpp @@ -59,6 +59,17 @@ class Message_Auth_Tests final : public Text_Based_Test result.test_is_nonempty("provider", provider); result.test_eq(provider, mac->name(), algo); + try + { + std::vector<uint8_t> buf(128); + mac->update(buf.data(), buf.size()); + result.test_failure("Was able to MAC without a key being set"); + } + catch(Botan::Invalid_State&) + { + result.test_success("Trying to MAC with no key set fails"); + } + mac->set_key(key); mac->start(iv); @@ -108,6 +119,30 @@ class Message_Auth_Tests final : public Text_Based_Test result.test_eq(provider + " split mac", mac->verify_mac(expected.data(), expected.size()), true); } + + mac->clear(); + + try + { + std::vector<uint8_t> buf(128); + mac->update(buf.data(), buf.size()); + result.test_failure("Was able to MAC without a key being set"); + } + catch(Botan::Invalid_State&) + { + result.test_success("Trying to MAC with no key set (after clear) fails"); + } + + try + { + std::vector<uint8_t> buf(mac->output_length()); + mac->final(buf.data()); + result.test_failure("Was able to MAC without a key being set"); + } + catch(Botan::Invalid_State&) + { + result.test_success("Trying to MAC with no key set (after clear) fails"); + } } return result; diff --git a/src/tests/test_stream.cpp b/src/tests/test_stream.cpp index 50012fe97..357b8c769 100644 --- a/src/tests/test_stream.cpp +++ b/src/tests/test_stream.cpp @@ -56,6 +56,18 @@ class Stream_Cipher_Tests final : public Text_Based_Test const std::string provider(cipher->provider()); result.test_is_nonempty("provider", provider); result.test_eq(provider, cipher->name(), algo); + + try + { + std::vector<uint8_t> buf(128); + cipher->cipher1(buf.data(), buf.size()); + result.test_failure("Was able to encrypt without a key being set"); + } + catch(Botan::Invalid_State&) + { + result.test_success("Trying to encrypt with no key set fails"); + } + cipher->set_key(key); if(nonce.size()) @@ -96,6 +108,17 @@ class Stream_Cipher_Tests final : public Text_Based_Test cipher->clear(); + try + { + std::vector<uint8_t> buf(128); + cipher->cipher1(buf.data(), buf.size()); + result.test_failure("Was able to encrypt without a key being set (after clear)"); + } + catch(Botan::Invalid_State&) + { + result.test_success("Trying to encrypt with no key set (after clear) fails"); + } + result.test_eq(provider, "encrypt", buf, expected); } |