wechatDataBackup/pkg/wechat/wechatDBDec.go
2024-08-26 22:56:29 +08:00

171 lines
3.5 KiB
Go

package wechat
import (
"bufio"
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/sha1"
"fmt"
"io"
"os"
)
const (
keySize = 32
defaultIter = 64000
defaultPageSize = 4096
)
func DecryptDataBase(path string, password []byte, expPath string) error {
sqliteFileHeader := []byte("SQLite format 3")
sqliteFileHeader = append(sqliteFileHeader, byte(0))
fp, err := os.Open(path)
if err != nil {
return err
}
defer fp.Close()
fpReader := bufio.NewReaderSize(fp, defaultPageSize*100)
// fpReader := bufio.NewReader(fp)
buffer := make([]byte, defaultPageSize)
n, err := fpReader.Read(buffer)
if err != nil && n != defaultPageSize {
return fmt.Errorf("read failed")
}
salt := buffer[:16]
key := pbkdf2HMAC(password, salt, defaultIter, keySize)
page1 := buffer[16:defaultPageSize]
macSalt := xorBytes(salt, 0x3a)
macKey := pbkdf2HMAC(key, macSalt, 2, keySize)
hashMac := hmac.New(sha1.New, macKey)
hashMac.Write(page1[:len(page1)-32])
hashMac.Write([]byte{1, 0, 0, 0})
if !hmac.Equal(hashMac.Sum(nil), page1[len(page1)-32:len(page1)-12]) {
return fmt.Errorf("incorrect password")
}
outFilePath := expPath
outFile, err := os.Create(outFilePath)
if err != nil {
return err
}
defer outFile.Close()
// Write SQLite file header
_, err = outFile.Write(sqliteFileHeader)
if err != nil {
return err
}
block, err := aes.NewCipher(key)
if err != nil {
return err
}
page1 = buffer[16:defaultPageSize]
iv := page1[len(page1)-48 : len(page1)-32]
stream := cipher.NewCBCDecrypter(block, iv)
decrypted := make([]byte, len(page1)-48)
stream.CryptBlocks(decrypted, page1[:len(page1)-48])
_, err = outFile.Write(decrypted)
if err != nil {
return err
}
_, err = outFile.Write(page1[len(page1)-48:])
if err != nil {
return err
}
for {
n, err = fpReader.Read(buffer)
if err != nil {
if err == io.EOF {
break
}
return err
} else if n < defaultPageSize {
return fmt.Errorf("read data to short %d", n)
}
iv := buffer[len(buffer)-48 : len(buffer)-32]
stream := cipher.NewCBCDecrypter(block, iv)
decrypted := make([]byte, len(buffer)-48)
stream.CryptBlocks(decrypted, buffer[:len(buffer)-48])
_, err = outFile.Write(decrypted)
if err != nil {
return err
}
_, err = outFile.Write(buffer[len(buffer)-48:])
if err != nil {
return err
}
}
return nil
}
func pbkdf2HMAC(password, salt []byte, iter, keyLen int) []byte {
dk := make([]byte, keyLen)
loop := (keyLen + sha1.Size - 1) / sha1.Size
key := make([]byte, 0, len(salt)+4)
u := make([]byte, sha1.Size)
for i := 1; i <= loop; i++ {
key = key[:0]
key = append(key, salt...)
key = append(key, byte(i>>24), byte(i>>16), byte(i>>8), byte(i))
hmac := hmac.New(sha1.New, password)
hmac.Write(key)
digest := hmac.Sum(nil)
copy(u, digest)
for j := 2; j <= iter; j++ {
hmac.Reset()
hmac.Write(digest)
digest = hmac.Sum(digest[:0])
for k, di := range digest {
u[k] ^= di
}
}
copy(dk[(i-1)*sha1.Size:], u)
}
return dk
}
func xorBytes(a []byte, b byte) []byte {
result := make([]byte, len(a))
for i := range a {
result[i] = a[i] ^ b
}
return result
}
/*
func main() {
str := "82b1a210335140a1bc8a57397391186494abe666595b4f408095538b5518f7d5"
// 将十六进制字符串解码为字节
password, err := hex.DecodeString(str)
if err != nil {
fmt.Println("解码出错:", err)
return
}
fmt.Println(hex.EncodeToString(password))
err = decryptMsg("Media.db", password)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Decryption successful!")
}
}
*/