]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/crypto/openssl/DataCryptor.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / librbd / crypto / openssl / DataCryptor.cc
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) {
16 m_key = nullptr;
17 if (cipher_name == nullptr) {
18 lderr(m_cct) << "missing cipher name" << dendl;
19 return -EINVAL;
20 }
21 if (key == nullptr) {
22 lderr(m_cct) << "missing key" << dendl;
23 return -EINVAL;
24 }
25
26 m_cipher = EVP_get_cipherbyname(cipher_name);
27 if (m_cipher == nullptr) {
28 lderr(m_cct) << "EVP_get_cipherbyname failed. Cipher name: " << cipher_name
29 << dendl;
30 log_errors();
31 return -EINVAL;
32 }
33
34 auto expected_key_length = EVP_CIPHER_key_length(m_cipher);
35 if (expected_key_length != key_length) {
36 lderr(m_cct) << "cipher " << cipher_name << " expects key of "
37 << expected_key_length << " bytes. got: " << key_length
38 << dendl;
39 return -EINVAL;
40 }
41
42 m_key = new unsigned char[key_length];
43 memcpy(m_key, key, key_length);
44 m_iv_size = static_cast<uint32_t>(EVP_CIPHER_iv_length(m_cipher));
45 return 0;
46 }
47
48 DataCryptor::~DataCryptor() {
49 if (m_key != nullptr) {
50 ceph_memzero_s(m_key, EVP_CIPHER_key_length(m_cipher),
51 EVP_CIPHER_key_length(m_cipher));
52 delete [] m_key;
53 m_key = nullptr;
54 }
55 }
56
57 uint32_t DataCryptor::get_block_size() const {
58 return EVP_CIPHER_block_size(m_cipher);
59 }
60
61 uint32_t DataCryptor::get_iv_size() const {
62 return m_iv_size;
63 }
64
65 const unsigned char* DataCryptor::get_key() const {
66 return m_key;
67 }
68
69 int DataCryptor::get_key_length() const {
70 return EVP_CIPHER_key_length(m_cipher);
71 }
72
73 EVP_CIPHER_CTX* DataCryptor::get_context(CipherMode mode) {
74 int enc;
75 switch(mode) {
76 case CIPHER_MODE_ENC:
77 enc = 1;
78 break;
79 case CIPHER_MODE_DEC:
80 enc = 0;
81 break;
82 default:
83 lderr(m_cct) << "Invalid CipherMode:" << mode << dendl;
84 return nullptr;
85 }
86
87 auto ctx = EVP_CIPHER_CTX_new();
88 if (ctx == nullptr) {
89 lderr(m_cct) << "EVP_CIPHER_CTX_new failed" << dendl;
90 log_errors();
91 return nullptr;
92 }
93
94 if (1 != EVP_CipherInit_ex(ctx, m_cipher, nullptr, m_key, nullptr, enc)) {
95 lderr(m_cct) << "EVP_CipherInit_ex failed" << dendl;
96 log_errors();
97 return nullptr;
98 }
99
100 return ctx;
101 }
102
103 void DataCryptor::return_context(EVP_CIPHER_CTX* ctx, CipherMode mode) {
104 if (ctx != nullptr) {
105 EVP_CIPHER_CTX_free(ctx);
106 }
107 }
108
109 int DataCryptor::init_context(EVP_CIPHER_CTX* ctx, const unsigned char* iv,
110 uint32_t iv_length) const {
111 if (iv_length != m_iv_size) {
112 lderr(m_cct) << "cipher expects IV of " << m_iv_size << " bytes. got: "
113 << iv_length << dendl;
114 return -EINVAL;
115 }
116 if (1 != EVP_CipherInit_ex(ctx, nullptr, nullptr, nullptr, iv, -1)) {
117 lderr(m_cct) << "EVP_CipherInit_ex failed" << dendl;
118 log_errors();
119 return -EIO;
120 }
121 return 0;
122 }
123
124 int DataCryptor::update_context(EVP_CIPHER_CTX* ctx, const unsigned char* in,
125 unsigned char* out, uint32_t len) const {
126 int out_length;
127 if (1 != EVP_CipherUpdate(ctx, out, &out_length, in, len)) {
128 lderr(m_cct) << "EVP_CipherUpdate failed. len=" << len << dendl;
129 log_errors();
130 return -EIO;
131 }
132 return out_length;
133 }
134
135 void DataCryptor::log_errors() const {
136 while (true) {
137 auto error = ERR_get_error();
138 if (error == 0) {
139 break;
140 }
141 lderr(m_cct) << "OpenSSL error: " << ERR_error_string(error, nullptr)
142 << dendl;
143 }
144 }
145
146 } // namespace openssl
147 } // namespace crypto
148 } // namespace librbd