dm-crypt/设备加密 - Arch Linux 中文维基

跳至內容

# dm-crypt/设备加密

出自 Arch Linux 中文维基
< Dm-crypt

翻譯狀態：

- 本文（或部分內容）譯自 Dm-crypt/Device encryption，最近一次同步於 2024-08-14，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

本節介紹如何從命令行手動使用 dm-crypt 來加密系統。

## 準備

在使用 cryptsetup包 之前，請始終確保已加載`dm_crypt`內核模塊（kernel module）。

## Cryptsetup 用法

cryptsetup(8) 是與 dm-crypt 交互的命令行工具，用於創建、訪問和管理加密設備。該工具後來被擴展為支持依賴 Linux 內核設備映射器和加密模塊（Linux kernel device-mapper and the cryptographic modules）的不同加密類型。最顯著的擴展是 Linux 統一密鑰設置 (LUKS) 擴展，它將 dm-crypt 所需的所有設置信息存儲在磁碟本身上，並抽象分區和密鑰管理以提高易用性。通過設備映射器訪問的設備稱為塊設備。有關詳細信息，請參閱靜態數據加密#塊設備加密（Data-at-rest encryption#Block device encryption）。

該工具的使用如下：

    # cryptsetup action options device dmname

它具有選項和加密模式的編譯默認值，如果在命令行上未指定其他值，則將使用這些默認值。看看

    $ cryptsetup --help

它按順序列出了加密模式的選項、操作和默認參數。可以在手冊頁上找到完整的選項列表。由於需要或可選不同的參數，根據加密模式和操作，以下部分將進一步指出差異。塊設備加密速度很快，但速度也很重要。由於在設置後更改塊設備的加密密碼很困難，因此提前檢查各個參數的 dm-crypt 性能很重要：

    $ cryptsetup benchmark

可以指導在安裝之前決定算法和密鑰大小。如果某些 AES 密碼以相當高的吞吐量表現出色，那麼這些密碼可能是 CPU中具有硬體支持的密碼。

提示：您可能想在學習時練習在虛擬機（virtual machine）中加密虛擬硬碟。

### Cryptsetup 密碼和密鑰

加密的塊設備受密鑰保護。密鑰可能是以下兩者之一：

- 密碼: 參見 Security#Passwords。
- 密鑰文件, 參見 #密鑰文件。

兩種密鑰類型都有默認的最大大小：密碼最多可包含 512 個字符，密鑰文件最多可包含 8192KiB。

LUKS 在這一點上需要注意的一個重要區別是，該密鑰用於解鎖 LUKS 加密設備的主密鑰，並且可以通過 root 訪問權限進行更改。其他加密模式不支持在設置後更改密鑰，因為它們不使用主密鑰進行加密。有關詳細信息，請參閱靜態數據加密#塊設備加密（Data-at-rest encryption#Block device encryption）。

## 加密選項

Cryptsetup 支持與 dm-crypt 一起使用的不同加密操作模式：

- `--type luks` 使用默認的 LUKS 格式版本（cryptsetup<2.1.0為LUKS1，cryptsetup≥2.1.0為LUKS2）；
- `--type luks1` 用於使用 LUKS1，LUKS 的過往版本；
- `--type luks2` 用於使用 LUKS2，LUKS 的當前版本，引入了附加擴展；
  - `--hw-opal-only` 用於驅動盤實現了 TCG OPAL 標準的硬體加密。見自加密驅動#使用 cryptsetup（英語：Self-encrypting drives#Using cryptsetup） 和 cryptsetup(8) § SED (SELF ENCRYPTING DRIVE) OPAL EXTENSION。
  - `--hw-opal` 用於 OPAL 硬體加密與 dm-crypt 軟體加密疊疊樂。

- `--type plain` 使用 dm-crypt plain模式；
- `--type loopaes` 用於 loopaes傳統模式；
- `--type tcrypt` 用於TrueCrypt 兼容模式。
- `--type bitlk` 用於 BitLocker 兼容模式。請參閱cryptsetup(8) § BITLK (WINDOWS BITLOCKER COMPATIBLE) EXTENSION。

可用的加密密碼和散列的基本加密選項可用於所有模式，並依賴於內核加密後端功能。所有已加載並可在運行時用作選項的內容都可以通過以下方式查看：

    $ less /proc/crypto

提示：如果列表很短，請執行`$ cryptsetup benchmark`觸發加載可用模塊。

下面介紹 `luks`、 `luks1`、 `luks2` 和 `plain` 模式的加密選項。請注意，表格列出了本文各個示例中使用的選項，而不是所有可用的選項。

### LUKS 模式的加密選項

在 LUKS 加密模式下設置新的 dm-crypt 設備的 cryptsetup 操作是`luksFormat`。與名稱所暗示的不同，它不會格式化設備，而是設置 LUKS設備標頭並使用所需的加密選項加密主密鑰。

為了使用`cryptsetup --help`列出的編譯默認值創建一個新的 LUKS 容器，只需執行：

    # cryptsetup luksFormat device

從 cryptsetup 2.4.0 開始，這相當於：

    # cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --hash sha256 --iter-time 2000 --key-size 256 --pbkdf argon2id --use-urandom --verify-passphrase device

默認值與下表中更高規格的加密示例進行了比較，並附有注釋：

