1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
9 #include <sys/syscall.h>
10 #include "common/dout.h"
11 #include "common/errno.h"
13 #define dout_subsys ceph_subsys_rbd
15 #define dout_prefix *_dout << "librbd::crypto::luks::Header: " << this << " " \
22 Header::Header(CephContext
* cct
) : m_cct(cct
), m_fd(-1), m_cd(nullptr) {
30 if (m_cd
!= nullptr) {
36 void Header::libcryptsetup_log_wrapper(int level
, const char* msg
, void* header
) {
37 ((Header
*)header
)->libcryptsetup_log(level
, msg
);
40 void Header::libcryptsetup_log(int level
, const char* msg
) {
42 case CRYPT_LOG_NORMAL
:
43 ldout(m_cct
, 5) << "[libcryptsetup] " << msg
<< dendl
;
46 lderr(m_cct
) << "[libcryptsetup] " << msg
<< dendl
;
48 case CRYPT_LOG_VERBOSE
:
49 ldout(m_cct
, 10) << "[libcryptsetup] " << msg
<< dendl
;
52 ldout(m_cct
, 20) << "[libcryptsetup] " << msg
<< dendl
;
58 // create anonymous file
59 m_fd
= syscall(SYS_memfd_create
, "LibcryptsetupInterface", 0);
61 lderr(m_cct
) << "error creating anonymous file: " << cpp_strerror(-errno
)
66 "/proc/" + std::to_string(getpid()) + "/fd/" + std::to_string(m_fd
);
68 if (m_cct
->_conf
->subsys
.should_gather
<dout_subsys
, 20>()) {
69 crypt_set_debug_level(CRYPT_DEBUG_ALL
);
72 // init libcryptsetup handle
73 auto r
= crypt_init(&m_cd
, path
.c_str());
75 lderr(m_cct
) << "crypt_init failed: " << cpp_strerror(r
) << dendl
;
80 crypt_set_log_callback(m_cd
, &libcryptsetup_log_wrapper
, this);
85 int Header::write(const ceph::bufferlist
& bl
) {
86 ceph_assert(m_fd
!= -1);
88 auto r
= bl
.write_fd(m_fd
);
90 lderr(m_cct
) << "error writing header: " << cpp_strerror(r
) << dendl
;
95 ssize_t
Header::read(ceph::bufferlist
* bl
) {
96 ceph_assert(m_fd
!= -1);
98 // get current header size
100 ssize_t r
= fstat(m_fd
, &st
);
103 lderr(m_cct
) << "failed to stat anonymous file: " << cpp_strerror(r
)
108 r
= bl
->read_fd(m_fd
, st
.st_size
);
110 lderr(m_cct
) << "error reading header: " << cpp_strerror(r
) << dendl
;
113 ldout(m_cct
, 20) << "read size = " << r
<< dendl
;
117 int Header::format(const char* type
, const char* alg
, const char* key
,
118 size_t key_size
, const char* cipher_mode
,
119 uint32_t sector_size
, uint32_t data_alignment
,
120 bool insecure_fast_mode
) {
121 ceph_assert(m_cd
!= nullptr);
123 ldout(m_cct
, 20) << "sector size: " << sector_size
<< ", data alignment: "
124 << data_alignment
<< dendl
;
126 // required for passing libcryptsetup device size check
127 if (ftruncate(m_fd
, 4096) != 0) {
128 lderr(m_cct
) << "failed to truncate anonymous file: "
129 << cpp_strerror(-errno
) << dendl
;
133 struct crypt_params_luks1 luks1params
;
134 struct crypt_params_luks2 luks2params
;
136 const size_t converted_data_alignment
= data_alignment
/ 512;
138 void* params
= nullptr;
139 if (strcmp(type
, CRYPT_LUKS1
) == 0) {
140 memset(&luks1params
, 0, sizeof(luks1params
));
141 luks1params
.data_alignment
= converted_data_alignment
;
142 params
= &luks1params
;
143 } else if (strcmp(type
, CRYPT_LUKS2
) == 0) {
144 memset(&luks2params
, 0, sizeof(luks2params
));
145 luks2params
.data_alignment
= converted_data_alignment
;
146 luks2params
.sector_size
= sector_size
;
147 params
= &luks2params
;
150 // this mode should be used for testing only
151 if (insecure_fast_mode
) {
152 struct crypt_pbkdf_type pbkdf
;
153 memset(&pbkdf
, 0, sizeof(pbkdf
));
154 pbkdf
.type
= CRYPT_KDF_PBKDF2
;
155 pbkdf
.flags
= CRYPT_PBKDF_NO_BENCHMARK
;
156 pbkdf
.hash
= "sha256";
157 pbkdf
.iterations
= 1000;
159 auto r
= crypt_set_pbkdf_type(m_cd
, &pbkdf
);
161 lderr(m_cct
) << "crypt_set_pbkdf_type failed: " << cpp_strerror(r
)
167 auto r
= crypt_format(
168 m_cd
, type
, alg
, cipher_mode
, NULL
, key
, key_size
, params
);
170 lderr(m_cct
) << "crypt_format failed: " << cpp_strerror(r
) << dendl
;
177 int Header::add_keyslot(const char* passphrase
, size_t passphrase_size
) {
178 ceph_assert(m_cd
!= nullptr);
180 auto r
= crypt_keyslot_add_by_volume_key(
181 m_cd
, CRYPT_ANY_SLOT
, NULL
, 0, passphrase
, passphrase_size
);
183 lderr(m_cct
) << "crypt_keyslot_add_by_volume_key failed: "
184 << cpp_strerror(r
) << dendl
;
191 int Header::load(const char* type
) {
192 ceph_assert(m_cd
!= nullptr);
194 // libcryptsetup checks if device size matches the header and keyslots size
195 // in LUKS2, 2 X 4MB header + 128MB keyslots
196 if (ftruncate(m_fd
, 136 * 1024 * 1024) != 0) {
197 lderr(m_cct
) << "failed to truncate anonymous file: "
198 << cpp_strerror(-errno
) << dendl
;
202 auto r
= crypt_load(m_cd
, type
, NULL
);
204 lderr(m_cct
) << "crypt_load failed: " << cpp_strerror(r
) << dendl
;
208 ldout(m_cct
, 20) << "sector size: " << get_sector_size() << ", data offset: "
209 << get_data_offset() << dendl
;
214 int Header::read_volume_key(const char* passphrase
, size_t passphrase_size
,
215 char* volume_key
, size_t* volume_key_size
) {
216 ceph_assert(m_cd
!= nullptr);
218 auto r
= crypt_volume_key_get(
219 m_cd
, CRYPT_ANY_SLOT
, volume_key
, volume_key_size
, passphrase
,
222 lderr(m_cct
) << "crypt_volume_key_get failed: " << cpp_strerror(r
)
230 int Header::get_sector_size() {
231 ceph_assert(m_cd
!= nullptr);
232 return crypt_get_sector_size(m_cd
);
235 uint64_t Header::get_data_offset() {
236 ceph_assert(m_cd
!= nullptr);
237 return crypt_get_data_offset(m_cd
) << 9;
240 const char* Header::get_cipher() {
241 ceph_assert(m_cd
!= nullptr);
242 return crypt_get_cipher(m_cd
);
245 const char* Header::get_cipher_mode() {
246 ceph_assert(m_cd
!= nullptr);
247 return crypt_get_cipher_mode(m_cd
);
251 } // namespace crypto
252 } // namespace librbd