]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2016 Mirantis <akupczyk@mirantis.com> | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | #include <iostream> | |
15 | #include "global/global_init.h" | |
16 | #include "common/ceph_argparse.h" | |
17 | #include "rgw/rgw_common.h" | |
18 | #include "rgw/rgw_rados.h" | |
19 | #include "rgw/rgw_crypt.h" | |
20 | #include <gtest/gtest.h> | |
11fdf7f2 | 21 | #include "include/ceph_assert.h" |
7c673cae FG |
22 | #define dout_subsys ceph_subsys_rgw |
23 | ||
24 | using namespace std; | |
25 | ||
26 | ||
20effc67 | 27 | std::unique_ptr<BlockCrypt> AES_256_CBC_create(const DoutPrefixProvider *dpp, CephContext* cct, const uint8_t* key, size_t len); |
7c673cae | 28 | |
11fdf7f2 | 29 | class ut_get_sink : public RGWGetObj_Filter { |
7c673cae FG |
30 | std::stringstream sink; |
31 | public: | |
32 | ut_get_sink() {} | |
33 | virtual ~ut_get_sink() {} | |
34 | ||
35 | int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) override | |
36 | { | |
f67539c2 | 37 | sink << std::string_view(bl.c_str()+bl_ofs, bl_len); |
7c673cae FG |
38 | return 0; |
39 | } | |
40 | std::string get_sink() | |
41 | { | |
42 | return sink.str(); | |
43 | } | |
44 | }; | |
45 | ||
20effc67 | 46 | class ut_put_sink: public rgw::sal::DataProcessor |
7c673cae FG |
47 | { |
48 | std::stringstream sink; | |
49 | public: | |
11fdf7f2 | 50 | int process(bufferlist&& bl, uint64_t ofs) override |
7c673cae | 51 | { |
f67539c2 | 52 | sink << std::string_view(bl.c_str(),bl.length()); |
7c673cae FG |
53 | return 0; |
54 | } | |
55 | std::string get_sink() | |
56 | { | |
57 | return sink.str(); | |
58 | } | |
59 | }; | |
60 | ||
61 | ||
62 | class BlockCryptNone: public BlockCrypt { | |
a8e16298 | 63 | size_t block_size = 256; |
7c673cae FG |
64 | public: |
65 | BlockCryptNone(){}; | |
a8e16298 | 66 | BlockCryptNone(size_t sz) : block_size(sz) {} |
7c673cae FG |
67 | virtual ~BlockCryptNone(){}; |
68 | size_t get_block_size() override | |
69 | { | |
a8e16298 | 70 | return block_size; |
7c673cae FG |
71 | } |
72 | bool encrypt(bufferlist& input, | |
73 | off_t in_ofs, | |
74 | size_t size, | |
75 | bufferlist& output, | |
76 | off_t stream_offset) override | |
77 | { | |
78 | output.clear(); | |
79 | output.append(input.c_str(), input.length()); | |
80 | return true; | |
81 | } | |
82 | bool decrypt(bufferlist& input, | |
83 | off_t in_ofs, | |
84 | size_t size, | |
85 | bufferlist& output, | |
86 | off_t stream_offset) override | |
87 | { | |
88 | output.clear(); | |
89 | output.append(input.c_str(), input.length()); | |
90 | return true; | |
91 | } | |
92 | }; | |
93 | ||
7c673cae FG |
94 | TEST(TestRGWCrypto, verify_AES_256_CBC_identity) |
95 | { | |
20effc67 | 96 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
7c673cae FG |
97 | //create some input for encryption |
98 | const off_t test_range = 1024*1024; | |
99 | buffer::ptr buf(test_range); | |
100 | char* p = buf.c_str(); | |
101 | for(size_t i = 0; i < buf.length(); i++) | |
102 | p[i] = i + i*i + (i >> 2); | |
103 | ||
104 | bufferlist input; | |
105 | input.append(buf); | |
106 | ||
107 | for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17}) | |
108 | { | |
109 | //make some random key | |
110 | uint8_t key[32]; | |
111 | for(size_t i=0;i<sizeof(key);i++) | |
112 | key[i]=i*step; | |
113 | ||
20effc67 | 114 | auto aes(AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32)); |
7c673cae FG |
115 | ASSERT_NE(aes.get(), nullptr); |
116 | ||
117 | size_t block_size = aes->get_block_size(); | |
118 | ASSERT_NE(block_size, 0u); | |
119 | ||
120 | for (size_t r = 97; r < 123 ; r++) | |
121 | { | |
122 | off_t begin = (r*r*r*r*r % test_range); | |
123 | begin = begin - begin % block_size; | |
124 | off_t end = begin + r*r*r*r*r*r*r % (test_range - begin); | |
125 | if (r % 3) | |
126 | end = end - end % block_size; | |
127 | off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000); | |
128 | offset = offset - offset % block_size; | |
129 | ||
130 | ASSERT_EQ(begin % block_size, 0u); | |
131 | ASSERT_LE(end, test_range); | |
132 | ASSERT_EQ(offset % block_size, 0u); | |
133 | ||
134 | bufferlist encrypted; | |
135 | ASSERT_TRUE(aes->encrypt(input, begin, end - begin, encrypted, offset)); | |
136 | bufferlist decrypted; | |
137 | ASSERT_TRUE(aes->decrypt(encrypted, 0, end - begin, decrypted, offset)); | |
138 | ||
139 | ASSERT_EQ(decrypted.length(), end - begin); | |
f67539c2 TL |
140 | ASSERT_EQ(std::string_view(input.c_str() + begin, end - begin), |
141 | std::string_view(decrypted.c_str(), end - begin) ); | |
7c673cae FG |
142 | } |
143 | } | |
144 | } | |
145 | ||
146 | ||
147 | TEST(TestRGWCrypto, verify_AES_256_CBC_identity_2) | |
148 | { | |
20effc67 | 149 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
7c673cae FG |
150 | //create some input for encryption |
151 | const off_t test_range = 1024*1024; | |
152 | buffer::ptr buf(test_range); | |
153 | char* p = buf.c_str(); | |
154 | for(size_t i = 0; i < buf.length(); i++) | |
155 | p[i] = i + i*i + (i >> 2); | |
156 | ||
157 | bufferlist input; | |
158 | input.append(buf); | |
159 | ||
160 | for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17}) | |
161 | { | |
162 | //make some random key | |
163 | uint8_t key[32]; | |
164 | for(size_t i=0;i<sizeof(key);i++) | |
165 | key[i]=i*step; | |
166 | ||
20effc67 | 167 | auto aes(AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32)); |
7c673cae FG |
168 | ASSERT_NE(aes.get(), nullptr); |
169 | ||
170 | size_t block_size = aes->get_block_size(); | |
171 | ASSERT_NE(block_size, 0u); | |
172 | ||
173 | for (off_t end = 1; end < 6096 ; end+=3) | |
174 | { | |
175 | off_t begin = 0; | |
176 | off_t offset = end*end*end*end*end % (1000*1000*1000); | |
177 | offset = offset - offset % block_size; | |
178 | ||
179 | ASSERT_EQ(begin % block_size, 0u); | |
180 | ASSERT_LE(end, test_range); | |
181 | ASSERT_EQ(offset % block_size, 0u); | |
182 | ||
183 | bufferlist encrypted; | |
184 | ASSERT_TRUE(aes->encrypt(input, begin, end, encrypted, offset)); | |
185 | bufferlist decrypted; | |
186 | ASSERT_TRUE(aes->decrypt(encrypted, 0, end, decrypted, offset)); | |
187 | ||
188 | ASSERT_EQ(decrypted.length(), end); | |
f67539c2 TL |
189 | ASSERT_EQ(std::string_view(input.c_str(), end), |
190 | std::string_view(decrypted.c_str(), end) ); | |
7c673cae FG |
191 | } |
192 | } | |
193 | } | |
194 | ||
195 | ||
196 | TEST(TestRGWCrypto, verify_AES_256_CBC_identity_3) | |
197 | { | |
20effc67 | 198 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
7c673cae FG |
199 | //create some input for encryption |
200 | const off_t test_range = 1024*1024; | |
201 | buffer::ptr buf(test_range); | |
202 | char* p = buf.c_str(); | |
203 | for(size_t i = 0; i < buf.length(); i++) | |
204 | p[i] = i + i*i + (i >> 2); | |
205 | ||
206 | bufferlist input; | |
207 | input.append(buf); | |
208 | ||
209 | for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17}) | |
210 | { | |
211 | //make some random key | |
212 | uint8_t key[32]; | |
213 | for(size_t i=0;i<sizeof(key);i++) | |
214 | key[i]=i*step; | |
215 | ||
20effc67 | 216 | auto aes(AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32)); |
7c673cae FG |
217 | ASSERT_NE(aes.get(), nullptr); |
218 | ||
219 | size_t block_size = aes->get_block_size(); | |
220 | ASSERT_NE(block_size, 0u); | |
221 | size_t rr = 111; | |
222 | for (size_t r = 97; r < 123 ; r++) | |
223 | { | |
224 | off_t begin = 0; | |
225 | off_t end = begin + r*r*r*r*r*r*r % (test_range - begin); | |
226 | //sometimes make aligned | |
227 | if (r % 3) | |
228 | end = end - end % block_size; | |
229 | off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000); | |
230 | offset = offset - offset % block_size; | |
231 | ||
232 | ASSERT_EQ(begin % block_size, 0u); | |
233 | ASSERT_LE(end, test_range); | |
234 | ASSERT_EQ(offset % block_size, 0u); | |
235 | ||
236 | bufferlist encrypted1; | |
237 | bufferlist encrypted2; | |
238 | ||
239 | off_t pos = begin; | |
240 | off_t chunk; | |
241 | while (pos < end) { | |
242 | chunk = block_size + (rr/3)*(rr+17)*(rr+71)*(rr+123)*(rr+131) % 50000; | |
243 | chunk = chunk - chunk % block_size; | |
244 | if (pos + chunk > end) | |
245 | chunk = end - pos; | |
246 | bufferlist tmp; | |
247 | ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos)); | |
248 | encrypted1.append(tmp); | |
249 | pos += chunk; | |
250 | rr++; | |
251 | } | |
252 | ||
253 | pos = begin; | |
254 | while (pos < end) { | |
255 | chunk = block_size + (rr/3)*(rr+97)*(rr+151)*(rr+213)*(rr+251) % 50000; | |
256 | chunk = chunk - chunk % block_size; | |
257 | if (pos + chunk > end) | |
258 | chunk = end - pos; | |
259 | bufferlist tmp; | |
260 | ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos)); | |
261 | encrypted2.append(tmp); | |
262 | pos += chunk; | |
263 | rr++; | |
264 | } | |
265 | ASSERT_EQ(encrypted1.length(), end); | |
266 | ASSERT_EQ(encrypted2.length(), end); | |
f67539c2 TL |
267 | ASSERT_EQ(std::string_view(encrypted1.c_str(), end), |
268 | std::string_view(encrypted2.c_str(), end) ); | |
7c673cae FG |
269 | } |
270 | } | |
271 | } | |
272 | ||
273 | ||
274 | TEST(TestRGWCrypto, verify_AES_256_CBC_size_0_15) | |
275 | { | |
20effc67 | 276 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
7c673cae FG |
277 | //create some input for encryption |
278 | const off_t test_range = 1024*1024; | |
279 | buffer::ptr buf(test_range); | |
280 | char* p = buf.c_str(); | |
281 | for(size_t i = 0; i < buf.length(); i++) | |
282 | p[i] = i + i*i + (i >> 2); | |
283 | ||
284 | bufferlist input; | |
285 | input.append(buf); | |
286 | ||
287 | for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17}) | |
288 | { | |
289 | //make some random key | |
290 | uint8_t key[32]; | |
291 | for(size_t i=0;i<sizeof(key);i++) | |
292 | key[i]=i*step; | |
293 | ||
20effc67 | 294 | auto aes(AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32)); |
7c673cae FG |
295 | ASSERT_NE(aes.get(), nullptr); |
296 | ||
297 | size_t block_size = aes->get_block_size(); | |
298 | ASSERT_NE(block_size, 0u); | |
299 | for (size_t r = 97; r < 123 ; r++) | |
300 | { | |
301 | off_t begin = 0; | |
302 | off_t end = begin + r*r*r*r*r*r*r % (16); | |
303 | ||
304 | off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000); | |
305 | offset = offset - offset % block_size; | |
306 | ||
307 | ASSERT_EQ(begin % block_size, 0u); | |
308 | ASSERT_LE(end, test_range); | |
309 | ASSERT_EQ(offset % block_size, 0u); | |
310 | ||
311 | bufferlist encrypted; | |
312 | bufferlist decrypted; | |
313 | ASSERT_TRUE(aes->encrypt(input, 0, end, encrypted, offset)); | |
314 | ASSERT_TRUE(aes->encrypt(encrypted, 0, end, decrypted, offset)); | |
315 | ASSERT_EQ(encrypted.length(), end); | |
316 | ASSERT_EQ(decrypted.length(), end); | |
f67539c2 TL |
317 | ASSERT_EQ(std::string_view(input.c_str(), end), |
318 | std::string_view(decrypted.c_str(), end) ); | |
7c673cae FG |
319 | } |
320 | } | |
321 | } | |
322 | ||
323 | ||
324 | TEST(TestRGWCrypto, verify_AES_256_CBC_identity_last_block) | |
325 | { | |
20effc67 | 326 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
7c673cae FG |
327 | //create some input for encryption |
328 | const off_t test_range = 1024*1024; | |
329 | buffer::ptr buf(test_range); | |
330 | char* p = buf.c_str(); | |
331 | for(size_t i = 0; i < buf.length(); i++) | |
332 | p[i] = i + i*i + (i >> 2); | |
333 | ||
334 | bufferlist input; | |
335 | input.append(buf); | |
336 | ||
337 | for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17}) | |
338 | { | |
339 | //make some random key | |
340 | uint8_t key[32]; | |
341 | for(size_t i=0;i<sizeof(key);i++) | |
342 | key[i]=i*step; | |
343 | ||
20effc67 | 344 | auto aes(AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32)); |
7c673cae FG |
345 | ASSERT_NE(aes.get(), nullptr); |
346 | ||
347 | size_t block_size = aes->get_block_size(); | |
348 | ASSERT_NE(block_size, 0u); | |
349 | size_t rr = 111; | |
350 | for (size_t r = 97; r < 123 ; r++) | |
351 | { | |
352 | off_t begin = 0; | |
353 | off_t end = r*r*r*r*r*r*r % (test_range - 16); | |
354 | end = end - end % block_size; | |
355 | end = end + (r+3)*(r+5)*(r+7) % 16; | |
356 | ||
357 | off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000); | |
358 | offset = offset - offset % block_size; | |
359 | ||
360 | ASSERT_EQ(begin % block_size, 0u); | |
361 | ASSERT_LE(end, test_range); | |
362 | ASSERT_EQ(offset % block_size, 0u); | |
363 | ||
364 | bufferlist encrypted1; | |
365 | bufferlist encrypted2; | |
366 | ||
367 | off_t pos = begin; | |
368 | off_t chunk; | |
369 | while (pos < end) { | |
370 | chunk = block_size + (rr/3)*(rr+17)*(rr+71)*(rr+123)*(rr+131) % 50000; | |
371 | chunk = chunk - chunk % block_size; | |
372 | if (pos + chunk > end) | |
373 | chunk = end - pos; | |
374 | bufferlist tmp; | |
375 | ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos)); | |
376 | encrypted1.append(tmp); | |
377 | pos += chunk; | |
378 | rr++; | |
379 | } | |
380 | pos = begin; | |
381 | while (pos < end) { | |
382 | chunk = block_size + (rr/3)*(rr+97)*(rr+151)*(rr+213)*(rr+251) % 50000; | |
383 | chunk = chunk - chunk % block_size; | |
384 | if (pos + chunk > end) | |
385 | chunk = end - pos; | |
386 | bufferlist tmp; | |
387 | ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos)); | |
388 | encrypted2.append(tmp); | |
389 | pos += chunk; | |
390 | rr++; | |
391 | } | |
392 | ASSERT_EQ(encrypted1.length(), end); | |
393 | ASSERT_EQ(encrypted2.length(), end); | |
f67539c2 TL |
394 | ASSERT_EQ(std::string_view(encrypted1.c_str(), end), |
395 | std::string_view(encrypted2.c_str(), end) ); | |
7c673cae FG |
396 | } |
397 | } | |
398 | } | |
399 | ||
400 | ||
401 | TEST(TestRGWCrypto, verify_RGWGetObj_BlockDecrypt_ranges) | |
402 | { | |
20effc67 | 403 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
7c673cae FG |
404 | //create some input for encryption |
405 | const off_t test_range = 1024*1024; | |
406 | bufferptr buf(test_range); | |
407 | char* p = buf.c_str(); | |
408 | for(size_t i = 0; i < buf.length(); i++) | |
409 | p[i] = i + i*i + (i >> 2); | |
410 | ||
411 | bufferlist input; | |
412 | input.append(buf); | |
413 | ||
414 | uint8_t key[32]; | |
415 | for(size_t i=0;i<sizeof(key);i++) | |
416 | key[i] = i; | |
417 | ||
20effc67 | 418 | auto cbc = AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32); |
7c673cae FG |
419 | ASSERT_NE(cbc.get(), nullptr); |
420 | bufferlist encrypted; | |
421 | ASSERT_TRUE(cbc->encrypt(input, 0, test_range, encrypted, 0)); | |
422 | ||
423 | ||
424 | for (off_t r = 93; r < 150; r++ ) | |
425 | { | |
426 | ut_get_sink get_sink; | |
20effc67 | 427 | auto cbc = AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32); |
7c673cae | 428 | ASSERT_NE(cbc.get(), nullptr); |
20effc67 | 429 | RGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink, std::move(cbc)); |
7c673cae FG |
430 | |
431 | //random ranges | |
432 | off_t begin = (r/3)*r*(r+13)*(r+23)*(r+53)*(r+71) % test_range; | |
433 | off_t end = begin + (r/5)*(r+7)*(r+13)*(r+101)*(r*103) % (test_range - begin) - 1; | |
434 | ||
435 | off_t f_begin = begin; | |
436 | off_t f_end = end; | |
437 | decrypt.fixup_range(f_begin, f_end); | |
438 | decrypt.handle_data(encrypted, f_begin, f_end - f_begin + 1); | |
439 | decrypt.flush(); | |
440 | const std::string& decrypted = get_sink.get_sink(); | |
441 | size_t expected_len = end - begin + 1; | |
442 | ASSERT_EQ(decrypted.length(), expected_len); | |
f67539c2 | 443 | ASSERT_EQ(decrypted, std::string_view(input.c_str()+begin, expected_len)); |
7c673cae FG |
444 | } |
445 | } | |
446 | ||
447 | ||
448 | TEST(TestRGWCrypto, verify_RGWGetObj_BlockDecrypt_chunks) | |
449 | { | |
20effc67 | 450 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
7c673cae FG |
451 | //create some input for encryption |
452 | const off_t test_range = 1024*1024; | |
453 | bufferptr buf(test_range); | |
454 | char* p = buf.c_str(); | |
455 | for(size_t i = 0; i < buf.length(); i++) | |
456 | p[i] = i + i*i + (i >> 2); | |
457 | ||
458 | bufferlist input; | |
459 | input.append(buf); | |
460 | ||
461 | uint8_t key[32]; | |
462 | for(size_t i=0;i<sizeof(key);i++) | |
463 | key[i] = i; | |
464 | ||
20effc67 | 465 | auto cbc = AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32); |
7c673cae FG |
466 | ASSERT_NE(cbc.get(), nullptr); |
467 | bufferlist encrypted; | |
468 | ASSERT_TRUE(cbc->encrypt(input, 0, test_range, encrypted, 0)); | |
469 | ||
470 | for (off_t r = 93; r < 150; r++ ) | |
471 | { | |
472 | ut_get_sink get_sink; | |
20effc67 | 473 | auto cbc = AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32); |
7c673cae | 474 | ASSERT_NE(cbc.get(), nullptr); |
20effc67 | 475 | RGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink, std::move(cbc)); |
7c673cae FG |
476 | |
477 | //random | |
478 | off_t begin = (r/3)*r*(r+13)*(r+23)*(r+53)*(r+71) % test_range; | |
479 | off_t end = begin + (r/5)*(r+7)*(r+13)*(r+101)*(r*103) % (test_range - begin) - 1; | |
480 | ||
481 | off_t f_begin = begin; | |
482 | off_t f_end = end; | |
483 | decrypt.fixup_range(f_begin, f_end); | |
484 | off_t pos = f_begin; | |
485 | do | |
486 | { | |
487 | off_t size = 2 << ((pos * 17 + pos / 113 + r) % 16); | |
488 | size = (pos + 1117) * (pos + 2229) % size + 1; | |
489 | if (pos + size > f_end + 1) | |
490 | size = f_end + 1 - pos; | |
491 | ||
492 | decrypt.handle_data(encrypted, pos, size); | |
493 | pos = pos + size; | |
494 | } while (pos < f_end + 1); | |
495 | decrypt.flush(); | |
496 | ||
497 | const std::string& decrypted = get_sink.get_sink(); | |
498 | size_t expected_len = end - begin + 1; | |
499 | ASSERT_EQ(decrypted.length(), expected_len); | |
f67539c2 | 500 | ASSERT_EQ(decrypted, std::string_view(input.c_str()+begin, expected_len)); |
7c673cae FG |
501 | } |
502 | } | |
503 | ||
504 | ||
505 | using range_t = std::pair<off_t, off_t>; | |
506 | ||
507 | // call filter->fixup_range() and return the range as a pair. this makes it easy | |
508 | // to fit on a single line for ASSERT_EQ() | |
509 | range_t fixup_range(RGWGetObj_BlockDecrypt *decrypt, off_t ofs, off_t end) | |
510 | { | |
511 | decrypt->fixup_range(ofs, end); | |
512 | return {ofs, end}; | |
513 | } | |
514 | ||
515 | TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup) | |
516 | { | |
20effc67 | 517 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
7c673cae FG |
518 | ut_get_sink get_sink; |
519 | auto nonecrypt = std::unique_ptr<BlockCrypt>(new BlockCryptNone); | |
20effc67 | 520 | RGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink, |
7c673cae FG |
521 | std::move(nonecrypt)); |
522 | ASSERT_EQ(fixup_range(&decrypt,0,0), range_t(0,255)); | |
523 | ASSERT_EQ(fixup_range(&decrypt,1,256), range_t(0,511)); | |
524 | ASSERT_EQ(fixup_range(&decrypt,0,255), range_t(0,255)); | |
525 | ASSERT_EQ(fixup_range(&decrypt,255,256), range_t(0,511)); | |
526 | ASSERT_EQ(fixup_range(&decrypt,511,1023), range_t(256,1023)); | |
527 | ASSERT_EQ(fixup_range(&decrypt,513,1024), range_t(512,1024+255)); | |
528 | } | |
529 | ||
a8e16298 TL |
530 | using parts_len_t = std::vector<size_t>; |
531 | ||
532 | class TestRGWGetObj_BlockDecrypt : public RGWGetObj_BlockDecrypt { | |
533 | using RGWGetObj_BlockDecrypt::RGWGetObj_BlockDecrypt; | |
534 | public: | |
535 | void set_parts_len(parts_len_t&& other) { | |
536 | parts_len = std::move(other); | |
537 | } | |
538 | }; | |
539 | ||
540 | std::vector<size_t> create_mp_parts(size_t obj_size, size_t mp_part_len){ | |
541 | std::vector<size_t> parts_len; | |
542 | size_t part_size; | |
543 | size_t ofs=0; | |
544 | ||
545 | while (ofs < obj_size){ | |
546 | part_size = std::min(mp_part_len, (obj_size - ofs)); | |
547 | ofs += part_size; | |
548 | parts_len.push_back(part_size); | |
549 | } | |
550 | return parts_len; | |
551 | } | |
552 | ||
553 | const size_t part_size = 5*1024*1024; | |
554 | const size_t obj_size = 30*1024*1024; | |
555 | ||
556 | TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup_simple) | |
557 | { | |
20effc67 | 558 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
a8e16298 TL |
559 | |
560 | ut_get_sink get_sink; | |
11fdf7f2 | 561 | auto nonecrypt = std::make_unique<BlockCryptNone>(4096); |
20effc67 | 562 | TestRGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink, |
a8e16298 TL |
563 | std::move(nonecrypt)); |
564 | decrypt.set_parts_len(create_mp_parts(obj_size, part_size)); | |
565 | ASSERT_EQ(fixup_range(&decrypt,0,0), range_t(0,4095)); | |
566 | ASSERT_EQ(fixup_range(&decrypt,1,4096), range_t(0,8191)); | |
567 | ASSERT_EQ(fixup_range(&decrypt,0,4095), range_t(0,4095)); | |
568 | ASSERT_EQ(fixup_range(&decrypt,4095,4096), range_t(0,8191)); | |
569 | ||
570 | // ranges are end-end inclusive, we request bytes just spanning short of first | |
571 | // part to exceeding the first part, part_size - 1 is aligned to a 4095 boundary | |
572 | ASSERT_EQ(fixup_range(&decrypt, 0, part_size - 2), range_t(0, part_size -1)); | |
573 | ASSERT_EQ(fixup_range(&decrypt, 0, part_size - 1), range_t(0, part_size -1)); | |
574 | ASSERT_EQ(fixup_range(&decrypt, 0, part_size), range_t(0, part_size + 4095)); | |
575 | ASSERT_EQ(fixup_range(&decrypt, 0, part_size + 1), range_t(0, part_size + 4095)); | |
576 | ||
577 | // request bytes spanning 2 parts | |
578 | ASSERT_EQ(fixup_range(&decrypt, part_size -2, part_size + 2), | |
579 | range_t(part_size - 4096, part_size + 4095)); | |
580 | ||
581 | // request last byte | |
582 | ASSERT_EQ(fixup_range(&decrypt, obj_size - 1, obj_size -1), | |
583 | range_t(obj_size - 4096, obj_size -1)); | |
584 | ||
585 | } | |
586 | ||
587 | TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup_non_aligned_obj_size) | |
588 | { | |
20effc67 | 589 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
a8e16298 TL |
590 | |
591 | ut_get_sink get_sink; | |
11fdf7f2 | 592 | auto nonecrypt = std::make_unique<BlockCryptNone>(4096); |
20effc67 | 593 | TestRGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink, |
a8e16298 TL |
594 | std::move(nonecrypt)); |
595 | auto na_obj_size = obj_size + 1; | |
596 | decrypt.set_parts_len(create_mp_parts(na_obj_size, part_size)); | |
597 | ||
598 | // these should be unaffected here | |
599 | ASSERT_EQ(fixup_range(&decrypt, 0, part_size - 2), range_t(0, part_size -1)); | |
600 | ASSERT_EQ(fixup_range(&decrypt, 0, part_size - 1), range_t(0, part_size -1)); | |
601 | ASSERT_EQ(fixup_range(&decrypt, 0, part_size), range_t(0, part_size + 4095)); | |
602 | ASSERT_EQ(fixup_range(&decrypt, 0, part_size + 1), range_t(0, part_size + 4095)); | |
603 | ||
604 | ||
605 | // request last 2 bytes; spanning 2 parts | |
606 | ASSERT_EQ(fixup_range(&decrypt, na_obj_size -2 , na_obj_size -1), | |
607 | range_t(na_obj_size - 1 - 4096, na_obj_size - 1)); | |
608 | ||
609 | // request last byte, spans last 1B part only | |
610 | ASSERT_EQ(fixup_range(&decrypt, na_obj_size -1, na_obj_size - 1), | |
611 | range_t(na_obj_size - 1, na_obj_size -1)); | |
612 | ||
613 | } | |
614 | ||
615 | TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup_non_aligned_part_size) | |
616 | { | |
20effc67 | 617 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
a8e16298 TL |
618 | |
619 | ut_get_sink get_sink; | |
11fdf7f2 | 620 | auto nonecrypt = std::make_unique<BlockCryptNone>(4096); |
20effc67 | 621 | TestRGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink, |
a8e16298 TL |
622 | std::move(nonecrypt)); |
623 | auto na_part_size = part_size + 1; | |
624 | decrypt.set_parts_len(create_mp_parts(obj_size, na_part_size)); | |
625 | ||
626 | // na_part_size -2, ie. part_size -1 is aligned to 4095 boundary | |
627 | ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size - 2), range_t(0, na_part_size -2)); | |
628 | // even though na_part_size -1 should not align to a 4095 boundary, the range | |
629 | // should not span the next part | |
630 | ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size - 1), range_t(0, na_part_size -1)); | |
631 | ||
632 | ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size), range_t(0, na_part_size + 4095)); | |
633 | ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size + 1), range_t(0, na_part_size + 4095)); | |
634 | ||
635 | // request spanning 2 parts | |
636 | ASSERT_EQ(fixup_range(&decrypt, na_part_size - 2, na_part_size + 2), | |
637 | range_t(na_part_size - 1 - 4096, na_part_size + 4095)); | |
638 | ||
639 | // request last byte, this will be interesting, since this a multipart upload | |
640 | // with 5MB+1 size, the last part is actually 5 bytes short of 5 MB, which | |
641 | // should be considered for the ranges alignment; an easier way to look at | |
642 | // this will be that the last offset aligned to a 5MiB part will be 5MiB - | |
643 | // 4095, this is a part that is 5MiB - 5 B | |
644 | ASSERT_EQ(fixup_range(&decrypt, obj_size - 1, obj_size -1), | |
645 | range_t(obj_size +5 -4096, obj_size -1)); | |
646 | ||
647 | } | |
648 | ||
649 | TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup_non_aligned) | |
650 | { | |
20effc67 | 651 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
a8e16298 TL |
652 | |
653 | ut_get_sink get_sink; | |
11fdf7f2 | 654 | auto nonecrypt = std::make_unique<BlockCryptNone>(4096); |
20effc67 | 655 | TestRGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink, |
a8e16298 TL |
656 | std::move(nonecrypt)); |
657 | auto na_part_size = part_size + 1; | |
658 | auto na_obj_size = obj_size + 7; // (6*(5MiB + 1) + 1) for the last 1B overflow | |
659 | decrypt.set_parts_len(create_mp_parts(na_obj_size, na_part_size)); | |
660 | ||
661 | // na_part_size -2, ie. part_size -1 is aligned to 4095 boundary | |
662 | ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size - 2), range_t(0, na_part_size -2)); | |
663 | // even though na_part_size -1 should not align to a 4095 boundary, the range | |
664 | // should not span the next part | |
665 | ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size - 1), range_t(0, na_part_size -1)); | |
666 | ||
667 | ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size), range_t(0, na_part_size + 4095)); | |
668 | ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size + 1), range_t(0, na_part_size + 4095)); | |
669 | ||
670 | // request last byte, spans last 1B part only | |
671 | ASSERT_EQ(fixup_range(&decrypt, na_obj_size -1, na_obj_size - 1), | |
672 | range_t(na_obj_size - 1, na_obj_size -1)); | |
673 | ||
674 | ASSERT_EQ(fixup_range(&decrypt, na_obj_size -2, na_obj_size -1), | |
675 | range_t(na_obj_size - 2, na_obj_size -1)); | |
676 | ||
677 | } | |
678 | ||
679 | TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup_invalid_ranges) | |
680 | { | |
20effc67 | 681 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
a8e16298 TL |
682 | |
683 | ut_get_sink get_sink; | |
11fdf7f2 | 684 | auto nonecrypt = std::make_unique<BlockCryptNone>(4096); |
20effc67 | 685 | TestRGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink, |
a8e16298 TL |
686 | std::move(nonecrypt)); |
687 | ||
688 | decrypt.set_parts_len(create_mp_parts(obj_size, part_size)); | |
689 | ||
690 | // the ranges below would be mostly unreachable in current code as rgw | |
691 | // would've returned a 411 before reaching, but we're just doing this to make | |
692 | // sure we don't have invalid access | |
693 | ASSERT_EQ(fixup_range(&decrypt, obj_size - 1, obj_size + 100), | |
694 | range_t(obj_size - 4096, obj_size - 1)); | |
695 | ASSERT_EQ(fixup_range(&decrypt, obj_size, obj_size + 1), | |
696 | range_t(obj_size - 1, obj_size - 1)); | |
697 | ASSERT_EQ(fixup_range(&decrypt, obj_size+1, obj_size + 100), | |
698 | range_t(obj_size - 1, obj_size - 1)); | |
699 | ||
700 | } | |
7c673cae FG |
701 | |
702 | TEST(TestRGWCrypto, verify_RGWPutObj_BlockEncrypt_chunks) | |
703 | { | |
20effc67 | 704 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
7c673cae FG |
705 | //create some input for encryption |
706 | const off_t test_range = 1024*1024; | |
707 | bufferptr buf(test_range); | |
708 | char* p = buf.c_str(); | |
709 | for(size_t i = 0; i < buf.length(); i++) | |
710 | p[i] = i + i*i + (i >> 2); | |
711 | ||
712 | bufferlist input; | |
713 | input.append(buf); | |
714 | ||
715 | uint8_t key[32]; | |
716 | for(size_t i=0;i<sizeof(key);i++) | |
717 | key[i] = i; | |
718 | ||
719 | for (off_t r = 93; r < 150; r++ ) | |
720 | { | |
721 | ut_put_sink put_sink; | |
20effc67 | 722 | auto cbc = AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32); |
7c673cae | 723 | ASSERT_NE(cbc.get(), nullptr); |
20effc67 TL |
724 | RGWPutObj_BlockEncrypt encrypt(&no_dpp, g_ceph_context, &put_sink, |
725 | std::move(cbc)); | |
7c673cae FG |
726 | |
727 | off_t test_size = (r/5)*(r+7)*(r+13)*(r+101)*(r*103) % (test_range - 1) + 1; | |
728 | off_t pos = 0; | |
729 | do | |
730 | { | |
731 | off_t size = 2 << ((pos * 17 + pos / 113 + r) % 16); | |
732 | size = (pos + 1117) * (pos + 2229) % size + 1; | |
733 | if (pos + size > test_size) | |
734 | size = test_size - pos; | |
735 | ||
736 | bufferlist bl; | |
737 | bl.append(input.c_str()+pos, size); | |
11fdf7f2 | 738 | encrypt.process(std::move(bl), pos); |
7c673cae FG |
739 | |
740 | pos = pos + size; | |
741 | } while (pos < test_size); | |
11fdf7f2 | 742 | encrypt.process({}, pos); |
7c673cae FG |
743 | |
744 | ASSERT_EQ(put_sink.get_sink().length(), static_cast<size_t>(test_size)); | |
745 | ||
20effc67 | 746 | cbc = AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32); |
7c673cae FG |
747 | ASSERT_NE(cbc.get(), nullptr); |
748 | ||
749 | bufferlist encrypted; | |
750 | bufferlist decrypted; | |
751 | encrypted.append(put_sink.get_sink()); | |
752 | ASSERT_TRUE(cbc->decrypt(encrypted, 0, test_size, decrypted, 0)); | |
753 | ||
754 | ASSERT_EQ(decrypted.length(), test_size); | |
f67539c2 TL |
755 | ASSERT_EQ(std::string_view(decrypted.c_str(), test_size), |
756 | std::string_view(input.c_str(), test_size)); | |
7c673cae FG |
757 | } |
758 | } | |
759 | ||
760 | ||
761 | TEST(TestRGWCrypto, verify_Encrypt_Decrypt) | |
762 | { | |
20effc67 | 763 | const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys); |
7c673cae FG |
764 | uint8_t key[32]; |
765 | for(size_t i=0;i<sizeof(key);i++) | |
766 | key[i]=i; | |
767 | ||
768 | size_t fi_a = 0; | |
769 | size_t fi_b = 1; | |
770 | size_t test_size; | |
771 | do | |
772 | { | |
773 | //fibonacci | |
774 | size_t tmp = fi_b; | |
775 | fi_b = fi_a + fi_b; | |
776 | fi_a = tmp; | |
777 | ||
778 | test_size = fi_b; | |
779 | ||
780 | uint8_t* test_in = new uint8_t[test_size]; | |
781 | //fill with something | |
782 | memset(test_in, test_size & 0xff, test_size); | |
783 | ||
784 | ut_put_sink put_sink; | |
20effc67 TL |
785 | RGWPutObj_BlockEncrypt encrypt(&no_dpp, g_ceph_context, &put_sink, |
786 | AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32)); | |
7c673cae FG |
787 | bufferlist bl; |
788 | bl.append((char*)test_in, test_size); | |
11fdf7f2 TL |
789 | encrypt.process(std::move(bl), 0); |
790 | encrypt.process({}, test_size); | |
7c673cae FG |
791 | ASSERT_EQ(put_sink.get_sink().length(), test_size); |
792 | ||
793 | bl.append(put_sink.get_sink().data(), put_sink.get_sink().length()); | |
794 | ASSERT_EQ(bl.length(), test_size); | |
795 | ||
796 | ut_get_sink get_sink; | |
20effc67 TL |
797 | RGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink, |
798 | AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32)); | |
7c673cae FG |
799 | |
800 | off_t bl_ofs = 0; | |
801 | off_t bl_end = test_size - 1; | |
802 | decrypt.fixup_range(bl_ofs, bl_end); | |
803 | decrypt.handle_data(bl, 0, bl.length()); | |
804 | decrypt.flush(); | |
805 | ASSERT_EQ(get_sink.get_sink().length(), test_size); | |
f67539c2 | 806 | ASSERT_EQ(get_sink.get_sink(), std::string_view((char*)test_in,test_size)); |
7c673cae FG |
807 | } |
808 | while (test_size < 20000); | |
809 | } | |
810 | ||
811 | ||
812 | int main(int argc, char **argv) { | |
20effc67 | 813 | auto args = argv_to_vec(argc, argv); |
11fdf7f2 TL |
814 | auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, |
815 | CODE_ENVIRONMENT_UTILITY, | |
816 | CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); | |
7c673cae FG |
817 | common_init_finish(g_ceph_context); |
818 | ||
819 | ::testing::InitGoogleTest(&argc, argv); | |
820 | return RUN_ALL_TESTS(); | |
821 | } | |
822 |