選項 | Cryptsetup 2.1.0默認值 | 示例 | 注釋
--- | --- | --- | ---
--cipher -c | `aes-xts-plain64` | `aes-xts-plain64` | 1.6.0 版 改為XTS 模式下的 AES 密碼 （參閱 FAQ的第 5.16 項）。建議不要使用以前的默認值 `--cipher aes-cbc-essiv`，因為它的已知問題和針對它們的實際攻擊。
--key-size -s | `256` (XTS為`512`) | `512` | 默認情況下，XTS密碼使用512 位密鑰大小。但是請注意，XTS將提供的密鑰分成兩半，因此這會導致使用 AES-256。
--hash -h | `sha256` | `sha512` | 用於密鑰派生的哈希算法。版本 1.7.0 將默認值從 `sha1` 更改為 `sha256` 「不是出於安全原因【而】主要是為了確保它可以在SHA1不可用的系統上運行」[1]。 以前默認的`sha1`仍然可以用於與舊版本的 cryptsetup 兼容，因為它被認為是安全的(參閱第5.20 條)。
--iter-time -i | `2000` | `5000` | 用於 PBKDF 密碼處理的毫秒數。版本 1.7.0 將默認值從 `1000` 更改為`2000`，以「儘量保持 PBKDF2 迭代計數仍然足夠高，並且用戶仍然可以接受。」[2]。此選項僅與設置或更改密碼的 LUKS 操作相關，例如 `luksFormat` 或 `luksAddKey` 。指定 0作為參數選擇編譯的默認值。
--use-urandom | `--use-urandom` | `--use-random` | 選擇要使用的隨機數生成器（隨機數生成）。請注意，/dev/random 阻塞池已被刪除。因此，`--use-random`標誌現在等同於`--use-urandom`。
--verify-passphrase -y | Yes | - | 在 Arch Linux 中默認為 `luksFormat` 和 `luksAddKey` 啟用。
--sector-size | `512` 或 `4096` （設備相關） | `4096` | 設置用於磁碟加密的扇區大小（以字節為單位）。對於報告為 4Kn 或 512e 的塊設備，默認值為 `4096`；對於報告為 512n 的塊設備，默認值為 `512`。將扇區大小從 512 字節增加到 4096 字節可以在大多數現代存儲設備上提供更好的性能。請參閱 先進格式化#dm-crypt

LUKS 功能和選項的屬性在 LUKS1(pdf) 和 LUKS2(pdf) 規範中進行了描述。

提示：項目開發者的 devconfcz2016(pdf) 演示文稿總結了 LUKS2 主要規範更新的動機。另請參閱 cryptsetup 的v2 release notes

#### 迭代時間

來自 cryptsetup FAQ§2.1 和 §3.4：

  設置密碼時計算密鑰槽 [……] 的解鎖時間。默認為 1 秒（LUKS2 為 2 秒）。 [……]
  密碼迭代計數基於時間，因此安全級別取決於創建 LUKS 容器的系統的 CPU 能力。 [……]
  如果在快速機器上設置密碼，然後在慢速機器上解鎖，解鎖時間可能會更長。

因此，最好始終在最常訪問它的機器上創建一個容器。

閱讀其餘部分，了解如何在需要時正確調整迭代次數。

#### 扇區大小

請參閱Advanced Format#dm-crypt.

### plain模式的加密選項

在dm-crypt plain模式下，設備上沒有主密鑰，因此，不需要設置它。相反，要使用的加密選項被直接用來創建加密硬碟和命名設備之間的映射。映射可以針對一個分區或一個完整的設備創建。在後一種情況下，甚至不需要一個分區表。

使用cryptsetup 的默認參數創建plain模式映射：

    # cryptsetup open --type plain options device dmname

Executing it will prompt for a password, which should have very high entropy, and the `--verify-passphrase` option can be used but is not a default. In general it is advisable to make exact note of the encryption options used for the creation, because they can not be derived from the encrypted device, or an optional key-file, and upstream defaults may change. 執行它將提示輸入密碼，該密碼應該具有非常高的熵。也可以添加 `--verify-passphrase` 選項（並非默認值）。一般來說，建議準確記錄用於創建加密驅動器的選項，因為它們不能從加密設備或可選密鑰文件中獲得，而上游（簡寫的）默認值可能會更改。

選項 | Cryptsetup 2.7.0默認值 | 示例 | 注釋
--- | --- | --- | ---
--hash -h | `sha256` | - | 哈希（hash）用於從密碼創建密鑰；它不用於密鑰文件。
--cipher -c | `aes-xts-plain64` | `aes-xts-plain64` | 密碼由三部分組成：cipher-chainmode-IV generator。請參閱 Data-at-rest encryption#Ciphers and modes of operation 了解這些設置的說明，以及DMCrypt 文檔了解一些可用選項。
--key-size -s | `256` | `512` | 密鑰大小（以位（bit）為單位）。其大小將取決於使用的密碼以及使用的鏈模式。 XTS 需要兩倍於 CBC 的密鑰大小.
--size -b | 目標硬碟的實際大小 | - （默認即可） | 限制設備的最大大小（以 512位元組扇區為單位）。
--offset -o | `0` | `0` | 從目標硬碟起始位置（the beginning of the target disk）的偏移量（以512 字節扇區為單位）開始映射。
--skip -p | `0` | `2048` (512B×2048=1MiB將被跳過) | 要跳過的 512 字節加密數據扇區的數量，用於計算初始向量（IV）。
--key-file -d | 默認使用密碼 | `/dev/sdZ` (或例如 `/boot/keyfile.enc`) | 用作密鑰的設備或文件。有關詳細信息，請參閱#Keyfiles[損壞的連結：無效的章節]。
--keyfile-offset | `0` | `0` | 從密鑰開始的文件開頭（the beginning of the file）的偏移量（以字節為單位）。從cryptsetup 1.6.7 開始支持此選項。
--keyfile-size -l | `8192kB` | - (默認應用) | 限制從密鑰文件中讀取的字節數。從 cryptsetup 1.6.7 開始支持此選項。
--sector-size | `512` | `4096` | 用於磁碟加密的扇區大小（以字節為單位）。除了 4Kn 塊設備，默認值為 `512`。將扇區大小從 512 字節增加到 4096 字節可以在大多數現代存儲設備上提供更好的性能。請參閱Advanced Format#dm-crypt。

使用設備`/dev/sdX`, 上述右欄示例的結果是：

    # cryptsetup open --type plain --cipher=aes-xts-plain64 --offset=0 --skip=2048 --key-file=/dev/sdZ --key-size=512 --sector-size 4096 /dev/sdX enc

警告：與使用 LUKS 加密不同，上述命令在需要重新建立映射時必須完整執行，因此記住密碼、哈希和密鑰文件的詳細信息很重要。不要依賴 cryptsetup 的默認值，它們可能會隨著版本迭代而改變。

現在可以檢查是否已映射：

    # fdisk -l

此時一個條目應當存在於`/dev/mapper/enc`。

## 使用 cryptsetup 加密設備

本節介紹如何使用選項來創建新的加密塊設備並手動訪問它們。

