1 /* 2 * (C) 2014,2015,2016 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_STREAM_CIPHER) 10 #include <botan/stream_cipher.h> 11 #endif 12 13 namespace Botan_Tests { 14 15 #if defined(BOTAN_HAS_STREAM_CIPHER) 16 17 class Stream_Cipher_Tests final : public Text_Based_Test 18 { 19 public: Stream_Cipher_Tests()20 Stream_Cipher_Tests(): Text_Based_Test("stream", "Key,Out", "In,Nonce,Seek") {} 21 run_one_test(const std::string & algo,const VarMap & vars)22 Test::Result run_one_test(const std::string& algo, const VarMap& vars) override 23 { 24 const std::vector<uint8_t> key = vars.get_req_bin("Key"); 25 const std::vector<uint8_t> expected = vars.get_req_bin("Out"); 26 const std::vector<uint8_t> nonce = vars.get_opt_bin("Nonce"); 27 const uint64_t seek = vars.get_opt_u64("Seek", 0); 28 std::vector<uint8_t> input = vars.get_opt_bin("In"); 29 30 if(input.empty()) 31 { 32 input.resize(expected.size()); 33 } 34 35 Test::Result result(algo); 36 37 const std::vector<std::string> providers = 38 provider_filter(Botan::StreamCipher::providers(algo)); 39 40 if(providers.empty()) 41 { 42 result.note_missing("stream cipher " + algo); 43 return result; 44 } 45 46 for(auto const& provider_ask : providers) 47 { 48 std::unique_ptr<Botan::StreamCipher> cipher(Botan::StreamCipher::create(algo, provider_ask)); 49 50 if(!cipher) 51 { 52 result.test_failure("Stream " + algo + " supported by " + provider_ask + " but not found"); 53 continue; 54 } 55 56 const std::string provider(cipher->provider()); 57 result.test_is_nonempty("provider", provider); 58 result.test_eq(provider, cipher->name(), algo); 59 60 result.confirm("default iv length is valid", cipher->valid_iv_length(cipher->default_iv_length())); 61 62 if(cipher->default_iv_length() == 0) 63 { 64 result.confirm("if default iv length is zero, no iv supported", nonce.size() == 0); 65 66 // This should still succeed 67 cipher->set_iv(nullptr, 0); 68 } 69 70 try 71 { 72 std::vector<uint8_t> buf(128); 73 cipher->cipher1(buf.data(), buf.size()); 74 result.test_failure("Was able to encrypt without a key being set"); 75 } 76 catch(Botan::Invalid_State&) 77 { 78 result.test_success("Trying to encrypt with no key set fails"); 79 } 80 81 try 82 { 83 cipher->seek(0); 84 result.test_failure("Was able to seek without a key being set"); 85 } 86 catch(Botan::Invalid_State&) 87 { 88 result.test_success("Trying to seek with no key set fails"); 89 } 90 catch(Botan::Not_Implemented&) 91 { 92 result.test_success("Trying to seek failed because not implemented"); 93 } 94 95 if(!cipher->valid_iv_length(nonce.size())) 96 { 97 throw Test_Error("Invalid nonce for " + algo); 98 } 99 100 bool accepted_nonce_early = false; 101 if(nonce.size() > 0) 102 { 103 try 104 { 105 cipher->set_iv(nonce.data(), nonce.size()); 106 accepted_nonce_early = true; 107 } 108 catch(Botan::Invalid_State&) {} 109 } 110 111 /* 112 * Different providers may have additional restrictions on key sizes. 113 * Avoid testing the cipher with a key size that it does not natively support. 114 */ 115 if(!cipher->valid_keylength(key.size())) 116 { 117 result.test_note("Skipping test with provider " + provider + 118 " as it does not support key length " + std::to_string(key.size())); 119 continue; 120 } 121 122 cipher->set_key(key); 123 124 /* 125 Test invalid nonce sizes. this assumes no implemented cipher supports a nonce of 65000 126 */ 127 const size_t large_nonce_size = 65000; 128 result.confirm("Stream cipher does not support very large nonce", cipher->valid_iv_length(large_nonce_size) == false); 129 130 result.test_throws("Throws if invalid nonce size given", 131 [&]() { cipher->set_iv(nullptr, large_nonce_size); }); 132 133 /* 134 If the set_nonce call earlier succeded, then we require that it also 135 worked (ie saved the nonce for later use) even though the key was 136 not set. So, don't set the nonce now, to ensure the previous call 137 had an effect. 138 */ 139 if(nonce.size() > 0 && accepted_nonce_early == false) 140 { 141 cipher->set_iv(nonce.data(), nonce.size()); 142 } 143 144 if(seek != 0) 145 { 146 cipher->seek(seek); 147 } 148 149 // Test that clone works and does not affect parent object 150 std::unique_ptr<Botan::StreamCipher> clone(cipher->clone()); 151 result.confirm("Clone has different pointer", cipher.get() != clone.get()); 152 result.test_eq("Clone has same name", cipher->name(), clone->name()); 153 clone->set_key(Test::rng().random_vec(cipher->maximum_keylength())); 154 155 { 156 std::vector<uint8_t> buf = input; 157 cipher->encrypt(buf); 158 result.test_eq(provider, "encrypt", buf, expected); 159 } 160 161 if(nonce.size() > 0) 162 { 163 std::vector<uint8_t> buf = input; 164 cipher->set_iv(nonce.data(), nonce.size()); 165 if(seek != 0) 166 cipher->seek(seek); 167 cipher->encrypt(buf); 168 result.test_eq(provider, "second encrypt", buf, expected); 169 } 170 171 cipher->clear(); 172 173 try 174 { 175 std::vector<uint8_t> buf(128); 176 cipher->cipher1(buf.data(), buf.size()); 177 result.test_failure("Was able to encrypt without a key being set (after clear)"); 178 } 179 catch(Botan::Invalid_State&) 180 { 181 result.test_success("Trying to encrypt with no key set (after clear) fails"); 182 } 183 } 184 185 return result; 186 } 187 }; 188 189 BOTAN_REGISTER_TEST("stream", "stream", Stream_Cipher_Tests); 190 191 #endif 192 193 } 194