Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

openssl_mode.cpp
Go to the documentation of this file.
1 /*
2 * Cipher Modes via OpenSSL
3 * (C) 1999-2010,2015 Jack Lloyd
4 * (C) 2017 Alexander Bluhm (genua GmbH)
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8
9 #include <botan/cipher_mode.h>
10 #include <botan/internal/rounding.h>
11 #include <botan/internal/openssl.h>
12 #include <openssl/evp.h>
13 #include <limits.h>
14
15 namespace Botan {
16
17 namespace {
18
19 class OpenSSL_Cipher_Mode final : public Cipher_Mode
20 {
21 public:
22 OpenSSL_Cipher_Mode(const std::string& name,
23 const EVP_CIPHER* cipher,
24 Cipher_Dir direction);
25 ~OpenSSL_Cipher_Mode();
26
27 std::string provider() const override { return "openssl"; }
28 std::string name() const override { return m_mode_name; }
29
30 void start_msg(const uint8_t nonce[], size_t nonce_len) override;
31 size_t process(uint8_t msg[], size_t msg_len) override;
32 void finish(secure_vector<uint8_t>& final_block, size_t offset0) override;
33 size_t output_length(size_t input_length) const override;
34 size_t update_granularity() const override;
35 size_t minimum_final_size() const override;
36 size_t default_nonce_length() const override;
37 bool valid_nonce_length(size_t nonce_len) const override;
38 void clear() override;
39 void reset() override;
40 Key_Length_Specification key_spec() const override;
41
42 private:
43 void key_schedule(const uint8_t key[], size_t length) override;
44
45 const std::string m_mode_name;
46 const Cipher_Dir m_direction;
47 size_t m_block_size;
48 EVP_CIPHER_CTX* m_cipher;
49 bool m_key_set;
50 bool m_nonce_set;
51 };
52
53 OpenSSL_Cipher_Mode::OpenSSL_Cipher_Mode(const std::string& name,
54 const EVP_CIPHER* algo,
55 Cipher_Dir direction) :
56 m_mode_name(name),
57 m_direction(direction),
58 m_key_set(false),
59 m_nonce_set(false)
60 {
61 m_block_size = EVP_CIPHER_block_size(algo);
62
63 if(EVP_CIPHER_mode(algo) != EVP_CIPH_CBC_MODE)
64 throw Invalid_Argument("OpenSSL_BlockCipher: Non-CBC EVP was passed in");
65
66 m_cipher = EVP_CIPHER_CTX_new();
67 if (m_cipher == nullptr)
68 throw OpenSSL_Error("Can't allocate new context", ERR_get_error());
69
70 EVP_CIPHER_CTX_init(m_cipher);
71 if(!EVP_CipherInit_ex(m_cipher, algo, nullptr, nullptr, nullptr,
72 m_direction == ENCRYPTION ? 1 : 0))
73 throw OpenSSL_Error("EVP_CipherInit_ex", ERR_get_error());
74 if(!EVP_CIPHER_CTX_set_padding(m_cipher, 0))
75 throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding", ERR_get_error());
76 }
77
78 OpenSSL_Cipher_Mode::~OpenSSL_Cipher_Mode()
79 {
80 EVP_CIPHER_CTX_free(m_cipher);
81 }
82
83 void OpenSSL_Cipher_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
84 {
85 verify_key_set(m_key_set);
86
87 if(!valid_nonce_length(nonce_len))
88 throw Invalid_IV_Length(name(), nonce_len);
89
90 if(nonce_len)
91 {
92 if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, nullptr, nonce, -1))
93 throw OpenSSL_Error("EVP_CipherInit_ex nonce", ERR_get_error());
94 }
95 else if(m_nonce_set == false)
96 {
97 const std::vector<uint8_t> zeros(m_block_size);
98 if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, nullptr, zeros.data(), -1))
99 throw OpenSSL_Error("EVP_CipherInit_ex nonce", ERR_get_error());
100 }
101 // otherwise existing CBC state left unchanged
102
103 m_nonce_set = true;
104 }
105
106 size_t OpenSSL_Cipher_Mode::process(uint8_t msg[], size_t msg_len)
107 {
108 verify_key_set(m_key_set);
109 BOTAN_STATE_CHECK(m_nonce_set);
110
111 if(msg_len == 0)
112 return 0;
113 if(msg_len > INT_MAX)
114 throw Internal_Error("msg_len overflow");
115 int outl = msg_len;
116 secure_vector<uint8_t> out(outl);
117
118 if(!EVP_CipherUpdate(m_cipher, out.data(), &outl, msg, msg_len))
119 throw OpenSSL_Error("EVP_CipherUpdate", ERR_get_error());
120 copy_mem(msg, out.data(), outl);
121 return outl;
122 }
123
124 void OpenSSL_Cipher_Mode::finish(secure_vector<uint8_t>& buffer,
125 size_t offset)
126 {
127 verify_key_set(m_key_set);
128 BOTAN_STATE_CHECK(m_nonce_set);
129
130 BOTAN_ASSERT(buffer.size() >= offset, "Offset ok");
131 uint8_t* buf = buffer.data() + offset;
132 const size_t buf_size = buffer.size() - offset;
133
134 size_t written = process(buf, buf_size);
135 int outl = buf_size - written;
136 secure_vector<uint8_t> out(outl);
137
138 if(!EVP_CipherFinal_ex(m_cipher, out.data(), &outl))
139 throw OpenSSL_Error("EVP_CipherFinal_ex", ERR_get_error());
140 copy_mem(buf + written, out.data(), outl);
141 written += outl;
142 buffer.resize(offset + written);
143 }
144
145 size_t OpenSSL_Cipher_Mode::update_granularity() const
146 {
147 return m_block_size * BOTAN_BLOCK_CIPHER_PAR_MULT;
148 }
149
150 size_t OpenSSL_Cipher_Mode::minimum_final_size() const
151 {
152 return 0; // no padding
153 }
154
155 size_t OpenSSL_Cipher_Mode::default_nonce_length() const
156 {
157 return m_block_size;
158 }
159
160 bool OpenSSL_Cipher_Mode::valid_nonce_length(size_t nonce_len) const
161 {
162 return (nonce_len == 0 || nonce_len == m_block_size);
163 }
164
165 size_t OpenSSL_Cipher_Mode::output_length(size_t input_length) const
166 {
167 if(input_length == 0)
168 return m_block_size;
169 else
170 return round_up(input_length, m_block_size);
171 }
172
173 void OpenSSL_Cipher_Mode::clear()
174 {
175 m_key_set = false;
176 m_nonce_set = false;
177
178 const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(m_cipher);
179
180 if(!EVP_CIPHER_CTX_cleanup(m_cipher))
181 throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup", ERR_get_error());
182 EVP_CIPHER_CTX_init(m_cipher);
183 if(!EVP_CipherInit_ex(m_cipher, algo, nullptr, nullptr, nullptr,
184 m_direction == ENCRYPTION ? 1 : 0))
185 throw OpenSSL_Error("EVP_CipherInit_ex clear", ERR_get_error());
186 if(!EVP_CIPHER_CTX_set_padding(m_cipher, 0))
187 throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding clear", ERR_get_error());
188 }
189
190 void OpenSSL_Cipher_Mode::reset()
191 {
192 if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, nullptr, nullptr, -1))
193 throw OpenSSL_Error("EVP_CipherInit_ex clear", ERR_get_error());
194 m_nonce_set = false;
195 }
196
197 Key_Length_Specification OpenSSL_Cipher_Mode::key_spec() const
198 {
199 return Key_Length_Specification(EVP_CIPHER_CTX_key_length(m_cipher));
200 }
201
202 void OpenSSL_Cipher_Mode::key_schedule(const uint8_t key[], size_t length)
203 {
204 if(!EVP_CIPHER_CTX_set_key_length(m_cipher, length))
205 throw OpenSSL_Error("EVP_CIPHER_CTX_set_key_length", ERR_get_error());
206 if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, key, nullptr, -1))
207 throw OpenSSL_Error("EVP_CipherInit_ex key", ERR_get_error());
208 m_key_set = true;
209 m_nonce_set = false;
210 }
211
212 }
213
214 Cipher_Mode*
215 make_openssl_cipher_mode(const std::string& name, Cipher_Dir direction)
216 {
217 #define MAKE_OPENSSL_MODE(evp_fn) \
218 new OpenSSL_Cipher_Mode(name, (evp_fn)(), direction)
219
220 #if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_MODE_CBC) && !defined(OPENSSL_NO_AES)
221 if(name == "AES-128/CBC/NoPadding")
222 return MAKE_OPENSSL_MODE(EVP_aes_128_cbc);
223 if(name == "AES-192/CBC/NoPadding")
224 return MAKE_OPENSSL_MODE(EVP_aes_192_cbc);
225 if(name == "AES-256/CBC/NoPadding")
226 return MAKE_OPENSSL_MODE(EVP_aes_256_cbc);
227 #endif
228
229 #undef MAKE_OPENSSL_MODE
230 return nullptr;
231 }
232
233 }
m_direction
const Cipher_Dir m_direction
Definition: openssl_mode.cpp:46
m_mode_name
const std::string m_mode_name
Definition: openssl_mode.cpp:45
m_key_set
bool m_key_set
Definition: openssl_mode.cpp:49
final
int(* final)(unsigned char *, CTX *)
Definition: commoncrypto_hash.cpp:28
BOTAN_STATE_CHECK
#define BOTAN_STATE_CHECK(expr)
Definition: assert.h:49
Botan::make_openssl_cipher_mode
Cipher_Mode * make_openssl_cipher_mode(const std::string &name, Cipher_Dir direction)
Definition: openssl_mode.cpp:215
BOTAN_ASSERT
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
name
std::string name
Definition: commoncrypto_hash.cpp:23
m_cipher
EVP_CIPHER_CTX * m_cipher
Definition: openssl_mode.cpp:48
Botan::copy_mem
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:132
Botan
Definition: alg_id.cpp:13
Botan::Cipher_Dir
Cipher_Dir
Definition: cipher_mode.h:23
m_nonce_set
bool m_nonce_set
Definition: openssl_mode.cpp:50
Botan::ENCRYPTION
Definition: cipher_mode.h:23
m_block_size
size_t m_block_size
Definition: openssl_mode.cpp:47
Botan::OCSP::Response_Status_Code::Internal_Error
Botan::round_up
size_t round_up(size_t n, size_t align_to)
Definition: rounding.h:21
MAKE_OPENSSL_MODE
#define MAKE_OPENSSL_MODE(evp_fn)