Crypto API とストレージ暗号化

このページの目次

アンロックパスワードの変更では通常、ディスク全体を書き換える必要はありませんが、ボリュームキーの変更では再暗号化が必要になる場合があります。暗号プリミティブ、キー管理、および実際のデータパスは、階層的に理解する必要があります。

オフラインメディアの保護と、アンロック済みのシステム上で悪意のあるプロセスによるファイル読み取りの阻止は、異なる目標です。ストレージ暗号化は、アクセス制御と併用する必要があります。

参照目標読書位置
アルゴリズムのインスタンスと非同期リクエスト第 1 節
ブロック暗号、keyslot、ディレクトリポリシー第 2~3 節
ネットワーク暗号化、TPM、ダイジェスト実験第 4~6 節

1. Crypto API:アルゴリズムのインスタンスと単一リクエスト

インターフェースカテゴリタスク例
skcipher対称暗号化・復号化XTS、CBC などのモード
AEADデータと付加データの暗号化と認証GCM、ChaCha20-Poly1305
shash / ahash同期/非同期ダイジェストまたは関連する keyed hashSHA-256、HMAC
akcipher非対称暗号化などのインターフェースRSA 系操作
kppキー合意DH、ECDH
rng特定の乱数生成器インターフェース登録済みの RNG 実装

ECDH はキー合意に分類されるべきであり、RSA 形式の暗号化インターフェースの例として使用すべきではありません。通常のカーネルのランダムバイトの需要には、get_random_bytes() などの乱数サブシステムインターフェースが使用され、すべての呼び出し元が独自に crypto_rng を割り当てるわけではありません。

tfm は、アルゴリズムやキーなどの情報を設定する変換オブジェクトです。1回の操作には通常、リクエスト、ソース/ターゲットの scatterlist、長さ、および IV が必要です。正しい skcipher 暗号化のエントリポイントは skcipher_request * を受け取ります。偽造された crypto_skcipher_encrypt(tfm, src, dst, len) ではありません。

  1. tfm を割り当て、エラーをチェックし、キーを設定する。
  2. リクエスト、コールバック、ソース/ターゲットの範囲、および IV を構築する。
  3. 送信後、戻り値のステータスに応じて同期完了または非同期処理を区別する。
  4. 完了契約を満たした後、初めてリクエスト、データ、およびコンテキストを解放する。

スリープ可能なコンテキストでは、公式の例に従って crypto_wait_req() を使用して待機できます。これをアトミックコンテキストに持ち込むことはできません。skcipher API および完全な例 を参照してください。

アルゴリズム名は具体的な実行ユニットではない

xts(aes) などの名前は、テンプレートと基盤となるアルゴリズムを組み合わせたものです。複数の実装が同じ一般的なアルゴリズム名を提供でき、Crypto API は一致条件や実装の優先度などに基づいて選択します。ドライバー名を指定すると、選択範囲が狭まります。/proc/crypto で現在登録されている実装を観察できますが、これはシステムでロード可能なすべてのアルゴリズム組み合わせの完全なリストではありません。

AES-NI、ARM 暗号化拡張機能、および独立したアクセラレータは、異なる呼び出しコストを持ちます。小さなデータブロック、キューの遅延、DMA、およびコピーコストが結果に影響を与える可能性があり、「ハードウェア実装が存在すれば常に10倍速い」とは限りません。カーネルにはダイレクトな暗号化ライブラリインターフェースもあり、すべての暗号操作が動的な tfm 割り当てを経る必要はありません。Crypto API アーキテクチャ を参照してください。

2. dm-crypt と LUKS はそれぞれどのレイヤーにあるか

アンロックキーと読み書きデータのパスは異なる パスワード / TPM などのアンロック材料 ユーザー空間でのアンロックポリシー処理 LUKS keyslot ボリュームキーを保護 ボリュームキー 実行中の暗号化マッピングに渡す ファイルシステムブロック I/O アンロック済みの場合は平文にアクセス可能 dm-crypt セクタ単位で暗号化・復号化 下層ストレージ 暗号化データを保存 パスワードの変更は通常 keyslot を変更し、ボリュームキーの変更のみがデータの再暗号化に関与します。

dm-crypt は device-mapper のブロック暗号化ターゲットであり、マッピングデバイスへのデータ読み書きを処理します。上位のファイルシステムは通常、復号化されたブロックを見ます。LUKS はディスクフォーマットとキー管理の規約であり、cryptsetup などのユーザー空間ツールがヘッダーを読み取り、アンロックを完了してからカーネルマッピングを設定します。カーネルの dm-crypt は、各 LUKS JSON keyslot を解析する責任を負いません。

変更通常関与するレイヤー
パスワードの追加または変更PBKDF によるアンロック材料の派生、keyslot の処理
ボリュームキーの復元とマッピングのオープンkeyslot 内の保護されたキー材料の使用
ボリュームキーの真の変更データの再暗号化プロセスに関与

