【问题标题】:Openssl ECDSA sign input as-is - without digestOpenssl ECDSA 符号输入原样 - 没有摘要
【发布时间】:2020-05-13 12:44:05
【问题描述】:

我正在尝试使用openssl 签署现有摘要。

假设我已经有一个摘要“mydigest”。话虽如此,我不想使用:

echo -n "mydigest" | openssl dgst -sha256 -sign key.pem | openssl enc -A -base64

我有 ECDSA 而不是 rsa,所以我认为我不应该使用按原样使用输入的rsautl

所以我的假设是我需要按原样(mydigest)接受输入并使用我的 ECDSA 私钥对其进行签名的东西。

我尝试了以下以查看使用不同哈希算法创建的哈希大小是否对签名结果有任何影响:

echo -n "mydigest" | openssl pkeyutl -sign -inkey key.pem | openssl enc -A -base64

echo -n "my-very-very-very-long-digest" | openssl pkeyutl -sign -inkey key.pem | openssl enc -A -base64

但就输出长度而言,两个命令的输出大小相同。我会假设对于大型 my-very..-long-digest 它应该返回更大的输出(因为它应该按原样获取输入而不缩短(散列)。

=========================================

编辑。

也许下面的示例将有助于理解我的要求。这是 bouncycastle 的一个例子。

 // sign something
String messageToSign = "something_to_sign";
ECDomainParameters domain = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN());
ECDSASigner signer = new ECDSASigner();
signer.init(true, new ECPrivateKeyParameters(privateKey, domain));
MessageDigest digest = MessageDigest.getInstance("Keccak-256");
byte[] hash = digest.digest(messageToSign.getBytes(StandardCharsets.UTF_8));
BigInteger[] signature = signer.generateSignature(hash);

假设我有以下内容:

  1. 散列。
  2. 键。

现在我想用openssl 创建签名,它应该将hashkeys 作为输入而不创建散列。基本上我想替换

BigInteger[] signature = signer.generateSignature(hash);

在带有 openssl 的示例中。

openssl * ????? *

我假设结果的大小应该表明我用于散列的散列(具有不同的摘要大小)算法是否对结果有任何影响。

【问题讨论】:

  • 很难理解你在问什么。您的所有示例,包括 RSA,首先将所有输入(无论多大)散列到固定长度的输出中,然后再将公钥原语应用于它。无论输入是 1 字节还是 1 PB,输出的大小都是相同的。
  • @PresidentJamesK.Polk 感谢您的评论。我在 OP 中添加了一个示例。长话短说,我只想使用 openssl 替换 BigInteger[] signature = signer.generateSignature(hash);使用命令行 openssl。但是,也许这是不可能的:) .... 我还检查了帖子:superuser.com/a/943973。因此,如果我有-pkeyopt digest:$hash,它将不会在 rfc3447 的第 9.2 节中执行 EMSA-PKCS1-v1_5-ENCODE 的第 1 步——这基本上是散列?
  • 我明白了,谢谢你的例子。我想我希望 openssl 命令以相同的格式返回签名。当然,它们不会返回相同的签名,因为 ECDSA 包含一个随机组件。
  • 这是我可以通过 openssl 命令行获得的最接近的结果:echo -n "mydigest" | openssl pkeyutl -inkey ecdsa1-priv.pem -sign -asn1parse

标签: openssl rsa bouncycastle sign ecdsa


【解决方案1】:

openssl pkeyutl -sign -inkey ecprivkey.pem 完全正确。

我假设对于大型 my-very..-long-digest 它应该返回更大的输出(因为它应该按原样获取输入而不缩短(散列)。

你猜错了。 ECDSA 签名在数学上由两个整数 (r,s) 组成,范围为 1 到曲线子组的阶数;它完全不受用作(或用于)输入的哈希大小的影响。 建议使用大小与子组匹配的散列 - 例如SHA256(或您的 Keccak256)与 P-256 aka secp256r1 - 因为否则如果散列太大,它会被截断,或者如果太小,它会被填充,并且会降低安全性。

对于 DSA 也是如此,尤其是对于 RSA - 对于 RSA,签名始终是 RSA 密钥的大小,并且填充了小于 RSA 密钥的编码和填充散列,但是太大了一个被拒绝为错误。 (这是非常罕见的,因为 2048 位以下的 RSA 密钥不再被认为可以安全使用,而且没有人使用这么大的哈希值。)

ECDSA 签名表示(或编码)的大小可能会有所不同,并且有几种不同的标准。 OpenSSL 始终使用rfc3279 2.2.3 中显示的整数的 ASN.1 序列。 Java 中的标准 SunEC 和 BouncyCastle 提供程序默认情况下也是如此。 ASN.1 编码的长度通常仅略微取决于两个整数的值,正如您正确指出的那样,这两个整数的值由随机值 (k) 控制,因此它们本身实际上是伪随机数。请参阅(添加)Java ECDSAwithSHA256 signature with inconsistent length 和(交叉)https://crypto.stackexchange.com/questions/33095/shouldnt-a-signature-using-ecdsa-be-exactly-96-bytes-not-102-or-103https://crypto.stackexchange.com/questions/44988/length-of-ecdsa-signature

Bouncy 提供程序还支持 '{hash}with{PLAIN-,CVC-}ECDSA' 算法,这些算法执行相同的数学签名,但使用 P1363 定义的更简单的表示,只需两个(无符号 bigendian)固定大小的整数(等于到子组订单大小)连接。编辑:自 Java 9 以来的 SunEC 提供程序使用不同的名称“{hash}withECDSAinP1363format”(不知何故我在第一次写作时错过了这个)。 JWS 也使用这种表示。最后,您展示的 Bouncy LWAPI 返回或采用 BigInteger[] - 数学值 - 并将编码和解码留给您。

【讨论】:

  • 谢谢!啊...我没有意识到输出只是(r,s)。感谢您的精彩解释。所以为了验证,我肯定需要 1. 签名,2. 原始数据 3. 公钥。我还需要用于哈希/摘要计算的哈希函数吗?
  • Vlado: 是的,您必须使用相同的哈希来验证 - 以及相同的曲线,尽管 一些 公钥表示(包括 3279 中其他地方的表示)包括曲线规格。但是,鉴于只有十几种常用的哈希值,如果有必要,您可能可以通过反复试验找到正确的哈希值。
猜你喜欢
  • 1970-01-01
  • 2020-07-06
  • 2021-10-08
  • 2016-07-26
  • 1970-01-01
  • 2020-04-25
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多