127 lines
3.1 KiB
Go
127 lines
3.1 KiB
Go
package rsa
|
||
|
||
import (
|
||
"context"
|
||
"crypto/rand"
|
||
"crypto/rsa"
|
||
"crypto/x509"
|
||
"encoding/pem"
|
||
"errors"
|
||
"os"
|
||
"sync"
|
||
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
)
|
||
|
||
type rsaClient struct {
|
||
publicKey *rsa.PublicKey
|
||
privateKey *rsa.PrivateKey
|
||
}
|
||
|
||
var (
|
||
instance *rsaClient
|
||
once sync.Once
|
||
)
|
||
|
||
// init 会在包初始化时自动调用,用于加载默认的 RSA 公钥和私钥。
|
||
func init() {
|
||
ctx := context.Background()
|
||
once.Do(func() {
|
||
instance = &rsaClient{}
|
||
err := instance.loadKeys(g.Config().MustGet(ctx, "rsa.publickey").String(), g.Config().MustGet(ctx, "rsa.privatekey").String())
|
||
if err != nil {
|
||
panic("加载 RSA 密钥失败: " + err.Error())
|
||
}
|
||
})
|
||
}
|
||
|
||
// GetRsaClient 返回 RSA 客户端的单例实例。
|
||
//
|
||
// 通常用于执行加解密操作。
|
||
func GetRsaClient() *rsaClient {
|
||
return instance
|
||
}
|
||
|
||
// EncryptWithRsaPublicKey 使用加载的 RSA 公钥对原始数据进行加密。
|
||
//
|
||
// 参数:
|
||
// - plain: 待加密的明文数据。
|
||
//
|
||
// 返回值:
|
||
// - 加密后的密文数据。
|
||
// - 如果加密失败,则返回错误。
|
||
func (c *rsaClient) EncryptWithRsaPublicKey(plain []byte) ([]byte, error) {
|
||
if c.publicKey == nil {
|
||
return nil, errors.New("公钥未加载")
|
||
}
|
||
return rsa.EncryptPKCS1v15(rand.Reader, c.publicKey, plain)
|
||
}
|
||
|
||
// DecryptWithRsaPrivateKey 使用加载的 RSA 私钥对密文数据进行解密。
|
||
//
|
||
// 参数:
|
||
// - cipher: 加密后的密文数据。
|
||
//
|
||
// 返回值:
|
||
// - 解密后的明文数据。
|
||
// - 如果解密失败,则返回错误。
|
||
func (c *rsaClient) DecryptWithRsaPrivateKey(cipher []byte) ([]byte, error) {
|
||
if c.privateKey == nil {
|
||
return nil, errors.New("私钥未加载")
|
||
}
|
||
return rsa.DecryptPKCS1v15(rand.Reader, c.privateKey, cipher)
|
||
}
|
||
|
||
// loadKeys 从指定文件中加载 RSA 公钥和私钥。
|
||
//
|
||
// 参数:
|
||
// - publicKeyPath: 公钥 PEM 文件路径。
|
||
// - privateKeyPath: 私钥 PEM 文件路径。
|
||
//
|
||
// 返回值:
|
||
// - 成功返回 nil,否则返回错误信息。
|
||
func (c *rsaClient) loadKeys(publicKeyPath, privateKeyPath string) error {
|
||
// 加载公钥
|
||
pubBytes, err := os.ReadFile(publicKeyPath)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
pubBlock, _ := pem.Decode(pubBytes)
|
||
if pubBlock == nil {
|
||
return errors.New("无法解析公钥 PEM 文件")
|
||
}
|
||
pubKey, err := x509.ParsePKIXPublicKey(pubBlock.Bytes)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
var ok bool
|
||
if c.publicKey, ok = pubKey.(*rsa.PublicKey); !ok {
|
||
return errors.New("公钥不是 RSA 公钥")
|
||
}
|
||
|
||
// 加载私钥
|
||
privBytes, err := os.ReadFile(privateKeyPath)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
privBlock, _ := pem.Decode(privBytes)
|
||
if privBlock == nil {
|
||
return errors.New("无法解析私钥 PEM 文件")
|
||
}
|
||
// 尝试解析 PKCS#8 格式
|
||
privKey, err := x509.ParsePKCS8PrivateKey(privBlock.Bytes)
|
||
if err != nil {
|
||
// 回退尝试 PKCS#1 格式
|
||
privKey, err = x509.ParsePKCS1PrivateKey(privBlock.Bytes)
|
||
if err != nil {
|
||
return errors.New("解析私钥失败: 既不是 PKCS#8 也不是 PKCS#1 格式")
|
||
}
|
||
}
|
||
var ok2 bool
|
||
if c.privateKey, ok2 = privKey.(*rsa.PrivateKey); !ok2 {
|
||
return errors.New("私钥不是 RSA 私钥")
|
||
}
|
||
|
||
return nil
|
||
}
|