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

Go语言中Brainpool曲线ECDH实现:elliptic.Unmarshal反序列化失败

解决Brainpool P512r1公钥Unmarshal失败的问题

我帮你排查了下代码,问题出在公钥的解析步骤上——你直接用elliptic.Unmarshal处理PEM解码后的字节是行不通的,原因如下:

  • PEM里的PUBLIC KEY是ASN.1 DER编码的SubjectPublicKeyInfo结构,除了椭圆曲线点(x,y),还包含算法标识、参数等元数据;
  • elliptic.Unmarshal只接受「裸的曲线点字节」(压缩或非压缩格式),所以它无法识别带结构的公钥数据,自然返回nil。

修正后的代码

我们改用crypto/x509包的ParsePKIXPublicKey来解析完整的公钥结构,直接得到ecdsa.PublicKey对象,再进行后续的ECDH计算:

package main

import (
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/sha256"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"log"

	"github.com/keybase/go-crypto/brainpool"
)

func main() {
	fmt.Println("Hello")
	content, err := ioutil.ReadFile("/tmp/TEST.pem")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("File contents: %s", content)

	block, _ := pem.Decode(content)
	if block == nil || block.Type != "PUBLIC KEY" {
		log.Fatal("failed to decode PEM")
	}

	// 关键修改:用x509解析PKIX格式的公钥
	pubKey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		log.Fatalf("failed to parse public key: %v", err)
	}

	// 断言为ecdsa.PublicKey类型
	pubb, ok := pubKey.(*ecdsa.PublicKey)
	if !ok {
		log.Fatal("public key is not ECDSA")
	}

	// 验证曲线是否匹配
	if pubb.Curve != brainpool.P512r1() {
		log.Fatal("public key curve mismatch")
	}

	priva, err := ecdsa.GenerateKey(brainpool.P512r1(), rand.Reader)
	if err != nil {
		log.Fatalf("failed to generate private key: %v", err)
	}

	// ECDH计算:用私钥的D对对方公钥做ScalarMult
	b, _ := pubb.Curve.ScalarMult(pubb.X, pubb.Y, priva.D.Bytes())
	shared1 := sha256.Sum256(b.Bytes())
	fmt.Printf("\nShared key %x\n", shared1)
}

额外说明

  • 解析后一定要做类型断言和曲线匹配检查,避免后续出现意外错误;
  • 生成私钥时别忘了处理错误(你之前忽略了err,这在生产环境中很危险);
  • Keybase的go-crypto分支已经正确实现了Brainpool曲线的相关操作,只要公钥解析正确,后续的ECDH计算就能正常运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:09:43