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 }