Commit 16ac7030 authored by Milan Broz's avatar Milan Broz

Move PBKDF2 into crypto backend wrapper.

Implement new KDF bechmark check.
Use internal openssl kdf (and prepare gcrypt one).
parent 24e2ee58
......@@ -4,22 +4,26 @@ noinst_LTLIBRARIES = libcrypto_backend.la
libcrypto_backend_la_CFLAGS = -Wall @CRYPTO_CFLAGS@
libcrypto_backend_la_SOURCES = crypto_backend.h
libcrypto_backend_la_SOURCES = crypto_backend.h pbkdf_check.c
if CRYPTO_BACKEND_GCRYPT
libcrypto_backend_la_SOURCES += crypto_gcrypt.c
libcrypto_backend_la_SOURCES += pbkdf2_generic.c
endif
if CRYPTO_BACKEND_OPENSSL
libcrypto_backend_la_SOURCES += crypto_openssl.c
endif
if CRYPTO_BACKEND_NSS
libcrypto_backend_la_SOURCES += crypto_nss.c
libcrypto_backend_la_SOURCES += pbkdf2_generic.c
endif
if CRYPTO_BACKEND_KERNEL
libcrypto_backend_la_SOURCES += crypto_kernel.c
libcrypto_backend_la_SOURCES += pbkdf2_generic.c
endif
if CRYPTO_BACKEND_NETTLE
libcrypto_backend_la_SOURCES += crypto_nettle.c
libcrypto_backend_la_SOURCES += pbkdf2_generic.c
endif
INCLUDES = -D_GNU_SOURCE -I$(top_srcdir)/lib
......@@ -20,6 +20,7 @@
#define _CRYPTO_BACKEND_H
#include <stdint.h>
#include <string.h>
#include "config.h"
struct crypt_device;
......@@ -52,4 +53,19 @@ int crypt_hmac_destroy(struct crypt_hmac *ctx);
enum { CRYPT_RND_NORMAL = 0, CRYPT_RND_KEY = 1, CRYPT_RND_SALT = 2 };
int crypt_backend_rng(char *buffer, size_t length, int quality, int fips);
/* PBKDF*/
int crypt_pbkdf_check(const char *kdf, const char *hash, uint64_t *iter_secs);
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
unsigned int iterations);
/* internal PBKDF2 implementation */
int pkcs5_pbkdf2(const char *hash,
const char *P, size_t Plen,
const char *S, size_t Slen,
unsigned int c,
unsigned int dkLen,char *DK);
#endif /* _CRYPTO_BACKEND_H */
......@@ -251,3 +251,44 @@ int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
}
return 0;
}
/* PBKDF */
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
unsigned int iterations)
{
if (!kdf || strncmp(kdf, "pbkdf2", 6))
return -EINVAL;
return pkcs5_pbkdf2(hash, password, password_length, salt, salt_length,
iterations, key_length, key);
}
#if 0
/* Until bug in gcrypt related to empty password is fixed, cannot use this */
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
unsigned int iterations)
{
int hash_id = gcry_md_map_name(hash);
int kdf_id;
if (!hash_id)
return -EINVAL;
if (kdf && !strncmp(kdf, "pbkdf2", 6))
kdf_id = GCRY_KDF_PBKDF2;
else
return -EINVAL;
if (gcry_kdf_derive(password, password_length, kdf_id, hash_id,
salt, salt_length, iterations, key_length, key))
return -EINVAL;
return 0;
}
#endif
......@@ -302,3 +302,17 @@ int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
{
return -EINVAL;
}
/* PBKDF */
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
unsigned int iterations)
{
if (!kdf || strncmp(kdf, "pbkdf2", 6))
return -EINVAL;
return pkcs5_pbkdf2(hash, password, password_length, salt, salt_length,
iterations, key_length, key);
}
......@@ -274,3 +274,18 @@ int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
{
return -EINVAL;
}
/* PBKDF */
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
unsigned int iterations)
{
if (!kdf || strncmp(kdf, "pbkdf2", 6))
return -EINVAL;
/* FIXME: switch to internal implementation in Nettle 2.6 */
return pkcs5_pbkdf2(hash, password, password_length, salt, salt_length,
iterations, key_length, key);
}
......@@ -298,3 +298,17 @@ int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
return 0;
}
/* PBKDF */
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
unsigned int iterations)
{
if (!kdf || strncmp(kdf, "pbkdf2", 6))
return -EINVAL;
return pkcs5_pbkdf2(hash, password, password_length, salt, salt_length,
iterations, key_length, key);
}
......@@ -52,7 +52,7 @@ int crypt_backend_init(struct crypt_device *ctx)
if (crypto_backend_initialised)
return 0;
OpenSSL_add_all_digests();
OpenSSL_add_all_algorithms();
crypto_backend_initialised = 1;
return 0;
......@@ -230,3 +230,27 @@ int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
return 0;
}
/* PBKDF */
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
unsigned int iterations)
{
const EVP_MD *hash_id;
if (!kdf || strncmp(kdf, "pbkdf2", 6))
return -EINVAL;
hash_id = EVP_get_digestbyname(hash);
if (!hash_id)
return -EINVAL;
if (!PKCS5_PBKDF2_HMAC(password, (int)password_length,
(unsigned char *)salt, (int)salt_length,
(int)iterations, hash_id, (int)key_length, (unsigned char *)key))
return -EINVAL;
return 0;
}
......@@ -3,9 +3,8 @@
* Copyright (C) 2002,2003 Simon Josefsson
* Copyright (C) 2004 Free Software Foundation
*
* LUKS code
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
* cryptsetup related changes
* Copyright (C) 2012, Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -23,17 +22,9 @@
*
*/
#include <netinet/in.h>
#include <errno.h>
#include <signal.h>
#include <alloca.h>
#include <string.h>
#include <sys/time.h>
#include "crypto_backend.h"
#include "pbkdf.h"
static volatile uint64_t __PBKDF2_global_j = 0;
static volatile uint64_t __PBKDF2_performance = 0;
/*
* 5.2 PBKDF2
......@@ -63,11 +54,11 @@ static volatile uint64_t __PBKDF2_performance = 0;
#define MAX_PRF_BLOCK_LEN 80
static int pkcs5_pbkdf2(const char *hash,
int pkcs5_pbkdf2(const char *hash,
const char *P, size_t Plen,
const char *S, size_t Slen,
unsigned int c, unsigned int dkLen,
char *DK, int perfcheck)
char *DK)
{
struct crypt_hmac *hmac;
char U[MAX_PRF_BLOCK_LEN];
......@@ -164,7 +155,7 @@ static int pkcs5_pbkdf2(const char *hash,
if (crypt_hmac_init(&hmac, hash, P, Plen))
return -EINVAL;
for (i = 1; (uint) i <= l; i++) {
for (i = 1; (unsigned int) i <= l; i++) {
memset(T, 0, hLen);
for (u = 1; u <= c ; u++) {
......@@ -185,83 +176,14 @@ static int pkcs5_pbkdf2(const char *hash,
if (crypt_hmac_final(hmac, U, hLen))
goto out;
for (k = 0; (uint) k < hLen; k++)
for (k = 0; (unsigned int) k < hLen; k++)
T[k] ^= U[k];
if (perfcheck && __PBKDF2_performance) {
rc = 0;
goto out;
}
if (perfcheck)
__PBKDF2_global_j++;
}
memcpy(DK + (i - 1) * hLen, T, (uint) i == l ? r : hLen);
memcpy(DK + (i - 1) * hLen, T, (unsigned int) i == l ? r : hLen);
}
rc = 0;
out:
crypt_hmac_destroy(hmac);
return rc;
}
int PBKDF2_HMAC(const char *hash,
const char *password, size_t passwordLen,
const char *salt, size_t saltLen, unsigned int iterations,
char *dKey, size_t dKeyLen)
{
return pkcs5_pbkdf2(hash, password, passwordLen, salt, saltLen,
iterations, (unsigned int)dKeyLen, dKey, 0);
}
int PBKDF2_HMAC_ready(const char *hash)
{
if (crypt_hmac_size(hash) < 20)
return -EINVAL;
return 1;
}
static void sigvtalarm(int foo __attribute__((unused)))
{
__PBKDF2_performance = __PBKDF2_global_j;
}
/* This code benchmarks PBKDF2 and returns iterations/second using wth specified hash */
int PBKDF2_performance_check(const char *hash, uint64_t *iter)
{
int timer_type, r;
char buf;
struct itimerval it;
if (__PBKDF2_global_j)
return -EBUSY;
if (PBKDF2_HMAC_ready(hash) < 0)
return -EINVAL;
/* If crypto backend is not implemented in userspace,
* but uses some kernel part, we must measure also time
* spent in kernel. */
if (crypt_backend_flags() & CRYPT_BACKEND_KERNEL) {
timer_type = ITIMER_PROF;
signal(SIGPROF,sigvtalarm);
} else {
timer_type = ITIMER_VIRTUAL;
signal(SIGVTALRM,sigvtalarm);
}
it.it_interval.tv_usec = 0;
it.it_interval.tv_sec = 0;
it.it_value.tv_usec = 0;
it.it_value.tv_sec = 1;
if (setitimer(timer_type, &it, NULL) < 0)
return -EINVAL;
r = pkcs5_pbkdf2(hash, "foo", 3, "bar", 3, ~(0U), 1, &buf, 1);
*iter = __PBKDF2_performance;
__PBKDF2_global_j = 0;
__PBKDF2_performance = 0;
return r;
}
......@@ -6,10 +6,8 @@ libluks1_la_CFLAGS = -Wall @CRYPTO_CFLAGS@
libluks1_la_SOURCES = \
af.c \
pbkdf.c \
keymanage.c \
keyencryption.c \
pbkdf.h \
af.h \
luks.h
......
......@@ -33,7 +33,6 @@
#include "luks.h"
#include "af.h"
#include "pbkdf.h"
#include "internal.h"
/* Get size of struct luks_phdr with all keyslots material space */
......@@ -422,7 +421,7 @@ static int _check_and_convert_hdr(const char *device,
}
hdr->hashSpec[LUKS_HASHSPEC_L - 1] = '\0';
if (PBKDF2_HMAC_ready(hdr->hashSpec) < 0) {
if (crypt_hmac_size(hdr->hashSpec) < LUKS_DIGESTSIZE) {
log_err(ctx, _("Requested LUKS hash %s is not supported.\n"), hdr->hashSpec);
return -EINVAL;
}
......@@ -604,7 +603,7 @@ static int LUKS_PBKDF2_performance_check(const char *hashSpec,
struct crypt_device *ctx)
{
if (!*PBKDF2_per_sec) {
if (PBKDF2_performance_check(hashSpec, PBKDF2_per_sec) < 0) {
if (crypt_pbkdf_check("pbkdf2", hashSpec, PBKDF2_per_sec) < 0) {
log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"), hashSpec);
return -EINVAL;
}
......@@ -635,7 +634,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
if (alignPayload == 0 && !detached_metadata_device)
alignPayload = DEFAULT_DISK_ALIGNMENT / SECTOR_SIZE;
if (PBKDF2_HMAC_ready(hashSpec) < 0) {
if (crypt_hmac_size(hashSpec) < LUKS_DIGESTSIZE) {
log_err(ctx, _("Requested LUKS hash %s is not supported.\n"), hashSpec);
return -EINVAL;
}
......@@ -678,10 +677,10 @@ int LUKS_generate_phdr(struct luks_phdr *header,
header->mkDigestIterations = at_least((uint32_t)(*PBKDF2_per_sec/1024) * iteration_time_ms,
LUKS_MKD_ITERATIONS_MIN);
r = PBKDF2_HMAC(header->hashSpec,vk->key,vk->keylength,
header->mkDigestSalt,LUKS_SALTSIZE,
header->mkDigestIterations,
header->mkDigest,LUKS_DIGESTSIZE);
r = crypt_pbkdf("pbkdf2", header->hashSpec, vk->key,vk->keylength,
header->mkDigestSalt, LUKS_SALTSIZE,
header->mkDigest,LUKS_DIGESTSIZE,
header->mkDigestIterations);
if(r < 0) {
log_err(ctx, _("Cannot create LUKS header: header digest failed (using hash %s).\n"),
header->hashSpec);
......@@ -786,10 +785,10 @@ int LUKS_set_key(unsigned int keyIndex,
if (r < 0)
goto out;
r = PBKDF2_HMAC(hdr->hashSpec, password,passwordLen,
hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
hdr->keyblock[keyIndex].passwordIterations,
derived_key->key, hdr->keyBytes);
r = crypt_pbkdf("pbkdf2", hdr->hashSpec, password, passwordLen,
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
derived_key->key, hdr->keyBytes,
hdr->keyblock[keyIndex].passwordIterations);
if (r < 0)
goto out;
......@@ -844,10 +843,10 @@ int LUKS_verify_volume_key(const struct luks_phdr *hdr,
{
char checkHashBuf[LUKS_DIGESTSIZE];
if (PBKDF2_HMAC(hdr->hashSpec, vk->key, vk->keylength,
if (crypt_pbkdf("pbkdf2", hdr->hashSpec, vk->key, vk->keylength,
hdr->mkDigestSalt, LUKS_SALTSIZE,
hdr->mkDigestIterations, checkHashBuf,
LUKS_DIGESTSIZE) < 0)
checkHashBuf, LUKS_DIGESTSIZE,
hdr->mkDigestIterations) < 0)
return -EINVAL;
if (memcmp(checkHashBuf, hdr->mkDigest, LUKS_DIGESTSIZE))
......@@ -888,10 +887,10 @@ static int LUKS_open_key(unsigned int keyIndex,
goto out;
}
r = PBKDF2_HMAC(hdr->hashSpec, password,passwordLen,
hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
hdr->keyblock[keyIndex].passwordIterations,
derived_key->key, hdr->keyBytes);
r = crypt_pbkdf("pbkdf2", hdr->hashSpec, password, passwordLen,
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
derived_key->key, hdr->keyBytes,
hdr->keyblock[keyIndex].passwordIterations);
if (r < 0)
goto out;
......
/*
* Implementation of Password-Based Cryptography as per PKCS#5
* Copyright (C) 2002,2003 Simon Josefsson
* Copyright (C) 2004 Free Software Foundation
*
* LUKS code
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
*
* 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.
*
*/
#ifndef INCLUDED_CRYPTSETUP_LUKS_PBKDF_H
#define INCLUDED_CRYPTSETUP_LUKS_PBKDF_H
#include <stddef.h>
int PBKDF2_HMAC(const char *hash,
const char *password, size_t passwordLen,
const char *salt, size_t saltLen, unsigned int iterations,
char *dKey, size_t dKeyLen);
int PBKDF2_performance_check(const char *hash, uint64_t *iter);
int PBKDF2_HMAC_ready(const char *hash);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment