1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Crypto filters for Put/Post/Get operations.
6 #include <rgw/rgw_op.h>
7 #include <rgw/rgw_crypt.h>
8 #include <auth/Crypto.h>
9 #include <rgw/rgw_b64.h>
10 #include <rgw/rgw_rest_s3.h>
11 #include "include/assert.h"
12 #include <boost/utility/string_view.hpp>
13 #include <rgw/rgw_keystone.h>
14 #include "include/str_map.h"
15 #include "crypto/crypto_accel.h"
16 #include "crypto/crypto_plugin.h"
24 #include <cryptopp/cryptlib.h>
25 #include <cryptopp/modes.h>
26 #include <cryptopp/aes.h>
27 using namespace CryptoPP
;
30 #define dout_context g_ceph_context
31 #define dout_subsys ceph_subsys_rgw
36 * Encryption in CTR mode. offset is used as IV for each block.
38 #warning "TODO: move this code to auth/Crypto for others to reuse."
40 class AES_256_CTR
: public BlockCrypt
{
42 static const size_t AES_256_KEYSIZE
= 256 / 8;
43 static const size_t AES_256_IVSIZE
= 128 / 8;
45 static const uint8_t IV
[AES_256_IVSIZE
];
47 uint8_t key
[AES_256_KEYSIZE
];
49 AES_256_CTR(CephContext
* cct
): cct(cct
) {
52 memset(key
, 0, AES_256_KEYSIZE
);
54 bool set_key(const uint8_t* _key
, size_t key_size
) {
55 if (key_size
!= AES_256_KEYSIZE
) {
58 memcpy(key
, _key
, AES_256_KEYSIZE
);
61 size_t get_block_size() {
62 return AES_256_IVSIZE
;
67 bool encrypt(bufferlist
& input
, off_t in_ofs
, size_t size
, bufferlist
& output
, off_t stream_offset
) {
68 byte iv
[AES_256_IVSIZE
];
70 << "Encrypt in_ofs " << in_ofs
72 << " stream_offset=" << stream_offset
74 if (input
.length() < in_ofs
+ size
) {
79 buffer::ptr
buf((size
+ AES_256_KEYSIZE
- 1) / AES_256_KEYSIZE
* AES_256_KEYSIZE
);
81 prepare_iv(iv
, stream_offset
);
82 CTR_Mode
< AES
>::Encryption e
;
83 e
.SetKeyWithIV(key
, AES_256_KEYSIZE
, iv
, AES_256_IVSIZE
);
85 e
.ProcessData((byte
*)buf
.c_str(), (byte
*)buf
.c_str(), buf
.length());
87 off_t plaintext_pos
= in_ofs
;
89 auto iter
= input
.buffers().begin();
90 //skip unaffected begin
91 while ((iter
!= input
.buffers().end()) && (plaintext_pos
>= iter
->length())) {
92 plaintext_pos
-= iter
->length();
95 while (iter
!= input
.buffers().end()) {
96 off_t cnt
= std::min
<off_t
>(iter
->length() - plaintext_pos
, size
- crypt_pos
);
97 byte
* src
= (byte
*)iter
->c_str() + plaintext_pos
;
98 byte
* dst
= (byte
*)buf
.c_str() + crypt_pos
;
99 for (off_t i
= 0; i
< cnt
; i
++) {
110 #elif defined(USE_NSS)
112 bool encrypt(bufferlist
& input
, off_t in_ofs
, size_t size
, bufferlist
& output
, off_t stream_offset
)
118 CK_AES_CTR_PARAMS ctr_params
= {0};
124 unsigned int written2
;
126 slot
= PK11_GetBestSlot(CKM_AES_CTR
, NULL
);
128 keyItem
.type
= siBuffer
;
130 keyItem
.len
= AES_256_KEYSIZE
;
132 symkey
= PK11_ImportSymKey(slot
, CKM_AES_CTR
, PK11_OriginUnwrap
, CKA_UNWRAP
, &keyItem
, NULL
);
134 static_assert(sizeof(ctr_params
.cb
) >= AES_256_IVSIZE
, "Must fit counter");
135 ctr_params
.ulCounterBits
= 128;
136 prepare_iv(reinterpret_cast<unsigned char*>(&ctr_params
.cb
), stream_offset
);
138 ivItem
.type
= siBuffer
;
139 ivItem
.data
= (unsigned char*)&ctr_params
;
140 ivItem
.len
= sizeof(ctr_params
);
142 param
= PK11_ParamFromIV(CKM_AES_CTR
, &ivItem
);
144 ectx
= PK11_CreateContextBySymKey(CKM_AES_CTR
, CKA_ENCRYPT
, symkey
, param
);
146 buffer::ptr
buf((size
+ AES_256_KEYSIZE
- 1) / AES_256_KEYSIZE
* AES_256_KEYSIZE
);
147 ret
= PK11_CipherOp(ectx
,
148 (unsigned char*)buf
.c_str(), &written
, buf
.length(),
149 (unsigned char*)input
.c_str() + in_ofs
, size
);
150 if (ret
== SECSuccess
) {
151 ret
= PK11_DigestFinal(ectx
,
152 (unsigned char*)buf
.c_str() + written
, &written2
,
153 buf
.length() - written
);
154 if (ret
== SECSuccess
) {
155 buf
.set_length(written
+ written2
);
160 PK11_DestroyContext(ectx
, PR_TRUE
);
162 SECITEM_FreeItem(param
, PR_TRUE
);
164 PK11_FreeSymKey(symkey
);
168 if (result
== false) {
169 ldout(cct
, 5) << "Failed to perform AES-CTR encryption: " << PR_GetError() << dendl
;
175 #error Must define USE_CRYPTOPP or USE_NSS
177 /* in CTR encrypt is the same as decrypt */
178 bool decrypt(bufferlist
& input
, off_t in_ofs
, size_t size
, bufferlist
& output
, off_t stream_offset
) {
179 return encrypt(input
, in_ofs
, size
, output
, stream_offset
);
182 void prepare_iv(byte iv
[AES_256_IVSIZE
], off_t offset
) {
183 off_t index
= offset
/ AES_256_IVSIZE
;
184 off_t i
= AES_256_IVSIZE
- 1;
186 unsigned int carry
= 0;
188 val
= (index
& 0xff) + IV
[i
] + carry
;
197 const uint8_t AES_256_CTR::IV
[AES_256_CTR::AES_256_IVSIZE
] =
198 { 'a', 'e', 's', '2', '5', '6', 'i', 'v', '_', 'c', 't', 'r', '1', '3', '3', '7' };
201 CryptoAccelRef
get_crypto_accel(CephContext
*cct
)
203 CryptoAccelRef ca_impl
= nullptr;
205 PluginRegistry
*reg
= cct
->get_plugin_registry();
206 string crypto_accel_type
= cct
->_conf
->plugin_crypto_accelerator
;
208 CryptoPlugin
*factory
= dynamic_cast<CryptoPlugin
*>(reg
->get_with_load("crypto", crypto_accel_type
));
209 if (factory
== nullptr) {
210 lderr(cct
) << __func__
<< " cannot load crypto accelerator of type " << crypto_accel_type
<< dendl
;
213 int err
= factory
->factory(&ca_impl
, &ss
);
215 lderr(cct
) << __func__
<< " factory return error " << err
<<
216 " with description: " << ss
.str() << dendl
;
223 * Encryption in CBC mode. Chunked to 4K blocks. Offset is used as IV for each 4K block.
228 * 1. Input is split to 4K chunks + remainder in one, smaller chunk
229 * 2. Each full chunk is encrypted separately with CBC chained mode, with initial IV derived from offset
230 * 3. Last chunk is 16*m + n.
231 * 4. 16*m bytes are encrypted with CBC chained mode, with initial IV derived from offset
232 * 5. Last n bytes are xor-ed with pattern obtained by CBC encryption of
233 * last encrypted 16 byte block <16m-16, 16m-15) with IV = {0}.
234 * 6. (Special case) If m == 0 then last n bytes are xor-ed with pattern
235 * obtained by CBC encryption of {0} with IV derived from offset
238 * 1. Input is split to 4K chunks + remainder in one, smaller chunk
239 * 2. Each full chunk is decrypted separately with CBC chained mode, with initial IV derived from offset
240 * 3. Last chunk is 16*m + n.
241 * 4. 16*m bytes are decrypted with CBC chained mode, with initial IV derived from offset
242 * 5. Last n bytes are xor-ed with pattern obtained by CBC ENCRYPTION of
243 * last (still encrypted) 16 byte block <16m-16,16m-15) with IV = {0}
244 * 6. (Special case) If m == 0 then last n bytes are xor-ed with pattern
245 * obtained by CBC ENCRYPTION of {0} with IV derived from offset
247 #warning "TODO: use auth/Crypto instead of reimplementing."
248 class AES_256_CBC
: public BlockCrypt
{
250 static const size_t AES_256_KEYSIZE
= 256 / 8;
251 static const size_t AES_256_IVSIZE
= 128 / 8;
252 static const size_t CHUNK_SIZE
= 4096;
254 static const uint8_t IV
[AES_256_IVSIZE
];
256 uint8_t key
[AES_256_KEYSIZE
];
258 AES_256_CBC(CephContext
* cct
): cct(cct
) {
261 memset(key
, 0, AES_256_KEYSIZE
);
263 bool set_key(const uint8_t* _key
, size_t key_size
) {
264 if (key_size
!= AES_256_KEYSIZE
) {
267 memcpy(key
, _key
, AES_256_KEYSIZE
);
270 size_t get_block_size() {
276 bool cbc_transform(unsigned char* out
,
277 const unsigned char* in
,
279 const unsigned char (&iv
)[AES_256_IVSIZE
],
280 const unsigned char (&key
)[AES_256_KEYSIZE
],
284 CBC_Mode
< AES
>::Encryption e
;
285 e
.SetKeyWithIV(key
, AES_256_KEYSIZE
, iv
, AES_256_IVSIZE
);
286 e
.ProcessData((byte
*)out
, (byte
*)in
, size
);
288 CBC_Mode
< AES
>::Decryption d
;
289 d
.SetKeyWithIV(key
, AES_256_KEYSIZE
, iv
, AES_256_IVSIZE
);
290 d
.ProcessData((byte
*)out
, (byte
*)in
, size
);
295 #elif defined(USE_NSS)
297 bool cbc_transform(unsigned char* out
,
298 const unsigned char* in
,
300 const unsigned char (&iv
)[AES_256_IVSIZE
],
301 const unsigned char (&key
)[AES_256_KEYSIZE
],
308 CK_AES_CBC_ENCRYPT_DATA_PARAMS ctr_params
= {0};
315 slot
= PK11_GetBestSlot(CKM_AES_CBC
, NULL
);
317 keyItem
.type
= siBuffer
;
318 keyItem
.data
= const_cast<unsigned char*>(&key
[0]);
319 keyItem
.len
= AES_256_KEYSIZE
;
320 symkey
= PK11_ImportSymKey(slot
, CKM_AES_CBC
, PK11_OriginUnwrap
, CKA_UNWRAP
, &keyItem
, NULL
);
322 memcpy(ctr_params
.iv
, iv
, AES_256_IVSIZE
);
323 ivItem
.type
= siBuffer
;
324 ivItem
.data
= (unsigned char*)&ctr_params
;
325 ivItem
.len
= sizeof(ctr_params
);
327 param
= PK11_ParamFromIV(CKM_AES_CBC
, &ivItem
);
329 ectx
= PK11_CreateContextBySymKey(CKM_AES_CBC
, encrypt
?CKA_ENCRYPT
:CKA_DECRYPT
, symkey
, param
);
331 ret
= PK11_CipherOp(ectx
,
334 if ((ret
== SECSuccess
) && (written
== (int)size
)) {
337 PK11_DestroyContext(ectx
, PR_TRUE
);
339 SECITEM_FreeItem(param
, PR_TRUE
);
341 PK11_FreeSymKey(symkey
);
345 if (result
== false) {
346 ldout(cct
, 5) << "Failed to perform AES-CBC encryption: " << PR_GetError() << dendl
;
352 #error Must define USE_CRYPTOPP or USE_NSS
355 bool cbc_transform(unsigned char* out
,
356 const unsigned char* in
,
359 const unsigned char (&key
)[AES_256_KEYSIZE
],
362 static std::atomic
<bool> failed_to_get_crypto(false);
363 CryptoAccelRef crypto_accel
;
364 if (! failed_to_get_crypto
.load())
366 crypto_accel
= get_crypto_accel(cct
);
368 failed_to_get_crypto
= true;
371 unsigned char iv
[AES_256_IVSIZE
];
372 for (size_t offset
= 0; result
&& (offset
< size
); offset
+= CHUNK_SIZE
) {
373 size_t process_size
= offset
+ CHUNK_SIZE
<= size
? CHUNK_SIZE
: size
- offset
;
374 prepare_iv(iv
, stream_offset
+ offset
);
375 if (crypto_accel
!= nullptr) {
377 result
= crypto_accel
->cbc_encrypt(out
+ offset
, in
+ offset
,
378 process_size
, iv
, key
);
380 result
= crypto_accel
->cbc_decrypt(out
+ offset
, in
+ offset
,
381 process_size
, iv
, key
);
384 result
= cbc_transform(
385 out
+ offset
, in
+ offset
, process_size
,
393 bool encrypt(bufferlist
& input
,
400 size_t aligned_size
= size
/ AES_256_IVSIZE
* AES_256_IVSIZE
;
401 size_t unaligned_rest_size
= size
- aligned_size
;
403 buffer::ptr
buf(aligned_size
+ AES_256_IVSIZE
);
404 unsigned char* buf_raw
= reinterpret_cast<unsigned char*>(buf
.c_str());
405 const unsigned char* input_raw
= reinterpret_cast<const unsigned char*>(input
.c_str());
407 /* encrypt main bulk of data */
408 result
= cbc_transform(buf_raw
,
411 stream_offset
, key
, true);
412 if (result
&& (unaligned_rest_size
> 0)) {
413 /* remainder to encrypt */
414 if (aligned_size
% CHUNK_SIZE
> 0) {
415 /* use last chunk for unaligned part */
416 unsigned char iv
[AES_256_IVSIZE
] = {0};
417 result
= cbc_transform(buf_raw
+ aligned_size
,
418 buf_raw
+ aligned_size
- AES_256_IVSIZE
,
422 /* 0 full blocks in current chunk, use IV as base for unaligned part */
423 unsigned char iv
[AES_256_IVSIZE
] = {0};
424 unsigned char data
[AES_256_IVSIZE
];
425 prepare_iv(data
, stream_offset
+ aligned_size
);
426 result
= cbc_transform(buf_raw
+ aligned_size
,
432 for(size_t i
= aligned_size
; i
< size
; i
++) {
433 *(buf_raw
+ i
) ^= *(input_raw
+ in_ofs
+ i
);
438 ldout(cct
, 25) << "Encrypted " << size
<< " bytes"<< dendl
;
439 buf
.set_length(size
);
442 ldout(cct
, 5) << "Failed to encrypt" << dendl
;
448 bool decrypt(bufferlist
& input
,
455 size_t aligned_size
= size
/ AES_256_IVSIZE
* AES_256_IVSIZE
;
456 size_t unaligned_rest_size
= size
- aligned_size
;
458 buffer::ptr
buf(aligned_size
+ AES_256_IVSIZE
);
459 unsigned char* buf_raw
= reinterpret_cast<unsigned char*>(buf
.c_str());
460 unsigned char* input_raw
= reinterpret_cast<unsigned char*>(input
.c_str());
462 /* decrypt main bulk of data */
463 result
= cbc_transform(buf_raw
,
466 stream_offset
, key
, false);
467 if (result
&& unaligned_rest_size
> 0) {
468 /* remainder to decrypt */
469 if (aligned_size
% CHUNK_SIZE
> 0) {
470 /*use last chunk for unaligned part*/
471 unsigned char iv
[AES_256_IVSIZE
] = {0};
472 result
= cbc_transform(buf_raw
+ aligned_size
,
473 input_raw
+ in_ofs
+ aligned_size
- AES_256_IVSIZE
,
477 /* 0 full blocks in current chunk, use IV as base for unaligned part */
478 unsigned char iv
[AES_256_IVSIZE
] = {0};
479 unsigned char data
[AES_256_IVSIZE
];
480 prepare_iv(data
, stream_offset
+ aligned_size
);
481 result
= cbc_transform(buf_raw
+ aligned_size
,
487 for(size_t i
= aligned_size
; i
< size
; i
++) {
488 *(buf_raw
+ i
) ^= *(input_raw
+ in_ofs
+ i
);
493 ldout(cct
, 25) << "Decrypted " << size
<< " bytes"<< dendl
;
494 buf
.set_length(size
);
497 ldout(cct
, 5) << "Failed to decrypt" << dendl
;
503 void prepare_iv(byte (&iv
)[AES_256_IVSIZE
], off_t offset
) {
504 off_t index
= offset
/ AES_256_IVSIZE
;
505 off_t i
= AES_256_IVSIZE
- 1;
507 unsigned int carry
= 0;
509 val
= (index
& 0xff) + IV
[i
] + carry
;
519 std::unique_ptr
<BlockCrypt
> AES_256_CBC_create(CephContext
* cct
, const uint8_t* key
, size_t len
)
521 auto cbc
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(cct
));
522 cbc
->set_key(key
, AES_256_KEYSIZE
);
523 return std::move(cbc
);
527 const uint8_t AES_256_CBC::IV
[AES_256_CBC::AES_256_IVSIZE
] =
528 { 'a', 'e', 's', '2', '5', '6', 'i', 'v', '_', 'c', 't', 'r', '1', '3', '3', '7' };
533 bool AES_256_ECB_encrypt(CephContext
* cct
,
536 const uint8_t* data_in
,
541 if (key_size
== AES_256_KEYSIZE
) {
543 ECB_Mode
< AES
>::Encryption e
;
544 e
.SetKey( key
, key_size
);
545 e
.ProcessData(data_out
, data_in
, data_size
);
547 } catch( CryptoPP::Exception
& ex
) {
548 ldout(cct
, 5) << "AES-ECB encryption failed with: " << ex
.GetWhat() << dendl
;
554 #elif defined USE_NSS
556 bool AES_256_ECB_encrypt(CephContext
* cct
,
559 const uint8_t* data_in
,
570 unsigned int written2
;
571 if (key_size
== AES_256_KEYSIZE
) {
572 slot
= PK11_GetBestSlot(CKM_AES_ECB
, NULL
);
574 keyItem
.type
= siBuffer
;
575 keyItem
.data
= const_cast<uint8_t*>(key
);
576 keyItem
.len
= AES_256_KEYSIZE
;
578 param
= PK11_ParamFromIV(CKM_AES_ECB
, NULL
);
580 symkey
= PK11_ImportSymKey(slot
, CKM_AES_ECB
, PK11_OriginUnwrap
, CKA_UNWRAP
, &keyItem
, NULL
);
582 ectx
= PK11_CreateContextBySymKey(CKM_AES_ECB
, CKA_ENCRYPT
, symkey
, param
);
584 ret
= PK11_CipherOp(ectx
,
585 data_out
, &written
, data_size
,
587 if (ret
== SECSuccess
) {
588 ret
= PK11_DigestFinal(ectx
,
589 data_out
+ written
, &written2
,
590 data_size
- written
);
591 if (ret
== SECSuccess
) {
595 PK11_DestroyContext(ectx
, PR_TRUE
);
597 PK11_FreeSymKey(symkey
);
599 SECITEM_FreeItem(param
, PR_TRUE
);
603 if (result
== false) {
604 ldout(cct
, 5) << "Failed to perform AES-ECB encryption: " << PR_GetError() << dendl
;
607 ldout(cct
, 5) << "Key size must be 256 bits long" << dendl
;
613 #error Must define USE_CRYPTOPP or USE_NSS
617 RGWGetObj_BlockDecrypt::RGWGetObj_BlockDecrypt(CephContext
* cct
,
619 std::unique_ptr
<BlockCrypt
> crypt
):
620 RGWGetObj_Filter(next
),
622 crypt(std::move(crypt
)),
628 block_size
= this->crypt
->get_block_size();
631 RGWGetObj_BlockDecrypt::~RGWGetObj_BlockDecrypt() {
634 int RGWGetObj_BlockDecrypt::read_manifest(bufferlist
& manifest_bl
) {
636 RGWObjManifest manifest
;
637 if (manifest_bl
.length()) {
638 bufferlist::iterator miter
= manifest_bl
.begin();
640 ::decode(manifest
, miter
);
641 } catch (buffer::error
& err
) {
642 ldout(cct
, 0) << "ERROR: couldn't decode manifest" << dendl
;
645 RGWObjManifest::obj_iterator mi
;
646 for (mi
= manifest
.obj_begin(); mi
!= manifest
.obj_end(); ++mi
) {
647 if (mi
.get_cur_stripe() == 0) {
648 parts_len
.push_back(0);
650 parts_len
.back() += mi
.get_stripe_size();
652 if (cct
->_conf
->subsys
.should_gather(ceph_subsys_rgw
, 20)) {
653 for (size_t i
= 0; i
<parts_len
.size(); i
++) {
654 ldout(cct
, 20) << "Manifest part " << i
<< ", size=" << parts_len
[i
] << dendl
;
661 int RGWGetObj_BlockDecrypt::fixup_range(off_t
& bl_ofs
, off_t
& bl_end
) {
662 off_t inp_ofs
= bl_ofs
;
663 off_t inp_end
= bl_end
;
664 if (parts_len
.size() > 0) {
665 off_t in_ofs
= bl_ofs
;
666 off_t in_end
= bl_end
;
669 while (i
<parts_len
.size() && (in_ofs
> (off_t
)parts_len
[i
])) {
670 in_ofs
-= parts_len
[i
];
673 //in_ofs is inside block i
675 while (j
<parts_len
.size() && (in_end
> (off_t
)parts_len
[j
])) {
676 in_end
-= parts_len
[j
];
679 //in_end is inside block j
682 rounded_end
= ( in_end
& ~(block_size
- 1) ) + (block_size
- 1);
683 if (rounded_end
+ 1 >= parts_len
[j
]) {
684 rounded_end
= parts_len
[j
] - 1;
687 enc_begin_skip
= in_ofs
& (block_size
- 1);
688 ofs
= bl_ofs
- enc_begin_skip
;
690 bl_ofs
= bl_ofs
- enc_begin_skip
;
691 bl_end
+= rounded_end
- in_end
;
695 enc_begin_skip
= bl_ofs
& (block_size
- 1);
696 ofs
= bl_ofs
& ~(block_size
- 1);
698 bl_ofs
= bl_ofs
& ~(block_size
- 1);
699 bl_end
= ( bl_end
& ~(block_size
- 1) ) + (block_size
- 1);
701 ldout(cct
, 20) << "fixup_range [" << inp_ofs
<< "," << inp_end
702 << "] => [" << bl_ofs
<< "," << bl_end
<< "]" << dendl
;
707 int RGWGetObj_BlockDecrypt::handle_data(bufferlist
& bl
, off_t bl_ofs
, off_t bl_len
) {
709 ldout(cct
, 25) << "Decrypt " << bl_len
<< " bytes" << dendl
;
710 size_t part_ofs
= ofs
;
712 while (i
<parts_len
.size() && (part_ofs
>= parts_len
[i
])) {
713 part_ofs
-= parts_len
[i
];
716 bl
.copy(bl_ofs
, bl_len
, cache
);
717 off_t aligned_size
= cache
.length() & ~(block_size
- 1);
718 if (aligned_size
> 0) {
720 if (! crypt
->decrypt(cache
, 0, aligned_size
, data
, part_ofs
) ) {
721 return -ERR_INTERNAL_ERROR
;
723 off_t send_size
= aligned_size
- enc_begin_skip
;
724 if (ofs
+ enc_begin_skip
+ send_size
> end
+ 1) {
725 send_size
= end
+ 1 - ofs
- enc_begin_skip
;
727 res
= next
->handle_data(data
, enc_begin_skip
, send_size
);
730 cache
.splice(0, aligned_size
);
736 * flush remainder of data to output
738 int RGWGetObj_BlockDecrypt::flush() {
740 size_t part_ofs
= ofs
;
742 while (i
<parts_len
.size() && (part_ofs
> parts_len
[i
])) {
743 part_ofs
-= parts_len
[i
];
746 if (cache
.length() > 0) {
748 if (! crypt
->decrypt(cache
, 0, cache
.length(), data
, part_ofs
) ) {
749 return -ERR_INTERNAL_ERROR
;
751 off_t send_size
= cache
.length() - enc_begin_skip
;
752 if (ofs
+ enc_begin_skip
+ send_size
> end
+ 1) {
753 send_size
= end
+ 1 - ofs
- enc_begin_skip
;
755 res
= next
->handle_data(data
, enc_begin_skip
, send_size
);
762 RGWPutObj_BlockEncrypt::RGWPutObj_BlockEncrypt(CephContext
* cct
,
763 RGWPutObjDataProcessor
* next
,
764 std::unique_ptr
<BlockCrypt
> crypt
):
765 RGWPutObj_Filter(next
),
767 crypt(std::move(crypt
)),
771 block_size
= this->crypt
->get_block_size();
774 RGWPutObj_BlockEncrypt::~RGWPutObj_BlockEncrypt() {
777 int RGWPutObj_BlockEncrypt::handle_data(bufferlist
& bl
,
783 ldout(cct
, 25) << "Encrypt " << bl
.length() << " bytes" << dendl
;
787 res
= next
->handle_data(no_data
, in_ofs
, phandle
, pobj
, again
);
788 //if *again is not set to false, we will have endless loop
791 ldout(cct
, 20) << "*again==true" << dendl
;
797 off_t proc_size
= cache
.length() & ~(block_size
- 1);
798 if (bl
.length() == 0) {
799 proc_size
= cache
.length();
803 if (! crypt
->encrypt(cache
, 0, proc_size
, data
, ofs
) ) {
804 return -ERR_INTERNAL_ERROR
;
806 res
= next
->handle_data(data
, ofs
, phandle
, pobj
, again
);
808 cache
.splice(0, proc_size
);
813 if (bl
.length() == 0) {
814 /*replicate 0-sized handle_data*/
815 res
= next
->handle_data(bl
, ofs
, phandle
, pobj
, again
);
820 int RGWPutObj_BlockEncrypt::throttle_data(void *handle
,
821 const rgw_raw_obj
& obj
,
824 return next
->throttle_data(handle
, obj
, size
, need_to_wait
);
827 std::string
create_random_key_selector(CephContext
* const cct
) {
828 char random
[AES_256_KEYSIZE
];
829 if (get_random_bytes(&random
[0], sizeof(random
)) != 0) {
830 ldout(cct
, 0) << "ERROR: cannot get_random_bytes. " << dendl
;
831 for (char& v
:random
) v
=rand();
833 return std::string(random
, sizeof(random
));
836 static int get_barbican_url(CephContext
* const cct
,
839 url
= cct
->_conf
->rgw_barbican_url
;
841 ldout(cct
, 0) << "ERROR: conf rgw_barbican_url is not set" << dendl
;
845 if (url
.back() != '/') {
852 static int request_key_from_barbican(CephContext
*cct
,
853 boost::string_view key_id
,
854 boost::string_view key_selector
,
855 const std::string
& barbican_token
,
856 std::string
& actual_key
) {
857 std::string secret_url
;
859 res
= get_barbican_url(cct
, secret_url
);
863 secret_url
+= "v1/secrets/" + std::string(key_id
);
865 bufferlist secret_bl
;
866 RGWHTTPTransceiver
secret_req(cct
, &secret_bl
);
867 secret_req
.append_header("Accept", "application/octet-stream");
868 secret_req
.append_header("X-Auth-Token", barbican_token
);
870 res
= secret_req
.process("GET", secret_url
.c_str());
874 if (secret_req
.get_http_status() ==
875 RGWHTTPTransceiver::HTTP_STATUS_UNAUTHORIZED
) {
879 if (secret_req
.get_http_status() >=200 &&
880 secret_req
.get_http_status() < 300 &&
881 secret_bl
.length() == AES_256_KEYSIZE
) {
882 actual_key
.assign(secret_bl
.c_str(), secret_bl
.length());
883 memset(secret_bl
.c_str(), 0, secret_bl
.length());
890 static map
<string
,string
> get_str_map(const string
&str
) {
891 map
<string
,string
> m
;
892 get_str_map(str
, &m
, ";, \t");
896 static int get_actual_key_from_kms(CephContext
*cct
,
897 boost::string_view key_id
,
898 boost::string_view key_selector
,
899 std::string
& actual_key
)
902 ldout(cct
, 20) << "Getting KMS encryption key for key=" << key_id
<< dendl
;
903 static map
<string
,string
> str_map
= get_str_map(
904 cct
->_conf
->rgw_crypt_s3_kms_encryption_keys
);
906 map
<string
, string
>::iterator it
= str_map
.find(std::string(key_id
));
907 if (it
!= str_map
.end() ) {
908 std::string master_key
= from_base64((*it
).second
);
909 if (master_key
.length() == AES_256_KEYSIZE
) {
910 uint8_t _actual_key
[AES_256_KEYSIZE
];
911 if (AES_256_ECB_encrypt(cct
,
912 reinterpret_cast<const uint8_t*>(master_key
.c_str()), AES_256_KEYSIZE
,
913 reinterpret_cast<const uint8_t*>(key_selector
.data()),
914 _actual_key
, AES_256_KEYSIZE
)) {
915 actual_key
= std::string((char*)&_actual_key
[0], AES_256_KEYSIZE
);
919 memset(_actual_key
, 0, sizeof(_actual_key
));
921 ldout(cct
, 20) << "Wrong size for key=" << key_id
<< dendl
;
926 if (rgw::keystone::Service::get_keystone_barbican_token(cct
, token
) < 0) {
927 ldout(cct
, 5) << "Failed to retrieve token for barbican" << dendl
;
932 res
= request_key_from_barbican(cct
, key_id
, key_selector
, token
, actual_key
);
934 ldout(cct
, 5) << "Failed to retrieve secret from barbican:" << key_id
<< dendl
;
940 static inline void set_attr(map
<string
, bufferlist
>& attrs
,
942 boost::string_view value
)
945 bl
.append(value
.data(), value
.size());
946 attrs
[key
] = std::move(bl
);
949 static inline std::string
get_str_attribute(map
<string
, bufferlist
>& attrs
,
952 auto iter
= attrs
.find(name
);
953 if (iter
== attrs
.end()) {
956 return iter
->second
.to_str();
960 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM
=0,
961 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY
,
962 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5
,
963 X_AMZ_SERVER_SIDE_ENCRYPTION
,
964 X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID
,
965 X_AMZ_SERVER_SIDE_ENCRYPTION_LAST
969 const char* http_header_name
;
970 const std::string post_part_name
;
971 } crypt_option_names
;
973 static const crypt_option_names crypt_options
[] = {
974 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", "x-amz-server-side-encryption-customer-algorithm"},
975 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", "x-amz-server-side-encryption-customer-key"},
976 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "x-amz-server-side-encryption-customer-key-md5"},
977 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION", "x-amz-server-side-encryption"},
978 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID", "x-amz-server-side-encryption-aws-kms-key-id"},
981 static boost::string_view
get_crypt_attribute(
983 std::map
<std::string
,
984 RGWPostObj_ObjStore::post_form_part
,
985 const ltstr_nocase
>* parts
,
986 crypt_option_e option
)
989 X_AMZ_SERVER_SIDE_ENCRYPTION_LAST
== sizeof(crypt_options
)/sizeof(*crypt_options
),
990 "Missing items in crypt_options");
991 if (parts
!= nullptr) {
993 = parts
->find(crypt_options
[option
].post_part_name
);
994 if (iter
== parts
->end())
995 return boost::string_view();
996 bufferlist
& data
= iter
->second
.data
;
997 boost::string_view str
= boost::string_view(data
.c_str(), data
.length());
998 return rgw_trim_whitespace(str
);
1000 const char* hdr
= env
->get(crypt_options
[option
].http_header_name
, nullptr);
1001 if (hdr
!= nullptr) {
1002 return boost::string_view(hdr
);
1004 return boost::string_view();
1010 int rgw_s3_prepare_encrypt(struct req_state
* s
,
1011 std::map
<std::string
, ceph::bufferlist
>& attrs
,
1012 std::map
<std::string
,
1013 RGWPostObj_ObjStore::post_form_part
,
1014 const ltstr_nocase
>* parts
,
1015 std::unique_ptr
<BlockCrypt
>* block_crypt
,
1016 std::map
<std::string
, std::string
>& crypt_http_responses
)
1019 crypt_http_responses
.clear();
1021 boost::string_view req_sse_ca
=
1022 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM
);
1023 if (! req_sse_ca
.empty()) {
1024 if (req_sse_ca
!= "AES256") {
1025 ldout(s
->cct
, 5) << "ERROR: Invalid value for header "
1026 << "x-amz-server-side-encryption-customer-algorithm"
1028 return -ERR_INVALID_REQUEST
;
1030 if (s
->cct
->_conf
->rgw_crypt_require_ssl
&&
1031 !s
->info
.env
->exists("SERVER_PORT_SECURE")) {
1032 ldout(s
->cct
, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl
;
1033 return -ERR_INVALID_REQUEST
;
1035 std::string key_bin
= from_base64(
1036 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY
) );
1037 if (key_bin
.size() != AES_256_CBC::AES_256_KEYSIZE
) {
1038 ldout(s
->cct
, 5) << "ERROR: invalid encryption key size" << dendl
;
1039 return -ERR_INVALID_REQUEST
;
1041 boost::string_view keymd5
=
1042 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5
);
1043 std::string keymd5_bin
= from_base64(keymd5
);
1044 if (keymd5_bin
.size() != CEPH_CRYPTO_MD5_DIGESTSIZE
) {
1045 ldout(s
->cct
, 5) << "ERROR: Invalid key md5 size" << dendl
;
1046 return -ERR_INVALID_DIGEST
;
1049 byte key_hash_res
[CEPH_CRYPTO_MD5_DIGESTSIZE
];
1050 key_hash
.Update(reinterpret_cast<const byte
*>(key_bin
.c_str()), key_bin
.size());
1051 key_hash
.Final(key_hash_res
);
1053 if (memcmp(key_hash_res
, keymd5_bin
.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE
) != 0) {
1054 ldout(s
->cct
, 5) << "ERROR: Invalid key md5 hash" << dendl
;
1055 return -ERR_INVALID_DIGEST
;
1058 set_attr(attrs
, RGW_ATTR_CRYPT_MODE
, "SSE-C-AES256");
1059 set_attr(attrs
, RGW_ATTR_CRYPT_KEYMD5
, keymd5_bin
);
1062 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1063 aes
->set_key(reinterpret_cast<const uint8_t*>(key_bin
.c_str()), AES_256_KEYSIZE
);
1064 *block_crypt
= std::move(aes
);
1067 crypt_http_responses
["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
1068 crypt_http_responses
["x-amz-server-side-encryption-customer-key-MD5"] = keymd5
.to_string();
1071 /* AMAZON server side encryption with KMS (key management service) */
1072 boost::string_view req_sse
=
1073 get_crypt_attribute(s
->info
.env
, parts
, X_AMZ_SERVER_SIDE_ENCRYPTION
);
1074 if (! req_sse
.empty()) {
1075 if (req_sse
!= "aws:kms") {
1076 ldout(s
->cct
, 5) << "ERROR: Invalid value for header x-amz-server-side-encryption"
1078 return -ERR_INVALID_REQUEST
;
1080 if (s
->cct
->_conf
->rgw_crypt_require_ssl
&&
1081 !s
->info
.env
->exists("SERVER_PORT_SECURE")) {
1082 ldout(s
->cct
, 5) << "ERROR: insecure request, rgw_crypt_require_ssl is set" << dendl
;
1083 return -ERR_INVALID_REQUEST
;
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 return -ERR_INVALID_ACCESS_KEY
;
1090 /* try to retrieve actual key */
1091 std::string key_selector
= create_random_key_selector(s
->cct
);
1092 std::string actual_key
;
1093 res
= get_actual_key_from_kms(s
->cct
, key_id
, key_selector
, actual_key
);
1096 if (actual_key
.size() != AES_256_KEYSIZE
) {
1097 ldout(s
->cct
, 5) << "ERROR: key obtained from key_id:" <<
1098 key_id
<< " is not 256 bit size" << dendl
;
1099 return -ERR_INVALID_ACCESS_KEY
;
1101 set_attr(attrs
, RGW_ATTR_CRYPT_MODE
, "SSE-KMS");
1102 set_attr(attrs
, RGW_ATTR_CRYPT_KEYID
, key_id
);
1103 set_attr(attrs
, RGW_ATTR_CRYPT_KEYSEL
, key_selector
);
1106 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1107 aes
->set_key(reinterpret_cast<const uint8_t*>(actual_key
.c_str()), AES_256_KEYSIZE
);
1108 *block_crypt
= std::move(aes
);
1110 actual_key
.replace(0, actual_key
.length(), actual_key
.length(), '\000');
1114 /* no other encryption mode, check if default encryption is selected */
1115 if (s
->cct
->_conf
->rgw_crypt_default_encryption_key
!= "") {
1116 std::string master_encryption_key
=
1117 from_base64(s
->cct
->_conf
->rgw_crypt_default_encryption_key
);
1118 if (master_encryption_key
.size() != 256 / 8) {
1119 ldout(s
->cct
, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl
;
1120 /* not an error to return; missing encryption does not inhibit processing */
1124 set_attr(attrs
, RGW_ATTR_CRYPT_MODE
, "RGW-AUTO");
1125 std::string key_selector
= create_random_key_selector(s
->cct
);
1126 set_attr(attrs
, RGW_ATTR_CRYPT_KEYSEL
, key_selector
);
1128 uint8_t actual_key
[AES_256_KEYSIZE
];
1129 if (AES_256_ECB_encrypt(s
->cct
,
1130 reinterpret_cast<const uint8_t*>(master_encryption_key
.c_str()), AES_256_KEYSIZE
,
1131 reinterpret_cast<const uint8_t*>(key_selector
.c_str()),
1132 actual_key
, AES_256_KEYSIZE
) != true) {
1133 memset(actual_key
, 0, sizeof(actual_key
));
1137 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1138 aes
->set_key(reinterpret_cast<const uint8_t*>(actual_key
), AES_256_KEYSIZE
);
1139 *block_crypt
= std::move(aes
);
1141 memset(actual_key
, 0, sizeof(actual_key
));
1150 int rgw_s3_prepare_decrypt(struct req_state
* s
,
1151 map
<string
, bufferlist
>& attrs
,
1152 std::unique_ptr
<BlockCrypt
>* block_crypt
,
1153 std::map
<std::string
, std::string
>& crypt_http_responses
)
1156 std::string stored_mode
= get_str_attribute(attrs
, RGW_ATTR_CRYPT_MODE
);
1157 ldout(s
->cct
, 15) << "Encryption mode: " << stored_mode
<< dendl
;
1158 if (stored_mode
== "SSE-C-AES256") {
1159 if (s
->cct
->_conf
->rgw_crypt_require_ssl
&&
1160 !s
->info
.env
->exists("SERVER_PORT_SECURE")) {
1161 ldout(s
->cct
, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl
;
1162 return -ERR_INVALID_REQUEST
;
1164 const char *req_cust_alg
=
1165 s
->info
.env
->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", NULL
);
1167 if ((nullptr == req_cust_alg
) || (strcmp(req_cust_alg
, "AES256") != 0)) {
1168 ldout(s
->cct
, 5) << "ERROR: Invalid value for header "
1169 << "x-amz-server-side-encryption-customer-algorithm"
1171 return -ERR_INVALID_REQUEST
;
1174 std::string key_bin
=
1175 from_base64(s
->info
.env
->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", ""));
1176 if (key_bin
.size() != AES_256_CBC::AES_256_KEYSIZE
) {
1177 ldout(s
->cct
, 5) << "ERROR: Invalid encryption key size" << dendl
;
1178 return -ERR_INVALID_REQUEST
;
1181 std::string keymd5
=
1182 s
->info
.env
->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "");
1183 std::string keymd5_bin
= from_base64(keymd5
);
1184 if (keymd5_bin
.size() != CEPH_CRYPTO_MD5_DIGESTSIZE
) {
1185 ldout(s
->cct
, 5) << "ERROR: Invalid key md5 size " << dendl
;
1186 return -ERR_INVALID_DIGEST
;
1190 uint8_t key_hash_res
[CEPH_CRYPTO_MD5_DIGESTSIZE
];
1191 key_hash
.Update(reinterpret_cast<const byte
*>(key_bin
.c_str()), key_bin
.size());
1192 key_hash
.Final(key_hash_res
);
1194 if ((memcmp(key_hash_res
, keymd5_bin
.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE
) != 0) ||
1195 (get_str_attribute(attrs
, RGW_ATTR_CRYPT_KEYMD5
) != keymd5_bin
)) {
1196 return -ERR_INVALID_DIGEST
;
1198 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1199 aes
->set_key(reinterpret_cast<const uint8_t*>(key_bin
.c_str()), AES_256_CBC::AES_256_KEYSIZE
);
1200 if (block_crypt
) *block_crypt
= std::move(aes
);
1202 crypt_http_responses
["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
1203 crypt_http_responses
["x-amz-server-side-encryption-customer-key-MD5"] = keymd5
;
1207 if (stored_mode
== "SSE-KMS") {
1208 if (s
->cct
->_conf
->rgw_crypt_require_ssl
&&
1209 !s
->info
.env
->exists("SERVER_PORT_SECURE")) {
1210 ldout(s
->cct
, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl
;
1211 return -ERR_INVALID_REQUEST
;
1213 /* try to retrieve actual key */
1214 std::string key_id
= get_str_attribute(attrs
, RGW_ATTR_CRYPT_KEYID
);
1215 std::string key_selector
= get_str_attribute(attrs
, RGW_ATTR_CRYPT_KEYSEL
);
1216 std::string actual_key
;
1217 res
= get_actual_key_from_kms(s
->cct
, key_id
, key_selector
, actual_key
);
1219 ldout(s
->cct
, 10) << "No encryption key for key-id=" << key_id
<< dendl
;
1222 if (actual_key
.size() != AES_256_KEYSIZE
) {
1223 ldout(s
->cct
, 0) << "ERROR: key obtained from key_id:" <<
1224 key_id
<< " is not 256 bit size" << dendl
;
1225 return -ERR_INVALID_ACCESS_KEY
;
1228 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1229 aes
->set_key(reinterpret_cast<const uint8_t*>(actual_key
.c_str()), AES_256_KEYSIZE
);
1230 actual_key
.replace(0, actual_key
.length(), actual_key
.length(), '\000');
1231 if (block_crypt
) *block_crypt
= std::move(aes
);
1233 crypt_http_responses
["x-amz-server-side-encryption"] = "aws:kms";
1234 crypt_http_responses
["x-amz-server-side-encryption-aws-kms-key-id"] = key_id
;
1238 if (stored_mode
== "RGW-AUTO") {
1239 std::string master_encryption_key
=
1240 from_base64(std::string(s
->cct
->_conf
->rgw_crypt_default_encryption_key
));
1241 if (master_encryption_key
.size() != 256 / 8) {
1242 ldout(s
->cct
, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl
;
1245 std::string attr_key_selector
= get_str_attribute(attrs
, RGW_ATTR_CRYPT_KEYSEL
);
1246 if (attr_key_selector
.size() != AES_256_CBC::AES_256_KEYSIZE
) {
1247 ldout(s
->cct
, 0) << "ERROR: missing or invalid " RGW_ATTR_CRYPT_KEYSEL
<< dendl
;
1250 uint8_t actual_key
[AES_256_KEYSIZE
];
1251 if (AES_256_ECB_encrypt(s
->cct
,
1252 reinterpret_cast<const uint8_t*>(master_encryption_key
.c_str()),
1254 reinterpret_cast<const uint8_t*>(attr_key_selector
.c_str()),
1255 actual_key
, AES_256_KEYSIZE
) != true) {
1256 memset(actual_key
, 0, sizeof(actual_key
));
1259 auto aes
= std::unique_ptr
<AES_256_CBC
>(new AES_256_CBC(s
->cct
));
1260 aes
->set_key(actual_key
, AES_256_KEYSIZE
);
1261 memset(actual_key
, 0, sizeof(actual_key
));
1262 if (block_crypt
) *block_crypt
= std::move(aes
);