Botan 2.17.3
Crypto and TLS for C&
openssl_block.cpp
Go to the documentation of this file.
1/*
2* Block Ciphers via OpenSSL
3* (C) 1999-2010,2015 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/block_cipher.h>
9#include <botan/internal/openssl.h>
10#include <openssl/evp.h>
11
12namespace Botan {
13
14namespace {
15
16class OpenSSL_BlockCipher final : public BlockCipher
17 {
18 public:
19 OpenSSL_BlockCipher(const std::string& name,
20 const EVP_CIPHER* cipher);
21
22 OpenSSL_BlockCipher(const std::string& name,
23 const EVP_CIPHER* cipher,
24 size_t kl_min, size_t kl_max, size_t kl_mod);
25
26 ~OpenSSL_BlockCipher();
27
28 void clear() override;
29 std::string provider() const override { return "openssl"; }
30 std::string name() const override { return m_cipher_name; }
31 BlockCipher* clone() const override;
32
33 size_t block_size() const override { return m_block_sz; }
34
35 Key_Length_Specification key_spec() const override { return m_cipher_key_spec; }
36
37 void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
38 {
39 verify_key_set(m_key_set);
40 int out_len = 0;
41 if(!EVP_EncryptUpdate(m_encrypt, out, &out_len, in, blocks * m_block_sz))
42 throw OpenSSL_Error("EVP_EncryptUpdate", ERR_get_error());
43 }
44
45 void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
46 {
47 verify_key_set(m_key_set);
48 int out_len = 0;
49 if(!EVP_DecryptUpdate(m_decrypt, out, &out_len, in, blocks * m_block_sz))
50 throw OpenSSL_Error("EVP_DecryptUpdate", ERR_get_error());
51 }
52
53 void key_schedule(const uint8_t key[], size_t key_len) override;
54
55 size_t m_block_sz;
56 Key_Length_Specification m_cipher_key_spec;
57 std::string m_cipher_name;
58 EVP_CIPHER_CTX *m_encrypt;
59 EVP_CIPHER_CTX *m_decrypt;
61 };
62
63OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name,
64 const EVP_CIPHER* algo) :
65 m_block_sz(EVP_CIPHER_block_size(algo)),
66 m_cipher_key_spec(EVP_CIPHER_key_length(algo)),
67 m_cipher_name(algo_name),
68 m_key_set(false)
69 {
70 if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
71 throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in");
72
73 m_encrypt = EVP_CIPHER_CTX_new();
74 m_decrypt = EVP_CIPHER_CTX_new();
75 if (m_encrypt == nullptr || m_decrypt == nullptr)
76 throw OpenSSL_Error("Can't allocate new context", ERR_get_error());
77
78 EVP_CIPHER_CTX_init(m_encrypt);
79 EVP_CIPHER_CTX_init(m_decrypt);
80
81 if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr))
82 throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
83 if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
84 throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());
85
86 if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0))
87 throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error());
88 if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
89 throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
90 }
91
92OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name,
93 const EVP_CIPHER* algo,
94 size_t key_min,
95 size_t key_max,
96 size_t key_mod) :
97 m_block_sz(EVP_CIPHER_block_size(algo)),
98 m_cipher_key_spec(key_min, key_max, key_mod),
99 m_cipher_name(algo_name),
100 m_key_set(false)
101 {
102 if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
103 throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in");
104
105 m_encrypt = EVP_CIPHER_CTX_new();
106 m_decrypt = EVP_CIPHER_CTX_new();
107 if (m_encrypt == nullptr || m_decrypt == nullptr)
108 throw OpenSSL_Error("Can't allocate new context", ERR_get_error());
109
110 EVP_CIPHER_CTX_init(m_encrypt);
111 EVP_CIPHER_CTX_init(m_decrypt);
112
113 if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr))
114 throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
115 if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
116 throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());
117
118 if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0))
119 throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error());
120 if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
121 throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
122 }
123
124OpenSSL_BlockCipher::~OpenSSL_BlockCipher()
125 {
126 EVP_CIPHER_CTX_cleanup(m_encrypt);
127 EVP_CIPHER_CTX_cleanup(m_decrypt);
128
129 EVP_CIPHER_CTX_free(m_encrypt);
130 EVP_CIPHER_CTX_free(m_decrypt);
131 }
132
133/*
134* Set the key
135*/
136void OpenSSL_BlockCipher::key_schedule(const uint8_t key[], size_t length)
137 {
138 secure_vector<uint8_t> full_key(key, key + length);
139
140 if(m_cipher_name == "TripleDES" && length == 16)
141 {
142 full_key += std::make_pair(key, 8);
143 }
144 else
145 {
146 if(EVP_CIPHER_CTX_set_key_length(m_encrypt, length) == 0 ||
147 EVP_CIPHER_CTX_set_key_length(m_decrypt, length) == 0)
148 throw Invalid_Argument("OpenSSL_BlockCipher: Bad key length for " +
150 }
151
152 if(!EVP_EncryptInit_ex(m_encrypt, nullptr, nullptr, full_key.data(), nullptr))
153 throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
154 if(!EVP_DecryptInit_ex(m_decrypt, nullptr, nullptr, full_key.data(), nullptr))
155 throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());
156
157 m_key_set = true;
158 }
159
160/*
161* Return a clone of this object
162*/
163BlockCipher* OpenSSL_BlockCipher::clone() const
164 {
165 return new OpenSSL_BlockCipher(m_cipher_name,
166 EVP_CIPHER_CTX_cipher(m_encrypt),
167 m_cipher_key_spec.minimum_keylength(),
168 m_cipher_key_spec.maximum_keylength(),
169 m_cipher_key_spec.keylength_multiple());
170 }
171
172/*
173* Clear memory of sensitive data
174*/
175void OpenSSL_BlockCipher::clear()
176 {
177 const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(m_encrypt);
178
179 m_key_set = false;
180
181 if(!EVP_CIPHER_CTX_cleanup(m_encrypt))
182 throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup encrypt", ERR_get_error());
183 if(!EVP_CIPHER_CTX_cleanup(m_decrypt))
184 throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup decrypt", ERR_get_error());
185 EVP_CIPHER_CTX_init(m_encrypt);
186 EVP_CIPHER_CTX_init(m_decrypt);
187 if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr))
188 throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
189 if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
190 throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());
191 if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0))
192 throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error());
193 if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
194 throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
195 }
196
197}
198
199std::unique_ptr<BlockCipher>
201 {
202#define MAKE_OPENSSL_BLOCK(evp_fn) \
203 std::unique_ptr<BlockCipher>(new OpenSSL_BlockCipher(name, evp_fn()))
204#define MAKE_OPENSSL_BLOCK_KEYLEN(evp_fn, kl_min, kl_max, kl_mod) \
205 std::unique_ptr<BlockCipher>(new OpenSSL_BlockCipher(name, evp_fn(), kl_min, kl_max, kl_mod))
206
207#if defined(BOTAN_HAS_AES) && !defined(OPENSSL_NO_AES)
208 if(name == "AES-128")
209 return MAKE_OPENSSL_BLOCK(EVP_aes_128_ecb);
210 if(name == "AES-192")
211 return MAKE_OPENSSL_BLOCK(EVP_aes_192_ecb);
212 if(name == "AES-256")
213 return MAKE_OPENSSL_BLOCK(EVP_aes_256_ecb);
214#endif
215
216#if defined(BOTAN_HAS_CAMELLIA) && !defined(OPENSSL_NO_CAMELLIA)
217 if(name == "Camellia-128")
218 return MAKE_OPENSSL_BLOCK(EVP_camellia_128_ecb);
219 if(name == "Camellia-192")
220 return MAKE_OPENSSL_BLOCK(EVP_camellia_192_ecb);
221 if(name == "Camellia-256")
222 return MAKE_OPENSSL_BLOCK(EVP_camellia_256_ecb);
223#endif
224
225#if defined(BOTAN_HAS_DES) && !defined(OPENSSL_NO_DES)
226 if(name == "DES")
227 return MAKE_OPENSSL_BLOCK(EVP_des_ecb);
228 if(name == "TripleDES")
229 return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_des_ede3_ecb, 16, 24, 8);
230#endif
231
232#if defined(BOTAN_HAS_BLOWFISH) && !defined(OPENSSL_NO_BF)
233 if(name == "Blowfish")
234 return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_bf_ecb, 1, 56, 1);
235#endif
236
237#if defined(BOTAN_HAS_CAST_128) && !defined(OPENSSL_NO_CAST)
238 if(name == "CAST-128")
239 return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_cast5_ecb, 1, 16, 1);
240#endif
241
242#if defined(BOTAN_HAS_SEED) && !defined(OPENSSL_NO_SEED)
243 if(name == "SEED")
244 return MAKE_OPENSSL_BLOCK(EVP_seed_ecb);
245#endif
246
247 return nullptr;
248 }
249
250}
251
std::string name
int(* final)(unsigned char *, CTX *)
Definition: alg_id.cpp:13
std::unique_ptr< BlockCipher > make_openssl_block_cipher(const std::string &name)
bool m_key_set
size_t m_block_sz
#define MAKE_OPENSSL_BLOCK(evp_fn)
std::string m_cipher_name
EVP_CIPHER_CTX * m_decrypt
EVP_CIPHER_CTX * m_encrypt
Key_Length_Specification m_cipher_key_spec
#define MAKE_OPENSSL_BLOCK_KEYLEN(evp_fn, kl_min, kl_max, kl_mod)