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

时间:2017-03-03 14:39:16

标签: encryption dsa encoding pkcs#11

我想使用PKCS#11 Java Wrapper为DSA签署一个SHA-256哈希,用于硬件安全模块的PKCS#11 API。为此,我选择了机制CKM_DSA,从令牌加载相应的DSA密钥,并将数据(读取为字节数组)签名。我用于测试的密钥长度为1024bit。

一切似乎都运行正常:密钥被加载,Session.sign()产生一个长度为40的byte []数组。这对应于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编码的DER序列。

现在我想对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确实接受输入格式,但验证有时会出错,有时只会出现&#34;验证失败&#34;。

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

1 个答案:

答案 0 :(得分:3)

您可能需要先将rs值转换为BigInteger类。原因是ASN.1使用有符号值编码,DH导致无符号值编码。因此,您在ASN.1中获得负值的可能性非常高,这将导致错误。

要执行转换,请使用new BigInteger(1, r)new BigInteger(1, s)并将结果放入ASN1Integer个实例。这里1表示该值需要转换为正值(即输入是无符号正数)。