You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Elixir生成GPG兼容的PEM编码密钥并实现加解密签名功能

问题原因

你当前的实现存在两个核心问题,导致导出的公钥无法被GnuPG识别:

  1. 格式不兼容:你导出的是原始RSA公钥的X.509 PEM格式,和GnuPG使用的OpenPGP协议密钥格式完全不属于一套标准。OpenPGP密钥除了基础RSA参数外,还要求包含密钥创建时间、用户身份标识、密钥自签名、用途标记等元数据,缺少这些元数据的裸RSA密钥GPG无法解析。
  2. 公钥提取逻辑错误:你写的public_key_from_private_key函数存在bug,将RSA公钥的指数字段错误赋值为和模数相同的值,你输出的公钥内容前后两段完全重复就是这个问题导致的,生成的公钥本身就是无效的。

遗漏的实现步骤

要生成GnuPG兼容的密钥,你需要补充以下实现逻辑:

1. 先修正公钥提取的基础错误

Erlang的RSAPrivateKey结构体中,第2位是RSA模数n,第3位才是公钥指数e,修正后的代码如下:

defp public_key_from_private_key(private_key) do
  # 正确提取模数和公钥指数
  {:RSAPublicKey, elem(private_key, 2), elem(private_key, 3)}
end

2. 封装为OpenPGP格式

裸RSA密钥必须按OpenPGP标准封装后才能被GPG识别,推荐两种实现方案:

  • 快速实现方案:调用系统GPG命令
    直接通过System.cmd调用本地安装的gpg工具完成密钥生成、导出、加解密操作,不需要自己实现OpenPGP协议逻辑,示例逻辑:

    # 生成GPG密钥的示例
    def generate_gpg_key(user_id, passphrase \\ "") do
      batch_config = """
      %echo Generating GPG key
      Key-Type: RSA
      Key-Length: 2048
      Subkey-Type: RSA
      Subkey-Length: 2048
      Name-Real: #{user_id}
      Expire-Date: 0
      Passphrase: #{passphrase}
      %commit
      %echo done
      """
      System.cmd("gpg", ["--batch", "--gen-key"], input: batch_config)
    end
    
    # 导出GPG兼容的ASCII格式公钥
    def export_gpg_public_key(user_id) do
      {pub_key, 0} = System.cmd("gpg", ["--export", "-a", user_id])
      pub_key
    end
    

    导出的公钥头部为-----BEGIN PGP PUBLIC KEY BLOCK-----,直接保存即可被gpg --show-keys识别。

  • 纯Elixir实现方案:自行封装OpenPGP结构
    如果不想依赖系统GPG工具,需要按OpenPGP v4标准组装以下数据包后再导出为ASCII装甲格式:

    • 公钥数据包:包含密钥版本、创建时间、RSA参数(n、e)
    • 用户ID数据包:包含密钥持有者的姓名、邮箱信息
    • 自签名数据包:用私钥对上述公钥和用户ID信息签名,证明密钥归属
      组装完成后按OpenPGP ASCII装甲格式编码,头部替换为PGP专用的标记即可。

3. 格式区分

如果需要同时支持导出通用RSA PEM和GPG兼容格式,要做明确的功能拆分:

  • 通用RSA PEM用于非GPG场景的加解密,不要给GPG工具使用
  • GPG专用格式仅用于和GnuPG生态交互,不要作为通用RSA密钥使用

内容的提问来源于stack exchange,提问作者fschuindt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 07:48:04