验证PKCS#11使用OpenSSL生成的DSA签名



我想使用pkcs#11 Java包装器使用DSA签署SHA-256 HASH,用于硬件安全模块的PKCS#11 API。为此,我选择了机制CKM_DSA,请从令牌上加载相应的DSA键,并具有签名的数据(读取为字节阵列)。我用于测试的密钥具有1024位长度。

一切似乎都很好:键已加载,session.sign()得出一个长度的字节[]阵列40。这对应于PKCS#11 Spec,它说:

" 出于这种机制的目的,DSA签名是40字节字符串,对应于DSA值r和s的串联,每个都代表最重要的字节。"

现在我想使用openssl验证此签名,即使用

openssl dgst -d -sha256 -verify ${PUBLIC_KEY} -signature signature.der <raw input file>

如果我

,这有效

a)使用openssl

创建签名

b)使用Bouncycastle创建了签名,并将结果编码为ASN1编码序列。

现在,我想对PKCS#11签名做同样的事情。我的问题是:如何格式化这个40个字节阵列?我尝试了以下内容:

        //sign data
        byte[] signedData = this.pkcs11Session.sign(dataToSign);
        //convert result
        byte[] r = new byte[20];
        byte[] s = new byte[20];
        System.arraycopy(signedData, 0, r, 0, 20);
        System.arraycopy(signedData, 19, s, 0, 20);
        //encode result
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(new ASN1Integer(r));
        v.add(new ASN1Integer(s));
        return new DERSequence(v).getEncoded(ASN1Encoding.DER);

编码零件似乎是正确的,因为如果我直接与Bouncycastle和另一个软件密钥生产R和S,则可以使用。此外,OpenSSL确实接受输入格式,但是验证有时会出错,有时只是"验证失败"。

因此,我假设PKCS#11签名转换为R和S是错误的。有人可以帮助找到错误吗?

您可能必须将rs值转换为BigInteger类之前。原因是ASN.1使用签名的值编码,DH会导致无符号值编码。因此,您有很大的机会在ASN.1中获得负值,这将导致错误。

要执行转换,请使用new BigInteger(1, r)new BigInteger(1, s),然后将结果放入ASN1Integer实例中。这里1表示该值需要转换为正值(即输入未签名为正)。

最新更新