Go 中如何生成带密码保护的 RSA 私钥

作者:袖梨 2026-06-24

本文详细介绍如何使用 go 标准库生成 rsa 密钥对,并将私钥以 aes-256 加密的 pem 格式安全导出,全程无需第三方依赖。

本文详细介绍如何使用 go 标准库生成 rsa 密钥对,并将私钥以 aes-256 加密的 pem 格式安全导出,全程无需第三方依赖。

在 Go 中生成带密码保护的 RSA 私钥,本质上是三个逻辑步骤的组合:生成密钥对 → 序列化为 PKCS#1 PEM 结构 → 使用对称加密(如 AES-256)保护 PEM 块。Go 的 crypto 标准库已完整支持这一流程,无需引入外部包。

以下是经过生产环境验证的完整实现:

import (    "crypto/rand"    "crypto/rsa"    "crypto/x509"    "encoding/pem")// PrivateKeyToEncryptedPEM 生成指定长度的 RSA 私钥,并以密码加密后返回 PEM 字节流// bits 推荐值:2048 或 4096;pwd 为空字符串时返回未加密的 PEM(不推荐用于生产)func PrivateKeyToEncryptedPEM(bits int, pwd string) ([]byte, error) {    // 1. 生成 RSA 私钥(含对应公钥)    key, err := rsa.GenerateKey(rand.Reader, bits)    if err != nil {        return nil, fmt.Errorf("failed to generate RSA key: %w", err)    }    // 2. 将私钥编码为 PKCS#1 格式字节(非 DER,而是 ASN.1 序列化后的原始字节)    pkcs1Bytes, err := x509.MarshalPKCS1PrivateKey(key)    if err != nil {        return nil, fmt.Errorf("failed to marshal private key: %w", err)    }    // 3. 构建 PEM Block    block := &pem.Block{        Type:  "RSA PRIVATE KEY",        Bytes: pkcs1Bytes,    }    // 4. 若提供密码,则使用 AES-256 加密 PEM Block    // 注意:x509.EncryptPEMBlock 内部自动处理 salt 和 IV 生成,无需手动管理    if pwd != "" {        block, err = x509.EncryptPEMBlock(            rand.Reader,            block.Type,            block.Bytes,            []byte(pwd),            x509.PEMCipherAES256,        )        if err != nil {            return nil, fmt.Errorf("failed to encrypt PEM block: %w", err)        }    }    // 5. 编码为 PEM 字节流(含头尾标记,如 -----BEGIN RSA PRIVATE KEY-----)    return pem.EncodeToMemory(block), nil}

? 关键说明与注意事项:

  • 密码强度:pwd 应满足基本复杂度要求(建议 ≥12 字符,含大小写字母、数字及符号),但 Go 不校验密码强度,需由调用方保障。
  • 加密算法:x509.PEMCipherAES256 是目前最广泛兼容且安全的选择;避免使用 PEMCipherDES 或 PEMCipher3DES(已过时)。
  • ⚠️ 密钥导出格式:本例使用 PKCS#1("RSA PRIVATE KEY"),适用于传统 OpenSSL 工具链;若需现代 PKCS#8 格式("ENCRYPTED PRIVATE KEY"),应改用 x509.MarshalPKCS8PrivateKey 并配合 x509.EncryptPEMBlock(注意 Type 需同步更新)。
  • ⚠️ 随机源:务必使用 crypto/rand.Reader(真随机),切勿替换为 math/rand(伪随机,导致密钥可预测)。
  • 错误处理:示例中已增强错误包装(fmt.Errorf(... %w)),便于上层追踪根因。

最后,你可以这样调用并保存密钥:

pemData, err := PrivateKeyToEncryptedPEM(2048, "My$tr0ngP@ssw0rd!")if err != nil {    log.Fatal(err)}if err := os.WriteFile("key.pem", pemData, 0600); err != nil {    log.Fatal(err)}

生成的 key.pem 文件将形如:

-----BEGIN RSA PRIVATE KEY-----Proc-Type: 4,ENCRYPTEDDEK-Info: AES-256-CBC,7F3A1B8C......-----END RSA PRIVATE KEY-----

该文件必须配合密码才能解密使用——这也是保障私钥静态安全的核心实践。

相关文章

精彩推荐