static int create_new_header(struct reenc_ctx *rc, const char *cipher, const char *cipher_mode, const char *uuid, const char *key, int key_size, struct crypt_params_luks1 *params) { struct crypt_device *cd_new = NULL; int i, r; if ((r = crypt_init(&cd_new, rc->header_file_new))) goto out; if (opt_random) crypt_set_rng_type(cd_new, CRYPT_RNG_RANDOM); else if (opt_urandom) crypt_set_rng_type(cd_new, CRYPT_RNG_URANDOM); if (opt_iteration_time) crypt_set_iteration_time(cd_new, opt_iteration_time); if ((r = crypt_format(cd_new, CRYPT_LUKS1, cipher, cipher_mode, uuid, key, key_size, params))) goto out; log_verbose(_("New LUKS header for device %s created.\n"), rc->device); for (i = 0; i < MAX_SLOT; i++) { if (!rc->p[i].password) continue; if ((r = crypt_keyslot_add_by_volume_key(cd_new, i, NULL, 0, rc->p[i].password, rc->p[i].passwordLen)) < 0) goto out; log_verbose(_("Activated keyslot %i.\n"), r); r = 0; } out: crypt_free(cd_new); return r; }
static int format_and_add_keyslots(const char *path) { struct crypt_device *cd; struct crypt_params_luks1 params; int r; /* * crypt_init() call precedes most of operations of cryptsetup API. The call is used * to initialize crypt device context stored in structure referenced by _cd_ in * the example. Second parameter is used to pass underlaying device path. * * Note: * If path refers to a regular file it'll be attached to a first free loop device. * crypt_init() operation fails in case there's no more loop device available. * Also, loop device will have the AUTOCLEAR flag set, so the file loopback will * be detached automatically. */ r = crypt_init(&cd, path); if (r < 0 ) { printf("crypt_init() failed for %s.\n", path); return r; } printf("Context is attached to block device %s.\n", crypt_get_device_name(cd)); /* * So far no data were written on your device. This will change with call of * crypt_format() only if you specify CRYPT_LUKS1 as device type. */ printf("Device %s will be formatted to LUKS device after 5 seconds.\n" "Press CTRL+C now if you want to cancel this operation.\n", path); sleep(5); /* * Prepare LUKS format parameters * * hash parameter defines PBKDF2 hash algorithm used in LUKS header. * For compatibility reason we use SHA1 here. */ params.hash = "sha1"; /* * data_alignment parameter is relevant only in case of the luks header * and the payload are both stored on same device. * * if you set data_alignment = 0, cryptsetup will autodetect * data_alignment according to underlaying device topology. */ params.data_alignment = 0; /* * data_device parameter defines that no external device * for luks header will be used */ params.data_device = NULL; /* * NULLs for uuid and volume_key means that these attributes will be * generated during crypt_format(). Volume key is generated with respect * to key size parameter passed to function. * * crypt_format() checks device size (LUKS header must fit there). */ r = crypt_format(cd, /* crypt context */ CRYPT_LUKS1, /* LUKS1 is standard LUKS header */ "aes", /* used cipher */ "xts-plain64", /* used block mode and IV generator*/ NULL, /* generate UUID */ NULL, /* generate volume key from RNG */ 256 / 8, /* 256bit key - here AES-128 in XTS mode, size is in bytes */ ¶ms); /* parameters above */ if(r < 0) { printf("crypt_format() failed on device %s\n", crypt_get_device_name(cd)); crypt_free(cd); return r; } /* * The device now contains LUKS1 header, but there is * no active keyslot with encrypted volume key yet. */ /* * cryptt_kesylot_add_* call stores volume_key in encrypted form into keyslot. * Without keyslot you can't manipulate with LUKS device after the context will be freed. * * To create a new keyslot you need to supply the existing one (to get the volume key from) or * you need to supply the volume key. * * After format, we have volume key stored internally in context so add new keyslot * using this internal volume key. */ r = crypt_keyslot_add_by_volume_key(cd, /* crypt context */ CRYPT_ANY_SLOT, /* just use first free slot */ NULL, /* use internal volume key */ 0, /* unused (size of volume key) */ "foo", /* passphrase - NULL means query*/ 3); /* size of passphrase */ if (r < 0) { printf("Adding keyslot failed.\n"); crypt_free(cd); return r; } printf("The first keyslot is initialized.\n"); /* * Add another keyslot, now using the first keyslot. * It will decrypt volume key from the first keyslot and creates new one with another passphrase. */ r = crypt_keyslot_add_by_passphrase(cd, /* crypt context */ CRYPT_ANY_SLOT, /* just use first free slot */ "foo", 3, /* passphrase for the old keyslot */ "bar", 3); /* passphrase for the new kesylot */ if (r < 0) { printf("Adding keyslot failed.\n"); crypt_free(cd); return r; } printf("The second keyslot is initialized.\n"); crypt_free(cd); return 0; }
/* Create fake header for original device */ static int backup_fake_header(struct reenc_ctx *rc) { struct crypt_device *cd_new = NULL; struct crypt_params_luks1 params = {0}; char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN]; const char *header_file_fake; int r; log_dbg("Creating fake (cipher_null) header for %s device.", (rc->reencrypt_mode == DECRYPT) ? "new" : "original"); header_file_fake = (rc->reencrypt_mode == DECRYPT) ? rc->header_file_new : rc->header_file_org; if (!opt_key_size) opt_key_size = DEFAULT_LUKS1_KEYBITS; if (opt_cipher) { r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode); if (r < 0) { log_err(_("No known cipher specification pattern detected.\n")); goto out; } } r = create_empty_header(header_file_fake, NULL, MAX_BCK_SECTORS); if (r < 0) return r; params.hash = opt_hash ?: DEFAULT_LUKS1_HASH; params.data_alignment = 0; params.data_device = rc->device; r = crypt_init(&cd_new, header_file_fake); if (r < 0) return r; r = crypt_format(cd_new, CRYPT_LUKS1, "cipher_null", "ecb", NO_UUID, NULL, opt_key_size / 8, ¶ms); if (r < 0) goto out; r = crypt_keyslot_add_by_volume_key(cd_new, rc->keyslot, NULL, 0, rc->p[rc->keyslot].password, rc->p[rc->keyslot].passwordLen); if (r < 0) goto out; /* The real header is backup header created in backup_luks_headers() */ if (rc->reencrypt_mode == DECRYPT) goto out; r = create_empty_header(rc->header_file_new, rc->header_file_org, 0); if (r < 0) goto out; params.data_alignment = ROUND_SECTOR(opt_reduce_size); r = create_new_header(rc, opt_cipher ? cipher : DEFAULT_LUKS1_CIPHER, opt_cipher ? cipher_mode : DEFAULT_LUKS1_MODE, NULL, NULL, (opt_key_size ? opt_key_size : DEFAULT_LUKS1_KEYBITS) / 8, ¶ms); out: crypt_free(cd_new); return r; }