blob: 780a7ea12485eac916d76f8d0092283b5d09a45a [file] [log] [blame]
Adam Langleyc5c0c7e2014-06-20 12:00:00 -07001/* 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>
David Benjaminbcb65b92016-08-14 22:06:49 -040021#include <stdlib.h>
Adam Langley2b2d66d2015-01-30 17:08:37 -080022#include <string.h>
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070023
Adam Langley92b6b022015-04-16 14:01:33 -070024#include <openssl/aead.h>
Adam Langley4fb0dc42015-11-13 13:09:47 -080025#include <openssl/curve25519.h>
Adam Langley92b6b022015-04-16 14:01:33 -070026#include <openssl/digest.h>
27#include <openssl/err.h>
Matt Braithwaite045a0ff2016-04-18 11:30:19 -070028#include <openssl/newhope.h>
David Benjamin98193672016-03-25 18:07:11 -040029#include <openssl/nid.h>
Adam Langley92b6b022015-04-16 14:01:33 -070030#include <openssl/rand.h>
31#include <openssl/rsa.h>
32
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070033#if defined(OPENSSL_WINDOWS)
David Benjamina353cdb2016-06-09 16:48:33 -040034OPENSSL_MSVC_PRAGMA(warning(push, 3))
Adam Langley3e719312015-03-20 16:32:23 -070035#include <windows.h>
David Benjamina353cdb2016-06-09 16:48:33 -040036OPENSSL_MSVC_PRAGMA(warning(pop))
Adam Langley30eda1d2014-06-24 11:15:12 -070037#elif defined(OPENSSL_APPLE)
38#include <sys/time.h>
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070039#endif
40
Adam Langleyd2b5af52016-07-12 08:03:59 -070041#include "../crypto/test/scoped_types.h"
David Benjamin58084af2015-06-07 00:25:15 -040042#include "internal.h"
Adam Langleyad6b28e2015-04-14 12:07:44 -070043
Adam Langley2b2d66d2015-01-30 17:08:37 -080044
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070045// TimeResults represents the results of benchmarking a function.
46struct TimeResults {
47 // num_calls is the number of function calls done in the time period.
48 unsigned num_calls;
49 // us is the number of microseconds that elapsed in the time period.
50 unsigned us;
51
52 void Print(const std::string &description) {
53 printf("Did %u %s operations in %uus (%.1f ops/sec)\n", num_calls,
54 description.c_str(), us,
55 (static_cast<double>(num_calls) / us) * 1000000);
56 }
57
58 void PrintWithBytes(const std::string &description, size_t bytes_per_call) {
59 printf("Did %u %s operations in %uus (%.1f ops/sec): %.1f MB/s\n",
60 num_calls, description.c_str(), us,
61 (static_cast<double>(num_calls) / us) * 1000000,
62 static_cast<double>(bytes_per_call * num_calls) / us);
63 }
64};
65
66#if defined(OPENSSL_WINDOWS)
67static uint64_t time_now() { return GetTickCount64() * 1000; }
Adam Langley30eda1d2014-06-24 11:15:12 -070068#elif defined(OPENSSL_APPLE)
69static uint64_t time_now() {
70 struct timeval tv;
71 uint64_t ret;
72
73 gettimeofday(&tv, NULL);
74 ret = tv.tv_sec;
75 ret *= 1000000;
76 ret += tv.tv_usec;
77 return ret;
78}
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070079#else
80static uint64_t time_now() {
81 struct timespec ts;
82 clock_gettime(CLOCK_MONOTONIC, &ts);
83
84 uint64_t ret = ts.tv_sec;
85 ret *= 1000000;
86 ret += ts.tv_nsec / 1000;
87 return ret;
88}
89#endif
90
David Benjaminbcb65b92016-08-14 22:06:49 -040091static uint64_t g_timeout_seconds = 1;
92
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070093static bool TimeFunction(TimeResults *results, std::function<bool()> func) {
David Benjaminbcb65b92016-08-14 22:06:49 -040094 // total_us is the total amount of time that we'll aim to measure a function
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070095 // for.
David Benjaminbcb65b92016-08-14 22:06:49 -040096 const uint64_t total_us = g_timeout_seconds * 1000000;
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070097 uint64_t start = time_now(), now, delta;
98 unsigned done = 0, iterations_between_time_checks;
99
100 if (!func()) {
101 return false;
102 }
103 now = time_now();
104 delta = now - start;
105 if (delta == 0) {
106 iterations_between_time_checks = 250;
107 } else {
108 // Aim for about 100ms between time checks.
109 iterations_between_time_checks =
110 static_cast<double>(100000) / static_cast<double>(delta);
111 if (iterations_between_time_checks > 1000) {
112 iterations_between_time_checks = 1000;
113 } else if (iterations_between_time_checks < 1) {
114 iterations_between_time_checks = 1;
115 }
116 }
117
118 for (;;) {
119 for (unsigned i = 0; i < iterations_between_time_checks; i++) {
120 if (!func()) {
121 return false;
122 }
123 done++;
124 }
125
126 now = time_now();
David Benjaminbcb65b92016-08-14 22:06:49 -0400127 if (now - start > total_us) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700128 break;
129 }
130 }
131
132 results->us = now - start;
133 results->num_calls = done;
134 return true;
135}
136
Adam Langley90b58402015-04-13 11:04:18 -0700137static bool SpeedRSA(const std::string &key_name, RSA *key,
138 const std::string &selected) {
139 if (!selected.empty() && key_name.find(selected) == std::string::npos) {
140 return true;
141 }
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700142
143 std::unique_ptr<uint8_t[]> sig(new uint8_t[RSA_size(key)]);
144 const uint8_t fake_sha256_hash[32] = {0};
145 unsigned sig_len;
146
Adam Langley90b58402015-04-13 11:04:18 -0700147 TimeResults results;
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700148 if (!TimeFunction(&results,
149 [key, &sig, &fake_sha256_hash, &sig_len]() -> bool {
Brian Smith7bee8532016-08-19 15:11:20 -1000150 /* Usually during RSA signing we're using a long-lived |RSA| that has
151 * already had all of its |BN_MONT_CTX|s constructed, so it makes
152 * sense to use |key| directly here. */
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700153 return RSA_sign(NID_sha256, fake_sha256_hash, sizeof(fake_sha256_hash),
154 sig.get(), &sig_len, key);
155 })) {
156 fprintf(stderr, "RSA_sign failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000157 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700158 return false;
159 }
160 results.Print(key_name + " signing");
161
162 if (!TimeFunction(&results,
163 [key, &fake_sha256_hash, &sig, sig_len]() -> bool {
Brian Smith7bee8532016-08-19 15:11:20 -1000164 /* Usually during RSA verification we have to parse an RSA key from a
165 * certificate or similar, in which case we'd need to construct a new
166 * RSA key, with a new |BN_MONT_CTX| for the public modulus. If we were
167 * to use |key| directly instead, then these costs wouldn't be
168 * accounted for. */
169 ScopedRSA verify_key(RSA_new());
170 if (!verify_key) {
171 return false;
172 }
173 verify_key->n = BN_dup(key->n);
174 verify_key->e = BN_dup(key->e);
175 if (!verify_key->n ||
176 !verify_key->e) {
177 return false;
178 }
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700179 return RSA_verify(NID_sha256, fake_sha256_hash,
180 sizeof(fake_sha256_hash), sig.get(), sig_len, key);
181 })) {
182 fprintf(stderr, "RSA_verify failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000183 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700184 return false;
185 }
186 results.Print(key_name + " verify");
187
188 return true;
189}
190
Adam Langley26725342015-01-28 15:52:57 -0800191static uint8_t *align(uint8_t *in, unsigned alignment) {
192 return reinterpret_cast<uint8_t *>(
Brian Smithd53b2c32015-03-17 00:37:06 -1000193 (reinterpret_cast<uintptr_t>(in) + alignment) &
194 ~static_cast<size_t>(alignment - 1));
David Benjamin384673c2015-01-21 15:56:14 -0500195}
Adam Langley543d0062015-01-15 16:05:41 -0800196
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700197static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
Adam Langleye7624342015-01-15 17:33:48 -0800198 size_t chunk_len, size_t ad_len) {
Adam Langley26725342015-01-28 15:52:57 -0800199 static const unsigned kAlignment = 16;
200
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700201 EVP_AEAD_CTX ctx;
202 const size_t key_len = EVP_AEAD_key_length(aead);
203 const size_t nonce_len = EVP_AEAD_nonce_length(aead);
204 const size_t overhead_len = EVP_AEAD_max_overhead(aead);
205
206 std::unique_ptr<uint8_t[]> key(new uint8_t[key_len]);
207 memset(key.get(), 0, key_len);
208 std::unique_ptr<uint8_t[]> nonce(new uint8_t[nonce_len]);
209 memset(nonce.get(), 0, nonce_len);
Brian Smith1d1562d2015-03-17 00:32:20 -1000210 std::unique_ptr<uint8_t[]> in_storage(new uint8_t[chunk_len + kAlignment]);
211 std::unique_ptr<uint8_t[]> out_storage(new uint8_t[chunk_len + overhead_len + kAlignment]);
Adam Langleye7624342015-01-15 17:33:48 -0800212 std::unique_ptr<uint8_t[]> ad(new uint8_t[ad_len]);
213 memset(ad.get(), 0, ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700214
Adam Langley26725342015-01-28 15:52:57 -0800215 uint8_t *const in = align(in_storage.get(), kAlignment);
216 memset(in, 0, chunk_len);
217 uint8_t *const out = align(out_storage.get(), kAlignment);
218 memset(out, 0, chunk_len + overhead_len);
219
David Benjamind434f282015-03-17 18:28:37 -0400220 if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, key.get(), key_len,
221 EVP_AEAD_DEFAULT_TAG_LENGTH,
222 evp_aead_seal)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700223 fprintf(stderr, "Failed to create EVP_AEAD_CTX.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000224 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700225 return false;
226 }
227
228 TimeResults results;
Adam Langley26725342015-01-28 15:52:57 -0800229 if (!TimeFunction(&results, [chunk_len, overhead_len, nonce_len, ad_len, in,
230 out, &ctx, &nonce, &ad]() -> bool {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700231 size_t out_len;
232
Adam Langleye7624342015-01-15 17:33:48 -0800233 return EVP_AEAD_CTX_seal(
Adam Langley26725342015-01-28 15:52:57 -0800234 &ctx, out, &out_len, chunk_len + overhead_len, nonce.get(),
235 nonce_len, in, chunk_len, ad.get(), ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700236 })) {
237 fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000238 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700239 return false;
240 }
241
242 results.PrintWithBytes(name + " seal", chunk_len);
243
244 EVP_AEAD_CTX_cleanup(&ctx);
245
246 return true;
247}
248
Adam Langleye7624342015-01-15 17:33:48 -0800249static bool SpeedAEAD(const EVP_AEAD *aead, const std::string &name,
Adam Langley90b58402015-04-13 11:04:18 -0700250 size_t ad_len, const std::string &selected) {
251 if (!selected.empty() && name.find(selected) == std::string::npos) {
252 return true;
253 }
254
Adam Langleye7624342015-01-15 17:33:48 -0800255 return SpeedAEADChunk(aead, name + " (16 bytes)", 16, ad_len) &&
256 SpeedAEADChunk(aead, name + " (1350 bytes)", 1350, ad_len) &&
257 SpeedAEADChunk(aead, name + " (8192 bytes)", 8192, ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700258}
259
Adam Langley006779a2014-06-20 12:00:00 -0700260static bool SpeedHashChunk(const EVP_MD *md, const std::string &name,
261 size_t chunk_len) {
262 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
263 uint8_t scratch[8192];
264
265 if (chunk_len > sizeof(scratch)) {
266 return false;
267 }
268
269 TimeResults results;
270 if (!TimeFunction(&results, [ctx, md, chunk_len, &scratch]() -> bool {
271 uint8_t digest[EVP_MAX_MD_SIZE];
272 unsigned int md_len;
273
274 return EVP_DigestInit_ex(ctx, md, NULL /* ENGINE */) &&
275 EVP_DigestUpdate(ctx, scratch, chunk_len) &&
276 EVP_DigestFinal_ex(ctx, digest, &md_len);
277 })) {
278 fprintf(stderr, "EVP_DigestInit_ex failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000279 ERR_print_errors_fp(stderr);
Adam Langley006779a2014-06-20 12:00:00 -0700280 return false;
281 }
282
283 results.PrintWithBytes(name, chunk_len);
284
285 EVP_MD_CTX_destroy(ctx);
286
287 return true;
288}
Adam Langley90b58402015-04-13 11:04:18 -0700289static bool SpeedHash(const EVP_MD *md, const std::string &name,
290 const std::string &selected) {
291 if (!selected.empty() && name.find(selected) == std::string::npos) {
292 return true;
293 }
294
Adam Langley006779a2014-06-20 12:00:00 -0700295 return SpeedHashChunk(md, name + " (16 bytes)", 16) &&
296 SpeedHashChunk(md, name + " (256 bytes)", 256) &&
297 SpeedHashChunk(md, name + " (8192 bytes)", 8192);
298}
299
Adam Langley90b58402015-04-13 11:04:18 -0700300static bool SpeedRandomChunk(const std::string name, size_t chunk_len) {
301 uint8_t scratch[8192];
302
303 if (chunk_len > sizeof(scratch)) {
304 return false;
305 }
306
307 TimeResults results;
308 if (!TimeFunction(&results, [chunk_len, &scratch]() -> bool {
309 RAND_bytes(scratch, chunk_len);
310 return true;
311 })) {
312 return false;
313 }
314
315 results.PrintWithBytes(name, chunk_len);
316 return true;
317}
318
319static bool SpeedRandom(const std::string &selected) {
320 if (!selected.empty() && selected != "RNG") {
321 return true;
322 }
323
324 return SpeedRandomChunk("RNG (16 bytes)", 16) &&
325 SpeedRandomChunk("RNG (256 bytes)", 256) &&
326 SpeedRandomChunk("RNG (8192 bytes)", 8192);
327}
328
Adam Langleyad6b28e2015-04-14 12:07:44 -0700329static bool SpeedECDHCurve(const std::string &name, int nid,
330 const std::string &selected) {
331 if (!selected.empty() && name.find(selected) == std::string::npos) {
332 return true;
333 }
334
335 TimeResults results;
336 if (!TimeFunction(&results, [nid]() -> bool {
337 ScopedEC_KEY key(EC_KEY_new_by_curve_name(nid));
338 if (!key ||
339 !EC_KEY_generate_key(key.get())) {
340 return false;
341 }
342 const EC_GROUP *const group = EC_KEY_get0_group(key.get());
343 ScopedEC_POINT point(EC_POINT_new(group));
344 ScopedBN_CTX ctx(BN_CTX_new());
345
346 ScopedBIGNUM x(BN_new());
347 ScopedBIGNUM y(BN_new());
348
349 if (!point || !ctx || !x || !y ||
350 !EC_POINT_mul(group, point.get(), NULL,
351 EC_KEY_get0_public_key(key.get()),
352 EC_KEY_get0_private_key(key.get()), ctx.get()) ||
353 !EC_POINT_get_affine_coordinates_GFp(group, point.get(), x.get(),
354 y.get(), ctx.get())) {
355 return false;
356 }
357
358 return true;
359 })) {
360 return false;
361 }
362
363 results.Print(name);
364 return true;
365}
366
367static bool SpeedECDSACurve(const std::string &name, int nid,
368 const std::string &selected) {
369 if (!selected.empty() && name.find(selected) == std::string::npos) {
370 return true;
371 }
372
373 ScopedEC_KEY key(EC_KEY_new_by_curve_name(nid));
374 if (!key ||
375 !EC_KEY_generate_key(key.get())) {
376 return false;
377 }
378
379 uint8_t signature[256];
380 if (ECDSA_size(key.get()) > sizeof(signature)) {
381 return false;
382 }
383 uint8_t digest[20];
384 memset(digest, 42, sizeof(digest));
385 unsigned sig_len;
386
387 TimeResults results;
388 if (!TimeFunction(&results, [&key, &signature, &digest, &sig_len]() -> bool {
389 return ECDSA_sign(0, digest, sizeof(digest), signature, &sig_len,
390 key.get()) == 1;
391 })) {
392 return false;
393 }
394
395 results.Print(name + " signing");
396
397 if (!TimeFunction(&results, [&key, &signature, &digest, sig_len]() -> bool {
398 return ECDSA_verify(0, digest, sizeof(digest), signature, sig_len,
399 key.get()) == 1;
400 })) {
401 return false;
402 }
403
404 results.Print(name + " verify");
405
406 return true;
407}
408
409static bool SpeedECDH(const std::string &selected) {
410 return SpeedECDHCurve("ECDH P-224", NID_secp224r1, selected) &&
411 SpeedECDHCurve("ECDH P-256", NID_X9_62_prime256v1, selected) &&
412 SpeedECDHCurve("ECDH P-384", NID_secp384r1, selected) &&
413 SpeedECDHCurve("ECDH P-521", NID_secp521r1, selected);
414}
415
416static bool SpeedECDSA(const std::string &selected) {
417 return SpeedECDSACurve("ECDSA P-224", NID_secp224r1, selected) &&
418 SpeedECDSACurve("ECDSA P-256", NID_X9_62_prime256v1, selected) &&
419 SpeedECDSACurve("ECDSA P-384", NID_secp384r1, selected) &&
420 SpeedECDSACurve("ECDSA P-521", NID_secp521r1, selected);
421}
422
Adam Langley4fb0dc42015-11-13 13:09:47 -0800423static bool Speed25519(const std::string &selected) {
424 if (!selected.empty() && selected.find("25519") == std::string::npos) {
425 return true;
426 }
427
428 TimeResults results;
429
Adam Langley4fb0dc42015-11-13 13:09:47 -0800430 uint8_t public_key[32], private_key[64];
431
432 if (!TimeFunction(&results, [&public_key, &private_key]() -> bool {
433 ED25519_keypair(public_key, private_key);
434 return true;
435 })) {
436 return false;
437 }
438
439 results.Print("Ed25519 key generation");
440
441 static const uint8_t kMessage[] = {0, 1, 2, 3, 4, 5};
442 uint8_t signature[64];
443
444 if (!TimeFunction(&results, [&private_key, &signature]() -> bool {
445 return ED25519_sign(signature, kMessage, sizeof(kMessage),
446 private_key) == 1;
447 })) {
448 return false;
449 }
450
451 results.Print("Ed25519 signing");
452
453 if (!TimeFunction(&results, [&public_key, &signature]() -> bool {
454 return ED25519_verify(kMessage, sizeof(kMessage), signature,
455 public_key) == 1;
456 })) {
457 fprintf(stderr, "Ed25519 verify failed.\n");
458 return false;
459 }
460
461 results.Print("Ed25519 verify");
Adam Langley4fb0dc42015-11-13 13:09:47 -0800462
463 if (!TimeFunction(&results, []() -> bool {
464 uint8_t out[32], in[32];
465 memset(in, 0, sizeof(in));
466 X25519_public_from_private(out, in);
467 return true;
468 })) {
469 fprintf(stderr, "Curve25519 base-point multiplication failed.\n");
470 return false;
471 }
472
473 results.Print("Curve25519 base-point multiplication");
474
475 if (!TimeFunction(&results, []() -> bool {
476 uint8_t out[32], in1[32], in2[32];
477 memset(in1, 0, sizeof(in1));
478 memset(in2, 0, sizeof(in2));
Adam Langley3ac32b12015-11-17 15:15:05 -0800479 in1[0] = 1;
480 in2[0] = 9;
Adam Langley4fb0dc42015-11-13 13:09:47 -0800481 return X25519(out, in1, in2) == 1;
482 })) {
483 fprintf(stderr, "Curve25519 arbitrary point multiplication failed.\n");
484 return false;
485 }
486
487 results.Print("Curve25519 arbitrary point multiplication");
488
489 return true;
490}
491
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800492static bool SpeedSPAKE2(const std::string &selected) {
493 if (!selected.empty() && selected.find("SPAKE2") == std::string::npos) {
494 return true;
495 }
496
497 TimeResults results;
498
499 static const uint8_t kAliceName[] = {'A'};
500 static const uint8_t kBobName[] = {'B'};
501 static const uint8_t kPassword[] = "password";
502 ScopedSPAKE2_CTX alice(SPAKE2_CTX_new(spake2_role_alice, kAliceName,
503 sizeof(kAliceName), kBobName,
504 sizeof(kBobName)));
505 uint8_t alice_msg[SPAKE2_MAX_MSG_SIZE];
506 size_t alice_msg_len;
507
508 if (!SPAKE2_generate_msg(alice.get(), alice_msg, &alice_msg_len,
509 sizeof(alice_msg),
510 kPassword, sizeof(kPassword))) {
511 fprintf(stderr, "SPAKE2_generate_msg failed.\n");
512 return false;
513 }
514
Adam Langley708db162016-03-01 11:48:00 -0800515 if (!TimeFunction(&results, [&alice_msg, alice_msg_len]() -> bool {
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800516 ScopedSPAKE2_CTX bob(SPAKE2_CTX_new(spake2_role_bob, kBobName,
517 sizeof(kBobName), kAliceName,
518 sizeof(kAliceName)));
519 uint8_t bob_msg[SPAKE2_MAX_MSG_SIZE], bob_key[64];
520 size_t bob_msg_len, bob_key_len;
521 if (!SPAKE2_generate_msg(bob.get(), bob_msg, &bob_msg_len,
522 sizeof(bob_msg), kPassword,
523 sizeof(kPassword)) ||
524 !SPAKE2_process_msg(bob.get(), bob_key, &bob_key_len,
525 sizeof(bob_key), alice_msg, alice_msg_len)) {
526 return false;
527 }
528
529 return true;
530 })) {
531 fprintf(stderr, "SPAKE2 failed.\n");
532 }
533
534 results.Print("SPAKE2 over Ed25519");
535
536 return true;
537}
538
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700539static bool SpeedNewHope(const std::string &selected) {
540 if (!selected.empty() && selected.find("newhope") == std::string::npos) {
541 return true;
542 }
543
544 TimeResults results;
545 NEWHOPE_POLY *sk = NEWHOPE_POLY_new();
Matt Braithwaitee09e5792016-05-19 10:30:52 -0700546 uint8_t acceptmsg[NEWHOPE_ACCEPTMSG_LENGTH];
547 RAND_bytes(acceptmsg, sizeof(acceptmsg));
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700548
Matt Braithwaitee09e5792016-05-19 10:30:52 -0700549 if (!TimeFunction(&results, [sk, &acceptmsg]() -> bool {
550 uint8_t key[SHA256_DIGEST_LENGTH];
551 uint8_t offermsg[NEWHOPE_OFFERMSG_LENGTH];
552 NEWHOPE_offer(offermsg, sk);
553 if (!NEWHOPE_finish(key, sk, acceptmsg, NEWHOPE_ACCEPTMSG_LENGTH)) {
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700554 return false;
555 }
556 return true;
557 })) {
558 fprintf(stderr, "failed to exchange key.\n");
559 return false;
560 }
561
562 NEWHOPE_POLY_free(sk);
Matt Braithwaitee09e5792016-05-19 10:30:52 -0700563 results.Print("newhope key exchange");
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700564 return true;
565}
566
David Benjaminbcb65b92016-08-14 22:06:49 -0400567static const struct argument kArguments[] = {
568 {
569 "-filter", kOptionalArgument,
570 "A filter on the speed tests to run",
571 },
572 {
573 "-timeout", kOptionalArgument,
574 "The number of seconds to run each test for (default is 1)",
575 },
576 {
577 "", kOptionalArgument, "",
578 },
579};
580
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700581bool Speed(const std::vector<std::string> &args) {
David Benjaminbcb65b92016-08-14 22:06:49 -0400582 std::map<std::string, std::string> args_map;
583 if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
584 PrintUsage(kArguments);
Adam Langley90b58402015-04-13 11:04:18 -0700585 return false;
586 }
David Benjaminbcb65b92016-08-14 22:06:49 -0400587
588 std::string selected;
589 if (args_map.count("-filter") != 0) {
590 selected = args_map["-filter"];
591 }
592
593 if (args_map.count("-timeout") != 0) {
594 g_timeout_seconds = atoi(args_map["-timeout"].c_str());
Adam Langley90b58402015-04-13 11:04:18 -0700595 }
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700596
David Benjamin74f71102015-06-27 14:56:25 -0400597 RSA *key = RSA_private_key_from_bytes(kDERRSAPrivate2048,
598 kDERRSAPrivate2048Len);
599 if (key == NULL) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700600 fprintf(stderr, "Failed to parse RSA key.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000601 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700602 return false;
603 }
604
Adam Langley90b58402015-04-13 11:04:18 -0700605 if (!SpeedRSA("RSA 2048", key, selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700606 return false;
607 }
608
609 RSA_free(key);
David Benjamin74f71102015-06-27 14:56:25 -0400610 key = RSA_private_key_from_bytes(kDERRSAPrivate3Prime2048,
611 kDERRSAPrivate3Prime2048Len);
612 if (key == NULL) {
Adam Langley839b8812015-05-26 11:36:46 -0700613 fprintf(stderr, "Failed to parse RSA key.\n");
614 ERR_print_errors_fp(stderr);
615 return false;
616 }
617
618 if (!SpeedRSA("RSA 2048 (3 prime, e=3)", key, selected)) {
619 return false;
620 }
621
622 RSA_free(key);
David Benjamin74f71102015-06-27 14:56:25 -0400623 key = RSA_private_key_from_bytes(kDERRSAPrivate4096,
624 kDERRSAPrivate4096Len);
625 if (key == NULL) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700626 fprintf(stderr, "Failed to parse 4096-bit RSA key.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000627 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700628 return 1;
629 }
630
Adam Langley90b58402015-04-13 11:04:18 -0700631 if (!SpeedRSA("RSA 4096", key, selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700632 return false;
633 }
634
635 RSA_free(key);
636
Adam Langleye7624342015-01-15 17:33:48 -0800637 // kTLSADLen is the number of bytes of additional data that TLS passes to
638 // AEADs.
639 static const size_t kTLSADLen = 13;
640 // kLegacyADLen is the number of bytes that TLS passes to the "legacy" AEADs.
641 // These are AEADs that weren't originally defined as AEADs, but which we use
642 // via the AEAD interface. In order for that to work, they have some TLS
643 // knowledge in them and construct a couple of the AD bytes internally.
644 static const size_t kLegacyADLen = kTLSADLen - 2;
645
Adam Langley90b58402015-04-13 11:04:18 -0700646 if (!SpeedAEAD(EVP_aead_aes_128_gcm(), "AES-128-GCM", kTLSADLen, selected) ||
647 !SpeedAEAD(EVP_aead_aes_256_gcm(), "AES-256-GCM", kTLSADLen, selected) ||
David Benjamin8ffab722015-11-30 18:48:18 -0500648 !SpeedAEAD(EVP_aead_chacha20_poly1305(), "ChaCha20-Poly1305", kTLSADLen,
649 selected) ||
Brian Smith3e23e4c2015-10-03 11:38:58 -1000650 !SpeedAEAD(EVP_aead_chacha20_poly1305_old(), "ChaCha20-Poly1305-Old",
651 kTLSADLen, selected) ||
Adam Langley90b58402015-04-13 11:04:18 -0700652 !SpeedAEAD(EVP_aead_rc4_md5_tls(), "RC4-MD5", kLegacyADLen, selected) ||
David Benjamindf571632015-12-07 19:48:16 -0500653 !SpeedAEAD(EVP_aead_rc4_sha1_tls(), "RC4-SHA1", kLegacyADLen, selected) ||
654 !SpeedAEAD(EVP_aead_des_ede3_cbc_sha1_tls(), "DES-EDE3-CBC-SHA1",
655 kLegacyADLen, selected) ||
Adam Langley90b58402015-04-13 11:04:18 -0700656 !SpeedAEAD(EVP_aead_aes_128_cbc_sha1_tls(), "AES-128-CBC-SHA1",
657 kLegacyADLen, selected) ||
658 !SpeedAEAD(EVP_aead_aes_256_cbc_sha1_tls(), "AES-256-CBC-SHA1",
659 kLegacyADLen, selected) ||
660 !SpeedHash(EVP_sha1(), "SHA-1", selected) ||
661 !SpeedHash(EVP_sha256(), "SHA-256", selected) ||
662 !SpeedHash(EVP_sha512(), "SHA-512", selected) ||
Adam Langleyad6b28e2015-04-14 12:07:44 -0700663 !SpeedRandom(selected) ||
664 !SpeedECDH(selected) ||
Adam Langley4fb0dc42015-11-13 13:09:47 -0800665 !SpeedECDSA(selected) ||
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800666 !Speed25519(selected) ||
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700667 !SpeedSPAKE2(selected) ||
668 !SpeedNewHope(selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700669 return false;
670 }
671
Adam Langley90b58402015-04-13 11:04:18 -0700672 return true;
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700673}