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