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) }