密钥加密技术用于加密和解密数据。密钥是与加密算法一起用于加密某些输入(称为明文)的值。输出称为密文。密钥本质上是非常非常大的数。密钥的尺寸用位(bit)来衡量,1024位密钥代表的数是非常巨大的。在公开密钥加密方法中,密钥的尺寸越大,密文就越安全。假定有相同的输入和相同的算法,不同的密钥会生成不同的密文。
有两种大量使用的密钥加密技术:私用密钥(对称加密)和公共密钥(非对称加密)。
对称密钥加密,又称私钥加密,即信息的发送方和接收方用一个密钥去加密和解密数据。它的最大优势是加/解密速度快,适合于对大数据量进行加密,但密钥管理困难。
使用对称加密技术将简化加密的处理,每个参与方都不必彼此研究和交换专用设备的加密算法,而是采用相同的加密算法并只交换共享的专用密钥。如果进行通信的双方能够确保专用密钥在密钥交换阶段未曾泄露,那么机密性和报文完整性就可以通过使用对称加密方法对机密信息进行加密以及通过随报文一起发送报文摘要或报文散列值来实现。
非对称密钥加密,又称公共密钥加密技术(Public Key Cryptography)是基于特地功能的数学算法。使用一个特定的公式来创建数学上相关联的两个密钥(key),但是,两个密钥之间不能推导出对方。一个密钥被用于加密信息,生成密文,另一个密钥用于解密信息,生成明文。然而,原始的密钥不能用于解密密文,因此,这种类型的加密技术被称为非对称的加密技术。公钥机制灵活,但加密和解密速度却比对称密钥加密慢得多。
在非对称加密体系中,密钥被分解为一对。这对密钥中的任何一把都可作为公开密钥(加密密钥)通过非保密方式向他人公开,而另一把则作为私用密钥(解密密钥)加以保存。私用密钥只能由生成密钥对的贸易方掌握,公开密钥可广泛发布。
现在问题来了:如何传递密钥?如何在不安全的信道上安全地传输密钥?
要解决这个问题,就需要使用密钥交换算法:DH算法(Diffie-Hellman算法)。DH算法解决了密钥在双方不直接传递密钥的情况下完成密钥交换,这个神奇的交换原理完全由数学理论支持。
如果我们把a看成甲的私钥,A看成甲的公钥,b看成乙的私钥,B看成乙的公钥,DH算法的本质就是双方各自生成自己的私钥和公钥,私钥仅对自己可见,然后交换公钥,并根据自己的私钥和对方的公钥,生成最终的密钥secretKey,DH算法通过数学定律保证了双方各自计算出的secretKey是相同的。使用Java实现DH算法的代码如下:
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.KeyAgreement;
public class Main {
public static void main(String[] args) {
// Bob和Alice:
Person bob = new Person("Bob");
Person alice = new Person("Alice");
// 各自生成KeyPair: 公钥+私钥
bob.generateKeyPair();
alice.generateKeyPair();
// 双方交换各自的PublicKey(公钥):
// Bob根据Alice的PublicKey生成自己的本地密钥(共享公钥):
bob.generateSecretKey(alice.publicKey.getEncoded());
// Alice根据Bob的PublicKey生成自己的本地密钥(共享公钥):
alice.generateSecretKey(bob.publicKey.getEncoded());
// 检查双方的本地密钥是否相同:
bob.printKeys();
alice.printKeys();
// 双方的SecretKey相同,后续通信将使用SecretKey作为密钥进行AES加解密...
}
}
// 用户类
class Person {
public final String name; // 姓名
// 密钥
public PublicKey publicKey; // 公钥
private PrivateKey privateKey; // 私钥
private byte[] secretKey; // 本地秘钥(共享密钥)
// 构造方法
public Person(String name) {
this.name = name;
}
// 生成本地KeyPair:(公钥+私钥)
public void generateKeyPair() {
try {
// 创建DH算法的“秘钥对”生成器
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DH");
kpGen.initialize(512);
// 生成一个"密钥对"
KeyPair kp = kpGen.generateKeyPair();
this.privateKey = kp.getPrivate(); // 私钥
this.publicKey = kp.getPublic(); // 公钥
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
// 按照 "对方的公钥" => 生成"共享密钥"
public void generateSecretKey(byte[] receivedPubKeyBytes) {
try {
// 从byte[]恢复PublicKey:
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(receivedPubKeyBytes);
// 根据DH算法获取KeyFactory
KeyFactory kf = KeyFactory.getInstance("DH");
// 通过KeyFactory创建公钥
PublicKey receivedPublicKey = kf.generatePublic(keySpec);
// 创建秘钥协议对象(用于秘钥协商)
KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
keyAgreement.init(this.privateKey); // 初始化"自己的PrivateKey"
keyAgreement.doPhase(receivedPublicKey, true); // 根据"对方的PublicKey"
// 生成SecretKey本地密钥(共享公钥)
this.secretKey = keyAgreement.generateSecret();
}