]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/crypto/BlockCrypto.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / librbd / crypto / BlockCrypto.cc
CommitLineData
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/BlockCrypto.h"
5#include "include/byteorder.h"
6#include "include/ceph_assert.h"
7
8#include <stdlib.h>
9
10namespace librbd {
11namespace crypto {
12
13template <typename T>
14BlockCrypto<T>::BlockCrypto(CephContext* cct, DataCryptor<T>* data_cryptor,
15 uint64_t block_size, uint64_t data_offset)
16 : m_cct(cct), m_data_cryptor(data_cryptor), m_block_size(block_size),
17 m_data_offset(data_offset), m_iv_size(data_cryptor->get_iv_size()) {
18 ceph_assert(isp2(block_size));
19 ceph_assert((block_size % data_cryptor->get_block_size()) == 0);
20 ceph_assert((block_size % 512) == 0);
21}
22
23template <typename T>
24BlockCrypto<T>::~BlockCrypto() {
25 if (m_data_cryptor != nullptr) {
26 delete m_data_cryptor;
27 m_data_cryptor = nullptr;
28 }
29}
30
31template <typename T>
32int BlockCrypto<T>::crypt(ceph::bufferlist* data, uint64_t image_offset,
33 CipherMode mode) {
34 if (image_offset % m_block_size != 0) {
35 lderr(m_cct) << "image offset: " << image_offset
36 << " not aligned to block size: " << m_block_size << dendl;
37 return -EINVAL;
38 }
39 if (data->length() % m_block_size != 0) {
40 lderr(m_cct) << "data length: " << data->length()
41 << " not aligned to block size: " << m_block_size << dendl;
42 return -EINVAL;
43 }
44
45 unsigned char* iv = (unsigned char*)alloca(m_iv_size);
46 memset(iv, 0, m_iv_size);
47
48 bufferlist src = *data;
49 data->clear();
50
51 auto ctx = m_data_cryptor->get_context(mode);
52 if (ctx == nullptr) {
53 lderr(m_cct) << "unable to get crypt context" << dendl;
54 return -EIO;
55 }
56 auto sector_number = image_offset / 512;
57 auto appender = data->get_contiguous_appender(src.length());
58 unsigned char* out_buf_ptr = nullptr;
59 unsigned char* leftover_block = (unsigned char*)alloca(m_block_size);
60 uint32_t leftover_size = 0;
61 for (auto buf = src.buffers().begin(); buf != src.buffers().end(); ++buf) {
62 auto in_buf_ptr = reinterpret_cast<const unsigned char*>(buf->c_str());
63 auto remaining_buf_bytes = buf->length();
64 while (remaining_buf_bytes > 0) {
65 if (leftover_size == 0) {
66 auto block_offset_le = init_le64(sector_number);
67 memcpy(iv, &block_offset_le, sizeof(block_offset_le));
68 auto r = m_data_cryptor->init_context(ctx, iv, m_iv_size);
69 if (r != 0) {
70 lderr(m_cct) << "unable to init cipher's IV" << dendl;
71 return r;
72 }
73
74 out_buf_ptr = reinterpret_cast<unsigned char*>(
75 appender.get_pos_add(m_block_size));
76 sector_number += m_block_size / 512;
77 }
78
79 if (leftover_size > 0 || remaining_buf_bytes < m_block_size) {
80 auto copy_size = std::min(
81 (uint32_t)m_block_size - leftover_size, remaining_buf_bytes);
82 memcpy(leftover_block + leftover_size, in_buf_ptr, copy_size);
83 in_buf_ptr += copy_size;
84 leftover_size += copy_size;
85 remaining_buf_bytes -= copy_size;
86 }
87
88 int crypto_output_length = 0;
89 if (leftover_size == 0) {
90 crypto_output_length = m_data_cryptor->update_context(
91 ctx, in_buf_ptr, out_buf_ptr, m_block_size);
92
93 in_buf_ptr += m_block_size;
94 remaining_buf_bytes -= m_block_size;
95 } else if (leftover_size == m_block_size) {
96 crypto_output_length = m_data_cryptor->update_context(
97 ctx, leftover_block, out_buf_ptr, m_block_size);
98 leftover_size = 0;
99 }
100
101 if (crypto_output_length < 0) {
102 lderr(m_cct) << "crypt update failed" << dendl;
103 return crypto_output_length;
104 }
105
106 out_buf_ptr += crypto_output_length;
107 }
108 }
109
110 m_data_cryptor->return_context(ctx, mode);
111
112 return 0;
113}
114
115template <typename T>
116int BlockCrypto<T>::encrypt(ceph::bufferlist* data, uint64_t image_offset) {
117 return crypt(data, image_offset, CipherMode::CIPHER_MODE_ENC);
118}
119
120template <typename T>
121int BlockCrypto<T>::decrypt(ceph::bufferlist* data, uint64_t image_offset) {
122 return crypt(data, image_offset, CipherMode::CIPHER_MODE_DEC);
123}
124
125} // namespace crypto
126} // namespace librbd
127
128template class librbd::crypto::BlockCrypto<EVP_CIPHER_CTX>;