pcgamedb/utils/privatebin.go

128 lines
3.0 KiB
Go

package utils
import (
"bytes"
"compress/flate"
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"io"
"strings"
"github.com/btcsuite/btcutil/base58"
"golang.org/x/crypto/pbkdf2"
)
type PrivateBinData struct {
Ct string `json:"ct"`
Adata []interface{} `json:"adata"`
}
func padStart(s string, minLength int, padRune rune) string {
currentLength := len(s)
if currentLength >= minLength {
return s
}
padding := strings.Repeat(string(padRune), minLength-currentLength)
return padding + s
}
func DecryptPrivateBin(URL string, password string) (string, error) {
if !strings.Contains(URL, "#") {
return "", errors.New("missing Decrypt Key")
}
key := strings.Split(URL, "#")[1]
resp, err := Request().SetHeader("Accept", "application/json, text/javascript, */*; q=0.01").Get(URL)
if err != nil {
return "", err
}
data := PrivateBinData{}
err = json.Unmarshal(resp.Body(), &data)
if err != nil {
return "", err
}
type pasteJson struct {
Paste string `json:"paste"`
}
ret, err := decryptPrivateBin(key, data.Adata, data.Ct, password)
if err != nil {
return "", err
}
var j pasteJson
err = json.Unmarshal([]byte(ret), &j)
if err != nil {
return "", err
}
return j.Paste, nil
}
func decryptPrivateBin(key string, data []interface{}, cipherMessage, password string) (string, error) {
decodedKey := base58.Decode(key)
key = padStart(string(decodedKey), 32, '\x00')
additionalData, err := json.Marshal(data)
if err != nil {
return "", err
}
spec := data[0].([]interface{})
iterations := int(spec[2].(float64))
iv, err := base64.StdEncoding.DecodeString(spec[0].(string))
if err != nil {
return "", err
}
salt, err := base64.StdEncoding.DecodeString(spec[1].(string))
if err != nil {
return "", err
}
cipherMessageBytes, err := base64.StdEncoding.DecodeString(cipherMessage)
if err != nil {
return "", err
}
keyArray := []byte(key)
if password != "" {
if spec[7].(string) == "rawdeflate" {
hash := sha256.New()
hash.Write([]byte(password))
password = hex.EncodeToString(hash.Sum(nil))
}
passwordArray := []byte(password)
keyArray = append(keyArray, passwordArray...)
}
aesKeyLength := int(spec[3].(float64)) / 8
deriveKey := pbkdf2.Key(keyArray, salt, iterations, aesKeyLength, sha256.New)
block, err := aes.NewCipher(deriveKey)
if err != nil {
return "", err
}
aesGCM, err := cipher.NewGCMWithNonceSize(block, len(iv))
if err != nil {
return "", err
}
plaintext, err := aesGCM.Open(nil, iv, cipherMessageBytes, additionalData)
if err != nil {
return "", err
}
if len(spec) >= 8 && spec[7].(string) == "zlib" {
data, err := decompress(plaintext)
if err != nil {
return "", err
}
plaintext = data
}
return string(plaintext), err
}
func decompress(data []byte) ([]byte, error) {
r := flate.NewReader(bytes.NewReader(data))
defer r.Close()
decompressed, err := io.ReadAll(r)
if err != nil {
return nil, err
}
return decompressed, nil
}