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

randombit / botan / 26703548991

30 May 2026 09:57PM UTC coverage: 89.37% (+0.009%) from 89.361%
26703548991

push

github

web-flow
Merge pull request #5629 from randombit/jack/pwhash-limit-mem

In Argon2 and Scrypt provide some reasonable upper bound on memory consumption

110243 of 123356 relevant lines covered (89.37%)

11053253.82 hits per line

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

98.53
/src/lib/stream/salsa20/salsa20.cpp
1
/*
2
* Salsa20 / XSalsa20
3
* (C) 1999-2010,2014 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/internal/salsa20.h>
9

10
#include <botan/exceptn.h>
11
#include <botan/internal/loadstor.h>
12
#include <botan/internal/rotate.h>
13

14
namespace Botan {
15

16
namespace {
17

18
inline void salsa20_quarter_round(uint32_t& x1, uint32_t& x2, uint32_t& x3, uint32_t& x4) {
445,141,118✔
19
   x2 ^= rotl<7>(x1 + x4);
445,141,118✔
20
   x3 ^= rotl<9>(x2 + x1);
445,141,118✔
21
   x4 ^= rotl<13>(x3 + x2);
445,141,118✔
22
   x1 ^= rotl<18>(x4 + x3);
445,141,118✔
23
}
24

25
}  // namespace
26

27
/*
28
* Generate HSalsa20 cipher stream (for XSalsa20 IV setup)
29
*/
30
//static
31
void Salsa20::hsalsa20(uint32_t output[8], const uint32_t input[16]) {
38✔
32
   uint32_t x00 = input[0];
38✔
33
   uint32_t x01 = input[1];
38✔
34
   uint32_t x02 = input[2];
38✔
35
   uint32_t x03 = input[3];
38✔
36
   uint32_t x04 = input[4];
38✔
37
   uint32_t x05 = input[5];
38✔
38
   uint32_t x06 = input[6];
38✔
39
   uint32_t x07 = input[7];
38✔
40
   uint32_t x08 = input[8];
38✔
41
   uint32_t x09 = input[9];
38✔
42
   uint32_t x10 = input[10];
38✔
43
   uint32_t x11 = input[11];
38✔
44
   uint32_t x12 = input[12];
38✔
45
   uint32_t x13 = input[13];
38✔
46
   uint32_t x14 = input[14];
38✔
47
   uint32_t x15 = input[15];
38✔
48

49
   for(size_t i = 0; i != 10; ++i) {
418✔
50
      salsa20_quarter_round(x00, x04, x08, x12);
380✔
51
      salsa20_quarter_round(x05, x09, x13, x01);
380✔
52
      salsa20_quarter_round(x10, x14, x02, x06);
380✔
53
      salsa20_quarter_round(x15, x03, x07, x11);
380✔
54

55
      salsa20_quarter_round(x00, x01, x02, x03);
380✔
56
      salsa20_quarter_round(x05, x06, x07, x04);
380✔
57
      salsa20_quarter_round(x10, x11, x08, x09);
380✔
58
      salsa20_quarter_round(x15, x12, x13, x14);
380✔
59
   }
60

61
   output[0] = x00;
38✔
62
   output[1] = x05;
38✔
63
   output[2] = x10;
38✔
64
   output[3] = x15;
38✔
65
   output[4] = x06;
38✔
66
   output[5] = x07;
38✔
67
   output[6] = x08;
38✔
68
   output[7] = x09;
38✔
69
}
38✔
70

