int openedIndex;
int r, last_slot;
- if (!LUKS_device_ready(options->device, O_RDWR))
- return -ENOTBLK;
+ r = LUKS_read_phdr(options->device, &hdr, 1, cd);
+ if(r < 0)
+ return r;
if(supply_it) {
get_key("Enter LUKS passphrase to be deleted: ",&password,&passwordLen, 0, options->new_key_file,
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) {
log_err(cd, "No remaining key available with this passphrase.\n");
r = -EPERM; goto out;
}
}
- 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.")))) {
r = -EINVAL; goto out;
}
if(!last_slot)
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 */
if (openedIndex >= 0) {
LUKS_dealloc_masterkey(mk);
char cipherName[LUKS_CIPHERNAME_L];
char cipherMode[LUKS_CIPHERMODE_L];
unsigned int passwordLen;
- unsigned int PBKDF2perSecond = 0;
+ uint64_t PBKDF2perSecond = 0;
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;
mk = LUKS_generate_masterkey(options->key_size);
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;
keyIndex = keyslot_from_option(NULL, options->key_slot, &header);
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,
options->timeout, options->flags, NULL);
if(!password) {
if(r < 0) goto out;
/* 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;
r = 0;
return -EEXIST;
}
- if (!LUKS_device_ready(options->device, O_RDONLY | excl))
+ if (!device_ready(cd, options->device, O_RDONLY | excl))
return -ENOTBLK;
if (get_device_infos(options->device, &infos, cd) < 0) {
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)
log_err(cd, "No key available with this passphrase.\n");
if (r < 0)
struct luks_phdr hdr;
char *password=NULL; unsigned int passwordLen;
unsigned int keyIndex;
- unsigned int PBKDF2perSecond = 0;
+ uint64_t PBKDF2perSecond = 0;
const char *device = options->device;
int r;
- if (!LUKS_device_ready(options->device, O_RDWR))
+ if (!device_ready(cd, options->device, O_RDWR))
return -ENOTBLK;
r = LUKS_read_phdr(device, &hdr, 1, cd);
if(!password) {
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) {
options->icb->log(CRYPT_LOG_ERROR,"No key available with this passphrase.\n");
r = -EPERM; goto out;
r = -EINVAL; goto out;
}
- r = LUKS_benchmarkt_iterations(hdr.hashSpec, &PBKDF2perSecond);
- 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);
+ r = LUKS_set_key(device, keyIndex, password, passwordLen, &hdr, mk, options->iteration_time, &PBKDF2perSecond, cd);
if(r < 0) goto out;
r = 0;
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
- *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
* along with this program; if not, write to the Free Software
* 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 <linux/fs.h>
+#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
-#include <assert.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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);
if(NULL == mk) return NULL;
mk->keyLength=keylength;
+ if (key)
+ memcpy(&mk->key, key, keylength);
return mk;
}
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;
int r = getRandom(mk->key,keylength);
return mk;
}
-int LUKS_read_phdr(
- const char *device,
- struct luks_phdr *hdr,
- int require_luks_device,
- struct crypt_device *ctx)
+int LUKS_read_phdr(const char *device,
+ struct luks_phdr *hdr,
+ int require_luks_device,
+ struct crypt_device *ctx)
{
int devfd = 0, r = 0;
unsigned int i;
return r;
}
-int LUKS_write_phdr(
- const char *device,
- struct luks_phdr *hdr,
- struct crypt_device *ctx)
+int LUKS_write_phdr(const char *device,
+ struct luks_phdr *hdr,
+ struct crypt_device *ctx)
{
int devfd = 0;
unsigned int i;
log_err(ctx, _("Error during update of LUKS header on device %s.\n"), device);
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;
}
-int LUKS_generate_phdr(
- struct luks_phdr *header,
- const struct luks_masterkey *mk,
- const char *cipherName, const char *cipherMode, const char *hashSpec,
- unsigned int stripes,
- unsigned int alignPayload,
- struct crypt_device *ctx)
+int LUKS_generate_phdr(struct luks_phdr *header,
+ const struct luks_masterkey *mk,
+ const char *cipherName, const char *cipherMode, const char *hashSpec,
+ const char *uuid, unsigned int stripes,
+ unsigned int alignPayload,
+ struct crypt_device *ctx)
{
unsigned int i=0;
unsigned int blocksPerStripeSet = div_round_up(mk->keyLength*stripes,SECTOR_SIZE);
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);
log_dbg("Data offset %d, UUID %s", header->payloadOffset, header->uuid);
return 0;
}
-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 crypt_device *ctx)
+int LUKS_set_key(const char *device, unsigned int keyIndex,
+ const char *password, size_t passwordLen,
+ struct luks_phdr *hdr, struct luks_masterkey *mk,
+ uint32_t iteration_time_ms,
+ uint64_t *PBKDF2_per_sec,
+ struct crypt_device *ctx)
{
char derivedKey[hdr->keyBytes];
char *AfKey;
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);
if(r < 0) return r;
}
/* 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);
if(r < 0) goto out;
return r;
}
+/* Check whether a master key is invalid. */
+int LUKS_verify_master_key(const struct luks_phdr *hdr,
+ const struct luks_masterkey *mk)
+{
+ 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)
+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 *AfKey;
size_t AFEKSize;
- char checkHashBuf[LUKS_DIGESTSIZE];
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;
- }
// assert((mk->keyLength % TWOFISH_BLOCKSIZE) == 0); FIXME
r = AF_merge(AfKey,mk->key,mk->keyLength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
if(r < 0) goto out;
- r = PBKDF2_HMAC(hdr->hashSpec,mk->key,mk->keyLength,
- hdr->mkDigestSalt,LUKS_SALTSIZE,
- hdr->mkDigestIterations,
- checkHashBuf,LUKS_DIGESTSIZE);
- if(r < 0) goto out;
-
- r = (memcmp(checkHashBuf,hdr->mkDigest, LUKS_DIGESTSIZE) == 0)?0:-EPERM;
+ r = LUKS_verify_master_key(hdr, mk);
if (r >= 0)
log_std(ctx, _("Key slot %d unlocked.\n"), keyIndex);
out:
return r;
}
-/* Tries to open any key from a given LUKS device reading the header on its own */
-int LUKS_open_any_key(
- const char *device,
- const char *password,
- size_t passwordLen,
- struct luks_phdr *hdr,
- struct luks_masterkey **mk,
- struct crypt_device *ctx)
+int LUKS_open_key_with_hdr(const char *device,
+ int keyIndex,
+ const char *password,
+ size_t passwordLen,
+ struct luks_phdr *hdr,
+ struct luks_masterkey **mk,
+ struct crypt_device *ctx)
{
+ unsigned int i;
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);
-}
+ *mk = LUKS_alloc_masterkey(hdr->keyBytes, NULL);
-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;
- int r;
+ if (keyIndex >= 0)
+ return LUKS_open_key(device, keyIndex, password, passwordLen, hdr, *mk, ctx);
- *mk=LUKS_alloc_masterkey(hdr->keyBytes);
- for(i=0; i<LUKS_NUMKEYS; i++) {
+ for(i = 0; i < LUKS_NUMKEYS; i++) {
r = LUKS_open_key(device, i, password, passwordLen, hdr, *mk, ctx);
if(r == 0)
return i;
return r;
}
-int LUKS_del_key(
- const char *device,
- unsigned int keyIndex,
- struct crypt_device *ctx)
+int LUKS_del_key(const char *device, unsigned int keyIndex, struct crypt_device *ctx)
{
struct luks_phdr hdr;
unsigned int startOffset, endOffset, stripesLen;
int r;
r = LUKS_read_phdr(device, &hdr, 1, ctx);
- if(r != 0) {
- /* placeholder */
- } else if(keyIndex >= LUKS_NUMKEYS || hdr.keyblock[keyIndex].active != LUKS_KEY_ENABLED) {
+ if (r)
+ return r;
+
+ 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"),
keyIndex, LUKS_NUMKEYS - 1);
- r = -ENOENT;
- } 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);
- }
+ return r;
}
+ /* 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;
}
-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;
- unsigned int i;
- int r;
+ int i;
- r = LUKS_read_phdr(device, &hdr, 1, NULL);
- if(r < 0) return r;
+ if(keyslot >= LUKS_NUMKEYS || keyslot < 0)
+ return SLOT_INVALID;
- for(i = 0; i < LUKS_NUMKEYS; i++) {
- if(i != keyIndex && hdr.keyblock[i].active == LUKS_KEY_ENABLED)
- return 0;
- }
- return 1;
+ if (hdr->keyblock[keyslot].active == LUKS_KEY_DISABLED)
+ return SLOT_INACTIVE;
+
+ if (hdr->keyblock[keyslot].active != LUKS_KEY_ENABLED)
+ 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) {
- set_error(_("Not compatible options (using hash algorithm %s)."), hash);
+ int i;
+
+ for (i = 0; i < LUKS_NUMKEYS; i++)
+ if(hdr->keyblock[i].active == LUKS_KEY_DISABLED)
+ break;
+
+ if (i == LUKS_NUMKEYS)
return -EINVAL;
- }
- *count /= 2;
- return 0;
+ return i;
}
-int LUKS_device_ready(const char *device, int mode)
+int LUKS_keyslot_active_count(struct luks_phdr *hdr)
{
- int devfd;
- struct stat st;
+ int i, num = 0;
- if(stat(device, &st) < 0) {
- set_error(_("Device %s doesn't exist or access denied."), device);
- return 0;
- }
+ for (i = 0; i < LUKS_NUMKEYS; i++)
+ if(hdr->keyblock[i].active == LUKS_KEY_ENABLED)
+ num++;
- 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 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;
- return 1;
+ 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;
}