dm-crypt/设备加密

出自 Arch Linux 中文维基

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

準備[編輯 | 編輯原始碼]

在使用 cryptsetup 之前,請始終確保已加載dm_crypt內核模塊(kernel module)。

Cryptsetup 用法[編輯 | 編輯原始碼]

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

該工具的使用如下:

# cryptsetup OPTIONS action action-specific-options device dmname

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

$ cryptsetup --help 

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

$ cryptsetup benchmark 

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

提示:您可能想在學習時練習在虛擬機(virtual machine)中加密虛擬硬盤。

Cryptsetup 密碼和密鑰[編輯 | 編輯原始碼]

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

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

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

使用 dm-crypt 的加密選項[編輯 | 編輯原始碼]

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

  • --type luks 使用默認的 LUKS 格式版本(cryptsetup<2.1.0為LUKS1,cryptsetup≥2.1.0為LUKS2);
  • --type luks1 用於使用 LUKS1,最常見的LUKS 版本;
  • --type luks2 用於使用 LUKS2,LUKS的最新可用版本,允許附加擴展;
  • --type plain 使用 dm-crypt plain模式;
  • --type loopaes 用於 loopaes傳統模式;
  • --type tcrypt 用於TrueCrypt 兼容模式。
  • --type bitlk 用於 BitLocker 兼容模式。請參閱cryptsetup(8) § BITLK (Windows BitLocker-compatible) EXTENSION (EXPERIMENTAL)

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

$ less /proc/crypto 
提示:如果列表很短,請執行$ cryptsetup benchmark觸發加載可用模塊。

下面介紹 luksluks1luks2plain 模式的加密選項。請注意,表格列出了本文各個示例中使用的選項,而不是所有可用的選項。

LUKS 模式的加密選項[編輯 | 編輯原始碼]

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

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

# cryptsetup luksFormat device

從 cryptsetup 2.4.0 開始,這相當於:

# cryptsetup --type luks2 --cipher aes-xts-plain64 --hash sha256 --iter-time 2000 --key-size 256 --pbkdf argon2id --use-urandom --verify-passphrase luksFormat 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 用於 PBKDF2 密碼處理的毫秒數。版本 1.7.0 將默認值從 1000 更改為2000,以「儘量保持 PBKDF2 迭代計數仍然足夠高,並且用戶仍然可以接受。」[2]。此選項僅與設置或更改密碼的 LUKS 操作相關,例如 luksFormatluksAddKey 。指定 0作為參數選擇編譯的默認值。
--use-urandom --use-urandom --use-random 選擇要使用的隨機數生成器(random number generator)。請注意,/dev/random 阻塞池已被刪除。因此,--use-random標誌現在等同於--use-urandom
--verify-passphrase

-y

Yes - 在 Arch Linux 中默認為 luksFormatluksAddKey 啟用。

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

提示:項目開發者的 devconfcz2016(pdf)演示文稿總結了 LUKS2 主要規範更新的動機。

迭代時間[編輯 | 編輯原始碼]

來自 cryptsetup FAQ§2.1§3.4

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

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

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

扇區大小[編輯 | 編輯原始碼]

請參閱Advanced Format#dm-crypt.

plain模式的加密選項[編輯 | 編輯原始碼]

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

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

# cryptsetup options open --type plain device dmname

執行它將提示輸入密碼,該密碼應該具有非常高的熵。下面是默認參數與dm-crypt/加密整個系統#Plain dm-crypt中的示例的比較。

選項 Cryptsetup 2.1.0默認值 示例 註釋
--hash

-h

ripemd160 - 哈希(hash)用於從密碼創建密鑰;它不用於密鑰文件。
--cipher

-c

aes-cbc-essiv:sha256 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

目標硬盤的實際大小 2048 (映射設備為 512B×2048=1MiB) 限制設備的最大大小(以 512位元組扇區為單位)。
--offset

-o

0 0 從目標硬盤起始位置(the beginning of the target disk)的偏移量(以512 字節扇區為單位)開始映射。
--skip

-p

0 2048 (512B×2048=1MiB將被跳過) 開始時要跳過的 512位元組加密數據扇區的數量。
--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 開始支持此選項。

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

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

與使用 LUKS 加密不同,上述命令在需要重新建立映射時必須完整執行,因此記住密碼、哈希和密鑰文件的詳細信息很重要。我們現在可以檢查是否已進行映射:

# fdisk -l

現在一個條目應當存在於/dev/mapper/enc

使用 cryptsetup 加密設備[編輯 | 編輯原始碼]

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

警告: GRUB 對 LUKS2 的支持有限;有關詳細信息,請參閱GRUB#Encrypted /boot。對 GRUB 需要解鎖的分區使用 LUKS1 (cryptsetup luksFormat --type luks1)。

