我有一个Diffie-Hellman安全类,如下所示:
public class AESSecurityCap {
private PublicKey publicKey;
KeyAgreement keyAgreement;
byte[] sharedsecret;
AESSecurityCap() {
makeKeyExchangeParams();
}
private void makeKeyExchangeParams() {
KeyPairGenerator kpg = null;
try {
kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(128);
KeyPair kp = kpg.generateKeyPair();
publicKey = kp.getPublic();
keyAgreement = KeyAgreement.getInstance("ECDH");
keyAgreement.init(kp.getPrivate());
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
}
public void setReceiverPublicKey(PublicKey publickey) {
try {
keyAgreement.doPhase(publickey, false); // <--- Error on this line
sharedsecret = keyAgreement.generateSecret();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
}
}
并实现了该类:
public class Node extends AESSecurityCap {
}
有时我需要重新初始化DH
keyAgreement
:public class TestMainClass {
public static void main(String[] args) {
Node server = new Node();
Node client = new Node();
server.setReceiverPublicKey(client.getPublicKey());
client.setReceiverPublicKey(server.getPublicKey());
// My problem is this line ,
// Second time result exception
server.setReceiverPublicKey(client.getPublicKey());
}
}
但收到此异常:
Exception in thread "main" java.lang.IllegalStateException: Phase already executed
at jdk.crypto.ec/sun.security.ec.ECDHKeyAgreement.engineDoPhase(ECDHKeyAgreement.java:91)
at java.base/javax.crypto.KeyAgreement.doPhase(KeyAgreement.java:579)
at ir.moke.AESSecurityCap.setReceiverPublicKey(AESSecurityCap.java:37)
at ir.moke.TestMainClass.main(TestMainClass.java:13)
有什么办法可以多次重新初始化ECDH KeyAgreement?
这是我的测试用例:
客户端初始化DH并生成公共密钥。
客户端向服务器发送了公钥。
Cerver使用客户端密钥初始化DH,并生成自己的公共密钥并生成共享密钥。
服务器将公钥发送给客户端。
客户端使用服务器公共密钥生成共享密钥。
在此步骤中,客户端和服务器具有公共密钥和共享机密。
我的问题是客户端断开连接()和KeyAgreement由单例对象初始化,而不是第二次重新初始化。
有时我需要做这个主题。
请指导我解决此问题。
最佳答案
IllegalStateException (Phase already executed)
似乎特别是由SunEC提供者的ECDH实现引起的。如果在init
之前立即执行(附加)doPhase
,则不会发生异常。但是,此init
调用不是必需的,因为在执行doPhase
-call generateSecret
之后,至少应将KeyAgreement
-instance重置为init
-call之后的状态。根据generateSecret
-文档:
此方法将这个KeyAgreement对象重置为最近一次调用其中一个init方法之后的状态...
这可能是SunEC提供程序中的错误。如果使用DH而不是ECDH(并且使用SunJCE提供程序而不是SunEC提供程序),则行为符合预期,即可能重复doPhase
-调用(无需其他init
-调用)。使用BouncyCastle提供程序的ECDH同样适用。因此,可以使用BouncyCastle提供程序而不是SunEC提供程序来用代码运行ECDH。
注意:应将lastPhase
中的第二个参数(doPhase
)设置为true,否则将生成IllegalStateException (Only two party agreement supported, lastPhase must be true)
(至少对于ECDH)。
编辑:
该错误是已知的,已在JDK 12中修复,请参见JDK-8205476: KeyAgreement#generateSecret
is not reset for ECDH based algorithmm。