1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab ft=cpp
/**
* Crypto filters for Put/Post/Get operations.
*/
#ifndef CEPH_RGW_CRYPT_H
#define CEPH_RGW_CRYPT_H
#include <string_view>
#include <rgw/rgw_op.h>
#include <rgw/rgw_rest.h>
#include <rgw/rgw_rest_s3.h>
#include "rgw_putobj.h"
/**
* \brief Interface for block encryption methods
*
* Encrypts and decrypts data.
* Operations are performed in context of larger stream being divided into blocks.
* Each block can be processed independently, but only as a whole.
* Part block cannot be properly processed.
* Each request must start on block-aligned offset.
* Each request should have length that is multiply of block size.
* Request with unaligned length is only acceptable for last part of stream.
*/
class BlockCrypt {
public:
BlockCrypt(){};
virtual ~BlockCrypt(){};
/**
* Determines size of encryption block.
* This is usually multiply of key size.
* It determines size of chunks that should be passed to \ref encrypt and \ref decrypt.
*/
virtual size_t get_block_size() = 0;
/**
* Encrypts data.
* Argument \ref stream_offset shows where in generalized stream chunk is located.
* Input for encryption is \ref input buffer, with relevant data in range <in_ofs, in_ofs+size).
* \ref input and \output may not be the same buffer.
*
* \params
* input - source buffer of data
* in_ofs - offset of chunk inside input
* size - size of chunk, must be chunk-aligned unless last part is processed
* output - destination buffer to encrypt to
* stream_offset - location of <in_ofs,in_ofs+size) chunk in data stream, must be chunk-aligned
* \return true iff successfully encrypted
*/
virtual bool encrypt(bufferlist& input,
off_t in_ofs,
size_t size,
bufferlist& output,
off_t stream_offset) = 0;
/**
* Decrypts data.
* Argument \ref stream_offset shows where in generalized stream chunk is located.
* Input for decryption is \ref input buffer, with relevant data in range <in_ofs, in_ofs+size).
* \ref input and \output may not be the same buffer.
*
* \params
* input - source buffer of data
* in_ofs - offset of chunk inside input
* size - size of chunk, must be chunk-aligned unless last part is processed
* output - destination buffer to encrypt to
* stream_offset - location of <in_ofs,in_ofs+size) chunk in data stream, must be chunk-aligned
* \return true iff successfully encrypted
*/
virtual bool decrypt(bufferlist& input,
off_t in_ofs,
size_t size,
bufferlist& output,
off_t stream_offset) = 0;
};
static const size_t AES_256_KEYSIZE = 256 / 8;
bool AES_256_ECB_encrypt(CephContext* cct,
const uint8_t* key,
size_t key_size,
const uint8_t* data_in,
uint8_t* data_out,
size_t data_size);
class RGWGetObj_BlockDecrypt : public RGWGetObj_Filter {
CephContext* cct;
std::unique_ptr<BlockCrypt> crypt; /**< already configured stateless BlockCrypt
for operations when enough data is accumulated */
off_t enc_begin_skip; /**< amount of data to skip from beginning of received data */
off_t ofs; /**< stream offset of data we expect to show up next through \ref handle_data */
off_t end; /**< stream offset of last byte that is requested */
bufferlist cache; /**< stores extra data that could not (yet) be processed by BlockCrypt */
size_t block_size; /**< snapshot of \ref BlockCrypt.get_block_size() */
int process(bufferlist& cipher, size_t part_ofs, size_t size);
protected:
std::vector<size_t> parts_len; /**< size of parts of multipart object, parsed from manifest */
public:
RGWGetObj_BlockDecrypt(CephContext* cct,
RGWGetObj_Filter* next,
std::unique_ptr<BlockCrypt> crypt);
virtual ~RGWGetObj_BlockDecrypt();
virtual int fixup_range(off_t& bl_ofs,
off_t& bl_end) override;
virtual int handle_data(bufferlist& bl,
off_t bl_ofs,
off_t bl_len) override;
virtual int flush() override;
int read_manifest(const DoutPrefixProvider *dpp, bufferlist& manifest_bl);
}; /* RGWGetObj_BlockDecrypt */
class RGWPutObj_BlockEncrypt : public rgw::putobj::Pipe
{
CephContext* cct;
std::unique_ptr<BlockCrypt> crypt; /**< already configured stateless BlockCrypt
for operations when enough data is accumulated */
bufferlist cache; /**< stores extra data that could not (yet) be processed by BlockCrypt */
const size_t block_size; /**< snapshot of \ref BlockCrypt.get_block_size() */
public:
RGWPutObj_BlockEncrypt(CephContext* cct,
rgw::putobj::DataProcessor *next,
std::unique_ptr<BlockCrypt> crypt);
int process(bufferlist&& data, uint64_t logical_offset) override;
}; /* RGWPutObj_BlockEncrypt */
int rgw_s3_prepare_encrypt(struct req_state* s,
std::map<std::string, ceph::bufferlist>& attrs,
std::map<std::string,
RGWPostObj_ObjStore::post_form_part,
const ltstr_nocase>* parts,
std::unique_ptr<BlockCrypt>* block_crypt,
std::map<std::string,
std::string>& crypt_http_responses);
int rgw_s3_prepare_decrypt(struct req_state* s,
std::map<std::string, ceph::bufferlist>& attrs,
std::unique_ptr<BlockCrypt>* block_crypt,
std::map<std::string,
std::string>& crypt_http_responses);
static inline void set_attr(map<string, bufferlist>& attrs,
const char* key,
std::string_view value)
{
bufferlist bl;
bl.append(value.data(), value.size());
attrs[key] = std::move(bl);
}
static inline std::string get_str_attribute(map<string, bufferlist>& attrs,
const char *name)
{
auto iter = attrs.find(name);
if (iter == attrs.end()) {
return {};
}
return iter->second.to_str();
}
#endif
|