]>
git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/crypto/BlockCrypto.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/crypto/BlockCrypto.h"
5 #include "include/byteorder.h"
6 #include "include/ceph_assert.h"
7 #include "include/scope_guard.h"
15 BlockCrypto
<T
>::BlockCrypto(CephContext
* cct
, DataCryptor
<T
>* data_cryptor
,
16 uint64_t block_size
, uint64_t data_offset
)
17 : m_cct(cct
), m_data_cryptor(data_cryptor
), m_block_size(block_size
),
18 m_data_offset(data_offset
), m_iv_size(data_cryptor
->get_iv_size()) {
19 ceph_assert(isp2(block_size
));
20 ceph_assert((block_size
% data_cryptor
->get_block_size()) == 0);
21 ceph_assert((block_size
% 512) == 0);
25 BlockCrypto
<T
>::~BlockCrypto() {
26 if (m_data_cryptor
!= nullptr) {
27 delete m_data_cryptor
;
28 m_data_cryptor
= nullptr;
33 int BlockCrypto
<T
>::crypt(ceph::bufferlist
* data
, uint64_t image_offset
,
35 if (image_offset
% m_block_size
!= 0) {
36 lderr(m_cct
) << "image offset: " << image_offset
37 << " not aligned to block size: " << m_block_size
<< dendl
;
40 if (data
->length() % m_block_size
!= 0) {
41 lderr(m_cct
) << "data length: " << data
->length()
42 << " not aligned to block size: " << m_block_size
<< dendl
;
46 unsigned char* iv
= (unsigned char*)alloca(m_iv_size
);
47 memset(iv
, 0, m_iv_size
);
49 bufferlist src
= *data
;
52 auto ctx
= m_data_cryptor
->get_context(mode
);
54 lderr(m_cct
) << "unable to get crypt context" << dendl
;
58 auto sg
= make_scope_guard([&] {
59 m_data_cryptor
->return_context(ctx
, mode
); });
61 auto sector_number
= image_offset
/ 512;
62 auto appender
= data
->get_contiguous_appender(src
.length());
63 unsigned char* out_buf_ptr
= nullptr;
64 unsigned char* leftover_block
= (unsigned char*)alloca(m_block_size
);
65 uint32_t leftover_size
= 0;
66 for (auto buf
= src
.buffers().begin(); buf
!= src
.buffers().end(); ++buf
) {
67 auto in_buf_ptr
= reinterpret_cast<const unsigned char*>(buf
->c_str());
68 auto remaining_buf_bytes
= buf
->length();
69 while (remaining_buf_bytes
> 0) {
70 if (leftover_size
== 0) {
71 auto block_offset_le
= ceph_le64(sector_number
);
72 memcpy(iv
, &block_offset_le
, sizeof(block_offset_le
));
73 auto r
= m_data_cryptor
->init_context(ctx
, iv
, m_iv_size
);
75 lderr(m_cct
) << "unable to init cipher's IV" << dendl
;
79 out_buf_ptr
= reinterpret_cast<unsigned char*>(
80 appender
.get_pos_add(m_block_size
));
81 sector_number
+= m_block_size
/ 512;
84 if (leftover_size
> 0 || remaining_buf_bytes
< m_block_size
) {
85 auto copy_size
= std::min(
86 (uint32_t)m_block_size
- leftover_size
, remaining_buf_bytes
);
87 memcpy(leftover_block
+ leftover_size
, in_buf_ptr
, copy_size
);
88 in_buf_ptr
+= copy_size
;
89 leftover_size
+= copy_size
;
90 remaining_buf_bytes
-= copy_size
;
93 int crypto_output_length
= 0;
94 if (leftover_size
== 0) {
95 crypto_output_length
= m_data_cryptor
->update_context(
96 ctx
, in_buf_ptr
, out_buf_ptr
, m_block_size
);
98 in_buf_ptr
+= m_block_size
;
99 remaining_buf_bytes
-= m_block_size
;
100 } else if (leftover_size
== m_block_size
) {
101 crypto_output_length
= m_data_cryptor
->update_context(
102 ctx
, leftover_block
, out_buf_ptr
, m_block_size
);
106 if (crypto_output_length
< 0) {
107 lderr(m_cct
) << "crypt update failed" << dendl
;
108 return crypto_output_length
;
111 out_buf_ptr
+= crypto_output_length
;
118 template <typename T
>
119 int BlockCrypto
<T
>::encrypt(ceph::bufferlist
* data
, uint64_t image_offset
) {
120 return crypt(data
, image_offset
, CipherMode::CIPHER_MODE_ENC
);
123 template <typename T
>
124 int BlockCrypto
<T
>::decrypt(ceph::bufferlist
* data
, uint64_t image_offset
) {
125 return crypt(data
, image_offset
, CipherMode::CIPHER_MODE_DEC
);
128 } // namespace crypto
129 } // namespace librbd
131 template class librbd::crypto::BlockCrypto
<EVP_CIPHER_CTX
>;