警告：GRUB 對 LUKS2 的支持有限；有關詳細信息，請參閱GRUB#Encrypted /boot。對 GRUB 需要解鎖的分區請使用 基於 PBKDF2 的 LUKS2 （`cryptsetup luksFormat --pbkdf pbkdf2`）。

### 使用 LUKS 模式加密設備

#### 格式化 LUKS 分區

要將分區設置為加密的 LUKS分區，請執行：

    # cryptsetup luksFormat device

然後將提示您輸入密碼並進行驗證。

有關命令行選項，請參閱#Encryption options for LUKS mode[損壞的連結：無效的章節]。

您可以通過以下方式檢查結果：

    # cryptsetup luksDump device

您會注意到，dump 不僅顯示密碼頭信息，還顯示用於 LUKS 分區的密鑰槽。

以下示例將使用 XTS 模式下的默認 AES 密碼和有效的 256 位加密在 `/dev/sda1`上創建一個加密的根分區

    # cryptsetup luksFormat -s 512 /dev/sda1

##### 使用LUKS來格式化帶有密鑰文件的分區

在創建新的 LUKS 加密分區時，密鑰文件可能會在創建時與分區相關聯，使用：

    # cryptsetup luksFormat device /path/to/mykeyfile

有關如何生成和管理密鑰文件的說明，請參閱#密鑰文件。

#### 使用設備映射器解鎖/映射 LUKS分區

一旦創建了 LUKS 分區，就可以解鎖它們。

解鎖過程將使用設備映射器將分區映射到新的設備名稱。這提醒內核，`device`實際上是一個加密設備，應該通過 LUKS 使用 `/dev/mapper/dm_name` 尋址，以免覆蓋加密數據。為防止意外覆蓋，為了防止意外覆蓋，請閱讀在完成設置後備份cryptheader的可能性。

為了打開一個加密的LUKS分區，執行：

    # cryptsetup open device dm_name

然後將提示您輸入密碼以解鎖該分區。通常，設備映射名稱描述了被映射的分區的功能。例如，以下內容解鎖了根 luks 分區`/dev/sda1`並將其映射到名為`root`的設備映射器：

    # cryptsetup open /dev/sda1 root

打開後，根分區設備地址將是`/dev/mapper/root` 而不是分區（例如 `/dev/sda1`）。

為了在加密層上設置 LVM，解密卷組的設備文件將類似於`/dev/mapper/root`而不是`/dev/sda1`。然後LVM 將為創建的所有邏輯卷提供附加名稱如`/dev/lvmpool/root` 與`/dev/lvmpool/swap`。

為了將加密數據寫入分區，必須通過設備映射名稱對其進行訪問。訪問的第一步通常是創建文件系統。例如：

    # mkfs.ext4 /dev/mapper/root

然後，設備`/dev/mapper/root`可以像其他分區一樣被掛載(mount)。

要關閉 LUKS 容器，請卸載分區並執行以下操作：

    # cryptsetup close root

#### 使用 TPM 存儲密鑰

請參閱可信平台模塊#通過 LUKS 的靜態數據加密

### 使用plain模式加密設備

創建和後續訪問dm-crypt plain模式加密只需要使用cryptsetup `open`操作，並使用正確的參數。下面的例子展示了兩個非根設備的例子，但通過將兩個設備堆疊起來增加了一個quirk(即，第二個是在第一個設備內部創建的)。顯然，疊加加密會使開銷加倍。這裡的用例只是為了演示使用cipher選項的另一個示例。

第一個映射器是使用 cryptsetup 的plain模式默認值創建的，如上文的表中左列所述

    # cryptsetup --type plain -v open /dev/sdxY plain1

    WARNING: Using default options for cipher (aes-xts-plain64, key size 256 bits) that could be incompatible with older versions.
    WARNING: Using default options for hash (sha256) that could be incompatible with older versions.
    For plain mode, always use options --cipher, --key-size and if no keyfile is used, then also --hash.

    Enter passphrase for /dev/sdxY:
    Command successful.

現在我們在其中添加第二個塊設備，使用不同的加密參數和（可選的）偏移量，創建一個文件系統並掛載它

    # cryptsetup --type plain --cipher=serpent-xts-plain64 --hash=sha256 --key-size=256 --offset=10  open /dev/mapper/plain1 plain2

    Enter passphrase for /dev/mapper/plain1:

    # lsblk -p

     NAME
     /dev/sda
     ├─/dev/sdxY
     │ └─/dev/mapper/plain1
     │   └─/dev/mapper/plain2
     ...

    # mkfs -t ext2 /dev/mapper/plain2
    # mount -t ext2 /dev/mapper/plain2 /mnt
    # echo "This is stacked. one passphrase per foot to shoot." > /mnt/stacked.txt

我們關閉堆棧（stack），以檢查訪問是否有效

    # cryptsetup close plain2
    # cryptsetup close plain1

首先，讓我們嘗試直接打開文件系統：

    # cryptsetup --type plain --cipher=serpent-xts-plain64 --hash=sha256 --key-size=256 --offset=10 open /dev/sdxY plain2

    # mount -t ext2 /dev/mapper/plain2 /mnt

    mount: /mnt: wrong fs type, bad option, bad superblock on /dev/mapper/plain2, missing codepage or helper program, or other error.
           dmesg(1) may have more information after failed mount system call.

為什麼那行不通？因為「plain2」起始塊（`10`）仍然使用「plain1」中的密碼加密。它只能通過堆疊映射器訪問。不過這個錯誤是任意的，嘗試錯誤的口令或錯誤的選項也會產生同樣的結果。對於 dm-crypt plain 模式，`open`操作本身不會出錯。

以正確的順序重試：

    # cryptsetup close plain2    # 上一次尝试的功能失调的映射器

    # cryptsetup --type plain open /dev/sdxY plain1

    WARNING: Using default options for cipher (aes-xts-plain64, key size 256 bits) that could be incompatible with older versions.
    WARNING: Using default options for hash (sha256) that could be incompatible with older versions.
    For plain mode, always use options --cipher, --key-size and if no keyfile is used, then also --hash.

    Enter passphrase for /dev/sdxY:

    # cryptsetup --type plain --cipher=serpent-xts-plain64 --hash=sha256 --key-size=256 --offset=10 open /dev/mapper/plain1 plain2

    Enter passphrase for /dev/mapper/plain1:

    # mount /dev/mapper/plain2 /mnt && cat /mnt/stacked.txt

    This is stacked. one passphrase per foot to shoot.