使用 LUKS 模式加密設備[編輯 | 編輯原始碼]

格式化 LUKS 分區[編輯 | 編輯原始碼]

要將分區設置為加密的 LUKS分區,請執行:

# cryptsetup luksFormat device

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

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

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

# cryptsetup luksDump device

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

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

# cryptsetup -s 512 luksFormat /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 -t ext4 /dev/mapper/root

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

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

# cryptsetup close root

使用 TPM 存儲密鑰[編輯 | 編輯原始碼]

請參閱 Trusted Platform Module#Data-at-rest encryption with LUKS.

使用plain模式加密設備[編輯 | 編輯原始碼]

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

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

# cryptsetup --type plain -v open /dev/sdaX plain1
Enter passphrase: 
Command successful.

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

# cryptsetup --type plain --cipher=serpent-xts-plain64 --hash=sha256 --key-size=256 --offset=10  open /dev/mapper/plain1 plain2
Enter passphrase:
# lsblk -p
 NAME                                                     
 /dev/sda                                     
 ├─/dev/sdaX          
 │ └─/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/sdaX plain2
# mount -t ext2 /dev/mapper/plain2 /mnt
mount: wrong fs type, bad option, bad superblock on /dev/mapper/plain2,
      missing codepage or helper program, or other error

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

以正確的順序重試:

# cryptsetup close plain2    # 上一次尝试的功能失调的映射器
# cryptsetup --type plain open /dev/sdaX plain1
Enter passphrase:
# cryptsetup --type plain --cipher=serpent-xts-plain64 --hash=sha256 --key-size=256 --offset=10 open /dev/mapper/plain1 plain2
Enter passphrase:
# 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/sdaX plain1
Enter passphrase:
# cryptsetup --type plain --offset 1000 --size 1000 --shared --cipher=aes-cbc-lmk --hash=sha256 open /dev/sdaX plain2
Enter passphrase:
# lsblk -p
NAME                    
dev/sdaX                    
├─/dev/sdaX               
│ ├─/dev/mapper/plain1     
│ └─/dev/mapper/plain2     
...

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

專門針對LUKS的Cryptsetup操作[編輯 | 編輯原始碼]

密鑰管理[編輯 | 編輯原始碼]

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

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

# cryptsetup luksDump /dev/device

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

添加 LUKS 密鑰[編輯 | 編輯原始碼]

添加新的密鑰槽是通過cryptsetup的luksAddKey動作完成的。為了安全起見,在輸入新密鑰之前,它總是會要求輸入一個有效的現有密鑰("any passphrase"),對於已經解鎖的設備也是如此。

# cryptsetup luksAddKey /dev/device (/path/to/additionalkeyfile)
Enter any 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
Enter any passphrase: 
Enter new passphrase for key slot: 
Verify passphrase:
# cryptsetup luksDump /dev/sda8 | grep 'Slot 6'
Key Slot 6: ENABLED

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

# cryptsetup luksChangeKey /dev/device -S 6
Enter LUKS passphrase to be changed: 
Enter new LUKS passphrase:

移除 LUKS 密鑰[編輯 | 編輯原始碼]

從頭中刪除密鑰有三種不同的操作:

  • luksRemoveKey 用於通過指定其密碼/密鑰文件來刪除密鑰。
  • luksKillSlot 可用於從特定密鑰槽中刪除密鑰(使用另一個密鑰)。顯然,如果您忘記了密碼、丟失了密鑰文件或無法訪問它,這將非常有用。
  • luksErase 用於快速刪除所有活動密鑰。
警告:
  • 以上所有操作都可用於不可撤銷地刪除加密設備的最後一個活動密鑰!
  • 在1.6.4版本中添加了luksErase命令,以快速關閉對設備的訪問。此操作不會提示輸入有效密碼!它不會擦除 LUKS 頭,而是一次擦除所有密鑰槽,因此,除非您擁有 LUKS 頭的有效備份,否則您將無法重新獲得訪問權限。


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

# cryptsetup --test-passphrase -v open /dev/device
Enter passphrase for /dev/device: 
Key slot 1 unlocked.
Command successful.

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

# cryptsetup luksRemoveKey /dev/device
Enter LUKS passphrase to be deleted:

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

或者,我們可以指定密鑰槽:

# cryptsetup luksKillSlot /dev/device 6
Enter any remaining LUKS passphrase:

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

# cryptsetup luksDump /dev/sda8 | grep 'Slot 6'
Key Slot 6: DISABLED

重申上面的警告:如果密鑰槽 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 卷的分區。

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

