mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
7b9a973c9c
* fix: per-tier master-key retrievers for mixed-cipher profiles
73 lines
2.9 KiB
Go
73 lines
2.9 KiB
Go
package keyretriever
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// MasterKeys bundles the per-cipher-version Chromium master keys used to decrypt data from a
|
|
// single profile. decryptValue dispatches on the ciphertext's version prefix and picks the
|
|
// matching key; a missing (nil) key for a tier means "that cipher version cannot be decrypted",
|
|
// but the other tiers remain usable — a Chrome 127+ profile upgraded from pre-127 carries mixed
|
|
// v10+v20 ciphertexts, and Linux profiles may carry mixed v10+v11 for analogous reasons.
|
|
//
|
|
// - V10: Chrome 80+ key with "v10" cipher prefix.
|
|
// - Windows: os_crypt.encrypted_key decrypted by user-level DPAPI (AES-GCM ciphertexts).
|
|
// - macOS: derived from Keychain via PBKDF2(1003, SHA-1) (AES-CBC ciphertexts).
|
|
// - Linux: derived from "peanuts" hardcoded password (Chromium's kV10Key, AES-CBC).
|
|
// - V11: Chrome Linux key with "v11" cipher prefix, derived from D-Bus Secret Service
|
|
// (KWallet / GNOME Keyring) via PBKDF2. Nil on Windows and macOS (v11 prefix not used there).
|
|
// - V20: Chrome 127+ Windows key with "v20" cipher prefix, retrieved via reflective injection
|
|
// into the browser's elevation service. Nil on non-Windows platforms.
|
|
type MasterKeys struct {
|
|
V10 []byte
|
|
V11 []byte
|
|
V20 []byte
|
|
}
|
|
|
|
// Retrievers is the per-tier retriever configuration passed to NewMasterKeys. Each slot runs
|
|
// independently — failure or absence of one tier does not affect others. Platform injectors set
|
|
// only the slots that apply to their platform and leave the rest nil (e.g. Linux populates
|
|
// V10+V11, leaves V20 nil).
|
|
type Retrievers struct {
|
|
V10 KeyRetriever
|
|
V11 KeyRetriever
|
|
V20 KeyRetriever
|
|
}
|
|
|
|
// NewMasterKeys fetches every configured tier in r independently and returns the assembled
|
|
// MasterKeys together with any per-tier errors joined into one. Nil retrievers and retrievers
|
|
// returning (nil, nil) (the "not applicable" signal — e.g. ABERetriever on a non-ABE fork)
|
|
// contribute nil keys silently; only non-nil errors propagate.
|
|
//
|
|
// The returned error, when non-nil, is an errors.Join of per-tier failures formatted as
|
|
// "<tier>: <err>" (e.g. "v10: dpapi decrypt: ..."). Callers are expected to log it at whatever
|
|
// severity fits their context — this function itself never logs, leaving logging policy to its
|
|
// callers. Other pieces of the keyretriever package (e.g. ChainRetriever) may still log on their
|
|
// own failures; the "no-logging" guarantee is scoped to NewMasterKeys.
|
|
func NewMasterKeys(r Retrievers, storage, localStatePath string) (MasterKeys, error) {
|
|
var keys MasterKeys
|
|
var errs []error
|
|
|
|
for _, t := range []struct {
|
|
name string
|
|
r KeyRetriever
|
|
dst *[]byte
|
|
}{
|
|
{"v10", r.V10, &keys.V10},
|
|
{"v11", r.V11, &keys.V11},
|
|
{"v20", r.V20, &keys.V20},
|
|
} {
|
|
if t.r == nil {
|
|
continue
|
|
}
|
|
k, err := t.r.RetrieveKey(storage, localStatePath)
|
|
if err != nil {
|
|
errs = append(errs, fmt.Errorf("%s: %w", t.name, err))
|
|
continue
|
|
}
|
|
*t.dst = k
|
|
}
|
|
return keys, errors.Join(errs...)
|
|
}
|