CsCrypto  1.0.1
aes.h
1 /***********************************************************************
2 *
3 * Copyright (c) 2021-2024 Tim van Deurzen
4 * Copyright (c) 2021-2024 Barbara Geller
5 * Copyright (c) 2021-2024 Ansel Sermersheim
6 *
7 * This file is part of CsCrypto.
8 *
9 * CsCrypto is free software, released under the BSD 2-Clause license.
10 * For license details refer to LICENSE provided with this project.
11 *
12 * CsCrypto is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * https://opensource.org/licenses/BSD-2-Clause
17 *
18 ***********************************************************************/
19 
20 #ifndef CS_CRYPTO_DRIVERS_OPENSSL_AES_H
21 #define CS_CRYPTO_DRIVERS_OPENSSL_AES_H
22 
23 #ifdef CSCRYPTO_HAVE_OPENSSL
24 
25 #include <core/cipher/block/aes.h>
26 #include <core/cipher/block/mode.h>
27 #include <core/cipher/sym_secret_key.h>
28 #include <core/cipher/sym_init_vector.h>
29 #include <core/cipher/sym_traits.h>
30 #include <drivers/base/aes.h>
31 #include <util/conversions/byte.h>
32 #include <util/tools/crypto_traits.h>
33 #include <util/tools/span.h>
34 
35 #include <algorithm>
36 #include <array>
37 #include <cstddef>
38 #include <iterator>
39 #include <memory>
40 #include <vector>
41 #include <optional>
42 
43 #include <openssl/evp.h>
44 
45 namespace cs_crypto::drivers::openssl {
46 
47 template <typename Cipher, typename Mode>
48 struct initialization_fn {
49  static_assert(cs_crypto::traits::always_false<Cipher>{}, "Cipher and Mode combination is not available");
50 };
51 
52 template <typename Cipher, typename Mode, bool Encryption = true>
53 class aes_interface
54 {
55  public:
56  using cipher_type = Cipher;
57  using mode_type = Mode;
58 
59  using key_type = cipher::secret_key<cipher::traits::key_size_v<Cipher>>;
60  using iv_type = cipher::init_vector<cipher::traits::iv_size_v<Mode>>;
61 
62  ~aes_interface() = default;
63 
64  aes_interface(const aes_interface &) = delete;
65  aes_interface(aes_interface &&) = default;
66 
67  aes_interface &operator=(const aes_interface &) & = delete;
68  aes_interface &operator=(aes_interface &&) & = default;
69 
70  static std::optional<aes_interface> make_context(key_type &&secret_key, iv_type &&iv)
71  {
72  // initialization of the cipher context copies the key and context,
73  // no need to store them after this point
74 
75  context_type context(EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
76 
77  int result;
78 
79  if constexpr (Encryption) {
80  result = EVP_EncryptInit_ex(context.get(), initializer(), nullptr,
81  util::from_byte_ptr(secret_key.data()), util::from_byte_ptr(iv.data()));
82 
83  } else {
84  result = EVP_DecryptInit_ex(context.get(), initializer(), nullptr,
85  util::from_byte_ptr(secret_key.data()), util::from_byte_ptr(iv.data()));
86  }
87 
88  if (result != 1) {
89  return std::nullopt;
90  }
91 
92  return aes_interface(std::move(context));
93  }
94 
95  void update(util::span<std::byte> plaintext_block) &
96  {
97  int len = m_ciphertext.size();
98  m_ciphertext.resize(len + plaintext_block.size() + Cipher::block_size);
99 
100  if constexpr (Encryption) {
101  EVP_EncryptUpdate(m_context.get(), util::from_byte_ptr(m_ciphertext.data() + m_last_byte_written),
102  &len, util::from_byte_ptr(plaintext_block.data()), plaintext_block.size());
103 
104  } else {
105  EVP_DecryptUpdate(m_context.get(), util::from_byte_ptr(m_ciphertext.data() + m_last_byte_written),
106  &len, util::from_byte_ptr(plaintext_block.data()), plaintext_block.size());
107  }
108 
109  m_last_byte_written += len;
110  }
111 
112  std::vector<std::byte> finalize() &&
113  {
114  std::vector<std::byte> result;
115  int len;
116  m_ciphertext.resize(m_ciphertext.size() + Cipher::block_size);
117 
118  if constexpr (Encryption) {
119  EVP_EncryptFinal_ex(m_context.get(),
120  util::from_byte_ptr(m_ciphertext.data()) + m_last_byte_written, &len);
121  } else {
122  EVP_DecryptFinal_ex(m_context.get(),
123  util::from_byte_ptr(m_ciphertext.data()) + m_last_byte_written, &len);
124  }
125 
126  result.resize(m_last_byte_written + len);
127  std::copy_n(m_ciphertext.begin(), m_last_byte_written + len, result.begin());
128  return result;
129  }
130 
131  private:
132  using context_type = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>;
133  context_type m_context;
134 
135  std::vector<std::byte> m_ciphertext = {};
136  std::size_t m_last_byte_written = 0;
137 
138  constexpr static const auto initializer = initialization_fn<Cipher, Mode>::init_function;
139 
140  aes_interface(context_type &&context)
141  : m_context(std::move(context))
142  {
143  }
144 };
145 
146 template <>
147 struct initialization_fn<block_cipher::aes128, block_cipher::mode::CBC> {
148  constexpr static const auto init_function = EVP_aes_128_cbc;
149 };
150 
151 template <>
152 struct initialization_fn<block_cipher::aes192, block_cipher::mode::CBC> {
153  constexpr static const auto init_function = EVP_aes_192_cbc;
154 };
155 
156 template <>
157 struct initialization_fn<block_cipher::aes256, block_cipher::mode::CBC> {
158  constexpr static const auto init_function = EVP_aes_256_cbc;
159 };
160 
161 struct cipher_mode : public basic_cipher_mode {
162  template <typename Cipher, typename Mode>
163  using encrypt = aes_interface<Cipher, Mode, true>;
164 
165  template <typename Cipher, typename Mode>
166  using decrypt = aes_interface<Cipher, Mode, false>;
167 };
168 
169 } // namespace cs_crypto::drivers::openssl
170 
171 #endif // CSCRYPTO_HAVE_OPENSSL
172 
173 #endif