Files
arenax-server/utility/rsa/rsa.go
2025-06-16 10:19:38 +08:00

175 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rsa
import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"os"
"strings"
"sync"
)
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, "gamelife.rsaKey").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(keyFilePath string) error {
// 读取密钥文件
keyBytes, err := os.ReadFile(keyFilePath)
if err != nil {
return fmt.Errorf("读取密钥文件失败: %w", err)
}
var pubFound, privFound bool
rest := keyBytes
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil {
break
}
// 转换为小写以匹配你的密钥格式
blockTypeLower := strings.ToLower(block.Type)
switch blockTypeLower {
case "rsa public key":
// 尝试解析 PKCS#1 格式的公钥
pubKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
// 尝试 PKIX 格式(兼容性处理)
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return fmt.Errorf("无法解析 RSA 公钥: %w", err)
}
var ok bool
if c.publicKey, ok = pub.(*rsa.PublicKey); !ok {
return errors.New("解析的公钥不是 RSA 公钥")
}
} else {
c.publicKey = pubKey
}
pubFound = true
case "rsa private key":
// 解析 PKCS#1 格式的私钥
privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return fmt.Errorf("无法解析 RSA 私钥: %w", err)
}
c.privateKey = privKey
privFound = true
default:
// 忽略未知的 PEM 块
continue
}
}
if !pubFound {
return errors.New("未找到有效的 RSA 公钥")
}
if !privFound {
return errors.New("未找到有效的 RSA 私钥")
}
return nil
}
// EncryptWithPublicKey 使用公钥加密数据
func (c *rsaClient) EncryptWithPublicKey(plaintext []byte) ([]byte, error) {
if c.publicKey == nil {
return nil, errors.New("公钥未加载")
}
// 使用 OAEP 填充进行加密
ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, c.publicKey, plaintext)
if err != nil {
return nil, fmt.Errorf("公钥加密失败: %w", err)
}
return ciphertext, nil
}
// DecryptWithPrivateKey 使用私钥解密数据
func (c *rsaClient) DecryptWithPrivateKey(ciphertext []byte) ([]byte, error) {
if c.privateKey == nil {
return nil, errors.New("私钥未加载")
}
// 使用 OAEP 填充进行解密
plaintext, err := rsa.DecryptPKCS1v15(rand.Reader, c.privateKey, ciphertext)
if err != nil {
return nil, fmt.Errorf("私钥解密失败: %w", err)
}
return plaintext, nil
}