yzbtdiy

yzbtdiy

github
bilibili

KeePass kdbx4 檔案解密

KDBX 解密過程#

為了簡化解密步驟,解密過程沒有進行數據校驗

  1. 輸入密碼,對密碼進行 sha256 哈希計算得到密碼哈希值
  2. 密碼哈希值加上 key 文件內容再次進行 sha256 哈希計算,如果沒有 key 文件就密碼哈希值再次進行 sha256 哈希計算得到新的密碼哈希值,也就是 SHA256 (SHA256 (password) + keyfile)
  3. 從文件頭得到加密算法 KDF 相關參數,默認是 AES-KDF, 從 KDF parameters 中得到 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

十六進制詳細分析#

image-20240822113406561

1. header#

文件開頭 12 個字節分成三組,每組都是 UInt32 類型,占用四個字節,之後為多個 Fields

Fields 由 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 字節

Format version#

image-20240821190950704
image-20240821180207025

Format version 是文件格式版本,類型為 UInt32, 占用 4 字節,當前為類型為0x00040000, 當前版本為 4

Encryption algorithm#

image-20240821181812965
image-20240821180719734

0x02轉 Int32 為 2, id 為 2 對應 Encryption algorithm, 表示加密算法,類型為 UUID, 長度0x00000010轉 Int32 為 16, 表示長度為 16 個字節,UUID 為 16 進制字符串,值為31C1F2E6BF714350BE5805216AFC5AFF, 對應上圖中的 AES-256

Compression algorithm#

image-20240821185423228
image-20240821182532355

0x03轉 Int32 為 3, id 為 3 對應 Compression algorithm, 表示壓縮算法,類型為 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 parameters#

image-20240821194315863
image-20240821194224498

0x0B轉為 Int32 為 11, 對應 KDF parameters, 表示密鑰派生函數 (KDF) 的參數,長度0x0000005D轉 Int32 為 93, 表示值為之後 93 個字符,值類型為 Variant Dictionary, 翻譯為變體詞典,可以理解為特殊的對象結構,可以拆分為版本信息和多個詞典對象組成的數組,詞典對象由值類型,名稱長度,名稱,值長度,值組成

image-20240821194643768

可將 Variant Dictionary 進行如下拆分,最後一個字節0x00沒有實際用途

image-20240822091916730

KDF Format version#

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 加密用的鹽

Encryption IV/nonce#

image-20240822111052671
image-20240822110900590

0x07轉為 Int32 為 7, id 為 7 對應 Encryption IV/nonce, 表示加密算法的初始化向量或隨機數,長度0x00000010轉 Int32 為 16, 表示值為之後的 16 個字節組成的數組,初始化向量為字節數組[0x6C, 0x77, 0x12, 0xF7, 0xE2, 0xD0, 0x2E, 0xAE, 0x63, 0x9D, 0x53, 0x92, 0xD6, 0x03, 0xFD, 0x08]

End of header#

image-20240822112151756
image-20240822112040258

0x00轉 Int32 為 0, id 為 0 對應 End of header, 表示頭部結束,長度0x00000004轉 Int32 為 4, 值為之後的 4 個字節,是固定值[0x0D, 0x0A, 0x0D, 0x0A]

2. SHA-256 hash of the header#

image-20240822114126587

[0x0D, 0x0A, 0x0D, 0x0A]之後的 32 個字節為 header 的 SHA-256 哈希值,用來校驗頭部信息的完整性

3. HMAC-SHA-256 hash of the header#

image-20240822114637960

在 hash of the header 之後的 32 個字節為 header 的 HMAC-SHA-256 值,需要主密鑰才能完成校驗

4. In HMAC-protected block stream#

Unknown Data#

image-20240822130720931

未知部分,解密與校驗未使用這部分數據,文檔沒有相關說明,解密需要跳過這部分,否則會出錯

Encrypted Data#

之後到文件結尾為加密部分 (需要去掉最後四個字節0x00000000)
解密後得到 Gzip 壓縮的數據,Gzip 壓縮內容的頭部是0x1F8B

image-20240823160036633

Gzip Decompress#

進行 Gzip 解壓後得到 Inner Header 和 XML 內容

image-20240823162455324

Inner Header#

Inner encryption algorithm#

image-20240823162909414
image-20240823162938566

0x01轉 Int32 為 1, id 為 1 對應 Inner encryption algorithm, 表示內部加密算法,長度0x00000004轉 Int32 為 4, 表示值長度為 4 字節,值0x0000003轉 Int32 為 3, 表示使用 ChaCha20 加密

Inner encryption key#

image-20240823163118692
image-20240823163628791

0x02轉 Int32 為 2, id 為 2 對應 Inner encryption key, 表示內部加密密鑰,長度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 document#

image-20240823164722691

XML 文檔中密碼包含Protected="True"屬性,需要將該字符串先進行 Base64 解碼,然後進行 ChaCha20 解密,由於是流密碼,所以解密後面的密碼需要之前的密碼流

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。