blob: d5f94e1a82b0027867b1026fd8b09b5b801e9e99 [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>
David Benjamin2f401ec2016-09-09 19:49:35 -040043#else
44#include <time.h>
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070045#endif
46
David Benjamin58084af2015-06-07 00:25:15 -040047#include "internal.h"
Adam Langleyad6b28e2015-04-14 12:07:44 -070048
Adam Langley2b2d66d2015-01-30 17:08:37 -080049
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070050// TimeResults represents the results of benchmarking a function.
51struct TimeResults {
52 // num_calls is the number of function calls done in the time period.
53 unsigned num_calls;
54 // us is the number of microseconds that elapsed in the time period.
55 unsigned us;
56
57 void Print(const std::string &description) {
58 printf("Did %u %s operations in %uus (%.1f ops/sec)\n", num_calls,
59 description.c_str(), us,
60 (static_cast<double>(num_calls) / us) * 1000000);
61 }
62
63 void PrintWithBytes(const std::string &description, size_t bytes_per_call) {
64 printf("Did %u %s operations in %uus (%.1f ops/sec): %.1f MB/s\n",
65 num_calls, description.c_str(), us,
66 (static_cast<double>(num_calls) / us) * 1000000,
67 static_cast<double>(bytes_per_call * num_calls) / us);
68 }
69};
70
71#if defined(OPENSSL_WINDOWS)
72static uint64_t time_now() { return GetTickCount64() * 1000; }
Adam Langley30eda1d2014-06-24 11:15:12 -070073#elif defined(OPENSSL_APPLE)
74static uint64_t time_now() {
75 struct timeval tv;
76 uint64_t ret;
77
78 gettimeofday(&tv, NULL);
79 ret = tv.tv_sec;
80 ret *= 1000000;
81 ret += tv.tv_usec;
82 return ret;
83}
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070084#else
85static uint64_t time_now() {
86 struct timespec ts;
87 clock_gettime(CLOCK_MONOTONIC, &ts);
88
89 uint64_t ret = ts.tv_sec;
90 ret *= 1000000;
91 ret += ts.tv_nsec / 1000;
92 return ret;
93}
94#endif
95
David Benjaminbcb65b92016-08-14 22:06:49 -040096static uint64_t g_timeout_seconds = 1;
97
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070098static bool TimeFunction(TimeResults *results, std::function<bool()> func) {
David Benjaminbcb65b92016-08-14 22:06:49 -040099 // total_us is the total amount of time that we'll aim to measure a function
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700100 // for.
David Benjaminbcb65b92016-08-14 22:06:49 -0400101 const uint64_t total_us = g_timeout_seconds * 1000000;
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700102 uint64_t start = time_now(), now, delta;
103 unsigned done = 0, iterations_between_time_checks;
104
105 if (!func()) {
106 return false;
107 }
108 now = time_now();
109 delta = now - start;
110 if (delta == 0) {
111 iterations_between_time_checks = 250;
112 } else {
113 // Aim for about 100ms between time checks.
114 iterations_between_time_checks =
115 static_cast<double>(100000) / static_cast<double>(delta);
116 if (iterations_between_time_checks > 1000) {
117 iterations_between_time_checks = 1000;
118 } else if (iterations_between_time_checks < 1) {
119 iterations_between_time_checks = 1;
120 }
121 }
122
123 for (;;) {
124 for (unsigned i = 0; i < iterations_between_time_checks; i++) {
125 if (!func()) {
126 return false;
127 }
128 done++;
129 }
130
131 now = time_now();
David Benjaminbcb65b92016-08-14 22:06:49 -0400132 if (now - start > total_us) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700133 break;
134 }
135 }
136
137 results->us = now - start;
138 results->num_calls = done;
139 return true;
140}
141
Adam Langley90b58402015-04-13 11:04:18 -0700142static bool SpeedRSA(const std::string &key_name, RSA *key,
143 const std::string &selected) {
144 if (!selected.empty() && key_name.find(selected) == std::string::npos) {
145 return true;
146 }
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700147
148 std::unique_ptr<uint8_t[]> sig(new uint8_t[RSA_size(key)]);
149 const uint8_t fake_sha256_hash[32] = {0};
150 unsigned sig_len;
151
Adam Langley90b58402015-04-13 11:04:18 -0700152 TimeResults results;
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700153 if (!TimeFunction(&results,
154 [key, &sig, &fake_sha256_hash, &sig_len]() -> bool {
Brian Smith7bee8532016-08-19 15:11:20 -1000155 /* Usually during RSA signing we're using a long-lived |RSA| that has
156 * already had all of its |BN_MONT_CTX|s constructed, so it makes
157 * sense to use |key| directly here. */
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700158 return RSA_sign(NID_sha256, fake_sha256_hash, sizeof(fake_sha256_hash),
159 sig.get(), &sig_len, key);
160 })) {
161 fprintf(stderr, "RSA_sign failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000162 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700163 return false;
164 }
165 results.Print(key_name + " signing");
166
167 if (!TimeFunction(&results,
168 [key, &fake_sha256_hash, &sig, sig_len]() -> bool {
Brian Smith7bee8532016-08-19 15:11:20 -1000169 /* Usually during RSA verification we have to parse an RSA key from a
170 * certificate or similar, in which case we'd need to construct a new
171 * RSA key, with a new |BN_MONT_CTX| for the public modulus. If we were
172 * to use |key| directly instead, then these costs wouldn't be
173 * accounted for. */
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700174 bssl::UniquePtr<RSA> verify_key(RSA_new());
Brian Smith7bee8532016-08-19 15:11:20 -1000175 if (!verify_key) {
176 return false;
177 }
178 verify_key->n = BN_dup(key->n);
179 verify_key->e = BN_dup(key->e);
180 if (!verify_key->n ||
181 !verify_key->e) {
182 return false;
183 }
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700184 return RSA_verify(NID_sha256, fake_sha256_hash,
185 sizeof(fake_sha256_hash), sig.get(), sig_len, key);
186 })) {
187 fprintf(stderr, "RSA_verify failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000188 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700189 return false;
190 }
191 results.Print(key_name + " verify");
192
193 return true;
194}
195
Adam Langley26725342015-01-28 15:52:57 -0800196static uint8_t *align(uint8_t *in, unsigned alignment) {
197 return reinterpret_cast<uint8_t *>(
Brian Smithd53b2c32015-03-17 00:37:06 -1000198 (reinterpret_cast<uintptr_t>(in) + alignment) &
199 ~static_cast<size_t>(alignment - 1));
David Benjamin384673c2015-01-21 15:56:14 -0500200}
Adam Langley543d0062015-01-15 16:05:41 -0800201
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700202static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
Adam Langleye7624342015-01-15 17:33:48 -0800203 size_t chunk_len, size_t ad_len) {
Adam Langley26725342015-01-28 15:52:57 -0800204 static const unsigned kAlignment = 16;
205
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700206 EVP_AEAD_CTX ctx;
207 const size_t key_len = EVP_AEAD_key_length(aead);
208 const size_t nonce_len = EVP_AEAD_nonce_length(aead);
209 const size_t overhead_len = EVP_AEAD_max_overhead(aead);
210
211 std::unique_ptr<uint8_t[]> key(new uint8_t[key_len]);
212 memset(key.get(), 0, key_len);
213 std::unique_ptr<uint8_t[]> nonce(new uint8_t[nonce_len]);
214 memset(nonce.get(), 0, nonce_len);
Brian Smith1d1562d2015-03-17 00:32:20 -1000215 std::unique_ptr<uint8_t[]> in_storage(new uint8_t[chunk_len + kAlignment]);
216 std::unique_ptr<uint8_t[]> out_storage(new uint8_t[chunk_len + overhead_len + kAlignment]);
Adam Langleye7624342015-01-15 17:33:48 -0800217 std::unique_ptr<uint8_t[]> ad(new uint8_t[ad_len]);
218 memset(ad.get(), 0, ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700219
Adam Langley26725342015-01-28 15:52:57 -0800220 uint8_t *const in = align(in_storage.get(), kAlignment);
221 memset(in, 0, chunk_len);
222 uint8_t *const out = align(out_storage.get(), kAlignment);
223 memset(out, 0, chunk_len + overhead_len);
224
David Benjamind434f282015-03-17 18:28:37 -0400225 if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, key.get(), key_len,
226 EVP_AEAD_DEFAULT_TAG_LENGTH,
227 evp_aead_seal)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700228 fprintf(stderr, "Failed to create EVP_AEAD_CTX.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000229 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700230 return false;
231 }
232
233 TimeResults results;
Adam Langley26725342015-01-28 15:52:57 -0800234 if (!TimeFunction(&results, [chunk_len, overhead_len, nonce_len, ad_len, in,
235 out, &ctx, &nonce, &ad]() -> bool {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700236 size_t out_len;
237
Adam Langleye7624342015-01-15 17:33:48 -0800238 return EVP_AEAD_CTX_seal(
Adam Langley26725342015-01-28 15:52:57 -0800239 &ctx, out, &out_len, chunk_len + overhead_len, nonce.get(),
240 nonce_len, in, chunk_len, ad.get(), ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700241 })) {
242 fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000243 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700244 return false;
245 }
246
247 results.PrintWithBytes(name + " seal", chunk_len);
248
249 EVP_AEAD_CTX_cleanup(&ctx);
250
251 return true;
252}
253
Adam Langleye7624342015-01-15 17:33:48 -0800254static bool SpeedAEAD(const EVP_AEAD *aead, const std::string &name,
Adam Langley90b58402015-04-13 11:04:18 -0700255 size_t ad_len, const std::string &selected) {
256 if (!selected.empty() && name.find(selected) == std::string::npos) {
257 return true;
258 }
259
Adam Langleye7624342015-01-15 17:33:48 -0800260 return SpeedAEADChunk(aead, name + " (16 bytes)", 16, ad_len) &&
261 SpeedAEADChunk(aead, name + " (1350 bytes)", 1350, ad_len) &&
262 SpeedAEADChunk(aead, name + " (8192 bytes)", 8192, ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700263}
264
Adam Langley006779a2014-06-20 12:00:00 -0700265static bool SpeedHashChunk(const EVP_MD *md, const std::string &name,
266 size_t chunk_len) {
267 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
268 uint8_t scratch[8192];
269
270 if (chunk_len > sizeof(scratch)) {
271 return false;
272 }
273
274 TimeResults results;
275 if (!TimeFunction(&results, [ctx, md, chunk_len, &scratch]() -> bool {
276 uint8_t digest[EVP_MAX_MD_SIZE];
277 unsigned int md_len;
278
279 return EVP_DigestInit_ex(ctx, md, NULL /* ENGINE */) &&
280 EVP_DigestUpdate(ctx, scratch, chunk_len) &&
281 EVP_DigestFinal_ex(ctx, digest, &md_len);
282 })) {
283 fprintf(stderr, "EVP_DigestInit_ex failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000284 ERR_print_errors_fp(stderr);
Adam Langley006779a2014-06-20 12:00:00 -0700285 return false;
286 }
287
288 results.PrintWithBytes(name, chunk_len);
289
290 EVP_MD_CTX_destroy(ctx);
291
292 return true;
293}
Adam Langley90b58402015-04-13 11:04:18 -0700294static bool SpeedHash(const EVP_MD *md, const std::string &name,
295 const std::string &selected) {
296 if (!selected.empty() && name.find(selected) == std::string::npos) {
297 return true;
298 }
299
Adam Langley006779a2014-06-20 12:00:00 -0700300 return SpeedHashChunk(md, name + " (16 bytes)", 16) &&
301 SpeedHashChunk(md, name + " (256 bytes)", 256) &&
302 SpeedHashChunk(md, name + " (8192 bytes)", 8192);
303}
304
Adam Langley90b58402015-04-13 11:04:18 -0700305static bool SpeedRandomChunk(const std::string name, size_t chunk_len) {
306 uint8_t scratch[8192];
307
308 if (chunk_len > sizeof(scratch)) {
309 return false;
310 }
311
312 TimeResults results;
313 if (!TimeFunction(&results, [chunk_len, &scratch]() -> bool {
314 RAND_bytes(scratch, chunk_len);
315 return true;
316 })) {
317 return false;
318 }
319
320 results.PrintWithBytes(name, chunk_len);
321 return true;
322}
323
324static bool SpeedRandom(const std::string &selected) {
325 if (!selected.empty() && selected != "RNG") {
326 return true;
327 }
328
329 return SpeedRandomChunk("RNG (16 bytes)", 16) &&
330 SpeedRandomChunk("RNG (256 bytes)", 256) &&
331 SpeedRandomChunk("RNG (8192 bytes)", 8192);
332}
333
Adam Langleyad6b28e2015-04-14 12:07:44 -0700334static bool SpeedECDHCurve(const std::string &name, int nid,
335 const std::string &selected) {
336 if (!selected.empty() && name.find(selected) == std::string::npos) {
337 return true;
338 }
339
340 TimeResults results;
341 if (!TimeFunction(&results, [nid]() -> bool {
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700342 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
Adam Langleyad6b28e2015-04-14 12:07:44 -0700343 if (!key ||
344 !EC_KEY_generate_key(key.get())) {
345 return false;
346 }
347 const EC_GROUP *const group = EC_KEY_get0_group(key.get());
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700348 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group));
349 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
Adam Langleyad6b28e2015-04-14 12:07:44 -0700350
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700351 bssl::UniquePtr<BIGNUM> x(BN_new());
352 bssl::UniquePtr<BIGNUM> y(BN_new());
Adam Langleyad6b28e2015-04-14 12:07:44 -0700353
354 if (!point || !ctx || !x || !y ||
355 !EC_POINT_mul(group, point.get(), NULL,
356 EC_KEY_get0_public_key(key.get()),
357 EC_KEY_get0_private_key(key.get()), ctx.get()) ||
358 !EC_POINT_get_affine_coordinates_GFp(group, point.get(), x.get(),
359 y.get(), ctx.get())) {
360 return false;
361 }
362
363 return true;
364 })) {
365 return false;
366 }
367
368 results.Print(name);
369 return true;
370}
371
372static bool SpeedECDSACurve(const std::string &name, int nid,
373 const std::string &selected) {
374 if (!selected.empty() && name.find(selected) == std::string::npos) {
375 return true;
376 }
377
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700378 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
Adam Langleyad6b28e2015-04-14 12:07:44 -0700379 if (!key ||
380 !EC_KEY_generate_key(key.get())) {
381 return false;
382 }
383
384 uint8_t signature[256];
385 if (ECDSA_size(key.get()) > sizeof(signature)) {
386 return false;
387 }
388 uint8_t digest[20];
389 memset(digest, 42, sizeof(digest));
390 unsigned sig_len;
391
392 TimeResults results;
393 if (!TimeFunction(&results, [&key, &signature, &digest, &sig_len]() -> bool {
394 return ECDSA_sign(0, digest, sizeof(digest), signature, &sig_len,
395 key.get()) == 1;
396 })) {
397 return false;
398 }
399
400 results.Print(name + " signing");
401
402 if (!TimeFunction(&results, [&key, &signature, &digest, sig_len]() -> bool {
403 return ECDSA_verify(0, digest, sizeof(digest), signature, sig_len,
404 key.get()) == 1;
405 })) {
406 return false;
407 }
408
409 results.Print(name + " verify");
410
411 return true;
412}
413
414static bool SpeedECDH(const std::string &selected) {
415 return SpeedECDHCurve("ECDH P-224", NID_secp224r1, selected) &&
416 SpeedECDHCurve("ECDH P-256", NID_X9_62_prime256v1, selected) &&
417 SpeedECDHCurve("ECDH P-384", NID_secp384r1, selected) &&
418 SpeedECDHCurve("ECDH P-521", NID_secp521r1, selected);
419}
420
421static bool SpeedECDSA(const std::string &selected) {
422 return SpeedECDSACurve("ECDSA P-224", NID_secp224r1, selected) &&
423 SpeedECDSACurve("ECDSA P-256", NID_X9_62_prime256v1, selected) &&
424 SpeedECDSACurve("ECDSA P-384", NID_secp384r1, selected) &&
425 SpeedECDSACurve("ECDSA P-521", NID_secp521r1, selected);
426}
427
Adam Langley4fb0dc42015-11-13 13:09:47 -0800428static bool Speed25519(const std::string &selected) {
429 if (!selected.empty() && selected.find("25519") == std::string::npos) {
430 return true;
431 }
432
433 TimeResults results;
434
Adam Langley4fb0dc42015-11-13 13:09:47 -0800435 uint8_t public_key[32], private_key[64];
436
437 if (!TimeFunction(&results, [&public_key, &private_key]() -> bool {
438 ED25519_keypair(public_key, private_key);
439 return true;
440 })) {
441 return false;
442 }
443
444 results.Print("Ed25519 key generation");
445
446 static const uint8_t kMessage[] = {0, 1, 2, 3, 4, 5};
447 uint8_t signature[64];
448
449 if (!TimeFunction(&results, [&private_key, &signature]() -> bool {
450 return ED25519_sign(signature, kMessage, sizeof(kMessage),
451 private_key) == 1;
452 })) {
453 return false;
454 }
455
456 results.Print("Ed25519 signing");
457
458 if (!TimeFunction(&results, [&public_key, &signature]() -> bool {
459 return ED25519_verify(kMessage, sizeof(kMessage), signature,
460 public_key) == 1;
461 })) {
462 fprintf(stderr, "Ed25519 verify failed.\n");
463 return false;
464 }
465
466 results.Print("Ed25519 verify");
Adam Langley4fb0dc42015-11-13 13:09:47 -0800467
468 if (!TimeFunction(&results, []() -> bool {
469 uint8_t out[32], in[32];
470 memset(in, 0, sizeof(in));
471 X25519_public_from_private(out, in);
472 return true;
473 })) {
474 fprintf(stderr, "Curve25519 base-point multiplication failed.\n");
475 return false;
476 }
477
478 results.Print("Curve25519 base-point multiplication");
479
480 if (!TimeFunction(&results, []() -> bool {
481 uint8_t out[32], in1[32], in2[32];
482 memset(in1, 0, sizeof(in1));
483 memset(in2, 0, sizeof(in2));
Adam Langley3ac32b12015-11-17 15:15:05 -0800484 in1[0] = 1;
485 in2[0] = 9;
Adam Langley4fb0dc42015-11-13 13:09:47 -0800486 return X25519(out, in1, in2) == 1;
487 })) {
488 fprintf(stderr, "Curve25519 arbitrary point multiplication failed.\n");
489 return false;
490 }
491
492 results.Print("Curve25519 arbitrary point multiplication");
493
494 return true;
495}
496
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800497static bool SpeedSPAKE2(const std::string &selected) {
498 if (!selected.empty() && selected.find("SPAKE2") == std::string::npos) {
499 return true;
500 }
501
502 TimeResults results;
503
504 static const uint8_t kAliceName[] = {'A'};
505 static const uint8_t kBobName[] = {'B'};
506 static const uint8_t kPassword[] = "password";
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700507 bssl::UniquePtr<SPAKE2_CTX> alice(SPAKE2_CTX_new(spake2_role_alice,
508 kAliceName, sizeof(kAliceName), kBobName,
509 sizeof(kBobName)));
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800510 uint8_t alice_msg[SPAKE2_MAX_MSG_SIZE];
511 size_t alice_msg_len;
512
513 if (!SPAKE2_generate_msg(alice.get(), alice_msg, &alice_msg_len,
514 sizeof(alice_msg),
515 kPassword, sizeof(kPassword))) {
516 fprintf(stderr, "SPAKE2_generate_msg failed.\n");
517 return false;
518 }
519
Adam Langley708db162016-03-01 11:48:00 -0800520 if (!TimeFunction(&results, [&alice_msg, alice_msg_len]() -> bool {
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700521 bssl::UniquePtr<SPAKE2_CTX> bob(SPAKE2_CTX_new(spake2_role_bob,
522 kBobName, sizeof(kBobName), kAliceName,
523 sizeof(kAliceName)));
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800524 uint8_t bob_msg[SPAKE2_MAX_MSG_SIZE], bob_key[64];
525 size_t bob_msg_len, bob_key_len;
526 if (!SPAKE2_generate_msg(bob.get(), bob_msg, &bob_msg_len,
527 sizeof(bob_msg), kPassword,
528 sizeof(kPassword)) ||
529 !SPAKE2_process_msg(bob.get(), bob_key, &bob_key_len,
530 sizeof(bob_key), alice_msg, alice_msg_len)) {
531 return false;
532 }
533
534 return true;
535 })) {
536 fprintf(stderr, "SPAKE2 failed.\n");
537 }
538
539 results.Print("SPAKE2 over Ed25519");
540
541 return true;
542}
543
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700544static bool SpeedNewHope(const std::string &selected) {
545 if (!selected.empty() && selected.find("newhope") == std::string::npos) {
546 return true;
547 }
548
549 TimeResults results;
550 NEWHOPE_POLY *sk = NEWHOPE_POLY_new();
Matt Braithwaitee09e5792016-05-19 10:30:52 -0700551 uint8_t acceptmsg[NEWHOPE_ACCEPTMSG_LENGTH];
552 RAND_bytes(acceptmsg, sizeof(acceptmsg));
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700553
Matt Braithwaitee09e5792016-05-19 10:30:52 -0700554 if (!TimeFunction(&results, [sk, &acceptmsg]() -> bool {
555 uint8_t key[SHA256_DIGEST_LENGTH];
556 uint8_t offermsg[NEWHOPE_OFFERMSG_LENGTH];
557 NEWHOPE_offer(offermsg, sk);
558 if (!NEWHOPE_finish(key, sk, acceptmsg, NEWHOPE_ACCEPTMSG_LENGTH)) {
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700559 return false;
560 }
561 return true;
562 })) {
563 fprintf(stderr, "failed to exchange key.\n");
564 return false;
565 }
566
567 NEWHOPE_POLY_free(sk);
Matt Braithwaitee09e5792016-05-19 10:30:52 -0700568 results.Print("newhope key exchange");
Matt Braithwaite045a0ff2016-04-18 11:30:19 -0700569 return true;
570}
571
David Benjaminbcb65b92016-08-14 22:06:49 -0400572static const struct argument kArguments[] = {
573 {
574 "-filter", kOptionalArgument,
575 "A filter on the speed tests to run",
576 },
577 {
578 "-timeout", kOptionalArgument,
579 "The number of seconds to run each test for (default is 1)",
580 },
581 {
582 "", kOptionalArgument, "",
583 },
584};
585
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700586bool Speed(const std::vector<std::string> &args) {
David Benjaminbcb65b92016-08-14 22:06:49 -0400587 std::map<std::string, std::string> args_map;
588 if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
589 PrintUsage(kArguments);
Adam Langley90b58402015-04-13 11:04:18 -0700590 return false;
591 }
David Benjaminbcb65b92016-08-14 22:06:49 -0400592
593 std::string selected;
594 if (args_map.count("-filter") != 0) {
595 selected = args_map["-filter"];
596 }
597
598 if (args_map.count("-timeout") != 0) {
599 g_timeout_seconds = atoi(args_map["-timeout"].c_str());
Adam Langley90b58402015-04-13 11:04:18 -0700600 }
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700601
David Benjamin74f71102015-06-27 14:56:25 -0400602 RSA *key = RSA_private_key_from_bytes(kDERRSAPrivate2048,
603 kDERRSAPrivate2048Len);
604 if (key == NULL) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700605 fprintf(stderr, "Failed to parse RSA key.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000606 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700607 return false;
608 }
609
Adam Langley90b58402015-04-13 11:04:18 -0700610 if (!SpeedRSA("RSA 2048", key, selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700611 return false;
612 }
613
614 RSA_free(key);
David Benjamin74f71102015-06-27 14:56:25 -0400615 key = RSA_private_key_from_bytes(kDERRSAPrivate3Prime2048,
616 kDERRSAPrivate3Prime2048Len);
617 if (key == NULL) {
Adam Langley839b8812015-05-26 11:36:46 -0700618 fprintf(stderr, "Failed to parse RSA key.\n");
619 ERR_print_errors_fp(stderr);
620 return false;
621 }
622
623 if (!SpeedRSA("RSA 2048 (3 prime, e=3)", key, selected)) {
624 return false;
625 }
626
627 RSA_free(key);
David Benjamin74f71102015-06-27 14:56:25 -0400628 key = RSA_private_key_from_bytes(kDERRSAPrivate4096,
629 kDERRSAPrivate4096Len);
630 if (key == NULL) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700631 fprintf(stderr, "Failed to parse 4096-bit RSA key.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000632 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700633 return 1;
634 }
635
Adam Langley90b58402015-04-13 11:04:18 -0700636 if (!SpeedRSA("RSA 4096", key, selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700637 return false;
638 }
639
640 RSA_free(key);
641
Adam Langleye7624342015-01-15 17:33:48 -0800642 // kTLSADLen is the number of bytes of additional data that TLS passes to
643 // AEADs.
644 static const size_t kTLSADLen = 13;
645 // kLegacyADLen is the number of bytes that TLS passes to the "legacy" AEADs.
646 // These are AEADs that weren't originally defined as AEADs, but which we use
647 // via the AEAD interface. In order for that to work, they have some TLS
648 // knowledge in them and construct a couple of the AD bytes internally.
649 static const size_t kLegacyADLen = kTLSADLen - 2;
650
Adam Langley90b58402015-04-13 11:04:18 -0700651 if (!SpeedAEAD(EVP_aead_aes_128_gcm(), "AES-128-GCM", kTLSADLen, selected) ||
652 !SpeedAEAD(EVP_aead_aes_256_gcm(), "AES-256-GCM", kTLSADLen, selected) ||
David Benjamin8ffab722015-11-30 18:48:18 -0500653 !SpeedAEAD(EVP_aead_chacha20_poly1305(), "ChaCha20-Poly1305", kTLSADLen,
654 selected) ||
Brian Smith3e23e4c2015-10-03 11:38:58 -1000655 !SpeedAEAD(EVP_aead_chacha20_poly1305_old(), "ChaCha20-Poly1305-Old",
656 kTLSADLen, selected) ||
David Benjamindf571632015-12-07 19:48:16 -0500657 !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}