]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "librbd/crypto/openssl/DataCryptor.h" | |
5 | #include <openssl/err.h> | |
6 | #include <string.h> | |
7 | #include "include/ceph_assert.h" | |
8 | #include "include/compat.h" | |
9 | ||
10 | namespace librbd { | |
11 | namespace crypto { | |
12 | namespace openssl { | |
13 | ||
14 | int DataCryptor::init(const char* cipher_name, const unsigned char* key, | |
15 | uint16_t key_length) { | |
20effc67 TL |
16 | if (m_key != nullptr) { |
17 | ceph_memzero_s(m_key, m_key_size, m_key_size); | |
18 | delete [] m_key; | |
19 | m_key = nullptr; | |
20 | m_key_size = 0; | |
21 | } | |
f67539c2 TL |
22 | if (cipher_name == nullptr) { |
23 | lderr(m_cct) << "missing cipher name" << dendl; | |
24 | return -EINVAL; | |
25 | } | |
26 | if (key == nullptr) { | |
27 | lderr(m_cct) << "missing key" << dendl; | |
28 | return -EINVAL; | |
29 | } | |
30 | ||
31 | m_cipher = EVP_get_cipherbyname(cipher_name); | |
32 | if (m_cipher == nullptr) { | |
33 | lderr(m_cct) << "EVP_get_cipherbyname failed. Cipher name: " << cipher_name | |
34 | << dendl; | |
35 | log_errors(); | |
36 | return -EINVAL; | |
37 | } | |
38 | ||
39 | auto expected_key_length = EVP_CIPHER_key_length(m_cipher); | |
40 | if (expected_key_length != key_length) { | |
41 | lderr(m_cct) << "cipher " << cipher_name << " expects key of " | |
42 | << expected_key_length << " bytes. got: " << key_length | |
43 | << dendl; | |
44 | return -EINVAL; | |
45 | } | |
46 | ||
20effc67 | 47 | m_key_size = key_length; |
f67539c2 TL |
48 | m_key = new unsigned char[key_length]; |
49 | memcpy(m_key, key, key_length); | |
50 | m_iv_size = static_cast<uint32_t>(EVP_CIPHER_iv_length(m_cipher)); | |
51 | return 0; | |
52 | } | |
53 | ||
54 | DataCryptor::~DataCryptor() { | |
55 | if (m_key != nullptr) { | |
20effc67 | 56 | ceph_memzero_s(m_key, m_key_size, m_key_size); |
f67539c2 TL |
57 | delete [] m_key; |
58 | m_key = nullptr; | |
59 | } | |
60 | } | |
61 | ||
62 | uint32_t DataCryptor::get_block_size() const { | |
63 | return EVP_CIPHER_block_size(m_cipher); | |
64 | } | |
65 | ||
66 | uint32_t DataCryptor::get_iv_size() const { | |
67 | return m_iv_size; | |
68 | } | |
69 | ||
70 | const unsigned char* DataCryptor::get_key() const { | |
71 | return m_key; | |
72 | } | |
73 | ||
74 | int DataCryptor::get_key_length() const { | |
75 | return EVP_CIPHER_key_length(m_cipher); | |
76 | } | |
77 | ||
78 | EVP_CIPHER_CTX* DataCryptor::get_context(CipherMode mode) { | |
79 | int enc; | |
80 | switch(mode) { | |
81 | case CIPHER_MODE_ENC: | |
82 | enc = 1; | |
83 | break; | |
84 | case CIPHER_MODE_DEC: | |
85 | enc = 0; | |
86 | break; | |
87 | default: | |
88 | lderr(m_cct) << "Invalid CipherMode:" << mode << dendl; | |
89 | return nullptr; | |
90 | } | |
91 | ||
92 | auto ctx = EVP_CIPHER_CTX_new(); | |
93 | if (ctx == nullptr) { | |
94 | lderr(m_cct) << "EVP_CIPHER_CTX_new failed" << dendl; | |
95 | log_errors(); | |
96 | return nullptr; | |
97 | } | |
98 | ||
99 | if (1 != EVP_CipherInit_ex(ctx, m_cipher, nullptr, m_key, nullptr, enc)) { | |
100 | lderr(m_cct) << "EVP_CipherInit_ex failed" << dendl; | |
101 | log_errors(); | |
102 | return nullptr; | |
103 | } | |
104 | ||
105 | return ctx; | |
106 | } | |
107 | ||
108 | void DataCryptor::return_context(EVP_CIPHER_CTX* ctx, CipherMode mode) { | |
109 | if (ctx != nullptr) { | |
110 | EVP_CIPHER_CTX_free(ctx); | |
111 | } | |
112 | } | |
113 | ||
114 | int DataCryptor::init_context(EVP_CIPHER_CTX* ctx, const unsigned char* iv, | |
115 | uint32_t iv_length) const { | |
116 | if (iv_length != m_iv_size) { | |
117 | lderr(m_cct) << "cipher expects IV of " << m_iv_size << " bytes. got: " | |
118 | << iv_length << dendl; | |
119 | return -EINVAL; | |
120 | } | |
121 | if (1 != EVP_CipherInit_ex(ctx, nullptr, nullptr, nullptr, iv, -1)) { | |
122 | lderr(m_cct) << "EVP_CipherInit_ex failed" << dendl; | |
123 | log_errors(); | |
124 | return -EIO; | |
125 | } | |
126 | return 0; | |
127 | } | |
128 | ||
129 | int DataCryptor::update_context(EVP_CIPHER_CTX* ctx, const unsigned char* in, | |
130 | unsigned char* out, uint32_t len) const { | |
131 | int out_length; | |
132 | if (1 != EVP_CipherUpdate(ctx, out, &out_length, in, len)) { | |
133 | lderr(m_cct) << "EVP_CipherUpdate failed. len=" << len << dendl; | |
134 | log_errors(); | |
135 | return -EIO; | |
136 | } | |
137 | return out_length; | |
138 | } | |
139 | ||
140 | void DataCryptor::log_errors() const { | |
141 | while (true) { | |
142 | auto error = ERR_get_error(); | |
143 | if (error == 0) { | |
144 | break; | |
145 | } | |
146 | lderr(m_cct) << "OpenSSL error: " << ERR_error_string(error, nullptr) | |
147 | << dendl; | |
148 | } | |
149 | } | |
150 | ||
151 | } // namespace openssl | |
152 | } // namespace crypto | |
153 | } // namespace librbd |