dm-crypt也會處理一些混合模式的疊加加密。例如，LUKS模式可以在 「plain1」映射器上疊加。當它被關閉時，它的頭會在 「plain1」中被加密。

僅可用於plain模式的是選項`--shared`。有了它，可以將單個設備分割成不同的非重疊映射器。我們在下一個示例中就是這樣做的，這次為「plain2」使用與 loopaes兼容的密碼模式：

    # cryptsetup --type plain --offset 0 --size 1000 open /dev/sdxY plain1

    WARNING: Using default options for cipher (aes-xts-plain64, key size 256 bits) that could be incompatible with older versions.
    WARNING: Using default options for hash (sha256) that could be incompatible with older versions.
    For plain mode, always use options --cipher, --key-size and if no keyfile is used, then also --hash.

    Enter passphrase for /dev/sdxY:

    # cryptsetup --type plain --offset 1000 --size 1000 --shared --cipher=aes-cbc-lmk --hash=sha256 open /dev/sdxY plain2

    WARNING: Using default options for cipher (aes-cbc-lmk, key size 256 bits) that could be incompatible with older versions.

    For plain mode, always use options --cipher, --key-size and if no keyfile is used, then also --hash.

    Enter passphrase for /dev/sdxY:

    # lsblk -p

    NAME
    dev/sdxY
    ├─/dev/sdxY
    │ ├─/dev/mapper/plain1
    │ └─/dev/mapper/plain2
    ...

正如設備樹所示，兩者都位於同一級別，即沒有堆疊，「plain2」可以單獨打開。

## 專門針對LUKS的Cryptsetup操作

### 密鑰管理

可以為 LUKS 分區添加額外的密鑰。這使用戶能夠創建訪問密鑰以進行安全的備份存儲。在所謂的密鑰託管中，一個密鑰用於日常使用，另一個保存在託管中以獲取對分區的訪問權限，以防忘記日常密碼或密鑰文件丟失/損壞。 也可以使用不同的密鑰槽向用戶授予對分區的訪問權限，方法是發出第二個密鑰，然後再將其撤銷。

一旦創建了加密分區，就會創建初始密鑰槽0。（如果沒有手動指定其他密鑰槽）。額外的密鑰槽從1到7進行編號。可以通過發出以下命令查看哪些密鑰槽被使用

    # cryptsetup luksDump /dev/device

其中`device`是包含LUKS頭的塊設備。此命令和以下本節中的所有命令也適用於頭備份文件。

#### 添加 LUKS 密鑰

添加新的密鑰槽是動作`luksAddKey`完成的。為了安全起見，在輸入新密鑰之前，它總是會要求輸入一個有效的現有密鑰（任意已有密碼槽的密碼），對於已經解鎖的設備也是如此。

    # cryptsetup luksAddKey /dev/device (/path/to/additionalkeyfile)

    Enter any existing passphrase:
    Enter new passphrase for key slot:
    Verify passphrase:

如果給出了`/path/to/additionalkeyfile`，cryptsetup 將為 `additionalkeyfile` 添加一個新的密鑰槽。否則提示輸入新密碼。若要使用現有的密鑰文件來授權操作，`--key-file`或 `-d` 選項後跟「舊的」 `keyfile`，這樣將嘗試解鎖所有可用的密鑰文件密鑰槽：

    # cryptsetup luksAddKey /dev/device [/path/to/additionalkeyfile] -d /path/to/keyfile

如果打算使用多個密鑰並更改或撤銷它們，則可以使用 `--key-slot`或 `-S` 選項來指定密鑰槽：

    # cryptsetup luksAddKey /dev/device -S 6

    WARNING: The --key-slot parameter is used for new keyslot number.
    Enter any existing passphrase:
    Enter new passphrase for key slot:
    Verify passphrase:

    # cryptsetup luksDump /dev/device

    ...
    Keyslots:
    ...
    6: luks2
          Key:      512 bits
          Priority: normal
    ...

提示：LUKS2 可以為各個密碼槽設置優先級，請參閱 cryptsetup-config(8)。 例如，如果上述密碼槽 `6` 旨在在啟動時解鎖設備，請用 root 執行 `cryptsetup config --priority Preferred --key-slot 6 /dev/device` 。

為了在此示例中顯示關聯的操作，我們決定在繼續刪除之前立即更改密鑰：

    # cryptsetup luksChangeKey /dev/device -S 6

    Enter passphrase to be changed:
    Enter new passphrase:
    Verify passphrase:

#### 移除 LUKS 密鑰

從加密頭部中刪除密鑰有三種不同的操作：

- `luksRemoveKey` 通過指定其密碼/密鑰文件來刪除密鑰。請參閱 cryptsetup-luksRemoveKey(8) 。
- `luksKillSlot` 可用於從特定密鑰槽中刪除密鑰（使用另一個有效密鑰）。顯然，如果您忘記了密碼、丟失了密鑰文件或無法訪問它，這將非常有用。請參閱 cryptsetup-luksKillSlot(8)。
- `erase` 用於快速刪除所有激活的密鑰。請參閱 cryptsetup-erase(8)。

警告：* 以上所有操作都可用於不可撤銷地刪除加密設備的最後一個活動密鑰！

- 在1.6.4版本中添加了`erase`命令，此操作不會提示輸入有效密碼！它不會擦除 LUKS 頭，而是一次擦除所有密鑰槽，因此，除非您擁有 LUKS 頭的有效備份，否則您將無法重新獲得訪問權限。
- 對 OPAL 硬體加密的分區使用 `erase` 命令時，LUKS 頭會被清空，同時 OPAL 鎖定區域會被移除。與軟體加密不同，這個操作不可恢復，即使存在有效的 LUKS 頭備份也不行。

對於上述警告，最好知道我們要保留的密鑰是有效的。一個簡單的檢查是使用 `-v` 選項解鎖設備，該選項將指出它占用的密鑰槽：

    # cryptsetup --test-passphrase -v open /dev/device

    No usable token is available.
    Enter passphrase for /dev/device:
    Key slot 1 unlocked.
    Command successful.

