1.概述:在对称加密算法中,加密和解密使用的都是同一把秘钥,把加密后的密文放在网络上传输是可以的,如果密文泄露了,没有秘钥是得不到原始内容的。但如果秘钥也通过网络传输,一旦秘钥泄露,就可能会通过秘钥对密文进行解密,使得原始内容泄露。为了安全地将秘钥和密文传输到解密方进行解密,可以采用DH秘钥交换算法。
2.DH秘钥交换算法
DH秘钥交换算法并没有将真正的秘钥放在网络中传输,而是双方通过一种协商和数学推导的方式来得到共同的秘钥。
如上图所示, 加密和解密双方都会拥有自己的私钥和公钥,公钥是公开的,私钥是只有自己知道的,Alice将自己的私钥与g,p两个参数进行计算得到自己的公钥,然后将自己的公钥和g,p两个参数通过网络发送给Bob,Bob根据Alice发送的g,p参数与自己的私钥进行相同计算得到他的公钥,再将他的公钥发送给Alice,最后,双方根据各自的私钥与对方发送来的公钥进行相同的数学计算得到共享秘钥(真正进行加密和解密的秘钥)。
例如:Alice的私钥是a=123,取p=509,g=5通过5^123mod 509进行与运算和求余得到公钥A=215,然后Alice将A=215,p=509,g=5发送给Bob,假设Bob的私钥b=456,Bob进行相同的运算5^456 mod 509得到自己的公钥B=181并发送给Alice,Alice根据自己的私钥a与Bob的公钥B进行B^a mod p进行计算得到结果121,Bob根据自己的私钥b与Alice的公钥A进行A^b mod p得到相同的结果121;
从上面的推导过程中看到,在网络传输中并没有传输关于真正秘钥的内容,而是双方将各自的公钥发送给对方,通过类似于协商的方式得到共同的秘钥。
3.实现DH交换算法
Person类:
class Person{
String name;
//存放公钥
PublicKey publicKey;
//存放私钥
PrivateKey privateKey;
//存放生成的共同私钥
byte[] secretKey;
public Person(String name) {
this.name=name;
try {
//根据算法名称获取对应的秘钥对生成器
KeyPairGenerator keyGener=KeyPairGenerator.getInstance("DH");
//生成一对秘钥
KeyPair keyPair=keyGener.generateKeyPair();
this.publicKey=keyPair.getPublic();
this.privateKey=keyPair.getPrivate();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public void generateSecretkey(byte[] revicePublickey) throws GeneralSecurityException {
//恢复对方传过来的公钥字节数组
X509EncodedKeySpec publicSpec=new X509EncodedKeySpec(revicePublickey);
KeyFactory keyFactory=KeyFactory.getInstance("DH");
PublicKey key=keyFactory.generatePublic(publicSpec);
//通过算法名称获取对应的协商对象
KeyAgreement agreement=KeyAgreement.getInstance("DH");
//初始化
agreement.init(privateKey);
//将对方的公钥添加进去
agreement.doPhase(key, true);
//使用协商对象生成共同的秘钥
this.secretKey=agreement.generateSecret();
}
}
在Person类中,分别保存了每个人对应的私钥,公钥和共同的秘钥,在构造方法中通过KeyPairGenerator秘钥对生成器为每个人生成一对秘钥,在类中定义generateSecretkey()方法根据对方发送过来的公钥生成秘钥,主要通过KeyAgreement协商对象的generateSecret方法生成。
public static void main(String[] args) throws GeneralSecurityException {
Person alice=new Person("Alice");
Person bob=new Person("Bob");
//输出Alice的公钥和私钥
System.out.println(alice.name+"的公钥:"+String.format("%x", new BigInteger(1,alice.publicKey.getEncoded())));
System.out.println(alice.name+"的私钥:"+String.format("%x", new BigInteger(1,alice.privateKey.getEncoded())));
//输出Bob的公钥和私钥
System.out.println(bob.name+"的公钥:"+String.format("%x", new BigInteger(1,bob.publicKey.getEncoded())));
System.out.println(bob.name+"的私钥:"+String.format("%x", new BigInteger(1,bob.privateKey.getEncoded())));
//Alice根据Bob的公钥计算共同的秘钥
alice.generateSecretkey(bob.publicKey.getEncoded());
//Bob根据Alice的公钥计算共同的秘钥
bob.generateSecretkey(alice.publicKey.getEncoded());
//输出各自计算的秘钥
System.out.println("alice生成的秘钥:"+Arrays.toString(alice.secretKey));
System.out.println("bob生成的秘钥:"+Arrays.toString(bob.secretKey));
}
在主函数中,我们创建出两个Person对象,分别代表上面例子中的Alice和Bob,双方各自根据对方发送过来的公钥来计算共同的秘钥。
运行结果:
从运行结果中看到,虽然Alice和Bob的私钥,公钥都不相同,但通过协商计算出了相同的秘钥,在后来的加密算法中,Alice和Bob就可以使用计算出的秘钥进行相应的加密和解密操作了。DH算法就是一种秘钥交换算法,双方在不安全的环境中协商出一个秘钥,防止秘钥在传输过程泄露。