Dm-crypt によるフルディスク暗号化
この記事では dm-crypt を (フル) ディスク暗号化に使用する際のいくつかの側面について解説します。この記事は主に dm-crypt、genkernel、または initramfs の wiki ページで書かれていない情報の補足的情報源となることを意図しています。
この記事で補足的に説明しているすべてのセキュリティ戦略は任意です。ここで提示しているいくつかの観点は、日常的に疑問を呈されていたり、高度に個人的なセキュリティ上の信念であると議論されています。したがって、この記事の目的は、願わくは客観的な議論を提供することです。さらなる情報源としては、cryptsetup FAQ を強くおすすめします。
どの暗号化:ハッシュの組み合わせか?
現在の LUKS におけるデフォルトの暗号は aes-xts-plain64
、すなわち AES 暗号化と XTS 利用モードです。これは、極めて限られた状況を除いては変更すべきではありません。この既定値は、セキュリティ上合理的な選択であると同時に、AES-NI を備えた CPU では 2-3 GiB/s で暗号化/復号化することができるため、パフォーマンス上も群を抜いて最良の選択です。
AES-NI が利用可能かどうかは以下のようにして確認できます:
user $
grep -m1 'aes' /proc/cpuinfo
XTS では2つの AES 鍵を使用するため、使用できる鍵長は -s 256
と -s 512
です。
デフォルトの暗号と鍵長は、以下の例のようにコマンドライン引数 -c
と -s
で上書きできます。
root #
cryptsetup luksFormat -c aes-xts-plain64 -s 512 ...
root #
cryptsetup luksFormat -c aes-cbc-essiv:sha256 -s 256 ...
ある暗号と利用モードの組み合わせのパフォーマンスについてよりよく知るには、ベンチマークを以下のようにして実行します:
root #
cryptsetup -c ... -s ... benchmark
このコマンドを -c
と -s
を付けずに実行すると、様々な選択肢についてベンチマークが実行されます。例えば、2014年半ばの Intel Core i7 CPU での(少し短縮した)出力は以下のようになります:
root #
cryptsetup benchmark
# Tests are approximate using memory only (no storage IO). # Algorithm | Key | Encryption | Decryption aes-cbc 256b 469.7 MiB/s 2093.2 MiB/s serpent-cbc 256b 85.3 MiB/s 523.3 MiB/s twofish-cbc 256b 173.4 MiB/s 340.2 MiB/s aes-xts 256b 2386.7 MiB/s 2387.4 MiB/s serpent-xts 256b 548.6 MiB/s 531.1 MiB/s twofish-xts 256b 320.0 MiB/s 342.3 MiB/s
dm-crypt は多くの暗号、利用モード、IV モードの組み合わせをサポートしていますDMCrypt wiki。これらのうちいくつかは他よりも安全性に劣っており、いくつかは非常に危険です (例えば ECB)。暗号や利用モードの詳細については Wikipedia を参照してください。よく分からなければ、デフォルト値のままにしておいてください。
cryptsetup luksFormatの使用方法に関するさらなる情報は dm-crypt のウィキページにあります。
例えば
aes-cbc-essiv:sha256
のように、いくつかの暗号の選択肢ではさらに cipher:hash
という形式でのハッシュ指定があります。このようなハッシュの指定は、(cbc-essiv
のような)いくつかの利用モードで IV を生成するために使用されます。しかしながら、plain64
の付く利用モードでは、このようなハッシュの指定は(IV の生成には)使用されません。この場合には、ハッシュの指定は取り除くべきです。鍵導出用にどのハッシュを選択するか?
LUKS では鍵導出に PBKDF2 を使用します。概要としては、ユーザーによって入力されたパスフレーズはソルトと組み合わせられ、指定された回数ハッシュされます。この鍵ストレッチング によって、パスワードの総当たり攻撃に対する安全性が増します。PBKDF2 で使用されるハッシュ関数は -h
を通じて設定できます。デフォルトは sha256
であり、(お好みで) 別の安全なハッシュアルゴリズムに変更することができます。反復回数の合計は使用しているハードウェアの速度によって決まりますが、PBKDF2 パスフレーズの処理に費やされるミリ秒数を --iter-time
で設定することで影響を与えることもできます。デフォルト値を2秒から3秒に増やし、sha512 を使用する場合、例えば以下のようにします:
root #
cryptsetup luksFormat ... -h sha512 --iter-time 3000 ...
上流の FAQ によれば、PBKDF2 の反復回数をデフォルト値よりも下げることは推奨されません。
パスフレーズ、分離された LUKS ヘッダー及び(暗号化された)キーファイル
十分に長いパスフレーズ(例えば、8-12 個のランダムな一般的単語。この問題については xkcd を見てください)を、鍵ストレッチのために PBKDF2 と組み合わせて使用します。
復号化のための重要な情報(例えばキーファイルや LUKS ヘッダーそのものなど)を格納する外部 USB フラッシュドライブを導入することで、総当たり攻撃に対するさらなる保護を実現できます。これによって、そのフラッシュドライブは物理的な鍵と同等の機能を持ちます; フラッシュドライブとパスフレーズが両方とも揃った場合にのみ、暗号化されたパーティションを開くことができます。しかしながら、この手法は、例えばディスク全体の暗号化を導入する際の複雑さや、(USB フラッシュドライブを紛失して)復号鍵を失う可能性の観点から見ると重大な短所を抱えています。
分離された LUKS ヘッダー
(パスワード導出に関する全ての情報が格納されている)分離されたLUKS ヘッダーを例えば USB フラッシュドライブなどの(物理的に)異なる場所に格納し、これを使用してパーティションを暗号化することができます。こうすると、そのフラッシュドライブを所持していない攻撃者に、使用されている鍵導出アルゴリズムや暗号アルゴリズムに関する情報を与えないようにできます。これにより、総当たり攻撃が潜在的により困難になります。
以下のコマンドは、まず luks-header
ファイルを5MBの固定サイズで作成します。次に、分離された LUKS ヘッダーがこのファイルに書き込まれます。(cryptsetup luksFormat や cryptsetup openコマンドの詳しい使用方法については、dm-crypt ウィキページを参照してください。)
root #
truncate -s 5M /path/to/luks-header
root #
cryptsetup luksFormat ... --header /path/to/luks-header ...
ヘッダーの書き込みが成功したことを確認するには、cryptsetup luksDump /path/to/luks-header を実行します。
暗号化されたデバイスを開くには、以下を実行します:
root #
cryptsetup open ... --header /path/to/luks-header
現在のところ、genkernel は分離された LUKS ヘッダーをサポートしていません。
GnuPG で暗号化されたキーファイルを生成する
USB フラッシュドライブを使用するためのより伝統的なやり方として、GnuPG で暗号化された(十分なエントロピーを含む)キーファイルを格納するというものがあります。このようなキーファイルは、genkernel で容易にサポートされています。
以下のコマンドは GnuPG で暗号化された512ビットのキーファイルを作成し、それを使って暗号化されたパーティションをセットアップします:
root #
dd if=/dev/urandom count=64 | gpg --symmetric --cipher-algo aes --armor > /path/to/key.gpg
root #
gpg --decrypt /path/to/key.gpg | cryptsetup luksFormat ...
暗号化されたデバイスを開くには、
root #
gpg --decrypt /path/to/key.gpg | cryptsetup open ...
当然ながら、dm-crypt は、暗号化されていない平文のキーファイルも使用できます。dm-crypt のウィキページを参照してください。ルートパーティションに保存した平文のキーファイルを"chain open"のために使用する方法については、さらに下の方で触れます。
ディスクの準備
この節で概説している方法を SSD に適用する場合、さらなる配慮が必要です。
ディスクの暗号化を設定する前にディスク全体を乱数で上書きすることもしばしば推奨されています。これが推奨される根拠は、暗号化されたディスクの読み込みによって漏れる情報を可能な限り少なくするべきであるというものです。しかし、それでも(ファイルシステムによって)使用されていないブロックが全てゼロになっていれば、敵対者は、(内容がランダムに見えるデータが含まれているため)どれが使用されていそうな(暗号化された)ブロックで、(例えば、全てゼロであるため)どれが使用されていないブロックであるか判別することによって、高レベルな情報をある程度復元することができます。使用されていそうな暗号化されたブロックの数と分布から、ディスクの使用率、使用しているファイルシステム、あるいはおそらくファイルの平均サイズといった情報が明らかにされる可能性があります。
したがって、ある程度効果的で(しかし時間のかかる)対策は、ディスクを使用する前にランダムなデータで上書きすることです。大量のランダムなデータを高速に生成する効率的な方法の1つは、cryptsetup のマッピングを使用することです。例えば、/dev/sdXX を上書きするには、
root #
cryptsetup open --type=plain --key-file=/dev/urandom /dev/sdXX delete_sdXX
root #
dd if=/dev/zero of=/dev/mapper/delete_sdXX bs=1M status=progress
root #
cryptsetup close delete_sdXX
これが終わったら、cryptsetup luksFormat ... としてディスクをフォーマットします。
SSD 全体をランダムなデータで上書きすると全てのブロックが使用済として記録され、メーカーとモデルによっては、ウェアレベリングが激しく劣化する可能性があります。こうなると、ディスクの寿命に潜在的に破滅的な効果をもたらすかもしれません。緩和策として、ウェアレベリングのために十分な空のブロックが残るよう、ディスクの相当部分、10-20% 程度を未使用にしておくことがしばしば推奨されます。そのためには、適切な大きさのフォーマットされていないパーティションを作成し、
blkdiscard
を使ってこれを適切に discard します。LUKS コンテナを --allow-discards
オプションを付けてマウントすると discard を SSD へ透過的に転送できますが、これは上記の構成とは矛盾することに留意してください。SSD や ハイブリッドドライブ上の dm-crypt
SSD やハイブリッドドライブ上で dm-crypt を使用する場合におけるセキュリティ面の更なる情報については、cryptsetup の FAQ を参照してください。
cryptsetup は、SSD へ discard 操作を透過的に転送することができます。この機能は --allow-discards
オプションを cryptsetup open と組み合わせて使うことで有効化できます。discard を暗号化された SSD 上で有効化することは、特にディスク全体が暗号化されている場合、効果的にウェアレベリングを行ってディスクを長命化する方策になるかもしれません。これに関するセキュリティ上の影響についての詳細な議論は、cryptsetup の FAQ や cryptsetup の man ページを参照してください。
initramfs を生成する
システムやディスクを暗号化すると、その中にあるルートファイルシステムをマウントして真の init に制御を渡せるようにするために、initramfs が必要になることがあります。dracut、mkinitcpio (ebuild やフォーラム内のスレッドがあります: sys-kernel/mkinitramfs-ll)、genkernel (やその後継) などの、LUKS をサポートするいくつかの一般的な initramfs 生成ツールを使うとこの目的を達成できます。
Genkernel
以下の例では、(カーネル全体ではなく) initramfs のみを生成し、luks のサポートを有効化するために sys-kernel/genkernel を使用します:
root #
genkernel --luks --lvm initramfs
より網羅的な説明については、/etc/genkernel.conf 自体のコメントや man genkernel の出力を参照してください。
initrd にドライブを復号化する方法を伝えるためにはパラメーターが必要になりますが、これは他のカーネルパラメーターと同じ方法で渡します。例えば:
title Gentoo Linux 3.4.0-gentoo
root (hd0,0)
kernel /boot/kernel-3.4.0-gentoo crypt_root=UUID=<encrypted partition uuid> root=/dev/mapper/root
initrd /boot/initramfs-3.4.0-gentoo
暗号化されたデバイスが対応している場合には root_trim=yes とすることで TRIM のサポートを有効化できますが、まずは cryptsetup ウィキの --allow-discards 節で概説されている、これによるセキュリティへの影響について読んでください。
genkernel の記事に更なる情報があります。
Dracut
sys-kernel/dracut は RedHat プロジェクトから移植されたパッケージで、initramfs を生成する似たようなツールを提供します。いくつかのモジュールが必要になります。 dracut を参照してください。一般的には、以下のコマンドによって、使えるデフォルトの initramfs が生成されます。
root #
dracut -a crypt
initrd にドライブを復号化する方法を伝えるためにはパラメーターが必要になりますが、これは他のカーネルパラメーターと同じ方法で渡します。例えば:
title Gentoo Linux 3.4.0-gentoo
root (hd0,0)
kernel /boot/kernel-3.4.0-gentoo root=UUID=<root filesystem uuid> rd.luks.uuid=<encrypted partition uuid>
initrd /boot/initramfs-3.4.0-gentoo.img
dracut は、複数の候補に当てはまらない限り、完全でない UUID でも一致します。そのため、簡潔さや明瞭さを重視する場合、最初の一節のみを入力することもできます。
暗号化されたデバイスが対応している(つまり SSD の)場合には rd.luks.allow-discards とすることで TRIM のサポートを有効化できますが、まずは cryptsetup ウィキの --allow-discards 節で概説されている、これによるセキュリティへの影響について読んでください。
dracut における luks のオプションの網羅的なリストについては、dracut のマニュアルを参照してください。
Mkinitramfs-LL
非公式の sys-kernel/mkinitramfs-ll (tokiclover's bar-overlay にあります)は、上述した有名な initramfs 生成ツールの軽量かつモジュール化された版であり、udev に依存しません。これはデフォルトでは mdev を含む busybox のみに依存していますが、追加機能についてはさらなる依存パッケージが必要です。そのため、initramfs には bash、coreutils、util-linux のいずれも組み込まれません。 同様に、LVM 上の DM-Crypt LUKSやその逆、DM-Crypt LUKS 上の btrfs や ZFS、RAID 上の DM-Crypt LUKS、dm-crypt LUKS ヘッダーの(デバイスやファイルへの)分離など、さらに柔軟な構成もできます。
root #
mkinitramfs-ll --luks --lvm --firmware=iwlwifi-5000
通常のキーファイルをリムーバブルデバイスに置く LVM/LUKS の構成を起動するには、以下の GRUB2 の設定の抜粋を使用します。
'"`UNIQ--pre-00000008-QINU`"'
設定ファイル(mkinitramfs-ll.conf)内には、コマンドライン引数と同様の効果を持つ環境変数を設定するためのオプションの環境変数が含まれており、これを使ってカーネルコマンドラインのないカーネルを起動することができます。しかしながら、この(環境変数としての)デフォルトのコマンドラインは、実行時に env=No コマンドライン引数を追加することで、必要に応じて無効にすることができます。
関連項目
- Genkernel — カーネルと initramfs を自動的にビルドすることができる Gentoo 謹製のツールです。
- Dracut — an initramfs infrastructure and aims to have as little as possible hard-coded into the initramfs.
- Initramfs — is used to prepare Linux systems during boot before the init process starts.
- Initramfs (EFI stub kernel) - initramfs の設定。