171 lines
3.5 KiB
Go
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!")
|
|
}
|
|
}
|
|
*/
|