其实本来想好好研究下DES、AES、MD5等这些加解密方式的,于是就最先研究了比较早使用的DES,去看了相关文档后发现,我去这变换也太多了吧,这这这,真要细细研究下来,那不得花很长的时间,于是准备先放弃详细研究,先考虑下大致的原理和如何在java中使用就好了。
DES算是发明最早的最广泛使用的分组对称加密算法,其全程是Data Encryption Standard,它需要三个参数来完成加解密的工作,分别是Key、Data以及Mode,其中Key是加密密钥(因为DES是一种对称加密算法,所以解密的密钥也是它了),Data是待加密或解密的数据,Mode则用来指定到底是加密还是解密。
关于Key和Data这里还得说明一点,就是Key是8个字节(64bit)的,而Data是8 * n(n >0)个字节的,当我们使用的Key大于八个字节时在java中会进行处理将其转为8个字节,而当Data不是8个字节时会将其补全再进行加密操作。
1、加密操作
因为DES算法参数本是针对字节的,这里先实现一个字节的加密操作
/**
* DES加密二进制数据
*
* @param data 二进制待加密数据
* @param key 二进制密钥
* @return 二进制加密后的数据
* @throws Exception
*/
public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
//生成一个可信任的随机数据源
SecureRandom secureRandom = new SecureRandom();
//通过原始密钥数据创建DESKeySpec对象
DESKeySpec desKeySpec = new DESKeySpec(key);
//创建一个密钥工厂,通过与我们传入的key值相关的DESKeySpec对象来生成一个SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
//创建一个Cipher对象,将由它来完成实质性的加密操作
Cipher cipher = Cipher.getInstance("DES");
//用密钥和随机数对cipher进行初始化
cipher.init(Cipher.ENCRYPT_MODE, secretKey, secureRandom);
//在这里进行Des加密操作
return cipher.doFinal(data);
}
关于二进制加密方法的实现,代码中已经注释的很清楚了,这里需要说明得是代码中前面都是在做准备加密工作对参数进行有一些初始化的操作,如将传入的key字节,转换为8个字节的secretKey,执行cipher.doFinal操作后 ,最后返回的也是8*n个字节,关于doFinal的实现细节这篇文章就不讨论了(太难了)。
平时使用时都是传递字符串格式的Key以及Data,所以我们这里也来实现一个字符串方式的加密方法
/**
* 重载encrypt方法,使得数据源和密钥可使用字符串
*
* @param data 字符串数据源
* @param key 字符串密钥
* @return 返回字符串类型的
* @throws Exception
*/
public static String encrypt(String data, String key) throws Exception {
byte[] bt = encrypt(data.getBytes(), key.getBytes());
String str = Base64.encodeBase64URLSafeString(bt);
return str;
}
这里代码就简单多了,注意这里不能用String str = new String(bt)的方式来生成加密的字符,因为这样生成字符解密时无法转通过data.getBytes()方法获取能够正确解密的字节,所以这里的Base64是帮助转换byte和String的工具类,方便能够将加密后的byte转为String,方便返回加密后字符串,以及后边要使用的将加密后的String转换为byte方便DES能够正常的解密。这里使用Base64这个工具类,但是有些博客用的是BASE64Encoder这个工具类,但是现在BASE64Encoder这个工具类找不到了,网上推荐使用org.apache.commons.codec.binary.Base64,也就是本博客使用的工具类,使用这个类需要下载一个Apache Commons Codec 的jar包,下载地址为Download Apache Commons Codec
2、解密操作
第一小节介绍了加密操作后,这一小节介绍解密操作就比较简单了,还是线上针对字节的机密方法吧
/**
* DES解密二进制数据
*
* @param data DES机密过的二进制数据
* @param key 用来解密的二进制密钥
* @return 返回解密后的数据
* @throws Exception
*/
public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
//生成一个可信任的随机数据源
SecureRandom secureRandom = new SecureRandom();
//通过原始密钥数据创建DESKeySpec对象
DESKeySpec desKeySpec = new DESKeySpec(key);
//创建一个密钥工厂,通过与我们传入的key值相关的DESKeySpec对象来生成一个SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
//声明一个Cipher对象
Cipher cipher = Cipher.getInstance("DES");
/**到这里为止都还和encrypt加密算法一样**/
//使用密钥和随机数初始化cipher,这里和加密操作的唯一区别是设置的MODE不一样
cipher.init(Cipher.DECRYPT_MODE, secretKey, secureRandom);
//进行解密操作,实际上执行的还是Cipher的doFinal方法
return cipher.doFinal(data);
}
从代码中可以看出,java写DES字节解密方法和字节加密方法,除了倒数第二行代码不一样外,其它的代码居然都是相同的。
然后再来实现针对字符串的机密方法
/**
* 重载decrypt方法,输入加密过的数据源和密钥输出解密后的字符串
* @param data 加密后的字符串数据源
* @param key 用来加密的字符串密钥
* @return 解密后的字符串
* @throws Exception
*/
public static String decrypt(String data, String key) throws Exception {
byte[] buf = Base64.decodeBase64(data);
byte[] bt = decrypt(buf, key.getBytes());
return new String(bt);
}
这里有了加密和机密方法,童鞋们便可自行的封装出去一个DesUtil工具类来。当然DES加密方式其实现在已经基本不用了,现在一般是使用安全等级更高的AES进行对称加密,而这个AES加密就放在后面讲吧。
3、参考文献
想要详细的了解DES加密算法的小伙伴可以去看第三和第四篇参考文献,包你满意。