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