yzbtdiy

yzbtdiy

github
bilibili

KeePass kdbx4 ファイルの復号化

KDBX 解密プロセス#

データ検証を行わずに、解読手順を簡素化するために、解読プロセスを行います。

  1. パスワードを入力し、パスワードの sha256 ハッシュ計算を行い、パスワードハッシュ値を取得します。
  2. パスワードハッシュ値に key ファイルの内容を加え、再度 sha256 ハッシュ計算を行います。key ファイルがない場合は、パスワードハッシュ値を再度 sha256 ハッシュ計算して新しいパスワードハッシュ値を取得します。つまり、SHA256 (SHA256 (password) + keyfile) です。
  3. ファイルヘッダーから暗号化アルゴリズム KDF に関連するパラメータを取得します。デフォルトは AES-KDF で、KDF パラメータから KDF の Salt/seed と Rounds を取得します。
  4. 二次 sha256 パスワードから得られたハッシュ値と KDF の Salt/seed および Rounds を使用して AES-KDF 計算を行い、変換されたキーを取得します。
  5. ファイルヘッダーから Master salt/seed と変換されたキーを再度 sha256 計算し、最終的な解読キーを取得します。
  6. ファイルヘッダーから Encryption IV/nonce を取得し、解読キーを加えて暗号化データを AES 解読します。
  7. 解読後のデータを Gzip 解凍し、Inner Header と XML 内容を取得します。XML 内のパスワードはデフォルトで ChaCha20 で暗号化されています。
  8. Inner Header から Inner encryption key を取得し、sha512 でハッシュ計算を行います。ハッシュ文字列のインデックス 0 から 31 バイトが ChaCha20 の key、32 から 43 が ChaCha20 暗号化の nonce です。
  9. ChaCha20 の key と nonce を使用して暗号化された文字列を解読し、平文のパスワードを取得します。ストリーム暗号であるため、暗号化された文字列の順序に従って順次解読する必要があります。

kdbx ファイルの作成#

KeePass クライアントを使用して kdbx ファイルを作成し、すべてデフォルトのパラメータを使用します。Hex エディタで kdbx ファイルを開き、KeePass 文書KDBX File Format Specification - KeePassに従ってファイルヘッダーを以下の図のように分割します。

image-20240822172200397

16 進数の詳細分析#

image-20240822113406561

1. ヘッダー#

ファイルの最初の 12 バイトは 3 つのグループに分けられ、各グループは UInt32 型で 4 バイトを占め、その後に複数のフィールドがあります。

フィールドは id、値の長さ、値から構成され、id は 1 バイト、値の長さは Int32 型で 4 バイトを占め、値の長さに基づいて対応するバイトデータを値として取得します。

詳細なファイル形式の説明はKDBX File Format Specification - KeePassを参照してください。

kdbx ファイルはリトルエンディアンバイトオーダーを使用し、数値型は右から左に読み取る必要があります。

Signature1#

image-20240821190624226
image-20240821174503304

Signature1 は固定値0x9AA2D903で、型は UInt32、4 バイトを占めます。

Signature2#

image-20240821190749110
image-20240821180053815

Signature2 は固定値0xB54BFB67で、型は UInt32、4 バイトを占めます。

フォーマットバージョン#

image-20240821190950704
image-20240821180207025

フォーマットバージョンはファイルフォーマットのバージョンで、型は UInt32、4 バイトを占め、現在のタイプは0x00040000、現在のバージョンは 4 です。

暗号化アルゴリズム#

image-20240821181812965
image-20240821180719734

0x02を Int32 に変換すると 2 になり、id は 2 で暗号化アルゴリズムを示し、型は UUID、長さ0x00000010を Int32 に変換すると 16 になり、16 バイトの長さを示します。UUID は 16 進数の文字列で、値は31C1F2E6BF714350BE5805216AFC5AFF、上の図の AES-256 に対応します。

圧縮アルゴリズム#

image-20240821185423228
image-20240821182532355

