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

如何在Go中验证GPG公钥、私钥字符串的有效性

Go 实现GPG密钥有效性验证的方案

不需要自行拆解密钥结构,使用目前社区维护的OpenPGP兼容库即可实现。官方原x/crypto/openpgp库停止维护后,ProtonMail维护的fork分支是目前兼容性最好、支持最新GPG密钥格式的实现。

前置依赖

执行以下命令安装依赖:
go get github.com/ProtonMail/go-crypto

核心验证逻辑

你需要完成三类常见验证,可根据实际需求选择:

1. 公钥有效性验证

验证逻辑:

  • 解析ASCII装甲格式的公钥字符串
  • 校验公钥的自签名合法性,确认密钥未被篡改
  • 校验公钥是否在有效期内(若设置了过期时间)

2. 私钥有效性验证

验证逻辑:

  • 解析ASCII装甲格式的私钥字符串
  • 若私钥设置了 passphrase 加密,先完成私钥解密
  • 校验私钥结构完整性,验证私钥对应的公钥自签名合法性

3. 公钥与私钥配对验证

验证逻辑:

  • 生成随机测试串用私钥完成签名
  • 用公钥验证签名合法性,校验通过即证明二者配对

示例代码

package main

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"github.com/ProtonMail/go-crypto/openpgp"
	"github.com/ProtonMail/go-crypto/openpgp/armor"
	"io"
)

// 验证公钥有效性
func ValidatePublicKey(pubKeyStr string) (*openpgp.Entity, error) {
	block, err := armor.Decode(bytes.NewBufferString(pubKeyStr))
	if err != nil {
		return nil, fmt.Errorf("公钥装甲解码失败: %w", err)
	}
	entities, err := openpgp.ReadKeyRing(block.Body)
	if err != nil {
		return nil, fmt.Errorf("公钥解析失败: %w", err)
	}
	if len(entities) == 0 {
		return nil, fmt.Errorf("未找到有效公钥实体")
	}
	pubEntity := entities[0]
	// 校验自签名
	if err = pubEntity.PrimaryKey.VerifySelfSignature(); err != nil {
		return nil, fmt.Errorf("公钥自签名校验失败: %w", err)
	}
	// 校验有效期
	if pubEntity.PrimaryKey.KeyExpired(pubEntity.PrimaryIdentity().SelfSignature) {
		return nil, fmt.Errorf("公钥已过期")
	}
	return pubEntity, nil
}

// 验证私钥有效性
func ValidatePrivateKey(privKeyStr string, passphrase []byte) (*openpgp.Entity, error) {
	block, err := armor.Decode(bytes.NewBufferString(privKeyStr))
	if err != nil {
		return nil, fmt.Errorf("私钥装甲解码失败: %w", err)
	}
	entities, err := openpgp.ReadKeyRing(block.Body)
	if err != nil {
		return nil, fmt.Errorf("私钥解析失败: %w", err)
	}
	if len(entities) == 0 {
		return nil, fmt.Errorf("未找到有效私钥实体")
	}
	privEntity := entities[0]
	// 解密私钥(未加密可跳过)
	if privEntity.PrivateKey.Encrypted {
		if err = privEntity.PrivateKey.Decrypt(passphrase); err != nil {
			return nil, fmt.Errorf("私钥解密失败: %w", err)
		}
	}
	// 校验私钥完整性
	if err = privEntity.PrivateKey.Validate(); err != nil {
		return nil, fmt.Errorf("私钥结构校验失败: %w", err)
	}
	// 校验自签名
	if err = privEntity.PrimaryKey.VerifySelfSignature(); err != nil {
		return nil, fmt.Errorf("私钥对应公钥自签名校验失败: %w", err)
	}
	return privEntity, nil
}

// 验证公私钥是否配对
func CheckKeyPairMatch(pubEntity *openpgp.Entity, privEntity *openpgp.Entity) error {
	// 生成随机测试数据
	testData := make([]byte, 32)
	if _, err := rand.Read(testData); err != nil {
		return fmt.Errorf("生成测试数据失败: %w", err)
	}
	// 私钥签名
	var sigBuf bytes.Buffer
	if err := openpgp.DetachSign(&sigBuf, privEntity, bytes.NewReader(testData), nil); err != nil {
		return fmt.Errorf("私钥签名失败: %w", err)
	}
	// 公钥验签
	_, err := openpgp.CheckDetachedSignature(openpgp.EntityList{pubEntity}, bytes.NewReader(testData), &sigBuf, nil)
	if err != nil {
		return fmt.Errorf("签名校验失败,公私钥不配对: %w", err)
	}
	return nil
}

注意事项

  • 若你的密钥包含子密钥,需要额外遍历Entity.Subkeys字段,逐一校验子密钥的签名有效性和有效期
  • 若不需要验证配对关系,单独校验公钥或私钥可跳过配对校验步骤

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 03:15:06