r = crypt_cipher_init(&cipher, "blowfish", "ecb",
&key[alg->key_offset], alg->key_size);
if (r < 0)
- goto out;
+ return r;
memcpy(iv, &key[alg->iv_offset], alg->iv_size);
for (i = 0; i < TCRYPT_HDR_LEN; i += bs) {
bs, NULL, 0);
blowfish_le(&buf[i]);
if (r < 0)
- goto out;
+ break;
for (j = 0; j < bs; j++)
buf[i + j] ^= iv[j];
memcpy(iv, iv_old, bs);
}
-out:
+
crypt_cipher_destroy(cipher);
return r;
}
continue;
r = decrypt_hdr_one(&tcrypt_cipher[i].cipher[j],
tcrypt_cipher[i].mode, key, &hdr2);
- if (r < 0) {
- log_dbg("Error %s.", tcrypt_cipher[i].cipher[j].name);
+ if (r < 0)
break;
- }
+ }
+
+ if (r < 0) {
+ log_dbg("TCRYPT: returned error %d, skipped.", r);
+ if (r == -ENOTSUP)
+ break;
+ r = -ENOENT;
+ continue;
}
if (!strncmp(hdr2.d.magic, TCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) {
unsigned char pwd[TCRYPT_KEY_POOL_LEN] = {};
size_t passphrase_size;
char *key;
- int r = -EINVAL, i, legacy_modes;
+ int r = -EINVAL, i, legacy_modes, skipped = 0;
if (posix_memalign((void*)&key, crypt_getpagesize(), TCRYPT_HDR_KEY_LEN))
return -ENOMEM;
/* Decrypt header */
r = decrypt_hdr(cd, hdr, key, legacy_modes);
+ if (r == -ENOENT) {
+ skipped++;
+ continue;
+ }
if (r != -EPERM)
break;
}
+ if (skipped == i || r == -ENOTSUP)
+ log_err(cd, _("Required kernel crypto interface not available.\n"
+ "Ensure you have algif_skcipher kernel module loaded.\n"));
if (r < 0)
goto out;
r = hdr_from_disk(hdr, params, i, r);
if (!r) {
log_dbg("TCRYPT: Header version: %d, req. %d, sector %d"
- ", PBKDF2 hash %s", (int)hdr->d.version,
+ ", mk_offset %" PRIu64 ", hidden_size %" PRIu64
+ ", volume size %" PRIu64, (int)hdr->d.version,
(int)hdr->d.version_tc, (int)hdr->d.sector_size,
- params->hash_name);
+ hdr->d.mk_offset, hdr->d.hidden_volume_size, hdr->d.volume_size);
log_dbg("TCRYPT: Header cipher %s-%s, key size %d",
params->cipher, params->mode, params->key_size);
}
{
struct device *device = crypt_metadata_device(cd);
ssize_t hdr_size = sizeof(struct tcrypt_phdr);
- int devfd = 0, r = -EIO, bs;
+ int devfd = 0, r, bs;
assert(sizeof(struct tcrypt_phdr) == 512);
return -EINVAL;
}
+ r = -EIO;
if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) {
- if (lseek(devfd, TCRYPT_HDR_HIDDEN_OFFSET, SEEK_SET) >= 0 &&
- read_blockwise(devfd, bs, hdr, hdr_size) == hdr_size)
- r = TCRYPT_init_hdr(cd, hdr, params);
- if (r &&
- lseek(devfd, TCRYPT_HDR_HIDDEN_OFFSET_OLD, SEEK_END) >= 0 &&
- read_blockwise(devfd, bs, hdr, hdr_size) == hdr_size)
+ if (params->flags & CRYPT_TCRYPT_BACKUP_HEADER) {
+ if (lseek(devfd, TCRYPT_HDR_HIDDEN_OFFSET_BCK, SEEK_END) >= 0 &&
+ read_blockwise(devfd, bs, hdr, hdr_size) == hdr_size)
+ r = TCRYPT_init_hdr(cd, hdr, params);
+ } else {
+ if (lseek(devfd, TCRYPT_HDR_HIDDEN_OFFSET, SEEK_SET) >= 0 &&
+ read_blockwise(devfd, bs, hdr, hdr_size) == hdr_size)
+ r = TCRYPT_init_hdr(cd, hdr, params);
+ if (r &&
+ lseek(devfd, TCRYPT_HDR_HIDDEN_OFFSET_OLD, SEEK_END) >= 0 &&
+ read_blockwise(devfd, bs, hdr, hdr_size) == hdr_size)
+ r = TCRYPT_init_hdr(cd, hdr, params);
+ }
+ } else if (params->flags & CRYPT_TCRYPT_BACKUP_HEADER) {
+ if (lseek(devfd, TCRYPT_HDR_OFFSET_BCK, SEEK_END) >= 0 &&
+ read_blockwise(devfd, bs, hdr, hdr_size) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
} else if (read_blockwise(devfd, bs, hdr, hdr_size) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
if (!algs)
return -EINVAL;
+ if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER)
+ dmd.size = hdr->d.hidden_volume_size / hdr->d.sector_size;
+ else
+ dmd.size = hdr->d.volume_size / hdr->d.sector_size;
+
r = device_block_adjust(cd, dmd.data_device, DEV_EXCL,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r)
return 0;
}
-uint64_t TCRYPT_get_data_offset(struct tcrypt_phdr *hdr)
+uint64_t TCRYPT_get_data_offset(struct crypt_device *cd,
+ struct tcrypt_phdr *hdr,
+ struct crypt_params_tcrypt *params)
{
+ uint64_t size;
+
+ if (params->mode && !strncmp(params->mode, "xts", 3)) {
+ if (hdr->d.version < 3)
+ return 1;
+
+ if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) {
+ if (hdr->d.version > 3)
+ return (hdr->d.mk_offset / hdr->d.sector_size);
+ if (device_size(crypt_metadata_device(cd), &size) < 0)
+ return 0;
+ return (size - hdr->d.hidden_volume_size +
+ (TCRYPT_HDR_HIDDEN_OFFSET_OLD)) / hdr->d.sector_size;
+ }
+ return (hdr->d.mk_offset / hdr->d.sector_size);
+ }
+
+ if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) {
+ if (device_size(crypt_metadata_device(cd), &size) < 0)
+ return 0;
+ return (size - hdr->d.hidden_volume_size +
+ (TCRYPT_HDR_HIDDEN_OFFSET_OLD)) / hdr->d.sector_size;
+ }
+
// FIXME: system vol.
- if (!hdr->d.mk_offset)
- return 1;
- return (hdr->d.mk_offset / hdr->d.sector_size);
+ return hdr->d.mk_offset / hdr->d.sector_size;
}
-uint64_t TCRYPT_get_iv_offset(struct tcrypt_phdr *hdr)
+uint64_t TCRYPT_get_iv_offset(struct crypt_device *cd,
+ struct tcrypt_phdr *hdr,
+ struct crypt_params_tcrypt *params
+)
{
- if (!hdr->d.mk_offset)
+ if (params->mode && !strncmp(params->mode, "xts", 3))
+ return TCRYPT_get_data_offset(cd, hdr, params);
+ else if (params->mode && !strncmp(params->mode, "lrw", 3))
return 0;
- return (hdr->d.mk_offset / hdr->d.sector_size);
+
+ return hdr->d.mk_offset / hdr->d.sector_size;
}
int TCRYPT_get_volume_key(struct crypt_device *cd,