七月迭代短暂完结,还有很多后端的关键东西没有弄,这是一版赶时间做的东西
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s
This commit is contained in:
61
internal/infrastructure/wecom/credential_cipher.go
Normal file
61
internal/infrastructure/wecom/credential_cipher.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Package wecom 提供企业微信外部系统 Adapter。
|
||||
package wecom
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
)
|
||||
|
||||
var credentialAAD = []byte("junhong-wecom-credential-v1")
|
||||
|
||||
// CredentialCipher 使用 AES-256-GCM 加解密企业微信敏感凭据。
|
||||
type CredentialCipher struct {
|
||||
aead cipher.AEAD
|
||||
}
|
||||
|
||||
// NewCredentialCipher 从 32 字节 Base64 密钥创建凭据加密器。
|
||||
func NewCredentialCipher(encodedKey string) (*CredentialCipher, error) {
|
||||
key, err := base64.StdEncoding.DecodeString(encodedKey)
|
||||
if err != nil || len(key) != 32 {
|
||||
return nil, errors.New(errors.CodeWeComCredentialInvalid, "企业微信凭据加密密钥必须是 32 字节 Base64")
|
||||
}
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeWeComCredentialInvalid, err, "初始化企业微信凭据加密器失败")
|
||||
}
|
||||
aead, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeWeComCredentialInvalid, err, "初始化企业微信凭据加密模式失败")
|
||||
}
|
||||
return &CredentialCipher{aead: aead}, nil
|
||||
}
|
||||
|
||||
// Encrypt 加密单个敏感凭据,返回 nonce 与密文组合。
|
||||
func (c *CredentialCipher) Encrypt(plaintext string) ([]byte, error) {
|
||||
if c == nil || c.aead == nil || plaintext == "" {
|
||||
return nil, errors.New(errors.CodeWeComCredentialInvalid)
|
||||
}
|
||||
nonce := make([]byte, c.aead.NonceSize())
|
||||
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "生成企业微信凭据随机数失败")
|
||||
}
|
||||
return c.aead.Seal(nonce, nonce, []byte(plaintext), credentialAAD), nil
|
||||
}
|
||||
|
||||
// Decrypt 解密单个企业微信敏感凭据。
|
||||
func (c *CredentialCipher) Decrypt(ciphertext []byte) (string, error) {
|
||||
if c == nil || c.aead == nil || len(ciphertext) <= c.aead.NonceSize() {
|
||||
return "", errors.New(errors.CodeWeComCredentialInvalid)
|
||||
}
|
||||
nonce := ciphertext[:c.aead.NonceSize()]
|
||||
plaintext, err := c.aead.Open(nil, nonce, ciphertext[c.aead.NonceSize():], credentialAAD)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(errors.CodeWeComCredentialInvalid, err, "解密企业微信凭据失败")
|
||||
}
|
||||
return string(plaintext), nil
|
||||
}
|
||||
Reference in New Issue
Block a user