blob: f089498bea5915248016b11e26cc103b5acd5a5a [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>
Matt Braithwaited17d74d2016-08-17 20:10:28 -070025#include <openssl/bn.h>
Adam Langley4fb0dc42015-11-13 13:09:47 -080026#include <openssl/curve25519.h>
Adam Langley92b6b022015-04-16 14:01:33 -070027#include <openssl/digest.h>
28#include <openssl/err.h>
Matt Braithwaited17d74d2016-08-17 20:10:28 -070029#include <openssl/ec.h>
30#include <openssl/ecdsa.h>
31#include <openssl/ec_key.h>
Matt Braithwaite045a0ff2016-04-18 11:30:19 -070032#include <openssl/newhope.h>
David Benjamin98193672016-03-25 18:07:11 -040033#include <openssl/nid.h>
Adam Langley92b6b022015-04-16 14:01:33 -070034#include <openssl/rand.h>
35#include <openssl/rsa.h>
36
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070037#if defined(OPENSSL_WINDOWS)
David Benjamina353cdb2016-06-09 16:48:33 -040038OPENSSL_MSVC_PRAGMA(warning(push, 3))
Adam Langley3e719312015-03-20 16:32:23 -070039#include <windows.h>
David Benjamina353cdb2016-06-09 16:48:33 -040040OPENSSL_MSVC_PRAGMA(warning(pop))
Adam Langley30eda1d2014-06-24 11:15:12 -070041#elif defined(OPENSSL_APPLE)
42#include <sys/time.h>
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070043#endif
44
David Benjamin58084af2015-06-07 00:25:15 -040045#include "internal.h"
Adam Langleyad6b28e2015-04-14 12:07:44 -070046
Adam Langley2b2d66d2015-01-30 17:08:37 -080047
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070048// TimeResults represents the results of benchmarking a function.
49struct TimeResults {
50 // num_calls is the number of function calls done in the time period.
51 unsigned num_calls;
52 // us is the number of microseconds that elapsed in the time period.
53 unsigned us;
54
55 void Print(const std::string &description) {
56 printf("Did %u %s operations in %uus (%.1f ops/sec)\n", num_calls,
57 description.c_str(), us,
58 (static_cast<double>(num_calls) / us) * 1000000);
59 }
60
61 void PrintWithBytes(const std::string &description, size_t bytes_per_call) {
62 printf("Did %u %s operations in %uus (%.1f ops/sec): %.1f MB/s\n",
63 num_calls, description.c_str(), us,
64 (static_cast<double>(num_calls) / us) * 1000000,
65 static_cast<double>(bytes_per_call * num_calls) / us);
66 }
67};
68
69#if defined(OPENSSL_WINDOWS)
70static uint64_t time_now() { return GetTickCount64() * 1000; }
Adam Langley30eda1d2014-06-24 11:15:12 -070071#elif defined(OPENSSL_APPLE)
72static uint64_t time_now() {
73 struct timeval tv;
74 uint64_t ret;
75
76 gettimeofday(&tv, NULL);
77 ret = tv.tv_sec;
78 ret *= 1000000;
79 ret += tv.tv_usec;
80 return ret;
81}
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070082#else
83static uint64_t time_now() {
84 struct timespec ts;
85 clock_gettime(CLOCK_MONOTONIC, &ts);
86
87 uint64_t ret = ts.tv_sec;
88 ret *= 1000000;
89 ret += ts.tv_nsec / 1000;
90 return ret;
91}
92#endif
93
David Benjaminbcb65b92016-08-14 22:06:49 -040094static uint64_t g_timeout_seconds = 1;
95
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070096static bool TimeFunction(TimeResults *results, std::function<bool()> func) {
David Benjaminbcb65b92016-08-14 22:06:49 -040097 // total_us is the total amount of time that we'll aim to measure a function
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070098 // for.
David Benjaminbcb65b92016-08-14 22:06:49 -040099 const uint64_t total_us = g_timeout_seconds * 1000000;
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700100 uint64_t start = time_now(), now, delta;
101 unsigned done = 0, iterations_between_time_checks;
102
103 if (!func()) {
104 return false;
105 }
106 now = time_now();
107 delta = now - start;
108 if (delta == 0) {
109 iterations_between_time_checks = 250;
110 } else {
111 // Aim for about 100ms between time checks.
112 iterations_between_time_checks =
113 static_cast<double>(100000) / static_cast<double>(delta);
114 if (iterations_between_time_checks > 1000) {
115 iterations_between_time_checks = 1000;
116 } else if (iterations_between_time_checks < 1) {
117 iterations_between_time_checks = 1;
118 }
119 }
120
121 for (;;) {
122 for (unsigned i = 0; i < iterations_between_time_checks; i++) {
123 if (!func()) {
124 return false;
125 }
126 done++;
127 }
128
129 now = time_now();
David Benjaminbcb65b92016-08-14 22:06:49 -0400130 if (now - start > total_us) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700131 break;
132 }
133 }
134
135 results->us = now - start;
136 results->num_calls = done;
137 return true;
138}
139
Adam Langley90b58402015-04-13 11:04:18 -0700140static bool SpeedRSA(const std::string &key_name, RSA *key,
141 const std::string &selected) {
142 if (!selected.empty() && key_name.find(selected) == std::string::npos) {
143 return true;
144 }
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700145
146 std::unique_ptr<uint8_t[]> sig(new uint8_t[RSA_size(key)]);
147 const uint8_t fake_sha256_hash[32] = {0};
148 unsigned sig_len;
149
Adam Langley90b58402015-04-13 11:04:18 -0700150 TimeResults results;
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700151 if (!TimeFunction(&results,
152 [key, &sig, &fake_sha256_hash, &sig_len]() -> bool {
Brian Smith7bee8532016-08-19 15:11:20 -1000153 /* Usually during RSA signing we're using a long-lived |RSA| that has
154 * already had all of its |BN_MONT_CTX|s constructed, so it makes
155 * sense to use |key| directly here. */
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700156 return RSA_sign(NID_sha256, fake_sha256_hash, sizeof(fake_sha256_hash),
157 sig.get(), &sig_len, key);
158 })) {
159 fprintf(stderr, "RSA_sign failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000160 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700161 return false;
162 }
163 results.Print(key_name + " signing");
164
165 if (!TimeFunction(&results,
166 [key, &fake_sha256_hash, &sig, sig_len]() -> bool {
Brian Smith7bee8532016-08-19 15:11:20 -1000167 /* Usually during RSA verification we have to parse an RSA key from a
168 * certificate or similar, in which case we'd need to construct a new
169 * RSA key, with a new |BN_MONT_CTX| for the public modulus. If we were
170 * to use |key| directly instead, then these costs wouldn't be
171 * accounted for. */
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700172 bssl::UniquePtr<RSA> verify_key(RSA_new());
Brian Smith7bee8532016-08-19 15:11:20 -1000173 if (!verify_key) {
174 return false;
175 }
176 verify_key->n = BN_dup(key->n);
177 verify_key->e = BN_dup(key->e);
178 if (!verify_key->n ||
179 !verify_key->e) {
180 return false;
181 }
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700182 return RSA_verify(NID_sha256, fake_sha256_hash,
183 sizeof(fake_sha256_hash), sig.get(), sig_len, key);
184 })) {
185 fprintf(stderr, "RSA_verify failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000186 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700187 return false;
188 }
189 results.Print(key_name + " verify");
190
191 return true;
192}
193
Adam Langley26725342015-01-28 15:52:57 -0800194static uint8_t *align(uint8_t *in, unsigned alignment) {
195 return reinterpret_cast<uint8_t *>(
Brian Smithd53b2c32015-03-17 00:37:06 -1000196 (reinterpret_cast<uintptr_t>(in) + alignment) &
197 ~static_cast<size_t>(alignment - 1));
David Benjamin384673c2015-01-21 15:56:14 -0500198}
Adam Langley543d0062015-01-15 16:05:41 -0800199
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700200static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
Adam Langleye7624342015-01-15 17:33:48 -0800201 size_t chunk_len, size_t ad_len) {
Adam Langley26725342015-01-28 15:52:57 -0800202 static const unsigned kAlignment = 16;
203
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700204 EVP_AEAD_CTX ctx;
205 const size_t key_len = EVP_AEAD_key_length(aead);
206 const size_t nonce_len = EVP_AEAD_nonce_length(aead);
207 const size_t overhead_len = EVP_AEAD_max_overhead(aead);
208
209 std::unique_ptr<uint8_t[]> key(new uint8_t[key_len]);
210 memset(key.get(), 0, key_len);
211 std::unique_ptr<uint8_t[]> nonce(new uint8_t[nonce_len]);
212 memset(nonce.get(), 0, nonce_len);
Brian Smith1d1562d2015-03-17 00:32:20 -1000213 std::unique_ptr<uint8_t[]> in_storage(new uint8_t[chunk_len + kAlignment]);
214 std::unique_ptr<uint8_t[]> out_storage(new uint8_t[chunk_len + overhead_len + kAlignment]);
Adam Langleye7624342015-01-15 17:33:48 -0800215 std::unique_ptr<uint8_t[]> ad(new uint8_t[ad_len]);
216 memset(ad.get(), 0, ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700217
Adam Langley26725342015-01-28 15:52:57 -0800218 uint8_t *const in = align(in_storage.get(), kAlignment);
219 memset(in, 0, chunk_len);
220 uint8_t *const out = align(out_storage.get(), kAlignment);
221 memset(out, 0, chunk_len + overhead_len);
222
David Benjamind434f282015-03-17 18:28:37 -0400223 if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, key.get(), key_len,
224 EVP_AEAD_DEFAULT_TAG_LENGTH,
225 evp_aead_seal)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700226 fprintf(stderr, "Failed to create EVP_AEAD_CTX.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000227 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700228 return false;
229 }
230
231 TimeResults results;
Adam Langley26725342015-01-28 15:52:57 -0800232 if (!TimeFunction(&results, [chunk_len, overhead_len, nonce_len, ad_len, in,
233 out, &ctx, &nonce, &ad]() -> bool {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700234 size_t out_len;
235
Adam Langleye7624342015-01-15 17:33:48 -0800236 return EVP_AEAD_CTX_seal(
Adam Langley26725342015-01-28 15:52:57 -0800237 &ctx, out, &out_len, chunk_len + overhead_len, nonce.get(),
238 nonce_len, in, chunk_len, ad.get(), ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700239 })) {
240 fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000241 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700242 return false;
243 }
244
245 results.PrintWithBytes(name + " seal", chunk_len);
246
247 EVP_AEAD_CTX_cleanup(&ctx);
248
249 return true;
250}
251
Adam Langleye7624342015-01-15 17:33:48 -0800252static bool SpeedAEAD(const EVP_AEAD *aead, const std::string &name,
Adam Langley90b58402015-04-13 11:04:18 -0700253 size_t ad_len, const std::string &selected) {
254 if (!selected.empty() && name.find(selected) == std::string::npos) {
255 return true;
256 }
257
Adam Langleye7624342015-01-15 17:33:48 -0800258 return SpeedAEADChunk(aead, name + " (16 bytes)", 16, ad_len) &&
259 SpeedAEADChunk(aead, name + " (1350 bytes)", 1350, ad_len) &&
260 SpeedAEADChunk(aead, name + " (8192 bytes)", 8192, ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700261}
262
Adam Langley006779a2014-06-20 12:00:00 -0700263static bool SpeedHashChunk(const EVP_MD *md, const std::string &name,
264 size_t chunk_len) {
265 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
266 uint8_t scratch[8192];
267
268 if (chunk_len > sizeof(scratch)) {
269 return false;
270 }
271
272 TimeResults results;
273 if (!TimeFunction(&results, [ctx, md, chunk_len, &scratch]() -> bool {
274 uint8_t digest[EVP_MAX_MD_SIZE];
275 unsigned int md_len;
276
277 return EVP_DigestInit_ex(ctx, md, NULL /* ENGINE */) &&
278 EVP_DigestUpdate(ctx, scratch, chunk_len) &&
279 EVP_DigestFinal_ex(ctx, digest, &md_len);
280 })) {
281 fprintf(stderr, "EVP_DigestInit_ex failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000282 ERR_print_errors_fp(stderr);
Adam Langley006779a2014-06-20 12:00:00 -0700283 return false;
284 }
285
286 results.PrintWithBytes(name, chunk_len);
287
288 EVP_MD_CTX_destroy(ctx);
289
290 return true;
291}
Adam Langley90b58402015-04-13 11:04:18 -0700292static bool SpeedHash(const EVP_MD *md, const std::string &name,
293 const std::string &selected) {
294 if (!selected.empty() && name.find(selected) == std::string::npos) {
295 return true;
296 }
297
Adam Langley006779a2014-06-20 12:00:00 -0700298 return SpeedHashChunk(md, name + " (16 bytes)", 16) &&
299 SpeedHashChunk(md, name + " (256 bytes)", 256) &&
300 SpeedHashChunk(md, name + " (8192 bytes)", 8192);
301}
302
Adam Langley90b58402015-04-13 11:04:18 -0700303static bool SpeedRandomChunk(const std::string name, size_t chunk_len) {
304 uint8_t scratch[8192];
305
306 if (chunk_len > sizeof(scratch)) {
307 return false;
308 }
309
310 TimeResults results;
311 if (!TimeFunction(&results, [chunk_len, &scratch]() -> bool {
312 RAND_bytes(scratch, chunk_len);
313 return true;
314 })) {
315 return false;
316 }
317
318 results.PrintWithBytes(name, chunk_len);
319 return true;
320}
321
322static bool SpeedRandom(const std::string &selected) {
323 if (!selected.empty() && selected != "RNG") {
324 return true;
325 }
326
327 return SpeedRandomChunk("RNG (16 bytes)", 16) &&
328 SpeedRandomChunk("RNG (256 bytes)", 256) &&
329 SpeedRandomChunk("RNG (8192 bytes)", 8192);
330}
331
Adam Langleyad6b28e2015-04-14 12:07:44 -0700332static bool SpeedECDHCurve(const std::string &name, int nid,
333 const std::string &selected) {
334 if (!selected.empty() && name.find(selected) == std::string::npos) {
335 return true;
336 }
337
338 TimeResults results;
339 if (!TimeFunction(&results, [nid]() -> bool {
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700340 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
Adam Langleyad6b28e2015-04-14 12:07:44 -0700341 if (!key ||
342 !EC_KEY_generate_key(key.get())) {
343 return false;
344 }
345 const EC_GROUP *const group = EC_KEY_get0_group(key.get());
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700346 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group));
347 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
Adam Langleyad6b28e2015-04-14 12:07:44 -0700348
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700349 bssl::UniquePtr<BIGNUM> x(BN_new());
350 bssl::UniquePtr<BIGNUM> y(BN_new());
Adam Langleyad6b28e2015-04-14 12:07:44 -0700351
352 if (!point || !ctx || !x || !y ||
353 !EC_POINT_mul(group, point.get(), NULL,
354 EC_KEY_get0_public_key(key.get()),
355 EC_KEY_get0_private_key(key.get()), ctx.get()) ||
356 !EC_POINT_get_affine_coordinates_GFp(group, point.get(), x.get(),
357 y.get(), ctx.get())) {
358 return false;
359 }
360
361 return true;
362 })) {
363 return false;
364 }
365
366 results.Print(name);
367 return true;
368}
369
370static bool SpeedECDSACurve(const std::string &name, int nid,
371 const std::string &selected) {
372 if (!selected.empty() && name.find(selected) == std::string::npos) {
373 return true;
374 }
375
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700376 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
Adam Langleyad6b28e2015-04-14 12:07:44 -0700377 if (!key ||
378 !EC_KEY_generate_key(key.get())) {
379 return false;
380 }
381
382 uint8_t signature[256];
383 if (ECDSA_size(key.get()) > sizeof(signature)) {
384 return false;
385 }
386 uint8_t digest[20];
387 memset(digest, 42, sizeof(digest));
388 unsigned sig_len;
389
390 TimeResults results;
391 if (!TimeFunction(&results, [&key, &signature, &digest, &sig_len]() -> bool {
392 return ECDSA_sign(0, digest, sizeof(digest), signature, &sig_len,
393 key.get()) == 1;
394 })) {
395 return false;
396 }
397
398 results.Print(name + " signing");
399
400 if (!TimeFunction(&results, [&key, &signature, &digest, sig_len]() -> bool {
401 return ECDSA_verify(0, digest, sizeof(digest), signature, sig_len,
402 key.get()) == 1;
403 })) {
404 return false;
405 }
406
407 results.Print(name + " verify");
408
409 return true;
410}
411
412static bool SpeedECDH(const std::string &selected) {
413 return SpeedECDHCurve("ECDH P-224", NID_secp224r1, selected) &&
414 SpeedECDHCurve("ECDH P-256", NID_X9_62_prime256v1, selected) &&
415 SpeedECDHCurve("ECDH P-384", NID_secp384r1, selected) &&
416 SpeedECDHCurve("ECDH P-521", NID_secp521r1, selected);
417}
418
419static bool SpeedECDSA(const std::string &selected) {
420 return SpeedECDSACurve("ECDSA P-224", NID_secp224r1, selected) &&
421 SpeedECDSACurve("ECDSA P-256", NID_X9_62_prime256v1, selected) &&
422 SpeedECDSACurve("ECDSA P-384", NID_secp384r1, selected) &&
423 SpeedECDSACurve("ECDSA P-521", NID_secp521r1, selected);
424}
425
Adam Langley4fb0dc42015-11-13 13:09:47 -0800426static bool Speed25519(const std::string &selected) {
427 if (!selected.empty() && selected.find("25519") == std::string::npos) {
428 return true;
429 }
430
431 TimeResults results;
432
Adam Langley4fb0dc42015-11-13 13:09:47 -0800433 uint8_t public_key[32], private_key[64];
434
435 if (!TimeFunction(&results, [&public_key, &private_key]() -> bool {
436 ED25519_keypair(public_key, private_key);
437 return true;
438 })) {
439 return false;
440 }
441
442 results.Print("Ed25519 key generation");
443
444 static const uint8_t kMessage[] = {0, 1, 2, 3, 4, 5};
445 uint8_t signature[64];
446
447 if (!TimeFunction(&results, [&private_key, &signature]() -> bool {
448 return ED25519_sign(signature, kMessage, sizeof(kMessage),
449 private_key) == 1;
450 })) {
451 return false;
452 }
453
454 results.Print("Ed25519 signing");
455
456 if (!TimeFunction(&results, [&public_key, &signature]() -> bool {
457 return ED25519_verify(kMessage, sizeof(kMessage), signature,
458 public_key) == 1;
459 })) {
460 fprintf(stderr, "Ed25519 verify failed.\n");
461 return false;
462 }
463
464 results.Print("Ed25519 verify");
Adam Langley4fb0dc42015-11-13 13:09:47 -0800465
466 if (!TimeFunction(&results, []() -> bool {
467 uint8_t out[32], in[32];
468 memset(in, 0, sizeof(in));
469 X25519_public_from_private(out, in);
470 return true;
471 })) {
472 fprintf(stderr, "Curve25519 base-point multiplication failed.\n");
473 return false;
474 }
475
476 results.Print("Curve25519 base-point multiplication");
477
478 if (!TimeFunction(&results, []() -> bool {
479 uint8_t out[32], in1[32], in2[32];
480 memset(in1, 0, sizeof(in1));
481 memset(in2, 0, sizeof(in2));
Adam Langley3ac32b12015-11-17 15:15:05 -0800482 in1[0] = 1;
483 in2[0] = 9;
Adam Langley4fb0dc42015-11-13 13:09:47 -0800484 return X25519(out, in1, in2) == 1;
485 })) {
486 fprintf(stderr, "Curve25519 arbitrary point multiplication failed.\n");
487 return false;
488 }
489
490 results.Print("Curve25519 arbitrary point multiplication");
491
492 return true;
493}
494
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800495static bool SpeedSPAKE2(const std::string &selected) {
496 if (!selected.empty() && selected.find("SPAKE2") == std::string::npos) {
497 return true;
498 }
499
500 TimeResults results;
501
502 static const uint8_t kAliceName[] = {'A'};
503 static const uint8_t kBobName[] = {'B'};
504 static const uint8_t kPassword[] = "password";
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700505 bssl::UniquePtr<SPAKE2_CTX> alice(SPAKE2_CTX_new(spake2_role_alice,
506 kAliceName, sizeof(kAliceName), kBobName,
507 sizeof(kBobName)));
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800508 uint8_t alice_msg[SPAKE2_MAX_MSG_SIZE];
509 size_t alice_msg_len;
510
511 if (!SPAKE2_generate_msg(alice.get(), alice_msg, &alice_msg_len,
512 sizeof(alice_msg),
513 kPassword, sizeof(kPassword))) {
514 fprintf(stderr, "SPAKE2_generate_msg failed.\n");
515 return false;
516 }
517
Adam Langley708db162016-03-01 11:48:00 -0800518 if (!TimeFunction(&results, [&alice_msg, alice_msg_len]() -> bool {
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700519 bssl::UniquePtr<SPAKE2_CTX> bob(SPAKE2_CTX_new(spake2_role_bob,
520 kBobName, sizeof(kBobName), kAliceName,
521 sizeof(kAliceName)));
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800522 uint8_t bob_msg[SPAKE2_MAX_MSG_SIZE], bob_key[64];
523 size_t bob_msg_len, bob_key_len;
524 if (!SPAKE2_generate_msg(bob.get(), bob_msg, &bob_msg_len,
525 sizeof(bob_msg), kPassword,
526 sizeof(kPassword)) ||
527 !SPAKE2_process_msg(bob.get(), bob_key, &bob_key_len,
528 sizeof(bob_key), alice_msg, alice_msg_len)) {
529 return false;
530 }
531
532 return true;
533 })) {
534 fprintf(stderr, "SPAKE2 failed.\n");
535 }
536
537 results.Print("SPAKE2 over Ed25519");
538
539 return true;
540}
541
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700542static bool SpeedNewHope(const std::string &selected) {
543 if (!selected.empty() && selected.find("newhope") == std::string::npos) {
544 return true;
545 }
546
547 TimeResults results;
548 NEWHOPE_POLY *sk = NEWHOPE_POLY_new();
Matt Braithwaitee09e5792016-05-19 10:30:52 -0700549 uint8_t acceptmsg[NEWHOPE_ACCEPTMSG_LENGTH];
550 RAND_bytes(acceptmsg, sizeof(acceptmsg));
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700551
Matt Braithwaitee09e5792016-05-19 10:30:52 -0700552 if (!TimeFunction(&results, [sk, &acceptmsg]() -> bool {
553 uint8_t key[SHA256_DIGEST_LENGTH];
554 uint8_t offermsg[NEWHOPE_OFFERMSG_LENGTH];
555 NEWHOPE_offer(offermsg, sk);
556 if (!NEWHOPE_finish(key, sk, acceptmsg, NEWHOPE_ACCEPTMSG_LENGTH)) {
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700557 return false;
558 }
559 return true;
560 })) {
561 fprintf(stderr, "failed to exchange key.\n");
562 return false;
563 }
564
565 NEWHOPE_POLY_free(sk);
Matt Braithwaitee09e5792016-05-19 10:30:52 -0700566 results.Print("newhope key exchange");
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700567 return true;
568}
569
David Benjaminbcb65b92016-08-14 22:06:49 -0400570static const struct argument kArguments[] = {
571 {
572 "-filter", kOptionalArgument,
573 "A filter on the speed tests to run",
574 },
575 {
576 "-timeout", kOptionalArgument,
577 "The number of seconds to run each test for (default is 1)",
578 },
579 {
580 "", kOptionalArgument, "",
581 },
582};
583
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700584bool Speed(const std::vector<std::string> &args) {
David Benjaminbcb65b92016-08-14 22:06:49 -0400585 std::map<std::string, std::string> args_map;
586 if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
587 PrintUsage(kArguments);
Adam Langley90b58402015-04-13 11:04:18 -0700588 return false;
589 }
David Benjaminbcb65b92016-08-14 22:06:49 -0400590
591 std::string selected;
592 if (args_map.count("-filter") != 0) {
593 selected = args_map["-filter"];
594 }
595
596 if (args_map.count("-timeout") != 0) {
597 g_timeout_seconds = atoi(args_map["-timeout"].c_str());
Adam Langley90b58402015-04-13 11:04:18 -0700598 }
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700599
David Benjamin74f71102015-06-27 14:56:25 -0400600 RSA *key = RSA_private_key_from_bytes(kDERRSAPrivate2048,
601 kDERRSAPrivate2048Len);
602 if (key == NULL) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700603 fprintf(stderr, "Failed to parse RSA key.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000604 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700605 return false;
606 }
607
Adam Langley90b58402015-04-13 11:04:18 -0700608 if (!SpeedRSA("RSA 2048", key, selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700609 return false;
610 }
611
612 RSA_free(key);
David Benjamin74f71102015-06-27 14:56:25 -0400613 key = RSA_private_key_from_bytes(kDERRSAPrivate3Prime2048,
614 kDERRSAPrivate3Prime2048Len);
615 if (key == NULL) {
Adam Langley839b8812015-05-26 11:36:46 -0700616 fprintf(stderr, "Failed to parse RSA key.\n");
617 ERR_print_errors_fp(stderr);
618 return false;
619 }
620
621 if (!SpeedRSA("RSA 2048 (3 prime, e=3)", key, selected)) {
622 return false;
623 }
624
625 RSA_free(key);
David Benjamin74f71102015-06-27 14:56:25 -0400626 key = RSA_private_key_from_bytes(kDERRSAPrivate4096,
627 kDERRSAPrivate4096Len);
628 if (key == NULL) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700629 fprintf(stderr, "Failed to parse 4096-bit RSA key.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000630 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700631 return 1;
632 }
633
Adam Langley90b58402015-04-13 11:04:18 -0700634 if (!SpeedRSA("RSA 4096", key, selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700635 return false;
636 }
637
638 RSA_free(key);
639
Adam Langleye7624342015-01-15 17:33:48 -0800640 // kTLSADLen is the number of bytes of additional data that TLS passes to
641 // AEADs.
642 static const size_t kTLSADLen = 13;
643 // kLegacyADLen is the number of bytes that TLS passes to the "legacy" AEADs.
644 // These are AEADs that weren't originally defined as AEADs, but which we use
645 // via the AEAD interface. In order for that to work, they have some TLS
646 // knowledge in them and construct a couple of the AD bytes internally.
647 static const size_t kLegacyADLen = kTLSADLen - 2;
648
Adam Langley90b58402015-04-13 11:04:18 -0700649 if (!SpeedAEAD(EVP_aead_aes_128_gcm(), "AES-128-GCM", kTLSADLen, selected) ||
650 !SpeedAEAD(EVP_aead_aes_256_gcm(), "AES-256-GCM", kTLSADLen, selected) ||
David Benjamin8ffab722015-11-30 18:48:18 -0500651 !SpeedAEAD(EVP_aead_chacha20_poly1305(), "ChaCha20-Poly1305", kTLSADLen,
652 selected) ||
Brian Smith3e23e4c2015-10-03 11:38:58 -1000653 !SpeedAEAD(EVP_aead_chacha20_poly1305_old(), "ChaCha20-Poly1305-Old",
654 kTLSADLen, selected) ||
Adam Langley90b58402015-04-13 11:04:18 -0700655 !SpeedAEAD(EVP_aead_rc4_md5_tls(), "RC4-MD5", kLegacyADLen, selected) ||
David Benjamindf571632015-12-07 19:48:16 -0500656 !SpeedAEAD(EVP_aead_rc4_sha1_tls(), "RC4-SHA1", kLegacyADLen, selected) ||
657 !SpeedAEAD(EVP_aead_des_ede3_cbc_sha1_tls(), "DES-EDE3-CBC-SHA1",
658 kLegacyADLen, selected) ||
Adam Langley90b58402015-04-13 11:04:18 -0700659 !SpeedAEAD(EVP_aead_aes_128_cbc_sha1_tls(), "AES-128-CBC-SHA1",
660 kLegacyADLen, selected) ||
661 !SpeedAEAD(EVP_aead_aes_256_cbc_sha1_tls(), "AES-256-CBC-SHA1",
662 kLegacyADLen, selected) ||
663 !SpeedHash(EVP_sha1(), "SHA-1", selected) ||
664 !SpeedHash(EVP_sha256(), "SHA-256", selected) ||
665 !SpeedHash(EVP_sha512(), "SHA-512", selected) ||
Adam Langleyad6b28e2015-04-14 12:07:44 -0700666 !SpeedRandom(selected) ||
667 !SpeedECDH(selected) ||
Adam Langley4fb0dc42015-11-13 13:09:47 -0800668 !SpeedECDSA(selected) ||
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800669 !Speed25519(selected) ||
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700670 !SpeedSPAKE2(selected) ||
671 !SpeedNewHope(selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700672 return false;
673 }
674
Adam Langley90b58402015-04-13 11:04:18 -0700675 return true;
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700676}