現在我們可以使用其密碼刪除在上一小節中添加的密鑰：

    # cryptsetup luksRemoveKey /dev/device

    Enter passphrase to be deleted:

如果我們對兩個密鑰槽使用相同的密碼，那麼現在將擦除第一個槽。只有再次執行它才會刪除第二個。

或者，我們可以指定密鑰槽：

    # cryptsetup luksKillSlot /dev/device 6

    Enter any remaining passphrase:

請注意，在這兩種情況下，都不需要確認。

重申上面的警告：如果密鑰槽 1 和 6 使用了相同的密碼，那麼現在兩者都將消失。

### 備份與恢復

如果 LUKS 加密分區的頭被破壞，您將無法解密您的數據。這就像忘記密碼或損壞用於解鎖分區的密鑰文件一樣，都是一種困境。損壞可能是由於您在稍後重新分區硬碟時自己的錯誤或第三方程序誤解了分區表而造成的。因此，備份（LUKS 加密分區的）頭並將其存儲在另一個硬碟上可能是個好主意。

注意：如果其中一個LUKS加密分區的密碼被洩露，你必須在每一個加密頭（cryptheader）的副本上撤銷它，即使是那些你已經備份的副本。否則，使用被洩露的密碼短語的備份加密頭的副本可被用來確定主密鑰，該主密鑰可以用來解密關聯的分區（甚至是實際的分區，而不僅僅是備份的版本）。另一方面，如果主密鑰被洩露，您必須重新加密整個分區。有關詳細信息，請參閱 LUKS FAQ。

#### 使用 cryptsetup 進行備份

Cryptsetup 的`luksHeaderBackup` 操作存儲LUKS 頭和密鑰槽區域的二進制備份：

    # cryptsetup luksHeaderBackup /dev/device --header-backup-file /mnt/backup/file.img

其中`device`是包含LUKS 卷的分區。

你也可以將純文本頭備份到tmpfs中，並在將其寫入持久性存儲之前用例如GPG進行加密：

    # mount --mkdir -t tmpfs -o noswap tmpfs /root/tmp
    # cryptsetup luksHeaderBackup /dev/device --header-backup-file /root/tmp/file.img
    # gpg --recipient User_ID --encrypt /root/tmp/file.img
    # cp /root/tmp/file.img.gpg /mnt/backup/
    # umount /root/tmp

提示：選項`noswap`確保了該文件系統不會交換到硬碟中去。

#### 使用 cryptsetup 恢復

警告：恢復不正確的頭或恢復到未加密的分區將導致數據丟失!該操作無法檢查頭是否實際上是該特定設備的正確頭。

為了避免恢復錯誤的頭，你可以先使用`--header` 遠程連接它，來確保它真的沒錯。

    # cryptsetup -v --header /mnt/backup/file.img open /dev/device test

    No usable token is available.
    Enter passphrase for /dev/device:
    Key slot 0 unlocked.
    Command successful.

    # mount /dev/mapper/test /mnt/test && ls /mnt/test
    # umount /mnt/test
    # cryptsetup close test

現在檢查成功，可以執行恢復：

    # cryptsetup luksHeaderRestore /dev/device --header-backup-file ./mnt/backup/file.img

現在所有的密鑰槽區域都被重寫了；發出命令後，只有備份文件中活躍的密鑰槽可用。

#### 手動備份和恢復

頭（header）始終位於設備的開頭，並且無需訪問 cryptsetup 也可以執行備份。首先，您必須找出加密分區的有效負載偏移量：

本文或本節內容已經過時。

原因： LUKS2 有不同的 `cryptsetup luksDump` 輸出。 (在Talk:Dm-crypt/設備加密討論)

    # cryptsetup luksDump /dev/device | grep "Payload offset"

    Payload offset:	4040

其次檢查驅動器的扇區大小

    # fdisk -l /dev/device | grep "Sector size"

    Sector size (logical/physical): 512 bytes / 512 bytes

現在您知道了這些值，您可以使用簡單的 dd 命令備份頭：

    # dd if=/dev/device of=/path/to/file.img bs=512 count=4040

並安全存儲。

然後可以使用與備份時相同的值執行還原：

    # dd if=./file.img of=/dev/device bs=512 count=4040

### 重新加密設備

這篇文章的某些內容需要擴充。

原因：使用 LUKS2（帶有 16 MiB 頭）的 cryptsetup 2.2 支持在線加密/解密/重新加密。[3] (在 Talk:Dm-crypt/設備加密 中討論)

cryptsetup `reencrypt` 操作能夠重新加密 LUKS 設備。在 LUKS2 設備上，此操作可在線進行、多重並行且抗系統故障（彈性）。在 LUKS1 設備上，此操作只能離線進行（卸載後），單進程操作且更少彈性。

請參閱 cryptsetup-reencrypt(8)了解操作模式和選項。

可以藉此改變#LUKS 模式的加密選項，也可用於將現有的未加密文件系統轉換為 LUKS 加密文件系統或從設備中永久刪除 LUKS 加密（使用`--decrypt`，請參閱去除系統加密（英語：Removing system encryption））。對於分離的 LUKS 標頭，重新加密也是可行的，但請注意 `--header` 選項的警告。不支持 LUKS 以外的模式（例如 plain 模式）的重新加密。

重新加密的一種應用可能是在密碼或#密鑰文件被洩露並且不能確定（對方）沒有獲得 LUKS 頭的副本後再次保護數據。例如，如果只有一個口令被竊取，但沒有發生對設備的物理/邏輯訪問，那麼只需改變相應的口令/密鑰即可（#密鑰管理）。

警告：始終確保有可靠的備份可用，並在使用該工具之前仔細檢查您指定的選項！

下面展示了一個對未加密的文件系統分區進行加密以及對現有LUKS設備進行重新加密的例子。

#### 加密現有的未加密文件系統

提示：如果您嘗試加密現有的根分區，您可能需要創建一個將被掛載到`/boot`的單獨的且未加密的引導分區（請參閱dm-crypt/加密整個系統#準備boot分區）。這不是絕對必要的，但有許多優點：

