Move PBKDF2 into crypto backend wrapper.
authorMilan Broz <gmazyland@gmail.com>
Fri, 26 Oct 2012 16:17:06 +0000 (18:17 +0200)
committerMilan Broz <gmazyland@gmail.com>
Mon, 19 Nov 2012 20:17:55 +0000 (21:17 +0100)
Implement new KDF bechmark check.
Use internal openssl kdf (and prepare gcrypt one).

lib/crypto_backend/Makefile.am
lib/crypto_backend/crypto_backend.h
lib/crypto_backend/crypto_gcrypt.c
lib/crypto_backend/crypto_kernel.c
lib/crypto_backend/crypto_nettle.c
lib/crypto_backend/crypto_nss.c
lib/crypto_backend/crypto_openssl.c
lib/crypto_backend/pbkdf2_generic.c [moved from lib/luks1/pbkdf.c with 71% similarity]
lib/luks1/Makefile.am
lib/luks1/keymanage.c
lib/luks1/pbkdf.h [deleted file]

index c7953b6..baddd50 100644 (file)
@@ -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
index c7f30cb..2ca53d0 100644 (file)
@@ -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 */
index ee14198..4173691 100644 (file)
@@ -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
index 50e7167..fa995a0 100644 (file)
@@ -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);
+}
index 2fc2ce6..39b6159 100644 (file)
@@ -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);
+}
index a4a5b08..5b49a39 100644 (file)
@@ -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);
+}
index bbd35bf..2577b18 100644 (file)
@@ -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;
+}
similarity index 71%
rename from lib/luks1/pbkdf.c
rename to lib/crypto_backend/pbkdf2_generic.c
index 0b0c9ee..f42faed 100644 (file)
@@ -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
  *
  */
 
-#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;
-}
index 54dad64..bf15200 100644 (file)
@@ -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
 
index 52df159..3bd57ee 100644 (file)
@@ -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;
 
diff --git a/lib/luks1/pbkdf.h b/lib/luks1/pbkdf.h
deleted file mode 100644 (file)
index f0d9751..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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