Coverage Report

Created: 2022-08-24 06:37

/src/botan/src/lib/stream/salsa20/salsa20.cpp
Line
Count
Source (jump to first uncovered line)
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
#include <botan/exceptn.h>
10
#include <botan/internal/loadstor.h>
11
#include <botan/internal/rotate.h>
12
13
namespace Botan {
14
15
namespace {
16
17
inline void salsa20_quarter_round(uint32_t& x1,
18
                                  uint32_t& x2,
19
                                  uint32_t& x3,
20
                                  uint32_t& x4)
21
0
   {
22
0
   x2 ^= rotl<7>(x1 + x4);
23
0
   x3 ^= rotl<9>(x2 + x1);
24
0
   x4 ^= rotl<13>(x3 + x2);
25
0
   x1 ^= rotl<18>(x4 + x3);
26
0
   }
27
28
}
29
30
/*
31
* Generate HSalsa20 cipher stream (for XSalsa20 IV setup)
32
*/
33
//static
34
void Salsa20::hsalsa20(uint32_t output[8], const uint32_t input[16])
35
0
   {
36
0
   uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3],
37
0
            x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7],
38
0
            x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11],
39
0
            x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];
40
41
0
   for(size_t i = 0; i != 10; ++i)
42
0
      {
43
0
      salsa20_quarter_round(x00, x04, x08, x12);
44
0
      salsa20_quarter_round(x05, x09, x13, x01);
45
0
      salsa20_quarter_round(x10, x14, x02, x06);
46
0
      salsa20_quarter_round(x15, x03, x07, x11);
47
48
0
      salsa20_quarter_round(x00, x01, x02, x03);
49
0
      salsa20_quarter_round(x05, x06, x07, x04);
50
0
      salsa20_quarter_round(x10, x11, x08, x09);
51
0
      salsa20_quarter_round(x15, x12, x13, x14);
52
0
      }
53
54
0
   output[0] = x00;
55
0
   output[1] = x05;
56
0
   output[2] = x10;
57
0
   output[3] = x15;
58
0
   output[4] = x06;
59
0
   output[5] = x07;
60
0
   output[6] = x08;
61
0
   output[7] = x09;
62
0
   }
63
64
/*
65
* Generate Salsa20 cipher stream
66
*/
67
//static
68
void Salsa20::salsa_core(uint8_t output[64], const uint32_t input[16], size_t rounds)
69
0
   {
70
0
   BOTAN_ASSERT_NOMSG(rounds % 2 == 0);
71
72
0
   uint32_t x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3],
73
0
            x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7],
74
0
            x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11],
75
0
            x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];
76
77
0
   for(size_t i = 0; i != rounds / 2; ++i)
78
0
      {
79
0
      salsa20_quarter_round(x00, x04, x08, x12);
80
0
      salsa20_quarter_round(x05, x09, x13, x01);
81
0
      salsa20_quarter_round(x10, x14, x02, x06);
82
0
      salsa20_quarter_round(x15, x03, x07, x11);
83
84
0
      salsa20_quarter_round(x00, x01, x02, x03);
85
0
      salsa20_quarter_round(x05, x06, x07, x04);
86
0
      salsa20_quarter_round(x10, x11, x08, x09);
87
0
      salsa20_quarter_round(x15, x12, x13, x14);
88
0
      }
89
90
0
   store_le(x00 + input[ 0], output + 4 *  0);
91
0
   store_le(x01 + input[ 1], output + 4 *  1);
92
0
   store_le(x02 + input[ 2], output + 4 *  2);
93
0
   store_le(x03 + input[ 3], output + 4 *  3);
94
0
   store_le(x04 + input[ 4], output + 4 *  4);
95
0
   store_le(x05 + input[ 5], output + 4 *  5);
96
0
   store_le(x06 + input[ 6], output + 4 *  6);
97
0
   store_le(x07 + input[ 7], output + 4 *  7);
98
0
   store_le(x08 + input[ 8], output + 4 *  8);
99
0
   store_le(x09 + input[ 9], output + 4 *  9);
100
0
   store_le(x10 + input[10], output + 4 * 10);
101
0
   store_le(x11 + input[11], output + 4 * 11);
102
0
   store_le(x12 + input[12], output + 4 * 12);
103
0
   store_le(x13 + input[13], output + 4 * 13);
104
0
   store_le(x14 + input[14], output + 4 * 14);
105
0
   store_le(x15 + input[15], output + 4 * 15);
106
0
   }
107
108
/*
109
* Combine cipher stream with message
110
*/
111
void Salsa20::cipher(const uint8_t in[], uint8_t out[], size_t length)
112
0
   {
113
0
   verify_key_set(m_state.empty() == false);
114
115
0
   while(length >= m_buffer.size() - m_position)
116
0
      {
117
0
      const size_t available = m_buffer.size() - m_position;
118
119
0
      xor_buf(out, in, &m_buffer[m_position], available);
120
0
      salsa_core(m_buffer.data(), m_state.data(), 20);
121
122
0
      ++m_state[8];
123
0
      m_state[9] += (m_state[8] == 0);
124
125
0
      length -= available;
126
0
      in += available;
127
0
      out += available;
128
129
0
      m_position = 0;
130
0
      }
131
132
0
   xor_buf(out, in, &m_buffer[m_position], length);
133
134
0
   m_position += length;
135
0
   }
