Skip to content

Commit f2c8d38

Browse files
committed
Update AES, add tests.
1 parent 31dfe95 commit f2c8d38

File tree

4 files changed

+222
-136
lines changed

4 files changed

+222
-136
lines changed

include/bitcoin/system/crypto/aes256.hpp

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,34 @@
2424

2525
namespace libbitcoin {
2626
namespace system {
27-
namespace aes256 {
28-
29-
/// This is an implementation of AES256 (in ECB mode).
30-
/// ECB mode is the simplest block cipher mode but is insecure for most
31-
/// applications because it doesn't hide patterns in the plaintext.
32-
/// NIST selected three members of the Rijndael family, each with a block
33-
/// size of 128 bits, but three different key lengths: 128, 192 and 256 bits.
3427

35-
constexpr size_t block_size = bytes<128>;
36-
typedef data_array<block_size> block;
28+
/// Advanced Encryption Standard (AES) 256.
29+
class BC_API aes256 final
30+
{
31+
public:
32+
/// AES block is always 128 bits.
33+
typedef data_array<bytes<128>> block;
3734

38-
constexpr size_t secret_size = bytes<256>;
39-
typedef data_array<secret_size> secret;
35+
/// AES-256 secret is always 256 bits.
36+
typedef data_array<bytes<256>> secret;
4037

41-
/// Perform aes256 encryption/decryption on a data block.
42-
void encrypt(block& bytes, const secret& key) NOEXCEPT;
43-
void decrypt(block& bytes, const secret& key) NOEXCEPT;
38+
/// nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf
39+
static void encrypt_ecb(block& bytes, const secret& key) NOEXCEPT;
40+
static void decrypt_ecb(block& bytes, const secret& key) NOEXCEPT;
41+
42+
private:
43+
struct context
44+
{
45+
secret key;
46+
secret enckey;
47+
secret deckey;
48+
};
49+
50+
static void initialize(context& context, const secret& key) NOEXCEPT;
51+
static void encrypt_ecb(context& context, block& bytes) NOEXCEPT;
52+
static void decrypt_ecb(context& context, block& bytes) NOEXCEPT;
53+
};
4454

45-
} // namespace aes256
4655
} // namespace system
4756
} // namespace libbitcoin
4857

src/crypto/aes256.cpp

