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