]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #include <errno.h> |
2 | #include <time.h> | |
3 | ||
11fdf7f2 TL |
4 | #include <boost/container/small_vector.hpp> |
5 | ||
7c673cae FG |
6 | #include "gtest/gtest.h" |
7 | #include "include/types.h" | |
8 | #include "auth/Crypto.h" | |
9 | #include "common/Clock.h" | |
10 | #include "common/ceph_crypto.h" | |
11 | #include "common/ceph_context.h" | |
12 | #include "global/global_context.h" | |
13 | ||
20effc67 | 14 | using namespace std; |
11fdf7f2 | 15 | |
7c673cae FG |
16 | class CryptoEnvironment: public ::testing::Environment { |
17 | public: | |
18 | void SetUp() override { | |
9f95a23c | 19 | ceph::crypto::init(); |
7c673cae FG |
20 | } |
21 | }; | |
22 | ||
23 | TEST(AES, ValidateSecret) { | |
24 | CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); | |
25 | int l; | |
26 | ||
27 | for (l=0; l<16; l++) { | |
28 | bufferptr bp(l); | |
29 | int err; | |
30 | err = h->validate_secret(bp); | |
31 | EXPECT_EQ(-EINVAL, err); | |
32 | } | |
33 | ||
34 | for (l=16; l<50; l++) { | |
35 | bufferptr bp(l); | |
36 | int err; | |
37 | err = h->validate_secret(bp); | |
38 | EXPECT_EQ(0, err); | |
39 | } | |
40 | } | |
41 | ||
42 | TEST(AES, Encrypt) { | |
43 | CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); | |
44 | char secret_s[] = { | |
45 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | |
46 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | |
47 | }; | |
48 | bufferptr secret(secret_s, sizeof(secret_s)); | |
49 | ||
50 | unsigned char plaintext_s[] = { | |
51 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | |
52 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, | |
53 | }; | |
54 | bufferlist plaintext; | |
55 | plaintext.append((char *)plaintext_s, sizeof(plaintext_s)); | |
56 | ||
57 | bufferlist cipher; | |
58 | std::string error; | |
59 | CryptoKeyHandler *kh = h->get_key_handler(secret, error); | |
60 | int r = kh->encrypt(plaintext, cipher, &error); | |
61 | ASSERT_EQ(r, 0); | |
62 | ASSERT_EQ(error, ""); | |
63 | ||
64 | unsigned char want_cipher[] = { | |
65 | 0xb3, 0x8f, 0x5b, 0xc9, 0x35, 0x4c, 0xf8, 0xc6, | |
66 | 0x13, 0x15, 0x66, 0x6f, 0x37, 0xd7, 0x79, 0x3a, | |
67 | 0x11, 0x90, 0x7b, 0xe9, 0xd8, 0x3c, 0x35, 0x70, | |
68 | 0x58, 0x7b, 0x97, 0x9b, 0x03, 0xd2, 0xa5, 0x01, | |
69 | }; | |
70 | char cipher_s[sizeof(want_cipher)]; | |
71 | ||
72 | ASSERT_EQ(sizeof(cipher_s), cipher.length()); | |
9f95a23c | 73 | cipher.cbegin().copy(sizeof(cipher_s), &cipher_s[0]); |
7c673cae FG |
74 | |
75 | int err; | |
76 | err = memcmp(cipher_s, want_cipher, sizeof(want_cipher)); | |
77 | ASSERT_EQ(0, err); | |
78 | ||
79 | delete kh; | |
80 | } | |
81 | ||
11fdf7f2 TL |
82 | TEST(AES, EncryptNoBl) { |
83 | CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); | |
84 | char secret_s[] = { | |
85 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | |
86 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | |
87 | }; | |
88 | bufferptr secret(secret_s, sizeof(secret_s)); | |
89 | ||
90 | const unsigned char plaintext[] = { | |
91 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | |
92 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, | |
93 | }; | |
94 | ||
95 | std::string error; | |
96 | std::unique_ptr<CryptoKeyHandler> kh(h->get_key_handler(secret, error)); | |
97 | ||
98 | const CryptoKey::in_slice_t plain_slice { sizeof(plaintext), plaintext }; | |
99 | ||
100 | // we need to deduce size first | |
101 | const CryptoKey::out_slice_t probe_slice { 0, nullptr }; | |
102 | const auto needed = kh->encrypt(plain_slice, probe_slice); | |
103 | ASSERT_GE(needed, plain_slice.length); | |
104 | ||
105 | boost::container::small_vector< | |
106 | // FIXME? | |
107 | //unsigned char, sizeof(plaintext) + kh->get_block_size()> buf; | |
108 | unsigned char, sizeof(plaintext) + 16> buf(needed); | |
109 | const CryptoKey::out_slice_t cipher_slice { needed, buf.data() }; | |
110 | const auto cipher_size = kh->encrypt(plain_slice, cipher_slice); | |
111 | ASSERT_EQ(cipher_size, needed); | |
112 | ||
113 | const unsigned char want_cipher[] = { | |
114 | 0xb3, 0x8f, 0x5b, 0xc9, 0x35, 0x4c, 0xf8, 0xc6, | |
115 | 0x13, 0x15, 0x66, 0x6f, 0x37, 0xd7, 0x79, 0x3a, | |
116 | 0x11, 0x90, 0x7b, 0xe9, 0xd8, 0x3c, 0x35, 0x70, | |
117 | 0x58, 0x7b, 0x97, 0x9b, 0x03, 0xd2, 0xa5, 0x01, | |
118 | }; | |
119 | ||
120 | ASSERT_EQ(sizeof(want_cipher), cipher_size); | |
121 | ||
122 | const int err = memcmp(buf.data(), want_cipher, sizeof(want_cipher)); | |
123 | ASSERT_EQ(0, err); | |
124 | } | |
125 | ||
7c673cae FG |
126 | TEST(AES, Decrypt) { |
127 | CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); | |
128 | char secret_s[] = { | |
129 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | |
130 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | |
131 | }; | |
132 | bufferptr secret(secret_s, sizeof(secret_s)); | |
133 | ||
134 | unsigned char cipher_s[] = { | |
135 | 0xb3, 0x8f, 0x5b, 0xc9, 0x35, 0x4c, 0xf8, 0xc6, | |
136 | 0x13, 0x15, 0x66, 0x6f, 0x37, 0xd7, 0x79, 0x3a, | |
137 | 0x11, 0x90, 0x7b, 0xe9, 0xd8, 0x3c, 0x35, 0x70, | |
138 | 0x58, 0x7b, 0x97, 0x9b, 0x03, 0xd2, 0xa5, 0x01, | |
139 | }; | |
140 | bufferlist cipher; | |
141 | cipher.append((char *)cipher_s, sizeof(cipher_s)); | |
142 | ||
143 | unsigned char want_plaintext[] = { | |
144 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | |
145 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, | |
146 | }; | |
147 | char plaintext_s[sizeof(want_plaintext)]; | |
148 | ||
149 | std::string error; | |
150 | bufferlist plaintext; | |
151 | CryptoKeyHandler *kh = h->get_key_handler(secret, error); | |
152 | int r = kh->decrypt(cipher, plaintext, &error); | |
153 | ASSERT_EQ(r, 0); | |
154 | ASSERT_EQ(error, ""); | |
155 | ||
156 | ASSERT_EQ(sizeof(plaintext_s), plaintext.length()); | |
9f95a23c | 157 | plaintext.cbegin().copy(sizeof(plaintext_s), &plaintext_s[0]); |
7c673cae FG |
158 | |
159 | int err; | |
160 | err = memcmp(plaintext_s, want_plaintext, sizeof(want_plaintext)); | |
161 | ASSERT_EQ(0, err); | |
162 | ||
163 | delete kh; | |
164 | } | |
165 | ||
11fdf7f2 TL |
166 | TEST(AES, DecryptNoBl) { |
167 | CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); | |
168 | const char secret_s[] = { | |
169 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | |
170 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | |
171 | }; | |
7c673cae FG |
172 | bufferptr secret(secret_s, sizeof(secret_s)); |
173 | ||
11fdf7f2 TL |
174 | const unsigned char ciphertext[] = { |
175 | 0xb3, 0x8f, 0x5b, 0xc9, 0x35, 0x4c, 0xf8, 0xc6, | |
176 | 0x13, 0x15, 0x66, 0x6f, 0x37, 0xd7, 0x79, 0x3a, | |
177 | 0x11, 0x90, 0x7b, 0xe9, 0xd8, 0x3c, 0x35, 0x70, | |
178 | 0x58, 0x7b, 0x97, 0x9b, 0x03, 0xd2, 0xa5, 0x01, | |
179 | }; | |
180 | ||
181 | const unsigned char want_plaintext[] = { | |
182 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | |
183 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, | |
184 | }; | |
185 | constexpr static std::size_t plain_buf_size = \ | |
186 | CryptoKey::get_max_outbuf_size(sizeof(want_plaintext)); | |
187 | unsigned char plaintext[plain_buf_size]; | |
188 | ||
189 | std::string error; | |
190 | std::unique_ptr<CryptoKeyHandler> kh(h->get_key_handler(secret, error)); | |
191 | ||
192 | CryptoKey::in_slice_t cipher_slice { sizeof(ciphertext), ciphertext }; | |
193 | CryptoKey::out_slice_t plain_slice { sizeof(plaintext), plaintext }; | |
194 | const auto plain_size = kh->decrypt(cipher_slice, plain_slice); | |
195 | ||
196 | ASSERT_EQ(plain_size, sizeof(want_plaintext)); | |
197 | ||
198 | const int err = memcmp(plaintext, want_plaintext, sizeof(plain_size)); | |
7c673cae | 199 | ASSERT_EQ(0, err); |
11fdf7f2 TL |
200 | } |
201 | ||
202 | template <std::size_t TextSizeV> | |
203 | static void aes_loop_cephx() { | |
204 | CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); | |
205 | ||
206 | CryptoRandom random; | |
207 | ||
208 | bufferptr secret(16); | |
209 | random.get_bytes(secret.c_str(), secret.length()); | |
210 | std::string error; | |
211 | std::unique_ptr<CryptoKeyHandler> kh(h->get_key_handler(secret, error)); | |
212 | ||
213 | unsigned char plaintext[TextSizeV]; | |
214 | random.get_bytes(reinterpret_cast<char*>(plaintext), sizeof(plaintext)); | |
215 | ||
216 | const CryptoKey::in_slice_t plain_slice { sizeof(plaintext), plaintext }; | |
217 | ||
218 | // we need to deduce size first | |
219 | const CryptoKey::out_slice_t probe_slice { 0, nullptr }; | |
220 | const auto needed = kh->encrypt(plain_slice, probe_slice); | |
221 | ASSERT_GE(needed, plain_slice.length); | |
222 | ||
223 | boost::container::small_vector< | |
224 | // FIXME? | |
225 | //unsigned char, sizeof(plaintext) + kh->get_block_size()> buf; | |
226 | unsigned char, sizeof(plaintext) + 16> buf(needed); | |
227 | ||
228 | std::size_t cipher_size; | |
229 | for (std::size_t i = 0; i < 1000000; i++) { | |
230 | const CryptoKey::out_slice_t cipher_slice { needed, buf.data() }; | |
231 | cipher_size = kh->encrypt(plain_slice, cipher_slice); | |
232 | ASSERT_EQ(cipher_size, needed); | |
233 | } | |
234 | } | |
235 | ||
236 | // These magics reflects Cephx's signature size. Please consult | |
237 | // CephxSessionHandler::_calc_signature() for more details. | |
238 | TEST(AES, LoopCephx) { | |
239 | aes_loop_cephx<29>(); | |
240 | } | |
241 | ||
242 | TEST(AES, LoopCephxV2) { | |
243 | aes_loop_cephx<32>(); | |
244 | } | |
245 | ||
246 | static void aes_loop(const std::size_t text_size) { | |
247 | CryptoRandom random; | |
248 | ||
249 | bufferptr secret(16); | |
250 | random.get_bytes(secret.c_str(), secret.length()); | |
251 | ||
252 | bufferptr orig_plaintext(text_size); | |
253 | random.get_bytes(orig_plaintext.c_str(), orig_plaintext.length()); | |
7c673cae FG |
254 | |
255 | bufferlist plaintext; | |
11fdf7f2 | 256 | plaintext.append(orig_plaintext.c_str(), orig_plaintext.length()); |
7c673cae FG |
257 | |
258 | for (int i=0; i<10000; i++) { | |
259 | bufferlist cipher; | |
260 | { | |
261 | CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); | |
262 | ||
263 | std::string error; | |
264 | CryptoKeyHandler *kh = h->get_key_handler(secret, error); | |
265 | int r = kh->encrypt(plaintext, cipher, &error); | |
266 | ASSERT_EQ(r, 0); | |
267 | ASSERT_EQ(error, ""); | |
268 | ||
269 | delete kh; | |
270 | } | |
271 | plaintext.clear(); | |
272 | ||
273 | { | |
274 | CryptoHandler *h = g_ceph_context->get_crypto_handler(CEPH_CRYPTO_AES); | |
275 | std::string error; | |
276 | CryptoKeyHandler *ckh = h->get_key_handler(secret, error); | |
277 | int r = ckh->decrypt(cipher, plaintext, &error); | |
278 | ASSERT_EQ(r, 0); | |
279 | ASSERT_EQ(error, ""); | |
280 | ||
281 | delete ckh; | |
282 | } | |
283 | } | |
284 | ||
11fdf7f2 TL |
285 | bufferlist orig; |
286 | orig.append(orig_plaintext); | |
287 | ASSERT_EQ(orig, plaintext); | |
7c673cae FG |
288 | } |
289 | ||
11fdf7f2 TL |
290 | TEST(AES, Loop) { |
291 | aes_loop(256); | |
292 | } | |
293 | ||
294 | // These magics reflects Cephx's signature size. Please consult | |
295 | // CephxSessionHandler::_calc_signature() for more details. | |
296 | TEST(AES, Loop_29) { | |
297 | aes_loop(29); | |
298 | } | |
299 | ||
300 | TEST(AES, Loop_32) { | |
301 | aes_loop(32); | |
302 | } | |
303 | ||
304 | void aes_loopkey(const std::size_t text_size) { | |
305 | CryptoRandom random; | |
7c673cae | 306 | bufferptr k(16); |
11fdf7f2 | 307 | random.get_bytes(k.c_str(), k.length()); |
7c673cae FG |
308 | CryptoKey key(CEPH_CRYPTO_AES, ceph_clock_now(), k); |
309 | ||
310 | bufferlist data; | |
11fdf7f2 TL |
311 | bufferptr r(text_size); |
312 | random.get_bytes(r.c_str(), r.length()); | |
7c673cae FG |
313 | data.append(r); |
314 | ||
315 | utime_t start = ceph_clock_now(); | |
316 | int n = 100000; | |
317 | ||
318 | for (int i=0; i<n; ++i) { | |
319 | bufferlist encoded; | |
320 | string error; | |
321 | int r = key.encrypt(g_ceph_context, data, encoded, &error); | |
322 | ASSERT_EQ(r, 0); | |
323 | } | |
324 | ||
325 | utime_t end = ceph_clock_now(); | |
326 | utime_t dur = end - start; | |
327 | cout << n << " encoded in " << dur << std::endl; | |
328 | } | |
11fdf7f2 TL |
329 | |
330 | TEST(AES, LoopKey) { | |
331 | aes_loopkey(128); | |
332 | } | |
333 | ||
334 | // These magics reflects Cephx's signature size. Please consult | |
335 | // CephxSessionHandler::_calc_signature() for more details. | |
336 | TEST(AES, LoopKey_29) { | |
337 | aes_loopkey(29); | |
338 | } | |
339 | ||
340 | TEST(AES, LoopKey_32) { | |
341 | aes_loopkey(32); | |
342 | } |