int LUKS_write_phdr(struct luks_phdr *hdr, struct crypt_device *ctx) { struct device *device = crypt_metadata_device(ctx); ssize_t hdr_size = sizeof(struct luks_phdr); int devfd = 0; unsigned int i; struct luks_phdr convHdr; int r; log_dbg(ctx, "Updating LUKS header of size %zu on device %s", sizeof(struct luks_phdr), device_path(device)); r = LUKS_check_device_size(ctx, hdr, 1); if (r) return r; devfd = device_open(ctx, device, O_RDWR); if (devfd < 0) { if (errno == EACCES) log_err(ctx, _("Cannot write to device %s, permission denied."), device_path(device)); else log_err(ctx, _("Cannot open device %s."), device_path(device)); return -EINVAL; } memcpy(&convHdr, hdr, hdr_size); memset(&convHdr._padding, 0, sizeof(convHdr._padding)); /* Convert every uint16/32_t item to network byte order */ convHdr.version = htons(hdr->version); convHdr.payloadOffset = htonl(hdr->payloadOffset); convHdr.keyBytes = htonl(hdr->keyBytes); convHdr.mkDigestIterations = htonl(hdr->mkDigestIterations); for(i = 0; i < LUKS_NUMKEYS; ++i) { convHdr.keyblock[i].active = htonl(hdr->keyblock[i].active); convHdr.keyblock[i].passwordIterations = htonl(hdr->keyblock[i].passwordIterations); convHdr.keyblock[i].keyMaterialOffset = htonl(hdr->keyblock[i].keyMaterialOffset); convHdr.keyblock[i].stripes = htonl(hdr->keyblock[i].stripes); } r = write_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device), &convHdr, hdr_size, 0) < hdr_size ? -EIO : 0; if (r) log_err(ctx, _("Error during update of LUKS header on device %s."), device_path(device)); device_sync(ctx, device); /* Re-read header from disk to be sure that in-memory and on-disk data are the same. */ if (!r) { r = LUKS_read_phdr(hdr, 1, 0, ctx); if (r) log_err(ctx, _("Error re-reading LUKS header after update on device %s."), device_path(device)); } return r; }
int LUKS_del_key(unsigned int keyIndex, struct luks_phdr *hdr, struct crypt_device *ctx) { struct device *device = crypt_metadata_device(ctx); unsigned int startOffset, endOffset; int r; r = LUKS_read_phdr(hdr, 1, 0, ctx); if (r) return r; r = LUKS_keyslot_set(hdr, keyIndex, 0); if (r) { log_err(ctx, _("Key slot %d is invalid, please select keyslot between 0 and %d.\n"), keyIndex, LUKS_NUMKEYS - 1); return r; } /* secure deletion of key material */ startOffset = hdr->keyblock[keyIndex].keyMaterialOffset; endOffset = startOffset + AF_split_sectors(hdr->keyBytes, hdr->keyblock[keyIndex].stripes); r = crypt_wipe(device, startOffset * SECTOR_SIZE, (endOffset - startOffset) * SECTOR_SIZE, CRYPT_WIPE_DISK, 0); if (r) { if (r == -EACCES) { log_err(ctx, _("Cannot write to device %s, permission denied.\n"), device_path(device)); r = -EINVAL; } else log_err(ctx, _("Cannot wipe device %s.\n"), device_path(device)); return r; } /* Wipe keyslot info */ memset(&hdr->keyblock[keyIndex].passwordSalt, 0, LUKS_SALTSIZE); hdr->keyblock[keyIndex].passwordIterations = 0; r = LUKS_write_phdr(hdr, ctx); return r; }
int LUKS_hdr_restore( const char *backup_file, struct luks_phdr *hdr, struct crypt_device *ctx) { struct device *device = crypt_metadata_device(ctx); int r = 0, devfd = -1, diff_uuid = 0; ssize_t buffer_size = 0; char *buffer = NULL, msg[200]; struct luks_phdr hdr_file; r = LUKS_read_phdr_backup(backup_file, &hdr_file, 0, ctx); if (r == -ENOENT) return r; if (!r) buffer_size = LUKS_device_sectors(hdr_file.keyBytes) << SECTOR_SHIFT; if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) { log_err(ctx, _("Backup file doesn't contain valid LUKS header.\n")); r = -EINVAL; goto out; } buffer = crypt_safe_alloc(buffer_size); if (!buffer) { r = -ENOMEM; goto out; } devfd = open(backup_file, O_RDONLY); if (devfd == -1) { log_err(ctx, _("Cannot open header backup file %s.\n"), backup_file); r = -EINVAL; goto out; } if (read(devfd, buffer, buffer_size) < buffer_size) { log_err(ctx, _("Cannot read header backup file %s.\n"), backup_file); r = -EIO; goto out; } close(devfd); r = LUKS_read_phdr(hdr, 0, 0, ctx); if (r == 0) { log_dbg("Device %s already contains LUKS header, checking UUID and offset.", device_path(device)); if(hdr->payloadOffset != hdr_file.payloadOffset || hdr->keyBytes != hdr_file.keyBytes) { log_err(ctx, _("Data offset or key size differs on device and backup, restore failed.\n")); r = -EINVAL; goto out; } if (memcmp(hdr->uuid, hdr_file.uuid, UUID_STRING_L)) diff_uuid = 1; } if (snprintf(msg, sizeof(msg), _("Device %s %s%s"), device_path(device), r ? _("does not contain LUKS header. Replacing header can destroy data on that device.") : _("already contains LUKS header. Replacing header will destroy existing keyslots."), diff_uuid ? _("\nWARNING: real device header has different UUID than backup!") : "") < 0) { r = -ENOMEM; goto out; } if (!crypt_confirm(ctx, msg)) { r = -EINVAL; goto out; } log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes) to device %s.", sizeof(*hdr), buffer_size - LUKS_ALIGN_KEYSLOTS, device_path(device)); devfd = device_open(device, O_RDWR); if (devfd == -1) { if (errno == EACCES) log_err(ctx, _("Cannot write to device %s, permission denied.\n"), device_path(device)); else log_err(ctx, _("Cannot open device %s.\n"), device_path(device)); r = -EINVAL; goto out; } if (write_blockwise(devfd, device_block_size(device), buffer, buffer_size) < buffer_size) { r = -EIO; goto out; } close(devfd); /* Be sure to reload new data */ r = LUKS_read_phdr(hdr, 1, 0, ctx); out: if (devfd != -1) close(devfd); crypt_safe_free(buffer); return r; }
int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx) { struct device *device = crypt_metadata_device(ctx); struct luks_phdr hdr; int r = 0, devfd = -1; ssize_t hdr_size; ssize_t buffer_size; char *buffer = NULL; r = LUKS_read_phdr(&hdr, 1, 0, ctx); if (r) return r; hdr_size = LUKS_device_sectors(hdr.keyBytes) << SECTOR_SHIFT; buffer_size = size_round_up(hdr_size, crypt_getpagesize()); buffer = crypt_safe_alloc(buffer_size); if (!buffer || hdr_size < LUKS_ALIGN_KEYSLOTS || hdr_size > buffer_size) { r = -ENOMEM; goto out; } log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes).", sizeof(hdr), hdr_size - LUKS_ALIGN_KEYSLOTS); log_dbg("Output backup file size: %zu bytes.", buffer_size); devfd = device_open(device, O_RDONLY); if(devfd == -1) { log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device_path(device)); r = -EINVAL; goto out; } if (read_blockwise(devfd, device_block_size(device), buffer, hdr_size) < hdr_size) { r = -EIO; goto out; } close(devfd); /* Wipe unused area, so backup cannot contain old signatures */ if (hdr.keyblock[0].keyMaterialOffset * SECTOR_SIZE == LUKS_ALIGN_KEYSLOTS) memset(buffer + sizeof(hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(hdr)); devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR); if (devfd == -1) { if (errno == EEXIST) log_err(ctx, _("Requested header backup file %s already exists.\n"), backup_file); else log_err(ctx, _("Cannot create header backup file %s.\n"), backup_file); r = -EINVAL; goto out; } if (write(devfd, buffer, buffer_size) < buffer_size) { log_err(ctx, _("Cannot write header backup file %s.\n"), backup_file); r = -EIO; goto out; } close(devfd); r = 0; out: if (devfd != -1) close(devfd); crypt_memzero(&hdr, sizeof(hdr)); crypt_safe_free(buffer); return r; }