draft
This commit is contained in:
142
backend/internal/channel/heepay/crypto.go
Normal file
142
backend/internal/channel/heepay/crypto.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package heepay
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// EncryptRequest 使用 RSA+3DES 加密请求体
|
||||
// 1. 生成随机 3DES 密钥(24 字节)
|
||||
// 2. 用 3DES-CBC 加密 JSON 请求体
|
||||
// 3. 用汇元 RSA 公钥加密 3DES 密钥
|
||||
func EncryptRequest(plaintext []byte, publicKeyPEM string) (encData string, encKey string, err error) {
|
||||
pubKey, err := parseRSAPublicKey(publicKeyPEM)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// 生成 3DES 密钥
|
||||
desKey := make([]byte, 24)
|
||||
if _, err = rand.Read(desKey); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// 3DES 加密
|
||||
ciphertext, err := tripleDesEncrypt(plaintext, desKey)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// RSA 加密 3DES 密钥
|
||||
encKeyBytes, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, desKey)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
encData = base64.StdEncoding.EncodeToString(ciphertext)
|
||||
encKey = base64.StdEncoding.EncodeToString(encKeyBytes)
|
||||
return
|
||||
}
|
||||
|
||||
// DecryptResponse 使用 RSA 私钥 + 3DES 解密响应
|
||||
func DecryptResponse(encData, encKey, privateKeyPEM string) ([]byte, error) {
|
||||
privKey, err := parseRSAPrivateKey(privateKeyPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encKeyBytes, err := base64.StdEncoding.DecodeString(encKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
desKey, err := rsa.DecryptPKCS1v15(rand.Reader, privKey, encKeyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ciphertext, err := base64.StdEncoding.DecodeString(encData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tripleDesDecrypt(ciphertext, desKey)
|
||||
}
|
||||
|
||||
// tripleDesEncrypt 3DES-CBC 加密(PKCS5Padding)
|
||||
func tripleDesEncrypt(plaintext, key []byte) ([]byte, error) {
|
||||
block, err := des.NewTripleDESCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
plaintext = pkcs5Padding(plaintext, blockSize)
|
||||
|
||||
iv := key[:blockSize] // 使用密钥前 8 字节作为 IV
|
||||
mode := newCBCEncrypter(block, iv)
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
mode.CryptBlocks(ciphertext, plaintext)
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
// tripleDesDecrypt 3DES-CBC 解密
|
||||
func tripleDesDecrypt(ciphertext, key []byte) ([]byte, error) {
|
||||
block, err := des.NewTripleDESCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
iv := key[:blockSize]
|
||||
mode := newCBCDecrypter(block, iv)
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
mode.CryptBlocks(plaintext, ciphertext)
|
||||
return pkcs5Unpadding(plaintext)
|
||||
}
|
||||
|
||||
func pkcs5Padding(data []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(data)%blockSize
|
||||
padText := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(data, padText...)
|
||||
}
|
||||
|
||||
func pkcs5Unpadding(data []byte) ([]byte, error) {
|
||||
length := len(data)
|
||||
if length == 0 {
|
||||
return nil, errors.New("empty data")
|
||||
}
|
||||
padding := int(data[length-1])
|
||||
if padding > length {
|
||||
return nil, errors.New("invalid padding")
|
||||
}
|
||||
return data[:length-padding], nil
|
||||
}
|
||||
|
||||
func parseRSAPublicKey(pemStr string) (*rsa.PublicKey, error) {
|
||||
block, _ := pem.Decode([]byte(pemStr))
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode PEM block")
|
||||
}
|
||||
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rsaPub, ok := pub.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("not RSA public key")
|
||||
}
|
||||
return rsaPub, nil
|
||||
}
|
||||
|
||||
func parseRSAPrivateKey(pemStr string) (*rsa.PrivateKey, error) {
|
||||
block, _ := pem.Decode([]byte(pemStr))
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode PEM block")
|
||||
}
|
||||
return x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
}
|
||||
Reference in New Issue
Block a user