]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/crypto/BlockCrypto.cc
import quincy beta 17.1.0
[ceph.git] / 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
3
4 #include "librbd/crypto/BlockCrypto.h"
5 #include "include/byteorder.h"
6 #include "include/ceph_assert.h"
7 #include "include/scope_guard.h"
8
9 #include <stdlib.h>
10
11 namespace librbd {
12 namespace crypto {
13
14 template <typename T>
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);
22 }
23
24 template <typename T>
25 BlockCrypto<T>::~BlockCrypto() {
26 if (m_data_cryptor != nullptr) {
27 delete m_data_cryptor;
28 m_data_cryptor = nullptr;
29 }
30 }
31
32 template <typename T>
33 int BlockCrypto<T>::crypt(ceph::bufferlist* data, uint64_t image_offset,
34 CipherMode mode) {
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;
38 return -EINVAL;
39 }
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;
43 return -EINVAL;
44 }
45
46 unsigned char* iv = (unsigned char*)alloca(m_iv_size);
47 memset(iv, 0, m_iv_size);
48
49 bufferlist src = *data;
50 data->clear();
51
52 auto ctx = m_data_cryptor->get_context(mode);
53 if (ctx == nullptr) {
54 lderr(m_cct) << "unable to get crypt context" << dendl;
55 return -EIO;
56 }
57
58 auto sg = make_scope_guard([&] {
59 m_data_cryptor->return_context(ctx, mode); });
60
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);
74 if (r != 0) {
75 lderr(m_cct) << "unable to init cipher's IV" << dendl;
76 return r;
77 }
78
79 out_buf_ptr = reinterpret_cast<unsigned char*>(
80 appender.get_pos_add(m_block_size));
81 sector_number += m_block_size / 512;
82 }
83
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;
91 }
92
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);
97
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);
103 leftover_size = 0;
104 }
105
106 if (crypto_output_length < 0) {
107 lderr(m_cct) << "crypt update failed" << dendl;
108 return crypto_output_length;
109 }
110
111 out_buf_ptr += crypto_output_length;
112 }
113 }
114
115 return 0;
116 }
117
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);
121 }
122
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);
126 }
127
128 } // namespace crypto
129 } // namespace librbd
130
131 template class librbd::crypto::BlockCrypto<EVP_CIPHER_CTX>;