1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 * Crypto filters for Put/Post/Get operations.
8 #include <rgw/rgw_op.h>
9 #include <rgw/rgw_crypt.h>
10 #include <auth/Crypto.h>
11 #include <rgw/rgw_b64.h>
12 #include <rgw/rgw_rest_s3.h>
13 #include "include/ceph_assert.h"
14 #include <boost/utility/string_view.hpp>
15 #include <rgw/rgw_keystone.h>
16 #include "include/str_map.h"
17 #include "crypto/crypto_accel.h"
18 #include "crypto/crypto_plugin.h"
25 #define dout_context g_ceph_context
26 #define dout_subsys ceph_subsys_rgw
31 * Encryption in CTR mode. offset is used as IV for each block.
33 class AES_256_CTR
: public BlockCrypt
{
35 static const size_t AES_256_KEYSIZE
= 256 / 8;
36 static const size_t AES_256_IVSIZE
= 128 / 8;
38 static const uint8_t IV
[AES_256_IVSIZE
];
40 uint8_t key
[AES_256_KEYSIZE
];
42 explicit AES_256_CTR(CephContext
* cct
): cct(cct
) {
45 memset(key
, 0, AES_256_KEYSIZE
);
47 bool set_key(const uint8_t* _key
, size_t key_size
) {
48 if (key_size
!= AES_256_KEYSIZE
) {
51 memcpy(key
, _key
, AES_256_KEYSIZE
);
54 size_t get_block_size() {
55 return AES_256_IVSIZE
;
60 bool encrypt(bufferlist
& input
, off_t in_ofs
, size_t size
, bufferlist
& output
, off_t stream_offset
)
66 CK_AES_CTR_PARAMS ctr_params
= {0};
72 unsigned int written2
;
74 slot
= PK11_GetBestSlot(CKM_AES_CTR
, NULL
);
76 keyItem
.type
= siBuffer
;
78 keyItem
.len
= AES_256_KEYSIZE
;
80 symkey
= PK11_ImportSymKey(slot
, CKM_AES_CTR
, PK11_OriginUnwrap
, CKA_UNWRAP
, &keyItem
, NULL
);
82 static_assert(sizeof(ctr_params
.cb
) >= AES_256_IVSIZE
, "Must fit counter");
83 ctr_params
.ulCounterBits
= 128;
84 prepare_iv(reinterpret_cast<unsigned char*>(&ctr_params
.cb
), stream_offset
);
86 ivItem
.type
= siBuffer
;
87 ivItem
.data
= (unsigned char*)&ctr_params
;
88 ivItem
.len
= sizeof(ctr_params
);
90 param
= PK11_ParamFromIV(CKM_AES_CTR
, &ivItem
);
92 ectx
= PK11_CreateContextBySymKey(CKM_AES_CTR
, CKA_ENCRYPT
, symkey
, param
);
94 buffer::ptr
buf((size
+ AES_256_KEYSIZE
- 1) / AES_256_KEYSIZE
* AES_256_KEYSIZE
);
95 ret
= PK11_CipherOp(ectx
,
96 (unsigned char*)buf
.c_str(), &written
, buf
.length(),
97 (unsigned char*)input
.c_str() + in_ofs
, size
);
98 if (ret
== SECSuccess
) {
99 ret
= PK11_DigestFinal(ectx
,
100 (unsigned char*)buf
.c_str() + written
, &written2
,
101 buf
.length() - written
);
102 if (ret
== SECSuccess
) {
103 buf
.set_length(written
+ written2
);
108 PK11_DestroyContext(ectx
, PR_TRUE
);
110 SECITEM_FreeItem(param
, PR_TRUE
);
112 PK11_FreeSymKey(symkey
);
116 if (result
== false) {
117 ldout(cct
, 5) << "Failed to perform AES-CTR encryption: " << PR_GetError() << dendl
;
123 # error "No supported crypto implementation found."
125 /* in CTR encrypt is the same as decrypt */
126 bool decrypt(bufferlist
& input
, off_t in_ofs
, size_t size
, bufferlist
& output
, off_t stream_offset
) {
127 return encrypt(input
, in_ofs
, size
, output
, stream_offset
);
130 void prepare_iv(unsigned char iv
[AES_256_IVSIZE
], off_t offset
) {
131 off_t index
= offset
/ AES_256_IVSIZE
;
132 off_t i
= AES_256_IVSIZE
- 1;
134 unsigned int carry
= 0;
136 val
= (index
& 0xff) + IV
[i
] + carry
;
145 const uint8_t AES_256_CTR::IV
[AES_256_CTR::AES_256_IVSIZE
] =
146 { 'a', 'e', 's', '2', '5', '6', 'i', 'v', '_', 'c', 't', 'r', '1', '3', '3', '7' };
149 CryptoAccelRef
get_crypto_accel(CephContext
*cct
)
151 CryptoAccelRef ca_impl
= nullptr;
153 PluginRegistry
*reg
= cct
->get_plugin_registry();
154 string crypto_accel_type
= cct
->_conf
->plugin_crypto_accelerator
;
156 CryptoPlugin
*factory
= dynamic_cast<CryptoPlugin
*>(reg
->get_with_load("crypto", crypto_accel_type
));
157 if (factory
== nullptr) {
158 lderr(cct
) << __func__
<< " cannot load crypto accelerator of type " << crypto_accel_type
<< dendl
;
161 int err
= factory
->factory(&ca_impl
, &ss
);
163 lderr(cct
) << __func__
<< " factory return error " << err
<<
164 " with description: " << ss
.str() << dendl
;
171 * Encryption in CBC mode. Chunked to 4K blocks. Offset is used as IV for each 4K block.
176 * 1. Input is split to 4K chunks + remainder in one, smaller chunk
177 * 2. Each full chunk is encrypted separately with CBC chained mode, with initial IV derived from offset
178 * 3. Last chunk is 16*m + n.
179 * 4. 16*m bytes are encrypted with CBC chained mode, with initial IV derived from offset
180 * 5. Last n bytes are xor-ed with pattern obtained by CBC encryption of
181 * last encrypted 16 byte block <16m-16, 16m-15) with IV = {0}.
182 * 6. (Special case) If m == 0 then last n bytes are xor-ed with pattern
183 * obtained by CBC encryption of {0} with IV derived from offset
186 * 1. Input is split to 4K chunks + remainder in one, smaller chunk
187 * 2. Each full chunk is decrypted separately with CBC chained mode, with initial IV derived from offset
188 * 3. Last chunk is 16*m + n.
189 * 4. 16*m bytes are decrypted with CBC chained mode, with initial IV derived from offset
190 * 5. Last n bytes are xor-ed with pattern obtained by CBC ENCRYPTION of
191 * last (still encrypted) 16 byte block <16m-16,16m-15) with IV = {0}
192 * 6. (Special case) If m == 0 then last n bytes are xor-ed with pattern
193 * obtained by CBC ENCRYPTION of {0} with IV derived from offset
195 class AES_256_CBC
: public BlockCrypt
{
197 static const size_t AES_256_KEYSIZE
= 256 / 8;
198 static const size_t AES_256_IVSIZE
= 128 / 8;
199 static const size_t CHUNK_SIZE
= 4096;
201 static const uint8_t IV
[AES_256_IVSIZE
];
203 uint8_t key
[AES_256_KEYSIZE
];
205 explicit AES_256_CBC(CephContext
* cct
): cct(cct
) {
208 memset(key
, 0, AES_256_KEYSIZE
);
210 bool set_key(const uint8_t* _key
, size_t key_size
) {
211 if (key_size
!= AES_256_KEYSIZE
) {
214 memcpy(key
, _key
, AES_256_KEYSIZE
);
217 size_t get_block_size() {
223 bool cbc_transform(unsigned char* out
,
224 const unsigned char* in
,
226 const unsigned char (&iv
)[AES_256_IVSIZE
],
227 const unsigned char (&key
)[AES_256_KEYSIZE
],
234 CK_AES_CBC_ENCRYPT_DATA_PARAMS ctr_params
= {0};
241 slot
= PK11_GetBestSlot(CKM_AES_CBC
, NULL
);
243 keyItem
.type
= siBuffer
;
244 keyItem
.data
= const_cast<unsigned char*>(&key
[0]);
245 keyItem
.len
= AES_256_KEYSIZE
;
246 symkey
= PK11_ImportSymKey(slot
, CKM_AES_CBC
, PK11_OriginUnwrap
, CKA_UNWRAP
, &keyItem
, NULL
);
248 memcpy(ctr_params
.iv
, iv
, AES_256_IVSIZE
);
249 ivItem
.type
= siBuffer
;
250 ivItem
.data
= (unsigned char*)&ctr_params
;
251 ivItem
.len
= sizeof(ctr_params
);
253 param
= PK11_ParamFromIV(CKM_AES_CBC
, &ivItem
);
255 ectx
= PK11_CreateContextBySymKey(CKM_AES_CBC
, encrypt
?CKA_ENCRYPT
:CKA_DECRYPT
, symkey
, param
);
257 ret
= PK11_CipherOp(ectx
,
260 if ((ret
== SECSuccess
) && (written
== (int)size
)) {
263 PK11_DestroyContext(ectx
, PR_TRUE
);
265 SECITEM_FreeItem(param
, PR_TRUE
);
267 PK11_FreeSymKey(symkey
);
271 if (result
== false) {
272 ldout(cct
, 5) << "Failed to perform AES-CBC encryption: " << PR_GetError() << dendl
;
278 # error "No supported crypto implementation found."
281 bool cbc_transform(unsigned char* out
,
282 const unsigned char* in
,
285 const unsigned char (&key
)[AES_256_KEYSIZE
],
288 static std::atomic
<bool> failed_to_get_crypto(false);
289 CryptoAccelRef crypto_accel
;
290 if (! failed_to_get_crypto
.load())
292 crypto_accel
= get_crypto_accel(cct
);
294 failed_to_get_crypto
= true;
297 unsigned char iv
[AES_256_IVSIZE
];
298 for (size_t offset
= 0; result
&& (offset
< size
); offset
+= CHUNK_SIZE
) {
299 size_t process_size
= offset
+ CHUNK_SIZE
<= size
? CHUNK_SIZE
: size
- offset
;
300 prepare_iv(iv
, stream_offset
+ offset
);
301 if (crypto_accel
!= nullptr) {
303 result
= crypto_accel
->cbc_encrypt(out
+ offset
, in
+ offset
,
304 process_size
, iv
, key
);
306 result
= crypto_accel
->cbc_decrypt(out
+ offset
, in
+ offset
,
307 process_size
, iv
, key
);
310 result
= cbc_transform(
311 out
+ offset
, in
+ offset
, process_size
,
319 bool encrypt(bufferlist
& input
,
326 size_t aligned_size
= size
/ AES_256_IVSIZE
* AES_256_IVSIZE
;
327 size_t unaligned_rest_size
= size
- aligned_size
;
329 buffer::ptr
buf(aligned_size
+ AES_256_IVSIZE
);
330 unsigned char* buf_raw
= reinterpret_cast<unsigned char*>(buf
.c_str());
331 const unsigned char* input_raw
= reinterpret_cast<const unsigned char*>(input
.c_str());
333 /* encrypt main bulk of data */
334 result
= cbc_transform(buf_raw
,
337 stream_offset
, key
, true);
338 if (result
&& (unaligned_rest_size
> 0)) {
339 /* remainder to encrypt */
340 if (aligned_size
% CHUNK_SIZE
> 0) {
341 /* use last chunk for unaligned part */
342 unsigned char iv
[AES_256_IVSIZE
] = {0};
343 result
= cbc_transform(buf_raw
+ aligned_size
,
344 buf_raw
+ aligned_size
- AES_256_IVSIZE
,
348 /* 0 full blocks in current chunk, use IV as base for unaligned part */
349 unsigned char iv
[AES_256_IVSIZE
] = {0};
350 unsigned char data
[AES_256_IVSIZE
];
351 prepare_iv(data
, stream_offset
+ aligned_size
);
352 result
= cbc_transform(buf_raw
+ aligned_size
,
358 for(size_t i
= aligned_size
; i
< size
; i
++) {
359 *(buf_raw
+ i
) ^= *(input_raw
+ in_ofs
+ i
);
364 ldout(cct
, 25) << "Encrypted " << size
<< " bytes"<< dendl
;
365 buf
.set_length(size
);
368 ldout(cct
, 5) << "Failed to encrypt" << dendl
;
374 bool decrypt(bufferlist
& input
,
381 size_t aligned_size
= size
/ AES_256_IVSIZE
* AES_256_IVSIZE
;
382 size_t unaligned_rest_size
= size
- aligned_size
;
384 buffer::ptr
buf(aligned_size
+ AES_256_IVSIZE
);
385 unsigned char* buf_raw
= reinterpret_cast<unsigned char*>(buf
.c_str());
386 unsigned char* input_raw
= reinterpret_cast<unsigned char*>(input
.c_str());
388 /* decrypt main bulk of data */
389 result
= cbc_transform(buf_raw
,
392 stream_offset
, key
, false);
393 if (result
&& unaligned_rest_size
> 0) {
394 /* remainder to decrypt */
395 if (aligned_size
% CHUNK_SIZE
> 0) {
396 /*use last chunk for unaligned part*/
397 unsigned char iv
[AES_256_IVSIZE
] = {0};
398 result
= cbc_transform(buf_raw
+ aligned_size
,
399 input_raw
+ in_ofs
+ aligned_size
- AES_256_IVSIZE
,
403 /* 0 full blocks in current chunk, use IV as base for unaligned part */
404 unsigned char iv
[AES_256_IVSIZE
] = {0};
405 unsigned char data
[AES_256_IVSIZE
];
406 prepare_iv(data
, stream_offset
+ aligned_size
);
407 result
= cbc_transform(buf_raw
+ aligned_size
,
413 for(size_t i
= aligned_size
; i
< size
; i
++) {
414 *(buf_raw
+ i
) ^= *(input_raw
+ in_ofs
+ i
);
419 ldout(cct
, 25) << "Decrypted " << size
<< " bytes"<< dendl
;
420 buf
.set_length(size
);
423 ldout(cct
, 5) << "Failed to decrypt" << dendl
;
429 void prepare_iv(unsigned char (&iv
)[AES_256_IVSIZE
], off_t offset
) {
430 off_t index
= offset
/ AES_256_IVSIZE
;
431 off_t i
= AES_256_IVSIZE
- 1;
433 unsigned int carry
= 0;
435 val
= (index
& 0xff) + IV
[i
] + carry
;
445 std::unique_ptr
<BlockCrypt
> AES_256_CBC_create(CephContext
* cct
, const uint8_t* key
, size_t len
)
447 auto cbc
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(cct
));
448 cbc
->set_key(key
, AES_256_KEYSIZE
);
449 return std::move(cbc
);
453 const uint8_t AES_256_CBC::IV
[AES_256_CBC::AES_256_IVSIZE
] =
454 { 'a', 'e', 's', '2', '5', '6', 'i', 'v', '_', 'c', 't', 'r', '1', '3', '3', '7' };
459 bool AES_256_ECB_encrypt(CephContext
* cct
,
462 const uint8_t* data_in
,
473 unsigned int written2
;
474 if (key_size
== AES_256_KEYSIZE
) {
475 slot
= PK11_GetBestSlot(CKM_AES_ECB
, NULL
);
477 keyItem
.type
= siBuffer
;
478 keyItem
.data
= const_cast<uint8_t*>(key
);
479 keyItem
.len
= AES_256_KEYSIZE
;
481 param
= PK11_ParamFromIV(CKM_AES_ECB
, NULL
);
483 symkey
= PK11_ImportSymKey(slot
, CKM_AES_ECB
, PK11_OriginUnwrap
, CKA_UNWRAP
, &keyItem
, NULL
);
485 ectx
= PK11_CreateContextBySymKey(CKM_AES_ECB
, CKA_ENCRYPT
, symkey
, param
);
487 ret
= PK11_CipherOp(ectx
,
488 data_out
, &written
, data_size
,
490 if (ret
== SECSuccess
) {
491 ret
= PK11_DigestFinal(ectx
,
492 data_out
+ written
, &written2
,
493 data_size
- written
);
494 if (ret
== SECSuccess
) {
498 PK11_DestroyContext(ectx
, PR_TRUE
);
500 PK11_FreeSymKey(symkey
);
502 SECITEM_FreeItem(param
, PR_TRUE
);
506 if (result
== false) {
507 ldout(cct
, 5) << "Failed to perform AES-ECB encryption: " << PR_GetError() << dendl
;
510 ldout(cct
, 5) << "Key size must be 256 bits long" << dendl
;
516 # error "No supported crypto implementation found."
520 RGWGetObj_BlockDecrypt::RGWGetObj_BlockDecrypt(CephContext
* cct
,
521 RGWGetObj_Filter
* next
,
522 std::unique_ptr
<BlockCrypt
> crypt
):
523 RGWGetObj_Filter(next
),
525 crypt(std::move(crypt
)),
531 block_size
= this->crypt
->get_block_size();
534 RGWGetObj_BlockDecrypt::~RGWGetObj_BlockDecrypt() {
537 int RGWGetObj_BlockDecrypt::read_manifest(bufferlist
& manifest_bl
) {
539 RGWObjManifest manifest
;
540 if (manifest_bl
.length()) {
541 auto miter
= manifest_bl
.cbegin();
543 decode(manifest
, miter
);
544 } catch (buffer::error
& err
) {
545 ldout(cct
, 0) << "ERROR: couldn't decode manifest" << dendl
;
548 RGWObjManifest::obj_iterator mi
;
549 for (mi
= manifest
.obj_begin(); mi
!= manifest
.obj_end(); ++mi
) {
550 if (mi
.get_cur_stripe() == 0) {
551 parts_len
.push_back(0);
553 parts_len
.back() += mi
.get_stripe_size();
555 if (cct
->_conf
->subsys
.should_gather
<ceph_subsys_rgw
, 20>()) {
556 for (size_t i
= 0; i
<parts_len
.size(); i
++) {
557 ldout(cct
, 20) << "Manifest part " << i
<< ", size=" << parts_len
[i
] << dendl
;
564 int RGWGetObj_BlockDecrypt::fixup_range(off_t
& bl_ofs
, off_t
& bl_end
) {
565 off_t inp_ofs
= bl_ofs
;
566 off_t inp_end
= bl_end
;
567 if (parts_len
.size() > 0) {
568 off_t in_ofs
= bl_ofs
;
569 off_t in_end
= bl_end
;
572 while (i
<parts_len
.size() && (in_ofs
>= (off_t
)parts_len
[i
])) {
573 in_ofs
-= parts_len
[i
];
576 //in_ofs is inside block i
578 while (j
<(parts_len
.size() - 1) && (in_end
>= (off_t
)parts_len
[j
])) {
579 in_end
-= parts_len
[j
];
582 //in_end is inside part j, OR j is the last part
584 size_t rounded_end
= ( in_end
& ~(block_size
- 1) ) + (block_size
- 1);
585 if (rounded_end
> parts_len
[j
]) {
586 rounded_end
= parts_len
[j
] - 1;
589 enc_begin_skip
= in_ofs
& (block_size
- 1);
590 ofs
= bl_ofs
- enc_begin_skip
;
592 bl_end
+= rounded_end
- in_end
;
593 bl_ofs
= std::min(bl_ofs
- enc_begin_skip
, bl_end
);
597 enc_begin_skip
= bl_ofs
& (block_size
- 1);
598 ofs
= bl_ofs
& ~(block_size
- 1);
600 bl_ofs
= bl_ofs
& ~(block_size
- 1);
601 bl_end
= ( bl_end
& ~(block_size
- 1) ) + (block_size
- 1);
603 ldout(cct
, 20) << "fixup_range [" << inp_ofs
<< "," << inp_end
604 << "] => [" << bl_ofs
<< "," << bl_end
<< "]" << dendl
;
608 int RGWGetObj_BlockDecrypt::process(bufferlist
& in
, size_t part_ofs
, size_t size
)
611 if (!crypt
->decrypt(in
, 0, size
, data
, part_ofs
)) {
612 return -ERR_INTERNAL_ERROR
;
614 off_t send_size
= size
- enc_begin_skip
;
615 if (ofs
+ enc_begin_skip
+ send_size
> end
+ 1) {
616 send_size
= end
+ 1 - ofs
- enc_begin_skip
;
618 int res
= next
->handle_data(data
, enc_begin_skip
, send_size
);
625 int RGWGetObj_BlockDecrypt::handle_data(bufferlist
& bl
, off_t bl_ofs
, off_t bl_len
) {
626 ldout(cct
, 25) << "Decrypt " << bl_len
<< " bytes" << dendl
;
627 bl
.copy(bl_ofs
, bl_len
, cache
);
630 size_t part_ofs
= ofs
;
631 for (size_t part
: parts_len
) {
632 if (part_ofs
>= part
) {
634 } else if (part_ofs
+ cache
.length() >= part
) {
635 // flush data up to part boundaries, aligned or not
636 res
= process(cache
, part_ofs
, part
- part_ofs
);
645 // write up to block boundaries, aligned only
646 off_t aligned_size
= cache
.length() & ~(block_size
- 1);
647 if (aligned_size
> 0) {
648 res
= process(cache
, part_ofs
, aligned_size
);
654 * flush remainder of data to output
656 int RGWGetObj_BlockDecrypt::flush() {
657 ldout(cct
, 25) << "Decrypt flushing " << cache
.length() << " bytes" << dendl
;
659 size_t part_ofs
= ofs
;
660 for (size_t part
: parts_len
) {
661 if (part_ofs
>= part
) {
663 } else if (part_ofs
+ cache
.length() >= part
) {
664 // flush data up to part boundaries, aligned or not
665 res
= process(cache
, part_ofs
, part
- part_ofs
);
674 // flush up to block boundaries, aligned or not
675 if (cache
.length() > 0) {
676 res
= process(cache
, part_ofs
, cache
.length());
681 RGWPutObj_BlockEncrypt::RGWPutObj_BlockEncrypt(CephContext
* cct
,
682 rgw::putobj::DataProcessor
*next
,
683 std::unique_ptr
<BlockCrypt
> crypt
)
686 crypt(std::move(crypt
)),
687 block_size(this->crypt
->get_block_size())
691 int RGWPutObj_BlockEncrypt::process(bufferlist
&& data
, uint64_t logical_offset
)
693 ldout(cct
, 25) << "Encrypt " << data
.length() << " bytes" << dendl
;
695 // adjust logical offset to beginning of cached data
696 ceph_assert(logical_offset
>= cache
.length());
697 logical_offset
-= cache
.length();
699 const bool flush
= (data
.length() == 0);
700 cache
.claim_append(data
);
702 uint64_t proc_size
= cache
.length() & ~(block_size
- 1);
704 proc_size
= cache
.length();
708 cache
.splice(0, proc_size
, &in
);
709 if (!crypt
->encrypt(in
, 0, proc_size
, out
, logical_offset
)) {
710 return -ERR_INTERNAL_ERROR
;
712 int r
= Pipe::process(std::move(out
), logical_offset
);
713 logical_offset
+= proc_size
;
719 /*replicate 0-sized handle_data*/
720 return Pipe::process({}, logical_offset
);
726 std::string
create_random_key_selector(CephContext
* const cct
) {
727 char random
[AES_256_KEYSIZE
];
728 cct
->random()->get_bytes(&random
[0], sizeof(random
));
729 return std::string(random
, sizeof(random
));
732 static int get_barbican_url(CephContext
* const cct
,
735 url
= cct
->_conf
->rgw_barbican_url
;
737 ldout(cct
, 0) << "ERROR: conf rgw_barbican_url is not set" << dendl
;
741 if (url
.back() != '/') {
748 static int request_key_from_barbican(CephContext
*cct
,
749 boost::string_view key_id
,
750 boost::string_view key_selector
,
751 const std::string
& barbican_token
,
752 std::string
& actual_key
) {
753 std::string secret_url
;
755 res
= get_barbican_url(cct
, secret_url
);
759 secret_url
+= "v1/secrets/" + std::string(key_id
);
761 bufferlist secret_bl
;
762 RGWHTTPTransceiver
secret_req(cct
, "GET", secret_url
, &secret_bl
);
763 secret_req
.append_header("Accept", "application/octet-stream");
764 secret_req
.append_header("X-Auth-Token", barbican_token
);
766 res
= secret_req
.process();
770 if (secret_req
.get_http_status() ==
771 RGWHTTPTransceiver::HTTP_STATUS_UNAUTHORIZED
) {
775 if (secret_req
.get_http_status() >=200 &&
776 secret_req
.get_http_status() < 300 &&
777 secret_bl
.length() == AES_256_KEYSIZE
) {
778 actual_key
.assign(secret_bl
.c_str(), secret_bl
.length());
779 memset(secret_bl
.c_str(), 0, secret_bl
.length());
786 static map
<string
,string
> get_str_map(const string
&str
) {
787 map
<string
,string
> m
;
788 get_str_map(str
, &m
, ";, \t");
792 static int get_actual_key_from_kms(CephContext
*cct
,
793 boost::string_view key_id
,
794 boost::string_view key_selector
,
795 std::string
& actual_key
)
798 ldout(cct
, 20) << "Getting KMS encryption key for key=" << key_id
<< dendl
;
799 static map
<string
,string
> str_map
= get_str_map(
800 cct
->_conf
->rgw_crypt_s3_kms_encryption_keys
);
802 map
<string
, string
>::iterator it
= str_map
.find(std::string(key_id
));
803 if (it
!= str_map
.end() ) {
804 std::string master_key
;
806 master_key
= from_base64((*it
).second
);
808 ldout(cct
, 5) << "ERROR: get_actual_key_from_kms invalid encryption key id "
809 << "which contains character that is not base64 encoded."
814 if (master_key
.length() == AES_256_KEYSIZE
) {
815 uint8_t _actual_key
[AES_256_KEYSIZE
];
816 if (AES_256_ECB_encrypt(cct
,
817 reinterpret_cast<const uint8_t*>(master_key
.c_str()), AES_256_KEYSIZE
,
818 reinterpret_cast<const uint8_t*>(key_selector
.data()),
819 _actual_key
, AES_256_KEYSIZE
)) {
820 actual_key
= std::string((char*)&_actual_key
[0], AES_256_KEYSIZE
);
824 memset(_actual_key
, 0, sizeof(_actual_key
));
826 ldout(cct
, 20) << "Wrong size for key=" << key_id
<< dendl
;
831 if (rgw::keystone::Service::get_keystone_barbican_token(cct
, token
) < 0) {
832 ldout(cct
, 5) << "Failed to retrieve token for barbican" << dendl
;
837 res
= request_key_from_barbican(cct
, key_id
, key_selector
, token
, actual_key
);
839 ldout(cct
, 5) << "Failed to retrieve secret from barbican:" << key_id
<< dendl
;
845 static inline void set_attr(map
<string
, bufferlist
>& attrs
,
847 boost::string_view value
)
850 bl
.append(value
.data(), value
.size());
851 attrs
[key
] = std::move(bl
);
854 static inline std::string
get_str_attribute(map
<string
, bufferlist
>& attrs
,
857 auto iter
= attrs
.find(name
);
858 if (iter
== attrs
.end()) {
861 return iter
->second
.to_str();
865 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM
=0,
866 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY
,
867 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5
,
868 X_AMZ_SERVER_SIDE_ENCRYPTION
,
869 X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID
,
870 X_AMZ_SERVER_SIDE_ENCRYPTION_LAST
874 const char* http_header_name
;
875 const std::string post_part_name
;
876 } crypt_option_names
;
878 static const crypt_option_names crypt_options
[] = {
879 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", "x-amz-server-side-encryption-customer-algorithm"},
880 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", "x-amz-server-side-encryption-customer-key"},
881 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "x-amz-server-side-encryption-customer-key-md5"},
882 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION", "x-amz-server-side-encryption"},
883 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID", "x-amz-server-side-encryption-aws-kms-key-id"},
886 static boost::string_view
get_crypt_attribute(
888 std::map
<std::string
,
889 RGWPostObj_ObjStore::post_form_part
,
890 const ltstr_nocase
>* parts
,
891 crypt_option_e option
)
894 X_AMZ_SERVER_SIDE_ENCRYPTION_LAST
== sizeof(crypt_options
)/sizeof(*crypt_options
),
895 "Missing items in crypt_options");
896 if (parts
!= nullptr) {
898 = parts
->find(crypt_options
[option
].post_part_name
);
899 if (iter
== parts
->end())
900 return boost::string_view();
901 bufferlist
& data
= iter
->second
.data
;
902 boost::string_view str
= boost::string_view(data
.c_str(), data
.length());
903 return rgw_trim_whitespace(str
);
905 const char* hdr
= env
->get(crypt_options
[option
].http_header_name
, nullptr);
906 if (hdr
!= nullptr) {
907 return boost::string_view(hdr
);
909 return boost::string_view();
915 int rgw_s3_prepare_encrypt(struct req_state
* s
,
916 std::map
<std::string
, ceph::bufferlist
>& attrs
,
917 std::map
<std::string
,
918 RGWPostObj_ObjStore::post_form_part
,
919 const ltstr_nocase
>* parts
,
920 std::unique_ptr
<BlockCrypt
>* block_crypt
,
921 std::map
<std::string
, std::string
>& crypt_http_responses
)
924 crypt_http_responses
.clear();
926 boost::string_view req_sse_ca
=
927 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM
);
928 if (! req_sse_ca
.empty()) {
929 if (req_sse_ca
!= "AES256") {
930 ldout(s
->cct
, 5) << "ERROR: Invalid value for header "
931 << "x-amz-server-side-encryption-customer-algorithm"
933 s
->err
.message
= "The requested encryption algorithm is not valid, must be AES256.";
934 return -ERR_INVALID_ENCRYPTION_ALGORITHM
;
936 if (s
->cct
->_conf
->rgw_crypt_require_ssl
&&
937 !rgw_transport_is_secure(s
->cct
, *s
->info
.env
)) {
938 ldout(s
->cct
, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl
;
939 return -ERR_INVALID_REQUEST
;
944 key_bin
= from_base64(
945 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY
) );
947 ldout(s
->cct
, 5) << "ERROR: rgw_s3_prepare_encrypt invalid encryption "
948 << "key which contains character that is not base64 encoded."
950 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
951 "provided keys must provide an appropriate secret key.";
955 if (key_bin
.size() != AES_256_CBC::AES_256_KEYSIZE
) {
956 ldout(s
->cct
, 5) << "ERROR: invalid encryption key size" << dendl
;
957 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
958 "provided keys must provide an appropriate secret key.";
962 boost::string_view keymd5
=
963 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5
);
965 std::string keymd5_bin
;
967 keymd5_bin
= from_base64(keymd5
);
969 ldout(s
->cct
, 5) << "ERROR: rgw_s3_prepare_encrypt invalid encryption key "
970 << "md5 which contains character that is not base64 encoded."
972 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
973 "provided keys must provide an appropriate secret key md5.";
977 if (keymd5_bin
.size() != CEPH_CRYPTO_MD5_DIGESTSIZE
) {
978 ldout(s
->cct
, 5) << "ERROR: Invalid key md5 size" << dendl
;
979 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
980 "provided keys must provide an appropriate secret key md5.";
985 unsigned char key_hash_res
[CEPH_CRYPTO_MD5_DIGESTSIZE
];
986 key_hash
.Update(reinterpret_cast<const unsigned char*>(key_bin
.c_str()), key_bin
.size());
987 key_hash
.Final(key_hash_res
);
989 if (memcmp(key_hash_res
, keymd5_bin
.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE
) != 0) {
990 ldout(s
->cct
, 5) << "ERROR: Invalid key md5 hash" << dendl
;
991 s
->err
.message
= "The calculated MD5 hash of the key did not match the hash that was provided.";
995 set_attr(attrs
, RGW_ATTR_CRYPT_MODE
, "SSE-C-AES256");
996 set_attr(attrs
, RGW_ATTR_CRYPT_KEYMD5
, keymd5_bin
);
999 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1000 aes
->set_key(reinterpret_cast<const uint8_t*>(key_bin
.c_str()), AES_256_KEYSIZE
);
1001 *block_crypt
= std::move(aes
);
1004 crypt_http_responses
["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
1005 crypt_http_responses
["x-amz-server-side-encryption-customer-key-MD5"] = keymd5
.to_string();
1008 boost::string_view customer_key
=
1009 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY
);
1010 if (!customer_key
.empty()) {
1011 ldout(s
->cct
, 5) << "ERROR: SSE-C encryption request is missing the header "
1012 << "x-amz-server-side-encryption-customer-algorithm"
1014 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
1015 "provided keys must provide a valid encryption algorithm.";
1019 boost::string_view customer_key_md5
=
1020 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5
);
1021 if (!customer_key_md5
.empty()) {
1022 ldout(s
->cct
, 5) << "ERROR: SSE-C encryption request is missing the header "
1023 << "x-amz-server-side-encryption-customer-algorithm"
1025 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
1026 "provided keys must provide a valid encryption algorithm.";
1031 /* AMAZON server side encryption with KMS (key management service) */
1032 boost::string_view req_sse
=
1033 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION
);
1034 if (! req_sse
.empty()) {
1035 if (req_sse
!= "aws:kms") {
1036 ldout(s
->cct
, 5) << "ERROR: Invalid value for header x-amz-server-side-encryption"
1038 s
->err
.message
= "Server Side Encryption with KMS managed key requires "
1039 "HTTP header x-amz-server-side-encryption : aws:kms";
1042 if (s
->cct
->_conf
->rgw_crypt_require_ssl
&&
1043 !rgw_transport_is_secure(s
->cct
, *s
->info
.env
)) {
1044 ldout(s
->cct
, 5) << "ERROR: insecure request, rgw_crypt_require_ssl is set" << dendl
;
1045 return -ERR_INVALID_REQUEST
;
1047 boost::string_view key_id
=
1048 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID
);
1049 if (key_id
.empty()) {
1050 ldout(s
->cct
, 5) << "ERROR: not provide a valid key id" << dendl
;
1051 s
->err
.message
= "Server Side Encryption with KMS managed key requires "
1052 "HTTP header x-amz-server-side-encryption-aws-kms-key-id";
1053 return -ERR_INVALID_ACCESS_KEY
;
1055 /* try to retrieve actual key */
1056 std::string key_selector
= create_random_key_selector(s
->cct
);
1057 std::string actual_key
;
1058 res
= get_actual_key_from_kms(s
->cct
, key_id
, key_selector
, actual_key
);
1060 ldout(s
->cct
, 5) << "ERROR: failed to retrieve actual key from key_id: " << key_id
<< dendl
;
1061 s
->err
.message
= "Failed to retrieve the actual key, kms-keyid: " + key_id
.to_string();
1064 if (actual_key
.size() != AES_256_KEYSIZE
) {
1065 ldout(s
->cct
, 5) << "ERROR: key obtained from key_id:" <<
1066 key_id
<< " is not 256 bit size" << dendl
;
1067 s
->err
.message
= "KMS provided an invalid key for the given kms-keyid.";
1068 return -ERR_INVALID_ACCESS_KEY
;
1070 set_attr(attrs
, RGW_ATTR_CRYPT_MODE
, "SSE-KMS");
1071 set_attr(attrs
, RGW_ATTR_CRYPT_KEYID
, key_id
);
1072 set_attr(attrs
, RGW_ATTR_CRYPT_KEYSEL
, key_selector
);
1075 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1076 aes
->set_key(reinterpret_cast<const uint8_t*>(actual_key
.c_str()), AES_256_KEYSIZE
);
1077 *block_crypt
= std::move(aes
);
1079 actual_key
.replace(0, actual_key
.length(), actual_key
.length(), '\000');
1081 crypt_http_responses
["x-amz-server-side-encryption"] = "aws:kms";
1082 crypt_http_responses
["x-amz-server-side-encryption-aws-kms-key-id"] = key_id
.to_string();
1085 boost::string_view key_id
=
1086 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID
);
1087 if (!key_id
.empty()) {
1088 ldout(s
->cct
, 5) << "ERROR: SSE-KMS encryption request is missing the header "
1089 << "x-amz-server-side-encryption"
1091 s
->err
.message
= "Server Side Encryption with KMS managed key requires "
1092 "HTTP header x-amz-server-side-encryption : aws:kms";
1097 /* no other encryption mode, check if default encryption is selected */
1098 if (s
->cct
->_conf
->rgw_crypt_default_encryption_key
!= "") {
1099 std::string master_encryption_key
;
1101 master_encryption_key
= from_base64(s
->cct
->_conf
->rgw_crypt_default_encryption_key
);
1103 ldout(s
->cct
, 5) << "ERROR: rgw_s3_prepare_encrypt invalid default encryption key "
1104 << "which contains character that is not base64 encoded."
1106 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
1107 "provided keys must provide an appropriate secret key.";
1111 if (master_encryption_key
.size() != 256 / 8) {
1112 ldout(s
->cct
, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl
;
1113 /* not an error to return; missing encryption does not inhibit processing */
1117 set_attr(attrs
, RGW_ATTR_CRYPT_MODE
, "RGW-AUTO");
1118 std::string key_selector
= create_random_key_selector(s
->cct
);
1119 set_attr(attrs
, RGW_ATTR_CRYPT_KEYSEL
, key_selector
);
1121 uint8_t actual_key
[AES_256_KEYSIZE
];
1122 if (AES_256_ECB_encrypt(s
->cct
,
1123 reinterpret_cast<const uint8_t*>(master_encryption_key
.c_str()), AES_256_KEYSIZE
,
1124 reinterpret_cast<const uint8_t*>(key_selector
.c_str()),
1125 actual_key
, AES_256_KEYSIZE
) != true) {
1126 memset(actual_key
, 0, sizeof(actual_key
));
1130 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1131 aes
->set_key(reinterpret_cast<const uint8_t*>(actual_key
), AES_256_KEYSIZE
);
1132 *block_crypt
= std::move(aes
);
1134 memset(actual_key
, 0, sizeof(actual_key
));
1143 int rgw_s3_prepare_decrypt(struct req_state
* s
,
1144 map
<string
, bufferlist
>& attrs
,
1145 std::unique_ptr
<BlockCrypt
>* block_crypt
,
1146 std::map
<std::string
, std::string
>& crypt_http_responses
)
1149 std::string stored_mode
= get_str_attribute(attrs
, RGW_ATTR_CRYPT_MODE
);
1150 ldout(s
->cct
, 15) << "Encryption mode: " << stored_mode
<< dendl
;
1152 const char *req_sse
= s
->info
.env
->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION", NULL
);
1153 if (nullptr != req_sse
&& (s
->op
== OP_GET
|| s
->op
== OP_HEAD
)) {
1154 return -ERR_INVALID_REQUEST
;
1157 if (stored_mode
== "SSE-C-AES256") {
1158 if (s
->cct
->_conf
->rgw_crypt_require_ssl
&&
1159 !rgw_transport_is_secure(s
->cct
, *s
->info
.env
)) {
1160 ldout(s
->cct
, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl
;
1161 return -ERR_INVALID_REQUEST
;
1163 const char *req_cust_alg
=
1164 s
->info
.env
->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", NULL
);
1166 if (nullptr == req_cust_alg
) {
1167 ldout(s
->cct
, 5) << "ERROR: Request for SSE-C encrypted object missing "
1168 << "x-amz-server-side-encryption-customer-algorithm"
1170 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
1171 "provided keys must provide a valid encryption algorithm.";
1173 } else if (strcmp(req_cust_alg
, "AES256") != 0) {
1174 ldout(s
->cct
, 5) << "ERROR: The requested encryption algorithm is not valid, must be AES256." << dendl
;
1175 s
->err
.message
= "The requested encryption algorithm is not valid, must be AES256.";
1176 return -ERR_INVALID_ENCRYPTION_ALGORITHM
;
1179 std::string key_bin
;
1181 key_bin
= from_base64(s
->info
.env
->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", ""));
1183 ldout(s
->cct
, 5) << "ERROR: rgw_s3_prepare_decrypt invalid encryption key "
1184 << "which contains character that is not base64 encoded."
1186 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
1187 "provided keys must provide an appropriate secret key.";
1191 if (key_bin
.size() != AES_256_CBC::AES_256_KEYSIZE
) {
1192 ldout(s
->cct
, 5) << "ERROR: Invalid encryption key size" << dendl
;
1193 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
1194 "provided keys must provide an appropriate secret key.";
1198 std::string keymd5
=
1199 s
->info
.env
->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "");
1200 std::string keymd5_bin
;
1202 keymd5_bin
= from_base64(keymd5
);
1204 ldout(s
->cct
, 5) << "ERROR: rgw_s3_prepare_decrypt invalid encryption key md5 "
1205 << "which contains character that is not base64 encoded."
1207 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
1208 "provided keys must provide an appropriate secret key md5.";
1213 if (keymd5_bin
.size() != CEPH_CRYPTO_MD5_DIGESTSIZE
) {
1214 ldout(s
->cct
, 5) << "ERROR: Invalid key md5 size " << dendl
;
1215 s
->err
.message
= "Requests specifying Server Side Encryption with Customer "
1216 "provided keys must provide an appropriate secret key md5.";
1221 uint8_t key_hash_res
[CEPH_CRYPTO_MD5_DIGESTSIZE
];
1222 key_hash
.Update(reinterpret_cast<const unsigned char*>(key_bin
.c_str()), key_bin
.size());
1223 key_hash
.Final(key_hash_res
);
1225 if ((memcmp(key_hash_res
, keymd5_bin
.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE
) != 0) ||
1226 (get_str_attribute(attrs
, RGW_ATTR_CRYPT_KEYMD5
) != keymd5_bin
)) {
1227 s
->err
.message
= "The calculated MD5 hash of the key did not match the hash that was provided.";
1230 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1231 aes
->set_key(reinterpret_cast<const uint8_t*>(key_bin
.c_str()), AES_256_CBC::AES_256_KEYSIZE
);
1232 if (block_crypt
) *block_crypt
= std::move(aes
);
1234 crypt_http_responses
["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
1235 crypt_http_responses
["x-amz-server-side-encryption-customer-key-MD5"] = keymd5
;
1239 if (stored_mode
== "SSE-KMS") {
1240 if (s
->cct
->_conf
->rgw_crypt_require_ssl
&&
1241 !rgw_transport_is_secure(s
->cct
, *s
->info
.env
)) {
1242 ldout(s
->cct
, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl
;
1243 return -ERR_INVALID_REQUEST
;
1245 /* try to retrieve actual key */
1246 std::string key_id
= get_str_attribute(attrs
, RGW_ATTR_CRYPT_KEYID
);
1247 std::string key_selector
= get_str_attribute(attrs
, RGW_ATTR_CRYPT_KEYSEL
);
1248 std::string actual_key
;
1249 res
= get_actual_key_from_kms(s
->cct
, key_id
, key_selector
, actual_key
);
1251 ldout(s
->cct
, 10) << "ERROR: failed to retrieve actual key from key_id: " << key_id
<< dendl
;
1252 s
->err
.message
= "Failed to retrieve the actual key, kms-keyid: " + key_id
;
1255 if (actual_key
.size() != AES_256_KEYSIZE
) {
1256 ldout(s
->cct
, 0) << "ERROR: key obtained from key_id:" <<
1257 key_id
<< " is not 256 bit size" << dendl
;
1258 s
->err
.message
= "KMS provided an invalid key for the given kms-keyid.";
1259 return -ERR_INVALID_ACCESS_KEY
;
1262 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1263 aes
->set_key(reinterpret_cast<const uint8_t*>(actual_key
.c_str()), AES_256_KEYSIZE
);
1264 actual_key
.replace(0, actual_key
.length(), actual_key
.length(), '\000');
1265 if (block_crypt
) *block_crypt
= std::move(aes
);
1267 crypt_http_responses
["x-amz-server-side-encryption"] = "aws:kms";
1268 crypt_http_responses
["x-amz-server-side-encryption-aws-kms-key-id"] = key_id
;
1272 if (stored_mode
== "RGW-AUTO") {
1273 std::string master_encryption_key
;
1275 master_encryption_key
= from_base64(std::string(s
->cct
->_conf
->rgw_crypt_default_encryption_key
));
1277 ldout(s
->cct
, 5) << "ERROR: rgw_s3_prepare_decrypt invalid default encryption key "
1278 << "which contains character that is not base64 encoded."
1280 s
->err
.message
= "The default encryption key is not valid base64.";
1284 if (master_encryption_key
.size() != 256 / 8) {
1285 ldout(s
->cct
, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl
;
1288 std::string attr_key_selector
= get_str_attribute(attrs
, RGW_ATTR_CRYPT_KEYSEL
);
1289 if (attr_key_selector
.size() != AES_256_CBC::AES_256_KEYSIZE
) {
1290 ldout(s
->cct
, 0) << "ERROR: missing or invalid " RGW_ATTR_CRYPT_KEYSEL
<< dendl
;
1293 uint8_t actual_key
[AES_256_KEYSIZE
];
1294 if (AES_256_ECB_encrypt(s
->cct
,
1295 reinterpret_cast<const uint8_t*>(master_encryption_key
.c_str()),
1297 reinterpret_cast<const uint8_t*>(attr_key_selector
.c_str()),
1298 actual_key
, AES_256_KEYSIZE
) != true) {
1299 memset(actual_key
, 0, sizeof(actual_key
));
1302 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1303 aes
->set_key(actual_key
, AES_256_KEYSIZE
);
1304 memset(actual_key
, 0, sizeof(actual_key
));
1305 if (block_crypt
) *block_crypt
= std::move(aes
);