# mount --mkdir -t ramfs ramfs /root/tmp
# cryptsetup luksHeaderBackup /dev/device --header-backup-file /root/tmp/file.img
# gpg2 --recipient User_ID --encrypt /root/tmp/file.img 
# cp /root/tmp/file.img.gpg /mnt/backup/
# umount /root/tmp
警告: tmpfs 可以在內存不足的情況下交換到硬盤,所以這裏不推薦。

使用 cryptsetup 恢復[編輯 | 編輯原始碼]

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

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

# cryptsetup -v --header /mnt/backup/file.img open /dev/device test
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 也可以執行備份。首先,您必須找出加密分區的有效負載偏移量:

# 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 在 cryptsetup 2.5.0 中被移除。[4] (在Talk:Dm-crypt/設備加密討論)

cryptsetup包具有兩個重新加密選項。

cryptsetup reencrypt
cryptsetup本身的參數:首選方法。目前僅限 LUKS2 設備。可以在線執行操作。支持多個並行重新加密作業。對系統故障具有彈性。有關詳細信息,請參閱 cryptsetup(8)
cryptsetup-reencrypt
舊版工具,除 LUKS2 外,還支持 LUKS1。只能在未安裝的設備上執行操作。一次單個進程。對系統故障敏感。有關詳細信息,請參閱cryptsetup-reencrypt(8)

兩者都可用於將現有的未加密文件系統轉換為 LUKS 加密文件系統或從設備中永久刪除 LUKS 加密(使用--decrypt)。顧名思義,它也可用於重新加密現有的 LUKS 加密設備,但是,無法對分離的 LUKS 頭或其他加密模式(例如plain模式)進行重新加密。對於重新加密,可以更改#LUKS 模式的加密選項

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

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

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

加密現有的未加密文件系統[編輯 | 編輯原始碼]

