- 我用golang PKCS11 库分支 v3生成了一个 ed25519 密钥对(它连接到 SoftHSM2):
publicKeyTemplate := []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false),
pkcs11.NewAttribute(pkcs11.CKA_LABEL, "go_ed_3"),
pkcs11.NewAttribute(pkcs11.CKA_TRUSTED, false),
pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC_EDWARDS),
pkcs11.NewAttribute(pkcs11.CKA_ID, 1234),
pkcs11.NewAttribute(pkcs11.CKA_ENCRYPT, false),
pkcs11.NewAttribute(pkcs11.CKA_WRAP, false),
pkcs11.NewAttribute(pkcs11.CKA_VERIFY, false),
pkcs11.NewAttribute(pkcs11.CKA_VERIFY_RECOVER, false),
pkcs11.NewAttribute(pkcs11.CKA_DERIVE, false),
pkcs11.NewAttribute(pkcs11.CKA_MODIFIABLE, true),
pkcs11.NewAttribute(pkcs11.CKA_COPYABLE, true),
pkcs11.NewAttribute(pkcs11.CKA_DESTROYABLE, true),
pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, []byte{0x13, 0x0c, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64, 0x73, 0x32, 0x35, 0x35, 0x31, 0x39}),
}
// Set private key template
privateKeyTemplate := []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY),
pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true),
pkcs11.NewAttribute(pkcs11.CKA_LABEL, "go_ed_3"),
pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC_EDWARDS),
pkcs11.NewAttribute(pkcs11.CKA_ID, 1234),
}
mechanism := []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_EC_EDWARDS_KEY_PAIR_GEN, nil)}
pub, pri, err := p.GenerateKeyPair(session, mechanism, publicKeyTemplate, privateKeyTemplate)
if err != nil {
fmt.Println("Key generation failed:", err)
return
}
spew.Dump(pub)
spew.Dump(pri)
- 使用pkcs11-tools我检查了密钥对是否成功生成并且公钥如下:
p11cat pubk/go_ed_2
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA9JJpbH0+hBryC0zcSdeFwa57up4l4/umPTcZzowSI4Q=
-----END PUBLIC KEY-----
- 所以现在我想用我的代码导出公钥。我找到了公钥对象:
ktemplate := []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
pkcs11.NewAttribute(pkcs11.CKA_ID, 1234),
pkcs11.NewAttribute(pkcs11.CKA_LABEL, "go_ed_2"),
}
if err := p.FindObjectsInit(session, ktemplate); err != nil {
panic(err)
}
objs, _, err := p.FindObjects(session, 1)
if err != nil {
panic(err)
}
if err = p.FindObjectsFinal(session); err != nil {
panic(err)
}
fmt.Println("Objects found:", objs[0])
attr, err := p.GetAttributeValue(session, objs[0], []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, nil),
pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil),
})
if err != nil {
panic(err)
}
fmt.Println("attr:", attr[0].Value)
主要问题是如何从中导出正确的 ed25519 公钥?
我做了很多研究,但我还没有找到答案。我知道 RSA 公钥导出工作如下:
pr, err := p.GetAttributeValue(session, pbk, []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_MODULUS, nil),
pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, nil),
})
if err != nil {
panic(err)
}
modulus := new(big.Int)
modulus.SetBytes(pr[0].Value)
bigExponent := new(big.Int)
bigExponent.SetBytes(pr[1].Value)
exponent := int(bigExponent.Uint64())
rsaPub := &rsa.PublicKey{
N: modulus,
E: exponent,
}
pubkeyPem := string(pem.EncodeToMemory(&pem.Block{Type: "RSA PUBLIC KEY", Bytes: x509.MarshalPKCS1PublicKey(rsaPub)}))
log.Printf(" Public Key: \n%s\n", pubkeyPem)
对于椭圆键,应该使用类似的东西exportECDSAPublicKey,但 ed25519 并非如此
func exportECDSAPublicKey(session *pkcs11Session, pubHandle pkcs11.ObjectHandle) (crypto.PublicKey, error) {
var err error
var attributes []*pkcs11.Attribute
var pub ecdsa.PublicKey
template := []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_ECDSA_PARAMS, nil),
pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil),
}
if attributes, err = session.ctx.GetAttributeValue(session.handle, pubHandle, template); err != nil {
return nil, err
}
if pub.Curve, err = unmarshalEcParams(attributes[0].Value); err != nil {
return nil, err
}
if pub.X, pub.Y, err = unmarshalEcPoint(attributes[1].Value, pub.Curve); err != nil {
return nil, err
}
return &pub, nil
}