plusaes
plusaes.hpp
1// Copyright (C) 2015 kkAyataka
2//
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef PLUSAES_HPP__
8#define PLUSAES_HPP__
9
10#include <algorithm>
11#include <bitset>
12#include <cmath>
13#include <cstring>
14#include <stdexcept>
15#include <vector>
16
22#define PLUSAES_VERSION 0x01000000
23
27namespace plusaes {
28namespace detail {
29
30const int kWordSize = 4;
31typedef unsigned int Word;
32
33const int kBlockSize = 4;
35struct State {
36 Word w[4];
37 Word & operator[](const int index) {
38 return w[index];
39 }
40 const Word & operator[](const int index) const {
41 return w[index];
42 }
43};
44
45const int kStateSize = 16; // Word * BlockSize
46typedef State RoundKey;
47typedef std::vector<RoundKey> RoundKeys;
48
49inline void add_round_key(const RoundKey &key, State &state) {
50 for (int i = 0; i < kBlockSize; ++i) {
51 state[i] ^= key[i];
52 }
53}
54
55const unsigned char kSbox[] = {
56 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
57 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
58 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
59 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
60 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
61 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
62 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
63 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
64 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
65 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
66 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
67 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
68 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
69 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
70 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
71 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
72};
73
74const unsigned char kInvSbox[] = {
75 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
76 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
77 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
78 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
79 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
80 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
81 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
82 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
83 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
84 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
85 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
86 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
87 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
88 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
89 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
90 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
91};
92
93inline Word sub_word(const Word w) {
94 return kSbox[(w >> 0) & 0xFF] << 0 |
95 kSbox[(w >> 8) & 0xFF] << 8 |
96 kSbox[(w >> 16) & 0xFF] << 16 |
97 kSbox[(w >> 24) & 0xFF] << 24;
98}
99
100inline Word inv_sub_word(const Word w) {
101 return kInvSbox[(w >> 0) & 0xFF] << 0 |
102 kInvSbox[(w >> 8) & 0xFF] << 8 |
103 kInvSbox[(w >> 16) & 0xFF] << 16 |
104 kInvSbox[(w >> 24) & 0xFF] << 24;
105}
106
107inline void sub_bytes(State &state) {
108 for (int i = 0; i < kBlockSize; ++i) {
109 state[i] = sub_word(state[i]);
110 }
111}
112
113inline void inv_sub_bytes(State &state) {
114 for (int i = 0; i < kBlockSize; ++i) {
115 state[i] = inv_sub_word(state[i]);
116 }
117}
118
119inline void shift_rows(State &state) {
120 const State ori = { state[0], state[1], state[2], state[3] };
121 for (int r = 1; r < kWordSize; ++r) {
122 const Word m2 = 0xFF << (r * 8);
123 const Word m1 = ~m2;
124 for (int c = 0; c < kBlockSize; ++c) {
125 state[c] = (state[c] & m1) | (ori[(c + r) % kBlockSize] & m2);
126 }
127 }
128}
129
130inline void inv_shift_rows(State &state) {
131 const State ori = { state[0], state[1], state[2], state[3] };
132 for (int r = 1; r < kWordSize; ++r) {
133 const Word m2 = 0xFF << (r * 8);
134 const Word m1 = ~m2;
135 for (int c = 0; c < kBlockSize; ++c) {
136 state[c] = (state[c] & m1) | (ori[(c + kBlockSize - r) % kWordSize] & m2);
137 }
138 }
139}
140
141inline unsigned char mul2(const unsigned char b) {
142 unsigned char m2 = b << 1;
143 if (b & 0x80) {
144 m2 ^= 0x011B;
145 }
146
147 return m2;
148}
149
150inline unsigned char mul(const unsigned char b, const unsigned char m) {
151 unsigned char v = 0;
152 unsigned char t = b;
153 for (int i = 0; i < 8; ++i) { // 8-bits
154 if ((m >> i) & 0x01) {
155 v ^= t;
156 }
157
158 t = mul2(t);
159 }
160
161 return v;
162}
163
164inline void mix_columns(State &state) {
165 for (int i = 0; i < kBlockSize; ++i) {
166 const unsigned char v0_1 = (state[i] >> 0) & 0xFF;
167 const unsigned char v1_1 = (state[i] >> 8) & 0xFF;
168 const unsigned char v2_1 = (state[i] >> 16) & 0xFF;
169 const unsigned char v3_1 = (state[i] >> 24) & 0xFF;
170
171 const unsigned char v0_2 = mul2(v0_1);
172 const unsigned char v1_2 = mul2(v1_1);
173 const unsigned char v2_2 = mul2(v2_1);
174 const unsigned char v3_2 = mul2(v3_1);
175
176 const unsigned char v0_3 = v0_2 ^ v0_1;
177 const unsigned char v1_3 = v1_2 ^ v1_1;
178 const unsigned char v2_3 = v2_2 ^ v2_1;
179 const unsigned char v3_3 = v3_2 ^ v3_1;
180
181 state[i] =
182 (v0_2 ^ v1_3 ^ v2_1 ^ v3_1) << 0 |
183 (v0_1 ^ v1_2 ^ v2_3 ^ v3_1) << 8 |
184 (v0_1 ^ v1_1 ^ v2_2 ^ v3_3) << 16 |
185 (v0_3 ^ v1_1 ^ v2_1 ^ v3_2) << 24;
186 }
187}
188
189inline void inv_mix_columns(State &state) {
190 for (int i = 0; i < kBlockSize; ++i) {
191 const unsigned char v0 = (state[i] >> 0) & 0xFF;
192 const unsigned char v1 = (state[i] >> 8) & 0xFF;
193 const unsigned char v2 = (state[i] >> 16) & 0xFF;
194 const unsigned char v3 = (state[i] >> 24) & 0xFF;
195
196 state[i] =
197 (mul(v0, 0x0E) ^ mul(v1, 0x0B) ^ mul(v2, 0x0D) ^ mul(v3, 0x09)) << 0 |
198 (mul(v0, 0x09) ^ mul(v1, 0x0E) ^ mul(v2, 0x0B) ^ mul(v3, 0x0D)) << 8 |
199 (mul(v0, 0x0D) ^ mul(v1, 0x09) ^ mul(v2, 0x0E) ^ mul(v3, 0x0B)) << 16 |
200 (mul(v0, 0x0B) ^ mul(v1, 0x0D) ^ mul(v2, 0x09) ^ mul(v3, 0x0E)) << 24;
201 }
202}
203
204inline Word rot_word(const Word v) {
205 return ((v >> 8) & 0x00FFFFFF) | ((v & 0xFF) << 24);
206}
207
212inline unsigned int get_round_count(const int key_size) {
213 switch (key_size) {
214 case 16:
215 return 10;
216 case 24:
217 return 12;
218 case 32:
219 return 14;
220 default:
221 throw std::invalid_argument("Invalid key size");
222 }
223}
224
229inline RoundKeys expand_key(const unsigned char *key, const int key_size) {
230 if (key_size != 16 && key_size != 24 && key_size != 32) {
231 throw std::invalid_argument("Invalid key size");
232 }
233
234 const Word rcon[] = {
235 0x00, 0x01, 0x02, 0x04, 0x08, 0x10,
236 0x20, 0x40, 0x80, 0x1b, 0x36
237 };
238
239 const int nb = kBlockSize;
240 const int nk = key_size / nb;
241 const int nr = get_round_count(key_size);
242
243 std::vector<Word> w(nb * (nr + 1));
244 for (int i = 0; i < nk; ++ i) {
245 memcpy(&w[i], key + (i * kWordSize), kWordSize);
246 }
247
248 for (int i = nk; i < nb * (nr + 1); ++i) {
249 Word t = w[i - 1];
250 if (i % nk == 0) {
251 t = sub_word(rot_word(t)) ^ rcon[i / nk];
252 }
253 else if (nk > 6 && i % nk == 4) {
254 t = sub_word(t);
255 }
256
257 w[i] = t ^ w[i - nk];
258 }
259
260 RoundKeys keys(nr + 1);
261 memcpy(&keys[0], &w[0], w.size() * kWordSize);
262
263 return keys;
264}
265
266inline void copy_bytes_to_state(const unsigned char data[16], State &state) {
267 memcpy(&state[0], data + 0, kWordSize);
268 memcpy(&state[1], data + 4, kWordSize);
269 memcpy(&state[2], data + 8, kWordSize);
270 memcpy(&state[3], data + 12, kWordSize);
271}
272
273inline void copy_state_to_bytes(const State &state, unsigned char buf[16]) {
274 memcpy(buf + 0, &state[0], kWordSize);
275 memcpy(buf + 4, &state[1], kWordSize);
276 memcpy(buf + 8, &state[2], kWordSize);
277 memcpy(buf + 12, &state[3], kWordSize);
278}
279
280inline void xor_data(unsigned char data[kStateSize], const unsigned char v[kStateSize]) {
281 for (int i = 0; i < kStateSize; ++i) {
282 data[i] ^= v[i];
283 }
284}
285
287inline void incr_counter(unsigned char counter[kStateSize]) {
288 unsigned n = kStateSize, c = 1;
289 do {
290 --n;
291 c += counter[n];
292 counter[n] = c;
293 c >>= 8;
294 } while (n);
295}
296
297inline void encrypt_state(const RoundKeys &rkeys, const unsigned char data[16], unsigned char encrypted[16]) {
298 State s;
299 copy_bytes_to_state(data, s);
300
301 add_round_key(rkeys[0], s);
302
303 for (unsigned int i = 1; i < rkeys.size() - 1; ++i) {
304 sub_bytes(s);
305 shift_rows(s);
306 mix_columns(s);
307 add_round_key(rkeys[i], s);
308 }
309
310 sub_bytes(s);
311 shift_rows(s);
312 add_round_key(rkeys.back(), s);
313
314 copy_state_to_bytes(s, encrypted);
315}
316
317inline void decrypt_state(const RoundKeys &rkeys, const unsigned char data[16], unsigned char decrypted[16]) {
318 State s;
319 copy_bytes_to_state(data, s);
320
321 add_round_key(rkeys.back(), s);
322 inv_shift_rows(s);
323 inv_sub_bytes(s);
324
325 for (std::size_t i = rkeys.size() - 2; i > 0; --i) {
326 add_round_key(rkeys[i], s);
327 inv_mix_columns(s);
328 inv_shift_rows(s);
329 inv_sub_bytes(s);
330 }
331
332 add_round_key(rkeys[0], s);
333
334 copy_state_to_bytes(s, decrypted);
335}
336
337template<int KeyLen>
338std::vector<unsigned char> key_from_string(const char (*key_str)[KeyLen]) {
339 std::vector<unsigned char> key(KeyLen - 1);
340 memcpy(&key[0], *key_str, KeyLen - 1);
341 return key;
342}
343
344inline bool is_valid_key_size(const std::size_t key_size) {
345 if (key_size != 16 && key_size != 24 && key_size != 32) {
346 return false;
347 }
348 else {
349 return true;
350 }
351}
352
353
354namespace gcm {
355
356const int kBlockBitSize = 128;
357const int kBlockByteSize = kBlockBitSize / 8;
358
365typedef std::bitset<kBlockBitSize> bitset128;
366
386class Block {
387public:
388 Block() {
389 init_v(0, 0);
390 }
391
392 Block(const unsigned char * bytes, const unsigned long bytes_size) {
393 init_v(bytes, bytes_size);
394 }
395
396 Block(const std::vector<unsigned char> & bytes) {
397 init_v(&bytes[0], bytes.size());
398 }
399
400 Block(const std::bitset<128> & bits) {
401 init_v(0, 0);
402 const std::bitset<128> mask(0xFF); // 1 byte mask
403 for (std::size_t i = 0; i < 16; ++i) {
404 v_[15 - i] = static_cast<unsigned char>(((bits >> (i * 8)) & mask).to_ulong());
405 }
406 }
407
408 inline unsigned char * data() {
409 return v_;
410 }
411
412 inline const unsigned char* data() const {
413 return v_;
414 }
415
416 inline std::bitset<128> to_bits() const {
417 std::bitset<128> bits;
418 for (int i = 0; i < 16; ++i) {
419 bits <<= 8;
420 bits |= v_[i];
421 }
422
423 return bits;
424 }
425
426 inline Block operator^(const Block & b) const {
427 Block r;
428 for (int i = 0; i < 16; ++i) {
429 r.data()[i] = data()[i] ^ b.data()[i];
430 }
431 return r;
432 }
433
434private:
435 unsigned char v_[16];
436
437 inline void init_v(const unsigned char * bytes, const std::size_t bytes_size) {
438 memset(v_, 0, sizeof(v_));
439
440 const std::size_t cs = (std::min)(bytes_size, static_cast<std::size_t>(16));
441 for (std::size_t i = 0; i < cs; ++i) {
442 v_[i] = bytes[i];
443 }
444 }
445};
446
447template<typename T>
448unsigned long ceil(const T v) {
449 return static_cast<unsigned long>(std::ceil(v) + 0.5);
450}
451
452template<std::size_t N1, std::size_t N2>
453std::bitset<N1 + N2> operator||(const std::bitset<N1> &v1, const std::bitset<N2> &v2) {
454 std::bitset<N1 + N2> ret(v1.to_string() + v2.to_string());
455 return ret;
456}
457
458template<std::size_t S, std::size_t N>
459std::bitset<S> lsb(const std::bitset<N> &X) {
460 std::bitset<S> r;
461 for (std::size_t i = 0; i < S; ++i) {
462 r[i] = X[i];
463 }
464 return r;
465}
466
467template<std::size_t S, std::size_t N>
468std::bitset<S> msb(const std::bitset<N> &X) {
469 std::bitset<S> r;
470 for (std::size_t i = 0; i < S; ++i) {
471 r[S - 1 - i] = X[X.size() - 1 - i];
472 }
473 return r;
474}
475
476template<std::size_t N>
477std::bitset<N> inc32(const std::bitset<N> X) {
478 const std::size_t S = 32;
479
480 const auto a = msb<N - S>(X);
481 const std::bitset<S> b((lsb<S>(X).to_ulong() + 1)); // % (2^32);
482 // lsb<32> is low 32-bit value
483 // Spec.'s "mod 2^S" is not necessary when S is 32 (inc32).
484 // ...and 2^32 is over 32-bit integer.
485
486 return a || b;
487}
488
489#ifdef __clang__
490#pragma clang diagnostic push
491#pragma clang diagnostic ignored "-Wself-assign"
492#endif // __clang__
493
495inline Block mul_blocks(const Block X, const Block Y) {
496 const bitset128 R = (std::bitset<8>("11100001") || std::bitset<120>());
497
498 bitset128 X_bits = X.to_bits();
499 bitset128 Z;
500 bitset128 V = Y.to_bits();
501 for (int i = 127; i >= 0; --i) {
502 // Z
503 if (X_bits[i] == false) {
504 Z = Z;
505 }
506 else {
507 Z = Z ^ V;
508 }
509
510 // V
511 if (V[0] == false) {
512 V = V >> 1;
513 }
514 else {
515 V = (V >> 1) ^ R;
516 }
517 }
518
519 return Z;
520}
521
522#ifdef __clang__
523#pragma clang diagnostic pop
524#endif // __clang__
525
527inline Block ghash(const Block & H, const std::vector<unsigned char> & X) {
528 const std::size_t m = X.size() / kBlockByteSize;
529 Block Ym;
530 for (std::size_t i = 0; i < m; ++i) {
531 const Block Xi(&X[i * kBlockByteSize], kBlockByteSize);
532 Ym = mul_blocks((Ym ^ Xi), H);
533 }
534
535 return Ym;
536}
537
538template<std::size_t N>
539std::bitset<N> make_bitset(const unsigned char * bytes, const std::size_t bytes_size) {
540 std::bitset<N> bits;
541 for (auto i = 0u; i < bytes_size; ++i) {
542 bits <<= 8;
543 bits |= bytes[i];
544 }
545 return bits;
546}
547
549inline std::vector<unsigned char> gctr(const detail::RoundKeys & rkeys, const Block & ICB, const unsigned char * X, const std::size_t X_size){
550 if (!X || X_size == 0) {
551 return std::vector<unsigned char>();
552 }
553 else {
554 const unsigned long n = ceil(X_size * 8.0 / kBlockBitSize);
555 std::vector<unsigned char> Y(X_size);
556
557 Block CB;
558 for (std::size_t i = 0; i < n; ++i) {
559 // CB
560 if (i == 0) { // first
561 CB = ICB;
562 }
563 else {
564 CB = inc32(CB.to_bits());
565 }
566
567 // CIPH
568 Block eCB;
569 encrypt_state(rkeys, CB.data(), eCB.data());
570
571 // Y
572 int op_size = 0;
573 if (i < n - 1) {
574 op_size = kBlockByteSize;
575 }
576 else { // last
577 op_size = (X_size % kBlockByteSize) ? (X_size % kBlockByteSize) : kBlockByteSize;
578 }
579 const Block Yi = Block(X + i * kBlockBitSize / 8, op_size) ^ eCB;
580 memcpy(&Y[i * kBlockByteSize], Yi.data(), op_size);
581 }
582
583 return Y;
584 }
585}
586
587inline void push_back(std::vector<unsigned char> & bytes, const unsigned char * data, const std::size_t data_size) {
588 bytes.insert(bytes.end(), data, data + data_size);
589}
590
591inline void push_back(std::vector<unsigned char> & bytes, const std::bitset<64> & bits) {
592 const std::bitset<64> mask(0xFF); // 1 byte mask
593 for (std::size_t i = 0; i < 8; ++i) {
594 bytes.push_back(static_cast<unsigned char>(((bits >> ((7 - i) * 8)) & mask).to_ulong()));
595 }
596}
597
598inline void push_back_zero_bits(std::vector<unsigned char>& bytes, const std::size_t zero_bits_size) {
599 const std::vector<unsigned char> zero_bytes(zero_bits_size / 8);
600 bytes.insert(bytes.end(), zero_bytes.begin(), zero_bytes.end());
601}
602
603inline Block calc_H(const RoundKeys & rkeys) {
604 std::vector<unsigned char> H_raw(gcm::kBlockByteSize);
605 encrypt_state(rkeys, &H_raw[0], &H_raw[0]);
606 return gcm::Block(H_raw);
607}
608
609inline Block calc_J0(const Block & H, const unsigned char * iv, const std::size_t iv_size) {
610 if (iv_size == 12) {
611 const std::bitset<96> iv_bits = gcm::make_bitset<96>(iv, iv_size);
612 return iv_bits || std::bitset<31>() || std::bitset<1>(1);
613 }
614 else {
615 const auto len_iv = iv_size * 8;
616 const auto s = 128 * gcm::ceil(len_iv / 128.0) - len_iv;
617 std::vector<unsigned char> ghash_in;
618 gcm::push_back(ghash_in, iv, iv_size);
619 gcm::push_back_zero_bits(ghash_in, s + 64);
620 gcm::push_back(ghash_in, std::bitset<64>(len_iv));
621
622 return gcm::ghash(H, ghash_in);
623 }
624}
625
626inline void calc_gcm_tag(
627 const unsigned char * data,
628 const std::size_t data_size,
629 const unsigned char * aadata,
630 const std::size_t aadata_size,
631 const unsigned char * key,
632 const std::size_t key_size,
633 const unsigned char * iv,
634 const std::size_t iv_size,
635 unsigned char * tag,
636 const std::size_t tag_size
637) {
638 const detail::RoundKeys rkeys = detail::expand_key(key, static_cast<int>(key_size));
639 const gcm::Block H = gcm::calc_H(rkeys);
640 const gcm::Block J0 = gcm::calc_J0(H, iv, iv_size);
641
642 const auto lenC = data_size * 8;
643 const auto lenA = aadata_size * 8;
644 const std::size_t u = 128 * gcm::ceil(lenC / 128.0) - lenC;
645 const std::size_t v = 128 * gcm::ceil(lenA / 128.0) - lenA;
646
647 std::vector<unsigned char> ghash_in;
648 ghash_in.reserve((aadata_size + v / 8) + (data_size + u / 8) + 8 + 8);
649 gcm::push_back(ghash_in, aadata, aadata_size);
650 gcm::push_back_zero_bits(ghash_in, v);
651 gcm::push_back(ghash_in, data, data_size);
652 gcm::push_back_zero_bits(ghash_in, u);
653 gcm::push_back(ghash_in, std::bitset<64>(lenA));
654 gcm::push_back(ghash_in, std::bitset<64>(lenC));
655 const gcm::Block S = gcm::ghash(H, ghash_in);
656 const std::vector<unsigned char> T = gcm::gctr(rkeys, J0, S.data(), gcm::kBlockByteSize);
657
658 // return
659 memcpy(tag, &T[0], (std::min)(tag_size, static_cast<std::size_t>(16)));
660}
661
663inline void crypt_gcm(
664 const unsigned char* data,
665 const std::size_t data_size,
666 const unsigned char* key,
667 const std::size_t key_size,
668 const unsigned char* iv,
669 const std::size_t iv_size,
670 unsigned char* crypted
671) {
672 const detail::RoundKeys rkeys = detail::expand_key(key, static_cast<int>(key_size));
673 const gcm::Block H = gcm::calc_H(rkeys);
674 const gcm::Block J0 = gcm::calc_J0(H, iv, iv_size);
675
676 const std::vector<unsigned char> C = gcm::gctr(rkeys, gcm::inc32(J0.to_bits()), data, data_size);
677
678 if (crypted) {
679 memcpy(crypted, &C[0], data_size);
680 }
681}
682
683} // namespce detail::gcm
684
685} // namespace detail
686
692inline unsigned int version() {
693 return PLUSAES_VERSION;
694}
695
697inline std::vector<unsigned char> key_from_string(const char (*key_str)[17]) {
698 return detail::key_from_string<17>(key_str);
699}
700
702inline std::vector<unsigned char> key_from_string(const char (*key_str)[25]) {
703 return detail::key_from_string<25>(key_str);
704}
705
707inline std::vector<unsigned char> key_from_string(const char (*key_str)[33]) {
708 return detail::key_from_string<33>(key_str);
709}
710
712inline unsigned long get_padded_encrypted_size(const unsigned long data_size) {
713 return data_size + detail::kStateSize - (data_size % detail::kStateSize);
714}
715
717typedef enum {
718 kErrorOk = 0,
719 kErrorInvalidDataSize = 1,
720 kErrorInvalidKeySize,
721 kErrorInvalidBufferSize,
722 kErrorInvalidKey,
723 kErrorDeprecated, // kErrorInvalidNonceSize
724 kErrorInvalidIvSize,
725 kErrorInvalidTagSize,
726 kErrorInvalidTag
727} Error;
728
731namespace detail {
732
733inline Error check_encrypt_cond(
734 const unsigned long data_size,
735 const unsigned long key_size,
736 const unsigned long encrypted_size,
737 const bool pads) {
738 // check data size
739 if (!pads && (data_size % kStateSize != 0)) {
740 return kErrorInvalidDataSize;
741 }
742
743 // check key size
744 if (!detail::is_valid_key_size(key_size)) {
745 return kErrorInvalidKeySize;
746 }
747
748 // check encrypted buffer size
749 if (pads) {
750 const unsigned long required_size = get_padded_encrypted_size(data_size);
751 if (encrypted_size < required_size) {
752 return kErrorInvalidBufferSize;
753 }
754 }
755 else {
756 if (encrypted_size < data_size) {
757 return kErrorInvalidBufferSize;
758 }
759 }
760 return kErrorOk;
761}
762
763inline Error check_decrypt_cond(
764 const unsigned long data_size,
765 const unsigned long key_size,
766 const unsigned long decrypted_size,
767 const unsigned long * padded_size
768 ) {
769 // check data size
770 if (data_size % 16 != 0) {
771 return kErrorInvalidDataSize;
772 }
773
774 // check key size
775 if (!detail::is_valid_key_size(key_size)) {
776 return kErrorInvalidKeySize;
777 }
778
779 // check decrypted buffer size
780 if (!padded_size) {
781 if (decrypted_size < data_size) {
782 return kErrorInvalidBufferSize;
783 }
784 }
785 else {
786 if (decrypted_size < (data_size - kStateSize)) {
787 return kErrorInvalidBufferSize;
788 }
789 }
790
791 return kErrorOk;
792}
793
794inline bool check_padding(const unsigned long padding, const unsigned char data[kStateSize]) {
795 if (padding > kStateSize) {
796 return false;
797 }
798
799 for (unsigned long i = 0; i < padding; ++i) {
800 if (data[kStateSize - 1 - i] != padding) {
801 return false;
802 }
803 }
804
805 return true;
806}
807
808inline Error check_gcm_cond(
809 const std::size_t key_size,
810 const std::size_t iv_size,
811 const std::size_t tag_size
812) {
813 // check key size
814 if (!detail::is_valid_key_size(key_size)) {
815 return kErrorInvalidKeySize;
816 }
817
818 if (iv_size < 1) {
819 return kErrorInvalidIvSize;
820 }
821
822 // check tag size
823 if ((tag_size < 12 || 16 < tag_size) &&
824 (tag_size != 8) &&
825 (tag_size != 4)) {
826 return kErrorInvalidTagSize;
827 }
828
829 return kErrorOk;
830}
831
832} // namespace detail
833
854 const unsigned char * data,
855 const unsigned long data_size,
856 const unsigned char * key,
857 const unsigned long key_size,
858 unsigned char *encrypted,
859 const unsigned long encrypted_size,
860 const bool pads
861 ) {
862 const Error e = detail::check_encrypt_cond(data_size, key_size, encrypted_size, pads);
863 if (e != kErrorOk) {
864 return e;
865 }
866
867 const detail::RoundKeys rkeys = detail::expand_key(key, static_cast<int>(key_size));
868
869 const unsigned long bc = data_size / detail::kStateSize;
870 for (unsigned long i = 0; i < bc; ++i) {
871 detail::encrypt_state(rkeys, data + (i * detail::kStateSize), encrypted + (i * detail::kStateSize));
872 }
873
874 if (pads) {
875 const int rem = data_size % detail::kStateSize;
876 const char pad_v = detail::kStateSize - rem;
877
878 std::vector<unsigned char> ib(detail::kStateSize, pad_v), ob(detail::kStateSize);
879 memcpy(&ib[0], data + data_size - rem, rem);
880
881 detail::encrypt_state(rkeys, &ib[0], &ob[0]);
882 memcpy(encrypted + (data_size - rem), &ob[0], detail::kStateSize);
883 }
884
885 return kErrorOk;
886}
887
902 const unsigned char * data,
903 const unsigned long data_size,
904 const unsigned char * key,
905 const unsigned long key_size,
906 unsigned char * decrypted,
907 const unsigned long decrypted_size,
908 unsigned long * padded_size
909 ) {
910 const Error e = detail::check_decrypt_cond(data_size, key_size, decrypted_size, padded_size);
911 if (e != kErrorOk) {
912 return e;
913 }
914
915 const detail::RoundKeys rkeys = detail::expand_key(key, static_cast<int>(key_size));
916
917 const unsigned long bc = data_size / detail::kStateSize - 1;
918 for (unsigned long i = 0; i < bc; ++i) {
919 detail::decrypt_state(rkeys, data + (i * detail::kStateSize), decrypted + (i * detail::kStateSize));
920 }
921
922 unsigned char last[detail::kStateSize] = {};
923 detail::decrypt_state(rkeys, data + (bc * detail::kStateSize), last);
924
925 if (padded_size) {
926 *padded_size = last[detail::kStateSize - 1];
927 const unsigned long cs = detail::kStateSize - *padded_size;
928
929 if (!detail::check_padding(*padded_size, last)) {
930 return kErrorInvalidKey;
931 }
932 else if (decrypted_size >= (bc * detail::kStateSize) + cs) {
933 memcpy(decrypted + (bc * detail::kStateSize), last, cs);
934 }
935 else {
936 return kErrorInvalidBufferSize;
937 }
938 }
939 else {
940 memcpy(decrypted + (bc * detail::kStateSize), last, sizeof(last));
941 }
942
943 return kErrorOk;
944}
945
969 const unsigned char * data,
970 const unsigned long data_size,
971 const unsigned char * key,
972 const unsigned long key_size,
973 const unsigned char (* iv)[16],
974 unsigned char * encrypted,
975 const unsigned long encrypted_size,
976 const bool pads
977 ) {
978 const Error e = detail::check_encrypt_cond(data_size, key_size, encrypted_size, pads);
979 if (e != kErrorOk) {
980 return e;
981 }
982
983 const detail::RoundKeys rkeys = detail::expand_key(key, static_cast<int>(key_size));
984
985 unsigned char s[detail::kStateSize] = {}; // encrypting data
986
987 // calculate padding value
988 const bool ge16 = (data_size >= detail::kStateSize);
989 const int rem = data_size % detail::kStateSize;
990 const unsigned char pad_v = detail::kStateSize - rem;
991
992 // encrypt 1st state
993 if (ge16) {
994 memcpy(s, data, detail::kStateSize);
995 }
996 else {
997 memset(s, pad_v, detail::kStateSize);
998 memcpy(s, data, data_size);
999 }
1000 if (iv) {
1001 detail::xor_data(s, *iv);
1002 }
1003 detail::encrypt_state(rkeys, s, encrypted);
1004
1005 // encrypt mid
1006 const unsigned long bc = data_size / detail::kStateSize;
1007 for (unsigned long i = 1; i < bc; ++i) {
1008 const long offset = i * detail::kStateSize;
1009 memcpy(s, data + offset, detail::kStateSize);
1010 detail::xor_data(s, encrypted + offset - detail::kStateSize);
1011
1012 detail::encrypt_state(rkeys, s, encrypted + offset);
1013 }
1014
1015 // enctypt last
1016 if (pads && ge16) {
1017 std::vector<unsigned char> ib(detail::kStateSize, pad_v), ob(detail::kStateSize);
1018 memcpy(&ib[0], data + data_size - rem, rem);
1019
1020 detail::xor_data(&ib[0], encrypted + (bc - 1) * detail::kStateSize);
1021
1022 detail::encrypt_state(rkeys, &ib[0], &ob[0]);
1023 memcpy(encrypted + (data_size - rem), &ob[0], detail::kStateSize);
1024 }
1025
1026 return kErrorOk;
1027}
1028
1044 const unsigned char * data,
1045 const unsigned long data_size,
1046 const unsigned char * key,
1047 const unsigned long key_size,
1048 const unsigned char (* iv)[16],
1049 unsigned char * decrypted,
1050 const unsigned long decrypted_size,
1051 unsigned long * padded_size
1052 ) {
1053 const Error e = detail::check_decrypt_cond(data_size, key_size, decrypted_size, padded_size);
1054 if (e != kErrorOk) {
1055 return e;
1056 }
1057
1058 const detail::RoundKeys rkeys = detail::expand_key(key, static_cast<int>(key_size));
1059
1060 // decrypt 1st state
1061 detail::decrypt_state(rkeys, data, decrypted);
1062 if (iv) {
1063 detail::xor_data(decrypted, *iv);
1064 }
1065
1066 // decrypt mid
1067 const unsigned long bc = data_size / detail::kStateSize - 1;
1068 for (unsigned long i = 1; i < bc; ++i) {
1069 const long offset = i * detail::kStateSize;
1070 detail::decrypt_state(rkeys, data + offset, decrypted + offset);
1071 detail::xor_data(decrypted + offset, data + offset - detail::kStateSize);
1072 }
1073
1074 // decrypt last
1075 unsigned char last[detail::kStateSize] = {};
1076 if (data_size > detail::kStateSize) {
1077 detail::decrypt_state(rkeys, data + (bc * detail::kStateSize), last);
1078 detail::xor_data(last, data + (bc * detail::kStateSize - detail::kStateSize));
1079 }
1080 else {
1081 memcpy(last, decrypted, data_size);
1082 memset(decrypted, 0, decrypted_size);
1083 }
1084
1085 if (padded_size) {
1086 *padded_size = last[detail::kStateSize - 1];
1087 const unsigned long cs = detail::kStateSize - *padded_size;
1088
1089 if (!detail::check_padding(*padded_size, last)) {
1090 return kErrorInvalidKey;
1091 }
1092 else if (decrypted_size >= (bc * detail::kStateSize) + cs) {
1093 memcpy(decrypted + (bc * detail::kStateSize), last, cs);
1094 }
1095 else {
1096 return kErrorInvalidBufferSize;
1097 }
1098 }
1099 else {
1100 memcpy(decrypted + (bc * detail::kStateSize), last, sizeof(last));
1101 }
1102
1103 return kErrorOk;
1104}
1105
1124 unsigned char * data,
1125 const std::size_t data_size,
1126 const unsigned char * aadata,
1127 const std::size_t aadata_size,
1128 const unsigned char * key,
1129 const std::size_t key_size,
1130 const unsigned char * iv,
1131 const std::size_t iv_size,
1132 unsigned char * tag,
1133 const std::size_t tag_size
1134) {
1135 const Error err = detail::check_gcm_cond(key_size, iv_size, tag_size);
1136 if (err != kErrorOk) {
1137 return err;
1138 }
1139
1140 detail::gcm::crypt_gcm(data, data_size, key, key_size, iv, iv_size, data);
1141 detail::gcm::calc_gcm_tag(data, data_size, aadata, aadata_size, key, key_size, iv, iv_size, tag, tag_size);
1142
1143 return kErrorOk;
1144}
1145
1163 unsigned char * data,
1164 const std::size_t data_size,
1165 const unsigned char * aadata,
1166 const std::size_t aadata_size,
1167 const unsigned char * key,
1168 const std::size_t key_size,
1169 const unsigned char (*iv)[12],
1170 unsigned char (*tag)[16]
1171) {
1172 return encrypt_gcm(data, data_size, aadata, aadata_size, key, key_size, *iv, 12, *tag, 16);
1173}
1174
1188 unsigned char * data,
1189 const std::size_t data_size,
1190 const unsigned char * aadata,
1191 const std::size_t aadata_size,
1192 const unsigned char * key,
1193 const std::size_t key_size,
1194 const unsigned char * iv,
1195 const std::size_t iv_size,
1196 const unsigned char * tag,
1197 const std::size_t tag_size
1198) {
1199 const Error err = detail::check_gcm_cond(key_size, iv_size, tag_size);
1200 if (err != kErrorOk) {
1201 return err;
1202 }
1203
1204 unsigned char * C = data;
1205 const auto C_size = data_size;
1206 unsigned char tagd[16] = {};
1207 detail::gcm::calc_gcm_tag(C, C_size, aadata, aadata_size, key, key_size, iv, iv_size, tagd, 16);
1208
1209 if (memcmp(tag, tagd, tag_size) != 0) {
1210 return kErrorInvalidTag;
1211 }
1212 else {
1213 detail::gcm::crypt_gcm(C, C_size, key, key_size, iv, iv_size, C);
1214
1215 return kErrorOk;
1216 }
1217}
1218
1237 unsigned char * data,
1238 const std::size_t data_size,
1239 const unsigned char * aadata,
1240 const std::size_t aadata_size,
1241 const unsigned char * key,
1242 const std::size_t key_size,
1243 const unsigned char (*iv)[12],
1244 const unsigned char (*tag)[16]
1245) {
1246 return decrypt_gcm(data, data_size, aadata, aadata_size, key, key_size, *iv, 12, *tag, 16);
1247}
1248
1270 unsigned char * data,
1271 const std::size_t data_size,
1272 const unsigned char * key,
1273 const std::size_t key_size,
1274 const unsigned char (*nonce)[16]
1275) {
1276 if (!detail::is_valid_key_size(key_size)) return kErrorInvalidKeySize;
1277 const detail::RoundKeys rkeys = detail::expand_key(key, static_cast<int>(key_size));
1278
1279 unsigned long pos = 0;
1280 unsigned long blkpos = detail::kStateSize;
1281 unsigned char blk[detail::kStateSize] = {};
1282 unsigned char counter[detail::kStateSize] = {};
1283 memcpy(counter, nonce, 16);
1284
1285 while (pos < data_size) {
1286 if (blkpos == detail::kStateSize) {
1287 detail::encrypt_state(rkeys, counter, blk);
1288 detail::incr_counter(counter);
1289 blkpos = 0;
1290 }
1291 data[pos++] ^= blk[blkpos++];
1292 }
1293
1294 return kErrorOk;
1295}
1296
1299} // namespace plusaes
1300
1301#endif // PLUSAES_HPP__
unsigned int version()
Definition: plusaes.hpp:692
std::vector< unsigned char > key_from_string(const char(*key_str)[17])
Definition: plusaes.hpp:697
#define PLUSAES_VERSION
Definition: plusaes.hpp:22
Error
Definition: plusaes.hpp:717
unsigned long get_padded_encrypted_size(const unsigned long data_size)
Definition: plusaes.hpp:712
Error decrypt_cbc(const unsigned char *data, const unsigned long data_size, const unsigned char *key, const unsigned long key_size, const unsigned char(*iv)[16], unsigned char *decrypted, const unsigned long decrypted_size, unsigned long *padded_size)
Definition: plusaes.hpp:1043
Error encrypt_cbc(const unsigned char *data, const unsigned long data_size, const unsigned char *key, const unsigned long key_size, const unsigned char(*iv)[16], unsigned char *encrypted, const unsigned long encrypted_size, const bool pads)
Definition: plusaes.hpp:968
Error crypt_ctr(unsigned char *data, const std::size_t data_size, const unsigned char *key, const std::size_t key_size, const unsigned char(*nonce)[16])
Definition: plusaes.hpp:1269
Error decrypt_ecb(const unsigned char *data, const unsigned long data_size, const unsigned char *key, const unsigned long key_size, unsigned char *decrypted, const unsigned long decrypted_size, unsigned long *padded_size)
Definition: plusaes.hpp:901
Error encrypt_ecb(const unsigned char *data, const unsigned long data_size, const unsigned char *key, const unsigned long key_size, unsigned char *encrypted, const unsigned long encrypted_size, const bool pads)
Definition: plusaes.hpp:853
Error encrypt_gcm(unsigned char *data, const std::size_t data_size, const unsigned char *aadata, const std::size_t aadata_size, const unsigned char *key, const std::size_t key_size, const unsigned char *iv, const std::size_t iv_size, unsigned char *tag, const std::size_t tag_size)
Definition: plusaes.hpp:1123
Error decrypt_gcm(unsigned char *data, const std::size_t data_size, const unsigned char *aadata, const std::size_t aadata_size, const unsigned char *key, const std::size_t key_size, const unsigned char *iv, const std::size_t iv_size, const unsigned char *tag, const std::size_t tag_size)
Definition: plusaes.hpp:1187
Definition: plusaes.hpp:27