2 * libcryptsetup - cryptsetup library, cipher bechmark
4 * Copyright (C) 2012, Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2012, Milan Broz
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <sys/resource.h>
30 * This is not simulating storage, so using disk block causes extreme overhead.
31 * Let's use some fixed block size where results are more reliable...
33 #define CIPHER_BLOCK_BYTES 65536
36 * The whole test depends on Linux kernel usermode crypto API for now.
37 * (The same implementations are used in dm-crypt though.)
50 static long time_ms(struct rusage *start, struct rusage *end)
54 /* For kernel backend, we need to measure only tim in kernel.
55 ms = (end->ru_utime.tv_sec - start->ru_utime.tv_sec) * 1000;
56 ms += (end->ru_utime.tv_usec - start->ru_utime.tv_usec) / 1000;
59 ms += (end->ru_stime.tv_sec - start->ru_stime.tv_sec) * 1000;
60 ms += (end->ru_stime.tv_usec - start->ru_stime.tv_usec) / 1000;
65 static int cipher_perf_one(struct cipher_perf *cp, char *buf,
66 size_t buf_size, int enc)
68 struct crypt_cipher *cipher = NULL;
69 size_t done = 0, block = CIPHER_BLOCK_BYTES;
75 r = crypt_cipher_init(&cipher, cp->name, cp->mode, cp->key, cp->key_length);
77 log_dbg("Cannot initialise cipher %s, mode %s.", cp->name, cp->mode);
81 while (done < buf_size) {
82 if ((done + block) > buf_size)
83 block = buf_size - done;
86 r = crypt_cipher_encrypt(cipher, &buf[done], &buf[done],
87 block, cp->iv, cp->iv_length);
89 r = crypt_cipher_decrypt(cipher, &buf[done], &buf[done],
90 block, cp->iv, cp->iv_length);
97 crypt_cipher_destroy(cipher);
101 static long cipher_measure(struct cipher_perf *cp, char *buf,
102 size_t buf_size, int encrypt)
104 struct rusage rstart, rend;
107 if (getrusage(RUSAGE_SELF, &rstart) < 0)
110 r = cipher_perf_one(cp, buf, buf_size, encrypt);
114 if (getrusage(RUSAGE_SELF, &rend) < 0)
117 return time_ms(&rstart, &rend);
120 static double speed_mbs(unsigned long bytes, unsigned long ms)
122 double speed = bytes, s = ms / 1000.;
124 return speed / (1024 * 1024) / s;
127 static int cipher_perf(struct cipher_perf *cp,
128 double *encryption_mbs, double *decryption_mbs)
130 long ms_enc, ms_dec, ms;
131 int repeat_enc, repeat_dec;
134 if (posix_memalign(&buf, crypt_getpagesize(), cp->buffer_size))
139 while (ms_enc < 1000) {
140 ms = cipher_measure(cp, buf, cp->buffer_size, 1);
151 while (ms_dec < 1000) {
152 ms = cipher_measure(cp, buf, cp->buffer_size, 0);
163 *encryption_mbs = speed_mbs(cp->buffer_size * repeat_enc, ms_enc);
164 *decryption_mbs = speed_mbs(cp->buffer_size * repeat_dec, ms_dec);
169 int crypt_benchmark(struct crypt_device *cd,
171 const char *cipher_mode,
172 size_t volume_key_size,
175 double *encryption_mbs,
176 double *decryption_mbs)
178 struct cipher_perf cp = {
179 .key_length = volume_key_size,
180 .iv_length = iv_size,
181 .buffer_size = buffer_size,
186 if (!cipher || !cipher_mode || !volume_key_size)
195 cp.iv = malloc(iv_size);
198 crypt_random_get(cd, cp.iv, iv_size, CRYPT_RND_NORMAL);
201 cp.key = malloc(volume_key_size);
205 crypt_random_get(cd, cp.key, volume_key_size, CRYPT_RND_NORMAL);
206 strncpy(cp.name, cipher, sizeof(cp.name)-1);
207 strncpy(cp.mode, cipher_mode, sizeof(cp.mode)-1);
209 /* Ignore IV generator */
210 if ((c = strchr(cp.mode, '-')))
213 r = cipher_perf(&cp, encryption_mbs, decryption_mbs);
220 int crypt_benchmark_kdf(struct crypt_device *cd,
223 const char *password,
224 size_t password_size,
227 uint64_t *iterations_sec)
238 if (!strncmp(kdf, "pbkdf2", 6))
239 r = crypt_pbkdf_check(kdf, hash, password, password_size,
240 salt, salt_size, iterations_sec);
245 log_dbg("KDF %s, hash %s: %" PRIu64 " iterations per second.",
246 kdf, hash, *iterations_sec);