rijndael_impl.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation>
3 //
4 // MIT License
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in all
14 // copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 // SOFTWARE.
23 //---------------------------------------------------------------------------//
24 
25 #ifndef CRYPTO3_RIJNDAEL_IMPL_HPP
26 #define CRYPTO3_RIJNDAEL_IMPL_HPP
27 
29 
30 #include <nil/crypto3/detail/stream_endian.hpp>
31 #include <nil/crypto3/detail/pack.hpp>
32 
33 namespace nil {
34  namespace crypto3 {
35  namespace block {
39  namespace detail {
40  template<std::size_t KeyBitsImpl, std::size_t BlockBitsImpl, typename PolicyType>
41  class rijndael_impl {
42  typedef PolicyType policy_type;
43 
44  typedef typename policy_type::key_type key_type;
45  typedef typename policy_type::key_schedule_type key_schedule_type;
46  typedef typename policy_type::key_schedule_word_type key_schedule_word_type;
47 
48  typedef typename policy_type::block_type block_type;
49 
50  typedef typename policy_type::constants_type constants_type;
51  typedef typename policy_type::shift_offsets_type shift_offsets_type;
52  typedef typename policy_type::mm_type mm_type;
53 
54  BOOST_STATIC_ASSERT(KeyBitsImpl == PolicyType::key_bits);
55  BOOST_STATIC_ASSERT(BlockBitsImpl == PolicyType::block_bits);
56 
57  static inline key_schedule_word_type sub_word(const key_schedule_word_type &x,
58  const constants_type &constants) {
59  key_schedule_word_type result = {0};
60 
61  for (std::size_t i = 0; i < policy_type::word_bytes; ++i) {
62  result =
63  result << CHAR_BIT | constants[::nil::crypto3::detail::extract_uint_t<CHAR_BIT>(x, i)];
64  }
65 
66  return result;
67  }
68 
69  static inline void sub_bytes(block_type &state, const constants_type &sbox) {
70 
71  for (std::size_t i = 0; i < policy_type::word_bytes * policy_type::block_words; ++i) {
72  state[i] = sbox[state[i]];
73  }
74  }
75 
76  static inline void shift_rows(block_type &state, const shift_offsets_type &offset) {
77  std::array<typename policy_type::byte_type, policy_type::block_words> tmp = {0};
78 
79  // row 0 never gets shifted
80 
81  for (std::size_t row = 1; row < policy_type::word_bytes; ++row) {
82  const std::size_t off = offset[row - 1];
83 
84  for (std::size_t i = 0; i < off; ++i) {
85  tmp[i] = state[i * policy_type::word_bytes + row];
86  }
87 
88  for (std::size_t i = 0; i < policy_type::block_words - 1; ++i) {
89  state[i * policy_type::word_bytes + row] =
90  state[(i + off) * policy_type::word_bytes + row];
91  }
92 
93  for (std::size_t i = 0; i < off; ++i) {
94  state[(policy_type::block_words - 1 - i) * policy_type::word_bytes + row] =
95  tmp[off - 1 - i];
96  }
97  }
98  }
99 
100  template<typename StateType>
101  static inline block_type mix_columns(const StateType &state, const mm_type &mm) {
102  block_type tmp = {0};
103 
104 
105  for (std::size_t col = 0; col < policy_type::block_words; ++col) {
106 
107  for (std::size_t row = 0; row < policy_type::word_bytes; ++row) {
108 
109  for (std::size_t k = 0; k < policy_type::word_bytes; ++k) {
110  tmp[col * policy_type::word_bytes + row] ^=
111  policy_type::mul(mm[row * policy_type::word_bytes + k],
112  state[col * policy_type::word_bytes + k]);
113  }
114  }
115  }
116 
117  return tmp;
118  }
119 
120  template<typename InputIterator>
121  static inline void add_round_key(block_type &state, InputIterator first, InputIterator last) {
122  BOOST_ASSERT(std::distance(first, last) == policy_type::block_words &&
123  state.size() == policy_type::block_bytes);
124 
125 
126  for (std::size_t i = 0; i < policy_type::block_words && first != last; ++i && ++first) {
127 
128  for (std::size_t j = 0; j < policy_type::word_bytes; ++j) {
129  state[i * policy_type::word_bytes + j] ^=
130  ::nil::crypto3::detail::extract_uint_t<CHAR_BIT>(*first,
131  policy_type::word_bytes - (j + 1));
132  }
133  }
134  }
135 
136  static inline void apply_round(std::uint8_t round, block_type &state, const key_schedule_type &w,
137  const constants_type &sbox, const shift_offsets_type &offsets,
138  const mm_type &mm) {
139  sub_bytes(state, sbox);
140  shift_rows(state, offsets);
141  state = mix_columns(state, mm);
142  add_round_key(state, w.begin() + round * policy_type::block_words,
143  w.begin() + (round + 1) * policy_type::block_words);
144  }
145 
146  public:
147  static typename policy_type::block_type encrypt_block(const block_type &plaintext,
148  const key_schedule_type &encryption_key) {
149  block_type state = plaintext;
150 
151  add_round_key(state, encryption_key.begin(), encryption_key.begin() + policy_type::block_words);
152 
153 
154  for (std::size_t round = 1; round < policy_type::rounds; ++round) {
155  apply_round(round, state, encryption_key, policy_type::constants,
156  policy_type::shift_offsets, policy_type::mm);
157  }
158 
159  sub_bytes(state, policy_type::constants);
160  shift_rows(state, policy_type::shift_offsets);
161  add_round_key(state, encryption_key.begin() + policy_type::rounds * policy_type::block_words,
162  encryption_key.begin() + (policy_type::rounds + 1) * policy_type::block_words);
163 
164  return state;
165  }
166 
167  static typename policy_type::block_type decrypt_block(const block_type &plaintext,
168  const key_schedule_type &decryption_key) {
169  block_type state = plaintext;
170 
171  add_round_key(state, decryption_key.begin() + policy_type::rounds * policy_type::block_words,
172  decryption_key.begin() + (policy_type::rounds + 1) * policy_type::block_words);
173 
174 
175  for (std::size_t round = policy_type::rounds - 1; round > 0; --round) {
176  apply_round(round, state, decryption_key, policy_type::inverted_constants,
177  policy_type::inverted_shift_offsets, policy_type::inverted_mm);
178  }
179 
180  sub_bytes(state, policy_type::inverted_constants);
181  shift_rows(state, policy_type::inverted_shift_offsets);
182  add_round_key(state, decryption_key.begin(), decryption_key.begin() + policy_type::block_words);
183 
184  return state;
185  }
186 
187  static void schedule_key(const key_type &key, key_schedule_type &encryption_key,
188  key_schedule_type &decryption_key) {
189  // the first key_words words are the original key
192  policy_type::word_bits>(
193  key.begin(), key.begin() + policy_type::key_words * policy_type::word_bytes,
194  encryption_key.begin());
195 
196 
197  for (std::size_t i = policy_type::key_words; i < policy_type::key_schedule_words; ++i) {
198  typename policy_type::key_schedule_word_type tmp = encryption_key[i - 1];
199  if (i % policy_type::key_words == 0) {
200  tmp = sub_word(policy_type::rotate_left(tmp), policy_type::constants) ^
201  policy_type::round_constants[i / policy_type::key_words - 1];
202  } else if (policy_type::key_words > 6 && i % policy_type::key_words == 4) {
203  tmp = sub_word(tmp, policy_type::constants);
204  }
205  encryption_key[i] = encryption_key[i - policy_type::key_words] ^ tmp;
206  }
207 
208  std::array<typename policy_type::byte_type, policy_type::key_schedule_bytes> bekey = {0};
210  stream_endian::big_octet_big_bit, policy_type::word_bits,
211  CHAR_BIT>(encryption_key.begin(), encryption_key.end(),
212  bekey.begin());
213 
214 
215  for (std::uint8_t round = 1; round < policy_type::rounds; ++round) {
216  move(mix_columns(boost::adaptors::slice(bekey, round * policy_type::block_bytes,
217  (round + 1) * policy_type::block_bytes),
218  policy_type::inverted_mm),
219  bekey.begin() + round * policy_type::block_bytes);
220  }
221 
224  policy_type::word_bits>(bekey.begin(), bekey.end(),
225  decryption_key.begin());
226  }
227  };
228  } // namespace detail
232  } // namespace block
233  } // namespace crypto3
234 } // namespace nil
235 
236 #endif // CRYPTO3_RIJNDAEL_IMPL_HPP
void pack(InputIterator first, InputIterator last, std::random_access_iterator_tag, OutputIterator out)
Packs elements from the range [first, last) into elements starting from out. Works for input containe...
Definition: block/include/nil/crypto3/detail/pack.hpp:835
constexpr vector< T, M > slice(vector< T, N > v, std::size_t start=0)
slices a vector into a subvector
Definition: vector/utility.hpp:170
boost::mpl::apply< AccumulatorSet, tag::block< Mode > >::type::result_type block(const AccumulatorSet &acc)
Definition: accumulators/block.hpp:259
OutputIterator move(const SinglePassRange &rng, OutputIterator result)
Definition: move.hpp:45
little_unit_big_bit< 8 > little_octet_big_bit
Definition: algebra/include/nil/crypto3/detail/stream_endian.hpp:65
big_unit_big_bit< 8 > big_octet_big_bit
Definition: algebra/include/nil/crypto3/detail/stream_endian.hpp:55
Definition: pair.hpp:31