/* * LUKS - Linux Unified Key Setup v2, reencryption keyslot handler * * Copyright (C) 2016-2023 Red Hat, Inc. All rights reserved. * Copyright (C) 2016-2023 Ondrej Kozina * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "luks2_internal.h" static int reenc_keyslot_open(struct crypt_device *cd __attribute__((unused)), int keyslot __attribute__((unused)), const char *password __attribute__((unused)), size_t password_len __attribute__((unused)), char *volume_key __attribute__((unused)), size_t volume_key_len __attribute__((unused))) { return -ENOENT; } static json_object *reencrypt_keyslot_area_jobj(struct crypt_device *cd, const struct crypt_params_reencrypt *params, size_t alignment, uint64_t area_offset, uint64_t area_length) { json_object *jobj_area = json_object_new_object(); if (!jobj_area || !params || !params->resilience) return NULL; json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset)); json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length)); json_object_object_add(jobj_area, "type", json_object_new_string(params->resilience)); if (!strcmp(params->resilience, "checksum")) { log_dbg(cd, "Setting reencrypt keyslot for checksum protection."); json_object_object_add(jobj_area, "hash", json_object_new_string(params->hash)); json_object_object_add(jobj_area, "sector_size", json_object_new_int64(alignment)); } else if (!strcmp(params->resilience, "journal")) { log_dbg(cd, "Setting reencrypt keyslot for journal protection."); } else if (!strcmp(params->resilience, "none")) { log_dbg(cd, "Setting reencrypt keyslot for none protection."); } else if (!strcmp(params->resilience, "datashift")) { log_dbg(cd, "Setting reencrypt keyslot for datashift protection."); json_object_object_add(jobj_area, "shift_size", crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT)); } else if (!strcmp(params->resilience, "datashift-checksum")) { log_dbg(cd, "Setting reencrypt keyslot for datashift and checksum protection."); json_object_object_add(jobj_area, "hash", json_object_new_string(params->hash)); json_object_object_add(jobj_area, "sector_size", json_object_new_int64(alignment)); json_object_object_add(jobj_area, "shift_size", crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT)); } else if (!strcmp(params->resilience, "datashift-journal")) { log_dbg(cd, "Setting reencrypt keyslot for datashift and journal protection."); json_object_object_add(jobj_area, "shift_size", crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT)); } else { json_object_put(jobj_area); return NULL; } return jobj_area; } static json_object *reencrypt_keyslot_area_jobj_update_block_size(struct crypt_device *cd, json_object *jobj_area, size_t alignment) { json_object *jobj_type, *jobj_area_new = NULL; if (!jobj_area || !json_object_object_get_ex(jobj_area, "type", &jobj_type) || (strcmp(json_object_get_string(jobj_type), "checksum") && strcmp(json_object_get_string(jobj_type), "datashift-checksum"))) return NULL; if (json_object_copy(jobj_area, &jobj_area_new)) return NULL; log_dbg(cd, "Updating reencrypt resilience checksum block size."); json_object_object_add(jobj_area_new, "sector_size", json_object_new_int64(alignment)); return jobj_area_new; } static int reenc_keyslot_alloc(struct crypt_device *cd, struct luks2_hdr *hdr, int keyslot, const struct crypt_params_reencrypt *params, size_t alignment) { int r; json_object *jobj_keyslots, *jobj_keyslot, *jobj_area; uint64_t area_offset, area_length; log_dbg(cd, "Allocating reencrypt keyslot %d.", keyslot); if (!params || !params->resilience || params->direction > CRYPT_REENCRYPT_BACKWARD) return -EINVAL; if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX) return -ENOMEM; if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots)) return -EINVAL; /* only plain datashift resilience mode does not require additional storage */ if (!strcmp(params->resilience, "datashift")) r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length); else r = LUKS2_find_area_max_gap(cd, hdr, &area_offset, &area_length); if (r < 0) return r; jobj_area = reencrypt_keyslot_area_jobj(cd, params, alignment, area_offset, area_length); if (!jobj_area) return -EINVAL; jobj_keyslot = json_object_new_object(); if (!jobj_keyslot) { json_object_put(jobj_area); return -ENOMEM; } json_object_object_add(jobj_keyslot, "area", jobj_area); json_object_object_add(jobj_keyslot, "type", json_object_new_string("reencrypt")); json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(1)); /* useless but mandatory */ json_object_object_add(jobj_keyslot, "mode", json_object_new_string(crypt_reencrypt_mode_to_str(params->mode))); if (params->direction == CRYPT_REENCRYPT_FORWARD) json_object_object_add(jobj_keyslot, "direction", json_object_new_string("forward")); else json_object_object_add(jobj_keyslot, "direction", json_object_new_string("backward")); json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot); if (LUKS2_check_json_size(cd, hdr)) { log_dbg(cd, "New keyslot too large to fit in free metadata space."); json_object_object_del_by_uint(jobj_keyslots, keyslot); return -ENOSPC; } JSON_DBG(cd, hdr->jobj, "JSON:"); return 0; } static int reenc_keyslot_store_data(struct crypt_device *cd, json_object *jobj_keyslot, const void *buffer, size_t buffer_len) { int devfd, r; json_object *jobj_area, *jobj_offset, *jobj_length; uint64_t area_offset, area_length; struct device *device = crypt_metadata_device(cd); if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) || !json_object_object_get_ex(jobj_area, "offset", &jobj_offset) || !json_object_object_get_ex(jobj_area, "size", &jobj_length)) return -EINVAL; area_offset = crypt_jobj_get_uint64(jobj_offset); area_length = crypt_jobj_get_uint64(jobj_length); if (!area_offset || !area_length || ((uint64_t)buffer_len > area_length)) return -EINVAL; devfd = device_open_locked(cd, device, O_RDWR); if (devfd >= 0) { if (write_lseek_blockwise(devfd, device_block_size(cd, device), device_alignment(device), CONST_CAST(void *)buffer, buffer_len, area_offset) < 0) r = -EIO; else r = 0; } else r = -EINVAL; if (r) log_err(cd, _("IO error while encrypting keyslot.")); return r; } static int reenc_keyslot_store(struct crypt_device *cd, int keyslot, const char *password __attribute__((unused)), size_t password_len __attribute__((unused)), const char *buffer, size_t buffer_len) { struct luks2_hdr *hdr; json_object *jobj_keyslot; int r = 0; if (!cd || !buffer || !buffer_len) return -EINVAL; if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2))) return -EINVAL; log_dbg(cd, "Reencrypt keyslot %d store.", keyslot); jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot); if (!jobj_keyslot) return -EINVAL; r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd)); if (r) return r; r = reenc_keyslot_store_data(cd, jobj_keyslot, buffer, buffer_len); if (r < 0) { device_write_unlock(cd, crypt_metadata_device(cd)); return r; } r = LUKS2_hdr_write(cd, hdr); device_write_unlock(cd, crypt_metadata_device(cd)); return r < 0 ? r : keyslot; } static int reenc_keyslot_wipe(struct crypt_device *cd, int keyslot) { struct luks2_hdr *hdr; if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2))) return -EINVAL; /* remove reencryption verification data */ LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0); return 0; } static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot) { json_object *jobj_keyslot, *jobj_area, *jobj_direction, *jobj_mode, *jobj_resilience, *jobj1; jobj_keyslot = LUKS2_get_keyslot_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), keyslot); if (!jobj_keyslot) return -EINVAL; if (!json_object_object_get_ex(jobj_keyslot, "direction", &jobj_direction) || !json_object_object_get_ex(jobj_keyslot, "mode", &jobj_mode) || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) || !json_object_object_get_ex(jobj_area, "type", &jobj_resilience)) return -EINVAL; log_std(cd, "\t%-12s%s\n", "Mode:", json_object_get_string(jobj_mode)); log_std(cd, "\t%-12s%s\n", "Direction:", json_object_get_string(jobj_direction)); log_std(cd, "\t%-12s%s\n", "Resilience:", json_object_get_string(jobj_resilience)); if (!strcmp(json_object_get_string(jobj_resilience), "checksum")) { json_object_object_get_ex(jobj_area, "hash", &jobj1); log_std(cd, "\t%-12s%s\n", "Hash:", json_object_get_string(jobj1)); json_object_object_get_ex(jobj_area, "sector_size", &jobj1); log_std(cd, "\t%-12s%d [bytes]\n", "Hash data:", json_object_get_int(jobj1)); } else if (!strcmp(json_object_get_string(jobj_resilience), "datashift")) { json_object_object_get_ex(jobj_area, "shift_size", &jobj1); log_std(cd, "\t%-12s%" PRIu64 "[bytes]\n", "Shift size:", crypt_jobj_get_uint64(jobj1)); } json_object_object_get_ex(jobj_area, "offset", &jobj1); log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1)); json_object_object_get_ex(jobj_area, "size", &jobj1); log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1)); return 0; } static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot) { json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction, *jobj_key_size; const char *mode, *type, *direction; uint32_t sector_size; uint64_t shift_size; /* mode (string: encrypt,reencrypt,decrypt) * direction (string:) * area { * type: (string: datashift, journal, checksum, none, datashift-journal, datashift-checksum) * hash: (string: checksum and datashift-checksum types) * sector_size (uint32: checksum and datashift-checksum types) * shift_size (uint64: all datashift based types) * } */ /* area and area type are validated in general validation code */ if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) || !json_object_object_get_ex(jobj_area, "type", &jobj_type)) return -EINVAL; jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int); jobj_mode = json_contains_string(cd, jobj_keyslot, "", "reencrypt keyslot", "mode"); jobj_direction = json_contains_string(cd, jobj_keyslot, "", "reencrypt keyslot", "direction"); if (!jobj_mode || !jobj_direction || !jobj_key_size) return -EINVAL; if (!validate_json_uint32(jobj_key_size) || crypt_jobj_get_uint32(jobj_key_size) != 1) { log_dbg(cd, "Illegal reencrypt key size."); return -EINVAL; } mode = json_object_get_string(jobj_mode); type = json_object_get_string(jobj_type); direction = json_object_get_string(jobj_direction); if (strcmp(mode, "reencrypt") && strcmp(mode, "encrypt") && strcmp(mode, "decrypt")) { log_dbg(cd, "Illegal reencrypt mode %s.", mode); return -EINVAL; } if (strcmp(direction, "forward") && strcmp(direction, "backward")) { log_dbg(cd, "Illegal reencrypt direction %s.", direction); return -EINVAL; } if (!strcmp(type, "checksum") || !strcmp(type, "datashift-checksum")) { jobj_hash = json_contains_string(cd, jobj_area, "type:checksum", "Keyslot area", "hash"); jobj_sector_size = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "sector_size", json_type_int); if (!jobj_hash || !jobj_sector_size) return -EINVAL; if (!validate_json_uint32(jobj_sector_size)) return -EINVAL; sector_size = crypt_jobj_get_uint32(jobj_sector_size); if (sector_size < SECTOR_SIZE || NOTPOW2(sector_size)) { log_dbg(cd, "Invalid sector_size (%" PRIu32 ") for checksum resilience mode.", sector_size); return -EINVAL; } } else if (!strcmp(type, "datashift") || !strcmp(type, "datashift-checksum") || !strcmp(type, "datashift-journal")) { if (!(jobj_shift_size = json_contains_string(cd, jobj_area, "type:datashift", "Keyslot area", "shift_size"))) return -EINVAL; shift_size = crypt_jobj_get_uint64(jobj_shift_size); if (!shift_size) return -EINVAL; if (MISALIGNED_512(shift_size)) { log_dbg(cd, "Shift size field has to be aligned to 512 bytes."); return -EINVAL; } } return 0; } static int reenc_keyslot_update_needed(struct crypt_device *cd, json_object *jobj_keyslot, const struct crypt_params_reencrypt *params, size_t alignment) { const char *type; json_object *jobj_area, *jobj_type, *jobj; if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) || !json_object_object_get_ex(jobj_area, "type", &jobj_type) || !(type = json_object_get_string(jobj_type))) return -EINVAL; /* * If no resilience mode change is requested and effective * resilience mode is 'checksum' then check alignment matches * stored checksum block size. */ if (!params || !params->resilience) { if (!strcmp(json_object_get_string(jobj_type), "checksum") || !strcmp(json_object_get_string(jobj_type), "datashift-checksum")) return (json_object_object_get_ex(jobj_area, "sector_size", &jobj) || alignment != crypt_jobj_get_uint32(jobj)); return 0; } if (strcmp(params->resilience, type)) return 1; if (!strcmp(type, "checksum") || !strcmp(type, "datashift-checksum")) { if (!params->hash) return -EINVAL; if (!json_object_object_get_ex(jobj_area, "hash", &jobj) || strcmp(json_object_get_string(jobj), params->hash) || !json_object_object_get_ex(jobj_area, "sector_size", &jobj) || crypt_jobj_get_uint32(jobj) != alignment) return 1; } if (!strncmp(type, "datashift", 9)) { if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj)) return -EINVAL; if ((params->data_shift << SECTOR_SHIFT) != crypt_jobj_get_uint64(jobj)) return 1; } /* nothing to compare with 'none' and 'journal' */ return 0; } static int load_checksum_protection(struct crypt_device *cd, json_object *jobj_area, uint64_t area_length, struct reenc_protection *rp) { int r; json_object *jobj_hash, *jobj_block_size; if (!jobj_area || !rp || !json_object_object_get_ex(jobj_area, "hash", &jobj_hash) || !json_object_object_get_ex(jobj_area, "sector_size", &jobj_block_size)) return -EINVAL; r = snprintf(rp->p.csum.hash, sizeof(rp->p.csum.hash), "%s", json_object_get_string(jobj_hash)); if (r < 0 || (size_t)r >= sizeof(rp->p.csum.hash)) return -EINVAL; if (crypt_hash_init(&rp->p.csum.ch, rp->p.csum.hash)) { log_err(cd, _("Hash algorithm %s is not available."), rp->p.csum.hash); return -EINVAL; } r = crypt_hash_size(rp->p.csum.hash); if (r <= 0) { crypt_hash_destroy(rp->p.csum.ch); rp->p.csum.ch = NULL; log_dbg(cd, "Invalid hash size"); return -EINVAL; } rp->p.csum.hash_size = r; rp->p.csum.block_size = crypt_jobj_get_uint32(jobj_block_size); rp->p.csum.checksums_len = area_length; rp->type = REENC_PROTECTION_CHECKSUM; return 0; } static int reenc_keyslot_load_resilience_primary(struct crypt_device *cd, const char *type, json_object *jobj_area, uint64_t area_length, struct reenc_protection *rp) { json_object *jobj; if (!strcmp(type, "checksum")) { log_dbg(cd, "Initializing checksum resilience mode."); return load_checksum_protection(cd, jobj_area, area_length, rp); } else if (!strcmp(type, "journal")) { log_dbg(cd, "Initializing journal resilience mode."); rp->type = REENC_PROTECTION_JOURNAL; } else if (!strcmp(type, "none")) { log_dbg(cd, "Initializing none resilience mode."); rp->type = REENC_PROTECTION_NONE; } else if (!strcmp(type, "datashift") || !strcmp(type, "datashift-checksum") || !strcmp(type, "datashift-journal")) { log_dbg(cd, "Initializing datashift resilience mode."); if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj)) return -EINVAL; rp->type = REENC_PROTECTION_DATASHIFT; rp->p.ds.data_shift = crypt_jobj_get_uint64(jobj); } else return -EINVAL; return 0; } static int reenc_keyslot_load_resilience_secondary(struct crypt_device *cd, const char *type, json_object *jobj_area, uint64_t area_length, struct reenc_protection *rp) { if (!strcmp(type, "datashift-checksum")) { log_dbg(cd, "Initializing checksum resilience mode."); return load_checksum_protection(cd, jobj_area, area_length, rp); } else if (!strcmp(type, "datashift-journal")) { log_dbg(cd, "Initializing journal resilience mode."); rp->type = REENC_PROTECTION_JOURNAL; } else rp->type = REENC_PROTECTION_NOT_SET; return 0; } static int reenc_keyslot_load_resilience(struct crypt_device *cd, json_object *jobj_keyslot, struct reenc_protection *rp, bool primary) { const char *type; int r; json_object *jobj_area, *jobj_type; uint64_t dummy, area_length; if (!rp || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) || !json_object_object_get_ex(jobj_area, "type", &jobj_type)) return -EINVAL; r = LUKS2_keyslot_jobj_area(jobj_keyslot, &dummy, &area_length); if (r < 0) return r; type = json_object_get_string(jobj_type); if (!type) return -EINVAL; if (primary) return reenc_keyslot_load_resilience_primary(cd, type, jobj_area, area_length, rp); else return reenc_keyslot_load_resilience_secondary(cd, type, jobj_area, area_length, rp); } static bool reenc_keyslot_update_is_valid(struct crypt_device *cd, json_object *jobj_area, const struct crypt_params_reencrypt *params) { const char *type; json_object *jobj_type, *jobj; if (!json_object_object_get_ex(jobj_area, "type", &jobj_type) || !(type = json_object_get_string(jobj_type))) return false; /* do not allow switch to/away from datashift resilience type */ if ((strcmp(params->resilience, "datashift") && !strcmp(type, "datashift")) || (!strcmp(params->resilience, "datashift") && strcmp(type, "datashift"))) return false; /* do not allow switch to/away from datashift- resilience subvariants */ if ((strncmp(params->resilience, "datashift-", 10) && !strncmp(type, "datashift-", 10)) || (!strncmp(params->resilience, "datashift-", 10) && strncmp(type, "datashift-", 10))) return false; /* datashift value is also immutable */ if (!strncmp(type, "datashift", 9)) { if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj)) return false; return (params->data_shift << SECTOR_SHIFT) == crypt_jobj_get_uint64(jobj); } return true; } static int reenc_keyslot_update(struct crypt_device *cd, json_object *jobj_keyslot, const struct crypt_params_reencrypt *params, size_t alignment) { int r; json_object *jobj_area, *jobj_area_new; uint64_t area_offset, area_length; if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area)) return -EINVAL; r = LUKS2_keyslot_jobj_area(jobj_keyslot, &area_offset, &area_length); if (r < 0) return r; if (!params || !params->resilience) jobj_area_new = reencrypt_keyslot_area_jobj_update_block_size(cd, jobj_area, alignment); else { if (!reenc_keyslot_update_is_valid(cd, jobj_area, params)) { log_err(cd, _("Invalid reencryption resilience mode change requested.")); return -EINVAL; } jobj_area_new = reencrypt_keyslot_area_jobj(cd, params, alignment, area_offset, area_length); } if (!jobj_area_new) return -EINVAL; /* increase refcount for validation purposes */ json_object_get(jobj_area); json_object_object_add(jobj_keyslot, "area", jobj_area_new); r = reenc_keyslot_validate(cd, jobj_keyslot); if (r) { /* replace invalid object with previous valid one */ json_object_object_add(jobj_keyslot, "area", jobj_area); return -EINVAL; } /* previous area object is no longer needed */ json_object_put(jobj_area); return 0; } int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd, struct luks2_hdr *hdr, int keyslot, const struct crypt_params_reencrypt *params, size_t alignment) { int r; if (keyslot == CRYPT_ANY_SLOT) return -EINVAL; r = reenc_keyslot_alloc(cd, hdr, keyslot, params, alignment); if (r < 0) return r; r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0); if (r < 0) return r; r = reenc_keyslot_validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot)); if (r) { log_dbg(cd, "Keyslot validation failed."); return r; } return 0; } int LUKS2_keyslot_reencrypt_update_needed(struct crypt_device *cd, struct luks2_hdr *hdr, int keyslot, const struct crypt_params_reencrypt *params, size_t alignment) { int r; json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot); if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) || strcmp(json_object_get_string(jobj_type), "reencrypt")) return -EINVAL; r = reenc_keyslot_update_needed(cd, jobj_keyslot, params, alignment); if (!r) log_dbg(cd, "No update of reencrypt keyslot needed."); return r; } int LUKS2_keyslot_reencrypt_update(struct crypt_device *cd, struct luks2_hdr *hdr, int keyslot, const struct crypt_params_reencrypt *params, size_t alignment, struct volume_key *vks) { int r; uint8_t version; uint64_t max_size, moved_segment_size; json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot); struct reenc_protection check_rp = {}; if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) || strcmp(json_object_get_string(jobj_type), "reencrypt")) return -EINVAL; if (LUKS2_config_get_reencrypt_version(hdr, &version)) return -EINVAL; /* verify existing reencryption metadata before updating */ r = LUKS2_reencrypt_digest_verify(cd, hdr, vks); if (r < 0) return r; r = reenc_keyslot_update(cd, jobj_keyslot, params, alignment); if (r < 0) return r; r = reenc_keyslot_load_resilience(cd, jobj_keyslot, &check_rp, false); if (r < 0) return r; if (check_rp.type != REENC_PROTECTION_NOT_SET) { r = LUKS2_reencrypt_max_hotzone_size(cd, hdr, &check_rp, keyslot, &max_size); LUKS2_reencrypt_protection_erase(&check_rp); if (r < 0) return r; moved_segment_size = json_segment_get_size(LUKS2_get_segment_by_flag(hdr, "backup-moved-segment"), 0); if (!moved_segment_size) return -EINVAL; if (moved_segment_size > max_size) { log_err(cd, _("Can not update resilience type. " "New type only provides %" PRIu64 " bytes, " "required space is: %" PRIu64 " bytes."), max_size, moved_segment_size); return -EINVAL; } } r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, version, vks); if (r < 0) log_err(cd, _("Failed to refresh reencryption verification digest.")); return r ?: LUKS2_hdr_write(cd, hdr); } int LUKS2_keyslot_reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr, int keyslot, struct reenc_protection *rp, bool primary) { json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot); if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) || strcmp(json_object_get_string(jobj_type), "reencrypt")) return -EINVAL; return reenc_keyslot_load_resilience(cd, jobj_keyslot, rp, primary); } const keyslot_handler reenc_keyslot = { .name = "reencrypt", .open = reenc_keyslot_open, .store = reenc_keyslot_store, /* initialization only or also per every chunk write */ .wipe = reenc_keyslot_wipe, .dump = reenc_keyslot_dump, .validate = reenc_keyslot_validate };