X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Ftest%2Frgw%2Ftest_rgw_crypto.cc;fp=src%2Fceph%2Fsrc%2Ftest%2Frgw%2Ftest_rgw_crypto.cc;h=7739b4e996164737921070abd0a365b2e88ff2c6;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/test/rgw/test_rgw_crypto.cc b/src/ceph/src/test/rgw/test_rgw_crypto.cc new file mode 100644 index 0000000..7739b4e --- /dev/null +++ b/src/ceph/src/test/rgw/test_rgw_crypto.cc @@ -0,0 +1,660 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2016 Mirantis + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ +#include +#include "global/global_init.h" +#include "common/ceph_argparse.h" +#include "rgw/rgw_common.h" +#include "rgw/rgw_rados.h" +#include "rgw/rgw_crypt.h" +#include +#include "include/assert.h" +#define dout_subsys ceph_subsys_rgw + +using namespace std; + + +std::unique_ptr AES_256_CBC_create(CephContext* cct, const uint8_t* key, size_t len); + + +class ut_get_sink : public RGWGetDataCB { + std::stringstream sink; +public: + ut_get_sink() {} + virtual ~ut_get_sink() {} + + int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) override + { + sink << boost::string_ref(bl.c_str()+bl_ofs, bl_len); + return 0; + } + std::string get_sink() + { + return sink.str(); + } +}; + +class ut_put_sink: public RGWPutObjDataProcessor +{ + std::stringstream sink; +public: + ut_put_sink(){} + virtual ~ut_put_sink(){} + int handle_data(bufferlist& bl, off_t ofs, void **phandle, rgw_raw_obj *pobj, bool *again) override + { + sink << boost::string_ref(bl.c_str(),bl.length()); + *again = false; + return 0; + } + int throttle_data(void *handle, const rgw_raw_obj& obj, uint64_t size, bool need_to_wait) override + { + return 0; + } + std::string get_sink() + { + return sink.str(); + } +}; + + +class BlockCryptNone: public BlockCrypt { +public: + BlockCryptNone(){}; + virtual ~BlockCryptNone(){}; + size_t get_block_size() override + { + return 256; + } + bool encrypt(bufferlist& input, + off_t in_ofs, + size_t size, + bufferlist& output, + off_t stream_offset) override + { + output.clear(); + output.append(input.c_str(), input.length()); + return true; + } + bool decrypt(bufferlist& input, + off_t in_ofs, + size_t size, + bufferlist& output, + off_t stream_offset) override + { + output.clear(); + output.append(input.c_str(), input.length()); + return true; + } +}; + + +TEST(TestRGWCrypto, verify_AES_256_CBC_identity) +{ + //create some input for encryption + const off_t test_range = 1024*1024; + buffer::ptr buf(test_range); + char* p = buf.c_str(); + for(size_t i = 0; i < buf.length(); i++) + p[i] = i + i*i + (i >> 2); + + bufferlist input; + input.append(buf); + + for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17}) + { + //make some random key + uint8_t key[32]; + for(size_t i=0;iget_block_size(); + ASSERT_NE(block_size, 0u); + + for (size_t r = 97; r < 123 ; r++) + { + off_t begin = (r*r*r*r*r % test_range); + begin = begin - begin % block_size; + off_t end = begin + r*r*r*r*r*r*r % (test_range - begin); + if (r % 3) + end = end - end % block_size; + off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000); + offset = offset - offset % block_size; + + ASSERT_EQ(begin % block_size, 0u); + ASSERT_LE(end, test_range); + ASSERT_EQ(offset % block_size, 0u); + + bufferlist encrypted; + ASSERT_TRUE(aes->encrypt(input, begin, end - begin, encrypted, offset)); + bufferlist decrypted; + ASSERT_TRUE(aes->decrypt(encrypted, 0, end - begin, decrypted, offset)); + + ASSERT_EQ(decrypted.length(), end - begin); + ASSERT_EQ(boost::string_ref(input.c_str() + begin, end - begin), + boost::string_ref(decrypted.c_str(), end - begin) ); + } + } +} + + +TEST(TestRGWCrypto, verify_AES_256_CBC_identity_2) +{ + //create some input for encryption + const off_t test_range = 1024*1024; + buffer::ptr buf(test_range); + char* p = buf.c_str(); + for(size_t i = 0; i < buf.length(); i++) + p[i] = i + i*i + (i >> 2); + + bufferlist input; + input.append(buf); + + for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17}) + { + //make some random key + uint8_t key[32]; + for(size_t i=0;iget_block_size(); + ASSERT_NE(block_size, 0u); + + for (off_t end = 1; end < 6096 ; end+=3) + { + off_t begin = 0; + off_t offset = end*end*end*end*end % (1000*1000*1000); + offset = offset - offset % block_size; + + ASSERT_EQ(begin % block_size, 0u); + ASSERT_LE(end, test_range); + ASSERT_EQ(offset % block_size, 0u); + + bufferlist encrypted; + ASSERT_TRUE(aes->encrypt(input, begin, end, encrypted, offset)); + bufferlist decrypted; + ASSERT_TRUE(aes->decrypt(encrypted, 0, end, decrypted, offset)); + + ASSERT_EQ(decrypted.length(), end); + ASSERT_EQ(boost::string_ref(input.c_str(), end), + boost::string_ref(decrypted.c_str(), end) ); + } + } +} + + +TEST(TestRGWCrypto, verify_AES_256_CBC_identity_3) +{ + //create some input for encryption + const off_t test_range = 1024*1024; + buffer::ptr buf(test_range); + char* p = buf.c_str(); + for(size_t i = 0; i < buf.length(); i++) + p[i] = i + i*i + (i >> 2); + + bufferlist input; + input.append(buf); + + for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17}) + { + //make some random key + uint8_t key[32]; + for(size_t i=0;iget_block_size(); + ASSERT_NE(block_size, 0u); + size_t rr = 111; + for (size_t r = 97; r < 123 ; r++) + { + off_t begin = 0; + off_t end = begin + r*r*r*r*r*r*r % (test_range - begin); + //sometimes make aligned + if (r % 3) + end = end - end % block_size; + off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000); + offset = offset - offset % block_size; + + ASSERT_EQ(begin % block_size, 0u); + ASSERT_LE(end, test_range); + ASSERT_EQ(offset % block_size, 0u); + + bufferlist encrypted1; + bufferlist encrypted2; + + off_t pos = begin; + off_t chunk; + while (pos < end) { + chunk = block_size + (rr/3)*(rr+17)*(rr+71)*(rr+123)*(rr+131) % 50000; + chunk = chunk - chunk % block_size; + if (pos + chunk > end) + chunk = end - pos; + bufferlist tmp; + ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos)); + encrypted1.append(tmp); + pos += chunk; + rr++; + } + + pos = begin; + while (pos < end) { + chunk = block_size + (rr/3)*(rr+97)*(rr+151)*(rr+213)*(rr+251) % 50000; + chunk = chunk - chunk % block_size; + if (pos + chunk > end) + chunk = end - pos; + bufferlist tmp; + ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos)); + encrypted2.append(tmp); + pos += chunk; + rr++; + } + ASSERT_EQ(encrypted1.length(), end); + ASSERT_EQ(encrypted2.length(), end); + ASSERT_EQ(boost::string_ref(encrypted1.c_str(), end), + boost::string_ref(encrypted2.c_str(), end) ); + } + } +} + + +TEST(TestRGWCrypto, verify_AES_256_CBC_size_0_15) +{ + //create some input for encryption + const off_t test_range = 1024*1024; + buffer::ptr buf(test_range); + char* p = buf.c_str(); + for(size_t i = 0; i < buf.length(); i++) + p[i] = i + i*i + (i >> 2); + + bufferlist input; + input.append(buf); + + for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17}) + { + //make some random key + uint8_t key[32]; + for(size_t i=0;iget_block_size(); + ASSERT_NE(block_size, 0u); + for (size_t r = 97; r < 123 ; r++) + { + off_t begin = 0; + off_t end = begin + r*r*r*r*r*r*r % (16); + + off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000); + offset = offset - offset % block_size; + + ASSERT_EQ(begin % block_size, 0u); + ASSERT_LE(end, test_range); + ASSERT_EQ(offset % block_size, 0u); + + bufferlist encrypted; + bufferlist decrypted; + ASSERT_TRUE(aes->encrypt(input, 0, end, encrypted, offset)); + ASSERT_TRUE(aes->encrypt(encrypted, 0, end, decrypted, offset)); + ASSERT_EQ(encrypted.length(), end); + ASSERT_EQ(decrypted.length(), end); + ASSERT_EQ(boost::string_ref(input.c_str(), end), + boost::string_ref(decrypted.c_str(), end) ); + } + } +} + + +TEST(TestRGWCrypto, verify_AES_256_CBC_identity_last_block) +{ + //create some input for encryption + const off_t test_range = 1024*1024; + buffer::ptr buf(test_range); + char* p = buf.c_str(); + for(size_t i = 0; i < buf.length(); i++) + p[i] = i + i*i + (i >> 2); + + bufferlist input; + input.append(buf); + + for (unsigned int step : {1, 2, 3, 5, 7, 11, 13, 17}) + { + //make some random key + uint8_t key[32]; + for(size_t i=0;iget_block_size(); + ASSERT_NE(block_size, 0u); + size_t rr = 111; + for (size_t r = 97; r < 123 ; r++) + { + off_t begin = 0; + off_t end = r*r*r*r*r*r*r % (test_range - 16); + end = end - end % block_size; + end = end + (r+3)*(r+5)*(r+7) % 16; + + off_t offset = r*r*r*r*r*r*r*r % (1000*1000*1000); + offset = offset - offset % block_size; + + ASSERT_EQ(begin % block_size, 0u); + ASSERT_LE(end, test_range); + ASSERT_EQ(offset % block_size, 0u); + + bufferlist encrypted1; + bufferlist encrypted2; + + off_t pos = begin; + off_t chunk; + while (pos < end) { + chunk = block_size + (rr/3)*(rr+17)*(rr+71)*(rr+123)*(rr+131) % 50000; + chunk = chunk - chunk % block_size; + if (pos + chunk > end) + chunk = end - pos; + bufferlist tmp; + ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos)); + encrypted1.append(tmp); + pos += chunk; + rr++; + } + pos = begin; + while (pos < end) { + chunk = block_size + (rr/3)*(rr+97)*(rr+151)*(rr+213)*(rr+251) % 50000; + chunk = chunk - chunk % block_size; + if (pos + chunk > end) + chunk = end - pos; + bufferlist tmp; + ASSERT_TRUE(aes->encrypt(input, pos, chunk, tmp, offset + pos)); + encrypted2.append(tmp); + pos += chunk; + rr++; + } + ASSERT_EQ(encrypted1.length(), end); + ASSERT_EQ(encrypted2.length(), end); + ASSERT_EQ(boost::string_ref(encrypted1.c_str(), end), + boost::string_ref(encrypted2.c_str(), end) ); + } + } +} + + +TEST(TestRGWCrypto, verify_RGWGetObj_BlockDecrypt_ranges) +{ + //create some input for encryption + const off_t test_range = 1024*1024; + bufferptr buf(test_range); + char* p = buf.c_str(); + for(size_t i = 0; i < buf.length(); i++) + p[i] = i + i*i + (i >> 2); + + bufferlist input; + input.append(buf); + + uint8_t key[32]; + for(size_t i=0;iencrypt(input, 0, test_range, encrypted, 0)); + + + for (off_t r = 93; r < 150; r++ ) + { + ut_get_sink get_sink; + auto cbc = AES_256_CBC_create(g_ceph_context, &key[0], 32); + ASSERT_NE(cbc.get(), nullptr); + RGWGetObj_BlockDecrypt decrypt(g_ceph_context, &get_sink, std::move(cbc) ); + + //random ranges + off_t begin = (r/3)*r*(r+13)*(r+23)*(r+53)*(r+71) % test_range; + off_t end = begin + (r/5)*(r+7)*(r+13)*(r+101)*(r*103) % (test_range - begin) - 1; + + off_t f_begin = begin; + off_t f_end = end; + decrypt.fixup_range(f_begin, f_end); + decrypt.handle_data(encrypted, f_begin, f_end - f_begin + 1); + decrypt.flush(); + const std::string& decrypted = get_sink.get_sink(); + size_t expected_len = end - begin + 1; + ASSERT_EQ(decrypted.length(), expected_len); + ASSERT_EQ(decrypted, boost::string_ref(input.c_str()+begin, expected_len)); + } +} + + +TEST(TestRGWCrypto, verify_RGWGetObj_BlockDecrypt_chunks) +{ + //create some input for encryption + const off_t test_range = 1024*1024; + bufferptr buf(test_range); + char* p = buf.c_str(); + for(size_t i = 0; i < buf.length(); i++) + p[i] = i + i*i + (i >> 2); + + bufferlist input; + input.append(buf); + + uint8_t key[32]; + for(size_t i=0;iencrypt(input, 0, test_range, encrypted, 0)); + + for (off_t r = 93; r < 150; r++ ) + { + ut_get_sink get_sink; + auto cbc = AES_256_CBC_create(g_ceph_context, &key[0], 32); + ASSERT_NE(cbc.get(), nullptr); + RGWGetObj_BlockDecrypt decrypt(g_ceph_context, &get_sink, std::move(cbc) ); + + //random + off_t begin = (r/3)*r*(r+13)*(r+23)*(r+53)*(r+71) % test_range; + off_t end = begin + (r/5)*(r+7)*(r+13)*(r+101)*(r*103) % (test_range - begin) - 1; + + off_t f_begin = begin; + off_t f_end = end; + decrypt.fixup_range(f_begin, f_end); + off_t pos = f_begin; + do + { + off_t size = 2 << ((pos * 17 + pos / 113 + r) % 16); + size = (pos + 1117) * (pos + 2229) % size + 1; + if (pos + size > f_end + 1) + size = f_end + 1 - pos; + + decrypt.handle_data(encrypted, pos, size); + pos = pos + size; + } while (pos < f_end + 1); + decrypt.flush(); + + const std::string& decrypted = get_sink.get_sink(); + size_t expected_len = end - begin + 1; + ASSERT_EQ(decrypted.length(), expected_len); + ASSERT_EQ(decrypted, boost::string_ref(input.c_str()+begin, expected_len)); + } +} + + +using range_t = std::pair; + +// call filter->fixup_range() and return the range as a pair. this makes it easy +// to fit on a single line for ASSERT_EQ() +range_t fixup_range(RGWGetObj_BlockDecrypt *decrypt, off_t ofs, off_t end) +{ + decrypt->fixup_range(ofs, end); + return {ofs, end}; +} + +TEST(TestRGWCrypto, check_RGWGetObj_BlockDecrypt_fixup) +{ + ut_get_sink get_sink; + auto nonecrypt = std::unique_ptr(new BlockCryptNone); + RGWGetObj_BlockDecrypt decrypt(g_ceph_context, &get_sink, + std::move(nonecrypt)); + ASSERT_EQ(fixup_range(&decrypt,0,0), range_t(0,255)); + ASSERT_EQ(fixup_range(&decrypt,1,256), range_t(0,511)); + ASSERT_EQ(fixup_range(&decrypt,0,255), range_t(0,255)); + ASSERT_EQ(fixup_range(&decrypt,255,256), range_t(0,511)); + ASSERT_EQ(fixup_range(&decrypt,511,1023), range_t(256,1023)); + ASSERT_EQ(fixup_range(&decrypt,513,1024), range_t(512,1024+255)); +} + + +TEST(TestRGWCrypto, verify_RGWPutObj_BlockEncrypt_chunks) +{ + //create some input for encryption + const off_t test_range = 1024*1024; + bufferptr buf(test_range); + char* p = buf.c_str(); + for(size_t i = 0; i < buf.length(); i++) + p[i] = i + i*i + (i >> 2); + + bufferlist input; + input.append(buf); + + uint8_t key[32]; + for(size_t i=0;i test_size) + size = test_size - pos; + + bufferlist bl; + bl.append(input.c_str()+pos, size); + void* handle; + bool again = false; + rgw_raw_obj ro; + encrypt.handle_data(bl, 0, &handle, nullptr, &again); + encrypt.throttle_data(handle, ro, size, false); + + pos = pos + size; + } while (pos < test_size); + bufferlist bl; + void* handle; + bool again = false; + encrypt.handle_data(bl, 0, &handle, nullptr, &again); + + ASSERT_EQ(put_sink.get_sink().length(), static_cast(test_size)); + + cbc = AES_256_CBC_create(g_ceph_context, &key[0], 32); + ASSERT_NE(cbc.get(), nullptr); + + bufferlist encrypted; + bufferlist decrypted; + encrypted.append(put_sink.get_sink()); + ASSERT_TRUE(cbc->decrypt(encrypted, 0, test_size, decrypted, 0)); + + ASSERT_EQ(decrypted.length(), test_size); + ASSERT_EQ(boost::string_ref(decrypted.c_str(), test_size), + boost::string_ref(input.c_str(), test_size)); + } +} + + +TEST(TestRGWCrypto, verify_Encrypt_Decrypt) +{ + uint8_t key[32]; + for(size_t i=0;i args; + argv_to_vec(argc, (const char **)argv, args); + + auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0); + common_init_finish(g_ceph_context); + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +