]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rgw/test_rgw_crypto.cc
update ceph source to reef 18.2.1
[ceph.git] / ceph / src / test / rgw / test_rgw_crypto.cc
CommitLineData
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"
1e59de90
TL
17#include "rgw_common.h"
18#include "rgw_rados.h"
19#include "rgw_crypt.h"
7c673cae 20#include <gtest/gtest.h>
11fdf7f2 21#include "include/ceph_assert.h"
7c673cae
FG
22#define dout_subsys ceph_subsys_rgw
23
24using namespace std;
25
26
20effc67 27std::unique_ptr<BlockCrypt> AES_256_CBC_create(const DoutPrefixProvider *dpp, CephContext* cct, const uint8_t* key, size_t len);
7c673cae 28
11fdf7f2 29class ut_get_sink : public RGWGetObj_Filter {
7c673cae
FG
30 std::stringstream sink;
31public:
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 46class ut_put_sink: public rgw::sal::DataProcessor
7c673cae
FG
47{
48 std::stringstream sink;
49public:
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
62class BlockCryptNone: public BlockCrypt {
a8e16298 63 size_t block_size = 256;
7c673cae
FG
64public:
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
94TEST(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
147TEST(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
196TEST(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
274TEST(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
324TEST(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
401TEST(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);
aee94f69 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
448TEST(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);
aee94f69 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
505using 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()
509range_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
515TEST(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,
aee94f69 521 std::move(nonecrypt), {});
7c673cae
FG
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
530std::vector<size_t> create_mp_parts(size_t obj_size, size_t mp_part_len){
531 std::vector<size_t> parts_len;
532 size_t part_size;
533 size_t ofs=0;
534
535 while (ofs < obj_size){
536 part_size = std::min(mp_part_len, (obj_size - ofs));
537 ofs += part_size;
538 parts_len.push_back(part_size);
539 }
540 return parts_len;
541}
542
543const size_t part_size = 5*1024*1024;
544const size_t obj_size = 30*1024*1024;
545
546TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup_simple)
547{
20effc67 548 const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys);
a8e16298
TL
549
550 ut_get_sink get_sink;
11fdf7f2 551 auto nonecrypt = std::make_unique<BlockCryptNone>(4096);
aee94f69
TL
552 RGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink,
553 std::move(nonecrypt),
554 create_mp_parts(obj_size, part_size));
a8e16298
TL
555 ASSERT_EQ(fixup_range(&decrypt,0,0), range_t(0,4095));
556 ASSERT_EQ(fixup_range(&decrypt,1,4096), range_t(0,8191));
557 ASSERT_EQ(fixup_range(&decrypt,0,4095), range_t(0,4095));
558 ASSERT_EQ(fixup_range(&decrypt,4095,4096), range_t(0,8191));
559
560 // ranges are end-end inclusive, we request bytes just spanning short of first
561 // part to exceeding the first part, part_size - 1 is aligned to a 4095 boundary
562 ASSERT_EQ(fixup_range(&decrypt, 0, part_size - 2), range_t(0, part_size -1));
563 ASSERT_EQ(fixup_range(&decrypt, 0, part_size - 1), range_t(0, part_size -1));
564 ASSERT_EQ(fixup_range(&decrypt, 0, part_size), range_t(0, part_size + 4095));
565 ASSERT_EQ(fixup_range(&decrypt, 0, part_size + 1), range_t(0, part_size + 4095));
566
567 // request bytes spanning 2 parts
568 ASSERT_EQ(fixup_range(&decrypt, part_size -2, part_size + 2),
569 range_t(part_size - 4096, part_size + 4095));
570
571 // request last byte
572 ASSERT_EQ(fixup_range(&decrypt, obj_size - 1, obj_size -1),
573 range_t(obj_size - 4096, obj_size -1));
574
575}
576
577TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup_non_aligned_obj_size)
578{
20effc67 579 const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys);
a8e16298 580
aee94f69
TL
581 const size_t na_obj_size = obj_size + 1;
582
a8e16298 583 ut_get_sink get_sink;
11fdf7f2 584 auto nonecrypt = std::make_unique<BlockCryptNone>(4096);
aee94f69
TL
585 RGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink,
586 std::move(nonecrypt),
587 create_mp_parts(na_obj_size, part_size));
a8e16298
TL
588
589 // these should be unaffected here
590 ASSERT_EQ(fixup_range(&decrypt, 0, part_size - 2), range_t(0, part_size -1));
591 ASSERT_EQ(fixup_range(&decrypt, 0, part_size - 1), range_t(0, part_size -1));
592 ASSERT_EQ(fixup_range(&decrypt, 0, part_size), range_t(0, part_size + 4095));
593 ASSERT_EQ(fixup_range(&decrypt, 0, part_size + 1), range_t(0, part_size + 4095));
594
595
596 // request last 2 bytes; spanning 2 parts
597 ASSERT_EQ(fixup_range(&decrypt, na_obj_size -2 , na_obj_size -1),
598 range_t(na_obj_size - 1 - 4096, na_obj_size - 1));
599
600 // request last byte, spans last 1B part only
601 ASSERT_EQ(fixup_range(&decrypt, na_obj_size -1, na_obj_size - 1),
602 range_t(na_obj_size - 1, na_obj_size -1));
603
604}
605
606TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup_non_aligned_part_size)
607{
20effc67 608 const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys);
a8e16298 609
aee94f69
TL
610 const size_t na_part_size = part_size + 1;
611
a8e16298 612 ut_get_sink get_sink;
11fdf7f2 613 auto nonecrypt = std::make_unique<BlockCryptNone>(4096);
aee94f69
TL
614 RGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink,
615 std::move(nonecrypt),
616 create_mp_parts(obj_size, na_part_size));
a8e16298
TL
617
618 // na_part_size -2, ie. part_size -1 is aligned to 4095 boundary
619 ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size - 2), range_t(0, na_part_size -2));
620 // even though na_part_size -1 should not align to a 4095 boundary, the range
621 // should not span the next part
622 ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size - 1), range_t(0, na_part_size -1));
623
624 ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size), range_t(0, na_part_size + 4095));
625 ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size + 1), range_t(0, na_part_size + 4095));
626
627 // request spanning 2 parts
628 ASSERT_EQ(fixup_range(&decrypt, na_part_size - 2, na_part_size + 2),
629 range_t(na_part_size - 1 - 4096, na_part_size + 4095));
630
631 // request last byte, this will be interesting, since this a multipart upload
632 // with 5MB+1 size, the last part is actually 5 bytes short of 5 MB, which
633 // should be considered for the ranges alignment; an easier way to look at
634 // this will be that the last offset aligned to a 5MiB part will be 5MiB -
635 // 4095, this is a part that is 5MiB - 5 B
636 ASSERT_EQ(fixup_range(&decrypt, obj_size - 1, obj_size -1),
637 range_t(obj_size +5 -4096, obj_size -1));
638
639}
640
641TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup_non_aligned)
642{
20effc67 643 const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys);
a8e16298 644
aee94f69
TL
645 const size_t na_part_size = part_size + 1;
646 const size_t na_obj_size = obj_size + 7; // (6*(5MiB + 1) + 1) for the last 1B overflow
647
a8e16298 648 ut_get_sink get_sink;
11fdf7f2 649 auto nonecrypt = std::make_unique<BlockCryptNone>(4096);
aee94f69
TL
650 RGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink,
651 std::move(nonecrypt),
652 create_mp_parts(na_obj_size, na_part_size));
a8e16298
TL
653
654 // na_part_size -2, ie. part_size -1 is aligned to 4095 boundary
655 ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size - 2), range_t(0, na_part_size -2));
656 // even though na_part_size -1 should not align to a 4095 boundary, the range
657 // should not span the next part
658 ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size - 1), range_t(0, na_part_size -1));
659
660 ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size), range_t(0, na_part_size + 4095));
661 ASSERT_EQ(fixup_range(&decrypt, 0, na_part_size + 1), range_t(0, na_part_size + 4095));
662
663 // request last byte, spans last 1B part only
664 ASSERT_EQ(fixup_range(&decrypt, na_obj_size -1, na_obj_size - 1),
665 range_t(na_obj_size - 1, na_obj_size -1));
666
667 ASSERT_EQ(fixup_range(&decrypt, na_obj_size -2, na_obj_size -1),
668 range_t(na_obj_size - 2, na_obj_size -1));
669
670}
671
672TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup_invalid_ranges)
673{
20effc67 674 const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys);
a8e16298
TL
675
676 ut_get_sink get_sink;
11fdf7f2 677 auto nonecrypt = std::make_unique<BlockCryptNone>(4096);
aee94f69
TL
678 RGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink,
679 std::move(nonecrypt),
680 create_mp_parts(obj_size, part_size));
a8e16298 681
a8e16298
TL
682
683 // the ranges below would be mostly unreachable in current code as rgw
684 // would've returned a 411 before reaching, but we're just doing this to make
685 // sure we don't have invalid access
686 ASSERT_EQ(fixup_range(&decrypt, obj_size - 1, obj_size + 100),
687 range_t(obj_size - 4096, obj_size - 1));
688 ASSERT_EQ(fixup_range(&decrypt, obj_size, obj_size + 1),
689 range_t(obj_size - 1, obj_size - 1));
690 ASSERT_EQ(fixup_range(&decrypt, obj_size+1, obj_size + 100),
691 range_t(obj_size - 1, obj_size - 1));
692
693}
7c673cae
FG
694
695TEST(TestRGWCrypto, verify_RGWPutObj_BlockEncrypt_chunks)
696{
20effc67 697 const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys);
7c673cae
FG
698 //create some input for encryption
699 const off_t test_range = 1024*1024;
700 bufferptr buf(test_range);
701 char* p = buf.c_str();
702 for(size_t i = 0; i < buf.length(); i++)
703 p[i] = i + i*i + (i >> 2);
704
705 bufferlist input;
706 input.append(buf);
707
708 uint8_t key[32];
709 for(size_t i=0;i<sizeof(key);i++)
710 key[i] = i;
711
712 for (off_t r = 93; r < 150; r++ )
713 {
714 ut_put_sink put_sink;
20effc67 715 auto cbc = AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32);
7c673cae 716 ASSERT_NE(cbc.get(), nullptr);
20effc67
TL
717 RGWPutObj_BlockEncrypt encrypt(&no_dpp, g_ceph_context, &put_sink,
718 std::move(cbc));
7c673cae
FG
719
720 off_t test_size = (r/5)*(r+7)*(r+13)*(r+101)*(r*103) % (test_range - 1) + 1;
721 off_t pos = 0;
722 do
723 {
724 off_t size = 2 << ((pos * 17 + pos / 113 + r) % 16);
725 size = (pos + 1117) * (pos + 2229) % size + 1;
726 if (pos + size > test_size)
727 size = test_size - pos;
728
729 bufferlist bl;
730 bl.append(input.c_str()+pos, size);
11fdf7f2 731 encrypt.process(std::move(bl), pos);
7c673cae
FG
732
733 pos = pos + size;
734 } while (pos < test_size);
11fdf7f2 735 encrypt.process({}, pos);
7c673cae
FG
736
737 ASSERT_EQ(put_sink.get_sink().length(), static_cast<size_t>(test_size));
738
20effc67 739 cbc = AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32);
7c673cae
FG
740 ASSERT_NE(cbc.get(), nullptr);
741
742 bufferlist encrypted;
743 bufferlist decrypted;
744 encrypted.append(put_sink.get_sink());
745 ASSERT_TRUE(cbc->decrypt(encrypted, 0, test_size, decrypted, 0));
746
747 ASSERT_EQ(decrypted.length(), test_size);
f67539c2
TL
748 ASSERT_EQ(std::string_view(decrypted.c_str(), test_size),
749 std::string_view(input.c_str(), test_size));
7c673cae
FG
750 }
751}
752
753
754TEST(TestRGWCrypto, verify_Encrypt_Decrypt)
755{
20effc67 756 const NoDoutPrefix no_dpp(g_ceph_context, dout_subsys);
7c673cae
FG
757 uint8_t key[32];
758 for(size_t i=0;i<sizeof(key);i++)
759 key[i]=i;
760
761 size_t fi_a = 0;
762 size_t fi_b = 1;
763 size_t test_size;
764 do
765 {
766 //fibonacci
767 size_t tmp = fi_b;
768 fi_b = fi_a + fi_b;
769 fi_a = tmp;
770
771 test_size = fi_b;
772
773 uint8_t* test_in = new uint8_t[test_size];
774 //fill with something
775 memset(test_in, test_size & 0xff, test_size);
776
777 ut_put_sink put_sink;
20effc67
TL
778 RGWPutObj_BlockEncrypt encrypt(&no_dpp, g_ceph_context, &put_sink,
779 AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32));
7c673cae
FG
780 bufferlist bl;
781 bl.append((char*)test_in, test_size);
11fdf7f2
TL
782 encrypt.process(std::move(bl), 0);
783 encrypt.process({}, test_size);
7c673cae
FG
784 ASSERT_EQ(put_sink.get_sink().length(), test_size);
785
786 bl.append(put_sink.get_sink().data(), put_sink.get_sink().length());
787 ASSERT_EQ(bl.length(), test_size);
788
789 ut_get_sink get_sink;
20effc67 790 RGWGetObj_BlockDecrypt decrypt(&no_dpp, g_ceph_context, &get_sink,
aee94f69
TL
791 AES_256_CBC_create(&no_dpp, g_ceph_context, &key[0], 32),
792 {});
7c673cae
FG
793
794 off_t bl_ofs = 0;
795 off_t bl_end = test_size - 1;
796 decrypt.fixup_range(bl_ofs, bl_end);
797 decrypt.handle_data(bl, 0, bl.length());
798 decrypt.flush();
799 ASSERT_EQ(get_sink.get_sink().length(), test_size);
f67539c2 800 ASSERT_EQ(get_sink.get_sink(), std::string_view((char*)test_in,test_size));
7c673cae
FG
801 }
802 while (test_size < 20000);
803}
804
805
806int main(int argc, char **argv) {
20effc67 807 auto args = argv_to_vec(argc, argv);
11fdf7f2
TL
808 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
809 CODE_ENVIRONMENT_UTILITY,
810 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
7c673cae
FG
811 common_init_finish(g_ceph_context);
812
813 ::testing::InitGoogleTest(&argc, argv);
814 return RUN_ALL_TESTS();
815}
816