Coverage Report

Created: 2023-06-07 07:00

/src/botan/src/lib/block/noekeon/noekeon.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* Noekeon
3
* (C) 1999-2008 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/internal/noekeon.h>
9
10
#include <botan/internal/cpuid.h>
11
#include <botan/internal/loadstor.h>
12
#include <botan/internal/rotate.h>
13
14
namespace Botan {
15
16
namespace {
17
18
/*
19
* Noekeon's Theta Operation
20
*/
21
0
inline void theta(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3, const uint32_t EK[4]) {
22
0
   uint32_t T = A0 ^ A2;
23
0
   T ^= rotl<8>(T) ^ rotr<8>(T);
24
0
   A1 ^= T;
25
0
   A3 ^= T;
26
27
0
   A0 ^= EK[0];
28
0
   A1 ^= EK[1];
29
0
   A2 ^= EK[2];
30
0
   A3 ^= EK[3];
31
32
0
   T = A1 ^ A3;
33
0
   T ^= rotl<8>(T) ^ rotr<8>(T);
34
0
   A0 ^= T;
35
0
   A2 ^= T;
36
0
}
37
38
/*
39
* Theta With Null Key
40
*/
41
0
inline void theta(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3) {
42
0
   uint32_t T = A0 ^ A2;
43
0
   T ^= rotl<8>(T) ^ rotr<8>(T);
44
0
   A1 ^= T;
45
0
   A3 ^= T;
46
47
0
   T = A1 ^ A3;
48
0
   T ^= rotl<8>(T) ^ rotr<8>(T);
49
0
   A0 ^= T;
50
0
   A2 ^= T;
51
0
}
52
53
/*
54
* Noekeon's Gamma S-Box Layer
55
*/
56
0
inline void gamma(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3) {
57
0
   A1 ^= ~(A2 | A3);
58
0
   A0 ^= A2 & A1;
59
60
0
   uint32_t T = A3;
61
0
   A3 = A0;
62
0
   A0 = T;
63
64
0
   A2 ^= A0 ^ A1 ^ A3;
65
66
0
   A1 ^= ~(A2 | A3);
67
0
   A0 ^= A2 & A1;
68
0
}
69
70
}  // namespace
71
72
0
size_t Noekeon::parallelism() const {
73
0
#if defined(BOTAN_HAS_NOEKEON_SIMD)
74
0
   if(CPUID::has_simd_32()) {
75
0
      return 4;
76
0
   }
77
0
#endif
78
79
0
   return 1;
80
0
}
81
82
0
std::string Noekeon::provider() const {
83
0
#if defined(BOTAN_HAS_NOEKEON_SIMD)
84
0
   if(CPUID::has_simd_32()) {
85
0
      return "simd";
86
0
   }
87
0
#endif
88
89
0
   return "base";
90
0
}
91
92
/*
93
* Noekeon Round Constants
94
*/
95
const uint8_t Noekeon::RC[] = {
96
   0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4};
97
98
/*
99
* Noekeon Encryption
100
*/
101
0
void Noekeon::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
102
0
   assert_key_material_set();
103
104
0
#if defined(BOTAN_HAS_NOEKEON_SIMD)
105
0
   if(CPUID::has_simd_32()) {
106
0
      while(blocks >= 4) {
107
0
         simd_encrypt_4(in, out);
108
0
         in += 4 * BLOCK_SIZE;
109
0
         out += 4 * BLOCK_SIZE;
110
0
         blocks -= 4;
111
0
      }
112
0
   }
113
0
#endif
114
115
0
   for(size_t i = 0; i != blocks; ++i) {
116
0
      uint32_t A0 = load_be<uint32_t>(in, 0);
117
0
      uint32_t A1 = load_be<uint32_t>(in, 1);
118
0
      uint32_t A2 = load_be<uint32_t>(in, 2);
119
0
      uint32_t A3 = load_be<uint32_t>(in, 3);
120
121
0
      for(size_t j = 0; j != 16; ++j) {
122
0
         A0 ^= RC[j];
123
0
         theta(A0, A1, A2, A3, m_EK.data());
124
125
0
         A1 = rotl<1>(A1);
126
0
         A2 = rotl<5>(A2);
127
0
         A3 = rotl<2>(A3);
128
129
0
         gamma(A0, A1, A2, A3);
130
131
0
         A1 = rotr<1>(A1);
132
0
         A2 = rotr<5>(A2);
133
0
         A3 = rotr<2>(A3);
134
0
      }
135
136
0
      A0 ^= RC[16];
137
0
      theta(A0, A1, A2, A3, m_EK.data());
138
139
0
      store_be(out, A0, A1, A2, A3);
140
141
0
      in += BLOCK_SIZE;
142
0
      out += BLOCK_SIZE;
143
0
   }
144
0
}
145
146
/*
147
* Noekeon Encryption
148
*/
149
0
void Noekeon::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
150
0
   assert_key_material_set();
