我寫了個 PowerShell 小工具,用 ConvertTo-SecureString/ConvertFrom-SecureString 加密保存資料,背後是靠 Windows DPAPI (Data Protection API) 運作,一套 Windows 內建,與使用者帳號與所在主機整合的加解密機制,不用設密碼或金鑰就能無腦加解密。

接到報案,小工具噴出沒看過的「機碼用在特定狀態時無效」錯誤,用中文訊息爬文找到的資料不多,大多是程式安裝過程出錯的案例,由錯誤碼 0x8009000B 查到其原文是 Key not valid for use in specified state.,改用英文訊息爬文,鎖定與錯誤 RSA 加解密有關,而中文錯誤訊息中的「機碼」應是 Key (加密金鑰) 的錯誤翻譯。

詢問報案人,原來是最近換新電腦,忘了手冊有提醒加密資料只限原機原帳號使用,從舊電腦複製加密檔到新機器上執行,造成以上錯誤,而我被訊息錯翻的「機碼」一詞迷惑,沒能馬上意會到問題。

DPAPI 堪稱 Windows 內建的無腦加解密機制,使用者不用想密碼,Windows 自己有一套安全可靠的簡單方法實現該使用者在這台機器加密的資料,只有該使用者在這台機器上可以解密。加密機制會認帳號及機器,加密資料交給其他使用者或移到其他機器也會失效。(註:但也可設定認機器不限使用者)

DPAPI 的背後原理是靠主金鑰(Master Key)加解密,Windows 有自己的系統主金鑰(System Master Key),每個使用者也有專屬的使用者主金鑰(User Master Key),使用者主金鑰是用使用者的 Windows 密碼加密保存,因此,必須知道知道密碼才能取出金鑰,因此即便系統管理者強行拿走檔案也解不開。每次變更密碼時,需用原密碼解密使用者主金鑰,再用新密碼加密,因此管理者在不知原密碼的狀況重設密碼,雖然能登入主機仍無法解密,連管理者都能防,有相當的安全性。這意味著 1) 系統管理者無法透過重設密碼手段偷取使用者的加密資料 2) 使用者若自己忘了密碼,連管理者也無法幫忙解開。

參考:古老微軟文件

The DPAPI is invoked by the Winlogon component during password change operations in an Active Directory domain:

  • DPAPI receives notification from Winlogon during a password change operation.
  • DPAPI decrypts all master keys that were encrypted with the user's old passwords.
  • DPAPI re-encrypts all master keys with the user's new password.

A password reset is more complex than a password change. Because the administrator is not logged on as the user and does not have access to the user's old password, that old password cannot be used to decrypt the old master key and re-encrypt it with the new password.

最後,我做了小實驗觀察修改密碼時 Windows 重新加密主金鑰的行為。DPAPI 用起來很無腦但官方技術文件很少,理由是正常人不需要知道這麼多,會想摸透通常是想幹壞事的人,因此要靠破解相關文件解惑。個人的主金鑰存放在 C:\Users\<user>\AppData\Roaming\Microsoft\Protect\<SID> 目錄下,存在以 GUID 為名的檔案,是加密過的主金鑰。我用 PowerShell 指令改密碼,每改一次多一個新檔,查了文件發現 Windows 會保存舊金鑰,有個 Preferred 檔指向最新一支。而每次改密碼,所有檔案都會被覆寫更新寫入時間,推測就是重新用使用者密碼加密的行為。有興趣的話可以找到工具剖析檔案內容甚至破解金鑰,但我志不在此,就此打住。

【延伸閱讀】


Comments

Be the first to post a comment

Post a comment