summaryrefslogtreecommitdiff
path: root/tools/crypto_bench.c (plain)
blob: 203bffe19832866451d76c1ee363a33414e6647e
1/*
2 * Copyright (c) 2013 Nicolas George
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/* Optional external libraries; can be enabled using:
22 * make VERSUS=crypto+gcrypt+tomcrypt tools/crypto_bench */
23#define USE_crypto 0x01 /* OpenSSL's libcrypto */
24#define USE_gcrypt 0x02 /* GnuTLS's libgcrypt */
25#define USE_tomcrypt 0x04 /* LibTomCrypt */
26
27#include <stdlib.h>
28#include <math.h>
29
30#include "libavutil/avutil.h"
31#include "libavutil/avstring.h"
32#include "libavutil/crc.h"
33#include "libavutil/intreadwrite.h"
34#include "libavutil/timer.h"
35
36#ifndef AV_READ_TIME
37#define AV_READ_TIME(x) 0
38#endif
39
40#if HAVE_UNISTD_H
41#include <unistd.h> /* for getopt */
42#endif
43#if !HAVE_GETOPT
44#include "compat/getopt.c"
45#endif
46
47#define MAX_INPUT_SIZE 1048576
48#define MAX_OUTPUT_SIZE 128
49
50static const char *enabled_libs;
51static const char *enabled_algos;
52static unsigned specified_runs;
53
54static const uint8_t *hardcoded_key = "FFmpeg is the best program ever.";
55
56static void fatal_error(const char *tag)
57{
58 av_log(NULL, AV_LOG_ERROR, "Fatal error: %s\n", tag);
59 exit(1);
60}
61
62struct hash_impl {
63 const char *lib;
64 const char *name;
65 void (*run)(uint8_t *output, const uint8_t *input, unsigned size);
66 const char *output;
67};
68
69/***************************************************************************
70 * lavu: libavutil
71 ***************************************************************************/
72
73#include "libavutil/md5.h"
74#include "libavutil/sha.h"
75#include "libavutil/sha512.h"
76#include "libavutil/ripemd.h"
77#include "libavutil/aes.h"
78#include "libavutil/blowfish.h"
79#include "libavutil/camellia.h"
80#include "libavutil/cast5.h"
81#include "libavutil/des.h"
82#include "libavutil/twofish.h"
83#include "libavutil/rc4.h"
84#include "libavutil/xtea.h"
85
86#define IMPL_USE_lavu IMPL_USE
87
88static void run_lavu_md5(uint8_t *output,
89 const uint8_t *input, unsigned size)
90{
91 av_md5_sum(output, input, size);
92}
93
94#define DEFINE_LAVU_MD(suffix, type, namespace, hsize) \
95static void run_lavu_ ## suffix(uint8_t *output, \
96 const uint8_t *input, unsigned size) \
97{ \
98 static struct type *h; \
99 if (!h && !(h = av_ ## namespace ## _alloc())) \
100 fatal_error("out of memory"); \
101 av_ ## namespace ## _init(h, hsize); \
102 av_ ## namespace ## _update(h, input, size); \
103 av_ ## namespace ## _final(h, output); \
104}
105
106DEFINE_LAVU_MD(sha1, AVSHA, sha, 160);
107DEFINE_LAVU_MD(sha256, AVSHA, sha, 256);
108DEFINE_LAVU_MD(sha512, AVSHA512, sha512, 512);
109DEFINE_LAVU_MD(ripemd128, AVRIPEMD, ripemd, 128);
110DEFINE_LAVU_MD(ripemd160, AVRIPEMD, ripemd, 160);
111
112static void run_lavu_aes128(uint8_t *output,
113 const uint8_t *input, unsigned size)
114{
115 static struct AVAES *aes;
116 if (!aes && !(aes = av_aes_alloc()))
117 fatal_error("out of memory");
118 av_aes_init(aes, hardcoded_key, 128, 0);
119 av_aes_crypt(aes, output, input, size >> 4, NULL, 0);
120}
121
122static void run_lavu_blowfish(uint8_t *output,
123 const uint8_t *input, unsigned size)
124{
125 static struct AVBlowfish *blowfish;
126 if (!blowfish && !(blowfish = av_blowfish_alloc()))
127 fatal_error("out of memory");
128 av_blowfish_init(blowfish, hardcoded_key, 16);
129 av_blowfish_crypt(blowfish, output, input, size >> 3, NULL, 0);
130}
131
132static void run_lavu_camellia(uint8_t *output,
133 const uint8_t *input, unsigned size)
134{
135 static struct AVCAMELLIA *camellia;
136 if (!camellia && !(camellia = av_camellia_alloc()))
137 fatal_error("out of memory");
138 av_camellia_init(camellia, hardcoded_key, 128);
139 av_camellia_crypt(camellia, output, input, size >> 4, NULL, 0);
140}
141
142static void run_lavu_cast128(uint8_t *output,
143 const uint8_t *input, unsigned size)
144{
145 static struct AVCAST5 *cast;
146 if (!cast && !(cast = av_cast5_alloc()))
147 fatal_error("out of memory");
148 av_cast5_init(cast, hardcoded_key, 128);
149 av_cast5_crypt(cast, output, input, size >> 3, 0);
150}
151
152static void run_lavu_des(uint8_t *output,
153 const uint8_t *input, unsigned size)
154{
155 static struct AVDES *des;
156 if (!des && !(des = av_des_alloc()))
157 fatal_error("out of memory");
158 av_des_init(des, hardcoded_key, 64, 0);
159 av_des_crypt(des, output, input, size >> 3, NULL, 0);
160}
161
162static void run_lavu_twofish(uint8_t *output,
163 const uint8_t *input, unsigned size)
164{
165 static struct AVTWOFISH *twofish;
166 if (!twofish && !(twofish = av_twofish_alloc()))
167 fatal_error("out of memory");
168 av_twofish_init(twofish, hardcoded_key, 128);
169 av_twofish_crypt(twofish, output, input, size >> 4, NULL, 0);
170}
171
172static void run_lavu_rc4(uint8_t *output,
173 const uint8_t *input, unsigned size)
174{
175 static struct AVRC4 *rc4;
176 if (!rc4 && !(rc4 = av_rc4_alloc()))
177 fatal_error("out of memory");
178 av_rc4_init(rc4, hardcoded_key, 128, 0);
179 av_rc4_crypt(rc4, output, input, size, NULL, 0);
180}
181
182static void run_lavu_xtea(uint8_t *output,
183 const uint8_t *input, unsigned size)
184{
185 static struct AVXTEA *xtea;
186 if (!xtea && !(xtea = av_xtea_alloc()))
187 fatal_error("out of memory");
188 av_xtea_init(xtea, hardcoded_key);
189 av_xtea_crypt(xtea, output, input, size >> 3, NULL, 0);
190}
191
192/***************************************************************************
193 * crypto: OpenSSL's libcrypto
194 ***************************************************************************/
195
196#if (USE_EXT_LIBS) & USE_crypto
197
198#define OPENSSL_DISABLE_OLD_DES_SUPPORT
199#include <openssl/md5.h>
200#include <openssl/sha.h>
201#include <openssl/ripemd.h>
202#include <openssl/aes.h>
203#include <openssl/blowfish.h>
204#include <openssl/camellia.h>
205#include <openssl/cast.h>
206#include <openssl/des.h>
207#include <openssl/rc4.h>
208
209#define DEFINE_CRYPTO_WRAPPER(suffix, function) \
210static void run_crypto_ ## suffix(uint8_t *output, \
211 const uint8_t *input, unsigned size) \
212{ \
213 function(input, size, output); \
214}
215
216DEFINE_CRYPTO_WRAPPER(md5, MD5)
217DEFINE_CRYPTO_WRAPPER(sha1, SHA1)
218DEFINE_CRYPTO_WRAPPER(sha256, SHA256)
219DEFINE_CRYPTO_WRAPPER(sha512, SHA512)
220DEFINE_CRYPTO_WRAPPER(ripemd160, RIPEMD160)
221
222static void run_crypto_aes128(uint8_t *output,
223 const uint8_t *input, unsigned size)
224{
225 AES_KEY aes;
226 unsigned i;
227
228 AES_set_encrypt_key(hardcoded_key, 128, &aes);
229 size -= 15;
230 for (i = 0; i < size; i += 16)
231 AES_encrypt(input + i, output + i, &aes);
232}
233
234static void run_crypto_blowfish(uint8_t *output,
235 const uint8_t *input, unsigned size)
236{
237 BF_KEY blowfish;
238 unsigned i;
239
240 BF_set_key(&blowfish, 16, hardcoded_key);
241 for (i = 0; i < size; i += 8)
242 BF_ecb_encrypt(input + i, output + i, &blowfish, 1);
243}
244
245static void run_crypto_camellia(uint8_t *output,
246 const uint8_t *input, unsigned size)
247{
248 CAMELLIA_KEY camellia;
249 unsigned i;
250
251 Camellia_set_key(hardcoded_key, 128, &camellia);
252 size -= 15;
253 for (i = 0; i < size; i += 16)
254 Camellia_ecb_encrypt(input + i, output + i, &camellia, 1);
255}
256
257static void run_crypto_cast128(uint8_t *output,
258 const uint8_t *input, unsigned size)
259{
260 CAST_KEY cast;
261 unsigned i;
262
263 CAST_set_key(&cast, 16, hardcoded_key);
264 for (i = 0; i < size; i += 8)
265 CAST_ecb_encrypt(input + i, output + i, &cast, 1);
266}
267
268static void run_crypto_des(uint8_t *output,
269 const uint8_t *input, unsigned size)
270{
271 DES_key_schedule des;
272 unsigned i;
273
274 DES_set_key(hardcoded_key, &des);
275 for (i = 0; i < size; i += 8)
276 DES_ecb_encrypt(input + i, output + i, &des, 1);
277}
278
279static void run_crypto_rc4(uint8_t *output,
280 const uint8_t *input, unsigned size)
281{
282 RC4_KEY rc4;
283
284 RC4_set_key(&rc4, 16, hardcoded_key);
285 RC4(&rc4, size, input, output);
286}
287
288#define IMPL_USE_crypto(...) IMPL_USE(__VA_ARGS__)
289#else
290#define IMPL_USE_crypto(...) /* ignore */
291#endif
292
293/***************************************************************************
294 * gcrypt: GnuTLS's libgcrypt
295 ***************************************************************************/
296
297#if (USE_EXT_LIBS) & USE_gcrypt
298
299#include <gcrypt.h>
300
301#define DEFINE_GCRYPT_WRAPPER(suffix, algo) \
302static void run_gcrypt_ ## suffix(uint8_t *output, \
303 const uint8_t *input, unsigned size) \
304{ \
305 gcry_md_hash_buffer(GCRY_MD_ ## algo, output, input, size); \
306}
307
308DEFINE_GCRYPT_WRAPPER(md5, MD5)
309DEFINE_GCRYPT_WRAPPER(sha1, SHA1)
310DEFINE_GCRYPT_WRAPPER(sha256, SHA256)
311DEFINE_GCRYPT_WRAPPER(sha512, SHA512)
312DEFINE_GCRYPT_WRAPPER(ripemd160, RMD160)
313
314#define DEFINE_GCRYPT_CYPHER_WRAPPER(suffix, cypher, sz) \
315static void run_gcrypt_ ## suffix(uint8_t *output, \
316 const uint8_t *input, unsigned size) \
317{ \
318 static gcry_cipher_hd_t suffix; \
319 if (!suffix) \
320 gcry_cipher_open(&suffix, GCRY_CIPHER_ ## cypher, GCRY_CIPHER_MODE_ECB, 0); \
321 gcry_cipher_setkey(suffix, hardcoded_key, sz); \
322 gcry_cipher_encrypt(suffix, output, size, input, size); \
323}
324
325DEFINE_GCRYPT_CYPHER_WRAPPER(aes128, AES128, 16)
326DEFINE_GCRYPT_CYPHER_WRAPPER(blowfish, BLOWFISH, 16)
327DEFINE_GCRYPT_CYPHER_WRAPPER(camellia, CAMELLIA128, 16)
328DEFINE_GCRYPT_CYPHER_WRAPPER(cast128, CAST5, 16)
329DEFINE_GCRYPT_CYPHER_WRAPPER(des, DES, 8)
330DEFINE_GCRYPT_CYPHER_WRAPPER(twofish, TWOFISH128, 16)
331
332#define IMPL_USE_gcrypt(...) IMPL_USE(__VA_ARGS__)
333#else
334#define IMPL_USE_gcrypt(...) /* ignore */
335#endif
336
337/***************************************************************************
338 * tomcrypt: LibTomCrypt
339 ***************************************************************************/
340
341#if (USE_EXT_LIBS) & USE_tomcrypt
342
343#include <tomcrypt.h>
344
345#define DEFINE_TOMCRYPT_WRAPPER(suffix, namespace, algo) \
346static void run_tomcrypt_ ## suffix(uint8_t *output, \
347 const uint8_t *input, unsigned size) \
348{ \
349 hash_state md; \
350 namespace ## _init(&md); \
351 namespace ## _process(&md, input, size); \
352 namespace ## _done(&md, output); \
353}
354
355DEFINE_TOMCRYPT_WRAPPER(md5, md5, MD5)
356DEFINE_TOMCRYPT_WRAPPER(sha1, sha1, SHA1)
357DEFINE_TOMCRYPT_WRAPPER(sha256, sha256, SHA256)
358DEFINE_TOMCRYPT_WRAPPER(sha512, sha512, SHA512)
359DEFINE_TOMCRYPT_WRAPPER(ripemd128, rmd128, RIPEMD128)
360DEFINE_TOMCRYPT_WRAPPER(ripemd160, rmd160, RIPEMD160)
361
362static void run_tomcrypt_aes128(uint8_t *output,
363 const uint8_t *input, unsigned size)
364{
365 symmetric_key aes;
366 unsigned i;
367
368 aes_setup(hardcoded_key, 16, 0, &aes);
369 size -= 15;
370 for (i = 0; i < size; i += 16)
371 aes_ecb_encrypt(input + i, output + i, &aes);
372}
373
374static void run_tomcrypt_blowfish(uint8_t *output,
375 const uint8_t *input, unsigned size)
376{
377 symmetric_key blowfish;
378 unsigned i;
379
380 blowfish_setup(hardcoded_key, 16, 0, &blowfish);
381 for (i = 0; i < size; i += 8)
382 blowfish_ecb_encrypt(input + i, output + i, &blowfish);
383}
384
385static void run_tomcrypt_camellia(uint8_t *output,
386 const uint8_t *input, unsigned size)
387{
388 symmetric_key camellia;
389 unsigned i;
390
391 camellia_setup(hardcoded_key, 16, 0, &camellia);
392 size -= 15;
393 for (i = 0; i < size; i += 16)
394 camellia_ecb_encrypt(input + i, output + i, &camellia);
395}
396
397static void run_tomcrypt_cast128(uint8_t *output,
398 const uint8_t *input, unsigned size)
399{
400 symmetric_key cast;
401 unsigned i;
402
403 cast5_setup(hardcoded_key, 16, 0, &cast);
404 for (i = 0; i < size; i += 8)
405 cast5_ecb_encrypt(input + i, output + i, &cast);
406}
407
408static void run_tomcrypt_des(uint8_t *output,
409 const uint8_t *input, unsigned size)
410{
411 symmetric_key des;
412 unsigned i;
413
414 des_setup(hardcoded_key, 8, 0, &des);
415 for (i = 0; i < size; i += 8)
416 des_ecb_encrypt(input + i, output + i, &des);
417}
418
419static void run_tomcrypt_twofish(uint8_t *output,
420 const uint8_t *input, unsigned size)
421{
422 symmetric_key twofish;
423 unsigned i;
424
425 twofish_setup(hardcoded_key, 16, 0, &twofish);
426 size -= 15;
427 for (i = 0; i < size; i += 16)
428 twofish_ecb_encrypt(input + i, output + i, &twofish);
429}
430
431static void run_tomcrypt_xtea(uint8_t *output,
432 const uint8_t *input, unsigned size)
433{
434 symmetric_key xtea;
435 unsigned i;
436
437 xtea_setup(hardcoded_key, 16, 0, &xtea);
438 for (i = 0; i < size; i += 8)
439 xtea_ecb_encrypt(input + i, output + i, &xtea);
440}
441
442
443#define IMPL_USE_tomcrypt(...) IMPL_USE(__VA_ARGS__)
444#else
445#define IMPL_USE_tomcrypt(...) /* ignore */
446#endif
447
448/***************************************************************************
449 * Driver code
450 ***************************************************************************/
451
452static unsigned crc32(const uint8_t *data, unsigned size)
453{
454 return av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, data, size);
455}
456
457static void run_implementation(const uint8_t *input, uint8_t *output,
458 struct hash_impl *impl, unsigned size)
459{
460 uint64_t t0, t1;
461 unsigned nruns = specified_runs ? specified_runs : (1 << 30) / size;
462 unsigned outlen = 0, outcrc = 0;
463 unsigned i, j, val;
464 double mtime, ttime = 0, ttime2 = 0, stime;
465 uint8_t outref[MAX_OUTPUT_SIZE];
466
467 if (enabled_libs && !av_stristr(enabled_libs, impl->lib) ||
468 enabled_algos && !av_stristr(enabled_algos, impl->name))
469 return;
470 if (!sscanf(impl->output, "crc:%x", &outcrc)) {
471 outlen = strlen(impl->output) / 2;
472 for (i = 0; i < outlen; i++) {
473 sscanf(impl->output + i * 2, "%02x", &val);
474 outref[i] = val;
475 }
476 }
477 for (i = 0; i < 8; i++) /* heat caches */
478 impl->run(output, input, size);
479 for (i = 0; i < nruns; i++) {
480 memset(output, 0, size); /* avoid leftovers from previous runs */
481 t0 = AV_READ_TIME();
482 impl->run(output, input, size);
483 t1 = AV_READ_TIME();
484 if (outlen ? memcmp(output, outref, outlen) :
485 crc32(output, size) != outcrc) {
486 fprintf(stderr, "Expected: ");
487 if (outlen)
488 for (j = 0; j < outlen; j++)
489 fprintf(stderr, "%02x", output[j]);
490 else
491 fprintf(stderr, "%08x", crc32(output, size));
492 fprintf(stderr, "\n");
493 fatal_error("output mismatch");
494 }
495 mtime = (double)(t1 - t0) / size;
496 ttime += mtime;
497 ttime2 += mtime * mtime;
498 }
499
500 ttime /= nruns;
501 ttime2 /= nruns;
502 stime = sqrt(ttime2 - ttime * ttime);
503 printf("%-10s %-12s size: %7d runs: %6d time: %8.3f +- %.3f\n",
504 impl->lib, impl->name, size, nruns, ttime, stime);
505 fflush(stdout);
506}
507
508#define IMPL_USE(lib, name, symbol, output) \
509 { #lib, name, run_ ## lib ## _ ## symbol, output },
510#define IMPL(lib, ...) IMPL_USE_ ## lib(lib, __VA_ARGS__)
511#define IMPL_ALL(...) \
512 IMPL(lavu, __VA_ARGS__) \
513 IMPL(crypto, __VA_ARGS__) \
514 IMPL(gcrypt, __VA_ARGS__) \
515 IMPL(tomcrypt, __VA_ARGS__)
516
517struct hash_impl implementations[] = {
518 IMPL_ALL("MD5", md5, "aa26ff5b895356bcffd9292ba9f89e66")
519 IMPL_ALL("SHA-1", sha1, "1fd8bd1fa02f5b0fe916b0d71750726b096c5744")
520 IMPL_ALL("SHA-256", sha256, "14028ac673b3087e51a1d407fbf0df4deeec8f217119e13b07bf2138f93db8c5")
521 IMPL_ALL("SHA-512", sha512, "3afdd44a80d99af15c87bd724cb717243193767835ce866dd5d58c02d674bb57"
522 "7c25b9e118c200a189fcd5a01ef106a4e200061f3e97dbf50ba065745fd46bef")
523 IMPL(lavu, "RIPEMD-128", ripemd128, "9ab8bfba2ddccc5d99c9d4cdfb844a5f")
524 IMPL(tomcrypt, "RIPEMD-128", ripemd128, "9ab8bfba2ddccc5d99c9d4cdfb844a5f")
525 IMPL_ALL("RIPEMD-160", ripemd160, "62a5321e4fc8784903bb43ab7752c75f8b25af00")
526 IMPL_ALL("AES-128", aes128, "crc:ff6bc888")
527 IMPL_ALL("CAMELLIA", camellia, "crc:7abb59a7")
528 IMPL_ALL("CAST-128", cast128, "crc:456aa584")
529 IMPL_ALL("BLOWFISH", blowfish, "crc:33e8aa74")
530 IMPL_ALL("DES", des, "crc:31291e0b")
531 IMPL(lavu, "TWOFISH", twofish, "crc:9edbd5c1")
532 IMPL(gcrypt, "TWOFISH", twofish, "crc:9edbd5c1")
533 IMPL(tomcrypt, "TWOFISH", twofish, "crc:9edbd5c1")
534 IMPL(lavu, "RC4", rc4, "crc:538d37b2")
535 IMPL(crypto, "RC4", rc4, "crc:538d37b2")
536 IMPL(lavu, "XTEA", xtea, "crc:931fc270")
537 IMPL(tomcrypt, "XTEA", xtea, "crc:931fc270")
538};
539
540int main(int argc, char **argv)
541{
542 uint8_t *input = av_malloc(MAX_INPUT_SIZE * 2);
543 uint8_t *output = input + MAX_INPUT_SIZE;
544 unsigned i, impl, size;
545 int opt;
546
547 while ((opt = getopt(argc, argv, "hl:a:r:")) != -1) {
548 switch (opt) {
549 case 'l':
550 enabled_libs = optarg;
551 break;
552 case 'a':
553 enabled_algos = optarg;
554 break;
555 case 'r':
556 specified_runs = strtol(optarg, NULL, 0);
557 break;
558 case 'h':
559 default:
560 fprintf(stderr, "Usage: %s [-l libs] [-a algos] [-r runs]\n",
561 argv[0]);
562 if ((USE_EXT_LIBS)) {
563 char buf[1024];
564 snprintf(buf, sizeof(buf), "%s%s%s",
565 ((USE_EXT_LIBS) & USE_crypto) ? "+crypto" : "",
566 ((USE_EXT_LIBS) & USE_gcrypt) ? "+gcrypt" : "",
567 ((USE_EXT_LIBS) & USE_tomcrypt) ? "+tomcrypt" : "");
568 fprintf(stderr, "Built with the following external libraries:\n"
569 "make VERSUS=%s\n", buf + 1);
570 } else {
571 fprintf(stderr, "Built without external libraries; use\n"
572 "make VERSUS=crypto+gcrypt+tomcrypt tools/crypto_bench\n"
573 "to enable them.\n");
574 }
575 exit(opt != 'h');
576 }
577 }
578
579 if (!input)
580 fatal_error("out of memory");
581 for (i = 0; i < MAX_INPUT_SIZE; i += 4)
582 AV_WB32(input + i, i);
583
584 size = MAX_INPUT_SIZE;
585 for (impl = 0; impl < FF_ARRAY_ELEMS(implementations); impl++)
586 run_implementation(input, output, &implementations[impl], size);
587
588 av_free(input);
589
590 return 0;
591}
592