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

randombit / botan / 20579846577

29 Dec 2025 06:24PM UTC coverage: 90.415% (+0.2%) from 90.243%
20579846577

push

github

web-flow
Merge pull request #5167 from randombit/jack/src-size-reductions

Changes to reduce unnecessary inclusions

101523 of 112285 relevant lines covered (90.42%)

12817276.56 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/rng.h>
11
   #include <botan/stream_cipher.h>
12
   #include <botan/internal/fmt.h>
13
#endif
14

15
namespace Botan_Tests {
16

17
#if defined(BOTAN_HAS_STREAM_CIPHER)
18

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

215
#endif
216

217
}  // 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