【发布时间】:2017-07-24 01:56:22
【问题描述】:
我想使用 PKCS#11 Java Wrapper 为硬件安全模块的 PKCS#11 API 与 DSA 签署 SHA-256 哈希。为此,我选择了机制 CKM_DSA,从令牌中加载相应的 DSA 密钥并对数据(读取为字节数组)进行签名。我用于测试的密钥长度为 1024 位。
一切似乎都正常:密钥已加载,Session.sign() 产生一个长度为 40 的 byte[] 数组。这对应于 PKCS#11 规范,其中说:
"就该机制而言,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 确实接受输入格式,但验证有时会失败并出现错误,有时只是“验证失败”。
因此,我假设将 PKCS#11 签名转换为 r 和 s 是错误的。有人可以帮忙找出错误吗?
【问题讨论】:
-
删除了 cmets,包括我要求提供完整堆栈跟踪的那个。请提供完整的堆栈跟踪,最好提供一些测试数据和密钥。
-
第二个数组副本不应该从 pos 20 而不是 19 开始吗?好像你有两次 r 的最后一个字节,并且永远不会得到 s 的最后一个字节。
标签: encryption dsa encoding pkcs#11