提示:如果您嘗試加密現有的根分區,您可能需要創建一個將被掛載到/boot的單獨的且未加密的引導分區(請參閱Dm-crypt/Encrypting an entire system#Preparing the boot partition)。這不是絕對必要的,但有許多優點:
  • 如果/boot 位於加密的根分區內,系統將在機器開機時要求輸入兩次密碼。第一次發生在引導加載程序嘗試讀取位於加密/boot中的文件時,第二次發生在內核嘗試掛載加密分區 [5]。這可能不是所需的行為,可以通過使用單獨且未加密的引導分區來防止。
  • 如果/boot位於加密分區,某些系統還原應用程式(例如,timeshiftAUR)將無法運行[6]
簡而言之,如果需要,創建一個大小至少為 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/sdaX文件系統縮小到目前可能的最小值:

# umount /mnt
# e2fsck -f /dev/sdaX
e2fsck 1.43-WIP (18-May-2015)
Pass 1: Checking inodes, blocks, and sizes
...
/dev/sda6: 12/166320 files (0.0% non-contiguous), 28783/665062 blocks
# resize2fs -p -M /dev/sdaX
resize2fs 1.43-WIP (18-May-2015)
Resizing the filesystem on /dev/sdaX to 26347 (4k) blocks.
The filesystem on /dev/sdaX is now 26347 (4k) blocks long.
提示:使用-M 縮小到最小尺寸可能需要很長時間。您可能想要計算比當前大小僅小32 MiB 的大小,而不是使用 -M
警告: 文件系統應被縮小,而底層設備(比如說一個分區)應保持其原始大小。一些圖形工具(例如GParted)可能會同時調整文件系統和分區的大小,加密後可能會發生數據丟失。

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

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

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/sdaX 分區都被加密,而不僅僅是文件系統被壓縮的空間。作為最後一步,我們將原來的ext4文件系統擴展到現在加密的分區上,再次佔用所有可用的空間:

# cryptsetup open /dev/sdaX recrypt
Enter passphrase for /dev/sdaX: 
...
# 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

重新加密現有的 LUKS 分區[編輯 | 編輯原始碼]

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

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

為了使用現有加密選項重新加密設備,不需要指定它們:

# cryptsetup reencrypt /dev/sdaX
注意: 對於LUKS1,我們需要使用舊版工具:
# cryptsetup-reencrypt /dev/sdaX

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

# cryptsetup luksDump /dev/sdaX | 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/sdaX
注意: LUKS 頭大小將為 2 MiB 而不是 16MiB。

回滾到 LUKS1(例如,從帶有加密 /boot 的GRUB 啟動):

# cryptsetup convert --type luks1 /dev/sdaX
注意: 從 LUKS2 到 LUKS1 的轉換並非總是可行的。您可能會收到以下錯誤:
Cannot convert to LUKS1 format - keyslot 0 is not LUKS1 compatible.

調整加密設備的大小[編輯 | 編輯原始碼]

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

原因: 應該重寫本節以更通用地介紹調整大小。也許與 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 | cat - >> /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

密鑰文件[編輯 | 編輯原始碼]

注意: 本節描述使用明文密鑰文件。如果你想加密你的密鑰文件給你雙重身份驗證,請參閱使用 GPG 或OpenSSL 加密密鑰文件了解詳細信息,但仍請閱讀本節。

什麼是密鑰文件?

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

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

為什麼要使用密鑰文件?

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

密鑰文件的類型[編輯 | 編輯原始碼]

密碼[編輯 | 編輯原始碼]

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

示例: 1234

注意: 包含密碼短語的密鑰文件中不得有換行符。一種選擇是使用以下方法來創建它:
# echo -n 'your_passphrase' > /path/to/keyfile
# chown root:root /path/to/keyfile; chmod 400 /path/to/keyfile

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

# perl -pi -e 'chomp if eof' /path/to/keyfile

隨機文本[編輯 | 編輯原始碼]

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

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

二進制[編輯 | 編輯原始碼]

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

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

使用隨機字符創建密鑰文件[編輯 | 編輯原始碼]

將密鑰文件存儲在文件系統上[編輯 | 編輯原始碼]

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

這裏 dd 用於生成 2048 個隨機字節的密鑰文件,將其存儲在文件/etc/mykeyfile 中:

# dd bs=512 count=4 if=/dev/random of=/etc/mykeyfile iflag=fullblock

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

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

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

# chmod 600 /etc/mykeyfile
安全地覆蓋存儲的密鑰文件[編輯 | 編輯原始碼]

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

# shred --remove --zero mykeyfile

來安全地覆蓋它。對於 FAT 或 ext2等過時的文件系統,這已經足夠了,而在日誌文件系統、閃存硬件和其他情況下,強烈建議擦除整個設備

將密鑰文件存儲在 ramfs 中[編輯 | 編輯原始碼]

另外,您可以掛載一個 ramfs 來臨時存儲密鑰文件:

# mount --mkdir -t ramfs ramfs /root/myramfs
# cd /root/myramfs

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

# umount /root/myramfs

配置 LUKS 以使用密鑰文件[編輯 | 編輯原始碼]

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

# cryptsetup luksAddKey /dev/sda2 /etc/mykeyfile
Enter any LUKS passphrase:
key slot 0 unlocked.
Command successful.

使用密鑰文件手動解鎖分區[編輯 | 編輯原始碼]

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

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

在啟動時解鎖根分區[編輯 | 編輯原始碼]

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

下面介紹兩種情況:

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

使用存儲在外部介質上的密鑰文件[編輯 | 編輯原始碼]

配置mkinitcpio[編輯 | 編輯原始碼]

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

MODULES=(vfat)

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

重新生成 initramfs

配置內核參數[編輯 | 編輯原始碼]

在 initramfs 中嵌入密鑰文件[編輯 | 編輯原始碼]

警告: 只有你通過以下方式充分保護密鑰文件時,才使用嵌入式密鑰文件:
  • 在啟動過程的早期使用某種形式的身份驗證。否則會發生自動解密,完全違背塊設備加密的目的。
  • /boot已加密。否則,不同安裝(包括實時環境(live environment))上的 root 可以從 initramfs 中提取您的密鑰,並在沒有任何其他身份驗證的情況下解鎖設備。

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

encrypt鈎子允許用戶使用cryptkey 內核參數指定密鑰文件:在 initramfs 的情況下,語法是rootfs:/path/to/keyfile。請參閱dm-crypt/System configuration#cryptkey。此外,這個內核參數默認使用/crypto_keyfile.bin,如果 initramfs 包含具有此名稱的有效密鑰,將自動進行解密,無需配置cryptkey參數。

如果使用sd-encrypt而不是encrypt,請使用rd.luks.key內核參數指定密鑰文件的位置:在 initramfs的情況下,語法為/path/to/keyfile 。請參閱 dm-crypt/System configuration#rd.luks.key。這個內核參數默認使用/etc/cryptsetup-keys.d/name.key(其中 name是在#Encrypting devices with cryptsetup[損壞的連結:無效的章節] 中用於解密的 dm_name),如果 initramfs 包含此路徑的有效密鑰,則可以省略。

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

# dd bs=512 count=4 if=/dev/random of=/crypto_keyfile.bin iflag=fullblock
# chmod 600 /crypto_keyfile.bin
# cryptsetup luksAddKey /dev/sdX# /crypto_keyfile.bin
注意: 注意:initramfs 由 mkinitcpio 生成,默認權限600,因此普通用戶無法通過生成的 initramfs 讀取密鑰文件。

mkinitcpio 的 FILES array中括入密鑰:

/etc/mkinitcpio.conf
FILES=(/crypto_keyfile.bin)

最後重新生成initramfs

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

(資料來源)