• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 21786344715

07 Feb 2026 08:25PM UTC coverage: 90.068% (-0.005%) from 90.073%
21786344715

Pull #5295

github

web-flow
Merge 8d5fc3b23 into ebf8f0044
Pull Request #5295: Reduce header dependencies in tests and cli

102234 of 113507 relevant lines covered (90.07%)

11372278.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.98
/src/tests/test_stream.cpp
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/exceptn.h>
11
   #include <botan/rng.h>
12
   #include <botan/stream_cipher.h>
13
   #include <botan/internal/fmt.h>
14
#endif
15

16
namespace Botan_Tests {
17

18
#if defined(BOTAN_HAS_STREAM_CIPHER)
19

20
class Stream_Cipher_Tests final : public Text_Based_Test {
×
21
   public:
22
      Stream_Cipher_Tests() : Text_Based_Test("stream", "Key,Out", "In,Nonce,Seek") {}
2✔
23

24
      Test::Result run_one_test(const std::string& algo, const VarMap& vars) override {
3,538✔
25
         const std::vector<uint8_t> key = vars.get_req_bin("Key");
3,538✔
26
         const std::vector<uint8_t> expected = vars.get_req_bin("Out");
3,538✔
27
         const std::vector<uint8_t> nonce = vars.get_opt_bin("Nonce");
3,538✔
28
         const uint64_t seek = vars.get_opt_u64("Seek", 0);
3,538✔
29
         std::vector<uint8_t> input = vars.get_opt_bin("In");
3,538✔
30

31
         if(input.empty()) {
3,538✔
32
            input.resize(expected.size());
2,664✔
33
         }
34

35
         Test::Result result(algo);
7,076✔
36

37
         const std::vector<std::string> providers = provider_filter(Botan::StreamCipher::providers(algo));
3,538✔
38

39
         if(providers.empty()) {
3,538✔
40
            result.note_missing("stream cipher " + algo);
1✔
41
            return result;
1✔
42
         }
43

44
         for(const auto& provider_ask : providers) {
7,074✔
45
            auto cipher = Botan::StreamCipher::create(algo, provider_ask);
3,537✔
46

47
            if(!cipher) {
3,537✔
48
               result.test_failure(Botan::fmt("Stream cipher {} supported by {} but not found", algo, provider_ask));
×
49
               continue;
×
50
            }
51

52
            const std::string provider(cipher->provider());
3,537✔
53
            result.test_is_nonempty("provider", provider);
3,537✔
54
            result.test_eq(provider, cipher->name(), algo);
3,537✔
55

56
            result.confirm("default iv length is valid", cipher->valid_iv_length(cipher->default_iv_length()));
7,074✔
57

58
            result.confirm("advertised buffer size is > 0", cipher->buffer_size() > 0);
7,074✔
59

60
            if(cipher->default_iv_length() == 0) {
3,537✔
61
               result.confirm("if default iv length is zero, no iv supported", nonce.empty());
4,730✔
62

63
               // This should still succeed
64
               cipher->set_iv(nullptr, 0);
2,365✔
65
            }
66

67
            try {
3,537✔
68
               std::vector<uint8_t> buf(128);
3,537✔
69
               cipher->cipher1(buf.data(), buf.size());
3,537✔
70
               result.test_failure("Was able to encrypt without a key being set");
3,537✔
71
            } catch(Botan::Invalid_State&) {
3,537✔
72
               result.test_success("Trying to encrypt with no key set fails");
3,537✔
73
            }
3,537✔
74

75
            try {
3,537✔
76
               cipher->seek(0);
3,537✔
77
               result.test_failure("Was able to seek without a key being set");
×
78
            } catch(Botan::Invalid_State&) {
3,537✔
79
               result.test_success("Trying to seek with no key set fails");
1,155✔
80
            } catch(Botan::Not_Implemented&) {
3,537✔
81
               result.test_success("Trying to seek failed because not implemented");
2,382✔
82
            }
2,382✔
83

84
            if(!cipher->valid_iv_length(nonce.size())) {
3,537✔
85
               throw Test_Error("Invalid nonce for " + algo);
×
86
            }
87

88
            bool accepted_nonce_early = false;
3,537✔
89
            if(!nonce.empty()) {
3,537✔
90
               try {
1,168✔
91
                  cipher->set_iv(nonce.data(), nonce.size());
1,168✔
92
                  accepted_nonce_early = true;
93
               } catch(Botan::Invalid_State&) {}
1,168✔
94
            }
95

96
            /*
97
            * Different providers may have additional restrictions on key sizes.
98
            * Avoid testing the cipher with a key size that it does not natively support.
99
            */
100
            if(!cipher->valid_keylength(key.size())) {
3,537✔
101
               result.test_note("Skipping test with provider " + provider + " as it does not support key length " +
×
102
                                std::to_string(key.size()));
×
103
               continue;
×
104
            }
105

106
            result.test_eq("key not set", cipher->has_keying_material(), false);
3,537✔
107
            cipher->set_key(key);
3,537✔
108
            result.test_eq("key set", cipher->has_keying_material(), true);
3,537✔
109

110
            /*
111
            Test invalid nonce sizes. this assumes no implemented cipher supports a nonce of 65000
112
            */
113
            const size_t large_nonce_size = 65000;
3,537✔
114
            result.confirm("Stream cipher does not support very large nonce",
7,074✔
115
                           cipher->valid_iv_length(large_nonce_size) == false);
3,537✔
116

117
            result.test_throws("Throws if invalid nonce size given",
7,074✔
118
                               [&]() { cipher->set_iv(nullptr, large_nonce_size); });
7,074✔
119

120
            /*
121
            If the set_nonce call earlier succeeded, then we require that it also
122
            worked (ie saved the nonce for later use) even though the key was
123
            not set. So, don't set the nonce now, to ensure the previous call
124
            had an effect.
125
            */
126
            if(!nonce.empty() && accepted_nonce_early == false) {
3,537✔
127
               cipher->set_iv(nonce.data(), nonce.size());
1,168✔
128
            }
129

130
            if(seek != 0) {
3,537✔
131
               cipher->seek(seek);
626✔
132
            }
133

134
            // Test that clone works and does not affect parent object
135
            auto clone = cipher->new_object();
3,537✔
136
            result.confirm("Clone has different pointer", cipher.get() != clone.get());
7,074✔
137
            result.test_eq("Clone has same name", cipher->name(), clone->name());
7,074✔
138
            clone->set_key(this->rng().random_vec(cipher->maximum_keylength()));
3,537✔
139

140
            {
3,537✔
141
               std::vector<uint8_t> buf = input;
3,537✔
142
               cipher->encrypt(buf);
3,537✔
143
               result.test_eq(provider, "encrypt", buf, expected);
7,074✔
144
            }
×
145

146
            {
3,537✔
147
               if(nonce.empty()) {
3,537✔
148
                  cipher->set_key(key);
2,369✔
149
               } else {
150
                  cipher->set_iv(nonce.data(), nonce.size());
1,168✔
151
               }
152
               if(seek != 0) {
3,537✔
153
                  cipher->seek(seek);
626✔
154
               }
155
               std::vector<uint8_t> buf = input;
3,537✔
156
               cipher->encrypt(buf);
3,537✔
157
               result.test_eq(provider, "encrypt 2", buf, expected);
7,074✔
158
            }
×
159

160
            if(!nonce.empty()) {
3,537✔
161
               cipher->set_iv(nonce.data(), nonce.size());
1,168✔
162
               if(seek != 0) {
1,168✔
163
                  cipher->seek(seek);
626✔
164
               }
165
               std::vector<uint8_t> buf = input;
1,168✔
166
               cipher->encrypt(buf);
1,168✔
167
               result.test_eq(provider, "second encrypt", buf, expected);
2,336✔
168
            }
1,168✔
169

170
            {
3,537✔
171
               cipher->set_key(key);
3,537✔
172

173
               cipher->set_iv(nonce.data(), nonce.size());
3,537✔
174

175
               if(seek != 0) {
3,537✔
176
                  cipher->seek(seek);
626✔
177
               }
178

179
               std::vector<uint8_t> buf(input.size(), 0xAB);
3,537✔
180

181
               uint8_t* buf_ptr = buf.data();
3,537✔
182
               size_t buf_len = buf.size();
3,537✔
183

184
               while(buf_len > 0) {
8,940✔
185
                  const size_t next = std::min<size_t>(buf_len, this->rng().next_byte());
5,403✔
186
                  cipher->write_keystream(buf_ptr, next);
5,403✔
187
                  buf_ptr += next;
5,403✔
188
                  buf_len -= next;
5,403✔
189
               }
190

191
               for(size_t i = 0; i != input.size(); ++i) {
340,721✔
192
                  buf[i] ^= input[i];
337,184✔
193
               }
194
               result.test_eq(provider, "write_keystream", buf, expected);
7,074✔
195
            }
×
196

197
            result.test_eq("key set", cipher->has_keying_material(), true);
3,537✔
198
            cipher->clear();
3,537✔
199
            result.test_eq("key not set", cipher->has_keying_material(), false);
3,537✔
200

201
            try {
3,537✔
202
               std::vector<uint8_t> buf(128);
3,537✔
203
               cipher->cipher1(buf.data(), buf.size());
3,537✔
204
               result.test_failure("Was able to encrypt without a key being set (after clear)");
3,537✔
205
            } catch(Botan::Invalid_State&) {
3,537✔
206
               result.test_success("Trying to encrypt with no key set (after clear) fails");
3,537✔
207
            }
3,537✔
208
         }
7,074✔
209

210
         return result;
211
      }
15,321✔
212
};
213

214
BOTAN_REGISTER_SERIALIZED_SMOKE_TEST("stream", "stream_ciphers", Stream_Cipher_Tests);
215

216
#endif
217

218
}  // namespace Botan_Tests
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc