如何在 Java 中签署和验证 RSA PKCS#1 v2.0 签名
How to sign and validate RSA PKCS#1 v2.0 signatures in Java
我正在尝试使用 PKCS1 v2.0 填充在 RSA+SHA1 中签名和验证签名。
我没有在文档(JDK 或 JCE)中找到我必须使用的 algorithm/padding。
看来我必须使用OAEP填充但我没有成功:
为了验证,我尝试通过密码在 DECRYPT_MODE 中使用签名者发送的 public 密钥:
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)
...
有人可以帮助我吗?
I'm trying to sign and validate signature in RSA+SHA1 with PKCS1 v2.0 padding.
这是一个奇怪的要求。
首先,即使使用 PKCS#1 v1.5 兼容填充,RSA 也是安全的。但是,当使用 SHA-1 对 input/message 进行哈希处理时,它并不安全,原因很简单,出于这种目的,SHA-1 不再被认为是安全的。
其次,尽管 PKCS#1 v2.0 包含一种新的用于签名生成的填充模式,称为 PSS 或 - 更准确地说 - RSASSA-PSS,但它 还 包含单个签名标准 1.5 的生成模式称为 RSASSA-PKCS1-v1_5。所以至少理论上你的要求还不清楚
现在 PKCS#1 v1.5 padding 用于加密 已知可以防止 padding oracle 攻击。仅出于这个原因,PKCS#1 v2.0 中引入的 OAEP 加密已普遍可用。
用于签名生成的PSS 具有更好的安全证明,但PKCS#1 v1.5 仍被认为是安全的。这可能是 Oracle / SUN 没有在 Java SE JCA 中包含 PSS 的原因。如果你想要它,你可以投票给它 here.
I haven't found in the documentation (JDK or JCE) which algorithm/padding I have to use. It seems that I've to use OAEP padding but I didn't succeed.
OAEP 代表最佳非对称加密 填充。用于加密的填充 cannot/should 不用于签名生成。
添加 Bouncy Castle 提供程序后,RSA PSS 变得可用。您可以将您的(不安全)方案与 "SHA1withRSA/PSS"
或完全相同的 "SHA1withRSAandMGF1"
一起使用。一旦 TLS 1.3 规范最终确定,Oracle 的 Java SE 可能会支持 RSA/PSS。
希望我对此做出回应还不算太晚。最近我不得不面对与 RSA 加密相同的问题。我的签名者想要对通过 POST 发送的数据进行验证。这就是我在 Java 中设法解决这个问题的方式。
第 1 步 - 将以下内容添加到您的项目中
bcprov-ext-jdk14-1.45.jar
commons-codec-1.4.jar
第 2 步 - 声明您的密码
private Cipher cipher;
第 3 步 - 在您的 class 构造函数中调用下方
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
this.cipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding");
第 4 步 - 从 public 密钥文本字符串
获取您的公钥
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() 参数。这些是解决问题的方法。干杯
我正在尝试使用 PKCS1 v2.0 填充在 RSA+SHA1 中签名和验证签名。 我没有在文档(JDK 或 JCE)中找到我必须使用的 algorithm/padding。 看来我必须使用OAEP填充但我没有成功:
为了验证,我尝试通过密码在 DECRYPT_MODE 中使用签名者发送的 public 密钥:
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)
...
有人可以帮助我吗?
I'm trying to sign and validate signature in RSA+SHA1 with PKCS1 v2.0 padding.
这是一个奇怪的要求。
首先,即使使用 PKCS#1 v1.5 兼容填充,RSA 也是安全的。但是,当使用 SHA-1 对 input/message 进行哈希处理时,它并不安全,原因很简单,出于这种目的,SHA-1 不再被认为是安全的。
其次,尽管 PKCS#1 v2.0 包含一种新的用于签名生成的填充模式,称为 PSS 或 - 更准确地说 - RSASSA-PSS,但它 还 包含单个签名标准 1.5 的生成模式称为 RSASSA-PKCS1-v1_5。所以至少理论上你的要求还不清楚
现在 PKCS#1 v1.5 padding 用于加密 已知可以防止 padding oracle 攻击。仅出于这个原因,PKCS#1 v2.0 中引入的 OAEP 加密已普遍可用。
用于签名生成的PSS 具有更好的安全证明,但PKCS#1 v1.5 仍被认为是安全的。这可能是 Oracle / SUN 没有在 Java SE JCA 中包含 PSS 的原因。如果你想要它,你可以投票给它 here.
I haven't found in the documentation (JDK or JCE) which algorithm/padding I have to use. It seems that I've to use OAEP padding but I didn't succeed.
OAEP 代表最佳非对称加密 填充。用于加密的填充 cannot/should 不用于签名生成。
添加 Bouncy Castle 提供程序后,RSA PSS 变得可用。您可以将您的(不安全)方案与 "SHA1withRSA/PSS"
或完全相同的 "SHA1withRSAandMGF1"
一起使用。一旦 TLS 1.3 规范最终确定,Oracle 的 Java SE 可能会支持 RSA/PSS。
希望我对此做出回应还不算太晚。最近我不得不面对与 RSA 加密相同的问题。我的签名者想要对通过 POST 发送的数据进行验证。这就是我在 Java 中设法解决这个问题的方式。
第 1 步 - 将以下内容添加到您的项目中
bcprov-ext-jdk14-1.45.jar
commons-codec-1.4.jar
第 2 步 - 声明您的密码
private Cipher cipher;
第 3 步 - 在您的 class 构造函数中调用下方
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
this.cipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding");
第 4 步 - 从 public 密钥文本字符串
获取您的公钥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() 参数。这些是解决问题的方法。干杯