+ struct device *device = crypt_metadata_device(ctx);
+ struct crypt_storage *s;
+ struct stat st;
+ int devfd, r = 0;
+
+ /* Only whole sector reads supported */
+ if (MISALIGNED_512(dstLength))
+ return -EINVAL;
+
+ r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
+
+ if (r)
+ log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
+ cipher, cipher_mode, r);
+
+ /* Fallback to old temporary dmcrypt device */
+ if (r == -ENOTSUP || r == -ENOENT)
+ return LUKS_endec_template(dst, dstLength, cipher, cipher_mode,
+ vk, sector, read_blockwise, O_RDONLY, ctx);
+
+ if (r) {
+ _error_hint(ctx, device_path(device), cipher, cipher_mode,
+ vk->keylength * 8);
+ return r;
+ }
+
+ log_dbg(ctx, "Using userspace crypto wrapper to access keyslot area.");
+
+ /* Read buffer from device */
+ if (device_is_locked(device))
+ devfd = device_open_locked(ctx, device, O_RDONLY);
+ else
+ devfd = device_open(ctx, device, O_RDONLY);
+ if (devfd < 0) {
+ log_err(ctx, _("Cannot open device %s."), device_path(device));
+ crypt_storage_destroy(s);
+ return -EIO;
+ }
+
+ if (read_lseek_blockwise(devfd, device_block_size(ctx, device),
+ device_alignment(device), dst, dstLength,
+ sector * SECTOR_SIZE) < 0) {
+ if (!fstat(devfd, &st) && (st.st_size < (off_t)dstLength))
+ log_err(ctx, _("Device %s is too small."), device_path(device));
+ else
+ log_err(ctx, _("IO error while decrypting keyslot."));
+
+ crypt_storage_destroy(s);
+ return -EIO;
+ }
+
+ /* Decrypt buffer */
+ r = crypt_storage_decrypt(s, 0, dstLength, dst);
+ crypt_storage_destroy(s);
+
+ return r;