幫 Chrome、Chromium、VS Code、Slack、GitHub Desktop 這類程式保管密碼與登入憑證。
實作 freedesktop 的 Secret Service 規格(org.freedesktop.secrets),所以用 libsecret 的程式不用改就能用;
取代 gnome-keyring,不需要任何 GNOME/GTK 元件。
安全設計
- 檔案
~/.local/share/pomelo/keyring/login.keyring,權限 0600。 - 金鑰:PBKDF2-HMAC-SHA256(30 萬次)從鑰匙圈密碼推導;內容用 AES-256-GCM 加密。
- 整個內容都加密,包括每個項目的標籤和屬性(例如網站網址、帳號)。gnome-keyring 只加密密碼本身, 標籤和屬性是明文,拿到檔案就看得出你有哪些網站的帳號。
- 密碼錯誤和檔案被竄改都會讓 GCM 驗證失敗,一律回報「密碼不正確」。
- 服務只聽本機 session bus,而且只接受同一個使用者的連線;金鑰與密碼放在不會被換到磁碟的記憶體(mlock), 用完就清掉;程式禁止 core dump。
- 客戶端要求加密傳輸時(libsecret 預設),用規格裡的 DH(RFC 2409 群組 2)+ AES-128-CBC, 對方的公鑰會檢查範圍。
登入自動解鎖
登入畫面 ─PAM─▶ pam_pomelo_keyring.so(auth:記下密碼;session:以使用者身分啟動 pomelo-keyring --stash)
│ 密碼暫存在記憶體,等最多 15 分鐘
pomelo-session ─▶ pomelo-keyring --daemon ◀───┘ 從暫存程式取回(只給同一個 uid),解鎖
- PAM 設定由
pam-auth-update加進 common-auth/common-session,LightDM、GDM、文字登入都適用。 - 用
startx直接進桌面(沒經過 PAM):第一次要用時會跳出解鎖視窗。 - 用
passwd改了登入密碼:下次登入自動解鎖會失敗,第一次要用時問一次舊密碼,解鎖後自動改用新的登入密碼加密。 - 鎖定時的行為:如果這次登入後解鎖過,鎖定後程式搜尋還是找得到項目(標籤與屬性留在記憶體), libsecret 會自己要求解鎖、跳出視窗;如果服務啟動後從來沒解鎖過,搜尋會先跳解鎖視窗,取消就回「沒有」。
檔案格式(版本 1)
| 位移 | 內容 |
|---|---|
| 0 | PMKR |
| 4 | 版本 1 + 3 位元組保留 |
| 8 | PBKDF2 次數(u32 小端) |
| 12 | 鹽 16 位元組 |
| 28 | GCM IV 12 位元組 |
| 40 | GCM 標籤 16 位元組 |
| 56 | 密文長度(u32 小端) |
| 60 | 密文:項目清單(id、時間、標籤、內容型別、屬性、密碼,皆為長度前綴) |
前 40 位元組是 GCM 的附加認證資料。
還沒做的
- 不提供 SSH agent(gnome-keyring 有);需要的話用 ssh-agent。
- 只有一個鑰匙圈「登入」;程式要求建立其他集合會回「不支援」。
- 沒有閒置自動鎖定;可以在設定裡手動「立即鎖定」。
測試過的
secret-tool(libsecret)與 python secretstorage(走 DH 加密連線):建立、讀、搜尋、改名、改屬性、改密碼、刪除。- 建立鑰匙圈視窗、鎖定時的解鎖視窗(含密碼錯誤重試、取消)、Chrome 式的明確解鎖。
- PAM:在容器裡用 PAM 走一次驗證+開啟工作階段,密碼有交到暫存程式,而且只有同一個使用者拿得到。
- 檔案格式:300 次隨機竄改/截斷全部被擋下;DH 的 0、1、超長公鑰被拒絕;記憶體錯誤偵測版本無錯誤。
- 還沒在真的 Chrome/VS Code 上測(這台主機不能開瀏覽器),請在實機上確認。