crypto/rsa - RSA 非对称加密和签名
概述
crypto/rsa 包实现了 RSA 加密和签名算法(PKCS#1 v1.5 和 OAEP)。
RSA 是一种非对称加密算法,使用一对密钥:
- 私钥(Private Key):保密,用于解密和签名
- 公钥(Public Key):公开,用于加密和验证签名
主要用途:
- 🔐 加密:使用公钥加密,私钥解密
- ✍️ 数字签名:使用私钥签名,公钥验证
- 🔑 密钥交换:安全传输对称密钥
核心类型
1. PublicKey 类型
type PublicKey struct {
N *big.Int // 模数
E int // 指数
}
字段说明:
N:模数(大整数),决定密钥长度E:公钥指数,通常为 65537 (0x10001)
方法:
func (pub *PublicKey) Size() int
返回模数的大小(字节数)
示例:
pubKey := &rsa.PublicKey{
N: big.NewInt(...),
E: 65537,
}
size := pubKey.Size() // 256 (对于 2048 位密钥)
2. PrivateKey 类型
type PrivateKey struct {
PublicKey
D *big.Int // 私钥指数
Primes []*big.Int // 质数因子(通常为 P 和 Q)
// ... 其他预计算值
}
字段说明:
PublicKey:嵌入的公钥D:私钥指数(必须保密)Primes:生成 N 的质数因子(P, Q, …)
方法:
func (priv *PrivateKey) Public() crypto.PublicKey
func (priv *PrivateKey) Size() int
安全提示:
- ⚠️ 私钥必须严格保密
- ⚠️ 不应在日志或错误消息中打印私钥
- ⚠️ 使用后立即清除内存中的私钥
密钥生成
GenerateKey 函数
func GenerateKey(random io.Reader, bits int) (*PrivateKey, error)
功能:生成 RSA 密钥对。
参数:
random:随机数生成器(使用crypto/rand.Reader)bits:密钥长度(位)
密钥长度建议:
- ❌ 1024 位:已不安全,不应使用
- ⚠️ 2048 位:目前安全,推荐最低标准
- ✅ 3072 位:推荐,长期安全
- ✅ 4096 位:高安全性需求
返回值:
*PrivateKey:生成的私钥(包含公钥)error:生成错误
示例:
package main
import (
"crypto/rand"
"crypto/rsa"
"fmt"
"log"
)
func main() {
// 生成 2048 位密钥
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatal(err)
}
fmt.Printf("密钥长度:%d 位\n", privateKey.N.BitLen())
fmt.Printf("公钥指数:%d\n", privateKey.E)
fmt.Printf("私钥大小:%d 字节\n", privateKey.Size())
}
输出:
密钥长度:2048 位
公钥指数:65537
私钥大小:256 字节
密钥编码和序列化
PEM 编码
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"os"
)
// 保存私钥到 PEM 文件
func savePrivateKey(priv *rsa.PrivateKey, filename string) error {
// 1. 编码为 PKCS#1
privBytes := x509.MarshalPKCS1PrivateKey(priv)
// 2. 创建 PEM 块
privBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privBytes,
}
// 3. 写入文件
return os.WriteFile(filename, pem.EncodeToMemory(privBlock), 0600)
}
// 保存公钥到 PEM 文件
func savePublicKey(pub *rsa.PublicKey, filename string) error {
// 1. 编码为 PKCS#1
pubBytes := x509.MarshalPKCS1PublicKey(pub)
// 2. 创建 PEM 块
pubBlock := &pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubBytes,
}
// 3. 写入文件
return os.WriteFile(filename, pem.EncodeToMemory(pubBlock), 0644)
}
// 从 PEM 文件加载私钥
func loadPrivateKey(filename string) (*rsa.PrivateKey, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
block, _ := pem.Decode(data)
if block == nil {
return nil, fmt.Errorf("无法解析 PEM")
}
return x509.ParsePKCS1PrivateKey(block.Bytes)
}
// 从 PEM 文件加载公钥
func loadPublicKey(filename string) (*rsa.PublicKey, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
block, _ := pem.Decode(data)
if block == nil {
return nil, fmt.Errorf("无法解析 PEM")
}
return x509.ParsePKCS1PublicKey(block.Bytes)
}
PKCS#8 格式(推荐)
// 保存私钥为 PKCS#8 格式
func savePrivateKeyPKCS8(priv *rsa.PrivateKey, filename string) error {
// 1. 编码为 PKCS#8
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return err
}
// 2. 创建 PEM 块
privBlock := &pem.Block{
Type: "PRIVATE KEY",
Bytes: privBytes,
}
// 3. 写入文件
return os.WriteFile(filename, pem.EncodeToMemory(privBlock), 0600)
}
// 从 PKCS#8 加载私钥
func loadPrivateKeyPKCS8(filename string) (*rsa.PrivateKey, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
block, _ := pem.Decode(data)
if block == nil {
return nil, fmt.Errorf("无法解析 PEM")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return key.(*rsa.PrivateKey), nil
}
RSA 加密和解密
1. EncryptPKCS1v15(PKCS#1 v1.5 加密)
func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, error)
功能:使用 PKCS#1 v1.5 方案加密消息。
参数:
random:随机数生成器pub:公钥msg:要加密的消息
返回值:
[]byte:密文error:加密错误
限制:
- 消息长度受限:
len(msg) <= pub.Size() - 11 - 对于 2048 位密钥,最多加密 245 字节
示例:
package main
import (
"crypto/rand"
"crypto/rsa"
"encoding/hex"
"fmt"
"log"
)
func main() {
// 1. 生成密钥
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatal(err)
}
publicKey := &privateKey.PublicKey
// 2. 准备消息
message := []byte("Hello, RSA!")
fmt.Printf("明文:%s\n", message)
// 3. 加密
ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, message)
if err != nil {
log.Fatal(err)
}
fmt.Printf("密文(十六进制):%s\n", hex.EncodeToString(ciphertext))
// 4. 解密
decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, ciphertext)
if err != nil {
log.Fatal(err)
}
fmt.Printf("解密:%s\n", decrypted)
// 5. 验证
if string(decrypted) == string(message) {
fmt.Println("✓ 加密/解密成功")
}
}
2. EncryptOAEP(OAEP 加密,推荐)
func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey,
msg []byte, label []byte) ([]byte, error)
功能:使用 OAEP 方案加密消息。
参数:
hash:哈希函数(SHA-1, SHA-256 等)random:随机数生成器pub:公钥msg:要加密的消息label:标签(通常为nil或空)
优势:
- ✅ 比 PKCS#1 v1.5 更安全
- ✅ 可证明安全性
- ✅ 推荐使用
限制:
- 消息长度受限:
len(msg) <= pub.Size() - 2*hash.Size() - 2 - 对于 2048 位密钥 + SHA-256,最多加密 190 字节
示例:
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/hex"
"fmt"
"log"
)
func main() {
// 1. 生成密钥
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatal(err)
}
publicKey := &privateKey.PublicKey
// 2. 准备消息
message := []byte("Hello, OAEP!")
fmt.Printf("明文:%s\n", message)
// 3. 加密(使用 OAEP + SHA-256)
label := []byte("my-label")
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader,
publicKey, message, label)
if err != nil {
log.Fatal(err)
}
fmt.Printf("密文(十六进制):%s\n", hex.EncodeToString(ciphertext))
// 4. 解密
decrypted, err := rsa.DecryptOAEP(sha256.New(), rand.Reader,
privateKey, ciphertext, label)
if err != nil {
log.Fatal(err)
}
fmt.Printf("解密:%s\n", decrypted)
// 5. 验证
if string(decrypted) == string(message) {
fmt.Println("✓ OAEP 加密/解密成功")
}
}
3. DecryptPKCS1v15(PKCS#1 v1.5 解密)
func DecryptPKCS1v15(random io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error)
功能:使用 PKCS#1 v1.5 方案解密密文。
参数:
random:随机数生成器(用于防御侧信道攻击)priv:私钥ciphertext:密文
返回值:
[]byte:解密后的明文error:解密错误
4. DecryptOAEP(OAEP 解密,推荐)
func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey,
ciphertext []byte, label []byte) ([]byte, error)
功能:使用 OAEP 方案解密密文。
参数:
hash:哈希函数(必须与加密时相同)random:随机数生成器priv:私钥ciphertext:密文label:标签(必须与加密时相同)
RSA 签名和验证
1. SignPKCS1v15(PKCS#1 v1.5 签名)
func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash,
hashed []byte) ([]byte, error)
功能:使用 PKCS#1 v1.5 方案签名。
参数:
random:随机数生成器priv:私钥hash:哈希算法标识符hashed:已哈希的消息摘要
返回值:
[]byte:签名error:签名错误
支持的哈希算法:
crypto.MD5(不推荐)crypto.SHA1(不推荐)crypto.SHA224crypto.SHA256(推荐)crypto.SHA384crypto.SHA512(推荐)
示例:
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/hex"
"fmt"
"log"
)
func main() {
// 1. 生成密钥
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatal(err)
}
publicKey := &privateKey.PublicKey
// 2. 准备消息并哈希
message := []byte("Hello, RSA Signature!")
fmt.Printf("消息:%s\n", message)
hash := sha256.Sum256(message)
fmt.Printf("哈希(十六进制):%s\n", hex.EncodeToString(hash[:]))
// 3. 签名
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey,
crypto.SHA256, hash[:])
if err != nil {
log.Fatal(err)
}
fmt.Printf("签名(十六进制):%s\n", hex.EncodeToString(signature))
// 4. 验证
err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hash[:], signature)
if err != nil {
log.Fatal("验证失败:", err)
}
fmt.Println("✓ 签名验证成功")
}
2. VerifyPKCS1v15(PKCS#1 v1.5 签名验证)
func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error
功能:验证 PKCS#1 v1.5 签名。
参数:
pub:公钥hash:哈希算法标识符hashed:已哈希的消息摘要sig:签名
返回值:
error:验证失败返回错误,成功返回nil
使用模式:
err := rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hash[:], signature)
if err != nil {
// 验证失败
log.Fatal("签名无效")
}
// 验证成功
3. SignPSS(PSS 签名,推荐)
func SignPSS(random io.Reader, priv *PrivateKey, hash crypto.Hash,
hashed []byte, opts *PSSOptions) ([]byte, error)
功能:使用 PSS 方案签名。
参数:
random:随机数生成器priv:私钥hash:哈希算法hashed:消息摘要opts:PSS 选项(可为nil使用默认值)
优势:
- ✅ 比 PKCS#1 v1.5 更安全
- ✅ 可证明安全性
- ✅ 推荐使用
PSSOptions:
type PSSOptions struct {
SaltLength int // 盐长度(通常为哈希输出长度)
Hash crypto.Hash
}
示例:
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/hex"
"fmt"
"log"
)
func main() {
// 1. 生成密钥
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatal(err)
}
publicKey := &privateKey.PublicKey
// 2. 准备消息并哈希
message := []byte("Hello, PSS Signature!")
fmt.Printf("消息:%s\n", message)
hash := sha256.Sum256(message)
// 3. 签名(使用 PSS)
opts := &rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthAuto, // 自动选择
Hash: crypto.SHA256,
}
signature, err := rsa.SignPSS(rand.Reader, privateKey,
crypto.SHA256, hash[:], opts)
if err != nil {
log.Fatal(err)
}
fmt.Printf("签名(十六进制):%s\n", hex.EncodeToString(signature))
// 4. 验证
err = rsa.VerifyPSS(publicKey, crypto.SHA256, hash[:], signature, opts)
if err != nil {
log.Fatal("验证失败:", err)
}
fmt.Println("✓ PSS 签名验证成功")
}
4. VerifyPSS(PSS 签名验证,推荐)
func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte,
sig []byte, opts *PSSOptions) error
功能:验证 PSS 签名。
参数:
pub:公钥hash:哈希算法hashed:消息摘要sig:签名opts:PSS 选项(必须与签名时相同)
PSSOptions 常量
const (
PSSSaltLengthAuto = 0 // 自动选择盐长度
PSSSaltLengthEqualsHash = -1 // 盐长度等于哈希输出长度
PSSSaltLengthMax = -2 // 最大可能盐长度
)
推荐:
- 使用
PSSSaltLengthAuto让库自动选择 - 或使用
PSSSaltLengthEqualsHash获得最佳安全性
完整示例:密钥管理和加密
示例 1:完整的密钥生命周期
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"os"
)
// KeyManager 管理 RSA 密钥
type KeyManager struct {
privateKey *rsa.PrivateKey
publicKey *rsa.PublicKey
}
// NewKeyManager 生成新密钥对
func NewKeyManager(bits int) (*KeyManager, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, err
}
return &KeyManager{
privateKey: privateKey,
publicKey: &privateKey.PublicKey,
}, nil
}
// SaveKeys 保存密钥到文件
func (km *KeyManager) SaveKeys(privFile, pubFile string) error {
// 保存私钥(PKCS#8)
privBytes, err := x509.MarshalPKCS8PrivateKey(km.privateKey)
if err != nil {
return err
}
privBlock := &pem.Block{
Type: "PRIVATE KEY",
Bytes: privBytes,
}
if err := os.WriteFile(privFile, pem.EncodeToMemory(privBlock), 0600); err != nil {
return err
}
// 保存公钥
pubBytes := x509.MarshalPKCS1PublicKey(km.publicKey)
pubBlock := &pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubBytes,
}
return os.WriteFile(pubFile, pem.EncodeToMemory(pubBlock), 0644)
}
// LoadPrivateKey 从文件加载私钥
func LoadPrivateKey(filename string) (*rsa.PrivateKey, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
block, _ := pem.Decode(data)
if block == nil {
return nil, fmt.Errorf("无法解析 PEM")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return key.(*rsa.PrivateKey), nil
}
// LoadPublicKey 从文件加载公钥
func LoadPublicKey(filename string) (*rsa.PublicKey, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
block, _ := pem.Decode(data)
if block == nil {
return nil, fmt.Errorf("无法解析 PEM")
}
return x509.ParsePKCS1PublicKey(block.Bytes)
}
func main() {
// 1. 生成密钥对
km, err := NewKeyManager(2048)
if err != nil {
log.Fatal(err)
}
fmt.Println("✓ 密钥对生成成功")
// 2. 保存密钥
err = km.SaveKeys("private.pem", "public.pem")
if err != nil {
log.Fatal(err)
}
fmt.Println("✓ 密钥保存成功")
// 3. 加载密钥
privKey, err := LoadPrivateKey("private.pem")
if err != nil {
log.Fatal(err)
}
pubKey, err := LoadPublicKey("public.pem")
if err != nil {
log.Fatal(err)
}
fmt.Println("✓ 密钥加载成功")
// 4. 验证密钥匹配
if privKey.N.Cmp(pubKey.N) == 0 && privKey.E == pubKey.E {
fmt.Println("✓ 密钥对匹配")
}
}
示例 2:混合加密系统(RSA + AES)
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"encoding/hex"
"fmt"
"io"
"log"
)
// HybridEncrypt 使用 RSA 加密 AES 密钥,然后使用 AES 加密数据
func HybridEncrypt(pubKey *rsa.PublicKey, plaintext []byte) ([]byte, []byte, error) {
// 1. 生成随机 AES 密钥
aesKey := make([]byte, 32) // 256 位
if _, err := io.ReadFull(rand.Reader, aesKey); err != nil {
return nil, nil, err
}
// 2. 使用 RSA 加密 AES 密钥
encryptedKey, err := rsa.EncryptOAEP(sha256.New(), rand.Reader,
pubKey, aesKey, nil)
if err != nil {
return nil, nil, err
}
// 3. 使用 AES-GCM 加密数据
block, err := aes.NewCipher(aesKey)
if err != nil {
return nil, nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, nil, err
}
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, nil, err
}
ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
return encryptedKey, ciphertext, nil
}
// HybridDecrypt 使用 RSA 解密 AES 密钥,然后使用 AES 解密数据
func HybridDecrypt(privKey *rsa.PrivateKey, encryptedKey, ciphertext []byte) ([]byte, error) {
// 1. 使用 RSA 解密 AES 密钥
aesKey, err := rsa.DecryptOAEP(sha256.New(), rand.Reader,
privKey, encryptedKey, nil)
if err != nil {
return nil, err
}
// 2. 使用 AES-GCM 解密数据
block, err := aes.NewCipher(aesKey)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return nil, fmt.Errorf("密文太短")
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
}
return plaintext, nil
}
func main() {
// 1. 生成密钥对
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatal(err)
}
publicKey := &privateKey.PublicKey
// 2. 准备大数据
plaintext := []byte("这是一段很长的数据,需要使用混合加密系统...")
fmt.Printf("明文长度:%d 字节\n", len(plaintext))
// 3. 加密
encryptedKey, ciphertext, err := HybridEncrypt(publicKey, plaintext)
if err != nil {
log.Fatal(err)
}
fmt.Printf("加密的密钥(十六进制):%s\n", hex.EncodeToString(encryptedKey))
fmt.Printf("密文长度:%d 字节\n", len(ciphertext))
// 4. 解密
decrypted, err := HybridDecrypt(privateKey, encryptedKey, ciphertext)
if err != nil {
log.Fatal(err)
}
fmt.Printf("解密:%s\n", decrypted)
// 5. 验证
if string(decrypted) == string(plaintext) {
fmt.Println("✓ 混合加密/解密成功")
}
}
示例 3:数字签名应用
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"log"
"os"
)
// DocumentSigner 文档签名器
type DocumentSigner struct {
privateKey *rsa.PrivateKey
publicKey *rsa.PublicKey
}
// NewDocumentSigner 创建签名器
func NewDocumentSigner(privKey *rsa.PrivateKey, pubKey *rsa.PublicKey) *DocumentSigner {
return &DocumentSigner{
privateKey: privKey,
publicKey: pubKey,
}
}
// Sign 对文档进行签名
func (ds *DocumentSigner) Sign(document []byte) (string, error) {
// 1. 计算哈希
hash := sha256.Sum256(document)
// 2. 签名(使用 PSS)
opts := &rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthAuto,
Hash: crypto.SHA256,
}
signature, err := rsa.SignPSS(rand.Reader, ds.privateKey,
crypto.SHA256, hash[:], opts)
if err != nil {
return "", err
}
// 3. Base64 编码
return base64.StdEncoding.EncodeToString(signature), nil
}
// Verify 验证文档签名
func (ds *DocumentSigner) Verify(document []byte, signatureB64 string) error {
// 1. 解码签名
signature, err := base64.StdEncoding.DecodeString(signatureB64)
if err != nil {
return err
}
// 2. 计算哈希
hash := sha256.Sum256(document)
// 3. 验证
opts := &rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthAuto,
Hash: crypto.SHA256,
}
return rsa.VerifyPSS(ds.publicKey, crypto.SHA256, hash[:], signature, opts)
}
func main() {
// 1. 生成密钥对
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatal(err)
}
publicKey := &privateKey.PublicKey
// 2. 创建签名器
signer := NewDocumentSigner(privateKey, publicKey)
// 3. 文档
document := []byte(`
合同编号:2024-001
甲方:张三
乙方:李四
金额:10000 元
日期:2024-01-01
`)
// 4. 签名
signature, err := signer.Sign(document)
if err != nil {
log.Fatal(err)
}
fmt.Printf("签名(Base64):%s\n", signature)
// 5. 验证
err = signer.Verify(document, signature)
if err != nil {
log.Fatal("验证失败:", err)
}
fmt.Println("✓ 签名验证成功")
// 6. 篡改检测
tampered := append(document, []byte("篡改内容")...)
err = signer.Verify(tampered, signature)
if err != nil {
fmt.Println("✓ 检测到篡改:签名无效")
}
}
安全最佳实践
✅ 推荐做法
-
使用足够的密钥长度
// ✅ 推荐:2048 位或更高 privateKey, err := rsa.GenerateKey(rand.Reader, 2048) // ✅ 更好:3072 位 privateKey, err := rsa.GenerateKey(rand.Reader, 3072) -
使用 OAEP 而不是 PKCS#1 v1.5
// ✅ 推荐:OAEP ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, pubKey, msg, nil) // ❌ 避免:PKCS#1 v1.5(除非需要兼容性) ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, msg) -
使用 PSS 签名而不是 PKCS#1 v1.5
// ✅ 推荐:PSS opts := &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA256, } signature, err := rsa.SignPSS(rand.Reader, privKey, crypto.SHA256, hash[:], opts) -
使用安全的哈希算法
// ✅ 推荐:SHA-256 或 SHA-512 hash := sha256.Sum256(message) // ❌ 避免:MD5 或 SHA-1 hash := md5.Sum(message) // 不安全 -
保护私钥
// ✅ 使用文件权限 0600 os.WriteFile("private.pem", pemData, 0600) // ✅ 使用密码加密私钥 encryptedPEM := x509.EncryptPEMBlock(rand.Reader, "ENCRYPTED PRIVATE KEY", privBytes, password, nil) -
使用混合加密
// ✅ RSA 仅用于加密密钥,使用对称加密处理大数据 aesKey := make([]byte, 32) rand.Read(aesKey) encryptedKey, _ := rsa.EncryptOAEP(sha256.New(), rand.Reader, pubKey, aesKey, nil)
❌ 不安全做法
-
使用过短的密钥
// ❌ 1024 位已不安全 privateKey, err := rsa.GenerateKey(rand.Reader, 1024) -
直接使用 RSA 加密大数据
// ❌ RSA 有长度限制 largeData := make([]byte, 1024) // 超过限制 ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, largeData) // err: 消息太长 -
硬编码私钥
// ❌ 绝对不要硬编码私钥 privateKey := "-----BEGIN RSA PRIVATE KEY-----\n..." -
在日志中打印私钥
// ❌ 不要打印私钥 log.Printf("私钥:%+v", privateKey)
常见错误处理
1. 密钥生成错误
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
// 可能原因:随机数生成器失败
log.Printf("密钥生成失败:%v", err)
}
2. 加密长度错误
message := make([]byte, 300) // 太长
_, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, message)
if err != nil {
// 消息太长
log.Printf("加密失败:%v", err)
}
// 正确:检查长度限制
maxSize := pubKey.Size() - 11
if len(message) > maxSize {
log.Printf("消息太长:%d > %d", len(message), maxSize)
}
3. 解密错误
decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, privKey, ciphertext)
if err != nil {
// 可能原因:
// - 密文损坏
// - 使用错误的私钥
// - 密文被篡改
log.Printf("解密失败:%v", err)
}
4. 签名验证错误
err := rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, hash[:], signature)
if err != nil {
// 可能原因:
// - 签名无效
// - 使用错误的公钥
// - 哈希算法不匹配
// - 消息被篡改
log.Printf("验证失败:%v", err)
}
RSA vs ECC 对比
| 特性 | RSA | ECC (椭圆曲线) |
|---|---|---|
| 密钥长度 | 2048-4096 位 | 256-384 位 |
| 安全性 | 基于大数分解 | 基于离散对数 |
| 性能 | 较慢 | 更快 |
| 签名大小 | 较大(256 字节) | 较小(64 字节) |
| 兼容性 | 广泛支持 | 现代系统支持 |
| 推荐使用 | 传统系统 | 新系统 |
总结
核心 API
// 密钥生成
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
// 加密(推荐 OAEP)
ciphertext, err := rsa.EncryptOAEP(hash, random, pubKey, msg, label)
// 解密(推荐 OAEP)
plaintext, err := rsa.DecryptOAEP(hash, random, privKey, ciphertext, label)
// 签名(推荐 PSS)
signature, err := rsa.SignPSS(random, privKey, hash, hashed, opts)
// 验证(推荐 PSS)
err = rsa.VerifyPSS(pubKey, hash, hashed, signature, opts)
安全要点
✅ 应该:
- 使用 2048 位或更长的密钥
- 使用 OAEP 进行加密
- 使用 PSS 进行签名
- 使用 SHA-256 或更好的哈希
- 保护私钥安全
- 使用混合加密处理大数据
❌ 不应该:
- 使用短于 2048 位的密钥
- 使用 PKCS#1 v1.5(除非需要兼容性)
- 使用 MD5 或 SHA-1
- 直接加密大数据
- 泄露私钥
使用场景
| 场景 | 推荐方案 |
|---|---|
| 加密小数据 | RSA-OAEP |
| 加密大数据 | RSA + AES(混合) |
| 数字签名 | RSA-PSS |
| 密钥交换 | RSA-OAEP |
| 证书 | RSA 或 ECC |
参考资料
最后更新:2026-04-03
Go 版本:Go 1.23+
安全状态:✅ 推荐使用(正确配置下)