Lines changed: 90 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,39 @@
11
/**
2+
* Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
3+
*
4+
* This file is part of libbitcoin.
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Affero General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
#include <bitcoin/system/crypto/aes256.hpp>
20+
21+
#include <bitcoin/system/data/data.hpp>
22+
#include <bitcoin/system/define.hpp>
23+
#include <bitcoin/system/math/math.hpp>
24+
25+
namespace libbitcoin {
26+
namespace system {
27+
28+
BC_PUSH_WARNING(NO_ARRAY_INDEXING)
29+
BC_PUSH_WARNING(NO_DYNAMIC_ARRAY_INDEXING)
30+
31+
// local
32+
// ----------------------------------------------------------------------------
33+
// Derived in part from:
34+
/**
235
* Byte-oriented AES-256 implementation.
3-
* All lookup tables replaced with 'on the fly' calculations.
36+
* All lookup tables replaced with 'on the fly' calculations.
437
*
538
* Copyright (c) 2007-2009 Ilya O. Levin, http://www.literatecode.com
639
* Other contributors: Hal Finney
@@ -17,24 +50,10 @@
1750
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1851
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1952
*/
20-
#include <bitcoin/system/crypto/aes256.hpp>
21-
22-
#include <bitcoin/system/define.hpp>
23-
#include <bitcoin/system/data/data.hpp>
24-
#include <bitcoin/system/math/math.hpp>
25-
26-
namespace libbitcoin {
27-
namespace system {
28-
namespace aes256 {
29-
30-
struct context
31-
{
32-
secret key;
33-
secret enckey;
34-
secret deckey;
35-
};
3653

3754
constexpr size_t rounds = 14;
55+
constexpr auto block_size = array_count<aes256::block>;
56+
constexpr auto secret_size = array_count<aes256::secret>;
3857

3958
constexpr data_array<to_bits(secret_size)> sbox
4059
{
@@ -110,47 +129,48 @@ constexpr data_array<to_bits(secret_size)> sbox_inverse
110129

111130
constexpr uint8_t f_enc_key(uint8_t byte) NOEXCEPT
112131
{
113-
return shift_left(byte) ^ (get_left(byte) ? 0b0001'1011_u8 : zero);
132+
constexpr auto mask = 0b0001'1011_u8;
133+
return shift_left(byte) ^ (get_left(byte) ? mask : 0_u8);
114134
}
115135

116136
constexpr uint8_t f_dec_key(uint8_t byte) NOEXCEPT
117137
{
118-
return shift_right(byte) ^ (get_right(byte) ? 0b1000'1101_u8 : zero);
138+
constexpr auto mask = 0b1000'1101_u8;
139+
return shift_right(byte) ^ (get_right(byte) ? mask : 0_u8);
119140
}
120141

121-
BC_PUSH_WARNING(NO_ARRAY_INDEXING)
122-
BC_PUSH_WARNING(NO_DYNAMIC_ARRAY_INDEXING)
123-
124-
constexpr void sub_bytes(block& bytes) NOEXCEPT
142+
constexpr void sub_bytes(aes256::block& bytes) NOEXCEPT
125143
{
126144
auto i = block_size;
127145
while (to_bool(i--))
128146
bytes[i] = sbox[bytes[i]];
129147
}
130148

131-
constexpr void sub_bytes_inverse(block& bytes) NOEXCEPT
149+
constexpr void sub_bytes_inverse(aes256::block& bytes) NOEXCEPT
132150
{
133151
auto i = block_size;
134152
while (to_bool(i--))
135153
bytes[i] = sbox_inverse[bytes[i]];
136154
}
137155

138-
constexpr void add_round_key_lower(block& bytes, secret& key) NOEXCEPT
156+
constexpr void add_round_key_lower(aes256::block& bytes,
157+
aes256::secret& key) NOEXCEPT
139158
{
140159
auto i = block_size;
141160
while (to_bool(i--))
142161
bytes[i] ^= key[i];
143162
}
144163

145-
constexpr void add_round_key_upper(block& bytes, secret& key) NOEXCEPT
164+
constexpr void add_round_key_upper(aes256::block& bytes,
165+
aes256::secret& key) NOEXCEPT
146166
{
147167
auto i = block_size;
148168
while (to_bool(i--))
149169
bytes[i] ^= key[i + block_size];
150170
}
151171

152-
constexpr void add_round_key_copy(block& bytes, secret& key,
153-
secret& copy) NOEXCEPT
172+
constexpr void add_round_key_copy(aes256::block& bytes, aes256::secret& key,
173+
aes256::secret& copy) NOEXCEPT
154174
{
155175
auto i = block_size;
156176
while (to_bool(i--))
@@ -162,11 +182,9 @@ constexpr void add_round_key_copy(block& bytes, secret& key,
162182
}
163183
}
164184

165-
constexpr void shift_rows(block& bytes) NOEXCEPT
185+
constexpr void shift_rows(aes256::block& bytes) NOEXCEPT
166186
{
167-
uint8_t i, j;
168-
169-
i = bytes[1];
187+
auto i = bytes[1];
170188
bytes[ 1] = bytes[5];
171189
bytes[ 5] = bytes[9];
172190
bytes[ 9] = bytes[13];
@@ -176,7 +194,7 @@ constexpr void shift_rows(block& bytes) NOEXCEPT
176194
bytes[10] = bytes[2];
177195
bytes[ 2] = i;
178196

179-
j = bytes[3];
197+
auto j = bytes[3];
180198
bytes[ 3] = bytes[15];
181199
bytes[15] = bytes[11];
182200
bytes[11] = bytes[7];
@@ -187,11 +205,9 @@ constexpr void shift_rows(block& bytes) NOEXCEPT
187205
bytes[ 6] = j;
188206
}
189207

190-
constexpr void shift_rows_inverse(block& bytes) NOEXCEPT
208+
constexpr void shift_rows_inverse(aes256::block& bytes) NOEXCEPT
191209
{
192-
uint8_t i, j;
193-
194-
i = bytes[1];
210+
auto i = bytes[1];
195211
bytes[ 1] = bytes[13];
196212
bytes[13] = bytes[9];
197213
bytes[ 9] = bytes[5];
@@ -201,7 +217,7 @@ constexpr void shift_rows_inverse(block& bytes) NOEXCEPT
201217
bytes[ 2] = bytes[10];
202218
bytes[10] = i;
203219

204-
j = bytes[3];
220+
auto j = bytes[3];
205221
bytes[ 3] = bytes[7];
206222
bytes[ 7] = bytes[11];
207223
bytes[11] = bytes[15];
@@ -212,40 +228,36 @@ constexpr void shift_rows_inverse(block& bytes) NOEXCEPT
212228
bytes[14] = j;
213229
}
214230

215-
constexpr void mix_columns(block& bytes) NOEXCEPT
231+
constexpr void mix_columns(aes256::block& bytes) NOEXCEPT
216232
{
217-
uint8_t a, b, c, d, e;
218-
219233
for (size_t i = 0; i < block_size; i += 4_size)
220234
{
221-
a = bytes[i + 0];
222-
b = bytes[i + 1];
223-
c = bytes[i + 2];
224-
d = bytes[i + 3];
235+
const auto a = bytes[i + 0];
236+
const auto b = bytes[i + 1];
237+
const auto c = bytes[i + 2];
238+
const auto d = bytes[i + 3];
225239

226-
e = a ^ b ^ c ^ d;
240+
const uint8_t e = a ^ b ^ c ^ d;
227241
bytes[i + 0] ^= e ^ f_enc_key(a ^ b);
228242
bytes[i + 1] ^= e ^ f_enc_key(b ^ c);
229243
bytes[i + 2] ^= e ^ f_enc_key(c ^ d);
230244
bytes[i + 3] ^= e ^ f_enc_key(d ^ a);
231245
}
232246
}
233247

234-
constexpr void mix_columns_inverse(block& bytes) NOEXCEPT
248+
constexpr void mix_columns_inverse(aes256::block& bytes) NOEXCEPT
235249
{
236-
uint8_t a, b, c, d, e, x, y, z;
237-
238-
for (size_t i = 0; i < block_size; i += 4_size)
250+
for (size_t i{}; i < block_size; i += 4_size)
239251
{
240-
a = bytes[i + 0];
241-
b = bytes[i + 1];
242-
c = bytes[i + 2];
243-
d = bytes[i + 3];
252+
const auto a = bytes[i + 0];
253+
const auto b = bytes[i + 1];
254+
const auto c = bytes[i + 2];
255+
const auto d = bytes[i + 3];
244256

245-
e = a ^ b ^ c ^ d;
246-
z = f_enc_key(e);
247-
x = e ^ f_enc_key(f_enc_key(z ^ a ^ c));
248-
y = e ^ f_enc_key(f_enc_key(z ^ b ^ d));
257+
const uint8_t e = a ^ b ^ c ^ d;
258+
const uint8_t z = f_enc_key(e);
259+
const uint8_t x = e ^ f_enc_key(f_enc_key(z ^ a ^ c));
260+
const uint8_t y = e ^ f_enc_key(f_enc_key(z ^ b ^ d));
249261

250262
bytes[i + 0] ^= x ^ f_enc_key(a ^ b);
251263
bytes[i + 1] ^= y ^ f_enc_key(b ^ c);
@@ -254,7 +266,7 @@ constexpr void mix_columns_inverse(block& bytes) NOEXCEPT
254266
}
255267
}
256268

257-
constexpr void expand_key(secret& key, uint8_t& round) NOEXCEPT
269+
constexpr void expand_key(aes256::secret& key, uint8_t& round) NOEXCEPT
258270
{
259271
key[0] ^= sbox[key[29]] ^ round;
260272
key[1] ^= sbox[key[30]];
@@ -284,7 +296,7 @@ constexpr void expand_key(secret& key, uint8_t& round) NOEXCEPT
284296
}
285297
}
286298

287-
constexpr void expand_key_inverse(secret& key, uint8_t& round) NOEXCEPT
299+
constexpr void expand_key_inverse(aes256::secret& key, uint8_t& round) NOEXCEPT
288300
{
289301
for (size_t i = 28; i > 16_size; i -= 4_size)
290302
{
@@ -314,25 +326,25 @@ constexpr void expand_key_inverse(secret& key, uint8_t& round) NOEXCEPT
314326
key[3] ^= sbox[key[28]];
315327
}
316328

317-
BC_POP_WARNING()
318-
BC_POP_WARNING()
329+
// private/static
330+
// ----------------------------------------------------------------------------
319331

320-
constexpr void initialize(aes256::context& context, const secret& key) NOEXCEPT
332+
void aes256::initialize(context& context, const secret& key) NOEXCEPT
321333
{
322334
context.deckey = key;
323335
context.enckey = key;
324336

325337
auto round = bit_lo<uint8_t>;
326-
for (size_t i = 0; i < sub1(bits<uint8_t>); ++i)
338+
for (size_t i{}; i < sub1(bits<uint8_t>); ++i)
327339
expand_key(context.deckey, round);
328340
}
329341

330-
constexpr void encrypt_block(aes256::context& context, block& bytes) NOEXCEPT
342+
void aes256::encrypt_ecb(context& context, block& bytes) NOEXCEPT
331343
{
332344
add_round_key_copy(bytes, context.enckey, context.key);
333345

334346
auto round = bit_lo<uint8_t>;
335-
for (size_t i = 0; i < sub1(rounds); ++i)
347+
for (size_t i{}; i < sub1(rounds); ++i)
336348
{
337349
sub_bytes(bytes);
338350
shift_rows(bytes);
@@ -355,15 +367,14 @@ constexpr void encrypt_block(aes256::context& context, block& bytes) NOEXCEPT
355367
add_round_key_lower(bytes, context.key);
356368
}
357369

358-
constexpr void decrypt_block(aes256::context& context, block& bytes) NOEXCEPT
370+
void aes256::decrypt_ecb(context& context, block& bytes) NOEXCEPT
359371
{
360372
add_round_key_copy(bytes, context.deckey, context.key);
361-
362373
shift_rows_inverse(bytes);
363374
sub_bytes_inverse(bytes);
364375

365376
auto round = bit_hi<uint8_t>;
366-
for (size_t i = 0; i < sub1(rounds); ++i)
377+
for (size_t i{}; i < sub1(rounds); ++i)
367378
{
368379
if (is_even(i))
369380
{
@@ -383,32 +394,25 @@ constexpr void decrypt_block(aes256::context& context, block& bytes) NOEXCEPT
383394
add_round_key_lower(bytes, context.key);
384395
}
385396

386-
////constexpr void zeroize(aes256::context& context) NOEXCEPT
387-
////{
388-
//// context.key.fill(0);
389-
//// context.enckey.fill(0);
390-
//// context.deckey.fill(0);
391-
////}
392-
393-
// published
397+
// public/static
394398
// ----------------------------------------------------------------------------
395399

396-
void encrypt(block& bytes, const secret& key) NOEXCEPT
400+
void aes256::encrypt_ecb(block& bytes, const secret& key) NOEXCEPT
397401
{
398-
aes256::context context;
402+
context context{};
399403
initialize(context, key);
400-
encrypt_block(context, bytes);
401-
////zeroize(context);
404+
encrypt_ecb(context, bytes);
402405
}
403406

404-
void decrypt(block& bytes, const secret& key) NOEXCEPT
407+
void aes256::decrypt_ecb(block& bytes, const secret& key) NOEXCEPT
405408
{
406-
aes256::context context;
409+
context context;
407410
initialize(context, key);
408-
decrypt_block(context, bytes);
409-
////zeroize(context);
411+
decrypt_ecb(context, bytes);
410412
}
411413

412-
} // namespace aes256
414+
BC_POP_WARNING()
415+
BC_POP_WARNING()
416+
413417
} // namespace system
414418
} // namespace libbitcoin

0 commit comments

Comments
 (0)