目录
对称式加密算法总结
对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法,在大多数的对称算法中,加密密钥和解密密钥是相同的,所以也称这种加密算法为单密钥算法。
对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。不足之处是,交易双方都使用同样钥匙,那么如果在网络上传输时,被黑客劫取到了密钥,那么就会造成严重的安全性漏洞。所以对称加密算法的安全性得不到保证。
非对称式加密算法概述
非对称式加密: 加密和解密使用不同的密钥。例如,用户A密钥加密后所得到的信息,只能用用户A的解密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此,如果公开了密钥对中的一个密钥,并不会危害到另外一个的秘密性质。
我们将这个公开的密钥称为公钥;不能公开的密钥称为私钥,只有同一对公私钥,才能正常加密和解密。
从DH算法我们可以看到,公钥-私钥组成的密钥对是非常有用的加密方式,因为公钥是可以公开的,而私钥是完全保密的,由此奠定了非对称加密的基础。
非对称加密的典型算法就是RSA算法,它是由Ron Rivest,Adi Shamir,Leonard Adleman这三个人一起发明的,所以用他们三个人的姓氏首字母缩写表示。
非对称加密算法的优缺点
优点: 首先,毋庸置疑,非对称加密算法的加解密过程更加安全,即使公钥被劫获,也不影响私钥的保密性。
缺点: 既然使用不同的密钥进行加解密,那么它的运算速度肯定会大打折扣,相对于对称加密算法来说,它慢得多。
案例实现
现有小明和小红,小明要加密一个明文发给小红,按照非对称加密算法,他首先应该获取小红的公钥,然后用小红的公钥加密,把加密结果发送给小红,此密文只能由小红的私钥才能解开。由于小红的私钥一直在自己手里,没有进行任何传输动作,所以除了小红没有人可以解开这个密文。
下面是Java实现,RSA算法由JAVA标准库提供支持。
首先准备Human类:
- 两个Human实例代表小红和小明,分别有公钥和私钥的成员变量;
- 通过构造方法来生成各自的公私钥对。
- 实现了加密方法encrypt()和解密方法decrypt()。
// 用户类
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);
}
}
测试类:
分别获取小红的公钥和私钥进行加密解密操作。
// RSA
public class Main {
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"));
}
}
RSA的公钥和私钥都可以通过getEncoded()方法获得以byte[]表示的二进制数据,并根据需要保存到文件中。要从byte[]数组恢复公钥或私钥,可以这么写:
- 先根据"RSA"算法创建KeyFactory实例;
- 再将公钥的字节数组包装成 X509EncodedKeySpec 对象;
- 将私钥的字节数组包装成 PKCS8EncodedKeySpec 对象;
- 最后使用KeyFactory实例分别生成PublicKey类型的对象和PrivateKey类型的对象;
这样就完成了从字节数组恢复为公钥私钥对象。
byte[] pkData = ...
byte[] skData = ...
KeyFactory kf = KeyFactory.getInstance("RSA");
// 恢复公钥:
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(pkData);
PublicKey pk = kf.generatePublic(pkSpec);
// 恢复私钥:
PKCS8EncodedKeySpec skSpec = new PKCS8EncodedKeySpec(skData);
PrivateKey sk = kf.generatePrivate(skSpec);
总结
- 和密钥交换算法不同,非对称加密算法只是单向传输,且只传输公钥;
- 以RSA算法为例,它的密钥有256/512/1024/2048/4096等不同的长度。长度越长,密码强度越大,当然计算速度也越慢;
- 非对称加密就是加密和解密使用的不是相同的密钥,只有同一个公钥-私钥对才能正常加解密;
- 将字节数组恢复为公钥私钥对象,需要KeyFactory来生成;