151
152
0
#if defined(BOTAN_HAS_NOEKEON_SIMD)
153
0
   if(CPUID::has_simd_32()) {
154
0
      while(blocks >= 4) {
155
0
         simd_decrypt_4(in, out);
156
0
         in += 4 * BLOCK_SIZE;
157
0
         out += 4 * BLOCK_SIZE;
158
0
         blocks -= 4;
159
0
      }
160
0
   }
161
0
#endif
162
163
0
   for(size_t i = 0; i != blocks; ++i) {
164
0
      uint32_t A0 = load_be<uint32_t>(in, 0);
165
0
      uint32_t A1 = load_be<uint32_t>(in, 1);
166
0
      uint32_t A2 = load_be<uint32_t>(in, 2);
167
0
      uint32_t A3 = load_be<uint32_t>(in, 3);
168
169
0
      for(size_t j = 16; j != 0; --j) {
170
0
         theta(A0, A1, A2, A3, m_DK.data());
171
0
         A0 ^= RC[j];
172
173
0
         A1 = rotl<1>(A1);
174
0
         A2 = rotl<5>(A2);
175
0
         A3 = rotl<2>(A3);
176
177
0
         gamma(A0, A1, A2, A3);
178
179
0
         A1 = rotr<1>(A1);
180
0
         A2 = rotr<5>(A2);
181
0
         A3 = rotr<2>(A3);
182
0
      }
183
184
0
      theta(A0, A1, A2, A3, m_DK.data());
185
0
      A0 ^= RC[0];
186
187
0
      store_be(out, A0, A1, A2, A3);
188
189
0
      in += BLOCK_SIZE;
190
0
      out += BLOCK_SIZE;
191
0
   }
192
0
}
193
194
0
bool Noekeon::has_keying_material() const { return !m_EK.empty(); }
195
196
/*
197
* Noekeon Key Schedule
198
*/
199
0
void Noekeon::key_schedule(const uint8_t key[], size_t /*length*/) {
200
0
   uint32_t A0 = load_be<uint32_t>(key, 0);
201
0
   uint32_t A1 = load_be<uint32_t>(key, 1);
202
0
   uint32_t A2 = load_be<uint32_t>(key, 2);
203
0
   uint32_t A3 = load_be<uint32_t>(key, 3);
204
205
0
   for(size_t i = 0; i != 16; ++i) {
206
0
      A0 ^= RC[i];
207
0
      theta(A0, A1, A2, A3);
208
209
0
      A1 = rotl<1>(A1);
210
0
      A2 = rotl<5>(A2);
211
0
      A3 = rotl<2>(A3);
212
213
0
      gamma(A0, A1, A2, A3);
214
215
0
      A1 = rotr<1>(A1);
216
0
      A2 = rotr<5>(A2);
217
0
      A3 = rotr<2>(A3);
218
0
   }
219
220
0
   A0 ^= RC[16];
221
222
0
   m_DK.resize(4);
223
0
   m_DK[0] = A0;
224
0
   m_DK[1] = A1;
225
0
   m_DK[2] = A2;
226
0
   m_DK[3] = A3;
227
228
0
   theta(A0, A1, A2, A3);
229
230
0
   m_EK.resize(4);
231
0
   m_EK[0] = A0;
232
0
   m_EK[1] = A1;
233
0
   m_EK[2] = A2;
234
0
   m_EK[3] = A3;
235
0
}
236
237
/*
238
* Clear memory of sensitive data
239
*/
240
0
void Noekeon::clear() {
241
0
   zap(m_EK);
242
0
   zap(m_DK);
243
0
}
244
245
}  // namespace Botan