在不安全的信道上传递加密文件,当加密文件被截取时,没有秘钥,无法破解密文,但是如何在不安全的信道上安全的传输秘钥呢?如何传输秘钥才能使秘钥被截取是还能保证密文的安全的?
要解决这个问题,则需要要使用密钥交换算法,秘钥交换算法有两种:对称加密算法以及非对称加密算法
对称加密
对称加密算法:DH算法
DH算法交换密钥的步骤:
- Alice 首选选择一个素数p=5099,底数g=5(任选),随机数a =123,然后计算A=g^a mod p, 结果是215,然后, Alice 发送 p=509,g=5,A=215给Bob;
- Bob 收到后,也选择一个随机数b =456,然后计算B=g^bmodp,结果是181Bob再同时计算K=A A^b mod p,结果是121;
- Bob 把计算的 B=181 发给 Alice Alice计算 K=B^a modp的余数计算结果与Bob 算出的结果一样,者都是121 。
使用java实现DH算法的步骤:
- 首先需要用户类,在用户类中定义用户姓名以及密钥(私钥+公钥+共享密钥)
- 然后定义方法根据DH算法生成一个密钥对(公钥+私钥)
- 其次定义方法按照 "对方的公钥" => 生成"共享密钥"
public class Work3 {
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();
}
}
//用户类
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 (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 按照 "对方的公钥" => 生成"共享密钥"
public void generateSecretKey(byte[] receivedPubKeyBytes) {
try {
//从byte[]恢复PublicKey
X509EncodedKeySpec ketSpec = new X509EncodedKeySpec(receivedPubKeyBytes);
//根据DH算法获取keyFactory
KeyFactory kf = KeyFactory.getInstance("DH");
//通过keyFactory创建公钥
PublicKey receivePublicKey = kf.generatePublic(ketSpec);
//创建秘钥协议对象(用于协商秘钥)
KeyAgreement keyAgreemnet = KeyAgreement.getInstance("DH");
keyAgreemnet.init(this.privateKey);//初始化自己的PravateKey
keyAgreemnet.doPhase(receivePublicKey, true);//根据对方的PublicKey
//生成SecretKey本地密钥(共享秘钥)
this.secretKey = keyAgreemnet.generateSecret();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void printKeys() {
System.out.printf("Name: %s\n", this.name);
System.out.printf("Private key: %x\n", new BigInteger(1, this.privateKey.getEncoded()));
System.out.printf("Public key: %x\n", new BigInteger(1, this.publicKey.getEncoded()));
System.out.printf("Secret key: %x\n", new BigInteger(1, this.secretKey));
}
}
对称加密算法是指加密和解密使用的是相同的密钥,其特点是算法公开,计算量小,加密速度快,加密效率高。缺点是双方都使用同样的密钥,安全性较低,包括AES、DES、IDEA。
具体对称加密算法--> 对称加密算法_猿究院~小曹曹曹曹曹曹曹的博客-CSDN博客
非对称加密
非对称加密算法是指加密和解密使用的是不同的密钥(公钥加密,私钥解密),非对称加密的经典算法为RSA算法。
使用非对称加密算法的步骤(小明给小红发送信息):
- 生成个人密钥对(公钥+私钥)
- 小明使用小红的公钥进行加密(把加密结果发送给小红)
- 小红使用自己的私钥进行解密
//RSA
public class Work4 {
public static void main(String[] args) throws Exception {
// 明文:
byte[] plain = "Hello, encrypt use RSA".getBytes("UTF-8");
// 创建公钥/私钥对
Human hong = new Human("小红");
Human ming = new Human("小明");
// 小明使用小红的公钥进行加密
// 1.获取小红的公钥
PublicKey hongPublicKey = hong.getPublicKey();
System.out.println(String.format("小红的public key(公钥): %x", new BigInteger(1, hongPublicKey.getEncoded())));
// 2.使用公钥加密
byte[] encrypted = ming.encrypt(plain, hongPublicKey);
System.out.println(String.format("encrypted(加密): %x", new BigInteger(1, encrypted)));
// 小红使用自己的私钥解密:
// 1.获取小红的私钥,并输出
PrivateKey hongPrivateKey = hong.getPrivateKey();
System.out.println(String.format("小红的private key(私钥): %x", new BigInteger(1, hongPrivateKey.getEncoded())));
// 2.使用私钥解密
byte[] decrypted = hong.decrypt(encrypted);
System.out.println("decrypted(解密): " + new String(decrypted, "UTF-8"));
}
}
//用户类
class Human {
// 姓名
String name;
// 私钥:
PrivateKey privatekey;
// 公钥:
PublicKey publickey;
// 构造方法
public Human(String name) throws GeneralSecurityException {
// 初始化姓名
this.name = name;
// 生成公钥/私钥对:
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(1024);
KeyPair kp = kpGen.generateKeyPair();
this.privatekey = kp.getPrivate();
this.publickey = kp.getPublic();
}
// 把私钥导出为字节
public PrivateKey getPrivateKey() {
return this.privatekey;
}
// 把公钥导出为字节
public PublicKey getPublicKey() {
return this.publickey;
}
// 用公钥加密
public byte[] encrypt(byte[] message,PublicKey publickey) throws GeneralSecurityException {
// 使用公钥进行初始化
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publickey);//使用公钥进行初始化
return cipher.doFinal(message);
}
// 用私钥解密:
public byte[] decrypt(byte[] input) throws GeneralSecurityException {
// 使用私钥进行初始化
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, this.privatekey);//使用私钥进行初始化
return cipher.doFinal(input);
}
}
非对称加密的缺点:运算速度非常慢,比对称加密慢得多