java.security.invalidalgorithmparameterexception on Java 8,但在Java 11上工作
因此,假设您想使用使用BrainPoolp256R1椭圆曲线的ECDSA算法的公钥验证签名。
对于下面的代码,请按照以下步骤:
- 使用以下命令生成Brainpool的按键:
openssl ecparam -name brainpoolP256r1 -genkey -noout -out ec-brainpoolP256r1-priv-key.pem
openssl ec -in ec-brainpoolP256r1-priv-key.pem -pubout > ec-brainpoolP256r1-pub-key.pem
openssl pkcs8 -topk8 -nocrypt -in ec-brainpoolP256r1-priv-key.pem -out ec-brainpoolP256r1-priv-key-pkcs8.pem (to read it with tomitribe PEM utility, we need the PKCS8 format)
- 使用生成的密钥后运行以下代码:
package com.test.ecdsa;
import org.tomitribe.auth.signatures.PEM;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
public class Main {
public static void main(String[] args) throws Exception {
String privateKeyPem = "[use here the content from ec-brainpoolP256r1-priv-key-pkcs8.pem]";
Signature signer = Signature.getInstance("SHA256withECDSA");
PrivateKey privateKey = PEM.readPrivateKey(new ByteArrayInputStream(privateKeyPem.getBytes(StandardCharsets.UTF_8)));
signer.initSign(privateKey);
signer.update("testMessage".getBytes(StandardCharsets.UTF_8));
byte[] signature = signer.sign();
String publicKeyPem = "[use here the content from ec-brainpoolP256r1-pub-key.pem]";
PublicKey publicKey = PEM.readPublicKey(new ByteArrayInputStream(publicKeyPem.getBytes(StandardCharsets.UTF_8)));
Signature signatureVerifier = Signature.getInstance("SHA256withECDSA");
signatureVerifier.initVerify(publicKey);
signatureVerifier.update("testMessage".getBytes(StandardCharsets.UTF_8));
boolean result = signatureVerifier.verify(signature);
System.out.println(result);
}
}
在Java 8上运行此代码将导致:
Exception in thread "main" java.security.SignatureException: Could not sign data
at sun.security.ec.ECDSASignature.signDigestNative(ECDSASignature.java:367)
at sun.security.ec.ECDSASignature.engineSign(ECDSASignature.java:386)
at java.security.Signature$Delegate.engineSign(Signature.java:1382)
at java.security.Signature.sign(Signature.java:698)
at com.ing.obp.jws.lib.Main.main(Main.java:29)
Caused by: java.security.InvalidAlgorithmParameterException
at sun.security.ec.ECDSASignature.signDigest(Native Method)
at sun.security.ec.ECDSASignature.signDigestNative(ECDSASignature.java:364)
... 4 more
使用Java 11,控制台将打印“ True”。
这是为什么?
So let's assume you want to verify a signature using a public key that uses ECDSA algorithm with brainpoolP256r1 elliptic curve.
For running the code below, follows these steps:
- generate a keypair of brainpool using these commands:
openssl ecparam -name brainpoolP256r1 -genkey -noout -out ec-brainpoolP256r1-priv-key.pem
openssl ec -in ec-brainpoolP256r1-priv-key.pem -pubout > ec-brainpoolP256r1-pub-key.pem
openssl pkcs8 -topk8 -nocrypt -in ec-brainpoolP256r1-priv-key.pem -out ec-brainpoolP256r1-priv-key-pkcs8.pem (to read it with tomitribe PEM utility, we need the PKCS8 format)
- Run the following code after using your generated keys:
package com.test.ecdsa;
import org.tomitribe.auth.signatures.PEM;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
public class Main {
public static void main(String[] args) throws Exception {
String privateKeyPem = "[use here the content from ec-brainpoolP256r1-priv-key-pkcs8.pem]";
Signature signer = Signature.getInstance("SHA256withECDSA");
PrivateKey privateKey = PEM.readPrivateKey(new ByteArrayInputStream(privateKeyPem.getBytes(StandardCharsets.UTF_8)));
signer.initSign(privateKey);
signer.update("testMessage".getBytes(StandardCharsets.UTF_8));
byte[] signature = signer.sign();
String publicKeyPem = "[use here the content from ec-brainpoolP256r1-pub-key.pem]";
PublicKey publicKey = PEM.readPublicKey(new ByteArrayInputStream(publicKeyPem.getBytes(StandardCharsets.UTF_8)));
Signature signatureVerifier = Signature.getInstance("SHA256withECDSA");
signatureVerifier.initVerify(publicKey);
signatureVerifier.update("testMessage".getBytes(StandardCharsets.UTF_8));
boolean result = signatureVerifier.verify(signature);
System.out.println(result);
}
}
Running this code on java 8 will lead to:
Exception in thread "main" java.security.SignatureException: Could not sign data
at sun.security.ec.ECDSASignature.signDigestNative(ECDSASignature.java:367)
at sun.security.ec.ECDSASignature.engineSign(ECDSASignature.java:386)
at java.security.Signature$Delegate.engineSign(Signature.java:1382)
at java.security.Signature.sign(Signature.java:698)
at com.ing.obp.jws.lib.Main.main(Main.java:29)
Caused by: java.security.InvalidAlgorithmParameterException
at sun.security.ec.ECDSASignature.signDigest(Native Method)
at sun.security.ec.ECDSASignature.signDigestNative(ECDSASignature.java:364)
... 4 more
Using java 11 the console will print "true".
Why is that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧,Java 11中添加了Brainpool和其他ECC支持(自Java 7以来没有可用,我发现此链接很有趣: https://bugs.openjdk.java.java.net/browse/jdk-7007966 )
如果您想仍然使用Java 8用于阅读密钥,签名,验证签名,那么您将需要BouncycastleProvider。
maven依赖性:
要使用它,您可以将提供商注册到Java的安全层,然后在签名中参考它。使用BouncyCastleProvider.provider_name使用signature.getInstance。
像这样:
Well, Brainpool and other ECC support was added in java 11 (was not available since java 7, I found this link quite interesting: https://bugs.openjdk.java.net/browse/JDK-7007966)
If you want still to use java 8 for reading keys, signing, verifying signatures, then you will need BouncyCastleProvider.
Maven dependency:
To use it, you could register the provider to java's Security layer, and then refer to it in the Signature.getInstance using BouncyCastleProvider.PROVIDER_NAME.
Like this: