* Run performance check for PBKDF2 from LUKS code, do not mix hash algoritms results.

* Add ability to provide pre-generated master key and UUID in LUKS header format.
* Add LUKS function to verify master key digest.
* Move key slot manuipulation function into LUKS specific code.

Signed-off-by: Milan Broz <mbroz@redhat.com>

git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@94 36d66b0a-2a48-0410-832c-cd162a569da5
This commit is contained in:
Milan Broz
2009-08-30 18:09:34 +00:00
parent cee0f0b49f
commit 74b26c7b8a
7 changed files with 234 additions and 204 deletions

View File

@@ -8,6 +8,10 @@
* Move device utils code and provide context parameter (for log). * Move device utils code and provide context parameter (for log).
* Keyfile now must be provided by path, only stdin file descriptor is used (api only). * Keyfile now must be provided by path, only stdin file descriptor is used (api only).
* Do not call isatty() on closed keyfile descriptor. * Do not call isatty() on closed keyfile descriptor.
* Run performance check for PBKDF2 from LUKS code, do not mix hash algoritms results.
* Add ability to provide pre-generated master key and UUID in LUKS header format.
* Add LUKS function to verify master key digest.
* Move key slot manuipulation function into LUKS specific code.
2009-08-17 Milan Broz <mbroz@redhat.com> 2009-08-17 Milan Broz <mbroz@redhat.com>
* Fix PBKDF2 speed calculation for large passhrases. * Fix PBKDF2 speed calculation for large passhrases.

View File

@@ -6,6 +6,11 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
struct crypt_device; /* crypt device handle */
#define CRYPT_ANY_SLOT -1
typedef enum { SLOT_INVALID, SLOT_INACTIVE, SLOT_ACTIVE, SLOT_ACTIVE_LAST } crypt_keyslot_info;
#define CRYPT_LOG_NORMAL 0 #define CRYPT_LOG_NORMAL 0
#define CRYPT_LOG_ERROR 1 #define CRYPT_LOG_ERROR 1
@@ -16,7 +21,6 @@ struct interface_callbacks {
void (*log)(int class, char *msg); void (*log)(int class, char *msg);
}; };
#define CRYPT_FLAG_VERIFY (1 << 0) #define CRYPT_FLAG_VERIFY (1 << 0)
#define CRYPT_FLAG_READONLY (1 << 1) #define CRYPT_FLAG_READONLY (1 << 1)
#define CRYPT_FLAG_VERIFY_IF_POSSIBLE (1 << 2) #define CRYPT_FLAG_VERIFY_IF_POSSIBLE (1 << 2)
@@ -33,9 +37,9 @@ struct crypt_options {
const char *passphrase; const char *passphrase;
int passphrase_fd; int passphrase_fd;
const char *key_file; const char *key_file;
const char *new_key_file; const char *new_key_file;
int key_size; int key_size;
unsigned int flags; unsigned int flags;
int key_slot; int key_slot;
@@ -43,9 +47,9 @@ struct crypt_options {
uint64_t offset; uint64_t offset;
uint64_t skip; uint64_t skip;
uint64_t iteration_time; uint64_t iteration_time;
uint64_t timeout; uint64_t timeout;
uint64_t align_payload; uint64_t align_payload;
int tries; int tries;
struct interface_callbacks *icb; struct interface_callbacks *icb;
@@ -63,7 +67,6 @@ int crypt_luksRemoveKey(struct crypt_options *options);
int crypt_luksAddKey(struct crypt_options *options); int crypt_luksAddKey(struct crypt_options *options);
int crypt_luksUUID(struct crypt_options *options); int crypt_luksUUID(struct crypt_options *options);
int crypt_isLuks(struct crypt_options *options); int crypt_isLuks(struct crypt_options *options);
int crypt_luksFormat(struct crypt_options *options);
int crypt_luksDump(struct crypt_options *options); int crypt_luksDump(struct crypt_options *options);
void crypt_get_error(char *buf, size_t size); void crypt_get_error(char *buf, size_t size);

View File

@@ -250,8 +250,9 @@ static int luks_remove_helper(struct crypt_device *cd,
int openedIndex; int openedIndex;
int r, last_slot; int r, last_slot;
if (!LUKS_device_ready(options->device, O_RDWR)) r = LUKS_read_phdr(options->device, &hdr, 1, cd);
return -ENOTBLK; if(r < 0)
return r;
if(supply_it) { if(supply_it) {
get_key("Enter LUKS passphrase to be deleted: ",&password,&passwordLen, 0, options->new_key_file, get_key("Enter LUKS passphrase to be deleted: ",&password,&passwordLen, 0, options->new_key_file,
@@ -260,7 +261,7 @@ static int luks_remove_helper(struct crypt_device *cd,
r = -EINVAL; goto out; r = -EINVAL; goto out;
} }
keyIndex = LUKS_open_any_key(device, password, passwordLen, &hdr, &mk, cd); keyIndex = LUKS_open_key_with_hdr(device, CRYPT_ANY_SLOT, password, passwordLen, &hdr, &mk, cd);
if(keyIndex < 0) { if(keyIndex < 0) {
log_err(cd, "No remaining key available with this passphrase.\n"); log_err(cd, "No remaining key available with this passphrase.\n");
r = -EPERM; goto out; r = -EPERM; goto out;
@@ -276,7 +277,13 @@ static int luks_remove_helper(struct crypt_device *cd,
} }
} }
last_slot = LUKS_is_last_keyslot(options->device, keyIndex); if (LUKS_keyslot_info(&hdr, keyIndex) == SLOT_INACTIVE) {
log_err(cd, _("Key %d not active. Can't wipe.\n"), keyIndex);
r = -EINVAL;
goto out;
}
last_slot = (LUKS_keyslot_info(&hdr, keyIndex) == SLOT_ACTIVE_LAST);
if(last_slot && !(options->icb->yesDialog(_("This is the last keyslot. Device will become unusable after purging this key.")))) { if(last_slot && !(options->icb->yesDialog(_("This is the last keyslot. Device will become unusable after purging this key.")))) {
r = -EINVAL; goto out; r = -EINVAL; goto out;
} }
@@ -298,7 +305,7 @@ static int luks_remove_helper(struct crypt_device *cd,
if(!last_slot) if(!last_slot)
hdr.keyblock[keyIndex].active = LUKS_KEY_DISABLED; hdr.keyblock[keyIndex].active = LUKS_KEY_DISABLED;
openedIndex = LUKS_open_any_key_with_hdr(device, password, passwordLen, &hdr, &mk, cd); openedIndex = LUKS_open_key_with_hdr(device, CRYPT_ANY_SLOT, password, passwordLen, &hdr, &mk, cd);
/* Clean up */ /* Clean up */
if (openedIndex >= 0) { if (openedIndex >= 0) {
LUKS_dealloc_masterkey(mk); LUKS_dealloc_masterkey(mk);
@@ -429,10 +436,10 @@ int crypt_luksFormat(struct crypt_options *options)
char cipherName[LUKS_CIPHERNAME_L]; char cipherName[LUKS_CIPHERNAME_L];
char cipherMode[LUKS_CIPHERMODE_L]; char cipherMode[LUKS_CIPHERMODE_L];
unsigned int passwordLen; unsigned int passwordLen;
unsigned int PBKDF2perSecond = 0; uint64_t PBKDF2perSecond = 0;
int r, keyIndex; int r, keyIndex;
if (!LUKS_device_ready(options->device, O_RDWR | O_EXCL)) if (!device_ready(cd, options->device, O_RDWR | O_EXCL))
return -ENOTBLK; return -ENOTBLK;
mk = LUKS_generate_masterkey(options->key_size); mk = LUKS_generate_masterkey(options->key_size);
@@ -466,7 +473,7 @@ int crypt_luksFormat(struct crypt_options *options)
return r; return r;
} }
r = LUKS_generate_phdr(&header, mk, cipherName, cipherMode, options->hash, LUKS_STRIPES, options->align_payload, NULL); r = LUKS_generate_phdr(&header, mk, cipherName, cipherMode, options->hash, NULL, LUKS_STRIPES, options->align_payload, NULL);
if(r < 0) return r; if(r < 0) return r;
keyIndex = keyslot_from_option(NULL, options->key_slot, &header); keyIndex = keyslot_from_option(NULL, options->key_slot, &header);
@@ -474,13 +481,6 @@ int crypt_luksFormat(struct crypt_options *options)
r = -EINVAL; goto out; r = -EINVAL; goto out;
} }
r = LUKS_benchmarkt_iterations(options->hash, &PBKDF2perSecond);
if (r < 0) goto out;
header.keyblock[keyIndex].passwordIterations = at_least_one(PBKDF2perSecond * ((float)options->iteration_time / 1000.0));
#ifdef LUKS_DEBUG
logger(options, CRYPT_LOG_ERROR, "pitr %d\n", header.keyblock[0].passwordIterations);
#endif
get_key("Enter LUKS passphrase: ",&password,&passwordLen, 0, options->new_key_file, get_key("Enter LUKS passphrase: ",&password,&passwordLen, 0, options->new_key_file,
options->timeout, options->flags, NULL); options->timeout, options->flags, NULL);
if(!password) { if(!password) {
@@ -492,7 +492,8 @@ int crypt_luksFormat(struct crypt_options *options)
if(r < 0) goto out; if(r < 0) goto out;
/* Set key, also writes phdr */ /* Set key, also writes phdr */
r = LUKS_set_key(options->device, keyIndex, password, passwordLen, &header, mk, NULL); r = LUKS_set_key(options->device, keyIndex, password, passwordLen, &header, mk,
options->iteration_time, &PBKDF2perSecond, NULL);
if(r < 0) goto out; if(r < 0) goto out;
r = 0; r = 0;
@@ -522,7 +523,7 @@ int crypt_luksOpen(struct crypt_options *options)
return -EEXIST; return -EEXIST;
} }
if (!LUKS_device_ready(options->device, O_RDONLY | excl)) if (!device_ready(cd, options->device, O_RDONLY | excl))
return -ENOTBLK; return -ENOTBLK;
if (get_device_infos(options->device, &infos, cd) < 0) { if (get_device_infos(options->device, &infos, cd) < 0) {
@@ -557,7 +558,11 @@ start:
r = -EINVAL; goto out; r = -EINVAL; goto out;
} }
r = LUKS_open_any_key(options->device, password, passwordLen, &hdr, &mk, cd); r = LUKS_read_phdr(options->device, &hdr, 1, cd);
if(r < 0)
return r;
r = LUKS_open_key_with_hdr(options->device, CRYPT_ANY_SLOT, password, passwordLen, &hdr, &mk, cd);
if (r == -EPERM) if (r == -EPERM)
log_err(cd, "No key available with this passphrase.\n"); log_err(cd, "No key available with this passphrase.\n");
if (r < 0) if (r < 0)
@@ -628,11 +633,11 @@ int crypt_luksAddKey(struct crypt_options *options)
struct luks_phdr hdr; struct luks_phdr hdr;
char *password=NULL; unsigned int passwordLen; char *password=NULL; unsigned int passwordLen;
unsigned int keyIndex; unsigned int keyIndex;
unsigned int PBKDF2perSecond = 0; uint64_t PBKDF2perSecond = 0;
const char *device = options->device; const char *device = options->device;
int r; int r;
if (!LUKS_device_ready(options->device, O_RDWR)) if (!device_ready(cd, options->device, O_RDWR))
return -ENOTBLK; return -ENOTBLK;
r = LUKS_read_phdr(device, &hdr, 1, cd); r = LUKS_read_phdr(device, &hdr, 1, cd);
@@ -655,7 +660,7 @@ int crypt_luksAddKey(struct crypt_options *options)
if(!password) { if(!password) {
r = -EINVAL; goto out; r = -EINVAL; goto out;
} }
r = LUKS_open_any_key(device, password, passwordLen, &hdr, &mk, cd); r = LUKS_open_key_with_hdr(device, CRYPT_ANY_SLOT, password, passwordLen, &hdr, &mk, cd);
if(r < 0) { if(r < 0) {
options->icb->log(CRYPT_LOG_ERROR,"No key available with this passphrase.\n"); options->icb->log(CRYPT_LOG_ERROR,"No key available with this passphrase.\n");
r = -EPERM; goto out; r = -EPERM; goto out;
@@ -673,11 +678,7 @@ int crypt_luksAddKey(struct crypt_options *options)
r = -EINVAL; goto out; r = -EINVAL; goto out;
} }
r = LUKS_benchmarkt_iterations(hdr.hashSpec, &PBKDF2perSecond); r = LUKS_set_key(device, keyIndex, password, passwordLen, &hdr, mk, options->iteration_time, &PBKDF2perSecond, cd);
if (r < 0) goto out;
hdr.keyblock[keyIndex].passwordIterations = at_least_one(PBKDF2perSecond * ((float)options->iteration_time / 1000));
r = LUKS_set_key(device, keyIndex, password, passwordLen, &hdr, mk, cd);
if(r < 0) goto out; if(r < 0) goto out;
r = 0; r = 0;

View File

@@ -2,7 +2,7 @@
* LUKS - Linux Unified Key Setup * LUKS - Linux Unified Key Setup
* *
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org> * Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation. * version 2 as published by the Free Software Foundation.
@@ -16,17 +16,13 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <netinet/in.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -47,11 +43,13 @@ static inline int round_up_modulo(int x, int m) {
return div_round_up(x, m) * m; return div_round_up(x, m) * m;
} }
struct luks_masterkey *LUKS_alloc_masterkey(int keylength) struct luks_masterkey *LUKS_alloc_masterkey(int keylength, const char *key)
{ {
struct luks_masterkey *mk=malloc(sizeof(*mk) + keylength); struct luks_masterkey *mk=malloc(sizeof(*mk) + keylength);
if(NULL == mk) return NULL; if(NULL == mk) return NULL;
mk->keyLength=keylength; mk->keyLength=keylength;
if (key)
memcpy(&mk->key, key, keylength);
return mk; return mk;
} }
@@ -66,7 +64,7 @@ void LUKS_dealloc_masterkey(struct luks_masterkey *mk)
struct luks_masterkey *LUKS_generate_masterkey(int keylength) struct luks_masterkey *LUKS_generate_masterkey(int keylength)
{ {
struct luks_masterkey *mk=LUKS_alloc_masterkey(keylength); struct luks_masterkey *mk=LUKS_alloc_masterkey(keylength, NULL);
if(NULL == mk) return NULL; if(NULL == mk) return NULL;
int r = getRandom(mk->key,keylength); int r = getRandom(mk->key,keylength);
@@ -77,11 +75,10 @@ struct luks_masterkey *LUKS_generate_masterkey(int keylength)
return mk; return mk;
} }
int LUKS_read_phdr( int LUKS_read_phdr(const char *device,
const char *device, struct luks_phdr *hdr,
struct luks_phdr *hdr, int require_luks_device,
int require_luks_device, struct crypt_device *ctx)
struct crypt_device *ctx)
{ {
int devfd = 0, r = 0; int devfd = 0, r = 0;
unsigned int i; unsigned int i;
@@ -137,10 +134,9 @@ int LUKS_read_phdr(
return r; return r;
} }
int LUKS_write_phdr( int LUKS_write_phdr(const char *device,
const char *device, struct luks_phdr *hdr,
struct luks_phdr *hdr, struct crypt_device *ctx)
struct crypt_device *ctx)
{ {
int devfd = 0; int devfd = 0;
unsigned int i; unsigned int i;
@@ -176,16 +172,22 @@ int LUKS_write_phdr(
log_err(ctx, _("Error during update of LUKS header on device %s.\n"), device); log_err(ctx, _("Error during update of LUKS header on device %s.\n"), device);
close(devfd); close(devfd);
/* Re-read header from disk to be sure that in-memory and on-disk data are the same. */
if (!r) {
r = LUKS_read_phdr(device, hdr, 1, ctx);
if (r)
log_err(ctx, _("Error re-reading LUKS header after update on device %s.\n"), device);
}
return r; return r;
} }
int LUKS_generate_phdr( int LUKS_generate_phdr(struct luks_phdr *header,
struct luks_phdr *header, const struct luks_masterkey *mk,
const struct luks_masterkey *mk, const char *cipherName, const char *cipherMode, const char *hashSpec,
const char *cipherName, const char *cipherMode, const char *hashSpec, const char *uuid, unsigned int stripes,
unsigned int stripes, unsigned int alignPayload,
unsigned int alignPayload, struct crypt_device *ctx)
struct crypt_device *ctx)
{ {
unsigned int i=0; unsigned int i=0;
unsigned int blocksPerStripeSet = div_round_up(mk->keyLength*stripes,SECTOR_SIZE); unsigned int blocksPerStripeSet = div_round_up(mk->keyLength*stripes,SECTOR_SIZE);
@@ -241,7 +243,12 @@ int LUKS_generate_phdr(
header->payloadOffset=currentSector; header->payloadOffset=currentSector;
uuid_generate(partitionUuid); if (uuid && !uuid_parse(uuid, partitionUuid)) {
log_err(ctx, _("Wrong UUID format provided, generating new one.\n"));
uuid = NULL;
}
if (!uuid)
uuid_generate(partitionUuid);
uuid_unparse(partitionUuid, header->uuid); uuid_unparse(partitionUuid, header->uuid);
log_dbg("Data offset %d, UUID %s", header->payloadOffset, header->uuid); log_dbg("Data offset %d, UUID %s", header->payloadOffset, header->uuid);
@@ -249,14 +256,12 @@ int LUKS_generate_phdr(
return 0; return 0;
} }
int LUKS_set_key( int LUKS_set_key(const char *device, unsigned int keyIndex,
const char *device, const char *password, size_t passwordLen,
unsigned int keyIndex, struct luks_phdr *hdr, struct luks_masterkey *mk,
const char *password, uint32_t iteration_time_ms,
size_t passwordLen, uint64_t *PBKDF2_per_sec,
struct luks_phdr *hdr, struct crypt_device *ctx)
struct luks_masterkey *mk,
struct crypt_device *ctx)
{ {
char derivedKey[hdr->keyBytes]; char derivedKey[hdr->keyBytes];
char *AfKey; char *AfKey;
@@ -274,6 +279,21 @@ int LUKS_set_key(
return -EINVAL; return -EINVAL;
} }
log_dbg("Calculating data for key slot %d", keyIndex);
if (!*PBKDF2_per_sec) {
if (PBKDF2_performance_check(hdr->hashSpec, PBKDF2_per_sec) < 0) {
log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s)."), hdr->hashSpec);
return -EINVAL;
}
log_dbg("PBKDF2: %" PRIu64 " iterations per second using hash %s.", *PBKDF2_per_sec, hdr->hashSpec);
}
/* Avoid floating point operation - don't tell anyone that second have no 1024 miliseconds :-) */
iteration_time_ms = at_least_one(iteration_time_ms / 1024);
hdr->keyblock[keyIndex].passwordIterations = at_least_one((uint32_t)(*PBKDF2_per_sec/2) * iteration_time_ms);
log_dbg("Key slot %d use %d password iterations.", keyIndex, hdr->keyblock[keyIndex].passwordIterations);
r = getRandom(hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE); r = getRandom(hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE);
if(r < 0) return r; if(r < 0) return r;
@@ -315,7 +335,9 @@ int LUKS_set_key(
} }
/* Mark the key as active in phdr */ /* Mark the key as active in phdr */
hdr->keyblock[keyIndex].active = LUKS_KEY_ENABLED; r = LUKS_keyslot_set(hdr, (int)keyIndex, 1);
if(r < 0) goto out;
r = LUKS_write_phdr(device, hdr, ctx); r = LUKS_write_phdr(device, hdr, ctx);
if(r < 0) goto out; if(r < 0) goto out;
@@ -325,25 +347,43 @@ out:
return r; return r;
} }
/* Try to open a particular key slot */ /* Check whether a master key is invalid. */
int LUKS_open_key( int LUKS_verify_master_key(const struct luks_phdr *hdr,
const char *device, const struct luks_masterkey *mk)
unsigned int keyIndex,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
struct luks_masterkey *mk,
struct crypt_device *ctx)
{ {
char checkHashBuf[LUKS_DIGESTSIZE];
if (PBKDF2_HMAC(hdr->hashSpec, mk->key, mk->keyLength,
hdr->mkDigestSalt, LUKS_SALTSIZE,
hdr->mkDigestIterations, checkHashBuf,
LUKS_DIGESTSIZE) < 0)
return -EINVAL;
if (memcmp(checkHashBuf, hdr->mkDigest, LUKS_DIGESTSIZE))
return -EPERM;
return 0;
}
/* Try to open a particular key slot */
int LUKS_open_key(const char *device,
unsigned int keyIndex,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
struct luks_masterkey *mk,
struct crypt_device *ctx)
{
crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyIndex);
char derivedKey[hdr->keyBytes]; char derivedKey[hdr->keyBytes];
char *AfKey; char *AfKey;
size_t AFEKSize; size_t AFEKSize;
char checkHashBuf[LUKS_DIGESTSIZE];
int r; int r;
if(hdr->keyblock[keyIndex].active != LUKS_KEY_ENABLED) { log_dbg("Trying to open key slot %d [%d].", keyIndex, (int)ki);
if (ki < SLOT_ACTIVE)
return -ENOENT; return -ENOENT;
}
// assert((mk->keyLength % TWOFISH_BLOCKSIZE) == 0); FIXME // assert((mk->keyLength % TWOFISH_BLOCKSIZE) == 0); FIXME
@@ -374,13 +414,7 @@ int LUKS_open_key(
r = AF_merge(AfKey,mk->key,mk->keyLength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec); r = AF_merge(AfKey,mk->key,mk->keyLength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
if(r < 0) goto out; if(r < 0) goto out;
r = PBKDF2_HMAC(hdr->hashSpec,mk->key,mk->keyLength, r = LUKS_verify_master_key(hdr, mk);
hdr->mkDigestSalt,LUKS_SALTSIZE,
hdr->mkDigestIterations,
checkHashBuf,LUKS_DIGESTSIZE);
if(r < 0) goto out;
r = (memcmp(checkHashBuf,hdr->mkDigest, LUKS_DIGESTSIZE) == 0)?0:-EPERM;
if (r >= 0) if (r >= 0)
log_std(ctx, _("Key slot %d unlocked.\n"), keyIndex); log_std(ctx, _("Key slot %d unlocked.\n"), keyIndex);
out: out:
@@ -388,36 +422,23 @@ out:
return r; return r;
} }
/* Tries to open any key from a given LUKS device reading the header on its own */ int LUKS_open_key_with_hdr(const char *device,
int LUKS_open_any_key( int keyIndex,
const char *device, const char *password,
const char *password, size_t passwordLen,
size_t passwordLen, struct luks_phdr *hdr,
struct luks_phdr *hdr, struct luks_masterkey **mk,
struct luks_masterkey **mk, struct crypt_device *ctx)
struct crypt_device *ctx)
{
int r;
r = LUKS_read_phdr(device, hdr, 1, ctx);
if(r < 0)
return r;
return LUKS_open_any_key_with_hdr(device,password,passwordLen,hdr,mk, ctx);
}
int LUKS_open_any_key_with_hdr(
const char *device,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
struct luks_masterkey **mk,
struct crypt_device *ctx)
{ {
unsigned int i; unsigned int i;
int r; int r;
*mk=LUKS_alloc_masterkey(hdr->keyBytes); *mk = LUKS_alloc_masterkey(hdr->keyBytes, NULL);
for(i=0; i<LUKS_NUMKEYS; i++) {
if (keyIndex >= 0)
return LUKS_open_key(device, keyIndex, password, passwordLen, hdr, *mk, ctx);
for(i = 0; i < LUKS_NUMKEYS; i++) {
r = LUKS_open_key(device, i, password, passwordLen, hdr, *mk, ctx); r = LUKS_open_key(device, i, password, passwordLen, hdr, *mk, ctx);
if(r == 0) if(r == 0)
return i; return i;
@@ -491,84 +512,92 @@ static int wipe(const char *device, unsigned int from, unsigned int to)
return r; return r;
} }
int LUKS_del_key( int LUKS_del_key(const char *device, unsigned int keyIndex, struct crypt_device *ctx)
const char *device,
unsigned int keyIndex,
struct crypt_device *ctx)
{ {
struct luks_phdr hdr; struct luks_phdr hdr;
unsigned int startOffset, endOffset, stripesLen; unsigned int startOffset, endOffset, stripesLen;
int r; int r;
r = LUKS_read_phdr(device, &hdr, 1, ctx); r = LUKS_read_phdr(device, &hdr, 1, ctx);
if(r != 0) { if (r)
/* placeholder */ return r;
} else if(keyIndex >= LUKS_NUMKEYS || hdr.keyblock[keyIndex].active != LUKS_KEY_ENABLED) {
r = LUKS_keyslot_set(&hdr, keyIndex, 0);
if (r) {
log_err(ctx, _("Key slot %d is invalid, please select keyslot between 0 and %d.\n"), log_err(ctx, _("Key slot %d is invalid, please select keyslot between 0 and %d.\n"),
keyIndex, LUKS_NUMKEYS - 1); keyIndex, LUKS_NUMKEYS - 1);
r = -ENOENT; return r;
} else {
/* secure deletion of key material */
startOffset = hdr.keyblock[keyIndex].keyMaterialOffset;
stripesLen = hdr.keyBytes * hdr.keyblock[keyIndex].stripes;
endOffset = startOffset + div_round_up(stripesLen, SECTOR_SIZE);
r = wipe(device, startOffset, endOffset);
if(r == 0) {
/* mark the key as inactive in header */
hdr.keyblock[keyIndex].active = LUKS_KEY_DISABLED;
r = LUKS_write_phdr(device, &hdr, ctx);
}
} }
/* secure deletion of key material */
startOffset = hdr.keyblock[keyIndex].keyMaterialOffset;
stripesLen = hdr.keyBytes * hdr.keyblock[keyIndex].stripes;
endOffset = startOffset + div_round_up(stripesLen, SECTOR_SIZE);
r = wipe(device, startOffset, endOffset);
if (r) {
log_err(ctx, _("Cannot wipe device %s.\n"), device);
return r;
}
r = LUKS_write_phdr(device, &hdr, ctx);
return r; return r;
} }
int LUKS_is_last_keyslot(const char *device, unsigned int keyIndex) crypt_keyslot_info LUKS_keyslot_info(struct luks_phdr *hdr, int keyslot)
{ {
struct luks_phdr hdr; int i;
unsigned int i;
int r;
r = LUKS_read_phdr(device, &hdr, 1, NULL); if(keyslot >= LUKS_NUMKEYS || keyslot < 0)
if(r < 0) return r; return SLOT_INVALID;
for(i = 0; i < LUKS_NUMKEYS; i++) { if (hdr->keyblock[keyslot].active == LUKS_KEY_DISABLED)
if(i != keyIndex && hdr.keyblock[i].active == LUKS_KEY_ENABLED) return SLOT_INACTIVE;
return 0;
} if (hdr->keyblock[keyslot].active != LUKS_KEY_ENABLED)
return 1; return SLOT_INVALID;
for(i = 0; i < LUKS_NUMKEYS; i++)
if(i != keyslot && hdr->keyblock[i].active == LUKS_KEY_ENABLED)
return SLOT_ACTIVE;
return SLOT_ACTIVE_LAST;
} }
int LUKS_benchmarkt_iterations(const char *hash, unsigned int *count) int LUKS_keyslot_find_empty(struct luks_phdr *hdr)
{ {
if (PBKDF2_performance_check(hash, count) < 0) { int i;
set_error(_("Not compatible options (using hash algorithm %s)."), hash);
return -EINVAL;
}
*count /= 2; for (i = 0; i < LUKS_NUMKEYS; i++)
if(hdr->keyblock[i].active == LUKS_KEY_DISABLED)
break;
if (i == LUKS_NUMKEYS)
return -EINVAL;
return i;
}
int LUKS_keyslot_active_count(struct luks_phdr *hdr)
{
int i, num = 0;
for (i = 0; i < LUKS_NUMKEYS; i++)
if(hdr->keyblock[i].active == LUKS_KEY_ENABLED)
num++;
return num;
}
int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable)
{
crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyslot);
if (ki == SLOT_INVALID)
return -EINVAL;
hdr->keyblock[keyslot].active = enable ? LUKS_KEY_ENABLED : LUKS_KEY_DISABLED;
log_dbg("Key slot %d was %s in LUKS header.", keyslot, enable ? "enabled" : "disabled");
return 0; return 0;
} }
int LUKS_device_ready(const char *device, int mode)
{
int devfd;
struct stat st;
if(stat(device, &st) < 0) {
set_error(_("Device %s doesn't exist or access denied."), device);
return 0;
}
devfd = open(device, mode | O_DIRECT | O_SYNC);
if(devfd < 0) {
set_error(_("Can't open device %s for %s%saccess."), device,
(mode & O_EXCL)?_("exclusive "):"",
(mode & O_RDWR)?_("writable "):"read-only ");
return 0;
}
close(devfd);
return 1;
}

View File

@@ -5,10 +5,7 @@
* LUKS partition header * LUKS partition header
*/ */
#include <stddef.h>
#include <netinet/in.h>
#include "libcryptsetup.h" #include "libcryptsetup.h"
#include "internal.h"
#define LUKS_CIPHERNAME_L 32 #define LUKS_CIPHERNAME_L 32
#define LUKS_CIPHERMODE_L 32 #define LUKS_CIPHERMODE_L 32
@@ -78,16 +75,19 @@ struct luks_masterkey {
char key[]; char key[];
}; };
struct luks_masterkey *LUKS_alloc_masterkey(int keylength); struct luks_masterkey *LUKS_alloc_masterkey(int keylength, const char *key);
void LUKS_dealloc_masterkey(struct luks_masterkey *mk); void LUKS_dealloc_masterkey(struct luks_masterkey *mk);
struct luks_masterkey *LUKS_generate_masterkey(int keylength); struct luks_masterkey *LUKS_generate_masterkey(int keylength);
int LUKS_verify_master_key(const struct luks_phdr *hdr,
const struct luks_masterkey *mk);
int LUKS_generate_phdr( int LUKS_generate_phdr(
struct luks_phdr *header, struct luks_phdr *header,
const struct luks_masterkey *mk, const struct luks_masterkey *mk,
const char *cipherName, const char *cipherMode, const char *hashSpec, const char *cipherName,
const char *cipherMode,
const char *hashSpec,
const char *uuid,
unsigned int stripes, unsigned int stripes,
unsigned int alignPayload, unsigned int alignPayload,
struct crypt_device *ctx); struct crypt_device *ctx);
@@ -110,6 +110,8 @@ int LUKS_set_key(
size_t passwordLen, size_t passwordLen,
struct luks_phdr *hdr, struct luks_phdr *hdr,
struct luks_masterkey *mk, struct luks_masterkey *mk,
uint32_t iteration_time_ms,
uint64_t *PBKDF2_per_sec,
struct crypt_device *ctx); struct crypt_device *ctx);
int LUKS_open_key( int LUKS_open_key(
@@ -121,16 +123,9 @@ int LUKS_open_key(
struct luks_masterkey *mk, struct luks_masterkey *mk,
struct crypt_device *ctx); struct crypt_device *ctx);
int LUKS_open_any_key( int LUKS_open_key_with_hdr(
const char *device,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
struct luks_masterkey **mk,
struct crypt_device *ctx);
int LUKS_open_any_key_with_hdr(
const char *device, const char *device,
int keyIndex,
const char *password, const char *password,
size_t passwordLen, size_t passwordLen,
struct luks_phdr *hdr, struct luks_phdr *hdr,
@@ -142,8 +137,10 @@ int LUKS_del_key(
unsigned int keyIndex, unsigned int keyIndex,
struct crypt_device *ctx); struct crypt_device *ctx);
int LUKS_is_last_keyslot(const char *device, unsigned int keyIndex); crypt_keyslot_info LUKS_keyslot_info(struct luks_phdr *hdr, int keyslot);
int LUKS_benchmarkt_iterations(const char *hash, unsigned int *count); int LUKS_keyslot_find_empty(struct luks_phdr *hdr);
int LUKS_keyslot_active_count(struct luks_phdr *hdr);
int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable);
int LUKS_encrypt_to_storage( int LUKS_encrypt_to_storage(
char *src, size_t srcLength, char *src, size_t srcLength,
@@ -161,5 +158,4 @@ int LUKS_decrypt_from_storage(
unsigned int sector, unsigned int sector,
struct crypt_device *ctx); struct crypt_device *ctx);
int LUKS_device_ready(const char *device, int mode);
#endif #endif

View File

@@ -29,14 +29,14 @@
#include <sys/time.h> #include <sys/time.h>
#include <gcrypt.h> #include <gcrypt.h>
static volatile unsigned int __PBKDF2_global_j = 0; static volatile uint64_t __PBKDF2_global_j = 0;
static volatile unsigned int __PBKDF2_performance = 0; static volatile uint64_t __PBKDF2_performance = 0;
static int init_crypto(void) static int init_crypto(void)
{ {
if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) { if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) {
if (!gcry_check_version (GCRYPT_VERSION)) //if (!gcry_check_version (GCRYPT_VERSION))
return -ENOSYS; // return -ENOSYS;
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0); gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
gcry_control (GCRYCTL_RESUME_SECMEM_WARN); gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
@@ -219,7 +219,7 @@ static int pkcs5_pbkdf2(const char *hash,
} }
if (perfcheck) if (perfcheck)
__PBKDF2_global_j--; __PBKDF2_global_j++;
} }
memcpy(DK + (i - 1) * hLen, T, (uint) i == l ? r : hLen); memcpy(DK + (i - 1) * hLen, T, (uint) i == l ? r : hLen);
@@ -255,21 +255,18 @@ int PBKDF2_HMAC_ready(const char *hash)
static void sigvtalarm(int foo) static void sigvtalarm(int foo)
{ {
__PBKDF2_performance = ~(0U) - __PBKDF2_global_j; __PBKDF2_performance = __PBKDF2_global_j;
__PBKDF2_global_j = 0;
} }
/* This code benchmarks PBKDF2 and returns iterations/second using wth specified hash */ /* This code benchmarks PBKDF2 and returns iterations/second using wth specified hash */
int PBKDF2_performance_check(const char *hash, unsigned int *iter) int PBKDF2_performance_check(const char *hash, uint64_t *iter)
{ {
int r; int r;
char buf; char buf;
struct itimerval it; struct itimerval it;
if(__PBKDF2_performance != 0) { if (__PBKDF2_global_j)
*iter = __PBKDF2_performance; return -EBUSY;
return 0;
}
if (!PBKDF2_HMAC_ready(hash)) if (!PBKDF2_HMAC_ready(hash))
return -EINVAL; return -EINVAL;
@@ -284,8 +281,8 @@ int PBKDF2_performance_check(const char *hash, unsigned int *iter)
r = pkcs5_pbkdf2(hash, "foo", 3, "bar", 3, ~(0U), 1, &buf, 1); r = pkcs5_pbkdf2(hash, "foo", 3, "bar", 3, ~(0U), 1, &buf, 1);
__PBKDF2_global_j = 0;
*iter = __PBKDF2_performance; *iter = __PBKDF2_performance;
__PBKDF2_global_j = 0;
__PBKDF2_performance = 0;
return r; return r;
} }

View File

@@ -11,7 +11,7 @@ int PBKDF2_HMAC(const char *hash,
char *dKey, size_t dKeyLen); char *dKey, size_t dKeyLen);
int PBKDF2_performance_check(const char *hash, unsigned int *iter); int PBKDF2_performance_check(const char *hash, uint64_t *iter);
int PBKDF2_HMAC_ready(const char *hash); int PBKDF2_HMAC_ready(const char *hash);
#endif #endif