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
12 namespace Botan {
13
14 namespace {
15
16 class 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;
provider() const29 std::string provider() const override { return "openssl"; }
name() const30 std::string name() const override { return m_cipher_name; }
31 BlockCipher* clone() const override;
32
block_size() const33 size_t block_size() const override { return m_block_sz; }
34
key_spec() const35 Key_Length_Specification key_spec() const override { return m_cipher_key_spec; }
36
encrypt_n(const uint8_t in[],uint8_t out[],size_t blocks) const37 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
decrypt_n(const uint8_t in[],uint8_t out[],size_t blocks) const45 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;
60 bool m_key_set;
61 };
62
OpenSSL_BlockCipher(const std::string & algo_name,const EVP_CIPHER * algo)63 OpenSSL_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
OpenSSL_BlockCipher(const std::string & algo_name,const EVP_CIPHER * algo,size_t key_min,size_t key_max,size_t key_mod)92 OpenSSL_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
~OpenSSL_BlockCipher()124 OpenSSL_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 */
key_schedule(const uint8_t key[],size_t length)136 void 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 " +
149 m_cipher_name);
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 */
clone() const163 BlockCipher* 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 */
clear()175 void 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
199 std::unique_ptr<BlockCipher>
make_openssl_block_cipher(const std::string & name)200 make_openssl_block_cipher(const std::string& name)
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 == "TripleDES")
227 return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_des_ede3_ecb, 16, 24, 8);
228 #endif
229
230 return nullptr;
231 }
232
233 }
234
235