したがって、パスワードの変更は通常、ファイルシステム全体の再暗号化を意味しません。2つの操作のコストと復旧の要件は異なります。

LUKS1 の keyslot の上限は 8 です。LUKS2 は最大 32 個のスロットをサポートしますが、実際に使用可能な数は keyslot リージョンのサイズなどの条件によって制限されます。LUKS2 には冗長なメタデータと JSON 記述があり、ヘッダー、keyslot リージョン、およびデータオフセットには明確なレイアウトと構成可能なパラメータがあります。これらを単に「固定された先頭 16 MB のヘッダー」と呼ぶことはできません。LUKS2 フォーマット仕様 および cryptsetup パラメータ を参照してください。

PBKDF2、Argon2i、Argon2id の利用可能性とパラメータは、フォーマットとツールの設定によって異なります。メモリコストはオフラインパスワード推測のコストを増加させることができますが、弱いパスワードを解読不可能なキーに変えるわけではありません。アンロック段階での PBKDF オーバーヘッドを、毎回のセクタ読み書きの暗号化オーバーヘッドと混同しないでください。

機密性は完全性とは異なる

一般的な XTS モードはセクタデータの機密性を提供しますが、一般的な改ざん認証やロールバック防止の保証は提供しません。認証暗号化または完全性保護が必要な場合は、適切なモード、メタデータストレージ、および dm-integrity などの併用メカニズムを選択し、その境界を理解する必要があります。

discard を許可すると、使用済みのスペースなどのパターン情報が漏洩する可能性があります。アンロック済みの場合、読み取り権限を持つプロセスは依然として平文を取得できます。ボリュームキーとキャッシュされた平文は、実行中のシステムのメモリ脅威モデルにも関与します。dm-crypt ドキュメント を参照してください。

以下では、ブラウザで公開されたサンプルコンテンツを実際に暗号化し、暗号文中の1ビットを反転させます。認証なしの CTR と認証付きの GCM を比較します。いくつかのバイトを復号できることと、それらのバイトが検証を通過することは、異なる結果です。

図を準備しています
暗号文の1ビットを変更した場合、復号成功は内容の信頼性を示すか?

認証なしの CTR は、暗号文のビット反転後に修正された平文を復号できる。GCM は認証タグを検証し、ここでの変更を拒否する。機密性、完全性、およびロールバック防止は、それぞれ別々に説明する必要がある。

3. fscrypt:ファイルシステム内で保護範囲を選択する

fscrypt は、対応するファイルシステムに対してファイルコンテンツとファイル名の暗号化を提供します。ディレクトリポリシーにより、異なるディレクトリツリーで異なるマスターキーを使用でき、1つのファイルシステム内で複数のアンロックドメインを管理しやすくなります。

通常、fscrypt はファイルサイズ、権限、タイムスタンプ、およびディレクトリ構造などのファイル名以外のメタデータを隠蔽しません。また、オフラインの観察者がファイルを関連付けることを保証するものではありません。デフォルトのファイルごとの派生および nonce メカニズムには、DIRECT_KEY、IV_INO_LBLK などのポリシーの違いがあり、「あらゆる設定で各ファイルに独立したデータキーがある」と一般化することはできません。

通常の fscrypt の設計は、主に静止データの機密性を保護するためのものであり、能動的な改ざんやロールバックに対する完全なファイルシステム認証を自動的に提供するものではありません。マスターキーの削除時には、開いているファイルやキャッシュ内で依然として使用されている派生キーも考慮する必要があります。ioctl の戻り値を、すべての平文が瞬時に消失することを意味するものとして解釈してはいけません。

新しいディレクトリポリシーは、通常、空のディレクトリなどの条件を満たした後に設定され、その後作成されるファイルは対応するポリシーを継承します。既存の平文ディレクトリツリーを突然変異することはありません。FS_IOC_GET_ENCRYPTION_PWSALT は歴史的なパスワード派生の補助インターフェースであり、任意のディレクトリの固有のソルト値を読み取るための汎用インターフェースではありません。ポリシーと制限については fscrypt ドキュメント を参照してください。

比較点dm-cryptfscrypt
管理境界ブロックマッピングファイルシステム内のポリシーおよびキードメイン
ファイルシステムメタデータ暗号化マッピング内部では暗号化ブロックの一部となるファイル名以外の多くのメタデータが依然として可視
アンロック粒度通常はマッピング全体異なるディレクトリツリーのキーを管理可能
アンロック後のアクセス制御依然として権限/LSM などに依存同様に権限/LSM などに依存

これらを重ねて使用することもできます。これらは排他的な製品の代替関係ではありません。

4. WireGuard と kTLS:異なるネットワークレイヤーの暗号化