71
/*
72
* Generate Salsa20 cipher stream
73
*/
74
//static
75
void Salsa20::salsa_core(uint8_t output[64], const uint32_t input[16], size_t rounds) {
111,284,733✔
76
   BOTAN_ASSERT_NOMSG(rounds % 2 == 0);
111,284,733✔
77

78
   uint32_t x00 = input[0];
111,284,733✔
79
   uint32_t x01 = input[1];
111,284,733✔
80
   uint32_t x02 = input[2];
111,284,733✔
81
   uint32_t x03 = input[3];
111,284,733✔
82
   uint32_t x04 = input[4];
111,284,733✔
83
   uint32_t x05 = input[5];
111,284,733✔
84
   uint32_t x06 = input[6];
111,284,733✔
85
   uint32_t x07 = input[7];
111,284,733✔
86
   uint32_t x08 = input[8];
111,284,733✔
87
   uint32_t x09 = input[9];
111,284,733✔
88
   uint32_t x10 = input[10];
111,284,733✔
89
   uint32_t x11 = input[11];
111,284,733✔
90
   uint32_t x12 = input[12];
111,284,733✔
91
   uint32_t x13 = input[13];
111,284,733✔
92
   uint32_t x14 = input[14];
111,284,733✔
93
   uint32_t x15 = input[15];
111,284,733✔
94

95
   for(size_t i = 0; i != rounds / 2; ++i) {
556,425,471✔
96
      salsa20_quarter_round(x00, x04, x08, x12);
445,140,738✔
97
      salsa20_quarter_round(x05, x09, x13, x01);
445,140,738✔
98
      salsa20_quarter_round(x10, x14, x02, x06);
445,140,738✔
99
      salsa20_quarter_round(x15, x03, x07, x11);
445,140,738✔
100

101
      salsa20_quarter_round(x00, x01, x02, x03);
445,140,738✔
102
      salsa20_quarter_round(x05, x06, x07, x04);
445,140,738✔
103
      salsa20_quarter_round(x10, x11, x08, x09);
445,140,738✔
104
      salsa20_quarter_round(x15, x12, x13, x14);
445,140,738✔
105
   }
106

107
   store_le(x00 + input[0], output + 4 * 0);
111,284,733✔
108
   store_le(x01 + input[1], output + 4 * 1);
111,284,733✔
109
   store_le(x02 + input[2], output + 4 * 2);
111,284,733✔
110
   store_le(x03 + input[3], output + 4 * 3);
111,284,733✔
111
   store_le(x04 + input[4], output + 4 * 4);
111,284,733✔
112
   store_le(x05 + input[5], output + 4 * 5);
111,284,733✔
113
   store_le(x06 + input[6], output + 4 * 6);
111,284,733✔
114
   store_le(x07 + input[7], output + 4 * 7);
111,284,733✔
115
   store_le(x08 + input[8], output + 4 * 8);
111,284,733✔
116
   store_le(x09 + input[9], output + 4 * 9);
111,284,733✔
117
   store_le(x10 + input[10], output + 4 * 10);
111,284,733✔
118
   store_le(x11 + input[11], output + 4 * 11);
111,284,733✔
119
   store_le(x12 + input[12], output + 4 * 12);
111,284,733✔
120
   store_le(x13 + input[13], output + 4 * 13);
111,284,733✔
121
   store_le(x14 + input[14], output + 4 * 14);
111,284,733✔
122
   store_le(x15 + input[15], output + 4 * 15);
111,284,733✔
123
}
111,284,733✔
124

125
/*
126
* Combine cipher stream with message
127
*/
128
void Salsa20::cipher_bytes(const uint8_t in[], uint8_t out[], size_t length) {
124✔
129
   assert_key_material_set();
124✔
130

131
   while(length >= m_buffer.size() - m_position) {
334✔
132
      const size_t available = m_buffer.size() - m_position;
110✔
133

134
      xor_buf(out, in, &m_buffer[m_position], available);
110✔
135
      salsa_core(m_buffer.data(), m_state.data(), 20);
110✔
136

137
      ++m_state[8];
110✔
138
      if(m_state[8] == 0) {
110✔
139
         m_state[9] += 1;
×
140
      }
141

142
      length -= available;
110✔
143
      in += available;
110✔
144
      out += available;
110✔
145

146
      m_position = 0;
110✔
147
   }
148

149
   xor_buf(out, in, &m_buffer[m_position], length);
100✔
150

151
   m_position += length;
100✔
152
}
100✔
153

154
void Salsa20::initialize_state() {
142✔
155
   static const uint32_t TAU[] = {0x61707865, 0x3120646e, 0x79622d36, 0x6b206574};
142✔
156

157
   static const uint32_t SIGMA[] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
142✔
158

159
   m_state[1] = m_key[0];
142✔
160
   m_state[2] = m_key[1];
142✔
161
   m_state[3] = m_key[2];
142✔
162
   m_state[4] = m_key[3];
142✔
163

164
   if(m_key.size() == 4) {
142✔
165
      m_state[0] = TAU[0];
13✔
166
      m_state[5] = TAU[1];
13✔
167
      m_state[10] = TAU[2];
13✔
168
      m_state[15] = TAU[3];
13✔
169
      m_state[11] = m_key[0];
13✔
170
      m_state[12] = m_key[1];
13✔
171
      m_state[13] = m_key[2];
13✔
172
      m_state[14] = m_key[3];
13✔
173
   } else {
174
      m_state[0] = SIGMA[0];
129✔
175
      m_state[5] = SIGMA[1];
129✔
176
      m_state[10] = SIGMA[2];
129✔
177
      m_state[15] = SIGMA[3];
129✔
178
      m_state[11] = m_key[4];
129✔
179
      m_state[12] = m_key[5];
129✔
180
      m_state[13] = m_key[6];
129✔
181
      m_state[14] = m_key[7];
129✔
182
   }
183

184
   m_state[6] = 0;
142✔
185
   m_state[7] = 0;
142✔
186
   m_state[8] = 0;
142✔
187
   m_state[9] = 0;
142✔
188

189
   m_position = 0;
142✔
190
}
142✔
191

