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

标签 encryption dsa encoding pkcs#11

我想使用硬件安全模块的 PKCS#11 API 的 PKCS#11 Java 包装器通过 DSA 签署 SHA-256 哈希。为此,我选择了 CKM_DSA 机制,从 token 加载相应的 DSA key 并对数据(以字节数组形式读取)进行签名。我用于测试的 key 长度为 1024 位。

一切似乎都工作正常: key 已加载,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 和另一个软件 key 生成 r 和 s ,它就可以工作。此外,openssl确实接受输入格式,但验证有时会失败并出现错误,有时只是“验证失败”。

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

最佳答案

您可能必须转换 rs值为 BigInteger上课之前。原因是 ASN.1 使用有符号值编码,而 DH 结果为无符号值编码。因此,您很有可能在 ASN.1 中获得负值,这将导致错误。

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

关于encryption - 使用 OpenSSL 验证 PKCS#11 生成的 DSA 签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42587642/

相关文章:

SQL Server 加密数据

java - 尝试创建一个简单的加密程序

java - 将 Java 转换为 python DSA 签名

c++ - Openssl DSA 标志

c# - MVC .net 核心没有正确显示特殊字符

ruby-on-rails - 创建带有重音符号的 Ruby 符号是一种不好的做法吗?

android - 使用 AES 算法加密和解密

java - 使用 RSA 加密(模数/指数): too much data for RSA block

openssl - OpenSSL 字节序列是小端还是大端?

java - 无法解析和显示从 http 请求中读取的非 utf8 字符