- 如果`/boot` 位於加密的根分區內，系統將在機器開機時要求輸入兩次密碼。第一次發生在引導加載程序嘗試讀取位於加密`/boot`中的文件時，第二次發生在內核嘗試掛載加密分區 [4]。這可能不是所需的行為，可以通過使用單獨且未加密的引導分區來防止。
- 如果`/boot`位於加密分區，某些系統還原應用程式（例如，timeshift包）將無法運行[5]。

簡而言之，如果需要，創建一個大小至少為 260 MiB 的分區。請參閱Partitioning#/boot。

LUKS 加密頭始終存儲在設備的起始（the beginning of the device）。由於現有文件系統通常會分配所有分區扇區，因此第一步是縮小它以給 LUKS頭騰出空間。

這篇文章的某些內容需要擴充。

原因：cryptsetup手冊建議使用兩倍於LUKS2頭的大小，也就是32MB，並使用`--reduce-device-size 32M`。 (在 Talk:Dm-crypt/設備加密 中討論)

默認的LUKS2頭需要16兆字節。如果當前的文件系統占據了所有的可用空間，那麼我們至少要縮減這麼多。要將`ext4`上現有的`/dev/sdxY`文件系統縮小到目前可能的最小值:

    # umount /mnt

    # e2fsck -f /dev/sdxY

    e2fsck 1.46.5 (30-Dec-2021)
    Pass 1: Checking inodes, blocks, and sizes
    ...
    /dev/sda6: 12/166320 files (0.0% non-contiguous), 28783/665062 blocks

    # resize2fs -p -M /dev/sdxY

    e2fsck 1.46.5 (30-Dec-2021)
    Resizing the filesystem on /dev/sdxY to 26347 (4k) blocks.
    The filesystem on /dev/sdxY is now 26347 (4k) blocks long.

提示：使用`-M` 縮小到最小尺寸可能需要較長時間。您可能想要計算比當前大小僅小32 MiB 的大小，而不是使用 `-M` 。
警告：文件系統應被縮小，而底層設備（比如說一個分區）應保持其原始大小。一些圖形工具（例如GParted）可能會同時調整文件系統和分區的大小，加密後可能會發生數據丟失。

現在我們使用默認密碼對其進行加密，我們不必明確指定它：

    # cryptsetup reencrypt --encrypt --reduce-device-size 16M /dev/sdxY

    WARNING!

    ========

    This will overwrite data on LUKS2-temp-12345678-9012-3456-7890-123456789012.new irrevocably.

    Are you sure? (Type 'yes' in capital letters): YES
    Enter passphrase for LUKS2-temp-12345678-9012-3456-7890-123456789012.new:
    Verify passphrase:

完成後，整個`/dev/sdxY` 分區都被加密，而不僅僅是文件系統被壓縮的空間。作為最後一步，我們將原來的`ext4`文件系統擴展到現在加密的分區上，再次占用所有可用的空間：

    # cryptsetup open /dev/sdxY recrypt

    Enter passphrase for /dev/sdxY:
    ...

    # resize2fs /dev/mapper/recrypt

    resize2fs 1.43-WIP (18-May-2015)
    Resizing the filesystem on /dev/mapper/recrypt to 664807 (4k) blocks.
    The filesystem on /dev/mapper/recrypt is now 664807 (4k) blocks long.

    # mount /dev/mapper/recrypt /mnt

文件系統現在可以使用了。您可能希望將其添加到您的crypttab。

提示：如果剛剛加密了根分區，可能需要做許多加密後的調整。

1. 配置 mkinitcpio 和內核參數。參閱Dm-crypt/系統配置#在早期用戶空間解密
2. 更新 fstab 中的 `/` 條目，使用解鎖卷的標識 (如使用 UUID).

#### 重新加密現有的 LUKS 分區

在此示例中，現有的 LUKS 設備被重新加密。

警告：請仔細檢查您是否正確指定了加密選項，並且在沒有可靠備份的情況下永遠不要重新加密！

若要使用 LUKS2/1 默認加密選項重新加密設備：

     # cryptsetup reencrypt /dev/sdxY

使用不同的密碼和/或散列重新加密設備時，會保留現有密鑰。另一個用例是重新加密具有非當前加密選項的 LUKS 設備。除了上述關於正確指定選項的警告外，更改 LUKS 頭的能力也可能受到其大小的限制。例如，如果設備最初使用 CBC 模式密碼和 128 位密鑰大小加密，則 LUKS 頭將是上述`4096`個扇區大小的一半：

本文或本節內容已經過時。

原因： LUKS2 有不同的 `cryptsetup luksDump` 輸出。 (在Talk:Dm-crypt/設備加密討論)

    # cryptsetup luksDump /dev/sdxY | grep -e "mode" -e "Payload" -e "MK bits"

    Cipher mode:   	cbc-essiv:sha256
    Payload offset:	2048
    MK bits:       	128

雖然可以升級這種設備的加密，但目前只能分兩步進行。首先，使用相同的加密選項重新加密，但使用`--reduce-device-size` 選項為更大的 LUKS 頭騰出更多空間。其次，使用所需的密碼再次重新加密整個設備。由於這個原因以及在任何情況下都應該創建備份的事實，創建一個新的、全新的加密設備來恢復始終是更快的選擇。

### 從LUKS1到LUKS2的轉換和回退

cryptsetup包包具有`convert`選項，用於在 LUKS1 和 LUKS2 容器類型之間進行轉換。參數 `--type` 是必需的。

從 LUKS1 遷移到 LUKS2：

    # cryptsetup convert --type luks2 /dev/sdxY

注意：LUKS 頭大小將為 16 MiB 而不是 2MiB。

回滾到 LUKS1（例如，從帶有加密 /boot 的GRUB 啟動）：

    # cryptsetup convert --type luks1 /dev/sdxY

注意：從 LUKS2 到 LUKS1 的轉換並非總是可行的。您可能會收到以下錯誤：

    Cannot convert to LUKS1 format - keyslot 0 is not LUKS1 compatible.

If the container is using Argon2, it needs to be converted to PBKDF2 to be LUKS1-compatible.

    # cryptsetup luksConvertKey --pbkdf pbkdf2 /dev/sdxY

## 調整加密設備的大小

這篇文章的某些內容需要擴充。

