DES 算法简介
DES
加密算法属于对称密码范畴,那么什么是对称密码呢?加密和解密过程中所使用的密钥相同,就是对称密码,而且大多数对称密码算法,加密解密过程都是互逆的。DES 算法是一种数据加密算法,明文按照 64 位进行分组,分组后的明文与密钥按位替代或交换的方法形成密文组。 密钥的长度是 64 位(其实是56位,其中有8位是奇偶校验位)。
DES 工作模式简介
1 . ECB(电子密码密码本模式)
这是最原始的一种加密工作模式,将明文分组成64位,与密钥长度相同,然后按照加密算法加密,得到 64位密文,最后将所有加密后的密文连接在一起即可,各段之间互不影响(当最后一段不足64位是要补足64位在进行计算)
可见,这种模式的优点是实现起来简单,有利于并行运算,但是缺点是安全性比较低。
2 . CBC (密文链接模式)
这种模式相比于 ECB 就比较复杂了,让我们来看看它是如何加密的
1. 首先将数据按照8个字节一组进行分组得到D1D2......Dn(若数据不是8的整数倍,用指定的PADDING数据补位)
2. 第一组数据D1与初始化向量I异或后的结果进行DES加密得到第一组密文C1(初始化向量I为全零)
3. 第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2
4. 之后的数据以此类推,得到Cn
5. 按顺序连为C1C2C3......Cn即为加密结果。
这种加密模式相比于上一中比较安全一些,但是有一个致命的缺点,就是误差延续性,就是说只要有一个地方的密文出现错误,那么底下的密文就都会出现错误,为什么会这样?仔细看看加密过程就能明白,这也就是为什么这种模式叫做链接模式。
当然还有其他的模式,就不一一介绍了,一般还是利用以上两种模式。
DES 填充模式
NoPadding
API或算法本身不对数据进行处理,加密数据由加密双方约定填补算法。例如若对字符串数据进行加解密,可以补充\0或者空格,然后trim。
PKCS5Padding
加密前:数据字节长度对8取余,余数为m,若m>0,则补足8-m个字节,字节数值为8-m,即差几个字节就补几个字节,字节数值即为补充的字节数,若为0则补充8个字节的8
填充模式就用于当明文不是64的倍数的时候,由于在加密的过程中需要对明文进行分块,所以需要选择填充模式。
DES 的使用
1 . 和 Hmac 算法一样,想要使用 DES,首先要获取密钥,这需要借助于 JDK
自带的 KeyGenerator
public static byte[] initKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
keyGenerator.init(56); // 56 可填可不填
SecretKey secretKey = keyGenerator.generateKey();
return secretKey.getEncoded();
}
2 . 接下来就是 DES 加密过程
public static byte[] encryptDES(byte[] key, byte[] data) throws Exception {
SecretKey secretKey = new SecretKeySpec(key, "DES");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] resultBytes = cipher.doFinal(data);
return resultBytes;
}
传进去一个 helloworld
看看结果
public static void main(String[] args) throws Exception {
String data = "helloworld";
byte[] key = initKey();
byte[] resultBytes = encryptDES(key, data.getBytes());
String resultString = byteToHexString(resultBytes);
System.out.println(resultString);
}
结果为
215f9748bf31d5dc3d4eb5b77107643b
既然 DES 是用于数据加密,那么我们总应该能把数据还原成明文把,不然其意义何在呢?其实解密过程和加密过程几乎一模一样,如下所示
public static String decryptDES(byte[] key, byte[] data) throws Exception {
SecretKey secretKey = new SecretKeySpec(key, "DES");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] resultBytes = cipher.doFinal(data);
return new String(resultBytes);
}
这个时候传进来的 key 必须和加密时使用的 key 是相同的,而且这个时候传进来的 data 也必须是加密过后的密文。
咦,这个时候我们发现,我们开头介绍的加密模式和填充模式好像都没用到,其实我们一般是使用默认就可以了,如果有特殊需要,可以这样使用
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
DES加密过后的数据在以前是不可能被破解的,但是由于计算机的发展,DES 加密过得数据在如今完全可在24小时内被破解,所以在 DES 的基础上有延伸出了 3DES 和 AES,这两种算法将留到以后再介绍~