186d7f5d3SJohn Marino #include <string.h>
286d7f5d3SJohn Marino #include <stdio.h>
386d7f5d3SJohn Marino #include <stdlib.h>
486d7f5d3SJohn Marino #include <stdarg.h>
586d7f5d3SJohn Marino #include <fcntl.h>
686d7f5d3SJohn Marino #include <errno.h>
786d7f5d3SJohn Marino
886d7f5d3SJohn Marino #include "libcryptsetup.h"
986d7f5d3SJohn Marino #include "luks.h"
1086d7f5d3SJohn Marino #include "internal.h"
1186d7f5d3SJohn Marino
1286d7f5d3SJohn Marino struct crypt_device {
1386d7f5d3SJohn Marino char *type;
1486d7f5d3SJohn Marino
1586d7f5d3SJohn Marino char *device;
1686d7f5d3SJohn Marino struct luks_masterkey *volume_key;
1786d7f5d3SJohn Marino uint64_t timeout;
1886d7f5d3SJohn Marino uint64_t iteration_time;
1986d7f5d3SJohn Marino int tries;
2086d7f5d3SJohn Marino int password_verify;
2186d7f5d3SJohn Marino
2286d7f5d3SJohn Marino /* used in CRYPT_LUKS1 */
2386d7f5d3SJohn Marino struct luks_phdr hdr;
2486d7f5d3SJohn Marino uint64_t PBKDF2_per_sec;
2586d7f5d3SJohn Marino
2686d7f5d3SJohn Marino /* used in CRYPT_PLAIN */
2786d7f5d3SJohn Marino struct crypt_params_plain plain_hdr;
2886d7f5d3SJohn Marino char *plain_cipher;
2986d7f5d3SJohn Marino char *plain_cipher_mode;
3086d7f5d3SJohn Marino char *plain_uuid;
3186d7f5d3SJohn Marino
3286d7f5d3SJohn Marino /* callbacks definitions */
3386d7f5d3SJohn Marino void (*log)(int level, const char *msg, void *usrptr);
3486d7f5d3SJohn Marino void *log_usrptr;
3586d7f5d3SJohn Marino int (*confirm)(const char *msg, void *usrptr);
3686d7f5d3SJohn Marino void *confirm_usrptr;
3786d7f5d3SJohn Marino int (*password)(const char *msg, char *buf, size_t length, void *usrptr);
3886d7f5d3SJohn Marino void *password_usrptr;
3986d7f5d3SJohn Marino };
4086d7f5d3SJohn Marino
4186d7f5d3SJohn Marino /* Log helper */
4286d7f5d3SJohn Marino static void (*_default_log)(int level, const char *msg, void *usrptr) = NULL;
4386d7f5d3SJohn Marino static int _debug_level = 0;
4486d7f5d3SJohn Marino
crypt_set_debug_level(int level)4586d7f5d3SJohn Marino void crypt_set_debug_level(int level)
4686d7f5d3SJohn Marino {
4786d7f5d3SJohn Marino _debug_level = level;
4886d7f5d3SJohn Marino }
4986d7f5d3SJohn Marino
crypt_get_debug_level()5086d7f5d3SJohn Marino int crypt_get_debug_level()
5186d7f5d3SJohn Marino {
5286d7f5d3SJohn Marino return _debug_level;
5386d7f5d3SJohn Marino }
5486d7f5d3SJohn Marino
crypt_log(struct crypt_device * cd,int level,const char * msg)5586d7f5d3SJohn Marino void crypt_log(struct crypt_device *cd, int level, const char *msg)
5686d7f5d3SJohn Marino {
5786d7f5d3SJohn Marino if (cd && cd->log)
5886d7f5d3SJohn Marino cd->log(level, msg, cd->log_usrptr);
5986d7f5d3SJohn Marino else if (_default_log)
6086d7f5d3SJohn Marino _default_log(level, msg, NULL);
6186d7f5d3SJohn Marino }
6286d7f5d3SJohn Marino
logger(struct crypt_device * cd,int level,const char * file,int line,const char * format,...)6386d7f5d3SJohn Marino void logger(struct crypt_device *cd, int level, const char *file,
6486d7f5d3SJohn Marino int line, const char *format, ...)
6586d7f5d3SJohn Marino {
6686d7f5d3SJohn Marino va_list argp;
6786d7f5d3SJohn Marino char *target = NULL;
6886d7f5d3SJohn Marino
6986d7f5d3SJohn Marino va_start(argp, format);
7086d7f5d3SJohn Marino
7186d7f5d3SJohn Marino if (vasprintf(&target, format, argp) > 0) {
7286d7f5d3SJohn Marino if (level >= 0) {
7386d7f5d3SJohn Marino crypt_log(cd, level, target);
7486d7f5d3SJohn Marino #ifdef CRYPT_DEBUG
7586d7f5d3SJohn Marino } else if (_debug_level)
7686d7f5d3SJohn Marino printf("# %s:%d %s\n", file ?: "?", line, target);
7786d7f5d3SJohn Marino #else
7886d7f5d3SJohn Marino } else if (_debug_level)
7986d7f5d3SJohn Marino printf("# %s\n", target);
8086d7f5d3SJohn Marino #endif
8186d7f5d3SJohn Marino }
8286d7f5d3SJohn Marino
8386d7f5d3SJohn Marino va_end(argp);
8486d7f5d3SJohn Marino free(target);
8586d7f5d3SJohn Marino }
8686d7f5d3SJohn Marino
8786d7f5d3SJohn Marino /*
8886d7f5d3SJohn Marino * Password processing behaviour matrix of process_key
8986d7f5d3SJohn Marino *
9086d7f5d3SJohn Marino * from binary file: check if there is sufficently large key material
9186d7f5d3SJohn Marino * interactive & from fd: hash if requested, otherwise crop or pad with '0'
9286d7f5d3SJohn Marino */
process_key(struct crypt_device * cd,const char * hash_name,const char * key_file,size_t key_size,const char * pass,size_t passLen)9386d7f5d3SJohn Marino static char *process_key(struct crypt_device *cd, const char *hash_name,
9486d7f5d3SJohn Marino const char *key_file, size_t key_size,
9586d7f5d3SJohn Marino const char *pass, size_t passLen)
9686d7f5d3SJohn Marino {
9786d7f5d3SJohn Marino char *key = safe_alloc(key_size);
9886d7f5d3SJohn Marino memset(key, 0, key_size);
9986d7f5d3SJohn Marino
10086d7f5d3SJohn Marino /* key is coming from binary file */
10186d7f5d3SJohn Marino if (key_file && strcmp(key_file, "-")) {
10286d7f5d3SJohn Marino if(passLen < key_size) {
10386d7f5d3SJohn Marino log_err(cd, _("Cannot not read %d bytes from key file %s.\n"),
10486d7f5d3SJohn Marino key_size, key_file);
10586d7f5d3SJohn Marino safe_free(key);
10686d7f5d3SJohn Marino return NULL;
10786d7f5d3SJohn Marino }
10886d7f5d3SJohn Marino memcpy(key, pass, key_size);
10986d7f5d3SJohn Marino return key;
11086d7f5d3SJohn Marino }
11186d7f5d3SJohn Marino
11286d7f5d3SJohn Marino /* key is coming from tty, fd or binary stdin */
11386d7f5d3SJohn Marino if (hash_name) {
11486d7f5d3SJohn Marino if (hash(NULL, hash_name, key, key_size, pass, passLen) < 0) {
11586d7f5d3SJohn Marino log_err(cd, _("Key processing error (using hash algorithm %s).\n"),
11686d7f5d3SJohn Marino hash_name);
11786d7f5d3SJohn Marino safe_free(key);
11886d7f5d3SJohn Marino return NULL;
11986d7f5d3SJohn Marino }
12086d7f5d3SJohn Marino } else if (passLen > key_size) {
12186d7f5d3SJohn Marino memcpy(key, pass, key_size);
12286d7f5d3SJohn Marino } else {
12386d7f5d3SJohn Marino memcpy(key, pass, passLen);
12486d7f5d3SJohn Marino }
12586d7f5d3SJohn Marino
12686d7f5d3SJohn Marino return key;
12786d7f5d3SJohn Marino }
12886d7f5d3SJohn Marino
parse_into_name_and_mode(const char * nameAndMode,char * name,char * mode)12986d7f5d3SJohn Marino int parse_into_name_and_mode(const char *nameAndMode, char *name, char *mode)
13086d7f5d3SJohn Marino {
13186d7f5d3SJohn Marino /* Token content stringification, see info cpp/stringification */
13286d7f5d3SJohn Marino #define str(s) #s
13386d7f5d3SJohn Marino #define xstr(s) str(s)
13486d7f5d3SJohn Marino #define scanpattern1 "%" xstr(LUKS_CIPHERNAME_L) "[^-]-%" xstr(LUKS_CIPHERMODE_L) "s"
13586d7f5d3SJohn Marino #define scanpattern2 "%" xstr(LUKS_CIPHERNAME_L) "[^-]"
13686d7f5d3SJohn Marino
13786d7f5d3SJohn Marino int r;
13886d7f5d3SJohn Marino
13986d7f5d3SJohn Marino if(sscanf(nameAndMode,scanpattern1, name, mode) != 2) {
14086d7f5d3SJohn Marino if((r = sscanf(nameAndMode,scanpattern2,name)) == 1)
14186d7f5d3SJohn Marino strncpy(mode,"cbc-plain",10);
14286d7f5d3SJohn Marino else
14386d7f5d3SJohn Marino return -EINVAL;
14486d7f5d3SJohn Marino }
14586d7f5d3SJohn Marino
14686d7f5d3SJohn Marino return 0;
14786d7f5d3SJohn Marino
14886d7f5d3SJohn Marino #undef scanpattern1
14986d7f5d3SJohn Marino #undef scanpattern2
15086d7f5d3SJohn Marino #undef str
15186d7f5d3SJohn Marino #undef xstr
15286d7f5d3SJohn Marino }
15386d7f5d3SJohn Marino
isPLAIN(const char * type)15486d7f5d3SJohn Marino static int isPLAIN(const char *type)
15586d7f5d3SJohn Marino {
15686d7f5d3SJohn Marino return (type && !strcmp(CRYPT_PLAIN, type));
15786d7f5d3SJohn Marino }
15886d7f5d3SJohn Marino
isLUKS(const char * type)15986d7f5d3SJohn Marino static int isLUKS(const char *type)
16086d7f5d3SJohn Marino {
16186d7f5d3SJohn Marino return (type && !strcmp(CRYPT_LUKS1, type));
16286d7f5d3SJohn Marino }
16386d7f5d3SJohn Marino
16486d7f5d3SJohn Marino /* keyslot helpers */
keyslot_verify_or_find_empty(struct crypt_device * cd,int * keyslot)16586d7f5d3SJohn Marino static int keyslot_verify_or_find_empty(struct crypt_device *cd, int *keyslot)
16686d7f5d3SJohn Marino {
16786d7f5d3SJohn Marino if (*keyslot == CRYPT_ANY_SLOT) {
16886d7f5d3SJohn Marino *keyslot = LUKS_keyslot_find_empty(&cd->hdr);
16986d7f5d3SJohn Marino if (*keyslot < 0) {
17086d7f5d3SJohn Marino log_err(cd, _("All key slots full.\n"));
17186d7f5d3SJohn Marino return -EINVAL;
17286d7f5d3SJohn Marino }
17386d7f5d3SJohn Marino }
17486d7f5d3SJohn Marino
17586d7f5d3SJohn Marino switch (LUKS_keyslot_info(&cd->hdr, *keyslot)) {
17686d7f5d3SJohn Marino case CRYPT_SLOT_INVALID:
17786d7f5d3SJohn Marino log_err(cd, _("Key slot %d is invalid, please select between 0 and %d.\n"),
17886d7f5d3SJohn Marino *keyslot, LUKS_NUMKEYS - 1);
17986d7f5d3SJohn Marino return -EINVAL;
18086d7f5d3SJohn Marino case CRYPT_SLOT_INACTIVE:
18186d7f5d3SJohn Marino break;
18286d7f5d3SJohn Marino default:
18386d7f5d3SJohn Marino log_err(cd, _("Key slot %d is full, please select another one.\n"),
18486d7f5d3SJohn Marino *keyslot);
18586d7f5d3SJohn Marino return -EINVAL;
18686d7f5d3SJohn Marino }
18786d7f5d3SJohn Marino
18886d7f5d3SJohn Marino return 0;
18986d7f5d3SJohn Marino }
19086d7f5d3SJohn Marino
verify_other_keyslot(struct crypt_device * cd,const char * key_file,unsigned int flags,int keyIndex)19186d7f5d3SJohn Marino static int verify_other_keyslot(struct crypt_device *cd,
19286d7f5d3SJohn Marino const char *key_file,
19386d7f5d3SJohn Marino unsigned int flags,
19486d7f5d3SJohn Marino int keyIndex)
19586d7f5d3SJohn Marino {
19686d7f5d3SJohn Marino struct luks_masterkey *mk;
19786d7f5d3SJohn Marino crypt_keyslot_info ki;
19886d7f5d3SJohn Marino int openedIndex;
19986d7f5d3SJohn Marino char *password = NULL;
20086d7f5d3SJohn Marino unsigned int passwordLen;
20186d7f5d3SJohn Marino
20286d7f5d3SJohn Marino get_key(_("Enter any remaining LUKS passphrase: "), &password,
20386d7f5d3SJohn Marino &passwordLen, 0, key_file, cd->timeout, flags, cd);
20486d7f5d3SJohn Marino if(!password)
20586d7f5d3SJohn Marino return -EINVAL;
20686d7f5d3SJohn Marino
20786d7f5d3SJohn Marino ki = crypt_keyslot_status(cd, keyIndex);
20886d7f5d3SJohn Marino if (ki == CRYPT_SLOT_ACTIVE) /* Not last slot */
20986d7f5d3SJohn Marino LUKS_keyslot_set(&cd->hdr, keyIndex, 0);
21086d7f5d3SJohn Marino
21186d7f5d3SJohn Marino openedIndex = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT,
21286d7f5d3SJohn Marino password, passwordLen,
21386d7f5d3SJohn Marino &cd->hdr, &mk, cd);
21486d7f5d3SJohn Marino
21586d7f5d3SJohn Marino if (ki == CRYPT_SLOT_ACTIVE)
21686d7f5d3SJohn Marino LUKS_keyslot_set(&cd->hdr, keyIndex, 1);
21786d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
21886d7f5d3SJohn Marino safe_free(password);
21986d7f5d3SJohn Marino
22086d7f5d3SJohn Marino if (openedIndex < 0)
22186d7f5d3SJohn Marino return -EPERM;
22286d7f5d3SJohn Marino
22386d7f5d3SJohn Marino log_verbose(cd, _("Key slot %d verified.\n"), openedIndex);
22486d7f5d3SJohn Marino return 0;
22586d7f5d3SJohn Marino }
22686d7f5d3SJohn Marino
find_keyslot_by_passphrase(struct crypt_device * cd,const char * key_file,unsigned int flags,char * message)22786d7f5d3SJohn Marino static int find_keyslot_by_passphrase(struct crypt_device *cd,
22886d7f5d3SJohn Marino const char *key_file,
22986d7f5d3SJohn Marino unsigned int flags,
23086d7f5d3SJohn Marino char *message)
23186d7f5d3SJohn Marino {
23286d7f5d3SJohn Marino struct luks_masterkey *mk;
23386d7f5d3SJohn Marino char *password = NULL;
23486d7f5d3SJohn Marino unsigned int passwordLen;
23586d7f5d3SJohn Marino int keyIndex;
23686d7f5d3SJohn Marino
23786d7f5d3SJohn Marino get_key(message,&password,&passwordLen, 0, key_file,
23886d7f5d3SJohn Marino cd->timeout, flags, cd);
23986d7f5d3SJohn Marino if(!password)
24086d7f5d3SJohn Marino return -EINVAL;
24186d7f5d3SJohn Marino
24286d7f5d3SJohn Marino keyIndex = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT, password,
24386d7f5d3SJohn Marino passwordLen, &cd->hdr, &mk, cd);
24486d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
24586d7f5d3SJohn Marino safe_free(password);
24686d7f5d3SJohn Marino
24786d7f5d3SJohn Marino return keyIndex;
24886d7f5d3SJohn Marino }
24986d7f5d3SJohn Marino
device_check_and_adjust(struct crypt_device * cd,const char * device,uint64_t * size,uint64_t * offset,int * read_only)25086d7f5d3SJohn Marino static int device_check_and_adjust(struct crypt_device *cd,
25186d7f5d3SJohn Marino const char *device,
25286d7f5d3SJohn Marino uint64_t *size, uint64_t *offset,
25386d7f5d3SJohn Marino int *read_only)
25486d7f5d3SJohn Marino {
25586d7f5d3SJohn Marino struct device_infos infos;
25686d7f5d3SJohn Marino
25786d7f5d3SJohn Marino if (!device || get_device_infos(device, &infos, cd) < 0) {
25886d7f5d3SJohn Marino log_err(cd, _("Cannot get info about device %s.\n"),
25986d7f5d3SJohn Marino device ?: "[none]");
26086d7f5d3SJohn Marino return -ENOTBLK;
26186d7f5d3SJohn Marino }
26286d7f5d3SJohn Marino
26386d7f5d3SJohn Marino if (!*size) {
26486d7f5d3SJohn Marino *size = infos.size;
26586d7f5d3SJohn Marino if (!*size) {
26686d7f5d3SJohn Marino log_err(cd, _("Device %s has zero size.\n"), device);
26786d7f5d3SJohn Marino return -ENOTBLK;
26886d7f5d3SJohn Marino }
26986d7f5d3SJohn Marino if (*size < *offset) {
27086d7f5d3SJohn Marino log_err(cd, _("Device %s is too small.\n"), device);
27186d7f5d3SJohn Marino return -EINVAL;
27286d7f5d3SJohn Marino }
27386d7f5d3SJohn Marino *size -= *offset;
27486d7f5d3SJohn Marino }
27586d7f5d3SJohn Marino
27686d7f5d3SJohn Marino if (infos.readonly)
27786d7f5d3SJohn Marino *read_only = 1;
27886d7f5d3SJohn Marino
27986d7f5d3SJohn Marino log_dbg("Calculated device size is %" PRIu64 " sectors (%s), offset %" PRIu64 ".",
28086d7f5d3SJohn Marino *size, *read_only ? "RO" : "RW", *offset);
28186d7f5d3SJohn Marino return 0;
28286d7f5d3SJohn Marino }
28386d7f5d3SJohn Marino
luks_remove_helper(struct crypt_device * cd,int key_slot,const char * other_key_file,const char * key_file,int verify)28486d7f5d3SJohn Marino static int luks_remove_helper(struct crypt_device *cd,
28586d7f5d3SJohn Marino int key_slot,
28686d7f5d3SJohn Marino const char *other_key_file,
28786d7f5d3SJohn Marino const char *key_file,
28886d7f5d3SJohn Marino int verify)
28986d7f5d3SJohn Marino {
29086d7f5d3SJohn Marino crypt_keyslot_info ki;
29186d7f5d3SJohn Marino int r = -EINVAL;
29286d7f5d3SJohn Marino
29386d7f5d3SJohn Marino if (key_slot == CRYPT_ANY_SLOT) {
29486d7f5d3SJohn Marino key_slot = find_keyslot_by_passphrase(cd, key_file, 0,
29586d7f5d3SJohn Marino _("Enter LUKS passphrase to be deleted: "));
29686d7f5d3SJohn Marino if(key_slot < 0) {
29786d7f5d3SJohn Marino r = -EPERM;
29886d7f5d3SJohn Marino goto out;
29986d7f5d3SJohn Marino }
30086d7f5d3SJohn Marino
30186d7f5d3SJohn Marino log_std(cd, _("key slot %d selected for deletion.\n"), key_slot);
30286d7f5d3SJohn Marino }
30386d7f5d3SJohn Marino
30486d7f5d3SJohn Marino ki = crypt_keyslot_status(cd, key_slot);
30586d7f5d3SJohn Marino if (ki == CRYPT_SLOT_INVALID) {
30686d7f5d3SJohn Marino log_err(cd, _("Key slot %d is invalid, please select between 0 and %d.\n"),
30786d7f5d3SJohn Marino key_slot, LUKS_NUMKEYS - 1);
30886d7f5d3SJohn Marino r = -EINVAL;
30986d7f5d3SJohn Marino goto out;
31086d7f5d3SJohn Marino }
31186d7f5d3SJohn Marino if (ki <= CRYPT_SLOT_INACTIVE) {
31286d7f5d3SJohn Marino log_err(cd, _("Key %d not active. Can't wipe.\n"), key_slot);
31386d7f5d3SJohn Marino r = -EINVAL;
31486d7f5d3SJohn Marino goto out;
31586d7f5d3SJohn Marino }
31686d7f5d3SJohn Marino
31786d7f5d3SJohn Marino if (ki == CRYPT_SLOT_ACTIVE_LAST && cd->confirm &&
31886d7f5d3SJohn Marino !(cd->confirm(_("This is the last keyslot."
31986d7f5d3SJohn Marino " Device will become unusable after purging this key."),
32086d7f5d3SJohn Marino cd->confirm_usrptr))) {
32186d7f5d3SJohn Marino r = -EINVAL;
32286d7f5d3SJohn Marino goto out;
32386d7f5d3SJohn Marino }
32486d7f5d3SJohn Marino
32586d7f5d3SJohn Marino if(verify)
32686d7f5d3SJohn Marino r = verify_other_keyslot(cd, other_key_file, 0, key_slot);
32786d7f5d3SJohn Marino else
32886d7f5d3SJohn Marino r = 0;
32986d7f5d3SJohn Marino
33086d7f5d3SJohn Marino if (!r)
33186d7f5d3SJohn Marino r = crypt_keyslot_destroy(cd, key_slot);
33286d7f5d3SJohn Marino out:
33386d7f5d3SJohn Marino return (r < 0) ? r : 0;
33486d7f5d3SJohn Marino }
33586d7f5d3SJohn Marino
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)33686d7f5d3SJohn Marino static int create_device_helper(struct crypt_device *cd,
33786d7f5d3SJohn Marino const char *name,
33886d7f5d3SJohn Marino const char *hash,
33986d7f5d3SJohn Marino const char *cipher,
34086d7f5d3SJohn Marino const char *cipher_mode,
34186d7f5d3SJohn Marino const char *key_file,
34286d7f5d3SJohn Marino const char *key,
34386d7f5d3SJohn Marino unsigned int keyLen,
34486d7f5d3SJohn Marino int key_size,
34586d7f5d3SJohn Marino uint64_t size,
34686d7f5d3SJohn Marino uint64_t skip,
34786d7f5d3SJohn Marino uint64_t offset,
34886d7f5d3SJohn Marino const char *uuid,
34986d7f5d3SJohn Marino int read_only,
35086d7f5d3SJohn Marino unsigned int flags,
35186d7f5d3SJohn Marino int reload)
35286d7f5d3SJohn Marino {
35386d7f5d3SJohn Marino crypt_status_info ci;
35486d7f5d3SJohn Marino char *dm_cipher = NULL;
35586d7f5d3SJohn Marino char *processed_key = NULL;
35686d7f5d3SJohn Marino int r;
35786d7f5d3SJohn Marino
35886d7f5d3SJohn Marino ci = crypt_status(cd, name);
35986d7f5d3SJohn Marino if (ci == CRYPT_INVALID)
36086d7f5d3SJohn Marino return -EINVAL;
36186d7f5d3SJohn Marino
36286d7f5d3SJohn Marino if (reload && ci < CRYPT_ACTIVE)
36386d7f5d3SJohn Marino return -EINVAL;
36486d7f5d3SJohn Marino
36586d7f5d3SJohn Marino if (!reload && ci >= CRYPT_ACTIVE) {
36686d7f5d3SJohn Marino log_err(cd, _("Device %s already exists.\n"), name);
36786d7f5d3SJohn Marino return -EEXIST;
36886d7f5d3SJohn Marino }
36986d7f5d3SJohn Marino
37086d7f5d3SJohn Marino if (key_size < 0 || key_size > 1024) {
37186d7f5d3SJohn Marino log_err(cd, _("Invalid key size %d.\n"), key_size);
37286d7f5d3SJohn Marino return -EINVAL;
37386d7f5d3SJohn Marino }
37486d7f5d3SJohn Marino
37586d7f5d3SJohn Marino r = device_check_and_adjust(cd, cd->device, &size, &offset, &read_only);
37686d7f5d3SJohn Marino if (r)
37786d7f5d3SJohn Marino return r;
37886d7f5d3SJohn Marino
37986d7f5d3SJohn Marino if (cipher_mode && asprintf(&dm_cipher, "%s-%s", cipher, cipher_mode) < 0)
38086d7f5d3SJohn Marino return -ENOMEM;
38186d7f5d3SJohn Marino
38286d7f5d3SJohn Marino processed_key = process_key(cd, hash, key_file, key_size, key, keyLen);
38386d7f5d3SJohn Marino if (!processed_key)
38486d7f5d3SJohn Marino return -ENOENT;
38586d7f5d3SJohn Marino
38686d7f5d3SJohn Marino r = dm_create_device(name, cd->device, dm_cipher ?: cipher, cd->type, uuid, size, skip, offset,
38786d7f5d3SJohn Marino key_size, processed_key, read_only, reload);
38886d7f5d3SJohn Marino
38986d7f5d3SJohn Marino free(dm_cipher);
39086d7f5d3SJohn Marino safe_free(processed_key);
39186d7f5d3SJohn Marino return r;
39286d7f5d3SJohn Marino }
39386d7f5d3SJohn Marino
open_from_hdr_and_mk(struct crypt_device * cd,struct luks_masterkey * mk,const char * name,uint32_t flags)39486d7f5d3SJohn Marino static int open_from_hdr_and_mk(struct crypt_device *cd,
39586d7f5d3SJohn Marino struct luks_masterkey *mk,
39686d7f5d3SJohn Marino const char *name,
39786d7f5d3SJohn Marino uint32_t flags)
39886d7f5d3SJohn Marino {
39986d7f5d3SJohn Marino uint64_t size, offset;
40086d7f5d3SJohn Marino char *cipher;
40186d7f5d3SJohn Marino int read_only, no_uuid, r;
40286d7f5d3SJohn Marino
40386d7f5d3SJohn Marino size = 0;
40486d7f5d3SJohn Marino offset = crypt_get_data_offset(cd);
40586d7f5d3SJohn Marino read_only = flags & CRYPT_ACTIVATE_READONLY;
40686d7f5d3SJohn Marino no_uuid = flags & CRYPT_ACTIVATE_NO_UUID;
40786d7f5d3SJohn Marino
40886d7f5d3SJohn Marino r = device_check_and_adjust(cd, cd->device, &size, &offset, &read_only);
40986d7f5d3SJohn Marino if (r)
41086d7f5d3SJohn Marino return r;
41186d7f5d3SJohn Marino
41286d7f5d3SJohn Marino if (asprintf(&cipher, "%s-%s", crypt_get_cipher(cd),
41386d7f5d3SJohn Marino crypt_get_cipher_mode(cd)) < 0)
41486d7f5d3SJohn Marino r = -ENOMEM;
41586d7f5d3SJohn Marino else
41686d7f5d3SJohn Marino r = dm_create_device(name, cd->device, cipher, cd->type,
41786d7f5d3SJohn Marino no_uuid ? NULL : crypt_get_uuid(cd),
41886d7f5d3SJohn Marino size, 0, offset, mk->keyLength, mk->key,
41986d7f5d3SJohn Marino read_only, 0);
42086d7f5d3SJohn Marino free(cipher);
42186d7f5d3SJohn Marino return r;
42286d7f5d3SJohn Marino }
42386d7f5d3SJohn Marino
log_wrapper(int level,const char * msg,void * usrptr)42486d7f5d3SJohn Marino static void log_wrapper(int level, const char *msg, void *usrptr)
42586d7f5d3SJohn Marino {
42686d7f5d3SJohn Marino void (*xlog)(int level, char *msg) = usrptr;
42786d7f5d3SJohn Marino xlog(level, (char *)msg);
42886d7f5d3SJohn Marino }
42986d7f5d3SJohn Marino
yesDialog_wrapper(const char * msg,void * usrptr)43086d7f5d3SJohn Marino static int yesDialog_wrapper(const char *msg, void *usrptr)
43186d7f5d3SJohn Marino {
43286d7f5d3SJohn Marino int (*xyesDialog)(char *msg) = usrptr;
43386d7f5d3SJohn Marino return xyesDialog((char*)msg);
43486d7f5d3SJohn Marino }
43586d7f5d3SJohn Marino
crypt_confirm(struct crypt_device * cd,const char * msg)43686d7f5d3SJohn Marino int crypt_confirm(struct crypt_device *cd, const char *msg)
43786d7f5d3SJohn Marino {
43886d7f5d3SJohn Marino if (!cd || !cd->confirm)
43986d7f5d3SJohn Marino return 1;
44086d7f5d3SJohn Marino else
44186d7f5d3SJohn Marino return cd->confirm(msg, cd->confirm_usrptr);
44286d7f5d3SJohn Marino }
44386d7f5d3SJohn Marino
key_from_terminal(struct crypt_device * cd,char * msg,char ** key,unsigned int * key_len,int force_verify)44486d7f5d3SJohn Marino static void key_from_terminal(struct crypt_device *cd, char *msg, char **key,
44586d7f5d3SJohn Marino unsigned int *key_len, int force_verify)
44686d7f5d3SJohn Marino {
44786d7f5d3SJohn Marino int r, flags = 0;
44886d7f5d3SJohn Marino
44986d7f5d3SJohn Marino if (cd->password) {
45086d7f5d3SJohn Marino *key = safe_alloc(MAX_TTY_PASSWORD_LEN);
45186d7f5d3SJohn Marino if (*key)
45286d7f5d3SJohn Marino return;
45386d7f5d3SJohn Marino r = cd->password(msg, *key, (size_t)key_len, cd->password_usrptr);
45486d7f5d3SJohn Marino if (r < 0) {
45586d7f5d3SJohn Marino safe_free(*key);
45686d7f5d3SJohn Marino *key = NULL;
45786d7f5d3SJohn Marino } else
45886d7f5d3SJohn Marino *key_len = r;
45986d7f5d3SJohn Marino } else {
46086d7f5d3SJohn Marino if (force_verify || cd->password_verify)
46186d7f5d3SJohn Marino flags |= CRYPT_FLAG_VERIFY_IF_POSSIBLE;
46286d7f5d3SJohn Marino get_key(msg, key, key_len, 0, NULL, cd->timeout, flags, cd);
46386d7f5d3SJohn Marino }
46486d7f5d3SJohn Marino }
46586d7f5d3SJohn Marino
volume_key_by_terminal_passphrase(struct crypt_device * cd,int keyslot,struct luks_masterkey ** mk)46686d7f5d3SJohn Marino static int volume_key_by_terminal_passphrase(struct crypt_device *cd, int keyslot,
46786d7f5d3SJohn Marino struct luks_masterkey **mk)
46886d7f5d3SJohn Marino {
46986d7f5d3SJohn Marino char *prompt = NULL, *passphrase_read = NULL;
47086d7f5d3SJohn Marino unsigned int passphrase_size_read;
47186d7f5d3SJohn Marino int r = -EINVAL, tries = cd->tries;
47286d7f5d3SJohn Marino
47386d7f5d3SJohn Marino if(asprintf(&prompt, _("Enter passphrase for %s: "), cd->device) < 0)
47486d7f5d3SJohn Marino return -ENOMEM;
47586d7f5d3SJohn Marino
47686d7f5d3SJohn Marino *mk = NULL;
47786d7f5d3SJohn Marino do {
47886d7f5d3SJohn Marino if (*mk)
47986d7f5d3SJohn Marino LUKS_dealloc_masterkey(*mk);
48086d7f5d3SJohn Marino *mk = NULL;
48186d7f5d3SJohn Marino
48286d7f5d3SJohn Marino key_from_terminal(cd, prompt, &passphrase_read,
48386d7f5d3SJohn Marino &passphrase_size_read, 0);
48486d7f5d3SJohn Marino if(!passphrase_read) {
48586d7f5d3SJohn Marino r = -EINVAL;
48686d7f5d3SJohn Marino break;
48786d7f5d3SJohn Marino }
48886d7f5d3SJohn Marino
48986d7f5d3SJohn Marino r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase_read,
49086d7f5d3SJohn Marino passphrase_size_read, &cd->hdr, mk, cd);
49186d7f5d3SJohn Marino safe_free(passphrase_read);
49286d7f5d3SJohn Marino passphrase_read = NULL;
49386d7f5d3SJohn Marino } while (r == -EPERM && (--tries > 0));
49486d7f5d3SJohn Marino
49586d7f5d3SJohn Marino if (r < 0 && *mk) {
49686d7f5d3SJohn Marino LUKS_dealloc_masterkey(*mk);
49786d7f5d3SJohn Marino *mk = NULL;
49886d7f5d3SJohn Marino }
49986d7f5d3SJohn Marino free(prompt);
50086d7f5d3SJohn Marino
50186d7f5d3SJohn Marino return r;
50286d7f5d3SJohn Marino
50386d7f5d3SJohn Marino }
50486d7f5d3SJohn Marino
key_from_file(struct crypt_device * cd,char * msg,char ** key,unsigned int * key_len,const char * key_file,size_t key_size)50586d7f5d3SJohn Marino static void key_from_file(struct crypt_device *cd, char *msg,
50686d7f5d3SJohn Marino char **key, unsigned int *key_len,
50786d7f5d3SJohn Marino const char *key_file, size_t key_size)
50886d7f5d3SJohn Marino {
50986d7f5d3SJohn Marino get_key(msg, key, key_len, key_size, key_file, cd->timeout, 0, cd);
51086d7f5d3SJohn Marino }
51186d7f5d3SJohn Marino
_crypt_init(struct crypt_device ** cd,const char * type,struct crypt_options * options,int load,int need_dm)51286d7f5d3SJohn Marino static int _crypt_init(struct crypt_device **cd,
51386d7f5d3SJohn Marino const char *type,
51486d7f5d3SJohn Marino struct crypt_options *options,
51586d7f5d3SJohn Marino int load, int need_dm)
51686d7f5d3SJohn Marino {
51786d7f5d3SJohn Marino int init_by_name, r;
51886d7f5d3SJohn Marino
51986d7f5d3SJohn Marino /* if it is plain device and mapping table is being reloaded
52086d7f5d3SJohn Marino initialize it by name*/
52186d7f5d3SJohn Marino init_by_name = (type && !strcmp(type, CRYPT_PLAIN) && load);
52286d7f5d3SJohn Marino
52386d7f5d3SJohn Marino /* Some of old API calls do not require DM in kernel,
52486d7f5d3SJohn Marino fake initialisation by initialise it with kernel_check disabled */
52586d7f5d3SJohn Marino if (!need_dm)
52686d7f5d3SJohn Marino (void)dm_init(NULL, 0);
52786d7f5d3SJohn Marino if (init_by_name)
52886d7f5d3SJohn Marino r = crypt_init_by_name(cd, options->name);
52986d7f5d3SJohn Marino else
53086d7f5d3SJohn Marino r = crypt_init(cd, options->device);
53186d7f5d3SJohn Marino if (!need_dm)
53286d7f5d3SJohn Marino dm_exit();
53386d7f5d3SJohn Marino
53486d7f5d3SJohn Marino if (r)
53586d7f5d3SJohn Marino return -EINVAL;
53686d7f5d3SJohn Marino
53786d7f5d3SJohn Marino crypt_set_log_callback(*cd, log_wrapper, options->icb->log);
53886d7f5d3SJohn Marino crypt_set_confirm_callback(*cd, yesDialog_wrapper, options->icb->yesDialog);
53986d7f5d3SJohn Marino
54086d7f5d3SJohn Marino crypt_set_timeout(*cd, options->timeout);
54186d7f5d3SJohn Marino crypt_set_password_retry(*cd, options->tries);
54286d7f5d3SJohn Marino crypt_set_iterarion_time(*cd, options->iteration_time ?: 1000);
54386d7f5d3SJohn Marino crypt_set_password_verify(*cd, options->flags & CRYPT_FLAG_VERIFY);
54486d7f5d3SJohn Marino
54586d7f5d3SJohn Marino if (load && !init_by_name)
54686d7f5d3SJohn Marino r = crypt_load(*cd, type, NULL);
54786d7f5d3SJohn Marino
54886d7f5d3SJohn Marino if (!r && type && !(*cd)->type) {
54986d7f5d3SJohn Marino (*cd)->type = strdup(type);
55086d7f5d3SJohn Marino if (!(*cd)->type)
55186d7f5d3SJohn Marino r = -ENOMEM;
55286d7f5d3SJohn Marino }
55386d7f5d3SJohn Marino
55486d7f5d3SJohn Marino if (r)
55586d7f5d3SJohn Marino crypt_free(*cd);
55686d7f5d3SJohn Marino
55786d7f5d3SJohn Marino return r;
55886d7f5d3SJohn Marino }
55986d7f5d3SJohn Marino
crypt_set_log_callback(struct crypt_device * cd,void (* log)(int level,const char * msg,void * usrptr),void * usrptr)56086d7f5d3SJohn Marino void crypt_set_log_callback(struct crypt_device *cd,
56186d7f5d3SJohn Marino void (*log)(int level, const char *msg, void *usrptr),
56286d7f5d3SJohn Marino void *usrptr)
56386d7f5d3SJohn Marino {
56486d7f5d3SJohn Marino if (!cd)
56586d7f5d3SJohn Marino _default_log = log;
56686d7f5d3SJohn Marino else {
56786d7f5d3SJohn Marino cd->log = log;
56886d7f5d3SJohn Marino cd->log_usrptr = usrptr;
56986d7f5d3SJohn Marino }
57086d7f5d3SJohn Marino }
57186d7f5d3SJohn Marino
crypt_set_confirm_callback(struct crypt_device * cd,int (* confirm)(const char * msg,void * usrptr),void * usrptr)57286d7f5d3SJohn Marino void crypt_set_confirm_callback(struct crypt_device *cd,
57386d7f5d3SJohn Marino int (*confirm)(const char *msg, void *usrptr),
57486d7f5d3SJohn Marino void *usrptr)
57586d7f5d3SJohn Marino {
57686d7f5d3SJohn Marino cd->confirm = confirm;
57786d7f5d3SJohn Marino cd->confirm_usrptr = usrptr;
57886d7f5d3SJohn Marino }
57986d7f5d3SJohn Marino
crypt_set_password_callback(struct crypt_device * cd,int (* password)(const char * msg,char * buf,size_t length,void * usrptr),void * usrptr)58086d7f5d3SJohn Marino void crypt_set_password_callback(struct crypt_device *cd,
58186d7f5d3SJohn Marino int (*password)(const char *msg, char *buf, size_t length, void *usrptr),
58286d7f5d3SJohn Marino void *usrptr)
58386d7f5d3SJohn Marino {
58486d7f5d3SJohn Marino cd->password = password;
58586d7f5d3SJohn Marino cd->password_usrptr = usrptr;
58686d7f5d3SJohn Marino }
58786d7f5d3SJohn Marino
58886d7f5d3SJohn Marino /* OPTIONS: name, cipher, device, hash, key_file, key_size, key_slot,
58986d7f5d3SJohn Marino * offset, size, skip, timeout, tries, passphrase_fd (ignored),
59086d7f5d3SJohn Marino * flags, icb */
crypt_create_and_update_device(struct crypt_options * options,int update)59186d7f5d3SJohn Marino static int crypt_create_and_update_device(struct crypt_options *options, int update)
59286d7f5d3SJohn Marino {
59386d7f5d3SJohn Marino struct crypt_device *cd = NULL;
59486d7f5d3SJohn Marino char *key = NULL;
59586d7f5d3SJohn Marino unsigned int keyLen;
59686d7f5d3SJohn Marino int r;
59786d7f5d3SJohn Marino
59886d7f5d3SJohn Marino r = _crypt_init(&cd, CRYPT_PLAIN, options, 0, 1);
59986d7f5d3SJohn Marino if (r)
60086d7f5d3SJohn Marino return r;
60186d7f5d3SJohn Marino
60286d7f5d3SJohn Marino get_key(_("Enter passphrase: "), &key, &keyLen, options->key_size,
60386d7f5d3SJohn Marino options->key_file, cd->timeout, options->flags, cd);
60486d7f5d3SJohn Marino if (!key)
60586d7f5d3SJohn Marino r = -ENOENT;
60686d7f5d3SJohn Marino else
60786d7f5d3SJohn Marino r = create_device_helper(cd, options->name, options->hash,
60886d7f5d3SJohn Marino options->cipher, NULL, options->key_file, key, keyLen,
60986d7f5d3SJohn Marino options->key_size, options->size, options->skip,
61086d7f5d3SJohn Marino options->offset, NULL, options->flags & CRYPT_FLAG_READONLY,
61186d7f5d3SJohn Marino options->flags, update);
61286d7f5d3SJohn Marino
61386d7f5d3SJohn Marino safe_free(key);
61486d7f5d3SJohn Marino crypt_free(cd);
61586d7f5d3SJohn Marino return r;
61686d7f5d3SJohn Marino }
61786d7f5d3SJohn Marino
crypt_create_device(struct crypt_options * options)61886d7f5d3SJohn Marino int crypt_create_device(struct crypt_options *options)
61986d7f5d3SJohn Marino {
62086d7f5d3SJohn Marino return crypt_create_and_update_device(options, 0);
62186d7f5d3SJohn Marino }
62286d7f5d3SJohn Marino
crypt_update_device(struct crypt_options * options)62386d7f5d3SJohn Marino int crypt_update_device(struct crypt_options *options)
62486d7f5d3SJohn Marino {
62586d7f5d3SJohn Marino return crypt_create_and_update_device(options, 1);
62686d7f5d3SJohn Marino }
62786d7f5d3SJohn Marino
62886d7f5d3SJohn Marino /* OPTIONS: name, size, icb */
crypt_resize_device(struct crypt_options * options)62986d7f5d3SJohn Marino int crypt_resize_device(struct crypt_options *options)
63086d7f5d3SJohn Marino {
63186d7f5d3SJohn Marino struct crypt_device *cd = NULL;
63286d7f5d3SJohn Marino char *device = NULL, *cipher = NULL, *uuid = NULL, *key = NULL;
63386d7f5d3SJohn Marino char *type = NULL;
63486d7f5d3SJohn Marino uint64_t size, skip, offset;
63586d7f5d3SJohn Marino int key_size, read_only, r;
63686d7f5d3SJohn Marino
63786d7f5d3SJohn Marino log_dbg("Resizing device %s to %" PRIu64 " sectors.", options->name, options->size);
63886d7f5d3SJohn Marino
63986d7f5d3SJohn Marino if (dm_init(NULL, 1) < 0)
64086d7f5d3SJohn Marino return -ENOSYS;
64186d7f5d3SJohn Marino
64286d7f5d3SJohn Marino r = dm_query_device(options->name, &device, &size, &skip, &offset,
64386d7f5d3SJohn Marino &cipher, &key_size, &key, &read_only, NULL, &uuid);
64486d7f5d3SJohn Marino if (r < 0) {
64586d7f5d3SJohn Marino log_err(NULL, _("Device %s is not active.\n"), options->name);
64686d7f5d3SJohn Marino goto out;
64786d7f5d3SJohn Marino }
64886d7f5d3SJohn Marino
64986d7f5d3SJohn Marino /* Try to determine type of device from UUID */
65086d7f5d3SJohn Marino type = CRYPT_PLAIN;
65186d7f5d3SJohn Marino if (uuid) {
65286d7f5d3SJohn Marino if (!strncmp(uuid, CRYPT_PLAIN, strlen(CRYPT_PLAIN))) {
65386d7f5d3SJohn Marino type = CRYPT_PLAIN;
65486d7f5d3SJohn Marino free (uuid);
65586d7f5d3SJohn Marino uuid = NULL;
65686d7f5d3SJohn Marino } else if (!strncmp(uuid, CRYPT_LUKS1, strlen(CRYPT_LUKS1)))
65786d7f5d3SJohn Marino type = CRYPT_LUKS1;
65886d7f5d3SJohn Marino }
65986d7f5d3SJohn Marino
66086d7f5d3SJohn Marino if (!options->device)
66186d7f5d3SJohn Marino options->device = device;
66286d7f5d3SJohn Marino
66386d7f5d3SJohn Marino r = _crypt_init(&cd, type, options, 1, 1);
66486d7f5d3SJohn Marino if (r)
66586d7f5d3SJohn Marino goto out;
66686d7f5d3SJohn Marino
66786d7f5d3SJohn Marino size = options->size;
66886d7f5d3SJohn Marino r = device_check_and_adjust(cd, device, &size, &offset, &read_only);
66986d7f5d3SJohn Marino if (r)
67086d7f5d3SJohn Marino goto out;
67186d7f5d3SJohn Marino
67286d7f5d3SJohn Marino r = dm_create_device(options->name, device, cipher, type,
67386d7f5d3SJohn Marino crypt_get_uuid(cd), size, skip, offset,
67486d7f5d3SJohn Marino key_size, key, read_only, 1);
67586d7f5d3SJohn Marino out:
67686d7f5d3SJohn Marino safe_free(key);
67786d7f5d3SJohn Marino free(cipher);
67886d7f5d3SJohn Marino if (options->device == device)
67986d7f5d3SJohn Marino options->device = NULL;
68086d7f5d3SJohn Marino free(device);
68186d7f5d3SJohn Marino free(uuid);
68286d7f5d3SJohn Marino crypt_free(cd);
68386d7f5d3SJohn Marino dm_exit();
68486d7f5d3SJohn Marino return r;
68586d7f5d3SJohn Marino }
68686d7f5d3SJohn Marino
68786d7f5d3SJohn Marino /* OPTIONS: name, icb */
crypt_query_device(struct crypt_options * options)68886d7f5d3SJohn Marino int crypt_query_device(struct crypt_options *options)
68986d7f5d3SJohn Marino {
69086d7f5d3SJohn Marino int read_only, r;
69186d7f5d3SJohn Marino
69286d7f5d3SJohn Marino log_dbg("Query device %s.", options->name);
69386d7f5d3SJohn Marino
69486d7f5d3SJohn Marino if (dm_init(NULL, 1) < 0)
69586d7f5d3SJohn Marino return -ENOSYS;
69686d7f5d3SJohn Marino
69786d7f5d3SJohn Marino r = dm_status_device(options->name);
69886d7f5d3SJohn Marino if (r == -ENODEV) {
69986d7f5d3SJohn Marino dm_exit();
70086d7f5d3SJohn Marino return 0;
70186d7f5d3SJohn Marino }
70286d7f5d3SJohn Marino
70386d7f5d3SJohn Marino r = dm_query_device(options->name, (char **)&options->device, &options->size,
70486d7f5d3SJohn Marino &options->skip, &options->offset, (char **)&options->cipher,
70586d7f5d3SJohn Marino &options->key_size, NULL, &read_only, NULL, NULL);
70686d7f5d3SJohn Marino
70786d7f5d3SJohn Marino dm_exit();
70886d7f5d3SJohn Marino if (r < 0)
70986d7f5d3SJohn Marino return r;
71086d7f5d3SJohn Marino
71186d7f5d3SJohn Marino if (read_only)
71286d7f5d3SJohn Marino options->flags |= CRYPT_FLAG_READONLY;
71386d7f5d3SJohn Marino
71486d7f5d3SJohn Marino options->flags |= CRYPT_FLAG_FREE_DEVICE;
71586d7f5d3SJohn Marino options->flags |= CRYPT_FLAG_FREE_CIPHER;
71686d7f5d3SJohn Marino
71786d7f5d3SJohn Marino return 1;
71886d7f5d3SJohn Marino }
71986d7f5d3SJohn Marino
72086d7f5d3SJohn Marino /* OPTIONS: name, icb */
crypt_remove_device(struct crypt_options * options)72186d7f5d3SJohn Marino int crypt_remove_device(struct crypt_options *options)
72286d7f5d3SJohn Marino {
72386d7f5d3SJohn Marino struct crypt_device *cd = NULL;
72486d7f5d3SJohn Marino int r;
72586d7f5d3SJohn Marino
72686d7f5d3SJohn Marino r = crypt_init_by_name(&cd, options->name);
72786d7f5d3SJohn Marino if (r == 0)
72886d7f5d3SJohn Marino r = crypt_deactivate(cd, options->name);
72986d7f5d3SJohn Marino
73086d7f5d3SJohn Marino crypt_free(cd);
73186d7f5d3SJohn Marino return r;
73286d7f5d3SJohn Marino
73386d7f5d3SJohn Marino }
73486d7f5d3SJohn Marino
73586d7f5d3SJohn Marino /* OPTIONS: device, cipher, hash, align_payload, key_size (master key), key_slot
73686d7f5d3SJohn Marino * new_key_file, iteration_time, timeout, flags, icb */
crypt_luksFormat(struct crypt_options * options)73786d7f5d3SJohn Marino int crypt_luksFormat(struct crypt_options *options)
73886d7f5d3SJohn Marino {
73986d7f5d3SJohn Marino char cipherName[LUKS_CIPHERNAME_L];
74086d7f5d3SJohn Marino char cipherMode[LUKS_CIPHERMODE_L];
74186d7f5d3SJohn Marino char *password=NULL;
74286d7f5d3SJohn Marino unsigned int passwordLen;
74386d7f5d3SJohn Marino struct crypt_device *cd = NULL;
74486d7f5d3SJohn Marino struct crypt_params_luks1 cp = {
74586d7f5d3SJohn Marino .hash = options->hash,
74686d7f5d3SJohn Marino .data_alignment = options->align_payload
74786d7f5d3SJohn Marino };
74886d7f5d3SJohn Marino int r;
74986d7f5d3SJohn Marino
75086d7f5d3SJohn Marino r = parse_into_name_and_mode(options->cipher, cipherName, cipherMode);
75186d7f5d3SJohn Marino if(r < 0) {
75286d7f5d3SJohn Marino log_err(cd, _("No known cipher specification pattern detected.\n"));
75386d7f5d3SJohn Marino return r;
75486d7f5d3SJohn Marino }
75586d7f5d3SJohn Marino
75686d7f5d3SJohn Marino if ((r = _crypt_init(&cd, CRYPT_LUKS1, options, 0, 1)))
75786d7f5d3SJohn Marino return r;
75886d7f5d3SJohn Marino
75986d7f5d3SJohn Marino if (options->key_slot >= LUKS_NUMKEYS && options->key_slot != CRYPT_ANY_SLOT) {
76086d7f5d3SJohn Marino log_err(cd, _("Key slot %d is invalid, please select between 0 and %d.\n"),
76186d7f5d3SJohn Marino options->key_slot, LUKS_NUMKEYS - 1);
76286d7f5d3SJohn Marino r = -EINVAL;
76386d7f5d3SJohn Marino goto out;
76486d7f5d3SJohn Marino }
76586d7f5d3SJohn Marino
76686d7f5d3SJohn Marino get_key(_("Enter LUKS passphrase: "), &password, &passwordLen, 0,
76786d7f5d3SJohn Marino options->new_key_file, options->timeout, options->flags, cd);
76886d7f5d3SJohn Marino
76986d7f5d3SJohn Marino if(!password) {
77086d7f5d3SJohn Marino r = -EINVAL;
77186d7f5d3SJohn Marino goto out;
77286d7f5d3SJohn Marino }
77386d7f5d3SJohn Marino
77486d7f5d3SJohn Marino r = crypt_format(cd, CRYPT_LUKS1, cipherName, cipherMode,
77586d7f5d3SJohn Marino NULL, NULL, options->key_size, &cp);
77686d7f5d3SJohn Marino if (r < 0)
77786d7f5d3SJohn Marino goto out;
77886d7f5d3SJohn Marino
77986d7f5d3SJohn Marino /* Add keyslot using internally stored volume key generated during format */
78086d7f5d3SJohn Marino r = crypt_keyslot_add_by_volume_key(cd, options->key_slot, NULL, 0,
78186d7f5d3SJohn Marino password, passwordLen);
78286d7f5d3SJohn Marino out:
78386d7f5d3SJohn Marino crypt_free(cd);
78486d7f5d3SJohn Marino safe_free(password);
78586d7f5d3SJohn Marino return (r < 0) ? r : 0;
78686d7f5d3SJohn Marino }
78786d7f5d3SJohn Marino
78886d7f5d3SJohn Marino /* OPTIONS: name, device, key_size, key_file, timeout, tries, flags, icb */
crypt_luksOpen(struct crypt_options * options)78986d7f5d3SJohn Marino int crypt_luksOpen(struct crypt_options *options)
79086d7f5d3SJohn Marino {
79186d7f5d3SJohn Marino struct crypt_device *cd = NULL;
79286d7f5d3SJohn Marino uint32_t flags = 0;
79386d7f5d3SJohn Marino int r;
79486d7f5d3SJohn Marino
79586d7f5d3SJohn Marino if (!options->name)
79686d7f5d3SJohn Marino return -EINVAL;
79786d7f5d3SJohn Marino
79886d7f5d3SJohn Marino r = _crypt_init(&cd, CRYPT_LUKS1, options, 1, 1);
79986d7f5d3SJohn Marino if (r)
80086d7f5d3SJohn Marino return r;
80186d7f5d3SJohn Marino
80286d7f5d3SJohn Marino if (options->flags & CRYPT_FLAG_READONLY)
80386d7f5d3SJohn Marino flags |= CRYPT_ACTIVATE_READONLY;
80486d7f5d3SJohn Marino
80586d7f5d3SJohn Marino if (options->flags & CRYPT_FLAG_NON_EXCLUSIVE_ACCESS)
80686d7f5d3SJohn Marino flags |= CRYPT_ACTIVATE_NO_UUID;
80786d7f5d3SJohn Marino
80886d7f5d3SJohn Marino if (options->key_file)
80986d7f5d3SJohn Marino r = crypt_activate_by_keyfile(cd, options->name,
81086d7f5d3SJohn Marino CRYPT_ANY_SLOT, options->key_file, options->key_size,
81186d7f5d3SJohn Marino flags);
81286d7f5d3SJohn Marino else
81386d7f5d3SJohn Marino r = crypt_activate_by_passphrase(cd, options->name,
81486d7f5d3SJohn Marino CRYPT_ANY_SLOT, options->passphrase,
81586d7f5d3SJohn Marino options->passphrase ? strlen(options->passphrase) : 0,
81686d7f5d3SJohn Marino flags);
81786d7f5d3SJohn Marino
81886d7f5d3SJohn Marino crypt_free(cd);
81986d7f5d3SJohn Marino return (r < 0) ? r : 0;
82086d7f5d3SJohn Marino }
82186d7f5d3SJohn Marino
82286d7f5d3SJohn Marino /* OPTIONS: device, keys_slot, key_file, timeout, flags, icb */
crypt_luksKillSlot(struct crypt_options * options)82386d7f5d3SJohn Marino int crypt_luksKillSlot(struct crypt_options *options)
82486d7f5d3SJohn Marino {
82586d7f5d3SJohn Marino struct crypt_device *cd = NULL;
82686d7f5d3SJohn Marino int r;
82786d7f5d3SJohn Marino
82886d7f5d3SJohn Marino r = _crypt_init(&cd, CRYPT_LUKS1, options, 1, 1);
82986d7f5d3SJohn Marino if (r)
83086d7f5d3SJohn Marino return r;
83186d7f5d3SJohn Marino
83286d7f5d3SJohn Marino r = luks_remove_helper(cd, options->key_slot, options->key_file, NULL,
83386d7f5d3SJohn Marino options->flags & CRYPT_FLAG_VERIFY_ON_DELKEY);
83486d7f5d3SJohn Marino
83586d7f5d3SJohn Marino crypt_free(cd);
83686d7f5d3SJohn Marino return (r < 0) ? r : 0;
83786d7f5d3SJohn Marino }
83886d7f5d3SJohn Marino
83986d7f5d3SJohn Marino /* OPTIONS: device, new_key_file, key_file, timeout, flags, icb */
crypt_luksRemoveKey(struct crypt_options * options)84086d7f5d3SJohn Marino int crypt_luksRemoveKey(struct crypt_options *options)
84186d7f5d3SJohn Marino {
84286d7f5d3SJohn Marino struct crypt_device *cd = NULL;
84386d7f5d3SJohn Marino int r;
84486d7f5d3SJohn Marino
84586d7f5d3SJohn Marino r = _crypt_init(&cd, CRYPT_LUKS1, options, 1, 1);
84686d7f5d3SJohn Marino if (r)
84786d7f5d3SJohn Marino return r;
84886d7f5d3SJohn Marino
84986d7f5d3SJohn Marino r = luks_remove_helper(cd, CRYPT_ANY_SLOT, options->key_file, options->new_key_file,
85086d7f5d3SJohn Marino options->flags & CRYPT_FLAG_VERIFY_ON_DELKEY);
85186d7f5d3SJohn Marino
85286d7f5d3SJohn Marino crypt_free(cd);
85386d7f5d3SJohn Marino return (r < 0) ? r : 0;
85486d7f5d3SJohn Marino }
85586d7f5d3SJohn Marino
85686d7f5d3SJohn Marino
85786d7f5d3SJohn Marino /* OPTIONS: device, new_key_file, key_file, key_slot, flags,
85886d7f5d3SJohn Marino iteration_time, timeout, icb */
crypt_luksAddKey(struct crypt_options * options)85986d7f5d3SJohn Marino int crypt_luksAddKey(struct crypt_options *options)
86086d7f5d3SJohn Marino {
86186d7f5d3SJohn Marino struct crypt_device *cd = NULL;
86286d7f5d3SJohn Marino int r = -EINVAL;
86386d7f5d3SJohn Marino
86486d7f5d3SJohn Marino r = _crypt_init(&cd, CRYPT_LUKS1, options, 1, 1);
86586d7f5d3SJohn Marino if (r)
86686d7f5d3SJohn Marino return r;
86786d7f5d3SJohn Marino
86886d7f5d3SJohn Marino if (options->key_file || options->new_key_file)
86986d7f5d3SJohn Marino r = crypt_keyslot_add_by_keyfile(cd, options->key_slot,
87086d7f5d3SJohn Marino options->key_file, 0,
87186d7f5d3SJohn Marino options->new_key_file, 0);
87286d7f5d3SJohn Marino else
87386d7f5d3SJohn Marino r = crypt_keyslot_add_by_passphrase(cd, options->key_slot,
87486d7f5d3SJohn Marino NULL, 0, NULL, 0);
87586d7f5d3SJohn Marino
87686d7f5d3SJohn Marino crypt_free(cd);
87786d7f5d3SJohn Marino return (r < 0) ? r : 0;
87886d7f5d3SJohn Marino }
87986d7f5d3SJohn Marino
88086d7f5d3SJohn Marino /* OPTIONS: device, icb */
crypt_luksUUID(struct crypt_options * options)88186d7f5d3SJohn Marino int crypt_luksUUID(struct crypt_options *options)
88286d7f5d3SJohn Marino {
88386d7f5d3SJohn Marino struct crypt_device *cd = NULL;
88486d7f5d3SJohn Marino char *uuid;
88586d7f5d3SJohn Marino int r;
88686d7f5d3SJohn Marino
88786d7f5d3SJohn Marino r = _crypt_init(&cd, CRYPT_LUKS1, options, 1, 0);
88886d7f5d3SJohn Marino if (r)
88986d7f5d3SJohn Marino return r;
89086d7f5d3SJohn Marino
89186d7f5d3SJohn Marino uuid = (char *)crypt_get_uuid(cd);
89286d7f5d3SJohn Marino log_std(cd, uuid ?: "");
89386d7f5d3SJohn Marino log_std(cd, "\n");
89486d7f5d3SJohn Marino crypt_free(cd);
89586d7f5d3SJohn Marino return 0;
89686d7f5d3SJohn Marino }
89786d7f5d3SJohn Marino
89886d7f5d3SJohn Marino /* OPTIONS: device, icb */
crypt_isLuks(struct crypt_options * options)89986d7f5d3SJohn Marino int crypt_isLuks(struct crypt_options *options)
90086d7f5d3SJohn Marino {
90186d7f5d3SJohn Marino struct crypt_device *cd = NULL;
90286d7f5d3SJohn Marino int r;
90386d7f5d3SJohn Marino
90486d7f5d3SJohn Marino log_dbg("Check device %s for LUKS header.", options->device);
90586d7f5d3SJohn Marino
90686d7f5d3SJohn Marino if (init_crypto()) {
90786d7f5d3SJohn Marino log_err(cd, _("Cannot initialize crypto backend.\n"));
90886d7f5d3SJohn Marino return -ENOSYS;
90986d7f5d3SJohn Marino }
91086d7f5d3SJohn Marino
91186d7f5d3SJohn Marino r = crypt_init(&cd, options->device);
91286d7f5d3SJohn Marino if (r < 0)
91386d7f5d3SJohn Marino return -EINVAL;
91486d7f5d3SJohn Marino
91586d7f5d3SJohn Marino /* Do print fail here, no need to crypt_load() */
91686d7f5d3SJohn Marino r = LUKS_read_phdr(cd->device, &cd->hdr, 0, cd) ? -EINVAL : 0;
91786d7f5d3SJohn Marino
91886d7f5d3SJohn Marino crypt_free(cd);
91986d7f5d3SJohn Marino return r;
92086d7f5d3SJohn Marino }
92186d7f5d3SJohn Marino
92286d7f5d3SJohn Marino /* OPTIONS: device, icb */
crypt_luksDump(struct crypt_options * options)92386d7f5d3SJohn Marino int crypt_luksDump(struct crypt_options *options)
92486d7f5d3SJohn Marino {
92586d7f5d3SJohn Marino struct crypt_device *cd = NULL;
92686d7f5d3SJohn Marino int r;
92786d7f5d3SJohn Marino
92886d7f5d3SJohn Marino r = _crypt_init(&cd, CRYPT_LUKS1, options, 1, 0);
92986d7f5d3SJohn Marino if(r < 0)
93086d7f5d3SJohn Marino return r;
93186d7f5d3SJohn Marino
93286d7f5d3SJohn Marino r = crypt_dump(cd);
93386d7f5d3SJohn Marino
93486d7f5d3SJohn Marino crypt_free(cd);
93586d7f5d3SJohn Marino return 0;
93686d7f5d3SJohn Marino }
93786d7f5d3SJohn Marino
crypt_get_error(char * buf,size_t size)93886d7f5d3SJohn Marino void crypt_get_error(char *buf, size_t size)
93986d7f5d3SJohn Marino {
94086d7f5d3SJohn Marino const char *error = get_error();
94186d7f5d3SJohn Marino
94286d7f5d3SJohn Marino if (!buf || size < 1)
94386d7f5d3SJohn Marino set_error(NULL);
94486d7f5d3SJohn Marino else if (error) {
94586d7f5d3SJohn Marino strncpy(buf, error, size - 1);
94686d7f5d3SJohn Marino buf[size - 1] = '\0';
94786d7f5d3SJohn Marino set_error(NULL);
94886d7f5d3SJohn Marino } else
94986d7f5d3SJohn Marino buf[0] = '\0';
95086d7f5d3SJohn Marino }
95186d7f5d3SJohn Marino
crypt_put_options(struct crypt_options * options)95286d7f5d3SJohn Marino void crypt_put_options(struct crypt_options *options)
95386d7f5d3SJohn Marino {
95486d7f5d3SJohn Marino if (options->flags & CRYPT_FLAG_FREE_DEVICE) {
95586d7f5d3SJohn Marino free((char *)options->device);
95686d7f5d3SJohn Marino options->device = NULL;
95786d7f5d3SJohn Marino options->flags &= ~CRYPT_FLAG_FREE_DEVICE;
95886d7f5d3SJohn Marino }
95986d7f5d3SJohn Marino if (options->flags & CRYPT_FLAG_FREE_CIPHER) {
96086d7f5d3SJohn Marino free((char *)options->cipher);
96186d7f5d3SJohn Marino options->cipher = NULL;
96286d7f5d3SJohn Marino options->flags &= ~CRYPT_FLAG_FREE_CIPHER;
96386d7f5d3SJohn Marino }
96486d7f5d3SJohn Marino }
96586d7f5d3SJohn Marino
crypt_get_dir(void)96686d7f5d3SJohn Marino const char *crypt_get_dir(void)
96786d7f5d3SJohn Marino {
96886d7f5d3SJohn Marino return dm_get_dir();
96986d7f5d3SJohn Marino }
97086d7f5d3SJohn Marino
97186d7f5d3SJohn Marino /////////////////////////////////
97286d7f5d3SJohn Marino //
97386d7f5d3SJohn Marino // New API
97486d7f5d3SJohn Marino //
97586d7f5d3SJohn Marino
crypt_init(struct crypt_device ** cd,const char * device)97686d7f5d3SJohn Marino int crypt_init(struct crypt_device **cd, const char *device)
97786d7f5d3SJohn Marino {
97886d7f5d3SJohn Marino struct crypt_device *h = NULL;
97986d7f5d3SJohn Marino
98086d7f5d3SJohn Marino if (!cd)
98186d7f5d3SJohn Marino return -EINVAL;
98286d7f5d3SJohn Marino
98386d7f5d3SJohn Marino log_dbg("Allocating crypt device %s context.", device);
98486d7f5d3SJohn Marino
98586d7f5d3SJohn Marino if (device && !device_ready(NULL, device, O_RDONLY))
98686d7f5d3SJohn Marino return -ENOTBLK;
98786d7f5d3SJohn Marino
98886d7f5d3SJohn Marino if (!(h = malloc(sizeof(struct crypt_device))))
98986d7f5d3SJohn Marino return -ENOMEM;
99086d7f5d3SJohn Marino
99186d7f5d3SJohn Marino memset(h, 0, sizeof(*h));
99286d7f5d3SJohn Marino
99386d7f5d3SJohn Marino if (device) {
99486d7f5d3SJohn Marino h->device = strdup(device);
99586d7f5d3SJohn Marino if (!h->device) {
99686d7f5d3SJohn Marino free(h);
99786d7f5d3SJohn Marino return -ENOMEM;
99886d7f5d3SJohn Marino }
99986d7f5d3SJohn Marino } else
100086d7f5d3SJohn Marino h->device = NULL;
100186d7f5d3SJohn Marino
100286d7f5d3SJohn Marino if (dm_init(h, 1) < 0) {
100386d7f5d3SJohn Marino free(h);
100486d7f5d3SJohn Marino return -ENOSYS;
100586d7f5d3SJohn Marino }
100686d7f5d3SJohn Marino
100786d7f5d3SJohn Marino h->iteration_time = 1000;
100886d7f5d3SJohn Marino h->password_verify = 0;
100986d7f5d3SJohn Marino h->tries = 3;
101086d7f5d3SJohn Marino *cd = h;
101186d7f5d3SJohn Marino return 0;
101286d7f5d3SJohn Marino }
101386d7f5d3SJohn Marino
crypt_init_by_name(struct crypt_device ** cd,const char * name)101486d7f5d3SJohn Marino int crypt_init_by_name(struct crypt_device **cd, const char *name)
101586d7f5d3SJohn Marino {
101686d7f5d3SJohn Marino crypt_status_info ci;
101786d7f5d3SJohn Marino char *device = NULL;
101886d7f5d3SJohn Marino int r;
101986d7f5d3SJohn Marino
102086d7f5d3SJohn Marino log_dbg("Allocating crypt device context by device %s.", name);
102186d7f5d3SJohn Marino
102286d7f5d3SJohn Marino ci = crypt_status(NULL, name);
102386d7f5d3SJohn Marino if (ci == CRYPT_INVALID)
102486d7f5d3SJohn Marino return -ENODEV;
102586d7f5d3SJohn Marino
102686d7f5d3SJohn Marino if (ci < CRYPT_ACTIVE) {
102786d7f5d3SJohn Marino log_err(NULL, _("Device %s is not active.\n"), name);
102886d7f5d3SJohn Marino return -ENODEV;
102986d7f5d3SJohn Marino }
103086d7f5d3SJohn Marino
103186d7f5d3SJohn Marino r = dm_query_device(name, &device, NULL, NULL, NULL,
103286d7f5d3SJohn Marino NULL, NULL, NULL, NULL, NULL, NULL);
103386d7f5d3SJohn Marino
103486d7f5d3SJohn Marino /* Underlying device disappeared but mapping still active */
103586d7f5d3SJohn Marino if (r >= 0 && !device)
103686d7f5d3SJohn Marino log_verbose(NULL, _("Underlying device for crypt device %s disappeared.\n"),
103786d7f5d3SJohn Marino name);
103886d7f5d3SJohn Marino
103986d7f5d3SJohn Marino if (r >= 0)
104086d7f5d3SJohn Marino r = crypt_init(cd, device);
104186d7f5d3SJohn Marino
104286d7f5d3SJohn Marino free(device);
104386d7f5d3SJohn Marino return r;
104486d7f5d3SJohn Marino }
104586d7f5d3SJohn Marino
_crypt_format_plain(struct crypt_device * cd,const char * cipher,const char * cipher_mode,const char * uuid,struct crypt_params_plain * params)104686d7f5d3SJohn Marino static int _crypt_format_plain(struct crypt_device *cd,
104786d7f5d3SJohn Marino const char *cipher,
104886d7f5d3SJohn Marino const char *cipher_mode,
104986d7f5d3SJohn Marino const char *uuid,
105086d7f5d3SJohn Marino struct crypt_params_plain *params)
105186d7f5d3SJohn Marino {
105286d7f5d3SJohn Marino if (!cipher || !cipher_mode) {
105386d7f5d3SJohn Marino log_err(cd, _("Invalid plain crypt parameters.\n"));
105486d7f5d3SJohn Marino return -EINVAL;
105586d7f5d3SJohn Marino }
105686d7f5d3SJohn Marino
105786d7f5d3SJohn Marino if (cd->volume_key->keyLength > 1024) {
105886d7f5d3SJohn Marino log_err(cd, _("Invalid key size.\n"));
105986d7f5d3SJohn Marino return -EINVAL;
106086d7f5d3SJohn Marino }
106186d7f5d3SJohn Marino
106286d7f5d3SJohn Marino cd->plain_cipher = strdup(cipher);
106386d7f5d3SJohn Marino cd->plain_cipher_mode = strdup(cipher_mode);
106486d7f5d3SJohn Marino
106586d7f5d3SJohn Marino if (uuid)
106686d7f5d3SJohn Marino cd->plain_uuid = strdup(uuid);
106786d7f5d3SJohn Marino
106886d7f5d3SJohn Marino if (params && params->hash)
106986d7f5d3SJohn Marino cd->plain_hdr.hash = strdup(params->hash);
107086d7f5d3SJohn Marino
107186d7f5d3SJohn Marino cd->plain_hdr.offset = params ? params->offset : 0;
107286d7f5d3SJohn Marino cd->plain_hdr.skip = params ? params->skip : 0;
107386d7f5d3SJohn Marino
107486d7f5d3SJohn Marino if (!cd->plain_cipher || !cd->plain_cipher_mode)
107586d7f5d3SJohn Marino return -ENOMEM;
107686d7f5d3SJohn Marino
107786d7f5d3SJohn Marino return 0;
107886d7f5d3SJohn Marino }
107986d7f5d3SJohn Marino
_crypt_format_luks1(struct crypt_device * cd,const char * cipher,const char * cipher_mode,const char * uuid,struct crypt_params_luks1 * params)108086d7f5d3SJohn Marino static int _crypt_format_luks1(struct crypt_device *cd,
108186d7f5d3SJohn Marino const char *cipher,
108286d7f5d3SJohn Marino const char *cipher_mode,
108386d7f5d3SJohn Marino const char *uuid,
108486d7f5d3SJohn Marino struct crypt_params_luks1 *params)
108586d7f5d3SJohn Marino {
108686d7f5d3SJohn Marino int r;
108786d7f5d3SJohn Marino unsigned long required_alignment = DEFAULT_ALIGNMENT;
108886d7f5d3SJohn Marino unsigned long alignment_offset = 0;
108986d7f5d3SJohn Marino
109086d7f5d3SJohn Marino if (!cd->device) {
109186d7f5d3SJohn Marino log_err(cd, _("Can't format LUKS without device.\n"));
109286d7f5d3SJohn Marino return -EINVAL;
109386d7f5d3SJohn Marino }
109486d7f5d3SJohn Marino
109586d7f5d3SJohn Marino if (params && params->data_alignment)
109686d7f5d3SJohn Marino required_alignment = params->data_alignment * SECTOR_SIZE;
109786d7f5d3SJohn Marino else
109886d7f5d3SJohn Marino get_topology_alignment(cd->device, &required_alignment,
109986d7f5d3SJohn Marino &alignment_offset, DEFAULT_ALIGNMENT);
110086d7f5d3SJohn Marino
110186d7f5d3SJohn Marino r = LUKS_generate_phdr(&cd->hdr, cd->volume_key, cipher, cipher_mode,
110286d7f5d3SJohn Marino (params && params->hash) ? params->hash : "sha1",
110386d7f5d3SJohn Marino uuid, LUKS_STRIPES,
110486d7f5d3SJohn Marino required_alignment / SECTOR_SIZE,
110586d7f5d3SJohn Marino alignment_offset / SECTOR_SIZE,
110686d7f5d3SJohn Marino cd->iteration_time, &cd->PBKDF2_per_sec, cd);
110786d7f5d3SJohn Marino if(r < 0)
110886d7f5d3SJohn Marino return r;
110986d7f5d3SJohn Marino
111086d7f5d3SJohn Marino /* Wipe first 8 sectors - fs magic numbers etc. */
111186d7f5d3SJohn Marino r = wipe_device_header(cd->device, 8);
111286d7f5d3SJohn Marino if(r < 0) {
111386d7f5d3SJohn Marino log_err(cd, _("Can't wipe header on device %s.\n"), cd->device);
111486d7f5d3SJohn Marino return r;
111586d7f5d3SJohn Marino }
111686d7f5d3SJohn Marino
111786d7f5d3SJohn Marino r = LUKS_write_phdr(cd->device, &cd->hdr, cd);
111886d7f5d3SJohn Marino
111986d7f5d3SJohn Marino return r;
112086d7f5d3SJohn Marino }
112186d7f5d3SJohn Marino
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)112286d7f5d3SJohn Marino int crypt_format(struct crypt_device *cd,
112386d7f5d3SJohn Marino const char *type,
112486d7f5d3SJohn Marino const char *cipher,
112586d7f5d3SJohn Marino const char *cipher_mode,
112686d7f5d3SJohn Marino const char *uuid,
112786d7f5d3SJohn Marino const char *volume_key,
112886d7f5d3SJohn Marino size_t volume_key_size,
112986d7f5d3SJohn Marino void *params)
113086d7f5d3SJohn Marino {
113186d7f5d3SJohn Marino int r;
113286d7f5d3SJohn Marino
113386d7f5d3SJohn Marino log_dbg("Formatting device %s as type %s.", cd->device ?: "(none)", cd->type ?: "(none)");
113486d7f5d3SJohn Marino
113586d7f5d3SJohn Marino if (!type)
113686d7f5d3SJohn Marino return -EINVAL;
113786d7f5d3SJohn Marino
113886d7f5d3SJohn Marino /* Some hash functions need initialized gcrypt library */
113986d7f5d3SJohn Marino if (init_crypto()) {
114086d7f5d3SJohn Marino log_err(cd, _("Cannot initialize crypto backend.\n"));
114186d7f5d3SJohn Marino return -ENOSYS;
114286d7f5d3SJohn Marino }
114386d7f5d3SJohn Marino
114486d7f5d3SJohn Marino if (volume_key)
114586d7f5d3SJohn Marino cd->volume_key = LUKS_alloc_masterkey(volume_key_size,
114686d7f5d3SJohn Marino volume_key);
114786d7f5d3SJohn Marino else
114886d7f5d3SJohn Marino cd->volume_key = LUKS_generate_masterkey(volume_key_size);
114986d7f5d3SJohn Marino
115086d7f5d3SJohn Marino if(!cd->volume_key)
115186d7f5d3SJohn Marino return -ENOMEM;
115286d7f5d3SJohn Marino
115386d7f5d3SJohn Marino if (isPLAIN(type))
115486d7f5d3SJohn Marino r = _crypt_format_plain(cd, cipher, cipher_mode,
115586d7f5d3SJohn Marino uuid, params);
115686d7f5d3SJohn Marino else if (isLUKS(type))
115786d7f5d3SJohn Marino r = _crypt_format_luks1(cd, cipher, cipher_mode,
115886d7f5d3SJohn Marino uuid, params);
115986d7f5d3SJohn Marino else {
116086d7f5d3SJohn Marino /* FIXME: allow plugins here? */
116186d7f5d3SJohn Marino log_err(cd, _("Unknown crypt device type %s requested.\n"), type);
116286d7f5d3SJohn Marino r = -EINVAL;
116386d7f5d3SJohn Marino }
116486d7f5d3SJohn Marino
116586d7f5d3SJohn Marino if (!r && !(cd->type = strdup(type)))
116686d7f5d3SJohn Marino r = -ENOMEM;
116786d7f5d3SJohn Marino
116886d7f5d3SJohn Marino if (r < 0) {
116986d7f5d3SJohn Marino LUKS_dealloc_masterkey(cd->volume_key);
117086d7f5d3SJohn Marino cd->volume_key = NULL;
117186d7f5d3SJohn Marino }
117286d7f5d3SJohn Marino
117386d7f5d3SJohn Marino return r;
117486d7f5d3SJohn Marino }
117586d7f5d3SJohn Marino
crypt_load(struct crypt_device * cd,const char * requested_type,void * params)117686d7f5d3SJohn Marino int crypt_load(struct crypt_device *cd,
117786d7f5d3SJohn Marino const char *requested_type,
117886d7f5d3SJohn Marino void *params)
117986d7f5d3SJohn Marino {
118086d7f5d3SJohn Marino struct luks_phdr hdr;
118186d7f5d3SJohn Marino int r;
118286d7f5d3SJohn Marino
118386d7f5d3SJohn Marino log_dbg("Trying to load %s crypt type from device %s.",
118486d7f5d3SJohn Marino requested_type ?: "any", cd->device ?: "(none)");
118586d7f5d3SJohn Marino
118686d7f5d3SJohn Marino if (!cd->device)
118786d7f5d3SJohn Marino return -EINVAL;
118886d7f5d3SJohn Marino
118986d7f5d3SJohn Marino if (requested_type && !isLUKS(requested_type))
119086d7f5d3SJohn Marino return -EINVAL;
119186d7f5d3SJohn Marino
119286d7f5d3SJohn Marino /* Some hash functions need initialized gcrypt library */
119386d7f5d3SJohn Marino if (init_crypto()) {
119486d7f5d3SJohn Marino log_err(cd, _("Cannot initialize crypto backend.\n"));
119586d7f5d3SJohn Marino return -ENOSYS;
119686d7f5d3SJohn Marino }
119786d7f5d3SJohn Marino
119886d7f5d3SJohn Marino r = LUKS_read_phdr(cd->device, &hdr, 1, cd);
119986d7f5d3SJohn Marino
120086d7f5d3SJohn Marino if (!r) {
120186d7f5d3SJohn Marino memcpy(&cd->hdr, &hdr, sizeof(hdr));
120286d7f5d3SJohn Marino cd->type = strdup(requested_type);
120386d7f5d3SJohn Marino if (!cd->type)
120486d7f5d3SJohn Marino r = -ENOMEM;
120586d7f5d3SJohn Marino }
120686d7f5d3SJohn Marino
120786d7f5d3SJohn Marino return r;
120886d7f5d3SJohn Marino }
120986d7f5d3SJohn Marino
crypt_header_backup(struct crypt_device * cd,const char * requested_type,const char * backup_file)121086d7f5d3SJohn Marino int crypt_header_backup(struct crypt_device *cd,
121186d7f5d3SJohn Marino const char *requested_type,
121286d7f5d3SJohn Marino const char *backup_file)
121386d7f5d3SJohn Marino {
121486d7f5d3SJohn Marino if ((requested_type && !isLUKS(requested_type)) || !backup_file)
121586d7f5d3SJohn Marino return -EINVAL;
121686d7f5d3SJohn Marino
121786d7f5d3SJohn Marino /* Some hash functions need initialized gcrypt library */
121886d7f5d3SJohn Marino if (init_crypto()) {
121986d7f5d3SJohn Marino log_err(cd, _("Cannot initialize crypto backend.\n"));
122086d7f5d3SJohn Marino return -ENOSYS;
122186d7f5d3SJohn Marino }
122286d7f5d3SJohn Marino
122386d7f5d3SJohn Marino log_dbg("Requested header backup of device %s (%s) to "
122486d7f5d3SJohn Marino "file %s.", cd->device, requested_type, backup_file);
122586d7f5d3SJohn Marino
122686d7f5d3SJohn Marino return LUKS_hdr_backup(backup_file, cd->device, &cd->hdr, cd);
122786d7f5d3SJohn Marino }
122886d7f5d3SJohn Marino
crypt_header_restore(struct crypt_device * cd,const char * requested_type,const char * backup_file)122986d7f5d3SJohn Marino int crypt_header_restore(struct crypt_device *cd,
123086d7f5d3SJohn Marino const char *requested_type,
123186d7f5d3SJohn Marino const char *backup_file)
123286d7f5d3SJohn Marino {
123386d7f5d3SJohn Marino if (requested_type && !isLUKS(requested_type))
123486d7f5d3SJohn Marino return -EINVAL;
123586d7f5d3SJohn Marino
123686d7f5d3SJohn Marino /* Some hash functions need initialized gcrypt library */
123786d7f5d3SJohn Marino if (init_crypto()) {
123886d7f5d3SJohn Marino log_err(cd, _("Cannot initialize crypto backend.\n"));
123986d7f5d3SJohn Marino return -ENOSYS;
124086d7f5d3SJohn Marino }
124186d7f5d3SJohn Marino
124286d7f5d3SJohn Marino log_dbg("Requested header restore to device %s (%s) from "
124386d7f5d3SJohn Marino "file %s.", cd->device, requested_type, backup_file);
124486d7f5d3SJohn Marino
124586d7f5d3SJohn Marino return LUKS_hdr_restore(backup_file, cd->device, &cd->hdr, cd);
124686d7f5d3SJohn Marino }
124786d7f5d3SJohn Marino
crypt_free(struct crypt_device * cd)124886d7f5d3SJohn Marino void crypt_free(struct crypt_device *cd)
124986d7f5d3SJohn Marino {
125086d7f5d3SJohn Marino if (cd) {
125186d7f5d3SJohn Marino log_dbg("Releasing crypt device %s context.", cd->device);
125286d7f5d3SJohn Marino
125386d7f5d3SJohn Marino dm_exit();
125486d7f5d3SJohn Marino if (cd->volume_key)
125586d7f5d3SJohn Marino LUKS_dealloc_masterkey(cd->volume_key);
125686d7f5d3SJohn Marino
125786d7f5d3SJohn Marino free(cd->device);
125886d7f5d3SJohn Marino free(cd->type);
125986d7f5d3SJohn Marino
126086d7f5d3SJohn Marino /* used in plain device only */
126186d7f5d3SJohn Marino free((char*)cd->plain_hdr.hash);
126286d7f5d3SJohn Marino free(cd->plain_cipher);
126386d7f5d3SJohn Marino free(cd->plain_cipher_mode);
126486d7f5d3SJohn Marino free(cd->plain_uuid);
126586d7f5d3SJohn Marino
126686d7f5d3SJohn Marino free(cd);
126786d7f5d3SJohn Marino }
126886d7f5d3SJohn Marino }
126986d7f5d3SJohn Marino
crypt_suspend(struct crypt_device * cd,const char * name)127086d7f5d3SJohn Marino int crypt_suspend(struct crypt_device *cd,
127186d7f5d3SJohn Marino const char *name)
127286d7f5d3SJohn Marino {
127386d7f5d3SJohn Marino crypt_status_info ci;
127486d7f5d3SJohn Marino int r, suspended = 0;
127586d7f5d3SJohn Marino
127686d7f5d3SJohn Marino log_dbg("Suspending volume %s.", name);
127786d7f5d3SJohn Marino
127886d7f5d3SJohn Marino ci = crypt_status(NULL, name);
127986d7f5d3SJohn Marino if (ci < CRYPT_ACTIVE) {
128086d7f5d3SJohn Marino log_err(cd, _("Volume %s is not active.\n"), name);
128186d7f5d3SJohn Marino return -EINVAL;
128286d7f5d3SJohn Marino }
128386d7f5d3SJohn Marino
128486d7f5d3SJohn Marino if (!cd && dm_init(NULL, 1) < 0)
128586d7f5d3SJohn Marino return -ENOSYS;
128686d7f5d3SJohn Marino
128786d7f5d3SJohn Marino r = dm_query_device(name, NULL, NULL, NULL, NULL,
128886d7f5d3SJohn Marino NULL, NULL, NULL, NULL, &suspended, NULL);
128986d7f5d3SJohn Marino if (r < 0)
129086d7f5d3SJohn Marino goto out;
129186d7f5d3SJohn Marino
129286d7f5d3SJohn Marino if (suspended) {
129386d7f5d3SJohn Marino log_err(cd, _("Volume %s is already suspended.\n"), name);
129486d7f5d3SJohn Marino r = -EINVAL;
129586d7f5d3SJohn Marino goto out;
129686d7f5d3SJohn Marino }
129786d7f5d3SJohn Marino
129886d7f5d3SJohn Marino r = dm_suspend_and_wipe_key(name);
129986d7f5d3SJohn Marino if (r == -ENOTSUP)
130086d7f5d3SJohn Marino log_err(cd, "Suspend is not supported for device %s.\n", name);
130186d7f5d3SJohn Marino else if (r)
130286d7f5d3SJohn Marino log_err(cd, "Error during suspending device %s.\n", name);
130386d7f5d3SJohn Marino out:
130486d7f5d3SJohn Marino if (!cd)
130586d7f5d3SJohn Marino dm_exit();
130686d7f5d3SJohn Marino return r;
130786d7f5d3SJohn Marino }
130886d7f5d3SJohn Marino
crypt_resume_by_passphrase(struct crypt_device * cd,const char * name,int keyslot,const char * passphrase,size_t passphrase_size)130986d7f5d3SJohn Marino int crypt_resume_by_passphrase(struct crypt_device *cd,
131086d7f5d3SJohn Marino const char *name,
131186d7f5d3SJohn Marino int keyslot,
131286d7f5d3SJohn Marino const char *passphrase,
131386d7f5d3SJohn Marino size_t passphrase_size)
131486d7f5d3SJohn Marino {
131586d7f5d3SJohn Marino struct luks_masterkey *mk = NULL;
131686d7f5d3SJohn Marino int r, suspended = 0;
131786d7f5d3SJohn Marino
131886d7f5d3SJohn Marino log_dbg("Resuming volume %s.", name);
131986d7f5d3SJohn Marino
132086d7f5d3SJohn Marino if (!isLUKS(cd->type)) {
132186d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
132286d7f5d3SJohn Marino r = -EINVAL;
132386d7f5d3SJohn Marino goto out;
132486d7f5d3SJohn Marino }
132586d7f5d3SJohn Marino
132686d7f5d3SJohn Marino r = dm_query_device(name, NULL, NULL, NULL, NULL,
132786d7f5d3SJohn Marino NULL, NULL, NULL, NULL, &suspended, NULL);
132886d7f5d3SJohn Marino if (r < 0)
132986d7f5d3SJohn Marino return r;
133086d7f5d3SJohn Marino
133186d7f5d3SJohn Marino if (!suspended) {
133286d7f5d3SJohn Marino log_err(cd, _("Volume %s is not suspended.\n"), name);
133386d7f5d3SJohn Marino return -EINVAL;
133486d7f5d3SJohn Marino }
133586d7f5d3SJohn Marino
133686d7f5d3SJohn Marino if (passphrase) {
133786d7f5d3SJohn Marino r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase,
133886d7f5d3SJohn Marino passphrase_size, &cd->hdr, &mk, cd);
133986d7f5d3SJohn Marino } else
134086d7f5d3SJohn Marino r = volume_key_by_terminal_passphrase(cd, keyslot, &mk);
134186d7f5d3SJohn Marino
134286d7f5d3SJohn Marino if (r >= 0) {
134386d7f5d3SJohn Marino keyslot = r;
134486d7f5d3SJohn Marino r = dm_resume_and_reinstate_key(name, mk->keyLength, mk->key);
134586d7f5d3SJohn Marino if (r == -ENOTSUP)
134686d7f5d3SJohn Marino log_err(cd, "Resume is not supported for device %s.\n", name);
134786d7f5d3SJohn Marino else if (r)
134886d7f5d3SJohn Marino log_err(cd, "Error during resuming device %s.\n", name);
134986d7f5d3SJohn Marino } else
135086d7f5d3SJohn Marino r = keyslot;
135186d7f5d3SJohn Marino out:
135286d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
135386d7f5d3SJohn Marino return r < 0 ? r : keyslot;
135486d7f5d3SJohn Marino }
135586d7f5d3SJohn Marino
crypt_resume_by_keyfile(struct crypt_device * cd,const char * name,int keyslot,const char * keyfile,size_t keyfile_size)135686d7f5d3SJohn Marino int crypt_resume_by_keyfile(struct crypt_device *cd,
135786d7f5d3SJohn Marino const char *name,
135886d7f5d3SJohn Marino int keyslot,
135986d7f5d3SJohn Marino const char *keyfile,
136086d7f5d3SJohn Marino size_t keyfile_size)
136186d7f5d3SJohn Marino {
136286d7f5d3SJohn Marino struct luks_masterkey *mk = NULL;
136386d7f5d3SJohn Marino char *passphrase_read = NULL;
136486d7f5d3SJohn Marino unsigned int passphrase_size_read;
136586d7f5d3SJohn Marino int r, suspended = 0;
136686d7f5d3SJohn Marino
136786d7f5d3SJohn Marino log_dbg("Resuming volume %s.", name);
136886d7f5d3SJohn Marino
136986d7f5d3SJohn Marino if (!isLUKS(cd->type)) {
137086d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
137186d7f5d3SJohn Marino r = -EINVAL;
137286d7f5d3SJohn Marino goto out;
137386d7f5d3SJohn Marino }
137486d7f5d3SJohn Marino
137586d7f5d3SJohn Marino r = dm_query_device(name, NULL, NULL, NULL, NULL,
137686d7f5d3SJohn Marino NULL, NULL, NULL, NULL, &suspended, NULL);
137786d7f5d3SJohn Marino if (r < 0)
137886d7f5d3SJohn Marino return r;
137986d7f5d3SJohn Marino
138086d7f5d3SJohn Marino if (!suspended) {
138186d7f5d3SJohn Marino log_err(cd, _("Volume %s is not suspended.\n"), name);
138286d7f5d3SJohn Marino return -EINVAL;
138386d7f5d3SJohn Marino }
138486d7f5d3SJohn Marino
138586d7f5d3SJohn Marino if (!keyfile)
138686d7f5d3SJohn Marino return -EINVAL;
138786d7f5d3SJohn Marino
138886d7f5d3SJohn Marino key_from_file(cd, _("Enter passphrase: "), &passphrase_read,
138986d7f5d3SJohn Marino &passphrase_size_read, keyfile, keyfile_size);
139086d7f5d3SJohn Marino
139186d7f5d3SJohn Marino if(!passphrase_read)
139286d7f5d3SJohn Marino r = -EINVAL;
139386d7f5d3SJohn Marino else {
139486d7f5d3SJohn Marino r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase_read,
139586d7f5d3SJohn Marino passphrase_size_read, &cd->hdr, &mk, cd);
139686d7f5d3SJohn Marino safe_free(passphrase_read);
139786d7f5d3SJohn Marino }
139886d7f5d3SJohn Marino
139986d7f5d3SJohn Marino if (r >= 0) {
140086d7f5d3SJohn Marino keyslot = r;
140186d7f5d3SJohn Marino r = dm_resume_and_reinstate_key(name, mk->keyLength, mk->key);
140286d7f5d3SJohn Marino if (r)
140386d7f5d3SJohn Marino log_err(cd, "Error during resuming device %s.\n", name);
140486d7f5d3SJohn Marino } else
140586d7f5d3SJohn Marino r = keyslot;
140686d7f5d3SJohn Marino out:
140786d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
140886d7f5d3SJohn Marino return r < 0 ? r : keyslot;
140986d7f5d3SJohn Marino }
141086d7f5d3SJohn Marino
141186d7f5d3SJohn Marino // slot manipulation
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)141286d7f5d3SJohn Marino int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
141386d7f5d3SJohn Marino int keyslot, // -1 any
141486d7f5d3SJohn Marino const char *passphrase, // NULL -> terminal
141586d7f5d3SJohn Marino size_t passphrase_size,
141686d7f5d3SJohn Marino const char *new_passphrase, // NULL -> terminal
141786d7f5d3SJohn Marino size_t new_passphrase_size)
141886d7f5d3SJohn Marino {
141986d7f5d3SJohn Marino struct luks_masterkey *mk = NULL;
142086d7f5d3SJohn Marino char *password = NULL, *new_password = NULL;
142186d7f5d3SJohn Marino unsigned int passwordLen, new_passwordLen;
142286d7f5d3SJohn Marino int r;
142386d7f5d3SJohn Marino
142486d7f5d3SJohn Marino log_dbg("Adding new keyslot, existing passphrase %sprovided,"
142586d7f5d3SJohn Marino "new passphrase %sprovided.",
142686d7f5d3SJohn Marino passphrase ? "" : "not ", new_passphrase ? "" : "not ");
142786d7f5d3SJohn Marino
142886d7f5d3SJohn Marino if (!isLUKS(cd->type)) {
142986d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
143086d7f5d3SJohn Marino return -EINVAL;
143186d7f5d3SJohn Marino }
143286d7f5d3SJohn Marino
143386d7f5d3SJohn Marino r = keyslot_verify_or_find_empty(cd, &keyslot);
143486d7f5d3SJohn Marino if (r)
143586d7f5d3SJohn Marino return r;
143686d7f5d3SJohn Marino
143786d7f5d3SJohn Marino if (!LUKS_keyslot_active_count(&cd->hdr)) {
143886d7f5d3SJohn Marino /* No slots used, try to use pre-generated key in header */
143986d7f5d3SJohn Marino if (cd->volume_key) {
144086d7f5d3SJohn Marino mk = LUKS_alloc_masterkey(cd->volume_key->keyLength, cd->volume_key->key);
144186d7f5d3SJohn Marino r = mk ? 0 : -ENOMEM;
144286d7f5d3SJohn Marino } else {
144386d7f5d3SJohn Marino log_err(cd, _("Cannot add key slot, all slots disabled and no volume key provided.\n"));
144486d7f5d3SJohn Marino return -EINVAL;
144586d7f5d3SJohn Marino }
144686d7f5d3SJohn Marino } else if (passphrase) {
144786d7f5d3SJohn Marino /* Passphrase provided, use it to unlock existing keyslot */
144886d7f5d3SJohn Marino r = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT, passphrase,
144986d7f5d3SJohn Marino passphrase_size, &cd->hdr, &mk, cd);
145086d7f5d3SJohn Marino } else {
145186d7f5d3SJohn Marino /* Passphrase not provided, ask first and use it to unlock existing keyslot */
145286d7f5d3SJohn Marino key_from_terminal(cd, _("Enter any passphrase: "),
145386d7f5d3SJohn Marino &password, &passwordLen, 0);
145486d7f5d3SJohn Marino if (!password) {
145586d7f5d3SJohn Marino r = -EINVAL;
145686d7f5d3SJohn Marino goto out;
145786d7f5d3SJohn Marino }
145886d7f5d3SJohn Marino
145986d7f5d3SJohn Marino r = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT, password,
146086d7f5d3SJohn Marino passwordLen, &cd->hdr, &mk, cd);
146186d7f5d3SJohn Marino safe_free(password);
146286d7f5d3SJohn Marino }
146386d7f5d3SJohn Marino
146486d7f5d3SJohn Marino if(r < 0)
146586d7f5d3SJohn Marino goto out;
146686d7f5d3SJohn Marino
146786d7f5d3SJohn Marino if (new_passphrase) {
146886d7f5d3SJohn Marino new_password = (char *)new_passphrase;
146986d7f5d3SJohn Marino new_passwordLen = new_passphrase_size;
147086d7f5d3SJohn Marino } else {
147186d7f5d3SJohn Marino key_from_terminal(cd, _("Enter new passphrase for key slot: "),
147286d7f5d3SJohn Marino &new_password, &new_passwordLen, 1);
147386d7f5d3SJohn Marino if(!new_password) {
147486d7f5d3SJohn Marino r = -EINVAL;
147586d7f5d3SJohn Marino goto out;
147686d7f5d3SJohn Marino }
147786d7f5d3SJohn Marino }
147886d7f5d3SJohn Marino
147986d7f5d3SJohn Marino r = LUKS_set_key(cd->device, keyslot, new_password, new_passwordLen,
148086d7f5d3SJohn Marino &cd->hdr, mk, cd->iteration_time, &cd->PBKDF2_per_sec, cd);
148186d7f5d3SJohn Marino if(r < 0) goto out;
148286d7f5d3SJohn Marino
148386d7f5d3SJohn Marino r = 0;
148486d7f5d3SJohn Marino out:
148586d7f5d3SJohn Marino if (!new_passphrase)
148686d7f5d3SJohn Marino safe_free(new_password);
148786d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
148886d7f5d3SJohn Marino return r ?: keyslot;
148986d7f5d3SJohn Marino }
149086d7f5d3SJohn Marino
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)149186d7f5d3SJohn Marino int crypt_keyslot_add_by_keyfile(struct crypt_device *cd,
149286d7f5d3SJohn Marino int keyslot,
149386d7f5d3SJohn Marino const char *keyfile,
149486d7f5d3SJohn Marino size_t keyfile_size,
149586d7f5d3SJohn Marino const char *new_keyfile,
149686d7f5d3SJohn Marino size_t new_keyfile_size)
149786d7f5d3SJohn Marino {
149886d7f5d3SJohn Marino struct luks_masterkey *mk=NULL;
149986d7f5d3SJohn Marino char *password=NULL; unsigned int passwordLen;
150086d7f5d3SJohn Marino char *new_password = NULL; unsigned int new_passwordLen;
150186d7f5d3SJohn Marino int r;
150286d7f5d3SJohn Marino
150386d7f5d3SJohn Marino log_dbg("Adding new keyslot, existing keyfile %s, new keyfile %s.",
150486d7f5d3SJohn Marino keyfile ?: "[none]", new_keyfile ?: "[none]");
150586d7f5d3SJohn Marino
150686d7f5d3SJohn Marino if (!isLUKS(cd->type)) {
150786d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
150886d7f5d3SJohn Marino return -EINVAL;
150986d7f5d3SJohn Marino }
151086d7f5d3SJohn Marino
151186d7f5d3SJohn Marino r = keyslot_verify_or_find_empty(cd, &keyslot);
151286d7f5d3SJohn Marino if (r)
151386d7f5d3SJohn Marino return r;
151486d7f5d3SJohn Marino
151586d7f5d3SJohn Marino if (!LUKS_keyslot_active_count(&cd->hdr)) {
151686d7f5d3SJohn Marino /* No slots used, try to use pre-generated key in header */
151786d7f5d3SJohn Marino if (cd->volume_key) {
151886d7f5d3SJohn Marino mk = LUKS_alloc_masterkey(cd->volume_key->keyLength, cd->volume_key->key);
151986d7f5d3SJohn Marino r = mk ? 0 : -ENOMEM;
152086d7f5d3SJohn Marino } else {
152186d7f5d3SJohn Marino log_err(cd, _("Cannot add key slot, all slots disabled and no volume key provided.\n"));
152286d7f5d3SJohn Marino return -EINVAL;
152386d7f5d3SJohn Marino }
152486d7f5d3SJohn Marino } else {
152586d7f5d3SJohn Marino /* Read password from file of (if NULL) from terminal */
152686d7f5d3SJohn Marino if (keyfile)
152786d7f5d3SJohn Marino key_from_file(cd, _("Enter any passphrase: "), &password, &passwordLen,
152886d7f5d3SJohn Marino keyfile, keyfile_size);
152986d7f5d3SJohn Marino else
153086d7f5d3SJohn Marino key_from_terminal(cd, _("Enter any passphrase: "),
153186d7f5d3SJohn Marino &password, &passwordLen, 0);
153286d7f5d3SJohn Marino
153386d7f5d3SJohn Marino if (!password)
153486d7f5d3SJohn Marino return -EINVAL;
153586d7f5d3SJohn Marino
153686d7f5d3SJohn Marino r = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT, password, passwordLen,
153786d7f5d3SJohn Marino &cd->hdr, &mk, cd);
153886d7f5d3SJohn Marino safe_free(password);
153986d7f5d3SJohn Marino }
154086d7f5d3SJohn Marino
154186d7f5d3SJohn Marino if(r < 0)
154286d7f5d3SJohn Marino goto out;
154386d7f5d3SJohn Marino
154486d7f5d3SJohn Marino if (new_keyfile)
154586d7f5d3SJohn Marino key_from_file(cd, _("Enter new passphrase for key slot: "),
154686d7f5d3SJohn Marino &new_password, &new_passwordLen, new_keyfile,
154786d7f5d3SJohn Marino new_keyfile_size);
154886d7f5d3SJohn Marino else
154986d7f5d3SJohn Marino key_from_terminal(cd, _("Enter new passphrase for key slot: "),
155086d7f5d3SJohn Marino &new_password, &new_passwordLen, 1);
155186d7f5d3SJohn Marino
155286d7f5d3SJohn Marino if(!new_password) {
155386d7f5d3SJohn Marino r = -EINVAL;
155486d7f5d3SJohn Marino goto out;
155586d7f5d3SJohn Marino }
155686d7f5d3SJohn Marino
155786d7f5d3SJohn Marino r = LUKS_set_key(cd->device, keyslot, new_password, new_passwordLen,
155886d7f5d3SJohn Marino &cd->hdr, mk, cd->iteration_time, &cd->PBKDF2_per_sec, cd);
155986d7f5d3SJohn Marino out:
156086d7f5d3SJohn Marino safe_free(new_password);
156186d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
156286d7f5d3SJohn Marino return r < 0 ? r : keyslot;
156386d7f5d3SJohn Marino }
156486d7f5d3SJohn Marino
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)156586d7f5d3SJohn Marino int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
156686d7f5d3SJohn Marino int keyslot,
156786d7f5d3SJohn Marino const char *volume_key,
156886d7f5d3SJohn Marino size_t volume_key_size,
156986d7f5d3SJohn Marino const char *passphrase,
157086d7f5d3SJohn Marino size_t passphrase_size)
157186d7f5d3SJohn Marino {
157286d7f5d3SJohn Marino struct luks_masterkey *mk = NULL;
157386d7f5d3SJohn Marino int r = -EINVAL;
157486d7f5d3SJohn Marino char *new_password = NULL; unsigned int new_passwordLen;
157586d7f5d3SJohn Marino
157686d7f5d3SJohn Marino log_dbg("Adding new keyslot %d using volume key.", keyslot);
157786d7f5d3SJohn Marino
157886d7f5d3SJohn Marino if (!isLUKS(cd->type)) {
157986d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
158086d7f5d3SJohn Marino return -EINVAL;
158186d7f5d3SJohn Marino }
158286d7f5d3SJohn Marino
158386d7f5d3SJohn Marino if (volume_key)
158486d7f5d3SJohn Marino mk = LUKS_alloc_masterkey(volume_key_size, volume_key);
158586d7f5d3SJohn Marino else if (cd->volume_key)
158686d7f5d3SJohn Marino mk = LUKS_alloc_masterkey(cd->volume_key->keyLength, cd->volume_key->key);
158786d7f5d3SJohn Marino
158886d7f5d3SJohn Marino if (!mk)
158986d7f5d3SJohn Marino return -ENOMEM;
159086d7f5d3SJohn Marino
159186d7f5d3SJohn Marino r = LUKS_verify_master_key(&cd->hdr, mk);
159286d7f5d3SJohn Marino if (r < 0) {
159386d7f5d3SJohn Marino log_err(cd, _("Volume key does not match the volume.\n"));
159486d7f5d3SJohn Marino goto out;
159586d7f5d3SJohn Marino }
159686d7f5d3SJohn Marino
159786d7f5d3SJohn Marino r = keyslot_verify_or_find_empty(cd, &keyslot);
159886d7f5d3SJohn Marino if (r)
159986d7f5d3SJohn Marino goto out;
160086d7f5d3SJohn Marino
160186d7f5d3SJohn Marino if (!passphrase) {
160286d7f5d3SJohn Marino key_from_terminal(cd, _("Enter new passphrase for key slot: "),
160386d7f5d3SJohn Marino &new_password, &new_passwordLen, 1);
160486d7f5d3SJohn Marino passphrase = new_password;
160586d7f5d3SJohn Marino passphrase_size = new_passwordLen;
160686d7f5d3SJohn Marino }
160786d7f5d3SJohn Marino
160886d7f5d3SJohn Marino r = LUKS_set_key(cd->device, keyslot, passphrase, passphrase_size,
160986d7f5d3SJohn Marino &cd->hdr, mk, cd->iteration_time, &cd->PBKDF2_per_sec, cd);
161086d7f5d3SJohn Marino out:
161186d7f5d3SJohn Marino if (new_password)
161286d7f5d3SJohn Marino safe_free(new_password);
161386d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
161486d7f5d3SJohn Marino return r ?: keyslot;
161586d7f5d3SJohn Marino }
161686d7f5d3SJohn Marino
crypt_keyslot_destroy(struct crypt_device * cd,int keyslot)161786d7f5d3SJohn Marino int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot)
161886d7f5d3SJohn Marino {
161986d7f5d3SJohn Marino crypt_keyslot_info ki;
162086d7f5d3SJohn Marino
162186d7f5d3SJohn Marino log_dbg("Destroying keyslot %d.", keyslot);
162286d7f5d3SJohn Marino
162386d7f5d3SJohn Marino if (!isLUKS(cd->type)) {
162486d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
162586d7f5d3SJohn Marino return -EINVAL;
162686d7f5d3SJohn Marino }
162786d7f5d3SJohn Marino
162886d7f5d3SJohn Marino ki = crypt_keyslot_status(cd, keyslot);
162986d7f5d3SJohn Marino if (ki == CRYPT_SLOT_INVALID) {
163086d7f5d3SJohn Marino log_err(cd, _("Key slot %d is invalid.\n"), keyslot);
163186d7f5d3SJohn Marino return -EINVAL;
163286d7f5d3SJohn Marino }
163386d7f5d3SJohn Marino
163486d7f5d3SJohn Marino if (ki == CRYPT_SLOT_INACTIVE) {
163586d7f5d3SJohn Marino log_err(cd, _("Key slot %d is not used.\n"), keyslot);
163686d7f5d3SJohn Marino return -EINVAL;
163786d7f5d3SJohn Marino }
163886d7f5d3SJohn Marino
163986d7f5d3SJohn Marino return LUKS_del_key(cd->device, keyslot, &cd->hdr, cd);
164086d7f5d3SJohn Marino }
164186d7f5d3SJohn Marino
164286d7f5d3SJohn Marino // activation/deactivation of device mapping
crypt_activate_by_passphrase(struct crypt_device * cd,const char * name,int keyslot,const char * passphrase,size_t passphrase_size,uint32_t flags)164386d7f5d3SJohn Marino int crypt_activate_by_passphrase(struct crypt_device *cd,
164486d7f5d3SJohn Marino const char *name,
164586d7f5d3SJohn Marino int keyslot,
164686d7f5d3SJohn Marino const char *passphrase,
164786d7f5d3SJohn Marino size_t passphrase_size,
164886d7f5d3SJohn Marino uint32_t flags)
164986d7f5d3SJohn Marino {
165086d7f5d3SJohn Marino crypt_status_info ci;
165186d7f5d3SJohn Marino struct luks_masterkey *mk = NULL;
165286d7f5d3SJohn Marino char *prompt = NULL;
165386d7f5d3SJohn Marino int r;
165486d7f5d3SJohn Marino
165586d7f5d3SJohn Marino log_dbg("%s volume %s [keyslot %d] using %spassphrase.",
165686d7f5d3SJohn Marino name ? "Activating" : "Checking", name ?: "",
165786d7f5d3SJohn Marino keyslot, passphrase ? "" : "[none] ");
165886d7f5d3SJohn Marino
165986d7f5d3SJohn Marino if (!name)
166086d7f5d3SJohn Marino return -EINVAL;
166186d7f5d3SJohn Marino
166286d7f5d3SJohn Marino /* plain, use hashed passphrase */
166386d7f5d3SJohn Marino if (isPLAIN(cd->type))
166486d7f5d3SJohn Marino return create_device_helper(cd, name, cd->plain_hdr.hash,
166586d7f5d3SJohn Marino cd->plain_cipher, cd->plain_cipher_mode, NULL, passphrase, passphrase_size,
166686d7f5d3SJohn Marino cd->volume_key->keyLength, 0, cd->plain_hdr.skip,
166786d7f5d3SJohn Marino cd->plain_hdr.offset, cd->plain_uuid, flags & CRYPT_ACTIVATE_READONLY, 0, 0);
166886d7f5d3SJohn Marino
166986d7f5d3SJohn Marino if (name) {
167086d7f5d3SJohn Marino ci = crypt_status(NULL, name);
167186d7f5d3SJohn Marino if (ci == CRYPT_INVALID)
167286d7f5d3SJohn Marino return -EINVAL;
167386d7f5d3SJohn Marino else if (ci >= CRYPT_ACTIVE) {
167486d7f5d3SJohn Marino log_err(cd, _("Device %s already exists.\n"), name);
167586d7f5d3SJohn Marino return -EEXIST;
167686d7f5d3SJohn Marino }
167786d7f5d3SJohn Marino }
167886d7f5d3SJohn Marino
167986d7f5d3SJohn Marino if(asprintf(&prompt, _("Enter passphrase for %s: "), cd->device) < 0)
168086d7f5d3SJohn Marino return -ENOMEM;
168186d7f5d3SJohn Marino
168286d7f5d3SJohn Marino /* provided passphrase, do not retry */
168386d7f5d3SJohn Marino if (passphrase) {
168486d7f5d3SJohn Marino r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase,
168586d7f5d3SJohn Marino passphrase_size, &cd->hdr, &mk, cd);
168686d7f5d3SJohn Marino } else
168786d7f5d3SJohn Marino r = volume_key_by_terminal_passphrase(cd, keyslot, &mk);
168886d7f5d3SJohn Marino
168986d7f5d3SJohn Marino if (r >= 0) {
169086d7f5d3SJohn Marino keyslot = r;
169186d7f5d3SJohn Marino if (name)
169286d7f5d3SJohn Marino r = open_from_hdr_and_mk(cd, mk, name, flags);
169386d7f5d3SJohn Marino }
169486d7f5d3SJohn Marino
169586d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
169686d7f5d3SJohn Marino free(prompt);
169786d7f5d3SJohn Marino
169886d7f5d3SJohn Marino return r < 0 ? r : keyslot;
169986d7f5d3SJohn Marino }
170086d7f5d3SJohn Marino
crypt_activate_by_keyfile(struct crypt_device * cd,const char * name,int keyslot,const char * keyfile,size_t keyfile_size,uint32_t flags)170186d7f5d3SJohn Marino int crypt_activate_by_keyfile(struct crypt_device *cd,
170286d7f5d3SJohn Marino const char *name,
170386d7f5d3SJohn Marino int keyslot,
170486d7f5d3SJohn Marino const char *keyfile,
170586d7f5d3SJohn Marino size_t keyfile_size,
170686d7f5d3SJohn Marino uint32_t flags)
170786d7f5d3SJohn Marino {
170886d7f5d3SJohn Marino crypt_status_info ci;
170986d7f5d3SJohn Marino struct luks_masterkey *mk = NULL;
171086d7f5d3SJohn Marino char *passphrase_read = NULL;
171186d7f5d3SJohn Marino unsigned int passphrase_size_read;
171286d7f5d3SJohn Marino int r;
171386d7f5d3SJohn Marino
171486d7f5d3SJohn Marino log_dbg("Activating volume %s [keyslot %d] using keyfile %s.",
171586d7f5d3SJohn Marino name, keyslot, keyfile ?: "[none]");
171686d7f5d3SJohn Marino
171786d7f5d3SJohn Marino if (!isLUKS(cd->type)) {
171886d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
171986d7f5d3SJohn Marino return -EINVAL;
172086d7f5d3SJohn Marino }
172186d7f5d3SJohn Marino
172286d7f5d3SJohn Marino if (name) {
172386d7f5d3SJohn Marino ci = crypt_status(NULL, name);
172486d7f5d3SJohn Marino if (ci == CRYPT_INVALID)
172586d7f5d3SJohn Marino return -EINVAL;
172686d7f5d3SJohn Marino else if (ci >= CRYPT_ACTIVE) {
172786d7f5d3SJohn Marino log_err(cd, _("Device %s already exists.\n"), name);
172886d7f5d3SJohn Marino return -EEXIST;
172986d7f5d3SJohn Marino }
173086d7f5d3SJohn Marino }
173186d7f5d3SJohn Marino
173286d7f5d3SJohn Marino if (!keyfile)
173386d7f5d3SJohn Marino return -EINVAL;
173486d7f5d3SJohn Marino
173586d7f5d3SJohn Marino key_from_file(cd, _("Enter passphrase: "), &passphrase_read,
173686d7f5d3SJohn Marino &passphrase_size_read, keyfile, keyfile_size);
173786d7f5d3SJohn Marino if(!passphrase_read)
173886d7f5d3SJohn Marino r = -EINVAL;
173986d7f5d3SJohn Marino else {
174086d7f5d3SJohn Marino r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase_read,
174186d7f5d3SJohn Marino passphrase_size_read, &cd->hdr, &mk, cd);
174286d7f5d3SJohn Marino safe_free(passphrase_read);
174386d7f5d3SJohn Marino }
174486d7f5d3SJohn Marino
174586d7f5d3SJohn Marino if (r >= 0) {
174686d7f5d3SJohn Marino keyslot = r;
174786d7f5d3SJohn Marino r = open_from_hdr_and_mk(cd, mk, name, flags);
174886d7f5d3SJohn Marino }
174986d7f5d3SJohn Marino
175086d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
175186d7f5d3SJohn Marino
175286d7f5d3SJohn Marino return r < 0 ? r : keyslot;
175386d7f5d3SJohn Marino }
175486d7f5d3SJohn Marino
crypt_activate_by_volume_key(struct crypt_device * cd,const char * name,const char * volume_key,size_t volume_key_size,uint32_t flags)175586d7f5d3SJohn Marino int crypt_activate_by_volume_key(struct crypt_device *cd,
175686d7f5d3SJohn Marino const char *name,
175786d7f5d3SJohn Marino const char *volume_key,
175886d7f5d3SJohn Marino size_t volume_key_size,
175986d7f5d3SJohn Marino uint32_t flags)
176086d7f5d3SJohn Marino {
176186d7f5d3SJohn Marino crypt_status_info ci;
176286d7f5d3SJohn Marino struct luks_masterkey *mk;
176386d7f5d3SJohn Marino int r;
176486d7f5d3SJohn Marino
176586d7f5d3SJohn Marino log_dbg("Activating volume %s by volume key.", name);
176686d7f5d3SJohn Marino
176786d7f5d3SJohn Marino /* use key directly, no hash */
176886d7f5d3SJohn Marino if (isPLAIN(cd->type))
176986d7f5d3SJohn Marino return create_device_helper(cd, name, NULL,
177086d7f5d3SJohn Marino cd->plain_cipher, cd->plain_cipher_mode, NULL, volume_key, volume_key_size,
177186d7f5d3SJohn Marino cd->volume_key->keyLength, 0, cd->plain_hdr.skip,
177286d7f5d3SJohn Marino cd->plain_hdr.offset, cd->plain_uuid, flags & CRYPT_ACTIVATE_READONLY, 0, 0);
177386d7f5d3SJohn Marino
177486d7f5d3SJohn Marino if (!isLUKS(cd->type)) {
177586d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
177686d7f5d3SJohn Marino return -EINVAL;
177786d7f5d3SJohn Marino }
177886d7f5d3SJohn Marino
177986d7f5d3SJohn Marino if (name) {
178086d7f5d3SJohn Marino ci = crypt_status(NULL, name);
178186d7f5d3SJohn Marino if (ci == CRYPT_INVALID)
178286d7f5d3SJohn Marino return -EINVAL;
178386d7f5d3SJohn Marino else if (ci >= CRYPT_ACTIVE) {
178486d7f5d3SJohn Marino log_err(cd, _("Device %s already exists.\n"), name);
178586d7f5d3SJohn Marino return -EEXIST;
178686d7f5d3SJohn Marino }
178786d7f5d3SJohn Marino }
178886d7f5d3SJohn Marino
178986d7f5d3SJohn Marino mk = LUKS_alloc_masterkey(volume_key_size, volume_key);
179086d7f5d3SJohn Marino if (!mk)
179186d7f5d3SJohn Marino return -ENOMEM;
179286d7f5d3SJohn Marino r = LUKS_verify_master_key(&cd->hdr, mk);
179386d7f5d3SJohn Marino
179486d7f5d3SJohn Marino if (r == -EPERM)
179586d7f5d3SJohn Marino log_err(cd, _("Volume key does not match the volume.\n"));
179686d7f5d3SJohn Marino
179786d7f5d3SJohn Marino if (!r && name)
179886d7f5d3SJohn Marino r = open_from_hdr_and_mk(cd, mk, name, flags);
179986d7f5d3SJohn Marino
180086d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
180186d7f5d3SJohn Marino
180286d7f5d3SJohn Marino return r;
180386d7f5d3SJohn Marino }
180486d7f5d3SJohn Marino
crypt_deactivate(struct crypt_device * cd,const char * name)180586d7f5d3SJohn Marino int crypt_deactivate(struct crypt_device *cd, const char *name)
180686d7f5d3SJohn Marino {
180786d7f5d3SJohn Marino int r;
180886d7f5d3SJohn Marino
180986d7f5d3SJohn Marino if (!name)
181086d7f5d3SJohn Marino return -EINVAL;
181186d7f5d3SJohn Marino
181286d7f5d3SJohn Marino log_dbg("Deactivating volume %s.", name);
181386d7f5d3SJohn Marino
181486d7f5d3SJohn Marino if (!cd && dm_init(NULL, 1) < 0)
181586d7f5d3SJohn Marino return -ENOSYS;
181686d7f5d3SJohn Marino
181786d7f5d3SJohn Marino switch (crypt_status(cd, name)) {
181886d7f5d3SJohn Marino case CRYPT_ACTIVE:
181986d7f5d3SJohn Marino r = dm_remove_device(name, 0, 0);
182086d7f5d3SJohn Marino break;
182186d7f5d3SJohn Marino case CRYPT_BUSY:
182286d7f5d3SJohn Marino log_err(cd, _("Device %s is busy.\n"), name);
182386d7f5d3SJohn Marino r = -EBUSY;
182486d7f5d3SJohn Marino break;
182586d7f5d3SJohn Marino case CRYPT_INACTIVE:
182686d7f5d3SJohn Marino log_err(cd, _("Device %s is not active.\n"), name);
182786d7f5d3SJohn Marino r = -ENODEV;
182886d7f5d3SJohn Marino break;
182986d7f5d3SJohn Marino default:
183086d7f5d3SJohn Marino log_err(cd, _("Invalid device %s.\n"), name);
183186d7f5d3SJohn Marino r = -EINVAL;
183286d7f5d3SJohn Marino }
183386d7f5d3SJohn Marino
183486d7f5d3SJohn Marino if (!cd)
183586d7f5d3SJohn Marino dm_exit();
183686d7f5d3SJohn Marino
183786d7f5d3SJohn Marino return r;
183886d7f5d3SJohn Marino }
183986d7f5d3SJohn Marino
184086d7f5d3SJohn Marino // misc helper functions
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)184186d7f5d3SJohn Marino int crypt_volume_key_get(struct crypt_device *cd,
184286d7f5d3SJohn Marino int keyslot,
184386d7f5d3SJohn Marino char *volume_key,
184486d7f5d3SJohn Marino size_t *volume_key_size,
184586d7f5d3SJohn Marino const char *passphrase,
184686d7f5d3SJohn Marino size_t passphrase_size)
184786d7f5d3SJohn Marino {
184886d7f5d3SJohn Marino struct luks_masterkey *mk;
184986d7f5d3SJohn Marino char *processed_key = NULL;
185086d7f5d3SJohn Marino int r, key_len;
185186d7f5d3SJohn Marino
185286d7f5d3SJohn Marino key_len = crypt_get_volume_key_size(cd);
185386d7f5d3SJohn Marino if (key_len > *volume_key_size) {
185486d7f5d3SJohn Marino log_err(cd, _("Volume key buffer too small.\n"));
185586d7f5d3SJohn Marino return -ENOMEM;
185686d7f5d3SJohn Marino }
185786d7f5d3SJohn Marino
185886d7f5d3SJohn Marino if (isPLAIN(cd->type) && cd->plain_hdr.hash) {
185986d7f5d3SJohn Marino processed_key = process_key(cd, cd->plain_hdr.hash, NULL, key_len,
186086d7f5d3SJohn Marino passphrase, passphrase_size);
186186d7f5d3SJohn Marino if (!processed_key) {
186286d7f5d3SJohn Marino log_err(cd, _("Cannot retrieve volume key for plain device.\n"));
186386d7f5d3SJohn Marino return -EINVAL;
186486d7f5d3SJohn Marino }
186586d7f5d3SJohn Marino memcpy(volume_key, processed_key, key_len);
186686d7f5d3SJohn Marino *volume_key_size = key_len;
186786d7f5d3SJohn Marino safe_free(processed_key);
186886d7f5d3SJohn Marino return 0;
186986d7f5d3SJohn Marino }
187086d7f5d3SJohn Marino
187186d7f5d3SJohn Marino if (isLUKS(cd->type)) {
187286d7f5d3SJohn Marino r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase,
187386d7f5d3SJohn Marino passphrase_size, &cd->hdr, &mk, cd);
187486d7f5d3SJohn Marino
187586d7f5d3SJohn Marino if (r >= 0) {
187686d7f5d3SJohn Marino memcpy(volume_key, mk->key, mk->keyLength);
187786d7f5d3SJohn Marino *volume_key_size = mk->keyLength;
187886d7f5d3SJohn Marino }
187986d7f5d3SJohn Marino
188086d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
188186d7f5d3SJohn Marino return r;
188286d7f5d3SJohn Marino }
188386d7f5d3SJohn Marino
188486d7f5d3SJohn Marino log_err(cd, _("This operation is not supported for %s crypt device.\n"), cd->type ?: "(none)");
188586d7f5d3SJohn Marino return -EINVAL;
188686d7f5d3SJohn Marino }
188786d7f5d3SJohn Marino
crypt_volume_key_verify(struct crypt_device * cd,const char * volume_key,size_t volume_key_size)188886d7f5d3SJohn Marino int crypt_volume_key_verify(struct crypt_device *cd,
188986d7f5d3SJohn Marino const char *volume_key,
189086d7f5d3SJohn Marino size_t volume_key_size)
189186d7f5d3SJohn Marino {
189286d7f5d3SJohn Marino struct luks_masterkey *mk;
189386d7f5d3SJohn Marino int r;
189486d7f5d3SJohn Marino
189586d7f5d3SJohn Marino if (!isLUKS(cd->type)) {
189686d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
189786d7f5d3SJohn Marino return -EINVAL;
189886d7f5d3SJohn Marino }
189986d7f5d3SJohn Marino
190086d7f5d3SJohn Marino mk = LUKS_alloc_masterkey(volume_key_size, volume_key);
190186d7f5d3SJohn Marino if (!mk)
190286d7f5d3SJohn Marino return -ENOMEM;
190386d7f5d3SJohn Marino
190486d7f5d3SJohn Marino r = LUKS_verify_master_key(&cd->hdr, mk);
190586d7f5d3SJohn Marino
190686d7f5d3SJohn Marino if (r == -EPERM)
190786d7f5d3SJohn Marino log_err(cd, _("Volume key does not match the volume.\n"));
190886d7f5d3SJohn Marino
190986d7f5d3SJohn Marino LUKS_dealloc_masterkey(mk);
191086d7f5d3SJohn Marino
191186d7f5d3SJohn Marino return r;
191286d7f5d3SJohn Marino }
191386d7f5d3SJohn Marino
crypt_set_timeout(struct crypt_device * cd,uint64_t timeout_sec)191486d7f5d3SJohn Marino void crypt_set_timeout(struct crypt_device *cd, uint64_t timeout_sec)
191586d7f5d3SJohn Marino {
191686d7f5d3SJohn Marino log_dbg("Timeout set to %" PRIu64 " miliseconds.", timeout_sec);
191786d7f5d3SJohn Marino cd->timeout = timeout_sec;
191886d7f5d3SJohn Marino }
191986d7f5d3SJohn Marino
crypt_set_password_retry(struct crypt_device * cd,int tries)192086d7f5d3SJohn Marino void crypt_set_password_retry(struct crypt_device *cd, int tries)
192186d7f5d3SJohn Marino {
192286d7f5d3SJohn Marino log_dbg("Password retry count set to %d.", tries);
192386d7f5d3SJohn Marino cd->tries = tries;
192486d7f5d3SJohn Marino }
192586d7f5d3SJohn Marino
crypt_set_iterarion_time(struct crypt_device * cd,uint64_t iteration_time_ms)192686d7f5d3SJohn Marino void crypt_set_iterarion_time(struct crypt_device *cd, uint64_t iteration_time_ms)
192786d7f5d3SJohn Marino {
192886d7f5d3SJohn Marino log_dbg("Iteration time set to %" PRIu64 " miliseconds.", iteration_time_ms);
192986d7f5d3SJohn Marino cd->iteration_time = iteration_time_ms;
193086d7f5d3SJohn Marino }
193186d7f5d3SJohn Marino
crypt_set_password_verify(struct crypt_device * cd,int password_verify)193286d7f5d3SJohn Marino void crypt_set_password_verify(struct crypt_device *cd, int password_verify)
193386d7f5d3SJohn Marino {
193486d7f5d3SJohn Marino log_dbg("Password verification %s.", password_verify ? "enabled" : "disabled");
193586d7f5d3SJohn Marino cd->password_verify = password_verify ? 1 : 0;
193686d7f5d3SJohn Marino }
193786d7f5d3SJohn Marino
crypt_memory_lock(struct crypt_device * cd,int lock)193886d7f5d3SJohn Marino int crypt_memory_lock(struct crypt_device *cd, int lock)
193986d7f5d3SJohn Marino {
194086d7f5d3SJohn Marino return lock ? crypt_memlock_inc(cd) : crypt_memlock_dec(cd);
194186d7f5d3SJohn Marino }
194286d7f5d3SJohn Marino
194386d7f5d3SJohn Marino // reporting
crypt_status(struct crypt_device * cd,const char * name)194486d7f5d3SJohn Marino crypt_status_info crypt_status(struct crypt_device *cd, const char *name)
194586d7f5d3SJohn Marino {
194686d7f5d3SJohn Marino int r;
194786d7f5d3SJohn Marino
194886d7f5d3SJohn Marino if (!cd && dm_init(NULL, 1) < 0)
194986d7f5d3SJohn Marino return CRYPT_INVALID;
195086d7f5d3SJohn Marino
195186d7f5d3SJohn Marino r = dm_status_device(name);
195286d7f5d3SJohn Marino
195386d7f5d3SJohn Marino if (!cd)
195486d7f5d3SJohn Marino dm_exit();
195586d7f5d3SJohn Marino
195686d7f5d3SJohn Marino if (r < 0 && r != -ENODEV)
195786d7f5d3SJohn Marino return CRYPT_INVALID;
195886d7f5d3SJohn Marino
195986d7f5d3SJohn Marino if (r == 0)
196086d7f5d3SJohn Marino return CRYPT_ACTIVE;
196186d7f5d3SJohn Marino
196286d7f5d3SJohn Marino if (r > 0)
196386d7f5d3SJohn Marino return CRYPT_BUSY;
196486d7f5d3SJohn Marino
196586d7f5d3SJohn Marino return CRYPT_INACTIVE;
196686d7f5d3SJohn Marino }
196786d7f5d3SJohn Marino
hexprintICB(struct crypt_device * cd,char * d,int n)196886d7f5d3SJohn Marino static void hexprintICB(struct crypt_device *cd, char *d, int n)
196986d7f5d3SJohn Marino {
197086d7f5d3SJohn Marino int i;
197186d7f5d3SJohn Marino for(i = 0; i < n; i++)
197286d7f5d3SJohn Marino log_std(cd, "%02hhx ", (char)d[i]);
197386d7f5d3SJohn Marino }
197486d7f5d3SJohn Marino
crypt_dump(struct crypt_device * cd)197586d7f5d3SJohn Marino int crypt_dump(struct crypt_device *cd)
197686d7f5d3SJohn Marino {
197786d7f5d3SJohn Marino int i;
197886d7f5d3SJohn Marino if (!isLUKS(cd->type)) { //FIXME
197986d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
198086d7f5d3SJohn Marino return -EINVAL;
198186d7f5d3SJohn Marino }
198286d7f5d3SJohn Marino
198386d7f5d3SJohn Marino log_std(cd, "LUKS header information for %s\n\n", cd->device);
198486d7f5d3SJohn Marino log_std(cd, "Version: \t%d\n", cd->hdr.version);
198586d7f5d3SJohn Marino log_std(cd, "Cipher name: \t%s\n", cd->hdr.cipherName);
198686d7f5d3SJohn Marino log_std(cd, "Cipher mode: \t%s\n", cd->hdr.cipherMode);
198786d7f5d3SJohn Marino log_std(cd, "Hash spec: \t%s\n", cd->hdr.hashSpec);
198886d7f5d3SJohn Marino log_std(cd, "Payload offset:\t%d\n", cd->hdr.payloadOffset);
198986d7f5d3SJohn Marino log_std(cd, "MK bits: \t%d\n", cd->hdr.keyBytes * 8);
199086d7f5d3SJohn Marino log_std(cd, "MK digest: \t");
199186d7f5d3SJohn Marino hexprintICB(cd, cd->hdr.mkDigest, LUKS_DIGESTSIZE);
199286d7f5d3SJohn Marino log_std(cd, "\n");
199386d7f5d3SJohn Marino log_std(cd, "MK salt: \t");
199486d7f5d3SJohn Marino hexprintICB(cd, cd->hdr.mkDigestSalt, LUKS_SALTSIZE/2);
199586d7f5d3SJohn Marino log_std(cd, "\n \t");
199686d7f5d3SJohn Marino hexprintICB(cd, cd->hdr.mkDigestSalt+LUKS_SALTSIZE/2, LUKS_SALTSIZE/2);
199786d7f5d3SJohn Marino log_std(cd, "\n");
199886d7f5d3SJohn Marino log_std(cd, "MK iterations: \t%d\n", cd->hdr.mkDigestIterations);
199986d7f5d3SJohn Marino log_std(cd, "UUID: \t%s\n\n", cd->hdr.uuid);
200086d7f5d3SJohn Marino for(i = 0; i < LUKS_NUMKEYS; i++) {
200186d7f5d3SJohn Marino if(cd->hdr.keyblock[i].active == LUKS_KEY_ENABLED) {
200286d7f5d3SJohn Marino log_std(cd, "Key Slot %d: ENABLED\n",i);
200386d7f5d3SJohn Marino log_std(cd, "\tIterations: \t%d\n",
200486d7f5d3SJohn Marino cd->hdr.keyblock[i].passwordIterations);
200586d7f5d3SJohn Marino log_std(cd, "\tSalt: \t");
200686d7f5d3SJohn Marino hexprintICB(cd, cd->hdr.keyblock[i].passwordSalt,
200786d7f5d3SJohn Marino LUKS_SALTSIZE/2);
200886d7f5d3SJohn Marino log_std(cd, "\n\t \t");
200986d7f5d3SJohn Marino hexprintICB(cd, cd->hdr.keyblock[i].passwordSalt +
201086d7f5d3SJohn Marino LUKS_SALTSIZE/2, LUKS_SALTSIZE/2);
201186d7f5d3SJohn Marino log_std(cd, "\n");
201286d7f5d3SJohn Marino
201386d7f5d3SJohn Marino log_std(cd, "\tKey material offset:\t%d\n",
201486d7f5d3SJohn Marino cd->hdr.keyblock[i].keyMaterialOffset);
201586d7f5d3SJohn Marino log_std(cd, "\tAF stripes: \t%d\n",
201686d7f5d3SJohn Marino cd->hdr.keyblock[i].stripes);
201786d7f5d3SJohn Marino }
201886d7f5d3SJohn Marino else
201986d7f5d3SJohn Marino log_std(cd, "Key Slot %d: DISABLED\n", i);
202086d7f5d3SJohn Marino }
202186d7f5d3SJohn Marino return 0;
202286d7f5d3SJohn Marino }
202386d7f5d3SJohn Marino
crypt_get_cipher(struct crypt_device * cd)202486d7f5d3SJohn Marino const char *crypt_get_cipher(struct crypt_device *cd)
202586d7f5d3SJohn Marino {
202686d7f5d3SJohn Marino if (isPLAIN(cd->type))
202786d7f5d3SJohn Marino return cd->plain_cipher;
202886d7f5d3SJohn Marino
202986d7f5d3SJohn Marino if (isLUKS(cd->type))
203086d7f5d3SJohn Marino return cd->hdr.cipherName;
203186d7f5d3SJohn Marino
203286d7f5d3SJohn Marino return NULL;
203386d7f5d3SJohn Marino }
203486d7f5d3SJohn Marino
crypt_get_cipher_mode(struct crypt_device * cd)203586d7f5d3SJohn Marino const char *crypt_get_cipher_mode(struct crypt_device *cd)
203686d7f5d3SJohn Marino {
203786d7f5d3SJohn Marino if (isPLAIN(cd->type))
203886d7f5d3SJohn Marino return cd->plain_cipher_mode;
203986d7f5d3SJohn Marino
204086d7f5d3SJohn Marino if (isLUKS(cd->type))
204186d7f5d3SJohn Marino return cd->hdr.cipherMode;
204286d7f5d3SJohn Marino
204386d7f5d3SJohn Marino return NULL;
204486d7f5d3SJohn Marino }
204586d7f5d3SJohn Marino
crypt_get_uuid(struct crypt_device * cd)204686d7f5d3SJohn Marino const char *crypt_get_uuid(struct crypt_device *cd)
204786d7f5d3SJohn Marino {
204886d7f5d3SJohn Marino if (isLUKS(cd->type))
204986d7f5d3SJohn Marino return cd->hdr.uuid;
205086d7f5d3SJohn Marino
205186d7f5d3SJohn Marino return NULL;
205286d7f5d3SJohn Marino }
205386d7f5d3SJohn Marino
crypt_get_volume_key_size(struct crypt_device * cd)205486d7f5d3SJohn Marino int crypt_get_volume_key_size(struct crypt_device *cd)
205586d7f5d3SJohn Marino {
205686d7f5d3SJohn Marino if (isPLAIN(cd->type))
205786d7f5d3SJohn Marino return cd->volume_key->keyLength;
205886d7f5d3SJohn Marino
205986d7f5d3SJohn Marino if (isLUKS(cd->type))
206086d7f5d3SJohn Marino return cd->hdr.keyBytes;
206186d7f5d3SJohn Marino
206286d7f5d3SJohn Marino return 0;
206386d7f5d3SJohn Marino }
206486d7f5d3SJohn Marino
crypt_get_data_offset(struct crypt_device * cd)206586d7f5d3SJohn Marino uint64_t crypt_get_data_offset(struct crypt_device *cd)
206686d7f5d3SJohn Marino {
206786d7f5d3SJohn Marino if (isPLAIN(cd->type))
206886d7f5d3SJohn Marino return cd->plain_hdr.offset;
206986d7f5d3SJohn Marino
207086d7f5d3SJohn Marino if (isLUKS(cd->type))
207186d7f5d3SJohn Marino return cd->hdr.payloadOffset;
207286d7f5d3SJohn Marino
207386d7f5d3SJohn Marino return 0;
207486d7f5d3SJohn Marino }
207586d7f5d3SJohn Marino
crypt_keyslot_status(struct crypt_device * cd,int keyslot)207686d7f5d3SJohn Marino crypt_keyslot_info crypt_keyslot_status(struct crypt_device *cd, int keyslot)
207786d7f5d3SJohn Marino {
207886d7f5d3SJohn Marino if (!isLUKS(cd->type)) {
207986d7f5d3SJohn Marino log_err(cd, _("This operation is supported only for LUKS device.\n"));
208086d7f5d3SJohn Marino return CRYPT_SLOT_INVALID;
208186d7f5d3SJohn Marino }
208286d7f5d3SJohn Marino
208386d7f5d3SJohn Marino return LUKS_keyslot_info(&cd->hdr, keyslot);
208486d7f5d3SJohn Marino }
2085