136
137
void Salsa20::initialize_state()
138
0
   {
139
0
   static const uint32_t TAU[] =
140
0
      { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 };
141
142
0
   static const uint32_t SIGMA[] =
143
0
      { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
144
145
0
   m_state[1] = m_key[0];
146
0
   m_state[2] = m_key[1];
147
0
   m_state[3] = m_key[2];
148
0
   m_state[4] = m_key[3];
149
150
0
   if(m_key.size() == 4)
151
0
      {
152
0
      m_state[0] = TAU[0];
153
0
      m_state[5] = TAU[1];
154
0
      m_state[10] = TAU[2];
155
0
      m_state[15] = TAU[3];
156
0
      m_state[11] = m_key[0];
157
0
      m_state[12] = m_key[1];
158
0
      m_state[13] = m_key[2];
159
0
      m_state[14] = m_key[3];
160
0
      }
161
0
   else
162
0
      {
163
0
      m_state[0] = SIGMA[0];
164
0
      m_state[5] = SIGMA[1];
165
0
      m_state[10] = SIGMA[2];
166
0
      m_state[15] = SIGMA[3];
167
0
      m_state[11] = m_key[4];
168
0
      m_state[12] = m_key[5];
169
0
      m_state[13] = m_key[6];
170
0
      m_state[14] = m_key[7];
171
0
      }
172
173
0
   m_state[6] = 0;
174
0
   m_state[7] = 0;
175
0
   m_state[8] = 0;
176
0
   m_state[9] = 0;
177
178
0
   m_position = 0;
179
0
   }
180
181
/*
182
* Salsa20 Key Schedule
183
*/
184
void Salsa20::key_schedule(const uint8_t key[], size_t length)
185
0
   {
186
0
   m_key.resize(length / 4);
187
0
   load_le<uint32_t>(m_key.data(), key, m_key.size());
188
189
0
   m_state.resize(16);
190
0
   m_buffer.resize(64);
191
192
0
   set_iv(nullptr, 0);
193
0
   }
194
195
/*
196
* Set the Salsa IV
197
*/
198
void Salsa20::set_iv(const uint8_t iv[], size_t length)
199
0
   {
200
0
   verify_key_set(m_state.empty() == false);
201
202
0
   if(!valid_iv_length(length))
203
0
      throw Invalid_IV_Length(name(), length);
204
205
0
   initialize_state();
206
207
0
   if(length == 0)
208
0
      {
209
      // Salsa20 null IV
210
0
      m_state[6] = 0;
211
0
      m_state[7] = 0;
212
0
      }
213
0
   else if(length == 8)
214
0
      {
215
      // Salsa20
216
0
      m_state[6] = load_le<uint32_t>(iv, 0);
217
0
      m_state[7] = load_le<uint32_t>(iv, 1);
218
0
      }
219
0
   else
220
0
      {
221
      // XSalsa20
222
0
      m_state[6] = load_le<uint32_t>(iv, 0);
223
0
      m_state[7] = load_le<uint32_t>(iv, 1);
224
0
      m_state[8] = load_le<uint32_t>(iv, 2);
225
0
      m_state[9] = load_le<uint32_t>(iv, 3);
226
227
0
      secure_vector<uint32_t> hsalsa(8);
228
0
      hsalsa20(hsalsa.data(), m_state.data());
229
230
0
      m_state[ 1] = hsalsa[0];
231
0
      m_state[ 2] = hsalsa[1];
232
0
      m_state[ 3] = hsalsa[2];
233
0
      m_state[ 4] = hsalsa[3];
234
0
      m_state[ 6] = load_le<uint32_t>(iv, 4);
235
0
      m_state[ 7] = load_le<uint32_t>(iv, 5);
236
0
      m_state[11] = hsalsa[4];
237
0
      m_state[12] = hsalsa[5];
238
0
      m_state[13] = hsalsa[6];
239
0
      m_state[14] = hsalsa[7];
240
0
      }
241
242
0
   m_state[8] = 0;
243
0
   m_state[9] = 0;
244
245
0
   salsa_core(m_buffer.data(), m_state.data(), 20);
246
0
   ++m_state[8];
247
0
   m_state[9] += (m_state[8] == 0);
248
249
0
   m_position = 0;
250
0
   }
251
252
bool Salsa20::valid_iv_length(size_t iv_len) const
253
0
   {
254
0
   return (iv_len == 0 || iv_len == 8 || iv_len == 24);
255
0
   }
256
257
size_t Salsa20::default_iv_length() const
258
0
   {
259
0
   return 24;
260
0
   }
261
262
Key_Length_Specification Salsa20::key_spec() const
263
0
   {
264
0
   return Key_Length_Specification(16, 32, 16);
265
0
   }
266
267
std::unique_ptr<StreamCipher> Salsa20::new_object() const
268
0
   {
269
0
   return std::make_unique<Salsa20>();
270
0
   }
271
272
std::string Salsa20::name() const
273
0
   {
274
0
   return "Salsa20";
275
0
   }
276
277
/*
278
* Clear memory of sensitive data
279
*/
280
void Salsa20::clear()
281
0
   {
282
0
   zap(m_key);
283
0
   zap(m_state);
284
0
   zap(m_buffer);
285
0
   m_position = 0;
286
0
   }
287
288
void Salsa20::seek(uint64_t offset)
289
0
   {
290
0
   verify_key_set(m_state.empty() == false);
291
292
   // Find the block offset
293
0
   const uint64_t counter = offset / 64;
294
0
   uint8_t counter8[8];
295
0
   store_le(counter, counter8);
296
297
0
   m_state[8]  = load_le<uint32_t>(counter8, 0);
298
0
   m_state[9] += load_le<uint32_t>(counter8, 1);
299
300
0
   salsa_core(m_buffer.data(), m_state.data(), 20);
301
302
0
   ++m_state[8];
303
0
   m_state[9] += (m_state[8] == 0);
304
305
0
   m_position = offset % 64;
306
0
   }
307
}