0x03を Int32 に変換すると 3 になり、id は 3 で圧縮アルゴリズムを示し、型は UInt32、長さ0x00000004を Int32 に変換すると 4 になり、値の長さはその後の 4 バイトです。16 進数0x00000001を UInt32 に変換すると1になり、GZip 圧縮を使用することを示します。

Master salt/seed#

image-20240821190432826
image-20240821190323382

0x04を Int32 に変換すると 4 になり、id は 4 で Master salt/seed を示し、暗号化の塩 / 種子を示します。型は 32 バイトの配列で、長さ0x00000020を Int32 に変換すると 32 になり、値の長さはその後の 32 バイトです。対応するバイト配列は[0xFA, 0xC9, 0x50, 0x39, 0x79, 0x5F, 0x19, 0x83, 0x21, 0x22, 0x8F, 0x24, 0x8F, 0x59, 0x63, 0xD5, 0x30, 0x38, 0x7A, 0x55, 0xD8, 0x08, 0xD5, 0x19, 0xC4, 0xD6, 0xEC, 0xEC, 0xEE, 0xDF, 0xA8, 0x24]で、これは AES 暗号用の塩です。

KDF パラメータ#

image-20240821194315863
image-20240821194224498

0x0Bを Int32 に変換すると 11 になり、KDF パラメータに対応し、キー導出関数 (KDF) のパラメータを示します。長さ0x0000005Dを Int32 に変換すると 93 になり、値はその後の 93 文字です。値の型は Variant Dictionary で、変体辞書として理解できます。特別なオブジェクト構造であり、バージョン情報と複数の辞書オブジェクトからなる配列に分割できます。辞書オブジェクトは値の型、名前の長さ、名前、値の長さ、値から構成されます。

image-20240821194643768

Variant Dictionary は以下のように分割できます。最後のバイト0x00は実際には用途がありません。

image-20240822091916730

KDF フォーマットバージョン#

image-20240822092645747

最初は UInt16 型のバージョン情報で、値は0x0100、2 バイトを占めます。

KDF UUID#

image-20240822094338216
image-20240822093441124

0x42は [] byte 型を示し、0x000005を Int32 に変換すると 5 になり、名前の長さは 5 バイトです。0x2455554944は ASCII 文字列$UUIDに対応し、その後0x00000010を Int32 に変換すると 16 になり、UUID の長さは 16 文字です。対応する 16 進数の文字列はC9D9F39A628A4460BF740D08C18A4FEAで、デフォルトで AES-KDF を使用します。

KDF Rounds#

image-20240822100518464
image-20240822100401677

0x05は UInt64 型を示し、0x000001を Int32 に変換すると 1 になり、名前の長さは 1 バイトです。0x52は ASCII 文字Rに対応し、値の長さ0x000008を Int32 に変換すると 8 になり、Rounds の値はその後の 8 バイトです。0x00000000000927C0を UInt64 に変換すると 600000 になり、反復回数は 600000 です。

KDF Salt/seed#

image-20240822102413474
image-20240822102318666

0x42は [] byte 型を示し、0x000001を Int32 に変換すると 1 になり、名前の長さは 1 バイトです。0x53は ASCII 文字列Sに対応し、その後0x00000020を Int32 に変換すると 32 になり、Salt/Seed の長さは 32 文字です。対応するバイト配列は[0x0C, 0x34, 0x88, 0x19, 0x8E, 0x90, 0xA3, 0x65, 0x40, 0xB4, 0x1C, 0x4E, 0xCC, 0x85, 0x5D, 0x11, 0xC3, 0x0A, 0x20, 0xD6, 0xF4, 0xAA, 0x20, 0xE4, 0xEC, 0xF3, 0xCF, 0xF3, 0xD9, 0x81, 0xC5, 0xED]で、これも KDF 暗号用の塩です。

暗号化 IV/nonce#

image-20240822111052671
image-20240822110900590

