Files
soul-yongping/soul-api/internal/wechat/transferv3/decrypt.go

53 lines
1.5 KiB
Go
Raw Normal View History

package transferv3
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/json"
"fmt"
)
// DecryptResource 解密回调 resource文档AEAD_AES_256_GCM密钥 APIv3 32 字节,密文=实际密文+16 字节 tag
func DecryptResource(ciphertextBase64, nonce, associatedData string, apiV3Key []byte) ([]byte, error) {
if len(apiV3Key) != 32 {
return nil, fmt.Errorf("apiV3 key must be 32 bytes, got %d", len(apiV3Key))
}
raw, err := base64.StdEncoding.DecodeString(ciphertextBase64)
if err != nil {
return nil, fmt.Errorf("base64 decode: %w", err)
}
if len(raw) < 16 {
return nil, fmt.Errorf("ciphertext too short")
}
tag := raw[len(raw)-16:]
ctext := raw[:len(raw)-16]
block, err := aes.NewCipher(apiV3Key)
if err != nil {
return nil, err
}
aead, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
plain, err := aead.Open(nil, []byte(nonce), append(ctext, tag...), []byte(associatedData))
if err != nil {
return nil, fmt.Errorf("aes-gcm decrypt: %w", err)
}
return plain, nil
}
// DecryptResourceJSON 解密并解析为 JSON 对象(回调解密后的 resource
func DecryptResourceJSON(ciphertextBase64, nonce, associatedData string, apiV3Key []byte) (map[string]interface{}, error) {
plain, err := DecryptResource(ciphertextBase64, nonce, associatedData, apiV3Key)
if err != nil {
return nil, err
}
var out map[string]interface{}
if err := json.Unmarshal(plain, &out); err != nil {
return nil, err
}
return out, nil
}