nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* Copyright (c) 2014, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14  
15 #include <string>
16 #include <functional>
17 #include <memory>
18 #include <vector>
19  
20 #include <stdint.h>
21 #include <string.h>
22  
23 #include <openssl/aead.h>
24 #include <openssl/curve25519.h>
25 #include <openssl/digest.h>
26 #include <openssl/err.h>
27 #include <openssl/newhope.h>
28 #include <openssl/nid.h>
29 #include <openssl/rand.h>
30 #include <openssl/rsa.h>
31  
32 #if defined(OPENSSL_WINDOWS)
33 #pragma warning(push, 3)
34 #include <windows.h>
35 #pragma warning(pop)
36 #elif defined(OPENSSL_APPLE)
37 #include <sys/time.h>
38 #endif
39  
40 #include "../crypto/test/scoped_types.h"
41 #include "internal.h"
42  
43  
44 // TimeResults represents the results of benchmarking a function.
45 struct TimeResults {
46 // num_calls is the number of function calls done in the time period.
47 unsigned num_calls;
48 // us is the number of microseconds that elapsed in the time period.
49 unsigned us;
50  
51 void Print(const std::string &description) {
52 printf("Did %u %s operations in %uus (%.1f ops/sec)\n", num_calls,
53 description.c_str(), us,
54 (static_cast<double>(num_calls) / us) * 1000000);
55 }
56  
57 void PrintWithBytes(const std::string &description, size_t bytes_per_call) {
58 printf("Did %u %s operations in %uus (%.1f ops/sec): %.1f MB/s\n",
59 num_calls, description.c_str(), us,
60 (static_cast<double>(num_calls) / us) * 1000000,
61 static_cast<double>(bytes_per_call * num_calls) / us);
62 }
63 };
64  
65 #if defined(OPENSSL_WINDOWS)
66 static uint64_t time_now() { return GetTickCount64() * 1000; }
67 #elif defined(OPENSSL_APPLE)
68 static uint64_t time_now() {
69 struct timeval tv;
70 uint64_t ret;
71  
72 gettimeofday(&tv, NULL);
73 ret = tv.tv_sec;
74 ret *= 1000000;
75 ret += tv.tv_usec;
76 return ret;
77 }
78 #else
79 static uint64_t time_now() {
80 struct timespec ts;
81 clock_gettime(CLOCK_MONOTONIC, &ts);
82  
83 uint64_t ret = ts.tv_sec;
84 ret *= 1000000;
85 ret += ts.tv_nsec / 1000;
86 return ret;
87 }
88 #endif
89  
90 static bool TimeFunction(TimeResults *results, std::function<bool()> func) {
91 // kTotalMS is the total amount of time that we'll aim to measure a function
92 // for.
93 static const uint64_t kTotalUS = 1000000;
94 uint64_t start = time_now(), now, delta;
95 unsigned done = 0, iterations_between_time_checks;
96  
97 if (!func()) {
98 return false;
99 }
100 now = time_now();
101 delta = now - start;
102 if (delta == 0) {
103 iterations_between_time_checks = 250;
104 } else {
105 // Aim for about 100ms between time checks.
106 iterations_between_time_checks =
107 static_cast<double>(100000) / static_cast<double>(delta);
108 if (iterations_between_time_checks > 1000) {
109 iterations_between_time_checks = 1000;
110 } else if (iterations_between_time_checks < 1) {
111 iterations_between_time_checks = 1;
112 }
113 }
114  
115 for (;;) {
116 for (unsigned i = 0; i < iterations_between_time_checks; i++) {
117 if (!func()) {
118 return false;
119 }
120 done++;
121 }
122  
123 now = time_now();
124 if (now - start > kTotalUS) {
125 break;
126 }
127 }
128  
129 results->us = now - start;
130 results->num_calls = done;
131 return true;
132 }
133  
134 static bool SpeedRSA(const std::string &key_name, RSA *key,
135 const std::string &selected) {
136 if (!selected.empty() && key_name.find(selected) == std::string::npos) {
137 return true;
138 }
139  
140 std::unique_ptr<uint8_t[]> sig(new uint8_t[RSA_size(key)]);
141 const uint8_t fake_sha256_hash[32] = {0};
142 unsigned sig_len;
143  
144 TimeResults results;
145 if (!TimeFunction(&results,
146 [key, &sig, &fake_sha256_hash, &sig_len]() -> bool {
147 return RSA_sign(NID_sha256, fake_sha256_hash, sizeof(fake_sha256_hash),
148 sig.get(), &sig_len, key);
149 })) {
150 fprintf(stderr, "RSA_sign failed.\n");
151 ERR_print_errors_fp(stderr);
152 return false;
153 }
154 results.Print(key_name + " signing");
155  
156 if (!TimeFunction(&results,
157 [key, &fake_sha256_hash, &sig, sig_len]() -> bool {
158 return RSA_verify(NID_sha256, fake_sha256_hash,
159 sizeof(fake_sha256_hash), sig.get(), sig_len, key);
160 })) {
161 fprintf(stderr, "RSA_verify failed.\n");
162 ERR_print_errors_fp(stderr);
163 return false;
164 }
165 results.Print(key_name + " verify");
166  
167 return true;
168 }
169  
170 static uint8_t *align(uint8_t *in, unsigned alignment) {
171 return reinterpret_cast<uint8_t *>(
172 (reinterpret_cast<uintptr_t>(in) + alignment) &
173 ~static_cast<size_t>(alignment - 1));
174 }
175  
176 static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
177 size_t chunk_len, size_t ad_len) {
178 static const unsigned kAlignment = 16;
179  
180 EVP_AEAD_CTX ctx;
181 const size_t key_len = EVP_AEAD_key_length(aead);
182 const size_t nonce_len = EVP_AEAD_nonce_length(aead);
183 const size_t overhead_len = EVP_AEAD_max_overhead(aead);
184  
185 std::unique_ptr<uint8_t[]> key(new uint8_t[key_len]);
186 memset(key.get(), 0, key_len);
187 std::unique_ptr<uint8_t[]> nonce(new uint8_t[nonce_len]);
188 memset(nonce.get(), 0, nonce_len);
189 std::unique_ptr<uint8_t[]> in_storage(new uint8_t[chunk_len + kAlignment]);
190 std::unique_ptr<uint8_t[]> out_storage(new uint8_t[chunk_len + overhead_len + kAlignment]);
191 std::unique_ptr<uint8_t[]> ad(new uint8_t[ad_len]);
192 memset(ad.get(), 0, ad_len);
193  
194 uint8_t *const in = align(in_storage.get(), kAlignment);
195 memset(in, 0, chunk_len);
196 uint8_t *const out = align(out_storage.get(), kAlignment);
197 memset(out, 0, chunk_len + overhead_len);
198  
199 if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, key.get(), key_len,
200 EVP_AEAD_DEFAULT_TAG_LENGTH,
201 evp_aead_seal)) {
202 fprintf(stderr, "Failed to create EVP_AEAD_CTX.\n");
203 ERR_print_errors_fp(stderr);
204 return false;
205 }
206  
207 TimeResults results;
208 if (!TimeFunction(&results, [chunk_len, overhead_len, nonce_len, ad_len, in,
209 out, &ctx, &nonce, &ad]() -> bool {
210 size_t out_len;
211  
212 return EVP_AEAD_CTX_seal(
213 &ctx, out, &out_len, chunk_len + overhead_len, nonce.get(),
214 nonce_len, in, chunk_len, ad.get(), ad_len);
215 })) {
216 fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
217 ERR_print_errors_fp(stderr);
218 return false;
219 }
220  
221 results.PrintWithBytes(name + " seal", chunk_len);
222  
223 EVP_AEAD_CTX_cleanup(&ctx);
224  
225 return true;
226 }
227  
228 static bool SpeedAEAD(const EVP_AEAD *aead, const std::string &name,
229 size_t ad_len, const std::string &selected) {
230 if (!selected.empty() && name.find(selected) == std::string::npos) {
231 return true;
232 }
233  
234 return SpeedAEADChunk(aead, name + " (16 bytes)", 16, ad_len) &&
235 SpeedAEADChunk(aead, name + " (1350 bytes)", 1350, ad_len) &&
236 SpeedAEADChunk(aead, name + " (8192 bytes)", 8192, ad_len);
237 }
238  
239 static bool SpeedHashChunk(const EVP_MD *md, const std::string &name,
240 size_t chunk_len) {
241 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
242 uint8_t scratch[8192];
243  
244 if (chunk_len > sizeof(scratch)) {
245 return false;
246 }
247  
248 TimeResults results;
249 if (!TimeFunction(&results, [ctx, md, chunk_len, &scratch]() -> bool {
250 uint8_t digest[EVP_MAX_MD_SIZE];
251 unsigned int md_len;
252  
253 return EVP_DigestInit_ex(ctx, md, NULL /* ENGINE */) &&
254 EVP_DigestUpdate(ctx, scratch, chunk_len) &&
255 EVP_DigestFinal_ex(ctx, digest, &md_len);
256 })) {
257 fprintf(stderr, "EVP_DigestInit_ex failed.\n");
258 ERR_print_errors_fp(stderr);
259 return false;
260 }
261  
262 results.PrintWithBytes(name, chunk_len);
263  
264 EVP_MD_CTX_destroy(ctx);
265  
266 return true;
267 }
268 static bool SpeedHash(const EVP_MD *md, const std::string &name,
269 const std::string &selected) {
270 if (!selected.empty() && name.find(selected) == std::string::npos) {
271 return true;
272 }
273  
274 return SpeedHashChunk(md, name + " (16 bytes)", 16) &&
275 SpeedHashChunk(md, name + " (256 bytes)", 256) &&
276 SpeedHashChunk(md, name + " (8192 bytes)", 8192);
277 }
278  
279 static bool SpeedRandomChunk(const std::string name, size_t chunk_len) {
280 uint8_t scratch[8192];
281  
282 if (chunk_len > sizeof(scratch)) {
283 return false;
284 }
285  
286 TimeResults results;
287 if (!TimeFunction(&results, [chunk_len, &scratch]() -> bool {
288 RAND_bytes(scratch, chunk_len);
289 return true;
290 })) {
291 return false;
292 }
293  
294 results.PrintWithBytes(name, chunk_len);
295 return true;
296 }
297  
298 static bool SpeedRandom(const std::string &selected) {
299 if (!selected.empty() && selected != "RNG") {
300 return true;
301 }
302  
303 return SpeedRandomChunk("RNG (16 bytes)", 16) &&
304 SpeedRandomChunk("RNG (256 bytes)", 256) &&
305 SpeedRandomChunk("RNG (8192 bytes)", 8192);
306 }
307  
308 static bool SpeedECDHCurve(const std::string &name, int nid,
309 const std::string &selected) {
310 if (!selected.empty() && name.find(selected) == std::string::npos) {
311 return true;
312 }
313  
314 TimeResults results;
315 if (!TimeFunction(&results, [nid]() -> bool {
316 ScopedEC_KEY key(EC_KEY_new_by_curve_name(nid));
317 if (!key ||
318 !EC_KEY_generate_key(key.get())) {
319 return false;
320 }
321 const EC_GROUP *const group = EC_KEY_get0_group(key.get());
322 ScopedEC_POINT point(EC_POINT_new(group));
323 ScopedBN_CTX ctx(BN_CTX_new());
324  
325 ScopedBIGNUM x(BN_new());
326 ScopedBIGNUM y(BN_new());
327  
328 if (!point || !ctx || !x || !y ||
329 !EC_POINT_mul(group, point.get(), NULL,
330 EC_KEY_get0_public_key(key.get()),
331 EC_KEY_get0_private_key(key.get()), ctx.get()) ||
332 !EC_POINT_get_affine_coordinates_GFp(group, point.get(), x.get(),
333 y.get(), ctx.get())) {
334 return false;
335 }
336  
337 return true;
338 })) {
339 return false;
340 }
341  
342 results.Print(name);
343 return true;
344 }
345  
346 static bool SpeedECDSACurve(const std::string &name, int nid,
347 const std::string &selected) {
348 if (!selected.empty() && name.find(selected) == std::string::npos) {
349 return true;
350 }
351  
352 ScopedEC_KEY key(EC_KEY_new_by_curve_name(nid));
353 if (!key ||
354 !EC_KEY_generate_key(key.get())) {
355 return false;
356 }
357  
358 uint8_t signature[256];
359 if (ECDSA_size(key.get()) > sizeof(signature)) {
360 return false;
361 }
362 uint8_t digest[20];
363 memset(digest, 42, sizeof(digest));
364 unsigned sig_len;
365  
366 TimeResults results;
367 if (!TimeFunction(&results, [&key, &signature, &digest, &sig_len]() -> bool {
368 return ECDSA_sign(0, digest, sizeof(digest), signature, &sig_len,
369 key.get()) == 1;
370 })) {
371 return false;
372 }
373  
374 results.Print(name + " signing");
375  
376 if (!TimeFunction(&results, [&key, &signature, &digest, sig_len]() -> bool {
377 return ECDSA_verify(0, digest, sizeof(digest), signature, sig_len,
378 key.get()) == 1;
379 })) {
380 return false;
381 }
382  
383 results.Print(name + " verify");
384  
385 return true;
386 }
387  
388 static bool SpeedECDH(const std::string &selected) {
389 return SpeedECDHCurve("ECDH P-224", NID_secp224r1, selected) &&
390 SpeedECDHCurve("ECDH P-256", NID_X9_62_prime256v1, selected) &&
391 SpeedECDHCurve("ECDH P-384", NID_secp384r1, selected) &&
392 SpeedECDHCurve("ECDH P-521", NID_secp521r1, selected);
393 }
394  
395 static bool SpeedECDSA(const std::string &selected) {
396 return SpeedECDSACurve("ECDSA P-224", NID_secp224r1, selected) &&
397 SpeedECDSACurve("ECDSA P-256", NID_X9_62_prime256v1, selected) &&
398 SpeedECDSACurve("ECDSA P-384", NID_secp384r1, selected) &&
399 SpeedECDSACurve("ECDSA P-521", NID_secp521r1, selected);
400 }
401  
402 static bool Speed25519(const std::string &selected) {
403 if (!selected.empty() && selected.find("25519") == std::string::npos) {
404 return true;
405 }
406  
407 TimeResults results;
408  
409 uint8_t public_key[32], private_key[64];
410  
411 if (!TimeFunction(&results, [&public_key, &private_key]() -> bool {
412 ED25519_keypair(public_key, private_key);
413 return true;
414 })) {
415 return false;
416 }
417  
418 results.Print("Ed25519 key generation");
419  
420 static const uint8_t kMessage[] = {0, 1, 2, 3, 4, 5};
421 uint8_t signature[64];
422  
423 if (!TimeFunction(&results, [&private_key, &signature]() -> bool {
424 return ED25519_sign(signature, kMessage, sizeof(kMessage),
425 private_key) == 1;
426 })) {
427 return false;
428 }
429  
430 results.Print("Ed25519 signing");
431  
432 if (!TimeFunction(&results, [&public_key, &signature]() -> bool {
433 return ED25519_verify(kMessage, sizeof(kMessage), signature,
434 public_key) == 1;
435 })) {
436 fprintf(stderr, "Ed25519 verify failed.\n");
437 return false;
438 }
439  
440 results.Print("Ed25519 verify");
441  
442 if (!TimeFunction(&results, []() -> bool {
443 uint8_t out[32], in[32];
444 memset(in, 0, sizeof(in));
445 X25519_public_from_private(out, in);
446 return true;
447 })) {
448 fprintf(stderr, "Curve25519 base-point multiplication failed.\n");
449 return false;
450 }
451  
452 results.Print("Curve25519 base-point multiplication");
453  
454 if (!TimeFunction(&results, []() -> bool {
455 uint8_t out[32], in1[32], in2[32];
456 memset(in1, 0, sizeof(in1));
457 memset(in2, 0, sizeof(in2));
458 in1[0] = 1;
459 in2[0] = 9;
460 return X25519(out, in1, in2) == 1;
461 })) {
462 fprintf(stderr, "Curve25519 arbitrary point multiplication failed.\n");
463 return false;
464 }
465  
466 results.Print("Curve25519 arbitrary point multiplication");
467  
468 return true;
469 }
470  
471 static bool SpeedSPAKE2(const std::string &selected) {
472 if (!selected.empty() && selected.find("SPAKE2") == std::string::npos) {
473 return true;
474 }
475  
476 TimeResults results;
477  
478 static const uint8_t kAliceName[] = {'A'};
479 static const uint8_t kBobName[] = {'B'};
480 static const uint8_t kPassword[] = "password";
481 ScopedSPAKE2_CTX alice(SPAKE2_CTX_new(spake2_role_alice, kAliceName,
482 sizeof(kAliceName), kBobName,
483 sizeof(kBobName)));
484 uint8_t alice_msg[SPAKE2_MAX_MSG_SIZE];
485 size_t alice_msg_len;
486  
487 if (!SPAKE2_generate_msg(alice.get(), alice_msg, &alice_msg_len,
488 sizeof(alice_msg),
489 kPassword, sizeof(kPassword))) {
490 fprintf(stderr, "SPAKE2_generate_msg failed.\n");
491 return false;
492 }
493  
494 if (!TimeFunction(&results, [&alice_msg, alice_msg_len]() -> bool {
495 ScopedSPAKE2_CTX bob(SPAKE2_CTX_new(spake2_role_bob, kBobName,
496 sizeof(kBobName), kAliceName,
497 sizeof(kAliceName)));
498 uint8_t bob_msg[SPAKE2_MAX_MSG_SIZE], bob_key[64];
499 size_t bob_msg_len, bob_key_len;
500 if (!SPAKE2_generate_msg(bob.get(), bob_msg, &bob_msg_len,
501 sizeof(bob_msg), kPassword,
502 sizeof(kPassword)) ||
503 !SPAKE2_process_msg(bob.get(), bob_key, &bob_key_len,
504 sizeof(bob_key), alice_msg, alice_msg_len)) {
505 return false;
506 }
507  
508 return true;
509 })) {
510 fprintf(stderr, "SPAKE2 failed.\n");
511 }
512  
513 results.Print("SPAKE2 over Ed25519");
514  
515 return true;
516 }
517  
518 static bool SpeedNewHope(const std::string &selected) {
519 if (!selected.empty() && selected.find("newhope") == std::string::npos) {
520 return true;
521 }
522  
523 TimeResults results;
524 NEWHOPE_POLY *sk = NEWHOPE_POLY_new();
525 uint8_t clientmsg[NEWHOPE_CLIENTMSG_LENGTH];
526 RAND_bytes(clientmsg, sizeof(clientmsg));
527  
528 if (!TimeFunction(&results, [sk, &clientmsg]() -> bool {
529 uint8_t server_key[SHA256_DIGEST_LENGTH];
530 uint8_t servermsg[NEWHOPE_SERVERMSG_LENGTH];
531 NEWHOPE_keygen(servermsg, sk);
532 if (!NEWHOPE_server_compute_key(server_key, sk, clientmsg,
533 NEWHOPE_CLIENTMSG_LENGTH)) {
534 return false;
535 }
536 return true;
537 })) {
538 fprintf(stderr, "failed to exchange key.\n");
539 return false;
540 }
541  
542 NEWHOPE_POLY_free(sk);
543 results.Print("newhope server key exchange");
544 return true;
545 }
546  
547 bool Speed(const std::vector<std::string> &args) {
548 std::string selected;
549 if (args.size() > 1) {
550 fprintf(stderr, "Usage: bssl speed [speed test selector, i.e. 'RNG']\n");
551 return false;
552 }
553 if (args.size() > 0) {
554 selected = args[0];
555 }
556  
557 RSA *key = RSA_private_key_from_bytes(kDERRSAPrivate2048,
558 kDERRSAPrivate2048Len);
559 if (key == NULL) {
560 fprintf(stderr, "Failed to parse RSA key.\n");
561 ERR_print_errors_fp(stderr);
562 return false;
563 }
564  
565 if (!SpeedRSA("RSA 2048", key, selected)) {
566 return false;
567 }
568  
569 RSA_free(key);
570 key = RSA_private_key_from_bytes(kDERRSAPrivate3Prime2048,
571 kDERRSAPrivate3Prime2048Len);
572 if (key == NULL) {
573 fprintf(stderr, "Failed to parse RSA key.\n");
574 ERR_print_errors_fp(stderr);
575 return false;
576 }
577  
578 if (!SpeedRSA("RSA 2048 (3 prime, e=3)", key, selected)) {
579 return false;
580 }
581  
582 RSA_free(key);
583 key = RSA_private_key_from_bytes(kDERRSAPrivate4096,
584 kDERRSAPrivate4096Len);
585 if (key == NULL) {
586 fprintf(stderr, "Failed to parse 4096-bit RSA key.\n");
587 ERR_print_errors_fp(stderr);
588 return 1;
589 }
590  
591 if (!SpeedRSA("RSA 4096", key, selected)) {
592 return false;
593 }
594  
595 RSA_free(key);
596  
597 // kTLSADLen is the number of bytes of additional data that TLS passes to
598 // AEADs.
599 static const size_t kTLSADLen = 13;
600 // kLegacyADLen is the number of bytes that TLS passes to the "legacy" AEADs.
601 // These are AEADs that weren't originally defined as AEADs, but which we use
602 // via the AEAD interface. In order for that to work, they have some TLS
603 // knowledge in them and construct a couple of the AD bytes internally.
604 static const size_t kLegacyADLen = kTLSADLen - 2;
605  
606 if (!SpeedAEAD(EVP_aead_aes_128_gcm(), "AES-128-GCM", kTLSADLen, selected) ||
607 !SpeedAEAD(EVP_aead_aes_256_gcm(), "AES-256-GCM", kTLSADLen, selected) ||
608 !SpeedAEAD(EVP_aead_chacha20_poly1305(), "ChaCha20-Poly1305", kTLSADLen,
609 selected) ||
610 !SpeedAEAD(EVP_aead_chacha20_poly1305_old(), "ChaCha20-Poly1305-Old",
611 kTLSADLen, selected) ||
612 !SpeedAEAD(EVP_aead_rc4_md5_tls(), "RC4-MD5", kLegacyADLen, selected) ||
613 !SpeedAEAD(EVP_aead_rc4_sha1_tls(), "RC4-SHA1", kLegacyADLen, selected) ||
614 !SpeedAEAD(EVP_aead_des_ede3_cbc_sha1_tls(), "DES-EDE3-CBC-SHA1",
615 kLegacyADLen, selected) ||
616 !SpeedAEAD(EVP_aead_aes_128_cbc_sha1_tls(), "AES-128-CBC-SHA1",
617 kLegacyADLen, selected) ||
618 !SpeedAEAD(EVP_aead_aes_256_cbc_sha1_tls(), "AES-256-CBC-SHA1",
619 kLegacyADLen, selected) ||
620 !SpeedHash(EVP_sha1(), "SHA-1", selected) ||
621 !SpeedHash(EVP_sha256(), "SHA-256", selected) ||
622 !SpeedHash(EVP_sha512(), "SHA-512", selected) ||
623 !SpeedRandom(selected) ||
624 !SpeedECDH(selected) ||
625 !SpeedECDSA(selected) ||
626 !Speed25519(selected) ||
627 !SpeedSPAKE2(selected) ||
628 !SpeedNewHope(selected)) {
629 return false;
630 }
631  
632 return true;
633 }