From 1b7edcbe6cd6caf15f0377c66328850eaa508909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?= Date: Thu, 9 Jul 2020 19:34:26 +0800 Subject: [PATCH] feat: add firefox for windows decrypt Closes #11 --- core/common.go | 37 ++------------------- utils/utils.go | 16 +++++++++ utils/utils_darwin.go | 53 +++++++++++++++++++---------- utils/utils_windows.go | 75 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 53 deletions(-) diff --git a/core/common.go b/core/common.go index dc33409..a0cedca 100644 --- a/core/common.go +++ b/core/common.go @@ -2,8 +2,6 @@ package core import ( "bytes" - "crypto/hmac" - "crypto/sha1" "database/sql" "encoding/base64" "encoding/hex" @@ -445,7 +443,7 @@ func parseFirefoxKey4() { return } var masterPwd []byte - m, err := checkPassword(globalSalt, masterPwd, pbe) + m, err := utils.CheckPassword(globalSalt, masterPwd, pbe) if err != nil { log.Error("decrypt firefox failed", err) return @@ -460,7 +458,7 @@ func parseFirefoxKey4() { return } log.Debugf("decrypt asn1 pbe success") - finallyKey, err := checkPassword(globalSalt, masterPwd, pbe2) + finallyKey, err := utils.CheckPassword(globalSalt, masterPwd, pbe2) finallyKey = finallyKey[:24] if err != nil { log.Error(err) @@ -545,37 +543,6 @@ func parseFirefoxCookie() { } -func checkPassword(globalSalt, masterPwd []byte, pbe utils.MetaPBE) ([]byte, error) { - //byte[] GLMP; // GlobalSalt + MasterPassword - //byte[] HP; // SHA1(GLMP) - //byte[] HPES; // HP + EntrySalt - //byte[] CHP; // SHA1(HPES) - //byte[] PES; // EntrySalt completed to 20 bytes by zero - //byte[] PESES; // PES + EntrySalt - //byte[] k1; - //byte[] tk; - //byte[] k2; - //byte[] k; // final value conytaining key and iv - glmp := append(globalSalt, masterPwd...) - hp := sha1.Sum(glmp) - s := append(hp[:], pbe.EntrySalt...) - chp := sha1.Sum(s) - pes := utils.PaddingZero(pbe.EntrySalt, 20) - tk := hmac.New(sha1.New, chp[:]) - tk.Write(pes) - pes = append(pes, pbe.EntrySalt...) - k1 := hmac.New(sha1.New, chp[:]) - k1.Write(pes) - tkPlus := append(tk.Sum(nil), pbe.EntrySalt...) - k2 := hmac.New(sha1.New, chp[:]) - k2.Write(tkPlus) - k := append(k1.Sum(nil), k2.Sum(nil)...) - iv := k[len(k)-8:] - key := k[:24] - log.Warn("key=", hex.EncodeToString(key), "iv=", hex.EncodeToString(iv)) - return utils.Des3Decrypt(key, iv, pbe.Encrypted) -} - func GetLoginData() (l []loginData) { s, err := ioutil.ReadFile(utils.FirefoxLoginData) if err != nil { diff --git a/utils/utils.go b/utils/utils.go index 5b1be48..4cd524e 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,6 +1,7 @@ package utils import ( + "crypto/aes" "crypto/cipher" "crypto/des" "encoding/asn1" @@ -224,3 +225,18 @@ func DecodeLogin(decodeItem []byte) (pbe LoginPBE, err error) { } return pbe, nil } + +func aes128CBCDecrypt(key, iv, encryptPass []byte) ([]byte, error) { + if len(chromeKey) == 0 { + return []byte{}, nil + } + block, err := aes.NewCipher(key) + if err != nil { + return []byte{}, err + } + dst := make([]byte, len(encryptPass)) + mode := cipher.NewCBCDecrypter(block, iv) + mode.CryptBlocks(dst, encryptPass) + dst = PKCS5UnPadding(dst) + return dst, nil +} diff --git a/utils/utils_darwin.go b/utils/utils_darwin.go index 8dba0fc..45883f0 100644 --- a/utils/utils_darwin.go +++ b/utils/utils_darwin.go @@ -2,10 +2,10 @@ package utils import ( "bytes" - "crypto/aes" - "crypto/cipher" + "crypto/hmac" "crypto/sha1" "encoding/asn1" + "encoding/hex" "errors" "hack-browser-data/log" "os/exec" @@ -88,7 +88,8 @@ func decryptChromeKey(chromePass []byte) { func DecryptChromePass(encryptPass []byte) (string, error) { if len(encryptPass) > 3 { - return aes128CBCDecrypt(encryptPass[3:]) + m, err := aes128CBCDecrypt(chromeKey, iv, encryptPass[3:]) + return string(m), err } else { return "", &DecryptError{ err: passwordIsEmpty, @@ -96,21 +97,6 @@ func DecryptChromePass(encryptPass []byte) (string, error) { } } -func aes128CBCDecrypt(encryptPass []byte) (string, error) { - if len(chromeKey) == 0 { - return "", nil - } - block, err := aes.NewCipher(chromeKey) - if err != nil { - return "", err - } - dst := make([]byte, len(encryptPass)) - mode := cipher.NewCBCDecrypter(block, iv) - mode.CryptBlocks(dst, encryptPass) - dst = PKCS5UnPadding(dst) - return string(dst), nil -} - /* SEQUENCE (2 elem) SEQUENCE (2 elem) @@ -144,3 +130,34 @@ func DecodeMeta(decodeItem []byte) (pbe MetaPBE, err error) { } return } + +func CheckPassword(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) { + //byte[] GLMP; // GlobalSalt + MasterPassword + //byte[] HP; // SHA1(GLMP) + //byte[] HPES; // HP + EntrySalt + //byte[] CHP; // SHA1(HPES) + //byte[] PES; // EntrySalt completed to 20 bytes by zero + //byte[] PESES; // PES + EntrySalt + //byte[] k1; + //byte[] tk; + //byte[] k2; + //byte[] k; // final value conytaining key and iv + glmp := append(globalSalt, masterPwd...) + hp := sha1.Sum(glmp) + s := append(hp[:], pbe.EntrySalt...) + chp := sha1.Sum(s) + pes := PaddingZero(pbe.EntrySalt, 20) + tk := hmac.New(sha1.New, chp[:]) + tk.Write(pes) + pes = append(pes, pbe.EntrySalt...) + k1 := hmac.New(sha1.New, chp[:]) + k1.Write(pes) + tkPlus := append(tk.Sum(nil), pbe.EntrySalt...) + k2 := hmac.New(sha1.New, chp[:]) + k2.Write(tkPlus) + k := append(k1.Sum(nil), k2.Sum(nil)...) + iv := k[len(k)-8:] + key := k[:24] + log.Warn("key=", hex.EncodeToString(key), "iv=", hex.EncodeToString(iv)) + return Des3Decrypt(key, iv, pbe.Encrypted) +} diff --git a/utils/utils_windows.go b/utils/utils_windows.go index c0e14cb..55720c6 100644 --- a/utils/utils_windows.go +++ b/utils/utils_windows.go @@ -3,14 +3,20 @@ package utils import ( "crypto/aes" "crypto/cipher" + "crypto/sha1" + "crypto/sha256" + "encoding/asn1" "encoding/base64" + "encoding/hex" "errors" + "hack-browser-data/log" "os" "strings" "syscall" "unsafe" "github.com/tidwall/gjson" + "golang.org/x/crypto/pbkdf2" ) const ( @@ -22,6 +28,8 @@ const ( speed360KeyPath = "" qqBrowserProfilePath = "/AppData/Local/Tencent/QQBrowser/User Data/*/" qqBrowserKeyPath = "" + firefoxProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-release/" + firefoxKeyPath = "" ) var ( @@ -47,6 +55,10 @@ var ( qqBrowserProfilePath, qqBrowserKeyPath, }, + "firefox": { + firefoxProfilePath, + "", + }, } ) @@ -161,3 +173,66 @@ func DecryptStringWithDPAPI(data []byte) (string, error) { defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData))) return string(outBlob.ToByteArray()), nil } + +type MetaPBE struct { + SequenceA + CipherText []byte +} +type SequenceA struct { + PKCS5PBES2 asn1.ObjectIdentifier + SequenceB +} +type SequenceB struct { + SequenceC + SequenceD +} + +type SequenceC struct { + PKCS5PBKDF2 asn1.ObjectIdentifier + SequenceE +} + +type SequenceD struct { + AES256CBC asn1.ObjectIdentifier + IV []byte +} + +type SequenceE struct { + EntrySalt []byte + IterationCount int + KeySize int + SequenceF +} + +type SequenceF struct { + HMACWithSHA256 asn1.ObjectIdentifier +} + +func CheckPassword(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) { + sha1.New() + k := sha1.Sum(globalSalt) + + log.Println(hex.EncodeToString(k[:])) + key := pbkdf2.Key(k[:], pbe.EntrySalt, pbe.IterationCount, pbe.KeySize, sha256.New) + log.Println(hex.EncodeToString(key)) + i, err := hex.DecodeString("040e") + if err != nil { + log.Println(err) + } + // @https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49 + iv := append(i, pbe.IV...) + dst, err := aes128CBCDecrypt(key, iv, pbe.CipherText) + if err != nil { + log.Println(err) + } + return dst, err +} + +func DecodeMeta(decodeItem []byte) (pbe MetaPBE, err error) { + _, err = asn1.Unmarshal(decodeItem, &pbe) + if err != nil { + log.Error(err) + return + } + return +}