363 lines
8.0 KiB
Go
363 lines
8.0 KiB
Go
package core
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/hmac"
|
|
"crypto/md5"
|
|
"crypto/sha1"
|
|
"crypto/sha256"
|
|
"crypto/sha512"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"hash"
|
|
|
|
"github.com/dop251/goja"
|
|
)
|
|
|
|
func toBytes(v interface{}) []byte {
|
|
switch v := v.(type) {
|
|
case []byte:
|
|
return v
|
|
case string:
|
|
return []byte(v)
|
|
case *Buffer:
|
|
return v.value
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func toString(v interface{}) string {
|
|
switch v := v.(type) {
|
|
case []byte:
|
|
return string(v)
|
|
case string:
|
|
return v
|
|
case *Buffer:
|
|
return string(v.value)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
type Crypto struct {
|
|
vm *goja.Runtime
|
|
}
|
|
|
|
type Hmac struct {
|
|
// decode bool
|
|
vm *goja.Runtime
|
|
Algorithm string
|
|
middle interface{}
|
|
}
|
|
|
|
func (h *Hmac) Digest(EF string) interface{} {
|
|
var result interface{}
|
|
var SF = ""
|
|
switch h.Algorithm {
|
|
case "md5", "sha1", "sha256", "sha512":
|
|
result = h.middle.(hash.Hash).Sum(nil)
|
|
case "aes-256-cbc":
|
|
}
|
|
if EF == "" {
|
|
return &Buffer{
|
|
value: result.([]byte),
|
|
}
|
|
}
|
|
return Convert(h.vm, result, SF, EF)
|
|
}
|
|
|
|
func (h *Hmac) Update(data interface{}, SF, EF string) interface{} {
|
|
switch h.Algorithm {
|
|
case "md5", "sha1", "sha256", "sha512":
|
|
h.middle.(hash.Hash).Write(toBytes(data))
|
|
case "aes-256-cbc":
|
|
if SF == "hex" {
|
|
data = Convert(h.vm, data, "hex", "")
|
|
}
|
|
return Convert(h.vm, h.middle.(*AesCipher).Update(toBytes(data)), "", EF)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *Hmac) Final(EF string) interface{} {
|
|
switch h.Algorithm {
|
|
case "md5", "sha1", "sha256", "sha512":
|
|
case "aes-256-cbc":
|
|
return Convert(h.vm, h.middle.(*AesCipher).Final(), "", EF)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Crypto) CreateCipheriv(algorithm string, key, iv interface{}) *Hmac {
|
|
var middle interface{}
|
|
var err error
|
|
switch algorithm {
|
|
case "aes-256-cbc":
|
|
|
|
middle, err = NewAesCipher(c.vm, toBytes(key), toBytes(iv), false)
|
|
if err != nil {
|
|
panic(Error(c.vm, err))
|
|
}
|
|
}
|
|
return &Hmac{
|
|
vm: c.vm,
|
|
// decode: true,
|
|
middle: middle,
|
|
Algorithm: algorithm,
|
|
}
|
|
}
|
|
|
|
func (c *Crypto) CreateDecipheriv(algorithm string, key, iv interface{}) *Hmac {
|
|
var middle interface{}
|
|
var err error
|
|
switch algorithm {
|
|
case "aes-256-cbc":
|
|
middle, err = NewAesCipher(c.vm, toBytes(key), toBytes(iv), true)
|
|
if err != nil {
|
|
panic(Error(c.vm, err))
|
|
}
|
|
}
|
|
return &Hmac{
|
|
// decode: true,
|
|
vm: c.vm,
|
|
middle: middle,
|
|
Algorithm: algorithm,
|
|
}
|
|
}
|
|
|
|
func (c *Crypto) CreateHash(algorithm string) *Hmac {
|
|
var hashFunc func() hash.Hash
|
|
switch algorithm {
|
|
case "md5":
|
|
hashFunc = md5.New
|
|
case "sha1":
|
|
hashFunc = sha1.New
|
|
case "sha256":
|
|
hashFunc = sha256.New
|
|
case "sha512":
|
|
hashFunc = sha512.New
|
|
default:
|
|
return nil
|
|
}
|
|
return &Hmac{
|
|
vm: c.vm,
|
|
middle: hashFunc(),
|
|
Algorithm: algorithm,
|
|
}
|
|
}
|
|
|
|
func (c *Crypto) CreateHmac(algorithm string, key interface{}) *Hmac {
|
|
var hashFunc func() hash.Hash
|
|
switch algorithm {
|
|
case "md5":
|
|
hashFunc = md5.New
|
|
case "sha1":
|
|
hashFunc = sha1.New
|
|
case "sha256":
|
|
hashFunc = sha256.New
|
|
case "sha512":
|
|
hashFunc = sha512.New
|
|
default:
|
|
return nil
|
|
}
|
|
return &Hmac{
|
|
vm: c.vm,
|
|
middle: hmac.New(hashFunc, toBytes(key)),
|
|
Algorithm: algorithm,
|
|
}
|
|
}
|
|
|
|
type AesCipher struct {
|
|
block cipher.Block
|
|
iv []byte
|
|
mode cipher.BlockMode
|
|
decode bool
|
|
buffer bytes.Buffer
|
|
vm *goja.Runtime
|
|
}
|
|
|
|
func NewAesCipher(vm *goja.Runtime, key, iv []byte, decode bool) (*AesCipher, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
mode := cipher.NewCBCDecrypter(block, iv)
|
|
if !decode {
|
|
mode = cipher.NewCBCEncrypter(block, iv)
|
|
}
|
|
return &AesCipher{
|
|
vm: vm,
|
|
block: block,
|
|
iv: iv,
|
|
mode: mode,
|
|
decode: decode,
|
|
}, nil
|
|
}
|
|
|
|
func (ac *AesCipher) Update(text []byte) []byte {
|
|
//fmt.Println("Update", string(text))
|
|
if ac.decode {
|
|
// Decrypt
|
|
var err error
|
|
//fmt.Println("Decrypt1", string(text))
|
|
ac.mode.CryptBlocks(text, text)
|
|
//fmt.Println("Decrypt2", string(text))
|
|
text, err = pkcs7Unpadding(text)
|
|
if err != nil {
|
|
panic(Error(ac.vm, err))
|
|
}
|
|
//fmt.Println("Decrypt3", string(text), err)
|
|
} else {
|
|
// Encrypt
|
|
text = pkcs7Padding(text, ac.block.BlockSize())
|
|
ac.mode.CryptBlocks(text, text)
|
|
}
|
|
ac.buffer.Write(text)
|
|
return nil
|
|
// return text
|
|
}
|
|
|
|
func (ac *AesCipher) Final() []byte {
|
|
return ac.buffer.Bytes()
|
|
}
|
|
|
|
func pkcs7Unpadding(data []byte) ([]byte, error) {
|
|
length := len(data)
|
|
unpadding := int(data[length-1])
|
|
if unpadding > length {
|
|
return nil, fmt.Errorf("pkcs7: invalid padding")
|
|
}
|
|
return data[:(length - unpadding)], nil
|
|
}
|
|
|
|
// type Cipher struct{}
|
|
|
|
// func (c *Cipher) AesEncrypt(key, data string) (string, error) {
|
|
// block, err := aes.NewCipher([]byte(key))
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// ciphertext := make([]byte, aes.BlockSize+len(data))
|
|
// iv := ciphertext[:aes.BlockSize]
|
|
// if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
|
// return "", err
|
|
// }
|
|
// stream := cipher.NewCFBEncrypter(block, iv)
|
|
// stream.XORKeyStream(ciphertext[aes.BlockSize:], []byte(data))
|
|
// return base64.StdEncoding.EncodeToString(ciphertext), nil
|
|
// }
|
|
|
|
// func (c *Cipher) AesDecrypt(key, ciphertext string) (string, error) {
|
|
// block, err := aes.NewCipher([]byte(key))
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// data, err := base64.StdEncoding.DecodeString(ciphertext)
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// if len(data) < aes.BlockSize {
|
|
// return "", fmt.Errorf("ciphertext too short")
|
|
// }
|
|
// iv := data[:aes.BlockSize]
|
|
// data = data[aes.BlockSize:]
|
|
// stream := cipher.NewCFBDecrypter(block, iv)
|
|
// stream.XORKeyStream(data, data)
|
|
// return string(data), nil
|
|
// }
|
|
|
|
// func (c *Cipher) Rc4Encrypt(key, data string) (string, error) {
|
|
// cipher, err := rc4.NewCipher([]byte(key))
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// ciphertext := make([]byte, len(data))
|
|
// cipher.XORKeyStream(ciphertext, []byte(data))
|
|
// return base64.StdEncoding.EncodeToString(ciphertext), nil
|
|
// }
|
|
|
|
// func (c *Cipher) Rc4Decrypt(key, ciphertext string) (string, error) {
|
|
// cipher, err := rc4.NewCipher([]byte(key))
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// data, err := base64.StdEncoding.DecodeString(ciphertext)
|
|
// if err != nil {
|
|
// return "", err
|
|
// }
|
|
// cipher.XORKeyStream(data, data)
|
|
// return string(data), nil
|
|
// }
|
|
|
|
func Convert(vm *goja.Runtime, data interface{}, fromFormat string, toFormat string) interface{} {
|
|
//fmt.Println(data, fromFormat, toFormat)
|
|
var dataBytes []byte
|
|
|
|
switch input := data.(type) {
|
|
case string:
|
|
dataBytes = []byte(input)
|
|
case []byte:
|
|
dataBytes = input
|
|
case *Buffer:
|
|
dataBytes = input.value
|
|
default:
|
|
panic(Error(vm, fmt.Errorf("invalid data type: %T", data)))
|
|
}
|
|
|
|
switch fromFormat {
|
|
case "hex":
|
|
// 将数据从 HEX 编码格式转换为字节数组
|
|
decodedData, err := hex.DecodeString(string(dataBytes))
|
|
if err != nil {
|
|
panic(Error(vm, err))
|
|
}
|
|
dataBytes = decodedData
|
|
case "base64":
|
|
// 将数据从 Base64 编码格式转换为字节数组
|
|
decodedData, err := base64.StdEncoding.DecodeString(string(dataBytes))
|
|
if err != nil {
|
|
panic(Error(vm, err))
|
|
}
|
|
dataBytes = decodedData
|
|
case "bytes", "binary":
|
|
// 不需要进行转换
|
|
case "utf8", "utf-8", "":
|
|
|
|
default:
|
|
panic(Error(vm, fmt.Errorf("unsupported input format: %s", fromFormat)))
|
|
}
|
|
|
|
//fmt.Println(string(dataBytes), fromFormat, toFormat)
|
|
|
|
switch toFormat {
|
|
case "hex":
|
|
// 将数据转换为 HEX 编码格式
|
|
//fmt.Println("hex", hex.EncodeToString(dataBytes), fromFormat, toFormat)
|
|
return hex.EncodeToString(dataBytes)
|
|
case "base64":
|
|
// 将数据转换为 Base64 编码格式
|
|
return base64.StdEncoding.EncodeToString(dataBytes)
|
|
case "bytes", "binary":
|
|
// 不需要进行转换
|
|
return dataBytes
|
|
case "utf8", "utf-8", "":
|
|
// 将数据转换为 UTF-8 编码格式
|
|
return string(dataBytes)
|
|
default:
|
|
panic(Error(vm, fmt.Errorf("unsupported output format: %s", toFormat)))
|
|
}
|
|
}
|
|
|
|
func cryptoModule(vm *goja.Runtime, module *goja.Object) {
|
|
cryto := Crypto{
|
|
vm: vm,
|
|
}
|
|
o := module.Get("exports").(*goja.Object)
|
|
o.Set("createCipheriv", cryto.CreateCipheriv)
|
|
o.Set("createDecipheriv", cryto.CreateDecipheriv)
|
|
o.Set("createHash", cryto.CreateHash)
|
|
o.Set("createHmac", cryto.CreateHmac)
|
|
}
|