在BouncyCastle中导入PKCS11公钥

问题描述 投票:0回答:1

我正在使用HSM使用PKCS11命令生成一对公钥/私钥椭圆密钥,但我需要在BouncyCastle中使用公钥。

我可以读取DER格式的EC_POINT属性,但我无法弄清楚如何在BouncyCastle中导入它。

这是我的EC_POINT属性:CKA_EC_POINT:04-39-04-ED-48-AE-D9-F8-02-CA-80-E1-1C-F2-3D-C9-C4-7D-B4-C5-9E- D2-53-A6-FE-27-D7-12-EF-C3-7F-2D-FC-D2-D0-31-62-8F-AF-60-19-E4-33-0F-63-A7- E4-95-33-0C-0D-D5-94-6C-92-B9-44-D8-2B

这是我的工作解决方案(感谢戴夫)

public ECPublicKeyParameters GetPubKeyFromParms(string curve, string pub) {
    var pc = ToByteArray(pub);
    var x9ecpar = ECNamedCurveTable.GetByName(curve);
    var ecdp = new ECDomainParameters(x9ecpar.Curve, x9ecpar.G, x9ecpar.N);
    var basePoint = lsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(null, ecdp, pc));
    var subinfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(basePoint);
    var publicKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(subinfo);
    return publicKey;
}

将签名从PKCS11格式转换为BouncyCastle格式:

var r = signature.Take(signature.Length / 2).ToArray();
var s = signature.Skip(signature.Length / 2).ToArray();
var dersignature = new Org.BouncyCastle.Asn1.DerSequence(
                    new Org.BouncyCastle.Asn1.DerInteger(new Org.BouncyCastle.Math.BigInteger(1, r)),
                    new Org.BouncyCastle.Asn1.DerInteger(new Org.BouncyCastle.Math.BigInteger(1, s))
                ).GetDerEncoded();
pkcs#11
1个回答
1
投票

好吧,这确实似乎是一个(DER)OCTET STRING(标签04,长度39十六进制),包含标准(X9.62 / SEC1 et seq)未压缩格式(第一个八位字节04)的一个28字节的点(224-位)曲线。这对我来说似乎很愚蠢,因为我所知道的所有标准ASN.1结构都在BIT STRING中放置了一个(点或其他)pubkey并包含了元数据,但显然这是已知或至少听说过,因为asn1.x9.X9ECPoint有一个构造函数。 (为了简洁和格式化,我省略了适用于所有内容的外包org.bouncycastle。)

要使用点,您需要指定它所在的曲线;我知道由SECG和X9标准化的两条224位曲线(更确切地说,参数集),secp224 {k1,r1},后者(仅)在FIPS 186-2 +中被NIST采用为P-224,两个由TeleTrusT标准化为brainpool224 {r1,t1}。这些可以从asn1.x9.ECNamedCurveTablejce.ECNamedCurveTable内置。可能有任何数量的非标准曲线,您必须自己创建AFAICT。如果你不知道你的未压缩点是什么曲线,你可以通过测试它是否满足候选曲线的方程来有效地完美地猜测;我懒得为你做这件事。 (一个压缩点会更难猜测,也许是不可能的。)

鉴于曲线(来自参数集或直接)将DER转换为ASN1OctetStringASN1OctetString.getInstance(ASN1Primitive.fromByteArray(byte[]))或只是ASN1OctetString.getInstance(Object/*byte[]*/)为你做前者,然后你可以directly construct an X9ECPoint并根据你想要使用它的API,调用.getPoint转换为一个math.ec.ECPoint或构造相关(更复杂)的结构,如crypto.params.ECPublicKeyParameters


添加以回应评论,因为这是相当长的,加上有点改变我的答案:

我没有意识到你在使用dotNET;我的经验是使用Java版本的Bouncy,我印象深刻的是两个版本跟踪你的代码甚至编译得足够紧密。 FWIW修改后的代码的Java等价物,加上从参数显式构建BCECPublicKey,因为JCE Signature只采用Key类型而不是Parameters类型,对我来说有一个测试密钥对和数据。您可以尝试类似的练习 - 在软件中创建密钥对和签名(对于已知数据)并确认您的代码是否适用于该情况,然后尝试隔离硬件签名案例中的差异。虽然PKCS11和其他硬件设备通常设计用于防止设备生成的密钥导出到软件,但是它们可能存在更大的危害风险,但它们在导入时并不总是那么严格 - 您可以使用您的软件 - 生成硬件中的密钥以进行比较。

除了没有验证任何签名的一般原因(错误的数据,错误的哈希 - 你显然默认,错误的密钥)另一种可能性可能是签名格式。 ECDSA(和DSA)签名有两种常用格式(或编码):DER中的INTEGER的ASN.1 SEQUENCE,或者只是固定二进制格式的两个整数,没有任何元数据连接。 “标准”Java(更确切地说,Java与Sun / Oracle提供商)仅使用ASN.1格式;具有Bouncy的Java默认为ASN.1,但如果您将算法名称更改为[hash]WITH{PLAIN,CVC}-ECDSA,则支持ECDSA的固定格式,因此我希望dotNET中的Bouncy(假设您的代码正在使用它,尽管没有明确说明)也可以这样做。我理解(但没有个人经验)PKCS11使用固定格式。如果我以错误的格式提供Java Bouncy,它会抛出异常而不是返回verify = false,但我不知道dotNET在这里是否会有所不同。详细查看您的签名值以检查它的格式。

© www.soinside.com 2019 - 2024. All rights reserved.