]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rgw/test_rgw_crypto.cc
import ceph quincy 17.2.6
[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"
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
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);
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
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);
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
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,
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
530using parts_len_t = std::vector<size_t>;
531
532class TestRGWGetObj_BlockDecrypt : public RGWGetObj_BlockDecrypt {
533 using RGWGetObj_BlockDecrypt::RGWGetObj_BlockDecrypt;
534public:
535 void set_parts_len(parts_len_t&& other) {
536 parts_len = std::move(other);
537 }
538};
539
540std::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
553const size_t part_size = 5*1024*1024;
554const size_t obj_size = 30*1024*1024;
555
556TEST(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
587TEST(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
615TEST(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
649TEST(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
679TEST(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
702TEST(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
761TEST(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
812int 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