我想使用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是错误的。有人可以帮助找到错误吗?
您可能必须将r
和s
值转换为BigInteger
类之前。原因是ASN.1使用签名的值编码,DH会导致无符号值编码。因此,您有很大的机会在ASN.1中获得负值,这将导致错误。
要执行转换,请使用new BigInteger(1, r)
和new BigInteger(1, s)
,然后将结果放入ASN1Integer
实例中。这里1表示该值需要转换为正值(即输入未签名为正)。