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_BOTAN_AES_H
21 #define CS_CRYPTO_DRIVERS_BOTAN_AES_H
22 
23 #ifdef CSCRYPTO_HAVE_BOTAN
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 <cstddef>
36 #include <optional>
37 
38 #include <botan/aes.h>
39 #include <botan/cipher_mode.h>
40 #include <botan/cbc.h>
41 #include <botan/cfb.h>
42 
43 namespace cs_crypto::drivers::botan {
44 
45 template <typename Botan_T>
46 class aes_interface : public Botan_T
47 {
48  public:
49  using cipher_type = typename Botan_T::cipher_type;
50  using mode_type = typename Botan_T::mode_type;
51 
52  using key_type = typename Botan_T::key_type;
53  using iv_type = typename Botan_T::iv_type;
54 
55  aes_interface(const aes_interface &) = delete;
56 
57  ~aes_interface() = default;
58 
59  aes_interface &operator=(const aes_interface &) & = delete;
60 
61  aes_interface(aes_interface&&) = default;
62  aes_interface &operator=(aes_interface&&) & = default;
63 
64  static std::optional<aes_interface> make_context(key_type &&secret_key, iv_type &&iv)
65  {
66  auto context = Botan_T::make_context();
67 
68  if (context == nullptr) {
69  return std::nullopt;
70  }
71 
72  // The key and nonce are copied into the context by Botan, no need to
73  // store the key and nonce after this point.
74 
75  context->set_key(util::from_byte_ptr(secret_key.data()), secret_key.size());
76  context->start(util::from_byte_ptr(iv.data()), iv.size());
77 
78  return aes_interface(std::move(context));
79  }
80 
81  void update(cs_crypto::util::span<std::byte> plaintext_block) &
82  {
83  cs_crypto::util::span<uint8_t> uint_view = {util::from_byte_ptr(plaintext_block.data()), plaintext_block.size()};
84  m_plaintext.insert(m_plaintext.end(), uint_view.begin(), uint_view.end());
85  }
86 
87  std::vector<std::byte> finalize() &&
88  {
89  std::vector<std::byte> result;
90  m_context->finish(m_plaintext);
91 
92  result.resize(m_plaintext.size());
93  cs_crypto::util::span<std::byte> byte_view = {util::to_byte_ptr(m_plaintext.data()), m_plaintext.size()};
94  std::copy(byte_view.begin(), byte_view.end(), result.begin());
95 
96  return result;
97  }
98 
99  private:
100  Botan::secure_vector<uint8_t> m_plaintext;
101  std::unique_ptr<typename Botan_T::botan_context> m_context;
102 
103  explicit aes_interface(std::unique_ptr<typename Botan_T::botan_context> &&context)
104  : m_plaintext(), m_context(std::move(context))
105  {
106  }
107 };
108 
109 template <typename Cipher, typename Mode, bool Encryption>
110 struct aes_internal {
111  static_assert(cs_crypto::traits::always_false<Cipher>{}, "Cipher and Mode combination is not available");
112 };
113 
114 template <typename Cipher, bool Encryption>
115 struct aes_internal<Cipher, block_cipher::mode::CBC, Encryption> {
116  using cipher_type = Cipher;
117  using mode_type = block_cipher::mode::CBC;
118 
119  using key_type = cipher::secret_key<cipher::traits::key_size_v<cipher_type>>;
120  using iv_type = cipher::init_vector<cipher::traits::iv_size_v<mode_type>>;
121 
122  using botan_context = std::conditional_t<Encryption, Botan::CBC_Encryption, Botan::CBC_Decryption>;
123 
124  ~aes_internal() = default;
125 
126  static std::unique_ptr<botan_context> make_context() noexcept
127  {
128  std::unique_ptr<botan_context> context;
129 
130  if constexpr (std::is_same_v<Cipher, block_cipher::aes128>) {
131  return std::make_unique<botan_context>(new Botan::AES_128, new Botan::PKCS7_Padding);
132 
133  } else if constexpr (std::is_same_v<Cipher, block_cipher::aes192>) {
134  return std::make_unique<botan_context>(new Botan::AES_192, new Botan::PKCS7_Padding);
135 
136  } else if constexpr (std::is_same_v<Cipher, block_cipher::aes256>) {
137  return std::make_unique<botan_context>(new Botan::AES_256, new Botan::PKCS7_Padding);
138  }
139 
140  return nullptr;
141  }
142 };
143 
144 struct cipher_mode : public basic_cipher_mode {
145  template <typename Cipher, typename Mode>
146  using encrypt = aes_interface<aes_internal<Cipher, Mode, true>>;
147 
148  template <typename Cipher, typename Mode>
149  using decrypt = aes_interface<aes_internal<Cipher, Mode, false>>;
150 };
151 
152 } // namespace cs_crypto::drivers::botan
153 
154 #endif // CSCRYPTO_HAVE_BOTAN
155 
156 #endif