blob: 52708c073804a4d9aa3ff1b90a6c44b680e67e45 [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>
David Benjamin98193672016-03-25 18:07:11 -040032#include <openssl/nid.h>
Adam Langley92b6b022015-04-16 14:01:33 -070033#include <openssl/rand.h>
34#include <openssl/rsa.h>
35
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070036#if defined(OPENSSL_WINDOWS)
David Benjamina353cdb2016-06-09 16:48:33 -040037OPENSSL_MSVC_PRAGMA(warning(push, 3))
Adam Langley3e719312015-03-20 16:32:23 -070038#include <windows.h>
David Benjamina353cdb2016-06-09 16:48:33 -040039OPENSSL_MSVC_PRAGMA(warning(pop))
Adam Langley30eda1d2014-06-24 11:15:12 -070040#elif defined(OPENSSL_APPLE)
41#include <sys/time.h>
David Benjamin2f401ec2016-09-09 19:49:35 -040042#else
43#include <time.h>
Adam Langleyc5c0c7e2014-06-20 12:00:00 -070044#endif
45
David Benjamin17cf2cb2016-12-13 01:07:13 -050046#include "../crypto/internal.h"
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
David Benjamin0cce8632016-10-20 15:13:26 -0400206 bssl::ScopedEVP_AEAD_CTX ctx;
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700207 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]);
David Benjamin17cf2cb2016-12-13 01:07:13 -0500212 OPENSSL_memset(key.get(), 0, key_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700213 std::unique_ptr<uint8_t[]> nonce(new uint8_t[nonce_len]);
David Benjamin17cf2cb2016-12-13 01:07:13 -0500214 OPENSSL_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]);
David Benjamin17cf2cb2016-12-13 01:07:13 -0500218 OPENSSL_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);
David Benjamin17cf2cb2016-12-13 01:07:13 -0500221 OPENSSL_memset(in, 0, chunk_len);
Adam Langley26725342015-01-28 15:52:57 -0800222 uint8_t *const out = align(out_storage.get(), kAlignment);
David Benjamin17cf2cb2016-12-13 01:07:13 -0500223 OPENSSL_memset(out, 0, chunk_len + overhead_len);
Adam Langley26725342015-01-28 15:52:57 -0800224
David Benjamin0cce8632016-10-20 15:13:26 -0400225 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.get(), key_len,
David Benjamind434f282015-03-17 18:28:37 -0400226 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;
David Benjamin0cce8632016-10-20 15:13:26 -0400237 return EVP_AEAD_CTX_seal(ctx.get(), out, &out_len,
238 chunk_len + overhead_len, nonce.get(),
239 nonce_len, in, chunk_len, ad.get(), ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700240 })) {
241 fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000242 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700243 return false;
244 }
245
246 results.PrintWithBytes(name + " seal", chunk_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700247 return true;
248}
249
Adam Langleye7624342015-01-15 17:33:48 -0800250static bool SpeedAEAD(const EVP_AEAD *aead, const std::string &name,
Adam Langley90b58402015-04-13 11:04:18 -0700251 size_t ad_len, const std::string &selected) {
252 if (!selected.empty() && name.find(selected) == std::string::npos) {
253 return true;
254 }
255
Adam Langleye7624342015-01-15 17:33:48 -0800256 return SpeedAEADChunk(aead, name + " (16 bytes)", 16, ad_len) &&
257 SpeedAEADChunk(aead, name + " (1350 bytes)", 1350, ad_len) &&
258 SpeedAEADChunk(aead, name + " (8192 bytes)", 8192, ad_len);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700259}
260
Adam Langley006779a2014-06-20 12:00:00 -0700261static bool SpeedHashChunk(const EVP_MD *md, const std::string &name,
262 size_t chunk_len) {
263 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
264 uint8_t scratch[8192];
265
266 if (chunk_len > sizeof(scratch)) {
267 return false;
268 }
269
270 TimeResults results;
271 if (!TimeFunction(&results, [ctx, md, chunk_len, &scratch]() -> bool {
272 uint8_t digest[EVP_MAX_MD_SIZE];
273 unsigned int md_len;
274
275 return EVP_DigestInit_ex(ctx, md, NULL /* ENGINE */) &&
276 EVP_DigestUpdate(ctx, scratch, chunk_len) &&
277 EVP_DigestFinal_ex(ctx, digest, &md_len);
278 })) {
279 fprintf(stderr, "EVP_DigestInit_ex failed.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000280 ERR_print_errors_fp(stderr);
Adam Langley006779a2014-06-20 12:00:00 -0700281 return false;
282 }
283
284 results.PrintWithBytes(name, chunk_len);
285
286 EVP_MD_CTX_destroy(ctx);
287
288 return true;
289}
Adam Langley90b58402015-04-13 11:04:18 -0700290static bool SpeedHash(const EVP_MD *md, const std::string &name,
291 const std::string &selected) {
292 if (!selected.empty() && name.find(selected) == std::string::npos) {
293 return true;
294 }
295
Adam Langley006779a2014-06-20 12:00:00 -0700296 return SpeedHashChunk(md, name + " (16 bytes)", 16) &&
297 SpeedHashChunk(md, name + " (256 bytes)", 256) &&
298 SpeedHashChunk(md, name + " (8192 bytes)", 8192);
299}
300
David Benjamin1e5ac5d2016-11-01 16:37:09 -0400301static bool SpeedRandomChunk(const std::string &name, size_t chunk_len) {
Adam Langley90b58402015-04-13 11:04:18 -0700302 uint8_t scratch[8192];
303
304 if (chunk_len > sizeof(scratch)) {
305 return false;
306 }
307
308 TimeResults results;
309 if (!TimeFunction(&results, [chunk_len, &scratch]() -> bool {
310 RAND_bytes(scratch, chunk_len);
311 return true;
312 })) {
313 return false;
314 }
315
316 results.PrintWithBytes(name, chunk_len);
317 return true;
318}
319
320static bool SpeedRandom(const std::string &selected) {
321 if (!selected.empty() && selected != "RNG") {
322 return true;
323 }
324
325 return SpeedRandomChunk("RNG (16 bytes)", 16) &&
326 SpeedRandomChunk("RNG (256 bytes)", 256) &&
327 SpeedRandomChunk("RNG (8192 bytes)", 8192);
328}
329
Adam Langleyad6b28e2015-04-14 12:07:44 -0700330static bool SpeedECDHCurve(const std::string &name, int nid,
331 const std::string &selected) {
332 if (!selected.empty() && name.find(selected) == std::string::npos) {
333 return true;
334 }
335
336 TimeResults results;
337 if (!TimeFunction(&results, [nid]() -> bool {
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700338 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
Adam Langleyad6b28e2015-04-14 12:07:44 -0700339 if (!key ||
340 !EC_KEY_generate_key(key.get())) {
341 return false;
342 }
343 const EC_GROUP *const group = EC_KEY_get0_group(key.get());
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700344 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group));
345 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
Adam Langleyad6b28e2015-04-14 12:07:44 -0700346
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700347 bssl::UniquePtr<BIGNUM> x(BN_new());
348 bssl::UniquePtr<BIGNUM> y(BN_new());
Adam Langleyad6b28e2015-04-14 12:07:44 -0700349
350 if (!point || !ctx || !x || !y ||
351 !EC_POINT_mul(group, point.get(), NULL,
352 EC_KEY_get0_public_key(key.get()),
353 EC_KEY_get0_private_key(key.get()), ctx.get()) ||
354 !EC_POINT_get_affine_coordinates_GFp(group, point.get(), x.get(),
355 y.get(), ctx.get())) {
356 return false;
357 }
358
359 return true;
360 })) {
361 return false;
362 }
363
364 results.Print(name);
365 return true;
366}
367
368static bool SpeedECDSACurve(const std::string &name, int nid,
369 const std::string &selected) {
370 if (!selected.empty() && name.find(selected) == std::string::npos) {
371 return true;
372 }
373
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700374 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
Adam Langleyad6b28e2015-04-14 12:07:44 -0700375 if (!key ||
376 !EC_KEY_generate_key(key.get())) {
377 return false;
378 }
379
380 uint8_t signature[256];
381 if (ECDSA_size(key.get()) > sizeof(signature)) {
382 return false;
383 }
384 uint8_t digest[20];
David Benjamin17cf2cb2016-12-13 01:07:13 -0500385 OPENSSL_memset(digest, 42, sizeof(digest));
Adam Langleyad6b28e2015-04-14 12:07:44 -0700386 unsigned sig_len;
387
388 TimeResults results;
389 if (!TimeFunction(&results, [&key, &signature, &digest, &sig_len]() -> bool {
390 return ECDSA_sign(0, digest, sizeof(digest), signature, &sig_len,
391 key.get()) == 1;
392 })) {
393 return false;
394 }
395
396 results.Print(name + " signing");
397
398 if (!TimeFunction(&results, [&key, &signature, &digest, sig_len]() -> bool {
399 return ECDSA_verify(0, digest, sizeof(digest), signature, sig_len,
400 key.get()) == 1;
401 })) {
402 return false;
403 }
404
405 results.Print(name + " verify");
406
407 return true;
408}
409
410static bool SpeedECDH(const std::string &selected) {
411 return SpeedECDHCurve("ECDH P-224", NID_secp224r1, selected) &&
412 SpeedECDHCurve("ECDH P-256", NID_X9_62_prime256v1, selected) &&
413 SpeedECDHCurve("ECDH P-384", NID_secp384r1, selected) &&
414 SpeedECDHCurve("ECDH P-521", NID_secp521r1, selected);
415}
416
417static bool SpeedECDSA(const std::string &selected) {
418 return SpeedECDSACurve("ECDSA P-224", NID_secp224r1, selected) &&
419 SpeedECDSACurve("ECDSA P-256", NID_X9_62_prime256v1, selected) &&
420 SpeedECDSACurve("ECDSA P-384", NID_secp384r1, selected) &&
421 SpeedECDSACurve("ECDSA P-521", NID_secp521r1, selected);
422}
423
Adam Langley4fb0dc42015-11-13 13:09:47 -0800424static bool Speed25519(const std::string &selected) {
425 if (!selected.empty() && selected.find("25519") == std::string::npos) {
426 return true;
427 }
428
429 TimeResults results;
430
Adam Langley4fb0dc42015-11-13 13:09:47 -0800431 uint8_t public_key[32], private_key[64];
432
433 if (!TimeFunction(&results, [&public_key, &private_key]() -> bool {
434 ED25519_keypair(public_key, private_key);
435 return true;
436 })) {
437 return false;
438 }
439
440 results.Print("Ed25519 key generation");
441
442 static const uint8_t kMessage[] = {0, 1, 2, 3, 4, 5};
443 uint8_t signature[64];
444
445 if (!TimeFunction(&results, [&private_key, &signature]() -> bool {
446 return ED25519_sign(signature, kMessage, sizeof(kMessage),
447 private_key) == 1;
448 })) {
449 return false;
450 }
451
452 results.Print("Ed25519 signing");
453
454 if (!TimeFunction(&results, [&public_key, &signature]() -> bool {
455 return ED25519_verify(kMessage, sizeof(kMessage), signature,
456 public_key) == 1;
457 })) {
458 fprintf(stderr, "Ed25519 verify failed.\n");
459 return false;
460 }
461
462 results.Print("Ed25519 verify");
Adam Langley4fb0dc42015-11-13 13:09:47 -0800463
464 if (!TimeFunction(&results, []() -> bool {
465 uint8_t out[32], in[32];
David Benjamin17cf2cb2016-12-13 01:07:13 -0500466 OPENSSL_memset(in, 0, sizeof(in));
Adam Langley4fb0dc42015-11-13 13:09:47 -0800467 X25519_public_from_private(out, in);
468 return true;
469 })) {
470 fprintf(stderr, "Curve25519 base-point multiplication failed.\n");
471 return false;
472 }
473
474 results.Print("Curve25519 base-point multiplication");
475
476 if (!TimeFunction(&results, []() -> bool {
477 uint8_t out[32], in1[32], in2[32];
David Benjamin17cf2cb2016-12-13 01:07:13 -0500478 OPENSSL_memset(in1, 0, sizeof(in1));
479 OPENSSL_memset(in2, 0, sizeof(in2));
Adam Langley3ac32b12015-11-17 15:15:05 -0800480 in1[0] = 1;
481 in2[0] = 9;
Adam Langley4fb0dc42015-11-13 13:09:47 -0800482 return X25519(out, in1, in2) == 1;
483 })) {
484 fprintf(stderr, "Curve25519 arbitrary point multiplication failed.\n");
485 return false;
486 }
487
488 results.Print("Curve25519 arbitrary point multiplication");
489
490 return true;
491}
492
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800493static bool SpeedSPAKE2(const std::string &selected) {
494 if (!selected.empty() && selected.find("SPAKE2") == std::string::npos) {
495 return true;
496 }
497
498 TimeResults results;
499
500 static const uint8_t kAliceName[] = {'A'};
501 static const uint8_t kBobName[] = {'B'};
502 static const uint8_t kPassword[] = "password";
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700503 bssl::UniquePtr<SPAKE2_CTX> alice(SPAKE2_CTX_new(spake2_role_alice,
504 kAliceName, sizeof(kAliceName), kBobName,
505 sizeof(kBobName)));
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800506 uint8_t alice_msg[SPAKE2_MAX_MSG_SIZE];
507 size_t alice_msg_len;
508
509 if (!SPAKE2_generate_msg(alice.get(), alice_msg, &alice_msg_len,
510 sizeof(alice_msg),
511 kPassword, sizeof(kPassword))) {
512 fprintf(stderr, "SPAKE2_generate_msg failed.\n");
513 return false;
514 }
515
Adam Langley708db162016-03-01 11:48:00 -0800516 if (!TimeFunction(&results, [&alice_msg, alice_msg_len]() -> bool {
Matt Braithwaited17d74d2016-08-17 20:10:28 -0700517 bssl::UniquePtr<SPAKE2_CTX> bob(SPAKE2_CTX_new(spake2_role_bob,
518 kBobName, sizeof(kBobName), kAliceName,
519 sizeof(kAliceName)));
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800520 uint8_t bob_msg[SPAKE2_MAX_MSG_SIZE], bob_key[64];
521 size_t bob_msg_len, bob_key_len;
522 if (!SPAKE2_generate_msg(bob.get(), bob_msg, &bob_msg_len,
523 sizeof(bob_msg), kPassword,
524 sizeof(kPassword)) ||
525 !SPAKE2_process_msg(bob.get(), bob_key, &bob_key_len,
526 sizeof(bob_key), alice_msg, alice_msg_len)) {
527 return false;
528 }
529
530 return true;
531 })) {
532 fprintf(stderr, "SPAKE2 failed.\n");
533 }
534
535 results.Print("SPAKE2 over Ed25519");
536
537 return true;
538}
539
David Benjaminbcb65b92016-08-14 22:06:49 -0400540static const struct argument kArguments[] = {
541 {
542 "-filter", kOptionalArgument,
543 "A filter on the speed tests to run",
544 },
545 {
546 "-timeout", kOptionalArgument,
547 "The number of seconds to run each test for (default is 1)",
548 },
549 {
550 "", kOptionalArgument, "",
551 },
552};
553
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700554bool Speed(const std::vector<std::string> &args) {
David Benjaminbcb65b92016-08-14 22:06:49 -0400555 std::map<std::string, std::string> args_map;
556 if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
557 PrintUsage(kArguments);
Adam Langley90b58402015-04-13 11:04:18 -0700558 return false;
559 }
David Benjaminbcb65b92016-08-14 22:06:49 -0400560
561 std::string selected;
562 if (args_map.count("-filter") != 0) {
563 selected = args_map["-filter"];
564 }
565
566 if (args_map.count("-timeout") != 0) {
567 g_timeout_seconds = atoi(args_map["-timeout"].c_str());
Adam Langley90b58402015-04-13 11:04:18 -0700568 }
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700569
David Benjamin0cce8632016-10-20 15:13:26 -0400570 bssl::UniquePtr<RSA> key(
571 RSA_private_key_from_bytes(kDERRSAPrivate2048, kDERRSAPrivate2048Len));
572 if (key == nullptr) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700573 fprintf(stderr, "Failed to parse RSA key.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000574 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700575 return false;
576 }
577
David Benjamin0cce8632016-10-20 15:13:26 -0400578 if (!SpeedRSA("RSA 2048", key.get(), selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700579 return false;
580 }
581
David Benjamin0cce8632016-10-20 15:13:26 -0400582 key.reset(RSA_private_key_from_bytes(kDERRSAPrivate3Prime2048,
583 kDERRSAPrivate3Prime2048Len));
584 if (key == nullptr) {
Adam Langley839b8812015-05-26 11:36:46 -0700585 fprintf(stderr, "Failed to parse RSA key.\n");
586 ERR_print_errors_fp(stderr);
587 return false;
588 }
589
David Benjamin0cce8632016-10-20 15:13:26 -0400590 if (!SpeedRSA("RSA 2048 (3 prime, e=3)", key.get(), selected)) {
Adam Langley839b8812015-05-26 11:36:46 -0700591 return false;
592 }
593
David Benjamin0cce8632016-10-20 15:13:26 -0400594 key.reset(
595 RSA_private_key_from_bytes(kDERRSAPrivate4096, kDERRSAPrivate4096Len));
596 if (key == nullptr) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700597 fprintf(stderr, "Failed to parse 4096-bit RSA key.\n");
Brian Smith83a82982015-04-09 16:21:10 -1000598 ERR_print_errors_fp(stderr);
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700599 return 1;
600 }
601
David Benjamin0cce8632016-10-20 15:13:26 -0400602 if (!SpeedRSA("RSA 4096", key.get(), selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700603 return false;
604 }
605
David Benjamin0cce8632016-10-20 15:13:26 -0400606 key.reset();
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700607
Adam Langleye7624342015-01-15 17:33:48 -0800608 // kTLSADLen is the number of bytes of additional data that TLS passes to
609 // AEADs.
610 static const size_t kTLSADLen = 13;
611 // kLegacyADLen is the number of bytes that TLS passes to the "legacy" AEADs.
612 // These are AEADs that weren't originally defined as AEADs, but which we use
613 // via the AEAD interface. In order for that to work, they have some TLS
614 // knowledge in them and construct a couple of the AD bytes internally.
615 static const size_t kLegacyADLen = kTLSADLen - 2;
616
Adam Langley90b58402015-04-13 11:04:18 -0700617 if (!SpeedAEAD(EVP_aead_aes_128_gcm(), "AES-128-GCM", kTLSADLen, selected) ||
618 !SpeedAEAD(EVP_aead_aes_256_gcm(), "AES-256-GCM", kTLSADLen, selected) ||
David Benjamin8ffab722015-11-30 18:48:18 -0500619 !SpeedAEAD(EVP_aead_chacha20_poly1305(), "ChaCha20-Poly1305", kTLSADLen,
620 selected) ||
Brian Smith3e23e4c2015-10-03 11:38:58 -1000621 !SpeedAEAD(EVP_aead_chacha20_poly1305_old(), "ChaCha20-Poly1305-Old",
622 kTLSADLen, selected) ||
David Benjamindf571632015-12-07 19:48:16 -0500623 !SpeedAEAD(EVP_aead_des_ede3_cbc_sha1_tls(), "DES-EDE3-CBC-SHA1",
624 kLegacyADLen, selected) ||
Adam Langley90b58402015-04-13 11:04:18 -0700625 !SpeedAEAD(EVP_aead_aes_128_cbc_sha1_tls(), "AES-128-CBC-SHA1",
626 kLegacyADLen, selected) ||
627 !SpeedAEAD(EVP_aead_aes_256_cbc_sha1_tls(), "AES-256-CBC-SHA1",
628 kLegacyADLen, selected) ||
Adam Langleydf447ba2016-12-01 08:24:24 -0800629#if !defined(OPENSSL_SMALL)
630 !SpeedAEAD(EVP_aead_aes_128_gcm_siv(), "AES-128-GCM-SIV", kTLSADLen,
631 selected) ||
632 !SpeedAEAD(EVP_aead_aes_256_gcm_siv(), "AES-256-GCM-SIV", kTLSADLen,
633 selected) ||
634#endif
Adam Langley90b58402015-04-13 11:04:18 -0700635 !SpeedHash(EVP_sha1(), "SHA-1", selected) ||
636 !SpeedHash(EVP_sha256(), "SHA-256", selected) ||
637 !SpeedHash(EVP_sha512(), "SHA-512", selected) ||
Adam Langleyad6b28e2015-04-14 12:07:44 -0700638 !SpeedRandom(selected) ||
639 !SpeedECDH(selected) ||
Adam Langley4fb0dc42015-11-13 13:09:47 -0800640 !SpeedECDSA(selected) ||
Arnar Birgissonf27459e2016-02-09 18:09:00 -0800641 !Speed25519(selected) ||
Matthew Braithwaitef440e822016-12-09 16:41:07 -0800642 !SpeedSPAKE2(selected)) {
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700643 return false;
644 }
645
Adam Langley90b58402015-04-13 11:04:18 -0700646 return true;
Adam Langleyc5c0c7e2014-06-20 12:00:00 -0700647}