192
bool Salsa20::has_keying_material() const {
398✔
193
   return !m_state.empty();
398✔
194
}
195

196
size_t Salsa20::buffer_size() const {
12✔
197
   return 64;
12✔
198
}
199

200
/*
201
* Salsa20 Key Schedule
202
*/
203
void Salsa20::key_schedule(std::span<const uint8_t> key) {
65✔
204
   m_key.resize(key.size() / 4);
65✔
205
   load_le<uint32_t>(m_key.data(), key.data(), m_key.size());
65✔
206

207
   m_state.resize(16);
65✔
208
   m_buffer.resize(64);
65✔
209

210
   set_iv(nullptr, 0);
65✔
211
}
65✔
212

213
/*
214
* Set the Salsa IV
215
*/
216
void Salsa20::set_iv_bytes(const uint8_t iv[], size_t length) {
165✔
217
   assert_key_material_set();
165✔
218

219
   if(!valid_iv_length(length)) {
308✔
220
      throw Invalid_IV_Length(name(), length);
24✔
221
   }
222

223
   initialize_state();
142✔
224

225
   if(length == 0) {
142✔
226
      // Salsa20 null IV
227
      m_state[6] = 0;
66✔
228
      m_state[7] = 0;
66✔
229
   } else if(length == 8) {
76✔
230
      // Salsa20
231
      m_state[6] = load_le<uint32_t>(iv, 0);
42✔
232
      m_state[7] = load_le<uint32_t>(iv, 1);
42✔
233
   } else {
234
      // XSalsa20
235
      m_state[6] = load_le<uint32_t>(iv, 0);
34✔
236
      m_state[7] = load_le<uint32_t>(iv, 1);
34✔
237
      m_state[8] = load_le<uint32_t>(iv, 2);
34✔
238
      m_state[9] = load_le<uint32_t>(iv, 3);
34✔
239

240
      secure_vector<uint32_t> hsalsa(8);
34✔
241
      hsalsa20(hsalsa.data(), m_state.data());
34✔
242

243
      m_state[1] = hsalsa[0];
34✔
244
      m_state[2] = hsalsa[1];
34✔
245
      m_state[3] = hsalsa[2];
34✔
246
      m_state[4] = hsalsa[3];
34✔
247
      m_state[6] = load_le<uint32_t>(iv, 4);
34✔
248
      m_state[7] = load_le<uint32_t>(iv, 5);
34✔
249
      m_state[11] = hsalsa[4];
34✔
250
      m_state[12] = hsalsa[5];
34✔
251
      m_state[13] = hsalsa[6];
34✔
252
      m_state[14] = hsalsa[7];
34✔
253
   }
34✔
254

255
   m_state[8] = 0;
142✔
256
   m_state[9] = 0;
142✔
257

258
   salsa_core(m_buffer.data(), m_state.data(), 20);
142✔
259
   ++m_state[8];
142✔
260
   if(m_state[8] == 0) {
142✔
261
      m_state[9] += 1;
×
262
   }
263

264
   m_position = 0;
142✔
265
}
142✔
266

267
bool Salsa20::valid_iv_length(size_t iv_len) const {
190✔
268
   return (iv_len == 0 || iv_len == 8 || iv_len == 24);
190✔
269
}
270

271
size_t Salsa20::default_iv_length() const {
24✔
272
   return 24;
24✔
273
}
274

275
Key_Length_Specification Salsa20::key_spec() const {
101✔
276
   return Key_Length_Specification(16, 32, 16);
101✔
277
}
278

279
std::unique_ptr<StreamCipher> Salsa20::new_object() const {
16✔
280
   return std::make_unique<Salsa20>();
16✔
281
}
282

283
std::string Salsa20::name() const {
95✔
284
   return "Salsa20";
95✔
285
}
286

287
/*
288
* Clear memory of sensitive data
289
*/
290
void Salsa20::clear() {
12✔
291
   zap(m_key);
12✔
292
   zap(m_state);
12✔
293
   zap(m_buffer);
12✔
294
   m_position = 0;
12✔
295
}
12✔
296

297
void Salsa20::seek(uint64_t offset) {
61✔
298
   assert_key_material_set();
61✔
299

300
   const uint64_t counter = offset / 64;
49✔
301

302
   m_state[8] = static_cast<uint32_t>(counter);
49✔
303
   m_state[9] = static_cast<uint32_t>(counter >> 32);
49✔
304

305
   salsa_core(m_buffer.data(), m_state.data(), 20);
49✔
306

307
   ++m_state[8];
49✔
308
   if(m_state[8] == 0) {
49✔
309
      m_state[9] += 1;
×
310
   }
311

312
   m_position = offset % 64;
49✔
313
}
49✔
314
}  // namespace Botan
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