Botan 3.5.0
Crypto and TLS for C&
noekeon.cpp
Go to the documentation of this file.
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
14namespace Botan {
15
16namespace {
17
18/*
19* Noekeon's Theta Operation
20*/
21inline void theta(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3, const uint32_t EK[4]) {
22 uint32_t T = A0 ^ A2;
23 T ^= rotl<8>(T) ^ rotr<8>(T);
24 A1 ^= T;
25 A3 ^= T;
26
27 A0 ^= EK[0];
28 A1 ^= EK[1];
29 A2 ^= EK[2];
30 A3 ^= EK[3];
31
32 T = A1 ^ A3;
33 T ^= rotl<8>(T) ^ rotr<8>(T);
34 A0 ^= T;
35 A2 ^= T;
36}
37
38/*
39* Theta With Null Key
40*/
41inline void theta(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3) {
42 uint32_t T = A0 ^ A2;
43 T ^= rotl<8>(T) ^ rotr<8>(T);
44 A1 ^= T;
45 A3 ^= T;
46
47 T = A1 ^ A3;
48 T ^= rotl<8>(T) ^ rotr<8>(T);
49 A0 ^= T;
50 A2 ^= T;
51}
52
53/*
54* Noekeon's Gamma S-Box Layer
55*/
56inline void gamma(uint32_t& A0, uint32_t& A1, uint32_t& A2, uint32_t& A3) {
57 A1 ^= ~(A2 | A3);
58 A0 ^= A2 & A1;
59
60 uint32_t T = A3;
61 A3 = A0;
62 A0 = T;
63
64 A2 ^= A0 ^ A1 ^ A3;
65
66 A1 ^= ~(A2 | A3);
67 A0 ^= A2 & A1;
68}
69
70} // namespace
71
72size_t Noekeon::parallelism() const {
73#if defined(BOTAN_HAS_NOEKEON_SIMD)
74 if(CPUID::has_simd_32()) {
75 return 4;
76 }
77#endif
78
79 return 1;
80}
81
82std::string Noekeon::provider() const {
83#if defined(BOTAN_HAS_NOEKEON_SIMD)
84 if(CPUID::has_simd_32()) {
85 return "simd";
86 }
87#endif
88
89 return "base";
90}
91
92/*
93* Noekeon Round Constants
94*/
95const 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*/
101void Noekeon::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
103
104#if defined(BOTAN_HAS_NOEKEON_SIMD)
105 if(CPUID::has_simd_32()) {
106 while(blocks >= 4) {
107 simd_encrypt_4(in, out);
108 in += 4 * BLOCK_SIZE;
109 out += 4 * BLOCK_SIZE;
110 blocks -= 4;
111 }
112 }
113#endif
114
115 for(size_t i = 0; i != blocks; ++i) {
116 uint32_t A0 = load_be<uint32_t>(in, 0);
117 uint32_t A1 = load_be<uint32_t>(in, 1);
118 uint32_t A2 = load_be<uint32_t>(in, 2);
119 uint32_t A3 = load_be<uint32_t>(in, 3);
120
121 for(size_t j = 0; j != 16; ++j) {
122 A0 ^= RC[j];
123 theta(A0, A1, A2, A3, m_EK.data());
124
125 A1 = rotl<1>(A1);
126 A2 = rotl<5>(A2);
127 A3 = rotl<2>(A3);
128
129 gamma(A0, A1, A2, A3);
130
131 A1 = rotr<1>(A1);
132 A2 = rotr<5>(A2);
133 A3 = rotr<2>(A3);
134 }
135
136 A0 ^= RC[16];
137 theta(A0, A1, A2, A3, m_EK.data());
138
139 store_be(out, A0, A1, A2, A3);
140
141 in += BLOCK_SIZE;
142 out += BLOCK_SIZE;
143 }
144}
145
146/*
147* Noekeon Encryption
148*/
149void Noekeon::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
151
152#if defined(BOTAN_HAS_NOEKEON_SIMD)
153 if(CPUID::has_simd_32()) {
154 while(blocks >= 4) {
155 simd_decrypt_4(in, out);
156 in += 4 * BLOCK_SIZE;
157 out += 4 * BLOCK_SIZE;
158 blocks -= 4;
159 }
160 }
161#endif
162
163 for(size_t i = 0; i != blocks; ++i) {
164 uint32_t A0 = load_be<uint32_t>(in, 0);
165 uint32_t A1 = load_be<uint32_t>(in, 1);
166 uint32_t A2 = load_be<uint32_t>(in, 2);
167 uint32_t A3 = load_be<uint32_t>(in, 3);
168
169 for(size_t j = 16; j != 0; --j) {
170 theta(A0, A1, A2, A3, m_DK.data());
171 A0 ^= RC[j];
172
173 A1 = rotl<1>(A1);
174 A2 = rotl<5>(A2);
175 A3 = rotl<2>(A3);
176
177 gamma(A0, A1, A2, A3);
178
179 A1 = rotr<1>(A1);
180 A2 = rotr<5>(A2);
181 A3 = rotr<2>(A3);
182 }
183
184 theta(A0, A1, A2, A3, m_DK.data());
185 A0 ^= RC[0];
186
187 store_be(out, A0, A1, A2, A3);
188
189 in += BLOCK_SIZE;
190 out += BLOCK_SIZE;
191 }
192}
193
195 return !m_EK.empty();
196}
197
198/*
199* Noekeon Key Schedule
200*/
201void Noekeon::key_schedule(std::span<const uint8_t> key) {
202 uint32_t A0 = load_be<uint32_t>(key.data(), 0);
203 uint32_t A1 = load_be<uint32_t>(key.data(), 1);
204 uint32_t A2 = load_be<uint32_t>(key.data(), 2);
205 uint32_t A3 = load_be<uint32_t>(key.data(), 3);
206
207 for(size_t i = 0; i != 16; ++i) {
208 A0 ^= RC[i];
209 theta(A0, A1, A2, A3);
210
211 A1 = rotl<1>(A1);
212 A2 = rotl<5>(A2);
213 A3 = rotl<2>(A3);
214
215 gamma(A0, A1, A2, A3);
216
217 A1 = rotr<1>(A1);
218 A2 = rotr<5>(A2);
219 A3 = rotr<2>(A3);
220 }
221
222 A0 ^= RC[16];
223
224 m_DK.resize(4);
225 m_DK[0] = A0;
226 m_DK[1] = A1;
227 m_DK[2] = A2;
228 m_DK[3] = A3;
229
230 theta(A0, A1, A2, A3);
231
232 m_EK.resize(4);
233 m_EK[0] = A0;
234 m_EK[1] = A1;
235 m_EK[2] = A2;
236 m_EK[3] = A3;
237}
238
239/*
240* Clear memory of sensitive data
241*/
243 zap(m_EK);
244 zap(m_DK);
245}
246
247} // namespace Botan
static bool has_simd_32()
Definition cpuid.cpp:18
size_t parallelism() const override
Definition noekeon.cpp:72
void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
Definition noekeon.cpp:101
std::string provider() const override
Definition noekeon.cpp:82
void clear() override
Definition noekeon.cpp:242
void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
Definition noekeon.cpp:149
bool has_keying_material() const override
Definition noekeon.cpp:194
void assert_key_material_set() const
Definition sym_algo.h:139
FE_25519 T
Definition ge.cpp:34
void zap(std::vector< T, Alloc > &vec)
Definition secmem.h:117
constexpr T rotl(T input)
Definition rotate.h:21
void theta(SIMD_4x32 &A0, SIMD_4x32 &A1, SIMD_4x32 &A2, SIMD_4x32 &A3, const SIMD_4x32 &K0, const SIMD_4x32 &K1, const SIMD_4x32 &K2, const SIMD_4x32 &K3)
constexpr T rotr(T input)
Definition rotate.h:33
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:707
constexpr auto load_be(ParamTs &&... params)
Definition loadstor.h:467
void gamma(SIMD_4x32 &A0, SIMD_4x32 &A1, SIMD_4x32 &A2, SIMD_4x32 &A3)