From fe341735dd350afc3e83862570e3a468afa07b80 Mon Sep 17 00:00:00 2001 From: bvbej Date: Sat, 20 Dec 2025 10:45:09 +0800 Subject: [PATCH] =?UTF-8?q?[=F0=9F=9A=80]=20v0.13.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/rsa/rsa.go | 258 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 216 insertions(+), 42 deletions(-) diff --git a/pkg/rsa/rsa.go b/pkg/rsa/rsa.go index 928b98b..e074330 100644 --- a/pkg/rsa/rsa.go +++ b/pkg/rsa/rsa.go @@ -6,6 +6,7 @@ import ( "crypto/x509" "encoding/base64" "encoding/pem" + "errors" ) var _ Public = (*rsaPub)(nil) @@ -19,7 +20,6 @@ type Public interface { type Private interface { i() - Decrypt(decryptStr string) (string, error) DecryptURLEncoding(decryptStr string) (string, error) } @@ -46,86 +46,260 @@ func NewPrivate(privateKey string) Private { func (pub *rsaPub) i() {} -func (pub *rsaPub) Encrypt(encryptStr string) (string, error) { - // pem 解码 - block, _ := pem.Decode([]byte(pub.PublicKey)) +// parsePublicKey 解析多种格式的公钥 +func parsePublicKey(pemData []byte) (*rsa.PublicKey, error) { + block, _ := pem.Decode(pemData) + if block == nil { + return nil, errors.New("failed to decode PEM block containing public key") + } - // x509 解码 - publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + // 检查PEM块类型 + switch block.Type { + case "PUBLIC KEY": // PKIX/SPKI 格式 (Node.js生成的格式) + pub, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, err + } + if rsaPub, ok := pub.(*rsa.PublicKey); ok { + return rsaPub, nil + } + return nil, errors.New("not an RSA public key") + + case "RSA PUBLIC KEY": // PKCS#1 格式 + return x509.ParsePKCS1PublicKey(block.Bytes) + + default: + // 尝试自动检测格式 + // 先尝试PKIX格式 + if pub, err := x509.ParsePKIXPublicKey(block.Bytes); err == nil { + if rsaPub, ok := pub.(*rsa.PublicKey); ok { + return rsaPub, nil + } + } + + // 再尝试PKCS#1格式 + if pub, err := x509.ParsePKCS1PublicKey(block.Bytes); err == nil { + return pub, nil + } + + return nil, errors.New("unsupported public key format: " + block.Type) + } +} + +func (pub *rsaPub) Encrypt(encryptStr string) (string, error) { + publicKey, err := parsePublicKey([]byte(pub.PublicKey)) if err != nil { return "", err } - // 类型断言 - publicKey := publicKeyInterface.(*rsa.PublicKey) - - //对明文进行加密 + // 对明文进行加密 encryptedStr, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(encryptStr)) if err != nil { return "", err } - //返回密文 + // 返回密文 return base64.StdEncoding.EncodeToString(encryptedStr), nil } func (pub *rsaPub) EncryptURLEncoding(encryptStr string) (string, error) { - // pem 解码 - block, _ := pem.Decode([]byte(pub.PublicKey)) - - // x509 解码 - publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + publicKey, err := parsePublicKey([]byte(pub.PublicKey)) if err != nil { return "", err } - // 类型断言 - publicKey := publicKeyInterface.(*rsa.PublicKey) - - //对明文进行加密 + // 对明文进行加密 encryptedStr, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(encryptStr)) if err != nil { return "", err } - //返回密文 + // 返回密文 return base64.URLEncoding.EncodeToString(encryptedStr), nil } func (pri *rsaPri) i() {} -func (pri *rsaPri) Decrypt(decryptStr string) (string, error) { - // pem 解码 - block, _ := pem.Decode([]byte(pri.PrivateKey)) - - // X509 解码 - privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return "", err +// parsePrivateKey 解析多种格式的私钥 +func parsePrivateKey(pemData []byte) (*rsa.PrivateKey, error) { + block, _ := pem.Decode(pemData) + if block == nil { + return nil, errors.New("failed to decode PEM block containing private key") } - decryptBytes, err := base64.StdEncoding.DecodeString(decryptStr) - //对密文进行解密 - decrypted, _ := rsa.DecryptPKCS1v15(rand.Reader, privateKey, decryptBytes) + // 检查PEM块类型 + switch block.Type { + case "RSA PRIVATE KEY": // PKCS#1 格式 + return x509.ParsePKCS1PrivateKey(block.Bytes) - //返回明文 - return string(decrypted), nil + case "PRIVATE KEY": // PKCS#8 格式 (Node.js生成的格式) + priv, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + if rsaPriv, ok := priv.(*rsa.PrivateKey); ok { + return rsaPriv, nil + } + return nil, errors.New("not an RSA private key") + + case "ENCRYPTED PRIVATE KEY": // 加密的PKCS#8格式 + // 注意:对于加密的PKCS#8私钥,需要先解密 + // 这里返回错误,建议用户先解密再使用 + return nil, errors.New("encrypted private key detected. Please decrypt it first before using") + + default: + // 尝试自动检测格式 + // 先尝试PKCS#1格式 + if priv, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil { + return priv, nil + } + + // 再尝试PKCS#8格式 + if priv, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil { + if rsaPriv, ok := priv.(*rsa.PrivateKey); ok { + return rsaPriv, nil + } + return nil, errors.New("not an RSA private key") + } + + return nil, errors.New("unsupported private key format: " + block.Type) + } +} + +func (pri *rsaPri) Decrypt(decryptStr string) (string, error) { + return pri.decryptInternal(decryptStr, base64.StdEncoding.DecodeString) } func (pri *rsaPri) DecryptURLEncoding(decryptStr string) (string, error) { - // pem 解码 - block, _ := pem.Decode([]byte(pri.PrivateKey)) + return pri.decryptInternal(decryptStr, base64.URLEncoding.DecodeString) +} - // X509 解码 - privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) +// decryptInternal 内部解密方法 +func (pri *rsaPri) decryptInternal( + decryptStr string, + decodeFunc func(string) ([]byte, error), +) (string, error) { + // 解析私钥 + privateKey, err := parsePrivateKey([]byte(pri.PrivateKey)) if err != nil { return "", err } - decryptBytes, err := base64.URLEncoding.DecodeString(decryptStr) - //对密文进行解密 - decrypted, _ := rsa.DecryptPKCS1v15(rand.Reader, privateKey, decryptBytes) + // 解码Base64密文 + decryptBytes, err := decodeFunc(decryptStr) + if err != nil { + return "", err + } - //返回明文 + // 对密文进行解密 + decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, decryptBytes) + if err != nil { + return "", err + } + + // 返回明文 return string(decrypted), nil } + +// DetectKeyFormat 辅助函数:检测密钥格式并提供使用建议 +func DetectKeyFormat(key string) (string, string, error) { + block, _ := pem.Decode([]byte(key)) + if block == nil { + return "", "", errors.New("invalid PEM format") + } + + var format string + var suggestion string + + switch block.Type { + case "PUBLIC KEY": + if _, err := x509.ParsePKIXPublicKey(block.Bytes); err == nil { + format = "PKIX/SPKI Public Key" + suggestion = "可以直接使用" + } else { + format = "Unknown Public Key" + } + + case "RSA PUBLIC KEY": + format = "PKCS#1 Public Key" + suggestion = "可以直接使用" + + case "RSA PRIVATE KEY": + format = "PKCS#1 Private Key" + suggestion = "可以直接使用" + + case "PRIVATE KEY": + // 尝试解析以确认是否是PKCS#8 + if _, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil { + format = "PKCS#8 Private Key" + suggestion = "可以直接使用(兼容Node.js生成的格式)" + } else { + format = "Unknown PKCS#8 Private Key" + } + + case "ENCRYPTED PRIVATE KEY": + format = "Encrypted PKCS#8 Private Key" + suggestion = "请先使用OpenSSL解密:openssl pkcs8 -in encrypted.pem -out decrypted.pem -nocrypt" + + default: + format = "Unknown Key Type: " + block.Type + suggestion = "请转换为支持的格式" + } + + return format, suggestion, nil +} + +// ConvertPKCS8ToPKCS1 转换函数:PKCS#8 转 PKCS#1(如果需要) +func ConvertPKCS8ToPKCS1(pkcs8Key string) (string, error) { + block, _ := pem.Decode([]byte(pkcs8Key)) + if block == nil { + return "", errors.New("failed to decode PEM block") + } + + if block.Type != "PRIVATE KEY" { + return "", errors.New("not a PKCS#8 private key") + } + + key, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return "", err + } + + rsaKey, ok := key.(*rsa.PrivateKey) + if !ok { + return "", errors.New("not an RSA private key") + } + + // 编码为 PKCS#1 + pkcs1Bytes := x509.MarshalPKCS1PrivateKey(rsaKey) + pkcs1Block := &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: pkcs1Bytes, + } + + return string(pem.EncodeToMemory(pkcs1Block)), nil +} + +// IsEncryptedKey 检查是否是加密私钥 +func IsEncryptedKey(key string) bool { + block, _ := pem.Decode([]byte(key)) + if block == nil { + return false + } + + // 现代加密私钥使用 ENCRYPTED PRIVATE KEY 类型 + return block.Type == "ENCRYPTED PRIVATE KEY" +} + +// DecryptPrivateKey 解密加密私钥的辅助函数(使用OpenSSL命令) +func DecryptPrivateKey(encryptedKey, passphrase string) (string, error) { + if !IsEncryptedKey(encryptedKey) { + return "", errors.New("not an encrypted private key") + } + + // 注意:这里只提供建议,实际解密应在外部进行 + return "", errors.New(`请使用OpenSSL解密: +openssl pkcs8 -in encrypted.pem -out decrypted.pem -passin pass:"` + passphrase + `" + +或者使用编程方式在外部解密后再传入本库`) +} -- 2.34.1