Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.SHA224
  • crypto.SHA256(推荐)
  • crypto.SHA384
  • crypto.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("✓ 检测到篡改:签名无效")
    }
}

安全最佳实践

✅ 推荐做法

  1. 使用足够的密钥长度

    // ✅ 推荐:2048 位或更高
    privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
    // ✅ 更好:3072 位
    privateKey, err := rsa.GenerateKey(rand.Reader, 3072)
    
  2. 使用 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)
    
  3. 使用 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)
    
  4. 使用安全的哈希算法

    // ✅ 推荐:SHA-256 或 SHA-512
    hash := sha256.Sum256(message)
    
    // ❌ 避免:MD5 或 SHA-1
    hash := md5.Sum(message) // 不安全
    
  5. 保护私钥

    // ✅ 使用文件权限 0600
    os.WriteFile("private.pem", pemData, 0600)
    
    // ✅ 使用密码加密私钥
    encryptedPEM := x509.EncryptPEMBlock(rand.Reader, 
                                          "ENCRYPTED PRIVATE KEY", 
                                          privBytes, password, nil)
    
  6. 使用混合加密

    // ✅ RSA 仅用于加密密钥,使用对称加密处理大数据
    aesKey := make([]byte, 32)
    rand.Read(aesKey)
    encryptedKey, _ := rsa.EncryptOAEP(sha256.New(), rand.Reader, 
                                        pubKey, aesKey, nil)
    

❌ 不安全做法

  1. 使用过短的密钥

    // ❌ 1024 位已不安全
    privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
    
  2. 直接使用 RSA 加密大数据

    // ❌ RSA 有长度限制
    largeData := make([]byte, 1024) // 超过限制
    ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, largeData)
    // err: 消息太长
    
  3. 硬编码私钥

    // ❌ 绝对不要硬编码私钥
    privateKey := "-----BEGIN RSA PRIVATE KEY-----\n..."
    
  4. 在日志中打印私钥

    // ❌ 不要打印私钥
    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 对比

特性RSAECC (椭圆曲线)
密钥长度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+
安全状态:✅ 推荐使用(正确配置下)