0x07を Int32 に変換すると 7 になり、id は 7 で暗号化 IV/nonce を示し、暗号化アルゴリズムの初期化ベクトルまたはランダム数を示します。長さ0x00000010を Int32 に変換すると 16 になり、値はその後の 16 バイトからなる配列です。初期化ベクトルはバイト配列[0x6C, 0x77, 0x12, 0xF7, 0xE2, 0xD0, 0x2E, 0xAE, 0x63, 0x9D, 0x53, 0x92, 0xD6, 0x03, 0xFD, 0x08]です。

ヘッダーの終わり#

image-20240822112151756
image-20240822112040258

0x00を Int32 に変換すると 0 になり、id は 0 でヘッダーの終わりを示し、長さ0x00000004を Int32 に変換すると 4 になり、値はその後の 4 バイトで、固定値[0x0D, 0x0A, 0x0D, 0x0A]です。

2. ヘッダーの SHA-256 ハッシュ#

image-20240822114126587

[0x0D, 0x0A, 0x0D, 0x0A]の後の 32 バイトはヘッダーの SHA-256 ハッシュ値で、ヘッダー情報の完全性を検証するために使用されます。

3. ヘッダーの HMAC-SHA-256 ハッシュ#

image-20240822114637960

ヘッダーのハッシュの後の 32 バイトはヘッダーの HMAC-SHA-256 値で、検証を完了するには主キーが必要です。

4. HMAC 保護されたブロックストリーム内#

不明なデータ#

image-20240822130720931

不明な部分で、解読と検証にはこの部分のデータは使用されず、文書には関連する説明がありません。解読するにはこの部分をスキップする必要があります。そうしないとエラーが発生します。

暗号化データ#

その後、ファイルの末尾までが暗号化部分(最後の 4 バイト0x00000000を削除する必要があります)。
解読後、Gzip 圧縮データが得られ、Gzip 圧縮内容のヘッダーは0x1F8Bです。

image-20240823160036633

Gzip 解凍#

Gzip 解凍を行い、Inner Header と XML 内容を取得します。

image-20240823162455324

Inner Header#

内部暗号化アルゴリズム#

image-20240823162909414
image-20240823162938566

0x01を Int32 に変換すると 1 になり、id は 1 で内部暗号化アルゴリズムを示し、長さ0x00000004を Int32 に変換すると 4 になり、値の長さは 4 バイトです。値0x0000003を Int32 に変換すると 3 になり、ChaCha20 暗号化を使用することを示します。

内部暗号化キー#

image-20240823163118692
image-20240823163628791

0x02を Int32 に変換すると 2 になり、id は 2 で内部暗号化キーを示します。長さ0x00000040は 64 バイトの配列の長さを示し、つまり[0x68, 0x34, 0xD6, 0x1D, 0xFA, 0x98, 0x64, 0xB1, 0x8A, 0x51, 0x05, 0xAB, 0x26, 0x10, 0x35, 0xC8, 0xB0, 0x22, 0xF5, 0x14, 0x91, 0x0F, 0x47, 0x8C, 0x3D, 0xE7, 0x63, 0x86, 0x9C, 0x87, 0xC1, 0x26, 0xC6, 0xB7, 0xDE, 0x59, 0x77, 0x3B, 0xC6, 0x13, 0xF7, 0x17, 0x6C, 0x05, 0x7E, 0x1C, 0xF3, 0xDC, 0x78, 0x25, 0x64, 0xCA, 0x44, 0x7E, 0xFD, 0xB4, 0x6F, 0xEB, 0x4D, 0xDC, 0xD5, 0x91, 0x7B, 0x5C]です。

ここでの値は sha512 ハッシュ計算を行う必要があり、ハッシュ値配列のインデックス 0 から 31 は key、32 から 43 は nonce です。

image-20240823164208028

XML 文書#

image-20240823164722691

XML 文書内のパスワードにはProtected="True"属性が含まれており、この文字列を最初に Base64 デコードし、その後 ChaCha20 で解読する必要があります。ストリーム暗号であるため、解読後のパスワードは前のパスワードストリームが必要です。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。