WireGuard はレイヤー3の暗号化トンネルを提供し、Noise ハンドシェイク、Curve25519、ChaCha20-Poly1305 などの固定プロトコルコンポーネントを使用します。静的公開キーはピアを識別し、ハンドシェイクでセッションキーを生成します。パケットのカウンター、認証、およびリプレイ処理が保護に参加します。キー更新は、時間、メッセージ数、セッション状態などの条件に基づいてトリガーされ、厳密に2分ごとに無条件で実行されるタイマーアクションではありません。

Curve25519 は後量子アルゴリズムではありません。WireGuard は、追加の保護として事前共有対称キーを混在させることができますが、これは「後量子問題は重要ではない」または「システム全体がすべての後量子セキュリティ属性を獲得した」と一般化できるものではありません。設定インターフェースは主に generic netlink を使用し、ネットワークデバイスの作成などは通常のネットワークインターフェース管理にも関与します。WireGuard プロトコル を参照してください。

kTLS は、サポートされている TLS レコード層の送信/受信処理をカーネルまたはハードウェアに委ねます。ハンドシェイク、証明書検証、およびプロトコル状態の管理は、主にユーザー空間の TLS ライブラリによって担当されます。接続のネゴシエーション後、TCP の TLS ULP を設定し、TX/RX に必要な暗号状態を個別に設定する必要があります。setsockopt を1回コピーするだけで、完全な TLS クライアントになるわけではありません。

sendfile などのパスはユーザー空間のコピーを削減できますが、ソフトウェア暗号化、NIC オフロード、ゼロコピー送信は異なる機能であり、利用可否はカーネル、プロトコル、アルゴリズム、およびドライバーのサポートによって異なります。kTLS ドキュメント を参照してください。

5. TPM:ポリシーに基づいて秘密を使用し、ポリシー自体も管理する

TPM はキーオブジェクトを保護し、PCR などの条件に基づいてアンロックまたは使用を制約できます。典型的な LUKS 統合では、アンロック材料を生成し、それを TPM オブジェクト/ポリシーおよび LUKS トークンに関連付けます。これは、ディスク全体の暗号化キーを TPM 内に永久に保持し、毎回のセクタ暗号化に使用することを意味するものではありません。

PCR は、イベント測定の累積結果であり、TPM が「このカーネルは必ずしも良性である」と理解しているわけではありません。どの PCR を選択するか、測定チェーンが信頼できるかどうか、誰が認可ポリシーに署名するかが、アンロックの制約を決定します。合法アップグレードを許可するには、ポリシーの更新、署名付き PCR ポリシー、または回復クレデンシャルなどの設計が必要です。

起動認可、測定、およびシールはそれぞれ何を証明するか

Secure Boot はブートコードの認可関係を検証し、measured boot は測定を記録し、TPM sealing はポリシーに基づいて秘密の使用を制限します。これらは連携できますが、互いに代替することはできません。正常なアンロック後のランタイムの脆弱性も、PCR バインディングによって自動的に阻止されるわけではありません。実装については systemd-cryptenroll のソースコードとドキュメント を参照してください。

6. AF_ALG を使用してダイジェストリクエストを観察する

以下では、Linux AF_ALG を介してカーネルの SHA-256 を呼び出し、公開文字列に対して既知の結果検証を行います。キーの読み取りやストレージの変更は行いません。Python/Linux で AF_ALG がサポートされており、カーネルで対応するアルゴリズムユーザーインターフェースが有効になっている必要があります。これはカーネルインターフェースを示すものであり、一般的なアプリケーションが独自の暗号化ライブラリを置き換えるべきであることを意味するものではありません。

import socket

expected = 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'
with socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0) as alg:
    alg.bind(('hash', 'sha256'))
    op, _ = alg.accept()
    with op:
        sent = op.send(b'abc')
        if sent != 3:
            raise RuntimeError('unexpected short input')
        digest = op.recv(32)
assert len(digest) == 32 and digest.hex() == expected
print(digest.hex())

この環境で AF_ALG が有効になっていない場合、ソケットの作成は EAFNOSUPPORT を返します。これはインターフェースの機能が利用できないことを示しており、これに基づいて SHA-256 アルゴリズム自体に誤りがあるとは判断できません。

ソケットの作成が EAFNOSUPPORT を返す場合、まず CONFIG_CRYPTO_USER_API_HASH などのサポートを確認してください。これにより SHA-256 アルゴリズムの実装が誤っていると判断してはいけません。

ダイジェストの一致は、この呼び出しパスが予期された結果を得たことを証明しますが、全体の暗号化ストレージ構成、キー管理、またはハードウェアオフロードが正しく設定されていることを証明するものではありません。AF_ALG のインターフェース制限とサポート状況についてはカーネルユーザー空間暗号化インターフェース を参照してください。