【问题标题】:How to sign and validate RSA PKCS#1 v2.0 signatures in Java如何在 Java 中签名和验证 RSA PKCS#1 v2.0 签名
【发布时间】:2017-05-08 06:06:34
【问题描述】:

我正在尝试使用 PKCS1 v2.0 填充在 RSA+SHA1 中签名和验证签名。 我没有在文档(JDK 或 JCE)中找到我必须使用的算法/填充。 看来我必须使用 OAEP 填充但我没有成功:

为了验证,我已经在 DECRYPT_MODE 中使用签名者发送的公钥通过 Cipher 进行了尝试:

Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA1ANDMGF1PADDING", "SunJCE"); 
cipher.init(Cipher.DECRYPT_MODE, pub); //exception !

但我遇到了一个例外:

  java.security.InvalidKeyException: OAEP cannot be used to sign or verify signatures
        at com.sun.crypto.provider.RSACipher.init(RSACipher.java:303)
        at com.sun.crypto.provider.RSACipher.engineInit(RSACipher.java:207)
    ...

(由于未知原因,OAEPWITHSHA1ANDMGF1PADDING 只接受 ENCRYPT_MODE+PUBLIC KEY 或 DECRYPT_MODE+PRIVATE KEY,我想做的相反......)

对于签名,我正在尝试使用 Signature 但我不知道要使用哪种算法:

Signature mySig2 = Signature.getInstance("SHA1withRSAandMGF1");

没用:

java.security.NoSuchAlgorithmException: SHA1withRSAandMGF1 Signature not available
    at java.security.Signature.getInstance(Signature.java:229)
...

有人可以帮帮我吗?

【问题讨论】:

标签: java rsa digital-signature jce


【解决方案1】:

希望我对此做出回应还为时不晚。最近,我不得不面对同样的 RSA 加密问题。我的签名者想要对通过 POST 发送的数据进行验证。这就是我设法在 Java 中处理它的方式。

第 1 步 - 将以下内容添加到您的项目中

bcprov-ext-jdk14-1.45.jar 
commons-codec-1.4.jar

第 2 步 - 声明您的密码

private Cipher cipher;

第 3 步 - 在您的类构造函数中调用以下代码

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
this.cipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding");

第 4 步 - 从公钥文本字符串中获取您的 PublicKey

public PublicKey getPublic(String pubKey) throws Exception {
    byte[] publicBytes = Base64.decodeBase64(pubKey);
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return keyFactory.generatePublic(keySpec);
}

第 5 步 - 验证方法

public boolean verfyRSA(String signature, String data, PublicKey key) throws Exception {

    byte[] sign = Base64.decodeBase64(signature);
    byte[] dat = Base64.decodeBase64(data);

    Signature rsaVerify = Signature.getInstance("SHA1withRSAandMGF1");
    rsaVerify.initVerify(key);
    rsaVerify.update(dat);
    return rsaVerify.verify(sign);
}

第 6 步 - 用法

Yourclass yc = new YourClass();
PublicKey publicKey = yc.getPublic("Your PublicKey without leading and trailing -------text------");
boolean b = yc.verfyRSA("POST_Signature", "POST_data", publicKey);

希望这会有所帮助。注意 getInstance() 参数。这些是成功的。干杯

【讨论】:

  • 如果我的密钥包含诸如“----BEGIN PUBLIC KEY”之类的行,我应该删除它们吗?
  • @kirill-bazarov ;是的。删除前导和尾随 -------text----- 正如我在步骤 6 中提到的那样
【解决方案2】:

我正在尝试使用 PKCS1 v2.0 填充在 RSA+SHA1 中签名和验证签名。

这是一个奇怪的要求。

首先,即使使用 PKCS#1 v1.5 兼容的填充,RSA 也是安全的。然而,当使用 SHA-1 对输入/消息进行哈希处理时,它是不安全的,原因很简单,出于这种目的,SHA-1 不再被认为是安全的。

其次,虽然 PKCS#1 v2.0 包含一个新的签名生成填充模式,称为 PSS 或者 - 更准确地说 - RSASSA-PSS,它包含从 1.5 开始的单一签名生成模式该标准称为 RSASSA-PKCS1-v1_5。所以至少在理论上你的要求并不明确。


现在 PKCS#1 v1.5 填充 用于加密 已知可抵御填充 oracle 攻击。仅出于这个原因,PKCS#1 v2.0 中引入的 OAEP 加密普遍可用。

用于签名生成的 PSS 具有更好的安全证明,但 PKCS#1 v1.5 仍被认为是安全的。这可能是 Oracle / SUN 没有在 Java SE JCA 中包含 PSS 的原因。如果你想要它,你可以投票给它here


我没有在文档(JDK 或 JCE)中找到我必须使用的算法/填充。看来我必须使用OAEP填充但我没有成功。

OAEP 代表最优非对称 加密 填充。加密填充不能/不应用于签名生成。


添加 Bouncy Castle 提供程序后,RSA PSS 变得可用。您可以将(不安全的)方案与"SHA1withRSA/PSS" 或实际上相同的"SHA1withRSAandMGF1" 一起使用。一旦 TLS 1.3 规范最终确定,Oracle 的 Java SE 很可能会支持 RSA/PSS。

【讨论】:

  • 非常感谢您提供的所有精确信息。 PKCS 1 v2 的要求。 0 是由银行申请的编辑给出的。我必须建立一个与这个应用程序通信的服务。交换的文件必须是带有 pkcs 1 v2 的 signef
  • 我不是签名和密码学方面的专家。我认为签名几乎就像做加密:使用私钥加密散列并使用公钥解密散列。但是,如果我很好地理解了您的回答,则某些填充仅用于加密目的,而其他填充仅用于签名。这样对吗?是否可以使用 Cipher 类验证签名? (解密数据并与计算出的哈希值进行比较)
  • 创建especially for this question。请注意,当输入空间有限时,SHA-1 对于签名生成仍然相对安全;我希望是的!不客气:)
  • 我已经在您的链接中阅读了您的问题:非常感谢 :) 现在很清楚了。第一个想法并不总是一个(认为加密和签名几乎是一回事)
  • 一个愚蠢的问题:对签名使用弱散列方法是否“危险”?我的意思是:在签名中,哈希用于检查消息的完整性,但哈希受到私钥加密的“保护”,很难为不同的消息提供相同的哈希。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-22
  • 1970-01-01
  • 2012-01-16
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多