2 * libcryptsetup - cryptsetup library, cipher bechmark
4 * Copyright (C) 2012, Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2012-2013, 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.
29 * This is not simulating storage, so using disk block causes extreme overhead.
30 * Let's use some fixed block size where results are more reliable...
32 #define CIPHER_BLOCK_BYTES 65536
35 * If the measured value is lower, encrypted buffer is probably too small
36 * and calculated values are not reliable.
38 #define CIPHER_TIME_MIN_MS 0.001
41 * The whole test depends on Linux kernel usermode crypto API for now.
42 * (The same implementations are used in dm-crypt though.)
55 static int time_ms(struct timespec *start, struct timespec *end, double *ms)
57 double start_ms, end_ms;
59 start_ms = start->tv_sec * 1000.0 + start->tv_nsec / (1000.0 * 1000);
60 end_ms = end->tv_sec * 1000.0 + end->tv_nsec / (1000.0 * 1000);
62 *ms = end_ms - start_ms;
66 static int cipher_perf_one(struct cipher_perf *cp, char *buf,
67 size_t buf_size, int enc)
69 struct crypt_cipher *cipher = NULL;
70 size_t done = 0, block = CIPHER_BLOCK_BYTES;
76 r = crypt_cipher_init(&cipher, cp->name, cp->mode, cp->key, cp->key_length);
78 log_dbg("Cannot initialise cipher %s, mode %s.", cp->name, cp->mode);
82 while (done < buf_size) {
83 if ((done + block) > buf_size)
84 block = buf_size - done;
87 r = crypt_cipher_encrypt(cipher, &buf[done], &buf[done],
88 block, cp->iv, cp->iv_length);
90 r = crypt_cipher_decrypt(cipher, &buf[done], &buf[done],
91 block, cp->iv, cp->iv_length);
98 crypt_cipher_destroy(cipher);
102 static int cipher_measure(struct cipher_perf *cp, char *buf,
103 size_t buf_size, int encrypt, double *ms)
105 struct timespec start, end;
109 * Using getrusage would be better here but the precision
110 * is not adequate, so better stick with CLOCK_MONOTONIC
112 if (clock_gettime(CLOCK_MONOTONIC, &start) < 0)
115 r = cipher_perf_one(cp, buf, buf_size, encrypt);
119 if (clock_gettime(CLOCK_MONOTONIC, &end) < 0)
122 r = time_ms(&start, &end, ms);
126 if (*ms < CIPHER_TIME_MIN_MS) {
127 log_dbg("Measured cipher runtime (%1.6f) is too low.", *ms);
134 static double speed_mbs(unsigned long bytes, double ms)
136 double speed = bytes, s = ms / 1000.;
138 return speed / (1024 * 1024) / s;
141 static int cipher_perf(struct cipher_perf *cp,
142 double *encryption_mbs, double *decryption_mbs)
144 double ms_enc, ms_dec, ms;
145 int r, repeat_enc, repeat_dec;
148 if (posix_memalign(&buf, crypt_getpagesize(), cp->buffer_size))
153 while (ms_enc < 1000.0) {
154 r = cipher_measure(cp, buf, cp->buffer_size, 1, &ms);
165 while (ms_dec < 1000.0) {
166 r = cipher_measure(cp, buf, cp->buffer_size, 0, &ms);
177 *encryption_mbs = speed_mbs(cp->buffer_size * repeat_enc, ms_enc);
178 *decryption_mbs = speed_mbs(cp->buffer_size * repeat_dec, ms_dec);
183 int crypt_benchmark(struct crypt_device *cd,
185 const char *cipher_mode,
186 size_t volume_key_size,
189 double *encryption_mbs,
190 double *decryption_mbs)
192 struct cipher_perf cp = {
193 .key_length = volume_key_size,
194 .iv_length = iv_size,
195 .buffer_size = buffer_size,
200 if (!cipher || !cipher_mode || !volume_key_size)
209 cp.iv = malloc(iv_size);
212 crypt_random_get(cd, cp.iv, iv_size, CRYPT_RND_NORMAL);
215 cp.key = malloc(volume_key_size);
219 crypt_random_get(cd, cp.key, volume_key_size, CRYPT_RND_NORMAL);
220 strncpy(cp.name, cipher, sizeof(cp.name)-1);
221 strncpy(cp.mode, cipher_mode, sizeof(cp.mode)-1);
223 /* Ignore IV generator */
224 if ((c = strchr(cp.mode, '-')))
227 r = cipher_perf(&cp, encryption_mbs, decryption_mbs);
234 int crypt_benchmark_kdf(struct crypt_device *cd,
237 const char *password,
238 size_t password_size,
241 uint64_t *iterations_sec)
252 if (!strncmp(kdf, "pbkdf2", 6))
253 r = crypt_pbkdf_check(kdf, hash, password, password_size,
254 salt, salt_size, iterations_sec);
259 log_dbg("KDF %s, hash %s: %" PRIu64 " iterations per second.",
260 kdf, hash, *iterations_sec);