我想使用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是错误的。有人可以帮助找到错误吗?
答案 0 :(得分:3)
您可能需要先将r
和s
值转换为BigInteger
类。原因是ASN.1使用有符号值编码,DH导致无符号值编码。因此,您在ASN.1中获得负值的可能性非常高,这将导致错误。
要执行转换,请使用new BigInteger(1, r)
和new BigInteger(1, s)
并将结果放入ASN1Integer
个实例。这里1表示该值需要转换为正值(即输入是无符号正数)。