原因：應該重寫本節以更通用地介紹調整大小。也許與 Resizing LVM-on-LUKS 同步工作。 (在 Talk:Dm-crypt/設備加密 中討論)

如果將使用 dm-crypt 加密的存儲設備（使用dd 之類的工具）克隆到另一個更大的設備，則必須調整底層 dm-crypt 設備的大小以使用整個空間。

在此示例中，目標設備是 /dev/sdX2，將使用與分區相鄰的整個可用空間：

    # cryptsetup luksOpen /dev/sdX2 sdX2
    # cryptsetup resize sdX2

然後必須調整底層文件系統的大小。

### 回送文件系統

假設一個加密的回送文件系統存儲在文件`/bigsecret`中，循環到`/dev/loop0`，映射到`secret`並掛載在`/mnt/secret`上，如 dm-crypt/Encrypting a non-root file system#File container中的例子。

如果容器文件當前已映射和/或掛載，請卸載 並且/或著 關閉它：

    # umount /mnt/secret
    # cryptsetup close secret
    # losetup -d /dev/loop0

接下來，使用要添加的數據大小擴展容器文件。在本例中，文件將擴展 1M * 1024，即1G。

警告：一定確保使用兩個`>`，而不是只有一個，否則你會覆蓋文件，而不是追加到它。強烈建議在這一步驟之前做一個備份。

    # dd if=/dev/urandom bs=1M count=1024 iflag=fullblock >> /bigsecret

現在將容器映射到回送設備：

    # losetup /dev/loop0 /bigsecret
    # cryptsetup open /dev/loop0 secret

在此之後，將容器的加密部分的大小調整為容器文件的新的最大尺寸：

    # cryptsetup resize secret

最後，執行文件系統檢查，如果沒問題，調整它的大小（例如ext2/3/4）：

    # e2fsck -f /dev/mapper/secret
    # resize2fs /dev/mapper/secret

您現在可以再次掛載容器：

    # mount /dev/mapper/secret /mnt/secret

### 完整性保護設備

如果設備是在支持完整性的情況下格式化的 (例如 `--integrity hmac-sha256`) 並且支持塊設備縮小，則無法打開它，並出現以下錯誤： `device-mapper: reload ioctl on failed: Invalid argument`.

為了解決這個問題而不再次擦除設備，可以用以前的主密鑰進行格式化（保持每個扇區的標籤有效）。

    # cryptsetup luksDump /dev/sdX2 --dump-master-key --master-key-file=/tmp/masterkey-in-tmpfs.key
    # cryptsetup luksFormat /dev/sdX2 --type luks2 --integrity hmac-sha256 --master-key-file=/tmp/masterkey-in-tmpfs.key --integrity-no-wipe
    # rm /tmp/masterkey-in-tmpfs.key

## 密鑰文件

注意：本節描述使用明文密鑰文件。如果你想加密你的密鑰文件給你雙重身份驗證，請參閱dm-crypt/特殊應用#使用GPG、LUKS、OpenSSL加密的密鑰文件了解詳細信息，但仍請閱讀本節。

什麼是密鑰文件？

密鑰文件是將其數據用作解鎖加密卷的密碼的文件。 這意味著如果此類文件丟失或更改，則可能無法再解密該卷。

提示：在密鑰文件之外定義一個密碼，以便在定義的密鑰文件丟失或改變的情況下對加密卷進行備份訪問。

為什麼要使用密鑰文件？

密鑰文件有很多種。所使用的每種類型的密鑰文件都有以下總結的優點和缺點:

### 密鑰文件的類型

#### 密碼

這是一個包含簡單密碼的密鑰文件。這種類型的密鑰文件的好處是，如果文件丟失，它包含的數據是已知的，並且很容易被加密卷的所有者記住。然而，缺點是這不會增加在初始系統啟動期間輸入密碼的任何安全性。

示例： `1234`

