Implement new KDF bechmark check.
Use internal openssl kdf (and prepare gcrypt one).
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
#define _CRYPTO_BACKEND_H
#include <stdint.h>
+#include <string.h>
#include "config.h"
struct crypt_device;
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 */
}
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
{
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);
+}
{
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);
+}
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 (crypto_backend_initialised)
return 0;
- OpenSSL_add_all_digests();
+ OpenSSL_add_all_algorithms();
crypto_backend_initialised = 1;
return 0;
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;
+}
* 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
*
*/
-#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
#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];
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++) {
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;
-}
libluks1_la_SOURCES = \
af.c \
- pbkdf.c \
keymanage.c \
keyencryption.c \
- pbkdf.h \
af.h \
luks.h
#include "luks.h"
#include "af.h"
-#include "pbkdf.h"
#include "internal.h"
/* Get size of struct luks_phdr with all keyslots material space */
}
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;
}
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;
}
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;
}
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);
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;
{
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))
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;
+++ /dev/null
-/*
- * 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