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;
+/**
+ * Initialise crypt device handle and check if provided device exists.
+ *
+ * Returns 0 on success or negative errno value otherwise.
+ *
+ * @cd - returns pointer to crypt device handle
+ *
+ * Note that logging is not initialized here, possible messages uses
+ * default log function.
+ */
+int crypt_init(struct crypt_device **cd, const char *device);
+/**
+ * Set log function.
+ *
+ * @cd - crypt device handle
+ * @usrptr - provided identification in callback
+ * @class - log type below (debug messages can uses other levels)
+ * @msg - log message
+ */
#define CRYPT_LOG_NORMAL 0
#define CRYPT_LOG_ERROR 1
-#define CRYPT_LOG_DEBUG -1 /* always on stdout */
+#define CRYPT_LOG_DEBUG -1 /* always on stdout */
+void crypt_set_log_callback(struct crypt_device *cd,
+ void (*log)(int class, const char *msg, void *usrptr),
+ void *usrptr);
+
+/**
+ * Set confirmation callback (yes/no)
+ *
+ * If code need confirmation (like deleting last key slot) this function
+ * is called. If not defined, everything is confirmed.
+ *
+ * Calback should return 0 if operation is declined, other values mean accepted.
+ *
+ * @cd - crypt device handle
+ * @usrptr - provided identification in callback
+ * @msg - Message for user to confirm
+ */
+void crypt_set_confirm_callback(struct crypt_device *cd,
+ int (*confirm)(const char *msg, void *usrptr),
+ void *usrptr);
+
+/**
+ * Set password query callback.
+ *
+ * If code need _interactive_ query for password, this callback is called.
+ * If not defined, compiled-in default is called (uses terminal input).
+ *
+ * @cd - crypt device handle
+ * @usrptr - provided identification in callback
+ * @msg - Message for user
+ * @buf - buffer for password
+ * @length - size of buffer
+ *
+ * - Note that if this function is defined, verify option is ignored
+ * (caller whch provided callback is responsible fo password verification)
+ * - Only zero terminated passwords can be enteted this way, for complex
+ * API functions directly.
+ * - Maximal length of password is limited to @length-1 (minimal 511 chars)
+ */
+void crypt_set_password_callback(struct crypt_device *cd,
+ int (*password)(const char *msg, char *buf, size_t length, void *usrptr),
+ void *usrptr);
+
+/**
+ * Various crypt device parameters
+ *
+ * @cd - crypt device handle
+ * @timeout - timeout in secons for password entry if compiled-in function used
+ * @password_retry - number of tries for password if not verified
+ * @iteration_time - iteration time for LUKS header in miliseconds
+ * @password_verify - for compiled-in password query always verify passwords twice
+ */
+void crypt_set_timeout(struct crypt_device *cd, uint64_t timeout_sec);
+void crypt_set_password_retry(struct crypt_device *cd, int tries);
+void crypt_set_iterarion_time(struct crypt_device *cd, uint64_t iteration_time_ms);
+void crypt_set_password_verify(struct crypt_device *cd, int password_verify);
+
+/**
+ * Helper to lock/unlock memory to avoid swapping sesitive data_alignment
+ *
+ * @cd - crypt device handle, can be NULL
+ * @lock - 0 to unloct otherwise lock memory
+ *
+ * Return value indicated that memory is locked (function can be called multiple times).
+ * Only root can do this. Note it locks/unlocks all process memory, not only crypt context.
+ */
+int crypt_memory_lock(struct crypt_device *cd, int lock);
+
+#define CRYPT_PLAIN "PLAIN" /* regular crypt device, no on-disk header */
+#define CRYPT_LUKS1 "LUKS1" /* LUKS version 1 header on-disk */
+
+struct crypt_params_plain {
+ const char *hash; /* password hash function */
+ uint64_t offset; /* offset in sectors */
+ uint64_t skip; /* IV initilisation sector */
+};
+
+struct crypt_params_luks1 {
+ const char *hash; /* hash used in LUKS header */
+ size_t data_alignment; /* in sectors, data offset is multiple of this */
+};
+
+/**
+ * Create (format) new crypt device (and possible header on-disk) but not activates it.
+ *
+ * Returns 0 on success or negative errno value otherwise.
+ *
+ * @cd - crypt device handle
+ * @type - type of device (optional params struct must be of this type)
+ * @cipher - (e.g. "aes")
+ * @cipher_mode - including IV specification (e.g. "xts-plain")
+ * @uuid - requested UUID or NULL if it should be generated
+ * @volume_key - pre-generated volume key or NULL if it should be generated (only for LUKS)
+ * @volume_key_size - size og volume key in bytes.
+ * @params - crypt type specific parameters
+ *
+ * Note that crypt_format do not enable any keyslot, but it stores volume key internally
+ * and subsequent crypt_keyslot_add_* calls can be used.
+ * (It is the only situation when crypt_keyslot_add_* do not require active key slots.)
+ */
+int crypt_format(struct crypt_device *cd,
+ const char *type,
+ const char *cipher,
+ const char *cipher_mode,
+ const char *uuid,
+ const char *volume_key,
+ size_t volume_key_size,
+ void *params);
+
+/**
+ * Load crypt device parameters from on-disk header
+ *
+ * Returns 0 on success or negative errno value otherwise.
+ *
+ * @cd - crypt device handle
+ * @requested_type - use NULL for all known
+ * @params - crypt type specific parameters
+ */
+int crypt_load(struct crypt_device *cd,
+ const char *requested_type,
+ void *params);
+
+/**
+ * Releases crypt device context and used memory.
+ *
+ * @cd - crypt device handle
+ */
+void crypt_free(struct crypt_device *cd);
+
+/**
+ * Add key slot using provided passphrase
+ *
+ * Returns allocated key slot number or negative errno otherwise.
+ *
+ * @cd - crypt device handle
+ * @keyslot - requested keyslot or CRYPT_ANY_SLOT
+ * @passphrase - passphrase used to unlock volume key, NULL for query
+ * @passphrase_size - size of @passphrase (binary data)
+ * @new_passphrase - passphrase for new keyslot, NULL for query
+ * @new_passphrase_size - size of @new_passphrase (binary data)
+ */
+#define CRYPT_ANY_SLOT -1
+int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
+ int keyslot,
+ const char *passphrase,
+ size_t passphrase_size,
+ const char *new_passphrase,
+ size_t new_passphrase_size);
+
+/**
+* Add key slot using provided key file path
+ *
+ * Returns allocated key slot number or negative errno otherwise.
+ *
+ * @cd - crypt device handle
+ * @keyslot - requested keyslot or CRYPT_ANY_SLOT
+ * @keyfile - key file used to unlock volume key, NULL for passphrase query
+ * @keyfile_size - number of bytes to read from @keyfile, 0 is unlimited
+ * @new_keyfile - keyfile for new keyslot, NULL for passphrase query
+ * @new_keyfile_size - number of bytes to read from @new_keyfile, 0 is unlimited
+ *
+ * Note that @keyfile can be "-" for STDIN
+ */
+int crypt_keyslot_add_by_keyfile(struct crypt_device *cd,
+ int keyslot,
+ const char *keyfile,
+ size_t keyfile_size,
+ const char *new_keyfile,
+ size_t new_keyfile_size);
+
+/**
+ * Add key slot using provided volume key
+ *
+ * Returns allocated key slot number or negative errno otherwise.
+ *
+ * @cd - crypt device handle
+ * @keyslot - requested keyslot or CRYPT_ANY_SLOT
+ * @volume_key - provided volume key or NULL if used after crypt_format
+ * @volume_key_size - size of @volume_key
+ * @passphrase - passphrase for new keyslot, NULL for query
+ * @passphrase_size - size of @passphrase
+ */
+int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
+ int keyslot,
+ const char *volume_key,
+ size_t volume_key_size,
+ const char *passphrase,
+ size_t passphrase_size);
+
+/**
+ * Destroy (and disable) key slot
+ *
+ * Returns 0 on success or negative errno value otherwise.
+ *
+ * @cd - crypt device handle
+ * @keyslot - requested key slot to destroy
+ *
+ * Note that there is no passphrase verification used.
+ */
+int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
+
+/**
+ * Activation flags
+ */
+#define CRYPT_ACTIVATE_READONLY (1 << 0)
+#define CRYPT_ACTIVATE_NO_UUID (1 << 1)
+
+/**
+ * Activate device or check passphrase
+ *
+ * Returns unlocked key slot number or negative errno otherwise.
+ *
+ * @cd - crypt device handle
+ * @name - name of device to create, if NULL only check passphrase
+ * @keyslot - requested keyslot to check or CRYPT_ANY_SLOT
+ * @passphrase - passphrase used to unlock volume key, NULL for query
+ * @passphrase_size - size of @passphrase
+ * @flags - activation flags
+ */
+int crypt_activate_by_passphrase(struct crypt_device *cd,
+ const char *name,
+ int keyslot,
+ const char *passphrase,
+ size_t passphrase_size,
+ uint32_t flags);
+
+/**
+ * Activate device or check using key file
+ *
+ * Returns unlocked key slot number or negative errno otherwise.
+ *
+ * @cd - crypt device handle
+ * @name - name of device to create, if NULL only check keyfile
+ * @keyslot - requested keyslot to check or CRYPT_ANY_SLOT
+ * @keyfile - key file used to unlock volume key
+ * @keyfile_size - number of bytes to read from @keyfile, 0 is unlimited
+ * @flags - activation flags
+ */
+int crypt_activate_by_keyfile(struct crypt_device *cd,
+ const char *name,
+ int keyslot,
+ const char *keyfile,
+ size_t keyfile_size,
+ uint32_t flags);
+
+/**
+ * Activate device using provided volume key
+ *
+ * Returns 0 on success or negative errno value otherwise.
+ *
+ * @cd - crypt device handle
+ * @name - name of device to create, if NULL only check volume key
+ * @volume_key - provided volume key
+ * @volume_key_size - size of @volume_key
+ * @flags - activation flags
+ */
+int crypt_activate_by_volume_key(struct crypt_device *cd,
+ const char *name,
+ const char *volume_key,
+ size_t volume_key_size,
+ uint32_t flags);
+
+/**
+ * Deactivate crypt device
+ *
+ * @cd - crypt device handle, can be NULL
+ * @name - name of device to deactivate
+ */
+int crypt_deactivate(struct crypt_device *cd, const char *name);
+
+/**
+ * Get volume key from of crypt device
+ *
+ * Returns unlocked key slot number or negative errno otherwise.
+ *
+ * @cd - crypt device handle
+ * @keyslot - use this keyslot or CRYPT_ANY_SLOT
+ * @volume_key - buffer for volume key
+ * @volume_key_size - on input, size of buffer @volume_key,
+ * on output size of @volume_key
+ * @passphrase - passphrase used to unlock volume key, NULL for query
+ * @passphrase_size - size of @passphrase
+ */
+int crypt_volume_key_get(struct crypt_device *cd,
+ int keyslot,
+ char *volume_key,
+ size_t *volume_key_size,
+ const char *passphrase,
+ size_t passphrase_size);
+
+/**
+ * Verify that provided volume key is valid for crypt device
+ *
+ * Returns 0 on success or negative errno value otherwise.
+ *
+ * @cd - crypt device handle
+ * @volume_key - provided volume key
+ * @volume_key_size - size of @volume_key
+ */
+int crypt_volume_key_verify(struct crypt_device *cd,
+ const char *volume_key,
+ size_t volume_key_size);
+
+/**
+ * Get status info about device name
+ *
+ * Returns value defined by crypt_status_info.
+ *
+ * @cd - crypt device handle, can be NULL
+ * @name -crypt device name
+ *
+ * INACTIVE - no such mapped device
+ * ACTIVE - device is active
+ * BUSY - device is active and has open count > 0
+ */
+typedef enum { INVALID, INACTIVE, ACTIVE, BUSY } crypt_status_info;
+crypt_status_info crypt_status(struct crypt_device *cd, const char *name);
+
+/**
+ * Dump text-formatted information about crypt device to log output
+ *
+ * Returns 0 on success or negative errno value otherwise.
+ *
+ * @cd - crypt device handle, can be NULL
+ */
+int crypt_dump(struct crypt_device *cd);
+
+/**
+ * Various crypt device info functions
+ *
+ * @cd - crypt device handle
+ *
+ * cipher - used cipher, e.g. "aes" or NULL otherwise
+ * cipher_mode - used cipher mode including IV, e.g. "xts-plain" or NULL otherwise
+ * uuid - device UUID or NULL if not set
+ * data_offset - device offset in sectors where real data starts on underlying device)
+ * volume_key_size - size (in bytes) of volume key for crypt device
+ */
+const char *crypt_get_cipher(struct crypt_device *cd);
+const char *crypt_get_cipher_mode(struct crypt_device *cd);
+const char *crypt_get_uuid(struct crypt_device *cd);
+uint64_t crypt_get_data_offset(struct crypt_device *cd);
+int crypt_get_volume_key_size(struct crypt_device *cd);
+
+/**
+ * Get information about particular key slot
+ *
+ * Returns value defined by crypt_keyslot_info.
+ *
+ * @cd - crypt device handle
+ * @keyslot - requested keyslot to check or CRYPT_ANY_SLOT
+ */
+typedef enum { SLOT_INVALID, SLOT_INACTIVE, SLOT_ACTIVE, SLOT_ACTIVE_LAST } crypt_keyslot_info;
+crypt_keyslot_info crypt_keyslot_status(struct crypt_device *cd, int keyslot);
+
+/**
+ * Receives last reported error
+ *
+ * @buf - buffef for message
+ * @size - size of buffer
+ *
+ * Note that this is old API function using global context.
+ * All error messages are reported also through log callback.
+ */
+void crypt_get_error(char *buf, size_t size);
+
+/**
+ * Get directory where mapped crypt devices are created
+ */
+const char *crypt_get_dir(void);
+
+/**
+ * Set library debug level
+ */
+#define CRYPT_DEBUG_ALL -1
+#define CRYPT_DEBUG_NONE 0
+void crypt_set_debug_level(int level);
+
+/**
+ * OLD DEPRECATED API **********************************
+ *
+ * Provided only for backward compatibility.
+ */
struct interface_callbacks {
int (*yesDialog)(char *msg);
int crypt_isLuks(struct crypt_options *options);
int crypt_luksDump(struct crypt_options *options);
-void crypt_get_error(char *buf, size_t size);
void crypt_put_options(struct crypt_options *options);
-const char *crypt_get_dir(void);
#ifdef __cplusplus
}
#include "internal.h"
struct crypt_device {
+ char *type;
+
+ char *device;
+ struct luks_masterkey *volume_key;
+ uint64_t timeout;
+ uint64_t iteration_time;
+ int tries;
+ int password_verify;
+
+ /* used in CRYPT_LUKS1 */
+ struct luks_phdr hdr;
+ uint64_t PBKDF2_per_sec;
+
+ /* used in CRYPT_PLAIN */
+ struct crypt_params_plain plain_hdr;
+ char *plain_cipher;
+ char *plain_cipher_mode;
+ char *plain_uuid;
+
/* callbacks definitions */
void (*log)(int class, const char *msg, void *usrptr);
void *log_usrptr;
+ int (*confirm)(const char *msg, void *usrptr);
+ void *confirm_usrptr;
+ int (*password)(const char *msg, char *buf, size_t length, void *usrptr);
+ void *password_usrptr;
};
/* Log helper */
free(target);
}
-static void hexprintICB(struct crypt_device *cd, char *d, int n)
-{
- int i;
- for(i = 0; i < n; i++)
- log_std(cd, "%02hhx ", (char)d[i]);
-}
-
/*
* Password processing behaviour matrix of process_key
*
#undef xstr
}
+static int isPLAIN(const char *type)
+{
+ return (type && !strcmp(CRYPT_PLAIN, type));
+}
+
+static int isLUKS(const char *type)
+{
+ return (type && !strcmp(CRYPT_LUKS1, type));
+}
+
/* keyslot helpers */
+static int keyslot_verify_or_find_empty(struct crypt_device *cd, int *keyslot)
+{
+ if (*keyslot == CRYPT_ANY_SLOT) {
+ *keyslot = LUKS_keyslot_find_empty(&cd->hdr);
+ if (*keyslot < 0) {
+ log_err(cd, _("All key slots full.\n"));
+ return -EINVAL;
+ }
+ }
+
+ switch (LUKS_keyslot_info(&cd->hdr, *keyslot)) {
+ case SLOT_INVALID:
+ log_err(cd, _("Key slot %d is invalid, please select between 0 and %d.\n"),
+ *keyslot, LUKS_NUMKEYS - 1);
+ return -EINVAL;
+ case SLOT_INACTIVE:
+ break;
+ default:
+ log_err(cd, _("Key slot %d is full, please select another one.\n"),
+ *keyslot);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int keyslot_is_valid(struct crypt_device *cd, int keySlotIndex)
{
if(keySlotIndex >= LUKS_NUMKEYS || keySlotIndex < 0) {
return 0;
}
-static int create_device_helper(int reload, struct crypt_options *options)
+static int create_device_helper_old(int reload, struct crypt_options *options)
{
struct crypt_device *cd = NULL;
char *key = NULL;
return r;
}
-static int luks_remove_helper(struct crypt_device *cd,
+static int luks_remove_helper_old(struct crypt_device *cd,
struct crypt_options *options, int supply_it)
{
struct luks_masterkey *mk;
return r;
}
+static int create_device_helper(struct crypt_device *cd,
+ const char *name,
+ const char *hash,
+ const char *cipher,
+ const char *cipher_mode,
+ const char *key_file,
+ const char *key,
+ unsigned int keyLen,
+ int key_size,
+ uint64_t size,
+ uint64_t skip,
+ uint64_t offset,
+ const char *uuid,
+ int read_only,
+ unsigned int flags,
+ int reload)
+{
+ crypt_status_info ci;
+ char *dm_cipher = NULL;
+ char *processed_key = NULL;
+ int r;
+
+ ci = crypt_status(cd, name);
+ if (ci == INVALID)
+ return -EINVAL;
+
+ if (reload && ci < ACTIVE)
+ return -EINVAL;
+
+ if (!reload && ci >= ACTIVE) {
+ log_err(cd, _("Device %s already exists.\n"), name);
+ return -EEXIST;
+ }
+
+ if (key_size < 0 || key_size > 1024) {
+ log_err(cd, _("Invalid key size %d.\n"), key_size);
+ return -EINVAL;
+ }
+
+ r = device_check_and_adjust(cd, cd->device, &size, &offset, &read_only);
+ if (r)
+ return r;
+
+ if (cipher_mode && asprintf(&dm_cipher, "%s-%s", cipher, cipher_mode) < 0)
+ return -ENOMEM;
+
+ processed_key = process_key(cd, hash, key_file, key_size, key, keyLen);
+ if (!processed_key)
+ return -ENOENT;
+
+ r = dm_create_device(name, cd->device, dm_cipher ?: cipher, uuid, size, skip, offset,
+ key_size, processed_key, read_only, reload);
+
+ free(dm_cipher);
+ safe_free(processed_key);
+ return r;
+}
+
+static int open_from_hdr_and_mk(struct crypt_device *cd,
+ struct luks_masterkey *mk,
+ const char *name,
+ uint32_t flags)
+{
+ uint64_t size, offset;
+ char *cipher;
+ int read_only, no_uuid, r;
+
+ size = 0;
+ offset = crypt_get_data_offset(cd);
+ read_only = flags & CRYPT_ACTIVATE_READONLY;
+ no_uuid = flags & CRYPT_ACTIVATE_NO_UUID;
+
+ r = device_check_and_adjust(cd, cd->device, &size, &offset, &read_only);
+ if (r)
+ return r;
+
+ if (asprintf(&cipher, "%s-%s", crypt_get_cipher(cd),
+ crypt_get_cipher_mode(cd)) < 0)
+ r = -ENOMEM;
+ else
+ r = dm_create_device(name, cd->device, cipher, no_uuid ? NULL : crypt_get_uuid(cd),
+ size, 0, offset, mk->keyLength, mk->key,
+ read_only, 0);
+ free(cipher);
+ return r;
+}
+
+static void key_from_terminal(struct crypt_device *cd, char *msg, char **key,
+ unsigned int *key_len, int force_verify)
+{
+ int r, flags = 0;
+
+ if (cd->password) {
+ *key = safe_alloc(MAX_TTY_PASSWORD_LEN);
+ if (*key)
+ return;
+ r = cd->password(msg, *key, (size_t)key_len, cd->password_usrptr);
+ if (r < 0) {
+ safe_free(*key);
+ *key = NULL;
+ } else
+ *key_len = r;
+ } else {
+ if (force_verify || cd->password_verify)
+ flags |= CRYPT_FLAG_VERIFY_IF_POSSIBLE;
+ get_key(msg, key, key_len, 0, NULL, cd->timeout, flags, cd);
+ }
+}
+
+static void key_from_file(struct crypt_device *cd, char *msg,
+ char **key, unsigned int *key_len,
+ const char *key_file, size_t key_size)
+{
+ get_key(msg, key, key_len, key_size, key_file, cd->timeout, 0, cd);
+}
+
+void crypt_set_log_callback(struct crypt_device *cd,
+ void (*log)(int class, const char *msg, void *usrptr),
+ void *usrptr)
+{
+ cd->log = log;
+ cd->log_usrptr = usrptr;
+}
+
+void crypt_set_confirm_callback(struct crypt_device *cd,
+ int (*confirm)(const char *msg, void *usrptr),
+ void *usrptr)
+{
+ cd->confirm = confirm;
+ cd->confirm_usrptr = usrptr;
+}
+
+void crypt_set_password_callback(struct crypt_device *cd,
+ int (*password)(const char *msg, char *buf, size_t length, void *usrptr),
+ void *usrptr)
+{
+ cd->password = password;
+ cd->password_usrptr = usrptr;
+}
+
/* OPTIONS: name, cipher, device, hash, key_file, key_size, key_slot,
* offset, size, skip, timeout, tries, passphrase_fd (ignored),
* flags, icb */
int crypt_create_device(struct crypt_options *options)
{
- return create_device_helper(0, options);
+ return create_device_helper_old(0, options);
}
/* OPTIONS: same as create above */
int crypt_update_device(struct crypt_options *options)
{
- return create_device_helper(1, options);
+ return create_device_helper_old(1, options);
}
/* OPTIONS: name, size, icb */
/* OPTIONS: device, keys_slot, key_file, timeout, flags, icb */
int crypt_luksKillSlot(struct crypt_options *options)
{
- return luks_remove_helper(NULL, options, 0);
+ return luks_remove_helper_old(NULL, options, 0);
}
/* OPTIONS: device, new_key_file, key_file, timeout, flags, icb */
int crypt_luksRemoveKey(struct crypt_options *options)
{
- return luks_remove_helper(NULL, options, 1);
+ return luks_remove_helper_old(NULL, options, 1);
}
/* OPTIONS: device, new_key_file, key_file, key_slot, flags,
}
/* OPTIONS: device, icb */
+static void hexprintICB(struct crypt_device *cd, char *d, int n);
int crypt_luksDump(struct crypt_options *options)
{
struct crypt_device *cd = NULL;
{
return dm_get_dir();
}
+
+/////////////////////////////////
+//
+// New API
+//
+
+int crypt_init(struct crypt_device **cd, const char *device)
+{
+ struct crypt_device *h = NULL;
+
+ if (!cd)
+ return -EINVAL;
+
+ log_dbg("Allocating crypt device %s context.", device);
+
+ if (!device_ready(NULL, device, 0))
+ return -ENOTBLK;
+
+ if (!(h = malloc(sizeof(struct crypt_device))))
+ return -ENOMEM;
+
+ memset(h, 0, sizeof(*h));
+
+ h->device = strdup(device);
+ if (!h->device) {
+ free(h);
+ return -ENOMEM;
+ }
+
+ if (!dm_init(h, 1) < 0) {
+ free(h);
+ return -ENOSYS;
+ }
+
+ h->iteration_time = 1000;
+ h->password_verify = 0;
+ h->tries = 3;
+ *cd = h;
+ return 0;
+}
+
+static int _crypt_format_plain(struct crypt_device *cd,
+ const char *cipher,
+ const char *cipher_mode,
+ const char *uuid,
+ struct crypt_params_plain *params)
+{
+ if (!cipher || !cipher_mode || !params || !params->hash) {
+ log_err(cd, _("Invalid plain crypt parameters.\n"));
+ return -EINVAL;
+ }
+
+ if (cd->volume_key->keyLength > 1024) {
+ log_err(cd, _("Invalid key size.\n"));
+ return -EINVAL;
+ }
+
+ cd->plain_cipher = strdup(cipher);
+ cd->plain_cipher_mode = strdup(cipher_mode);
+
+ if (uuid)
+ cd->plain_uuid = strdup(uuid);
+
+ if (params->hash)
+ cd->plain_hdr.hash = strdup(params->hash);
+
+ cd->plain_hdr.offset = params->offset;
+ cd->plain_hdr.skip = params->skip;
+
+ if ((params->hash && !cd->plain_hdr.hash) ||
+ !cd->plain_cipher || !cd->plain_cipher_mode)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int _crypt_format_luks1(struct crypt_device *cd,
+ const char *cipher,
+ const char *cipher_mode,
+ const char *uuid,
+ struct crypt_params_luks1 *params)
+{
+ int r;
+
+ r = LUKS_generate_phdr(&cd->hdr, cd->volume_key, cipher, cipher_mode,
+ (params && params->hash) ? params->hash : "sha1",
+ uuid, LUKS_STRIPES,
+ params ? params->data_alignment: DEFAULT_ALIGNMENT, cd);
+ if(r < 0)
+ return r;
+
+ /* Wipe first 8 sectors - fs magic numbers etc. */
+ r = wipe_device_header(cd->device, 8);
+ if(r < 0) {
+ log_err(cd, _("Can't wipe header on device %s.\n"), cd->device);
+ return r;
+ }
+
+ r = LUKS_write_phdr(cd->device, &cd->hdr, cd);
+
+ return r;
+}
+
+int crypt_format(struct crypt_device *cd,
+ const char *type,
+ const char *cipher,
+ const char *cipher_mode,
+ const char *uuid,
+ const char *volume_key,
+ size_t volume_key_size,
+ void *params)
+{
+ int r;
+
+ log_dbg("Formatting device %s as type %s.", cd->device, cd->type ?: "(none)");
+
+ if (!type)
+ return -EINVAL;
+
+ if (volume_key)
+ cd->volume_key = LUKS_alloc_masterkey(volume_key_size,
+ volume_key);
+ else
+ cd->volume_key = LUKS_generate_masterkey(volume_key_size);
+
+ if(!cd->volume_key)
+ return -ENOMEM;
+
+ if (isPLAIN(type))
+ r = _crypt_format_plain(cd, cipher, cipher_mode,
+ uuid, params);
+ else if (isLUKS(type))
+ r = _crypt_format_luks1(cd, cipher, cipher_mode,
+ uuid, params);
+ else {
+ /* FIXME: allow plugins here? */
+ log_err(cd, _("Unkown crypt device type %s requesed.\n"), type);
+ r = -EINVAL;
+ }
+
+ if (!r && !(cd->type = strdup(type)))
+ r = -ENOMEM;
+
+ if (r < 0) {
+ LUKS_dealloc_masterkey(cd->volume_key);
+ cd->volume_key = NULL;
+ }
+
+ return r;
+}
+
+int crypt_load(struct crypt_device *cd,
+ const char *requested_type,
+ void *params)
+{
+ struct luks_phdr hdr;
+ int r;
+
+ log_dbg("Trying to load %s crypt type from device %s.",
+ requested_type ?: "any", cd->device);
+
+ if (requested_type && !isPLAIN(requested_type) && !isLUKS(requested_type))
+ return -EINVAL;
+
+ r = LUKS_read_phdr(cd->device, &hdr, 0, cd);
+
+ if (!r) {
+ memcpy(&cd->hdr, &hdr, sizeof(hdr));
+ cd->type = strdup(requested_type);
+ if (!cd->type)
+ r = -ENOMEM;
+ }
+
+ return r;
+}
+
+void crypt_free(struct crypt_device *cd)
+{
+ if (cd) {
+ log_dbg("Releasing crypt device %s context.", cd->device);
+
+ dm_exit();
+ if (cd->volume_key)
+ LUKS_dealloc_masterkey(cd->volume_key);
+
+ free(cd->device);
+ free(cd->type);
+
+ /* used in plain device only */
+ free((char*)cd->plain_hdr.hash);
+ free(cd->plain_cipher);
+ free(cd->plain_cipher_mode);
+ free(cd->plain_uuid);
+
+ free(cd);
+ }
+}
+
+// slot manipulation
+int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
+ int keyslot, // -1 any
+ const char *passphrase, // NULL -> terminal
+ size_t passphrase_size,
+ const char *new_passphrase, // NULL -> terminal
+ size_t new_passphrase_size)
+{
+ struct luks_masterkey *mk = NULL;
+ char *password = NULL, *new_password = NULL;
+ unsigned int passwordLen, new_passwordLen;
+ int r;
+
+ log_dbg("Adding new keyslot, existing passphrase %sprovided,"
+ "new passphrase %sprovided.",
+ passphrase ? "" : "not ", new_passphrase ? "" : "not ");
+
+ if (!isLUKS(cd->type)) {
+ log_err(cd, _("This operation is supported only for LUKS device.\n"));
+ return -EINVAL;
+ }
+
+ r = keyslot_verify_or_find_empty(cd, &keyslot);
+ if (r)
+ return r;
+
+ if (!LUKS_keyslot_active_count(&cd->hdr)) {
+ /* No slots used, try to use pre-generated key in header */
+ if (cd->volume_key) {
+ mk = LUKS_alloc_masterkey(cd->volume_key->keyLength, cd->volume_key->key);
+ r = mk ? 0 : -ENOMEM;
+ } else {
+ log_err(cd, _("Cannot add key slot, all slots disabled and no volume key provided.\n"));
+ return -EINVAL;
+ }
+ } else if (passphrase) {
+ /* Passphrase provided, use it to unlock existing keyslot */
+ r = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT, passphrase,
+ passphrase_size, &cd->hdr, &mk, cd);
+ } else {
+ /* Passphrase not provided, ask first and use it to unlock existing keyslot */
+ key_from_terminal(cd, _("Enter any passphrase: "),
+ &password, &passwordLen, 0);
+ if (!password) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ r = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT, password,
+ passwordLen, &cd->hdr, &mk, cd);
+ safe_free(password);
+ }
+
+ if(r < 0)
+ goto out;
+
+ if (new_passphrase) {
+ new_password = (char *)new_passphrase;
+ new_passwordLen = new_passphrase_size;
+ } else {
+ key_from_terminal(cd, _("Enter new passphrase for key slot: "),
+ &new_password, &new_passwordLen, 1);
+ if(!new_password) {
+ r = -EINVAL;
+ goto out;
+ }
+ }
+
+ r = LUKS_set_key(cd->device, keyslot, new_password, new_passwordLen,
+ &cd->hdr, mk, cd->iteration_time, &cd->PBKDF2_per_sec, cd);
+ if(r < 0) goto out;
+
+ r = 0;
+out:
+ if (!new_passphrase)
+ safe_free(new_password);
+ LUKS_dealloc_masterkey(mk);
+ return r ?: keyslot;
+}
+
+int crypt_keyslot_add_by_keyfile(struct crypt_device *cd,
+ int keyslot,
+ const char *keyfile,
+ size_t keyfile_size,
+ const char *new_keyfile,
+ size_t new_keyfile_size)
+{
+ struct luks_masterkey *mk=NULL;
+ char *password=NULL; unsigned int passwordLen;
+ char *new_password = NULL; unsigned int new_passwordLen;
+ int r;
+
+ log_dbg("Adding new keyslot, existing keyfile %s, new keyfile %s.",
+ keyfile ?: "[none]", new_keyfile ?: "[none]");
+
+ if (!isLUKS(cd->type)) {
+ log_err(cd, _("This operation is supported only for LUKS device.\n"));
+ return -EINVAL;
+ }
+
+ r = keyslot_verify_or_find_empty(cd, &keyslot);
+ if (r)
+ return r;
+
+ if (!LUKS_keyslot_active_count(&cd->hdr)) {
+ /* No slots used, try to use pre-generated key in header */
+ if (cd->volume_key) {
+ mk = LUKS_alloc_masterkey(cd->volume_key->keyLength, cd->volume_key->key);
+ r = mk ? 0 : -ENOMEM;
+ } else {
+ log_err(cd, _("Cannot add key slot, all slots disabled and no volume key provided.\n"));
+ return -EINVAL;
+ }
+ } else {
+ /* Read password from file of (if NULL) from terminal */
+ if (keyfile)
+ key_from_file(cd, _("Enter any passphrase: "), &password, &passwordLen,
+ keyfile, keyfile_size);
+ else
+ key_from_terminal(cd, _("Enter any passphrase: "),
+ &password, &passwordLen, 1);
+
+ if (!password)
+ return -EINVAL;
+
+ r = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT, password, passwordLen,
+ &cd->hdr, &mk, cd);
+ safe_free(password);
+ }
+
+ if(r < 0)
+ goto out;
+
+ if (new_keyfile)
+ key_from_file(cd, _("Enter new passphrase for key slot: "),
+ &new_password, &new_passwordLen, new_keyfile,
+ new_keyfile_size);
+ else
+ key_from_terminal(cd, _("Enter new passphrase for key slot: "),
+ &new_password, &new_passwordLen, 1);
+
+ if(!new_password) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ r = LUKS_set_key(cd->device, keyslot, new_password, new_passwordLen,
+ &cd->hdr, mk, cd->iteration_time, &cd->PBKDF2_per_sec, cd);
+out:
+ safe_free(new_password);
+ LUKS_dealloc_masterkey(mk);
+ return r < 0 ? r : keyslot;
+}
+
+int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
+ int keyslot,
+ const char *volume_key,
+ size_t volume_key_size,
+ const char *passphrase,
+ size_t passphrase_size
+)
+{
+ struct luks_masterkey *mk;
+ int r = -EINVAL;
+ char *new_password = NULL; unsigned int new_passwordLen;
+
+ log_dbg("Adding new keyslot %d using volume key.", keyslot);
+
+ if (!isLUKS(cd->type)) {
+ log_err(cd, _("This operation is supported only for LUKS device.\n"));
+ return -EINVAL;
+ }
+
+ if (volume_key)
+ mk = LUKS_alloc_masterkey(volume_key_size, volume_key);
+ else if (cd->volume_key)
+ mk = LUKS_alloc_masterkey(cd->volume_key->keyLength, cd->volume_key->key);
+
+ if (!mk)
+ return -ENOMEM;
+
+ r = LUKS_verify_master_key(&cd->hdr, mk);
+ if (r < 0) {
+ log_err(cd, _("Volume key does not match the volume.\n"));
+ goto out;
+ }
+
+ r = keyslot_verify_or_find_empty(cd, &keyslot);
+ if (r)
+ goto out;
+
+ if (!passphrase) {
+ key_from_terminal(cd, _("Enter new passphrase for key slot: "),
+ &new_password, &new_passwordLen, 1);
+ passphrase = new_password;
+ passphrase_size = new_passwordLen;
+ }
+
+ r = LUKS_set_key(cd->device, keyslot, passphrase, passphrase_size,
+ &cd->hdr, mk, cd->iteration_time, &cd->PBKDF2_per_sec, cd);
+out:
+ if (new_password)
+ safe_free(new_password);
+ LUKS_dealloc_masterkey(mk);
+ return r ?: keyslot;
+}
+
+int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot)
+{
+ crypt_keyslot_info ki;
+
+ log_dbg("Destroying keyslot %d.", keyslot);
+
+ if (!isLUKS(cd->type)) {
+ log_err(cd, _("This operation is supported only for LUKS device.\n"));
+ return -EINVAL;
+ }
+
+ ki = crypt_keyslot_status(cd, keyslot);
+ if (ki == SLOT_INVALID)
+ return -EINVAL;
+
+ if (ki == SLOT_INACTIVE)
+ return 0;
+
+ return LUKS_del_key(cd->device, keyslot, cd);
+}
+
+// activation/deactivation of device mapping
+int crypt_activate_by_passphrase(struct crypt_device *cd,
+ const char *name,
+ int keyslot,
+ const char *passphrase,
+ size_t passphrase_size,
+ uint32_t flags)
+{
+ crypt_status_info ci;
+ struct luks_masterkey *mk = NULL;
+ char *prompt = NULL, *passphrase_read = NULL;
+ unsigned int passphrase_size_read;
+ int r, tries = cd->tries;
+
+ log_dbg("%s volume %s [keyslot %d] using %spassphrase.",
+ name ? "Activating" : "Checking", name ?: "",
+ keyslot, passphrase ? "" : "[none] ");
+
+ if (!name)
+ return -EINVAL;
+
+ /* plain, use hashed passphrase */
+ if (isPLAIN(cd->type))
+ return create_device_helper(cd, name, cd->plain_hdr.hash,
+ cd->plain_cipher, cd->plain_cipher_mode, NULL, passphrase, passphrase_size,
+ cd->volume_key->keyLength, 0, cd->plain_hdr.skip,
+ cd->plain_hdr.offset, cd->plain_uuid, flags & CRYPT_ACTIVATE_READONLY, 0, 0);
+
+ if (name) {
+ ci = crypt_status(NULL, name);
+ if (ci == INVALID)
+ return -EINVAL;
+ else if (ci >= ACTIVE) {
+ log_err(cd, _("Device %s already exists.\n"), name);
+ return -EEXIST;
+ }
+ }
+
+ if(asprintf(&prompt, _("Enter passphrase for %s: "), cd->device) < 0)
+ return -ENOMEM;
+
+ /* provided passphrase, do not retry */
+ if (passphrase) {
+ r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase,
+ passphrase_size, &cd->hdr, &mk, cd);
+ } else do {
+ if (mk)
+ LUKS_dealloc_masterkey(mk);
+ mk = NULL;
+
+ key_from_terminal(cd, prompt, &passphrase_read,
+ &passphrase_size_read, 0);
+ if(!passphrase_read) {
+ r = -EINVAL;
+ break;
+ }
+
+ r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase_read,
+ passphrase_size_read, &cd->hdr, &mk, cd);
+ safe_free(passphrase_read);
+ passphrase_read = NULL;
+ } while (r == -EPERM && (--tries > 0));
+
+ if (r >= 0) {
+ keyslot = r;
+ if (name)
+ r = open_from_hdr_and_mk(cd, mk, name, flags);
+ }
+
+ LUKS_dealloc_masterkey(mk);
+ free(prompt);
+
+ return r < 0 ? r : keyslot;
+}
+
+int crypt_activate_by_keyfile(struct crypt_device *cd,
+ const char *name,
+ int keyslot,
+ const char *keyfile,
+ size_t keyfile_size,
+ uint32_t flags)
+{
+ crypt_status_info ci;
+ struct luks_masterkey *mk = NULL;
+ char *passphrase_read = NULL;
+ unsigned int passphrase_size_read;
+ int r;
+
+ log_dbg("Activating volume %s [keyslot %d] using keyfile %s.",
+ name, keyslot, keyfile ?: "[none]");
+
+ if (!isLUKS(cd->type)) {
+ log_err(cd, _("This operation is supported only for LUKS device.\n"));
+ return -EINVAL;
+ }
+
+ if (name) {
+ ci = crypt_status(NULL, name);
+ if (ci == INVALID)
+ return -EINVAL;
+ else if (ci >= ACTIVE) {
+ log_err(cd, _("Device %s already exists.\n"), name);
+ return -EEXIST;
+ }
+ }
+
+ if (!keyfile)
+ return -EINVAL;
+
+ key_from_file(cd, _("Enter passphrase: "), &passphrase_read,
+ &passphrase_size_read, keyfile, keyfile_size);
+ if(!passphrase_read)
+ r = -EINVAL;
+ else {
+ r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase_read,
+ passphrase_size_read, &cd->hdr, &mk, cd);
+ safe_free(passphrase_read);
+ }
+
+ if (r >= 0) {
+ keyslot = r;
+ r = open_from_hdr_and_mk(cd, mk, name, flags);
+ }
+
+ LUKS_dealloc_masterkey(mk);
+
+ return r < 0 ? r : keyslot;
+}
+
+int crypt_activate_by_volume_key(struct crypt_device *cd,
+ const char *name,
+ const char *volume_key,
+ size_t volume_key_size,
+ uint32_t flags)
+{
+ crypt_status_info ci;
+ struct luks_masterkey *mk;
+ int r;
+
+ log_dbg("Activating volume %s by volume key.", name);
+
+ /* use key directly, no hash */
+ if (isPLAIN(cd->type))
+ return create_device_helper(cd, name, NULL,
+ cd->plain_cipher, cd->plain_cipher_mode, NULL, volume_key, volume_key_size,
+ cd->volume_key->keyLength, 0, cd->plain_hdr.skip,
+ cd->plain_hdr.offset, cd->plain_uuid, flags & CRYPT_ACTIVATE_READONLY, 0, 0);
+
+ if (!isLUKS(cd->type)) {
+ log_err(cd, _("This operation is supported only for LUKS device.\n"));
+ return -EINVAL;
+ }
+
+ if (name) {
+ ci = crypt_status(NULL, name);
+ if (ci == INVALID)
+ return -EINVAL;
+ else if (ci >= ACTIVE) {
+ log_err(cd, _("Device %s already exists.\n"), name);
+ return -EEXIST;
+ }
+ }
+
+ mk = LUKS_alloc_masterkey(volume_key_size, volume_key);
+ if (!mk)
+ return -ENOMEM;
+ r = LUKS_verify_master_key(&cd->hdr, mk);
+
+ if (r == -EPERM)
+ log_err(cd, _("Volume key does not match the volume.\n"));
+
+ if (!r && name)
+ r = open_from_hdr_and_mk(cd, mk, name, flags);
+
+ LUKS_dealloc_masterkey(mk);
+
+ return r;
+}
+
+int crypt_deactivate(struct crypt_device *cd, const char *name)
+{
+ if (!name)
+ return -EINVAL;
+
+ log_dbg("Deactivating volume %s.", name);
+
+ switch (crypt_status(cd, name)) {
+ case ACTIVE: return dm_remove_device(name, 0, 0);
+ case BUSY: log_err(cd, _("Device %s is busy."), name);
+ return -EBUSY;
+ case INACTIVE: return -ENODEV;
+ default: log_err(cd, _("Invalid device %s."), name);
+ return -EINVAL;
+ }
+}
+
+// misc helper functions
+int crypt_volume_key_get(struct crypt_device *cd,
+ int keyslot,
+ char *volume_key,
+ size_t *volume_key_size,
+ const char *passphrase,
+ size_t passphrase_size)
+{
+ struct luks_masterkey *mk;
+ char *processed_key = NULL;
+ int r, key_len;
+
+ key_len = crypt_get_volume_key_size(cd);
+ if (key_len > *volume_key_size) {
+ log_err(cd, _("Volume key buffer too small.\n"));
+ return -ENOMEM;
+ }
+
+ if (isPLAIN(cd->type)) {
+ processed_key = process_key(cd, cd->plain_hdr.hash, NULL, key_len,
+ passphrase, passphrase_size);
+ if (!processed_key) {
+ log_err(cd, _("Cannot retrieve volume key for plain device.\n"));
+ return -EINVAL;
+ }
+ memcpy(volume_key, processed_key, key_len);
+ *volume_key_size = key_len;
+ safe_free(processed_key);
+ return 0;
+ }
+
+ if (isLUKS(cd->type)) {
+ r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase,
+ passphrase_size, &cd->hdr, &mk, cd);
+
+ if (r >= 0) {
+ memcpy(volume_key, mk->key, mk->keyLength);
+ *volume_key_size = mk->keyLength;
+ }
+
+ LUKS_dealloc_masterkey(mk);
+ return r;
+ }
+
+ log_err(cd, _("This operation is not supported for %s crypt device.\n"), cd->type ?: "(none)");
+ return -EINVAL;
+}
+
+int crypt_volume_key_verify(struct crypt_device *cd,
+ const char *volume_key,
+ size_t volume_key_size)
+{
+ struct luks_masterkey *mk;
+ int r;
+
+ if (!isLUKS(cd->type)) {
+ log_err(cd, _("This operation is supported only for LUKS device.\n"));
+ return -EINVAL;
+ }
+
+ mk = LUKS_alloc_masterkey(volume_key_size, volume_key);
+ if (!mk)
+ return -ENOMEM;
+
+ r = LUKS_verify_master_key(&cd->hdr, mk);
+
+ if (r == -EPERM)
+ log_err(cd, _("Volume key does not match the volume.\n"));
+
+ LUKS_dealloc_masterkey(mk);
+
+ return r;
+}
+
+void crypt_set_timeout(struct crypt_device *cd, uint64_t timeout_sec)
+{
+ log_dbg("Timeout set to %" PRIu64 " miliseconds.", timeout_sec);
+ cd->timeout = timeout_sec;
+}
+
+void crypt_set_password_retry(struct crypt_device *cd, int tries)
+{
+ log_dbg("Password retry count set to %d.", tries);
+ cd->tries = tries;
+}
+
+void crypt_set_iterarion_time(struct crypt_device *cd, uint64_t iteration_time_ms)
+{
+ log_dbg("Iteration time set to %" PRIu64 " miliseconds.", iteration_time_ms);
+ cd->iteration_time = iteration_time_ms;
+}
+
+void crypt_set_password_verify(struct crypt_device *cd, int password_verify)
+{
+ log_dbg("Password verification %s.", password_verify ? "enabled" : "disabled");
+ cd->password_verify = password_verify ? 1 : 0;
+}
+
+int crypt_memory_lock(struct crypt_device *cd, int lock)
+{
+ return lock ? memlock_inc(cd) : memlock_dec(cd);
+}
+
+// reporting
+crypt_status_info crypt_status(struct crypt_device *cd, const char *name)
+{
+ int r;
+
+ r = dm_status_device(name);
+
+ if (r < 0 && r != -ENODEV)
+ return INVALID;
+
+ if (r == 0)
+ return ACTIVE;
+
+ if (r > 0)
+ return BUSY;
+
+ return INACTIVE;
+}
+
+static void hexprintICB(struct crypt_device *cd, char *d, int n)
+{
+ int i;
+ for(i = 0; i < n; i++)
+ log_std(cd, "%02hhx ", (char)d[i]);
+}
+
+int crypt_dump(struct crypt_device *cd)
+{
+ int i;
+ if (!isLUKS(cd->type)) { //FIXME
+ log_err(cd, _("This operation is supported only for LUKS device.\n"));
+ return -EINVAL;
+ }
+
+ log_std(cd, "LUKS header information for %s\n\n", cd->device);
+ log_std(cd, "Version: \t%d\n", cd->hdr.version);
+ log_std(cd, "Cipher name: \t%s\n", cd->hdr.cipherName);
+ log_std(cd, "Cipher mode: \t%s\n", cd->hdr.cipherMode);
+ log_std(cd, "Hash spec: \t%s\n", cd->hdr.hashSpec);
+ log_std(cd, "Payload offset:\t%d\n", cd->hdr.payloadOffset);
+ log_std(cd, "MK bits: \t%d\n", cd->hdr.keyBytes * 8);
+ log_std(cd, "MK digest: \t");
+ hexprintICB(cd, cd->hdr.mkDigest, LUKS_DIGESTSIZE);
+ log_std(cd, "\n");
+ log_std(cd, "MK salt: \t");
+ hexprintICB(cd, cd->hdr.mkDigestSalt, LUKS_SALTSIZE/2);
+ log_std(cd, "\n \t");
+ hexprintICB(cd, cd->hdr.mkDigestSalt+LUKS_SALTSIZE/2, LUKS_SALTSIZE/2);
+ log_std(cd, "\n");
+ log_std(cd, "MK iterations: \t%d\n", cd->hdr.mkDigestIterations);
+ log_std(cd, "UUID: \t%s\n\n", cd->hdr.uuid);
+ for(i = 0; i < LUKS_NUMKEYS; i++) {
+ if(cd->hdr.keyblock[i].active == LUKS_KEY_ENABLED) {
+ log_std(cd, "Key Slot %d: ENABLED\n",i);
+ log_std(cd, "\tIterations: \t%d\n",
+ cd->hdr.keyblock[i].passwordIterations);
+ log_std(cd, "\tSalt: \t");
+ hexprintICB(cd, cd->hdr.keyblock[i].passwordSalt,
+ LUKS_SALTSIZE/2);
+ log_std(cd, "\n\t \t");
+ hexprintICB(cd, cd->hdr.keyblock[i].passwordSalt +
+ LUKS_SALTSIZE/2, LUKS_SALTSIZE/2);
+ log_std(cd, "\n");
+
+ log_std(cd, "\tKey material offset:\t%d\n",
+ cd->hdr.keyblock[i].keyMaterialOffset);
+ log_std(cd, "\tAF stripes: \t%d\n",
+ cd->hdr.keyblock[i].stripes);
+ }
+ else
+ log_std(cd, "Key Slot %d: DISABLED\n", i);
+ }
+ return 0;
+}
+
+const char *crypt_get_cipher(struct crypt_device *cd)
+{
+ if (isPLAIN(cd->type))
+ return cd->plain_cipher;
+
+ if (isLUKS(cd->type))
+ return cd->hdr.cipherName;
+
+ return NULL;
+}
+
+const char *crypt_get_cipher_mode(struct crypt_device *cd)
+{
+ if (isPLAIN(cd->type))
+ return cd->plain_cipher_mode;
+
+ if (isLUKS(cd->type))
+ return cd->hdr.cipherMode;
+
+ return NULL;
+}
+
+const char *crypt_get_uuid(struct crypt_device *cd)
+{
+ if (isLUKS(cd->type))
+ return cd->hdr.uuid;
+
+ return NULL;
+}
+
+int crypt_get_volume_key_size(struct crypt_device *cd)
+{
+ if (isPLAIN(cd->type))
+ return cd->volume_key->keyLength;
+
+ if (isLUKS(cd->type))
+ return cd->hdr.keyBytes;
+
+ return 0;
+}
+
+uint64_t crypt_get_data_offset(struct crypt_device *cd)
+{
+ if (isPLAIN(cd->type))
+ return cd->plain_hdr.offset;
+
+ if (isLUKS(cd->type))
+ return cd->hdr.payloadOffset;
+
+ return 0;
+}
+
+crypt_keyslot_info crypt_keyslot_status(struct crypt_device *cd, int keyslot)
+{
+ if (!isLUKS(cd->type)) {
+ log_err(cd, _("This operation is supported only for LUKS device.\n"));
+ return SLOT_INVALID;
+ }
+
+ return LUKS_keyslot_info(&cd->hdr, keyslot);
+}