Go语言中OpenSSL与liboqs-go的Dilithium2密钥尺寸对齐
OpenSSL与liboqs-go Dilithium2密钥尺寸对齐方案
差异原因
- OpenSSL生成的密钥是ASN.1/DER编码的完整密钥结构,包含算法OID、版本信息等元数据,所以总尺寸更大(3870字节);
- liboqs-go直接输出的是Dilithium2算法的原始二进制密钥材料,没有额外封装层,尺寸为标准的2528字节。
两种密钥本质上是同一算法的密钥,只是封装格式不同,只要统一格式就能实现跨库兼容。
方法1:将liboqs-go密钥封装为OpenSSL兼容格式
把liboqs生成的原始密钥套入OpenSSL使用的ASN.1结构中,这样生成的PEM文件就能直接被OpenSSL识别。
Go代码实现
import ( "encoding/asn1" "encoding/pem" "log" "os" ) // Dilithium2的官方OID(OpenSSL识别的标识) var dilithium2OID = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 2, 267, 7, 4, 4} // 定义OpenSSL私钥的ASN.1结构 type privateKeyInfo struct { Version int PrivateKeyAlgorithm []asn1.RawValue PrivateKey []byte } // 将liboqs原始私钥封装为OpenSSL兼容的DER格式 func wrapLiboqsPrivKey(rawPrivKey []byte) ([]byte, error) { // 构造算法标识符 algOIDBytes, err := asn1.Marshal(dilithium2OID) if err != nil { return nil, err } algID := asn1.RawValue{ Tag: asn1.TagSequence, Bytes: algOIDBytes, } pki := privateKeyInfo{ Version: 0, PrivateKeyAlgorithm: []asn1.RawValue{algID}, PrivateKey: rawPrivKey, } return asn1.Marshal(pki) } // 修改原liboqs密钥生成代码 func main() { signer := oqs.Signature{} err := signer.Init("Dilithium2", nil) if err != nil { log.Fatalf("failed to initialize signer: %v", err) } defer signer.Clean() pubKey, rawPrivKey, err := signer.GenerateKeyPair() if err != nil { log.Fatalf("failed to generate key pair: %v", err) } // 封装私钥为OpenSSL兼容格式 opensslPrivKeyDER, err := wrapLiboqsPrivKey(rawPrivKey) if err != nil { log.Fatalf("failed to wrap private key: %v", err) } // 写入PEM文件 privBlock := &pem.Block{ Type: "PRIVATE KEY", Bytes: opensslPrivKeyDER, } err = os.WriteFile("liboqs_openssl_compat_priv.pem", pem.EncodeToMemory(privBlock), 0600) if err != nil { log.Fatalf("failed to write private key file: %v", err) } // 公钥同理,封装为OpenSSL格式 type pkixPublicKey struct { Algorithm asn1.ObjectIdentifier Key []byte } opensslPubKeyDER, err := asn1.Marshal(pkixPublicKey{ Algorithm: dilithium2OID, Key: pubKey, }) if err != nil { log.Fatalf("failed to wrap public key: %v", err) } pubBlock := &pem.Block{ Type: "PUBLIC KEY", Bytes: opensslPubKeyDER, } err = os.WriteFile("liboqs_openssl_compat_pub.pem", pem.EncodeToMemory(pubBlock), 0644) if err != nil { log.Fatalf("failed to write public key file: %v", err) } }
方法2:提取OpenSSL密钥的原始材料
从OpenSSL生成的PEM文件中剥离ASN.1封装,提取出和liboqs-go一致的原始密钥字节。
命令行提取(私钥)
# 提取原始私钥字节到文件 openssl pkey -in dilithium_private.pem -outform der | openssl asn1parse -inform der -offset 16 -out dilithium_raw_priv.key -noout
Go代码中直接读取原始密钥
// 读取原始私钥用于liboqs操作 rawPrivKey, err := os.ReadFile("dilithium_raw_priv.key") if err != nil { log.Fatalf("failed to read raw private key: %v", err) } signer := oqs.Signature{} err = signer.Init("Dilithium2", rawPrivKey) if err != nil { log.Fatalf("failed to initialize signer with raw key: %v", err) } defer signer.Clean() // 后续签名操作和原流程一致
兼容性验证
不管用哪种方法,都要验证跨库签名/验证是否正常:
- OpenSSL签名 → liboqs-go验证
# OpenSSL生成签名 openssl dgst -sign dilithium_private.pem -sha256 -out sig.bin data.txt// liboqs验证签名 signer := oqs.Signature{} _ = signer.Init("Dilithium2", nil) defer signer.Clean() rawPubKey, _ := os.ReadFile("dilithium_raw_pub.key") data, _ := os.ReadFile("data.txt") sig, _ := os.ReadFile("sig.bin") if signer.Verify(data, sig, rawPubKey) { log.Println("跨库验证通过") } else { log.Println("跨库验证失败") } - liboqs-go签名 → OpenSSL验证
用封装后的liboqs密钥生成签名,直接用OpenSSL命令验证即可:openssl dgst -verify liboqs_openssl_compat_pub.pem -sha256 -signature sig.bin data.txt
内容的提问来源于stack exchange,提问作者O21
相关产品推荐
相关产品推荐

