mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-07 08:50:05 +01:00
The previous PBKDF2 benchmark code did not take into account output key length. For SHA1 (with 160-bits output) and 256-bit keys (and longer) it means that the final value was higher than it should be. For other hash algorithms (like SHA256 or SHA512) it caused that iteration count was smaller (in comparison to SHA1) than expected for the requested time period. This patch fixes the code to use key size for the formatted device (or default LUKS key size if running in informational benchmark mode). Thanks to A.Visconti, S.Bossi, A.Calo and H.Ragab (http://www.club.di.unimi.it/) for point this out. (Based on "What users should know about Full Disk Encryption based on LUKS" paper to be presented on CANS2015).
118 lines
2.9 KiB
C
118 lines
2.9 KiB
C
/*
|
|
* PBKDF performance check
|
|
* Copyright (C) 2012, Red Hat, Inc. All rights reserved.
|
|
* Copyright (C) 2012-2014, Milan Broz
|
|
*
|
|
* This file is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This file is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this file; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
#include "crypto_backend.h"
|
|
|
|
static long time_ms(struct rusage *start, struct rusage *end)
|
|
{
|
|
int count_kernel_time = 0;
|
|
long ms;
|
|
|
|
if (crypt_backend_flags() & CRYPT_BACKEND_KERNEL)
|
|
count_kernel_time = 1;
|
|
|
|
/*
|
|
* FIXME: if there is no self usage info, count system time.
|
|
* This seem like getrusage() bug in some hypervisors...
|
|
*/
|
|
if (!end->ru_utime.tv_sec && !start->ru_utime.tv_sec &&
|
|
!end->ru_utime.tv_usec && !start->ru_utime.tv_usec)
|
|
count_kernel_time = 1;
|
|
|
|
ms = (end->ru_utime.tv_sec - start->ru_utime.tv_sec) * 1000;
|
|
ms += (end->ru_utime.tv_usec - start->ru_utime.tv_usec) / 1000;
|
|
|
|
if (count_kernel_time) {
|
|
ms += (end->ru_stime.tv_sec - start->ru_stime.tv_sec) * 1000;
|
|
ms += (end->ru_stime.tv_usec - start->ru_stime.tv_usec) / 1000;
|
|
}
|
|
|
|
return ms;
|
|
}
|
|
|
|
/* This code benchmarks PBKDF and returns iterations/second using specified hash */
|
|
int crypt_pbkdf_check(const char *kdf, const char *hash,
|
|
const char *password, size_t password_length,
|
|
const char *salt, size_t salt_length,
|
|
size_t key_length, uint64_t *iter_secs)
|
|
{
|
|
struct rusage rstart, rend;
|
|
int r = 0, step = 0;
|
|
long ms = 0;
|
|
char *key = NULL;
|
|
unsigned int iterations;
|
|
|
|
if (!kdf || !hash || key_length <= 0)
|
|
return -EINVAL;
|
|
|
|
key = malloc(key_length);
|
|
if (!key)
|
|
return -ENOMEM;
|
|
|
|
iterations = 1 << 15;
|
|
while (ms < 500) {
|
|
if (getrusage(RUSAGE_SELF, &rstart) < 0) {
|
|
r = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
r = crypt_pbkdf(kdf, hash, password, password_length, salt,
|
|
salt_length, key, key_length, iterations);
|
|
if (r < 0)
|
|
goto out;
|
|
|
|
if (getrusage(RUSAGE_SELF, &rend) < 0) {
|
|
r = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
ms = time_ms(&rstart, &rend);
|
|
if (ms > 500)
|
|
break;
|
|
|
|
if (ms <= 62)
|
|
iterations <<= 4;
|
|
else if (ms <= 125)
|
|
iterations <<= 3;
|
|
else if (ms <= 250)
|
|
iterations <<= 2;
|
|
else
|
|
iterations <<= 1;
|
|
|
|
if (++step > 10 || !iterations) {
|
|
r = -EINVAL;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (iter_secs)
|
|
*iter_secs = (iterations * 1000) / ms;
|
|
out:
|
|
if (key) {
|
|
crypt_backend_memzero(key, key_length);
|
|
free(key);
|
|
}
|
|
return r;
|
|
}
|