1 /* 2 * (C) 2014,2015 Jack Lloyd 3 * 4 * Botan is released under the Simplified BSD License (see license.txt) 5 */ 6 7 #include "tests.h" 8 9 #if defined(BOTAN_HAS_BLOCK_CIPHER) 10 11 #include <botan/block_cipher.h> 12 13 namespace Botan_Tests { 14 15 class Block_Cipher_Tests final : public Text_Based_Test 16 { 17 public: Block_Cipher_Tests()18 Block_Cipher_Tests() : Text_Based_Test("block", "Key,In,Out", "Tweak,Iterations") {} 19 possible_providers(const std::string & algo)20 std::vector<std::string> possible_providers(const std::string& algo) override 21 { 22 return provider_filter(Botan::BlockCipher::providers(algo)); 23 } 24 run_one_test(const std::string & algo,const VarMap & vars)25 Test::Result run_one_test(const std::string& algo, const VarMap& vars) override 26 { 27 const std::vector<uint8_t> key = vars.get_req_bin("Key"); 28 const std::vector<uint8_t> input = vars.get_req_bin("In"); 29 const std::vector<uint8_t> expected = vars.get_req_bin("Out"); 30 const std::vector<uint8_t> tweak = vars.get_opt_bin("Tweak"); 31 const size_t iterations = vars.get_opt_sz("Iterations", 1); 32 33 Test::Result result(algo); 34 35 if(iterations > 1 && run_long_tests() == false) 36 { 37 return result; 38 } 39 40 const std::vector<std::string> providers = possible_providers(algo); 41 42 if(providers.empty()) 43 { 44 result.note_missing("block cipher " + algo); 45 return result; 46 } 47 48 for(auto const& provider_ask : providers) 49 { 50 std::unique_ptr<Botan::BlockCipher> cipher(Botan::BlockCipher::create(algo, provider_ask)); 51 52 if(!cipher) 53 { 54 result.test_failure("Cipher " + algo + " supported by " + provider_ask + " but not found"); 55 continue; 56 } 57 58 const std::string provider(cipher->provider()); 59 result.test_is_nonempty("provider", provider); 60 result.test_eq(provider, cipher->name(), algo); 61 result.test_gte(provider, cipher->parallelism(), 1); 62 result.test_gte(provider, cipher->block_size(), 8); 63 result.test_gte(provider, cipher->parallel_bytes(), cipher->block_size() * cipher->parallelism()); 64 65 // Test that trying to encrypt or decrypt with now key set throws Botan::Invalid_State 66 try 67 { 68 std::vector<uint8_t> block(cipher->block_size()); 69 cipher->encrypt(block); 70 result.test_failure("Was able to encrypt without a key being set"); 71 } 72 catch(Botan::Invalid_State&) 73 { 74 result.test_success("Trying to encrypt with no key set fails"); 75 } 76 77 try 78 { 79 std::vector<uint8_t> block(cipher->block_size()); 80 cipher->decrypt(block); 81 result.test_failure("Was able to decrypt without a key being set"); 82 } 83 catch(Botan::Invalid_State&) 84 { 85 result.test_success("Trying to encrypt with no key set fails"); 86 } 87 88 // Test to make sure clear() resets what we need it to 89 cipher->set_key(Test::rng().random_vec(cipher->key_spec().maximum_keylength())); 90 Botan::secure_vector<uint8_t> garbage = Test::rng().random_vec(cipher->block_size()); 91 cipher->encrypt(garbage); 92 cipher->clear(); 93 94 /* 95 * Different providers may have additional restrictions on key sizes. 96 * Avoid testing the cipher with a key size that it does not natively support. 97 */ 98 if(!cipher->valid_keylength(key.size())) 99 { 100 result.test_note("Skipping test with provider " + provider + 101 " as it does not support key length " + std::to_string(key.size())); 102 continue; 103 } 104 105 cipher->set_key(key); 106 107 if(tweak.size() > 0) 108 { 109 Botan::Tweakable_Block_Cipher* tbc = dynamic_cast<Botan::Tweakable_Block_Cipher*>(cipher.get()); 110 if(tbc == nullptr) 111 result.test_failure("Tweak set in test data but cipher is not a Tweakable_Block_Cipher"); 112 else 113 tbc->set_tweak(tweak.data(), tweak.size()); 114 } 115 116 // Test that clone works and does not affect parent object 117 std::unique_ptr<Botan::BlockCipher> clone(cipher->clone()); 118 result.confirm("Clone has different pointer", cipher.get() != clone.get()); 119 result.test_eq("Clone has same name", cipher->name(), clone->name()); 120 clone->set_key(Test::rng().random_vec(cipher->maximum_keylength())); 121 122 // have called set_key on clone: process input values 123 std::vector<uint8_t> buf = input; 124 125 for(size_t i = 0; i != iterations; ++i) 126 { 127 cipher->encrypt(buf); 128 } 129 130 result.test_eq(provider, "encrypt", buf, expected); 131 132 // always decrypt expected ciphertext vs what we produced above 133 buf = expected; 134 135 for(size_t i = 0; i != iterations; ++i) 136 { 137 cipher->decrypt(buf); 138 } 139 140 result.test_eq(provider, "decrypt", buf, input); 141 142 // Now test misaligned buffers 143 const size_t blocks = input.size() / cipher->block_size(); 144 buf.resize(input.size() + 1); 145 Botan::copy_mem(buf.data() + 1, input.data(), input.size()); 146 147 for(size_t i = 0; i != iterations; ++i) 148 { 149 cipher->encrypt_n(buf.data() + 1, buf.data() + 1, blocks); 150 } 151 152 result.test_eq(provider.c_str(), "encrypt misaligned", 153 buf.data() + 1, buf.size() - 1, 154 expected.data(), expected.size()); 155 156 // always decrypt expected ciphertext vs what we produced above 157 Botan::copy_mem(buf.data() + 1, expected.data(), expected.size()); 158 159 for(size_t i = 0; i != iterations; ++i) 160 { 161 cipher->decrypt_n(buf.data() + 1, buf.data() + 1, blocks); 162 } 163 164 result.test_eq(provider.c_str(), "decrypt misaligned", 165 buf.data() + 1, buf.size() - 1, 166 input.data(), input.size()); 167 168 cipher->clear(); 169 170 try 171 { 172 std::vector<uint8_t> block(cipher->block_size()); 173 cipher->encrypt(block); 174 result.test_failure("Was able to encrypt without a key being set"); 175 } 176 catch(Botan::Invalid_State&) 177 { 178 result.test_success("Trying to encrypt with no key set (after clear) fails"); 179 } 180 181 try 182 { 183 std::vector<uint8_t> block(cipher->block_size()); 184 cipher->decrypt(block); 185 result.test_failure("Was able to decrypt without a key being set"); 186 } 187 catch(Botan::Invalid_State&) 188 { 189 result.test_success("Trying to decrypt with no key set (after clear) fails"); 190 } 191 192 } 193 194 return result; 195 } 196 197 }; 198 199 BOTAN_REGISTER_TEST("block", "block", Block_Cipher_Tests); 200 201 } 202 203 #endif 204