]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/crypto/openssl/DataCryptor.cc
import quincy beta 17.1.0
[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 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 }
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
47 m_key_size = key_length;
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) {
56 ceph_memzero_s(m_key, m_key_size, m_key_size);
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