如何扩展 LUKS2

如何扩展 LUKS2

几年前我读过一本指南,内容是关于 LUKS1 如何在不丢失数据的情况下扩展到右侧和相邻的自由空间,但无法离开。如今LUKS2已经到来,带来了许多新功能,它是否可以在不丢失数据的情况下使左侧扩展不同?

答案1

太长了;博士这还不太可能——目前还不可能。元数据格式表明它应该是可行的,但到目前为止,它还没有实际实现。因此,您应该坚持古老的“重新定位所有数据”,或者“创建新分区并让 LVM 处理它”。您对 LUKS1 和大多数文件系统执行的操作相同。


LUKS2 标头有一个概念数据段:

Segments 对象包含磁盘上包含用户数据(在 LUKS1 中称为用户数据有效负载)的加密区域的定义。对于普通 LUKS 设备,仅存在一个数据段。

数据重加密时,内部根据新旧密钥划分数据区域,但只向用户呈现一个抽象区域。

数据段,应该可以将LUKS头向左移动,保持指向原始数据(第一个段),并使用空闲空间(头和数据段之间)作为新的数据段,逻辑上附加到数据段的末尾加密设备。就像 LVM 如何将任意物理范围组附加到逻辑卷一样。

但这只是一个理论。

到目前为止,还没有实际使用/工具来实现此功能,我不知道是否有任何计划这样做。


我试图让它以非常规的方式工作(概念证明,某种程度):

# truncate -s 100M foobar.img
# cryptsetup luksFormat --type=luks2 foobar.img
# cryptsetup luksOpen foobar.img foobar
# yes > /dev/mapper/foobar
# sync
# hexdump -C /dev/mapper/foobar
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
05400000

LUKS2 加密的是模式。数据段是什么样的?

# cryptsetup luksDump foobar.img
Data segments:
  0: crypt
    offset: 16777216 [bytes]
    length: (whole device)
    cipher: aes-xts-plain64
    sector: 512 [bytes]
# strings -n 100 foobar.img
"segments":{"0":{"type":"crypt","offset":"16777216","iv_tweak":"0","size":"dynamic","encryption":"aes-xts-plain64","sector_size":512}}

后者实际上就是原始 LUKS2 元数据的样子 - 它是一种 JSON 格式。我们稍后会编辑它...

让我们将其增长 - 向左(100M):

# truncate -s 100M barfoo.img
# cat foobar.img >> barfoo.img
# ls -lh *.img
-rw-r--r-- 1 root root 200M Jun  9 20:57 barfoo.img
-rw-r--r-- 1 root root 100M Jun  9 20:53 foobar.img

所以 barfoo.img 是 100M 的新空白空间,后面是 100M 的原始 LUKS 容器。

将 LUKS 标头重新定位到设备的新开头:

# dd bs=1M count=16 if=foobar.img of=barfoo.img conv=notrunc
# cryptsetup luksOpen barfoo.img barfoo
# hexdump -C -n 16 /dev/mapper/barfoo
00000000  4e a6 39 e7 e0 e8 63 ae  81 72 29 81 5f 1b 08 c2  |N.9...c..r)._...|
00000010

现在可以打开了,但是数据段仍然指向旧的偏移量 (16MiB),但当然,它不在那里 - 我们添加了 100M,所以这个偏移量数据段现在应该是 116MiB。

编辑它(偏移量 16777216 到偏移量 121634816):

# strings -n 100 barfoo.img | head -n 1 > barfoo.json
# nano -w barfoo.json
# dd if=barfoo.json of=barfoo.img bs=1 seek=4096 conv=notrunc
# dd if=barfoo.json of=barfoo.img bs=1 seek=20480 conv=notrunc

结果:

# cryptsetup luksDump barfoo.img
Device barfoo.img is not a valid LUKS device.

哦,但是当然。 LUKS2 现在也有元数据校验和。它不希望您使用 nano 编辑内容并使用 dd 破坏标题。先生,你没有什么神秘魔法。好吧,直到你也修补校验和......

# cryptsetup luksDump barfoo.img --debug
# LUKS2 header version 2 of size 16384 bytes, checksum sha256.
# Checksum:8552bf514ab70b53e63180e9fdd3bb59db1385e3dca87f792f8197b33b851aa1 (on-disk)
# Checksum:e6f322921feae0193bcbc4cddc23b87b7f192266b4a2ef34847580fd7ca18a3e (in-memory)
# LUKS2 header checksum error (offset 0).

...基本上用内存中的校验和替换磁盘上的校验和。

# echo e6f322921feae0193bcbc4cddc23b87b7f192266b4a2ef34847580fd7ca18a3e |
  xxd -r -ps - |
  dd of=barfoo.img bs=1 seek=448 conv=notrunc

结果(现在真的):

# cryptsetup luksDump barfoo.img
Data segments:
  0: crypt
    offset: 121634816 [bytes]
    length: (whole device)
    cipher: aes-xts-plain64
    sector: 512 [bytes]
# hexdump -C /dev/mapper/barfoo
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
05400000

至此,我们已经成功将LUKS头向左移动了100M。但设备大小仍然相同...现在,我们可以添加另一个数据段吗?从偏移16M到116M有一个空闲的100M段。让我们将其添加到 JSON 中。

# nano -w barfoo.json
man this is unreadable
# jq < barfoo.json > barfoo.pretty
# nano -w barfoo.pretty
...
  "segments": {
    "0": {
      "type": "crypt",
      "offset": "121634816",
      "iv_tweak": "0",
      "size": "88080384",
      "encryption": "aes-xts-plain64",
      "sector_size": 512
    },
    "1": {
      "type": "crypt",
      "offset": "16777216",
      "iv_tweak": "172032",
      "size": "104857600",
      "encryption": "aes-xts-plain64",
      "sector_size": 512
    }
  },
  "digests": {
    "0": {
      "type": "pbkdf2",
      "keyslots": [
        "0"
      ],
      "segments": [
        "0",
        "1"
      ],
...and so on and so forth...

结果:

# cryptsetup luksDump barfoo.img
Data segments:
  0: crypt
    offset: 121634816 [bytes]
    length: 88080384 [bytes]
    cipher: aes-xts-plain64
    sector: 512 [bytes]

  1: crypt
    offset: 16777216 [bytes]
    length: 104857600 [bytes]
    cipher: aes-xts-plain65
    sector: 512 [bytes]

不幸的是,此时,设备打开正常,尺寸增加正确(耶!),但数据错误(不!)。逻辑字节 0 映射到物理字节 16MiB,而不是预期的 116MiB。

嘿,那是段 1,不是段 0,你这个傻比利!什么地方出了错?

我不知道。这几乎就像您不应该进行简单的元数据修改来解锁尚未有人测试过的隐藏功能一样。

也许这是由于我缺乏理解,但即使以相反的方式放置片段,它仍然会以错误的顺序打开它们。有什么东西按物理偏移量对这些进行排序吗?但为什么?

不幸的是,这个特殊的魔法以失败告终。要么是因为我做错了什么,要么是它还没有准备好使用。尽管如此,该功能还是存在的——所以未来仍然充满希望。

请注意,即使它确实有效,也不建议您使用它。

相关内容