{{注意|包含密碼短語的密鑰文件中不得有換行符。一種選擇是使用以下方法來創建它：

     # mkdir -m 700 /etc/cryptsetup-keys.d
     # echo -n 'your_passphrase' > /etc/cryptsetup-keys.d/keyfile.key
     # chmod 600 /etc/cryptsetup-keys.d/keyfile.key

如果文件包含特殊字符，例如反斜槓，而不是轉義這些字符，建議直接編輯密鑰文件，直接輸入或粘貼密碼，然後用方便的perl命令一行刪除結尾換行：

     # perl -pi -e 'chomp if eof' /etc/cryptsetup-keys.d/keyfile.key

#### 隨機文本

這是一個包含隨機字符塊的密鑰文件。這種類型的密鑰文件的好處是它比簡單的密碼更能抵抗字典攻擊。在這種情況下，可以利用密鑰文件的另一個優勢，即所用數據的長度。由於這不是要由人記住以供輸入的字符串，因此創建包含數千個隨機字符作為密鑰的文件是微不足道的。缺點是如果此文件丟失或更改，則很可能在沒有備份密碼的情況下無法訪問加密卷。

示例: `fjqweifj830149-57 819y4my1-38t1934yt8-91m 34co3;t8y;9p3y-`

#### 二進制

這是一個已被定義為密鑰文件的二進制文件。在將文件識別為密鑰文件的候選文件時，建議選擇相對靜態的文件，例如照片、音樂、視頻剪輯。這些文件的好處是它們具有雙重功能，使它們更難被識別為密鑰文件。與具有大量隨機文本的文本文件不同，這種密鑰文件對於旁觀者來說看起來就像一個普通的圖像文件或音樂剪輯。缺點是如果此文件丟失或更改，則很可能在沒有備份密碼的情況下無法訪問加密卷。此外，與隨機生成的文本文件相比，理論上存在隨機性損失。這是因為圖像、視頻和音樂在相鄰數據位之間具有某種內在關係，而隨機文本文件不存在這種關係。然而，這是有爭議的，從未被公開利用。

示例： 圖片、文本、視頻……

### 使用隨機字符創建密鑰文件

#### 將密鑰文件存儲在文件系統上

密鑰文件可以是任意內容和大小。

這裡 dd 用於生成 2048 個隨機字節的密鑰文件，將其存儲在文件`/etc/cryptsetup-keys.d/mykeyfile.key` 中：

     # mkdir -m 700 /etc/cryptsetup-keys.d
     # dd bs=512 count=4 if=/dev/random of=/etc/cryptsetup-keys.d/mykeyfile.key iflag=fullblock

如果你計劃將密鑰文件存儲在一個外部設備上，也可以輕鬆將輸出文件更改為對應的目錄：

     # dd bs=512 count=4 if=/dev/random of=/run/media/user/usbstick/mykeyfile.key iflag=fullblock

要拒絕除`root` 以外的其他用戶的任何訪問：

     # chmod 600 /etc/cryptsetup-keys.d/mykeyfile.key

##### 安全地覆蓋存儲的密鑰文件

如果你把你的臨時密鑰文件存儲在一個物理存儲設備上，並想刪除它，記住以後不要只是刪除密鑰文件，而是使用類似於

    # shred --remove --zero mykeyfile

來安全地覆蓋它。對於 FAT 或 ext2等過時的文件系統，這已經足夠了，而在日誌文件系統、快閃記憶體硬體和其他情況下，強烈建議擦除整個設備（英語：Securely_wipe_disk）。

#### 將密鑰文件存儲在 tmpfs 中（關閉 swap）

另外，您可以掛載一個 tmpfs（關閉 swap） 來臨時存儲密鑰文件：

     # mount --mkdir -t tmpfs -o noswap tmpfs /root/mytmpfs
     # cd /root/mytmpfs

優點是它駐留在 RAM 中而不是物理磁碟上，因此卸載 tmpfs 後無法恢復。將密鑰文件複製到另一個安全且持久的文件系統後，再次卸載 tmpfs：

    # umount /root/mytmpfs

### 配置 LUKS 以使用密鑰文件

將密鑰文件的密鑰槽添加到 LUKS 頭：

    # cryptsetup luksAddKey /dev/sda2 /etc/cryptsetup-keys.d/mykeyfile.key

    Enter any existing passphrase:

### 使用密鑰文件手動解鎖分區

打開 LUKS設備時使用`--key-file` 選項：

     # cryptsetup open /dev/sda2 dm_name --key-file /etc/cryptsetup-keys.d/mykeyfile.key

### 在啟動時解鎖根分區

這只是配置mkinitcpio以包括必要的模塊或文件，並配置cryptkey以及內核參數以知道在哪裡找到密鑰文件。

下面介紹兩種情況：

1. 使用存儲在外部介質（例如 U盤）上的密鑰文件
2. 使用嵌入在initramfs 中的密鑰文件

#### 使用存儲在外部介質上的密鑰文件

##### 配置mkinitcpio

您必須將驅動器文件系統的內核模塊添加到 `/etc/mkinitcpio.conf`中的 MODULES array中。例如，如果文件系統是Ext4，則添加`ext4`；如果是FAT，則添加`vfat`：

    MODULES=(vfat)

如果在啟動時有關於壞的超級塊和壞的碼表的信息，那麼你需要加載一個額外的碼表模塊。例如，你可能需要`nls_iso8859-1`模塊來加載`iso8859-1`編碼頁。

重新生成 initramfs。

##### 配置內核參數

- 對於使用encrypt鉤子的基於busybox的initramfs，參閱Dm-crypt/系統配置#cryptkey。
- 對於使用sd-encrypt鉤子的基於systemd的initramfs，參閱Dm-crypt/系統配置#rd.luks.key。

#### 在 initramfs 中嵌入密鑰文件

警告：只有你通過以下方式充分保護密鑰文件時，才使用嵌入式密鑰文件：

- 在啟動過程的早期使用某種形式的身份驗證。否則會發生自動解密，完全違背塊設備加密的目的。
- `/boot`已加密。否則，不同安裝（包括實時環境（live environment））上的 root 可以從 initramfs 中提取您的密鑰，並在沒有任何其他身份驗證的情況下解鎖設備。

此方法允許使用一個特殊命名的密鑰文件，該密鑰文件將嵌入到 initramfs 中並由 `encrypt`鉤子拾取以自動解鎖根文件系統（ `cryptdevice` ）。在使用 GRUB 早期加密硬碟功能時應用它可能很有用，以避免在引導期間輸入兩個密碼。

生成密鑰文件，為其賦予適當的權限並將其添加為 LUKS 密鑰：

     # mkdir -m 700 /etc/cryptsetup-keys.d
     # dd bs=512 count=4 if=/dev/random of=/etc/cryptsetup-keys.d/root.key iflag=fullblock
     # chmod 600 /etc/cryptsetup-keys.d/root.key
     # cryptsetup luksAddKey /dev/sdX# /etc/cryptsetup-keys.d/root.key

注意：注意：initramfs 由 mkinitcpio 生成，默認權限為`600`，因此普通用戶無法通過生成的 initramfs 讀取密鑰文件。

在 mkinitcpio 的 FILES array中括入密鑰：

    /etc/mkinitcpio.conf

    FILES=(/etc/cryptsetup-keys.d/root.key)

重新生成initramfs

對於 `encrypt` 鉤子，密鑰文件由 `cryptkey=` 內核參數指定：在 initramfs，語法為 `rootfs:/path/to/keyfile`。默認值為 `/crypto_keyfile.bin`，如果 initramfs 包含此路徑的有效密鑰，則可以省略 `cryptkey`。請參閱Dm-crypt/系統配置#cryptkey。

對於上述示例，當在 busybox-based initramfs 中使用 `encrypt` 鉤子時，設置內核參數：

    cryptkey=rootfs:/etc/cryptsetup-keys.d/root.key

若以 `sd-encrypt` 鉤子替代，密鑰文件通過 `rd.luks.key=` 內核參數指定。默認值是 `/etc/cryptsetup-keys.d/name.key`（其中 `name` 是用於 #使用 cryptsetup 加密設備 中解密的 dm_name）。且當 initramfs 包含此路徑的有效密鑰時， `rd.luks.key` 可省略。參閱 Dm-crypt/系統配置#rd.luks.key。

在下一次重新啟動時，您應該只需要輸入一次容器解密密碼。

(資料來源)

分類：​

- 靜態數據加密
- 使用「模板:過時」標記的頁面或章節

隱藏分類：​

- 包含損壞章節連結的頁面

dm-crypt/设备加密
新增話題