说明: 上篇 RSA 是一种非对称的加解密算法, 今天这种是一种对称的加解密算法 DESDES 算法的入口参数有三个: Key,Data,Mode. 其中 Key 为 7 个字节共 56 位, 是 DES 算法的工作密钥; Data 为 8 个字节 64 位, 是要被加密或被解密的数据; Mode 为 DES 的工作方式, 有两种: 加密或解密. Java 里封装了很多种对称加密算法的使用, 这里以 DES 为例.
一, 什么是对称算法
对称密码算法有时又叫传统密码算法, 就是加密密钥能够从解密密钥中推算出来, 反过来也成立. 加密与解密互逆, 在大多数对称算法中, 加密解密密钥是相同的.
图 1 优点: 效率高 (加 / 解密速度能达到数十兆 / 秒或更多), 算法简单, 系统开销小, 适合加密大量数据. 缺点: 进行安全通信前需要以安全方式进行密钥交换, 安全得不到有效保证, 规模旁杂.
二, 密钥的机制
DES 密钥初始化的长度是 64 位, 而实际可用的位置是 56 位, 因为 DES 算法规定, 第 8,16,......64 位是奇偶校验位, 不参与 DES 运算. 1, 初始序化 Key 的长度
图 2 所以这里最好不要去指定长度了, 默认的就是 56 了. 2, 如果指定的 key 超过 64 位有啥影响
图 3
图 4 通过上面图 3, 图 4 对比可知 (加密后序列一样, 大家可以直接把生成 key 序列 16 进制打出来更直观), 初始的 key 序列超过 8 字节 64 位, 会自动截取掉, 后面多余长度不参与 key 生成. 3, 不同的加密序列加密后结果一样
图 5 参考图 3, 图 5 将字节数组中的 18->19, 发现加密后的序列完全一样. 啥原因呢? 在上面已经提到过, DES 实现中第 8,16,32... 64 位为校验位, 相当于只是用每个字节中的前 7 位进行生成; 将 18,19 转化为二进制为 00010010 ,00010011 然后去掉最后一位, 可以发现前 7 位是一样的. 所以这样解释了为什么有时候加密序列不同, 加密后的内容却是完全一样.
三, 完整的 DEMO
如果让 Base64 具有加解密的功能, 至少要一部分是变化的; 这里可以通过变化标准序列的方式; 建议大家用到的时候, 可以先看一下第 3 部分中标出那个类的源码 (没几行代码); 这个变化的序列可以根据时间, 根据 UUID, 根据一切可以变换的东西来生成, 这里是根据 UUID 来随机生成序列. 1, 生成随机序列
- package c.d.des;
- import java.security.Key;
- import javax.crypto.Cipher;
- import javax.crypto.KeyGenerator;
- import javax.crypto.SecretKeyFactory;
- import javax.crypto.spec.DESKeySpec;
- public class DesTest {
- Cipher cipher = null;
- public DesTest() {
- init();
- }
- public void init() {
- try {
- KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
- keyGenerator.init(56);
- cipher = Cipher.getInstance("DES");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- // 二进制转换字符串
- public static String bytesToHexString(byte[] src) {
- StringBuilder stringBuilder = new StringBuilder("");
- if (src == null || src.length <= 0) {
- return null;
- }
- for (int i = 0; i < src.length; i++) {
- int v = src[i] & 0xFF;
- String hv = Integer.toHexString(v);
- if (hv.length() < 2) {
- stringBuilder.append(0);
- }
- stringBuilder.append(hv);
- }
- return stringBuilder.toString();
- }
- // 获取 Key
- public Key getKey(byte[] passKey) {
- Key convertSecretKey = null;
- try {
- DESKeySpec deSedeKeySpec = new DESKeySpec(passKey);
- SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
- convertSecretKey = factory.generateSecret(deSedeKeySpec);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return convertSecretKey;
- }
- // 加密
- public byte[] encode(byte[] source, Key key) throws Exception {
- cipher.init(Cipher.ENCRYPT_MODE, key);
- byte[] encodeSource = cipher.doFinal(source);
- return encodeSource;
- }
- // 解密
- public String decode(byte[] encodeSource, Key key) throws Exception {
- cipher.init(Cipher.DECRYPT_MODE, key);
- byte[] decodeRes = cipher.doFinal(encodeSource);
- return new String(decodeRes, "UTF-8");
- }
- public static void main(String[] args) throws Exception {
- DesTest dt = new DesTest();
- byte[] passKey = new byte[] {11, 12, 13, 14, 15, 16, 17,18,19,20 };
- System.out.println(passKey.length);
- Key key = dt.getKey(passKey);
- String obj = "就先测试这句吧";
- System.out.println("加密前:" + obj);
- byte[] source = dt.encode(obj.getBytes("UTF-8"), key);
- System.out.println("加密后:" + bytesToHexString(source));
- String res = dt.decode(source, key);
- System.out.println("解密后:" + res);
- String s1 = "0815d22bf5ae0bdd9d37594cedd4be6c1fead86115544517";
- String s2 = "0815d22bf5ae0bdd9d37594cedd4be6c1fead86115544517";
- System.out.println(s1.equals(s2));
- }
- }
四, 后续
既然 DES 通过暴力一天便可破解, 那么 3DES 如何? 大家可以自行研究一下, 和 DES 类似.
持续更新中, 可以关注........
来源: https://juejin.im/post/5c0295b1518825741f628063