Package: cryptsetup Version: 2:1.0.4~rc2-1 Severity: wishlist
My key is manually generated in binary by a random physical process and memorized as a hexadecimal number, so I have nothing to gain but maybe something to lose by hashing it. I have patched cryptsetup to pay attention to the plain hash option when using LUKS format, and to refrain from hashing the password in that case, provided that the password is given as a hexadecimal number of the right length. I appreciate that using passwords that are secure but difficult to remember could cause trouble for some people. Other than that, there should be no breakage for anyone because there was previously no reason to use the plain hash option for LUKS format. Backward compatibility can be retained by continuing not to use it. I hope you like my patch. Feel free to send it upstream. *** 00list # no patches 01_terminal_timeout 02_docs_tries 03_fix_build_error 04_luks_plain_hash *** 04_luks_plain_hash.dpatch #! /bin/sh /usr/share/dpatch/dpatch-run ## 04_luks_plain_hash.dpatch by <[EMAIL PROTECTED]> ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: No description. @DPATCH@ diff -urNad cryptsetup-1.0.4~rc2~/debian/initramfs-cryptroot-script cryptsetup-1.0.4~rc2/debian/initramfs-cryptroot-script --- cryptsetup-1.0.4~rc2~/debian/initramfs-cryptroot-script 2006-09-09 22:20:56.000000000 +0100 +++ cryptsetup-1.0.4~rc2/debian/initramfs-cryptroot-script 2006-09-09 22:25:07.000000000 +0100 @@ -166,7 +166,7 @@ # prepare commands if /sbin/cryptsetup isLuks $cryptsource > /dev/null 2>&1; then - cryptcreate="/sbin/cryptsetup luksOpen $cryptsource $crypttarget" + cryptcreate="/sbin/cryptsetup -h $crypthash luksOpen $cryptsource $crypttarget" else cryptcreate="/sbin/cryptsetup -c $cryptcipher -s $cryptsize -h $crypthash create $crypttarget $cryptsource" fi diff -urNad cryptsetup-1.0.4~rc2~/lib/libcryptsetup.h cryptsetup-1.0.4~rc2/lib/libcryptsetup.h --- cryptsetup-1.0.4~rc2~/lib/libcryptsetup.h 2006-09-09 22:20:55.000000000 +0100 +++ cryptsetup-1.0.4~rc2/lib/libcryptsetup.h 2006-09-09 22:23:30.000000000 +0100 @@ -7,6 +7,7 @@ #define CRYPT_FLAG_READONLY (1 << 1) #define CRYPT_FLAG_VERIFY_IF_POSSIBLE (1 << 2) #define CRYPT_FLAG_VERIFY_ON_DELKEY (1 << 3) +#define CRYPT_FLAG_ALLOW_PLAIN_HASH (1 << 4) struct crypt_options { const char *name; diff -urNad cryptsetup-1.0.4~rc2~/lib/setup.c cryptsetup-1.0.4~rc2/lib/setup.c --- cryptsetup-1.0.4~rc2~/lib/setup.c 2006-09-09 22:23:30.000000000 +0100 +++ cryptsetup-1.0.4~rc2/lib/setup.c 2006-09-09 22:23:30.000000000 +0100 @@ -548,6 +548,7 @@ char cipherMode[LUKS_CIPHERMODE_L]; int passwordLen; int PBKDF2perSecond; + int allow_plain_hash = options->flags & CRYPT_FLAG_ALLOW_PLAIN_HASH; mk.keyLength = options->key_size; @@ -592,7 +593,7 @@ if(!password) { r = -EINVAL; goto out; } - r = LUKS_set_key(options->device, 0, password, passwordLen, &header, &mk, backend); + r = LUKS_set_key(options->device, 0, password, passwordLen, &header, &mk, backend, allow_plain_hash); if(r < 0) goto out; r = 0; @@ -613,6 +614,7 @@ }; char *dmCipherSpec; int r, tries = options->tries; + int allow_plain_hash = options->flags & CRYPT_FLAG_ALLOW_PLAIN_HASH; r = backend->status(0, &tmp, NULL); if (r >= 0) { @@ -638,7 +640,7 @@ if(!password) { r = -EINVAL; goto out; } - if(LUKS_open_any_key(options->device, password, passwordLen, &hdr, &mk, backend) < 0) { + if(LUKS_open_any_key(options->device, password, passwordLen, &hdr, &mk, backend, allow_plain_hash) < 0) { set_error("No key available with this passphrase.\n"); r = -EPERM; goto out1; } @@ -694,6 +696,7 @@ .flags = options->flags, }; int r; + int allow_plain_hash = options->flags & CRYPT_FLAG_ALLOW_PLAIN_HASH; r = LUKS_read_phdr(device, &hdr); if(r < 0) return r; @@ -713,7 +716,7 @@ if(!password) { r = -EINVAL; goto out; } - if(LUKS_open_any_key(device, password, passwordLen, &hdr, &mk, backend) < 0) { + if(LUKS_open_any_key(device, password, passwordLen, &hdr, &mk, backend, allow_plain_hash) < 0) { printf("No key available with this passphrase.\n"); r = -EPERM; goto out; } @@ -727,7 +730,7 @@ hdr.keyblock[keyIndex].passwordIterations = LUKS_benchmarkt_iterations() * ((float)options->iteration_time / 1000); - r = LUKS_set_key(device, keyIndex, password, passwordLen, &hdr, &mk, backend); + r = LUKS_set_key(device, keyIndex, password, passwordLen, &hdr, &mk, backend, allow_plain_hash); if(r < 0) goto out; r = 0; @@ -746,6 +749,7 @@ int keyIndex = options->key_slot; int openedIndex; int r; + int allow_plain_hash = options->flags & CRYPT_FLAG_ALLOW_PLAIN_HASH; if(options->flags & CRYPT_FLAG_VERIFY_ON_DELKEY) { options->flags &= ~CRYPT_FLAG_VERIFY_ON_DELKEY; @@ -754,7 +758,7 @@ if(!password) { r = -EINVAL; goto out; } - openedIndex = LUKS_open_any_key(device, password, passwordLen, &hdr, &mk, backend); + openedIndex = LUKS_open_any_key(device, password, passwordLen, &hdr, &mk, backend, allow_plain_hash); if(openedIndex < 0 || keyIndex == openedIndex) { printf("No remaining key available with this passphrase.\n"); r = -EPERM; goto out; diff -urNad cryptsetup-1.0.4~rc2~/luks/keymanage.c cryptsetup-1.0.4~rc2/luks/keymanage.c --- cryptsetup-1.0.4~rc2~/luks/keymanage.c 2006-09-09 22:20:56.000000000 +0100 +++ cryptsetup-1.0.4~rc2/luks/keymanage.c 2006-09-09 22:23:30.000000000 +0100 @@ -43,6 +43,9 @@ (__a - 1) / __b + 1; \ }) + +#define DISALLOW_PLAIN_HASH 0 + int LUKS_generate_masterkey(struct luks_masterkey *mk) { return getRandom(mk->key,mk->keyLength); @@ -178,7 +181,8 @@ PBKDF2_HMAC_SHA1(mk->key,mk->keyLength, header->mkDigestSalt,LUKS_SALTSIZE, header->mkDigestIterations, - header->mkDigest,LUKS_DIGESTSIZE); + header->mkDigest,LUKS_DIGESTSIZE, + DISALLOW_PLAIN_HASH); currentSector = round_up_modulo(LUKS_PHDR_SIZE, alignSectors); for(i = 0; i < LUKS_NUMKEYS; ++i) { @@ -199,7 +203,7 @@ int LUKS_set_key(const char *device, unsigned int keyIndex, const char *password, size_t passwordLen, struct luks_phdr *hdr, struct luks_masterkey *mk, - struct setup_backend *backend) + struct setup_backend *backend, int allow_plain_hash) { char derivedKey[hdr->keyBytes]; char *AfKey; @@ -223,7 +227,7 @@ PBKDF2_HMAC_SHA1(password,passwordLen, hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE, hdr->keyblock[keyIndex].passwordIterations, - derivedKey, hdr->keyBytes); + derivedKey, hdr->keyBytes, allow_plain_hash); /* * AF splitting, the masterkey stored in mk->key is splitted to AfMK */ @@ -265,7 +269,8 @@ size_t passwordLen, struct luks_phdr *hdr, struct luks_masterkey *mk, - struct setup_backend *backend) + struct setup_backend *backend, + int allow_plain_hash) { char derivedKey[hdr->keyBytes]; char *AfKey; @@ -289,7 +294,7 @@ PBKDF2_HMAC_SHA1(password,passwordLen, hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE, hdr->keyblock[keyIndex].passwordIterations, - derivedKey, hdr->keyBytes); + derivedKey, hdr->keyBytes, allow_plain_hash); r = LUKS_decrypt_from_storage(AfKey, AFEKSize, @@ -310,7 +315,7 @@ PBKDF2_HMAC_SHA1(mk->key,mk->keyLength, hdr->mkDigestSalt,LUKS_SALTSIZE, hdr->mkDigestIterations, - checkHashBuf,LUKS_DIGESTSIZE); + checkHashBuf,LUKS_DIGESTSIZE,DISALLOW_PLAIN_HASH); r = (memcmp(checkHashBuf,hdr->mkDigest, LUKS_DIGESTSIZE) == 0)?0:-EPERM; out: @@ -323,7 +328,8 @@ size_t passwordLen, struct luks_phdr *hdr, struct luks_masterkey *mk, - struct setup_backend *backend) + struct setup_backend *backend, + int allow_plain_hash) { unsigned int i; int r; @@ -334,7 +340,7 @@ mk->keyLength = hdr->keyBytes; for(i=0; i<LUKS_NUMKEYS; i++) { - if(LUKS_open_key(device, i, password, passwordLen, hdr, mk, backend) == 0) + if(LUKS_open_key(device, i, password, passwordLen, hdr, mk, backend, allow_plain_hash) == 0) break; } if(i!=LUKS_NUMKEYS) printf("key slot %d unlocked.\n",i); diff -urNad cryptsetup-1.0.4~rc2~/luks/luks.h cryptsetup-1.0.4~rc2/luks/luks.h --- cryptsetup-1.0.4~rc2~/luks/luks.h 2006-09-09 22:20:56.000000000 +0100 +++ cryptsetup-1.0.4~rc2/luks/luks.h 2006-09-09 22:23:30.000000000 +0100 @@ -95,8 +95,9 @@ const char *password, size_t passwordLen, struct luks_phdr *hdr, - struct luks_masterkey *mk, - struct setup_backend *backend); + struct luks_masterkey *mk, + struct setup_backend *backend, + int allow_plain_hash); int LUKS_open_key(const char *device, unsigned int keyIndex, @@ -104,14 +105,16 @@ size_t passwordLen, struct luks_phdr *hdr, struct luks_masterkey *mk, - struct setup_backend *backend); + struct setup_backend *backend, + int allow_plain_hash); int LUKS_open_any_key(const char *device, const char *password, size_t passwordLen, struct luks_phdr *hdr, struct luks_masterkey *mk, - struct setup_backend *backend); + struct setup_backend *backend, + int allow_plain_hash); int LUKS_del_key(const char *device, unsigned int keyIndex); int LUKS_is_last_keyslot(const char *device, unsigned int keyIndex); diff -urNad cryptsetup-1.0.4~rc2~/luks/pbkdf.c cryptsetup-1.0.4~rc2/luks/pbkdf.c --- cryptsetup-1.0.4~rc2~/luks/pbkdf.c 2006-09-09 22:20:56.000000000 +0100 +++ cryptsetup-1.0.4~rc2/luks/pbkdf.c 2006-09-09 22:23:30.000000000 +0100 @@ -20,16 +20,65 @@ #include <errno.h> #include <signal.h> #include <sys/time.h> +#include <ctype.h> +#include <stdio.h> #include "hmac_sha1.h" #include "XORblock.h" + + +static int is_hex_format(const char *password, size_t passwordLen, size_t dKeyLen) + +/* returns a non-zero value iff the password contains only the + characters 0..9 and a..f, and its length in characters is twice the + key length in bytes */ +{ + int i,h; + + i = 0; + h = (passwordLen == (dKeyLen << 1)); + while (h ? (i++ < passwordLen) : 0) { + h = (isdigit(*password) ? 1 : (isxdigit(*password) ? islower(*password) : 0)); + password++; + } + return h; +} + + + + + +static void directly_transcribe(const char *password, size_t passwordLen, char *dKey) + +/* generates the derived key from the password assumed to be in the + above specified hex format by transcribing it to binary with no + hashing */ + +{ + int i; + +#define nybble(n) (isdigit(n) ? (n - '0') : (10 + n - 'a')) + + for (i = 0; i < (passwordLen >> 1); i++) { + dKey[i] = (nybble(password[i << 1]) << 4) + nybble(password[(i << 1) + 1]); + } +#ifdef LUKS_DEBUG + fprintf(stderr, "hashing bypassed for hex format key of %d bits\n", passwordLen << 2); +#endif +} + + + + + + static unsigned int *__PBKDF2_global_j; static unsigned int __PBKDF2_performance=0; void PBKDF2_HMAC_SHA1(const char *password, size_t passwordLen, const char *salt, size_t saltLen, unsigned int iterations, - char *dKey, size_t dKeyLen) + char *dKey, size_t dKeyLen, int allow_plain_hash) { uint32_t i=1; unsigned int j; @@ -39,6 +88,17 @@ char F_buf[SHA1_DIGEST_SIZE]; hmac_ctx templateCtx; + + + /* Don't hash passwords that are already given in hexadecimal format */ + if (allow_plain_hash ? is_hex_format(password, passwordLen, dKeyLen) : 0) { + directly_transcribe (password, passwordLen, dKey); + return; + } + + + + /* We need a global pointer for signal handlers */ __PBKDF2_global_j = &j; @@ -106,7 +166,7 @@ PBKDF2_HMAC_SHA1("foo", 3, "bar", 3, ~(0U), - &buf, 1); + &buf, 1, 0); return __PBKDF2_performance; } diff -urNad cryptsetup-1.0.4~rc2~/luks/pbkdf.h cryptsetup-1.0.4~rc2/luks/pbkdf.h --- cryptsetup-1.0.4~rc2~/luks/pbkdf.h 2006-09-09 22:20:56.000000000 +0100 +++ cryptsetup-1.0.4~rc2/luks/pbkdf.h 2006-09-09 22:23:30.000000000 +0100 @@ -7,7 +7,7 @@ void PBKDF2_HMAC_SHA1(const char *password, size_t passwordLen, const char *salt, size_t saltLen, unsigned int iterations, - char *dKey, size_t dKeyLen); + char *dKey, size_t dKeyLen, int allow_plain_hash); unsigned int PBKDF2_performance_check(); diff -urNad cryptsetup-1.0.4~rc2~/man/cryptsetup.8 cryptsetup-1.0.4~rc2/man/cryptsetup.8 --- cryptsetup-1.0.4~rc2~/man/cryptsetup.8 2006-09-09 22:23:30.000000000 +0100 +++ cryptsetup-1.0.4~rc2/man/cryptsetup.8 2006-09-09 22:23:30.000000000 +0100 @@ -1,4 +1,4 @@ -.TH CRYPTSETUP "8" "March 2005" "cryptsetup 1.0.3" "Maintainance Commands" +.TH CRYPTSETUP "9" "September 2006" "cryptsetup 1.0.4" "Maintainance Commands" .SH NAME cryptsetup - setup cryptographic volumes for dm-crypt (including LUKS extension) .SH SYNOPSIS @@ -79,7 +79,7 @@ .SH OPTIONS .TP .B "\-\-hash, \-h" -specifies hash to use for password hashing. This option is only relevant for the "create" action. The hash string is passed to libgcrypt, so all hashes accepted by gcrypt are supported. Default is "ripemd160". +specifies hash to use for password hashing. This option is only relevant for the actions of "create", "luksFormat", "luksOpen", "luksDelKey", and "luksAddKey". The hash string is passed to libgcrypt, so all hashes accepted by gcrypt are supported, but for the luks actions, any hash other than "plain" is ignored. Default is "ripemd160". .TP .B "\-\-cipher, \-c" set cipher specification string. Usually, this is "aes-cbc-plain". For pre-2.6.10 kernels, use "aes-plain" as they don't understand the new cipher spec strings. To use ESSIV, use "aes-cbc-essiv:sha256". @@ -131,8 +131,10 @@ \fIFrom a key file\fR: It will be cropped to the size given by \-s. If there is insufficient key material in the key file, cryptsetup will quit with an error. .SH NOTES ON PASSWORD PROCESSING FOR LUKS Password processing is totally different for LUKS. LUKS uses PBKDF2 to protect against dictionary attacks (see RFC 2898). -LUKS will always use SHA1 in HMAC mode, and no other mode is supported at the moment. -Hence, \-h is ignored. +LUKS will always use SHA1 in HMAC mode, unless a "plain" hash is specified. For plain hashing, the password must be a +hexadecimal number containing only the digits 0 through 9 and the lower case letters a through f, and the length of the +password must be 1/4th of the keysize in bits (e.g., 64 letters or digits for a 256 bit key). A password of any other form +will be hashed regardless. Plain hashing with luks is currently specific to the Debian package of cryptsetup. LUKS will always do an exhaustive password reading. Hence, password can not be read from /dev/random, /dev/zero or any other stream, that does not terminate. @@ -146,6 +148,7 @@ cryptsetup is written by Christophe Saout <[EMAIL PROTECTED]> .br LUKS extensions, and man page by Clemens Fruhwirth <[EMAIL PROTECTED]> +with patches by Dennis Furey <[EMAIL PROTECTED]> .SH "REPORTING BUGS" Report bugs to <[EMAIL PROTECTED]>. .SH COPYRIGHT diff -urNad cryptsetup-1.0.4~rc2~/src/cryptsetup.c cryptsetup-1.0.4~rc2/src/cryptsetup.c --- cryptsetup-1.0.4~rc2~/src/cryptsetup.c 2006-09-09 22:20:55.000000000 +0100 +++ cryptsetup-1.0.4~rc2/src/cryptsetup.c 2006-09-09 22:23:30.000000000 +0100 @@ -223,6 +223,8 @@ int r = 0; char *msg = NULL; + if(opt_hash && strcmp(opt_hash, "plain") == 0) + options.flags |= CRYPT_FLAG_ALLOW_PLAIN_HASH; if(asprintf(&msg, _("This will overwrite data on %s irrevocably."), options.device) == -1) { fputs(_("memory allocation error in action_luksFormat"), stderr); } else { @@ -246,6 +248,8 @@ opt_verbose = 1; options.flags = 0; + if(opt_hash && strcmp(opt_hash, "plain") == 0) + options.flags |= CRYPT_FLAG_ALLOW_PLAIN_HASH; if (opt_readonly) options.flags |= CRYPT_FLAG_READONLY; r = crypt_luksOpen(&options); @@ -265,6 +269,8 @@ int r; opt_verbose = 1; + if(opt_hash && strcmp(opt_hash, "plain") == 0) + options.flags |= CRYPT_FLAG_ALLOW_PLAIN_HASH; if(LUKS_is_last_keyslot(options.device, options.key_slot) && !yesDialog(_("This is the last keyslot. Device will become unusable after purging this key."))) { r = -EINVAL; @@ -288,6 +294,8 @@ int r; opt_verbose = 1; + if(opt_hash && strcmp(opt_hash, "plain") == 0) + options.flags |= CRYPT_FLAG_ALLOW_PLAIN_HASH; r = crypt_luksAddKey(&options); show_status(-r); return r; -- System Information: Debian Release: testing/unstable APT prefers unstable APT policy: (500, 'unstable') Architecture: i386 (i686) Shell: /bin/sh linked to /bin/bash Kernel: Linux 2.6.17-2-686 Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968) Versions of packages cryptsetup depends on: ii dmsetup 2:1.02.08-1 The Linux Kernel Device Mapper use ii libc6 2.3.6.ds1-4 GNU C Library: Shared libraries ii libdevmapper1.02 2:1.02.08-1 The Linux Kernel Device Mapper use ii libgcrypt11 1.2.3-2 LGPL Crypto library - runtime libr ii libgpg-error0 1.2-1 library for common error values an ii libpopt0 1.10-3 lib for parsing cmdline parameters ii libuuid1 1.39-1 universally unique id library cryptsetup recommends no packages. -- no debconf information -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]