在BouncyCastle中导入PKCS11公钥

时间:2019-03-12 13:38:43

标签: pkcs#11

我正在使用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

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

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();

1 个答案:

答案 0 :(得分:1)

好的,这确实似乎是(DER)OCTET STRING(标签04,长度为39十六进制),其中包含标准的(X9.62 / SEC1 et seq)未压缩格式的点(第一个八位位组04) (224位)曲线。这对我来说似乎很愚蠢,因为我知道所有标准ASN.1结构都将(点或其他)发布密钥放在BIT STRING中并包含元数据,但显然这是已知的,或者至少听说过,因为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。如果您不知道未压缩点位于哪条曲线上,则可以通过测试该曲线是否满足候选曲线的方程式来进行有效的精确猜测。我懒得为你做这件事。 (一个压缩点将很难猜测,也许是不可能的。)

给出曲线(从参数集或直接获得),使用ASN1OctetString或仅使用ASN1OctetString.getInstance(ASN1Primitive.fromByteArray(byte[]))将DER转换为ASN1OctetString.getInstance(Object/*byte[]*/),然后您可以{{3} },并取决于要使用的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(更确切地说是带有Sun / Oracle提供程序的Java)仅使用ASN.1格式;带有Bouncy的Java默认为ASN.1,但是如果将算法名称更改为[hash]WITH{PLAIN,CVC}-ECDSA,则支持ECDSA的固定格式,因此我希望在dotNET中使用Bouncy(假设您的代码正在使用它,尽管未明确说明)相同。我了解(但没有个人经验)PKCS11使用固定格式。如果我以错误的格式输入Java Bouncy,它将引发异常,而不是返回verify = false,但是我不知道dotNET是否在此处可能有所不同。详细查看您的签名值以检查它是哪种格式。