Java 加解密技术系列之 DES

  • 背景
  • 概念
  • 基本原理
  • 主要流程
  • 分组模式
  • 代码实现
  • 结束语


几篇文章讲的都是单向加密算法,其中涉及到了 BASE64、MD5、SHA、HMAC
等几个比较常见的加解密算法。这篇文章,以及后面几篇,打算介绍几个对称加密算法,比如:DES、3DES(TripleDES)、AES
等。那么,这篇文章主要是对 DES 大概讲一下。

背景


讨论 DES
之前,首先了解一下什么是对称加密算法吧。对于对称加密算法,他应用的时间比较早,技术相对来说比较成熟,在对称加密算法中,数据发信方将明文(原始数
据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆
算法对密文进行解密,才能使其恢复成可读明文。
在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。对称加密算法的特点是算法公开、计算量小。不足之处是,交易双方都使用同样钥匙,安全性得不到保证。

概念

那么,什么是 DES?他是怎么来的?相信很多人都很感兴趣,因为以前在开发的时候,对进度的要求比较严,很多时候根本就没有时间来了解这些东西。因此,今天专门来研究研究这个东西。
DES,
全称为“Data Encryption Standard”,中文名为“数据加密标准”,是一种使用密钥加密的块算法。DES
算法为密码体制中的对称密码体制,又被称为美国数据加密标准,是 1972 年美国 IBM 公司研制的对称密码体制加密算法。 明文按 64
位进行分组,密钥长 64 位,密钥事实上是 56 位参与 DES 运算(第8、16、24、32、40、48、56、64
位是校验位, 使得每个密钥都有奇数个 1)分组后的明文组和 56 位的密钥按位替代或交换的方法形成密文组的加密方法。

基本原理

入口参数有三个:key、data、mode。key 为加密解密使用的密钥,data 为加密 解密的数据,mode 为其工作模式。当模式为加密模式时,明文按照 64 位进行分组,形成明文组,key 用于对数据加密,当模式为解密模式时,key 用于对数据解密。实际运用中,密钥只用到了
64 位中的 56 位,这样才具有高的安全性。

主要流程

DES 算法把 64 位的明文输入块变为 64 位的密文输出块,它所使用的密钥也是 64 位,其算法主要分为两步:

  • 初始置换
其功能是把输入的 64 位数据块按位重新组合,并把输出分为
L0、R0 两部分,每部分各长 32 位,其置换规则为将输入的第 58 位换到第一位,第 50 位换到第 2 位 ……
依此类推,最后一位是原来的第 7 位。L0、R0 则是换位输出后的两部分,L0 是输出的左 32 位,R0 是右  32
位,例:设置换前的输入值为 D1 D2 D3 …… D64,则经过初始置换后的结果为:L0 = D58 D50 …… D8;R0 = D57
D49 …… D7。
  • 整个算法 的主流程图如下:

分组模式

  • CTR,中文名“计数模式”,是对一系列输入数据块(称为计数)进行加密,产生一系列的输出块,输出块与明文异或得到密文。对于最后的数据块,可能是长 u 位的局部数据块,这 u 位就将用于异或操作,而剩下的 b-u 位将被丢弃(b表示块的长度)。

代码实现

import com.google.common.base.Strings;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder; import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException; /**
* Created by xiang.li on 2015/2/28.
* DES 加解密工具类
*
* <pre>
* 支持 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)
* DES key size must be equal to 56
* DESede(TripleDES) key size must be equal to 112 or 168
* AES key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
* Blowfish key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
* RC2 key size must be between 40 and 1024 bits
* RC4(ARCFOUR) key size must be between 40 and 1024 bits
* 具体内容 需要关注 JDK Document http://.../docs/technotes/guides/security/SunProviders.html
* </pre>
*/
public class DES {
/**
* 定义加密方式
*/
private final static String KEY_DES = "DES";
private final static String KEY_AES = "AES"; // 测试 /**
* 全局数组
*/
private final static String[] hexDigits = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; /**
* 初始化密钥
* @return
*/
public static String init() {
return init(null);
} /**
* 初始化密钥
* @param seed 初始化参数
* @return
*/
public static String init(String seed) {
SecureRandom secure = null;
String str = "";
try {
if (null != secure) {
// 带参数的初始化
secure = new SecureRandom(decryptBase64(seed));
} else {
// 不带参数的初始化
secure = new SecureRandom();
} KeyGenerator generator = KeyGenerator.getInstance(KEY_DES);
generator.init(secure); SecretKey key = generator.generateKey();
str = encryptBase64(key.getEncoded());
} catch (Exception e) {
e.printStackTrace();
}
return str;
} /**
* 转换密钥
* @param key 密钥的字节数组
* @return
*/
private static Key byteToKey(byte[] key) {
SecretKey secretKey = null;
try {
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DES);
secretKey = factory.generateSecret(dks); // 当使用其他对称加密算法时,如AES、Blowfish等算法时,用下述代码替换上述三行代码
// secretKey = new SecretKeySpec(key, KEY_DES);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return secretKey;
} /**
* DES 解密
* @param data 需要解密的字符串
* @param key 密钥
* @return
*/
public static String decryptDES(String data, String key) {
// 验证传入的字符串
if (Strings.isNullOrEmpty(data)) {
return "";
}
// 调用解密方法完成解密
byte[] bytes = decryptDES(hexString2Bytes(data), key);
// 将得到的字节数组变成字符串返回
return new String(bytes);
} /**
* DES 解密
* @param data 需要解密的字节数组
* @param key 密钥
* @return
*/
public static byte[] decryptDES(byte[] data, String key) {
byte[] bytes = null;
try {
Key k = byteToKey(decryptBase64(key));
Cipher cipher = Cipher.getInstance(KEY_DES);
cipher.init(Cipher.DECRYPT_MODE, k);
bytes = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
} /**
* DES 加密
* @param data 需要加密的字符串
* @param key 密钥
* @return
*/
public static String encryptDES(String data, String key) {
// 验证传入的字符串
if (Strings.isNullOrEmpty(data)) {
return "";
}
// 调用加密方法完成加密
byte[] bytes = encryptDES(data.getBytes(), key);
// 将得到的字节数组变成字符串返回
return byteArrayToHexString(bytes);
} /**
* DES 加密
* @param data 需要加密的字节数组
* @param key 密钥
* @return
*/
public static byte[] encryptDES(byte[] data, String key) {
byte[] bytes = null;
try {
Key k = byteToKey(decryptBase64(key));
Cipher cipher = Cipher.getInstance(KEY_DES);
cipher.init(Cipher.ENCRYPT_MODE, k);
bytes = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
} /**
* BASE64 解密
* @param key 需要解密的字符串
* @return 字节数组
* @throws Exception
*/
public static byte[] decryptBase64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
} /**
* BASE64 加密
* @param key 需要加密的字节数组
* @return 字符串
* @throws Exception
*/
public static String encryptBase64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
} /**
* 将一个字节转化成十六进制形式的字符串
* @param b 字节数组
* @return 字符串
*/
private static String byteToHexString(byte b) {
int ret = b;
//System.out.println("ret = " + ret);
if (ret < 0) {
ret += 256;
}
int m = ret / 16;
int n = ret % 16;
return hexDigits[m] + hexDigits[n];
} /**
* 转换字节数组为十六进制字符串
* @param bytes 字节数组
* @return 十六进制字符串
*/
private static String byteArrayToHexString(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
sb.append(byteToHexString(bytes[i]));
}
return sb.toString();
} /**
* 转换十六进制字符串为字节数组
* @param hexstr 十六进制字符串
* @return
*/
public static byte[] hexString2Bytes(String hexstr) {
byte[] b = new byte[hexstr.length() / 2];
int j = 0;
for (int i = 0; i < b.length; i++) {
char c0 = hexstr.charAt(j++);
char c1 = hexstr.charAt(j++);
b[i] = (byte) ((parse(c0) << 4) | parse(c1));
}
return b;
} /**
* 转换字符类型数据为整型数据
* @param c 字符
* @return
*/
private static int parse(char c) {
if (c >= 'a')
return (c - 'a' + 10) & 0x0f;
if (c >= 'A')
return (c - 'A' + 10) & 0x0f;
return (c - '0') & 0x0f;
} /**
* 测试方法
* @param args
*/
public static void main(String[] args) {
String key = DES.init();
System.out.println("DES密钥:\n" + key); String word = "123"; String encWord = encryptDES(word, key); System.out.println(word + "\n加密后:\n" + encWord);
System.out.println(word + "\n解密后:\n" + decryptDES(encWord, key));
}
}

结束语


这里,这篇文章也就差不多要结束了,希望以上的内容对各位看官有稍许的帮助,哪怕一点也好。其实,在日常的开发中,如果不是进度控制的特别严格,对于这些
原理性的东西,我们还是需要知道的,对于那些细节的东西,可以不用死记硬背,有网的话,随用随查就可以了。但这个前提是,原理性的东西必须要懂,知道了原
理,就会有解决思路,有了思路,解决问题是迟早的事,细节嘛,不用那么纠结,做的时候考虑到就行了,毕竟时间是有限的。

5.Java 加解密技术系列之 DES的更多相关文章

  1. Java 加解密技术系列之 DES

    序 前几篇文章讲的都是单向加密算法.当中涉及到了 BASE64.MD5.SHA.HMAC 等几个比較常见的加解密算法. 这篇文章,以及后面几篇.打算介绍几个对称加密算法.比方:DES.3DES(Tri ...

  2. Java 加解密技术系列文章

    Java 加解密技术系列之 总结 Java 加解密技术系列之 DH Java 加解密技术系列之 RSA Java 加解密技术系列之 PBE Java 加解密技术系列之 AES Java 加解密技术系列 ...

  3. 10.Java 加解密技术系列之 DH

    Java 加解密技术系列之 DH 序 概念 原理 代码实现 结果 结束语 序 上一篇文章中简单的介绍了一种非对称加密算法 — — RSA,今天这篇文章,继续介绍另一种非对称加密算法 — — DH.当然 ...

  4. 8.Java 加解密技术系列之 PBE

    Java 加解密技术系列之 PBE 序 概念 原理 代码实现 结束语 序 前 边的几篇文章,已经讲了几个对称加密的算法了,今天这篇文章再介绍最后一种对称加密算法 — — PBE,这种加密算法,对我的认 ...

  5. 7.java 加解密技术系列之 AES

    java 加解密技术系列之 AES 序 概念 原理 应用 代码实现 结束语 序 这篇文章继续介绍对称加密算法,至于今天的主角,不用说,也是个厉害的角色 — — AES.AES 的出现,就是为了来替代原 ...

  6. 6. Java 加解密技术系列之 3DES

    Java 加解密技术系列之 3DES 序 背景 概念 原理 代码实现 结束语 序 上一篇文章讲的是对称加密算法 — — DES,这篇文章打算在 DES 的基础上,继续多讲一点,也就是 3 重 DES ...

  7. 11.Java 加解密技术系列之 总结

    Java 加解密技术系列之 总结 序 背景 分类 常用算法 原理 关于代码 结束语 序 上一篇文章中简单的介绍了第二种非对称加密算法 — — DH,这种算法也经常被叫做密钥交换协议,它主要是针对密钥的 ...

  8. 9.Java 加解密技术系列之 RSA

    Java 加解密技术系列之 RSA 序 概念 工作流程 RSA 代码实现 加解密结果 结束语 序 距 离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版.上线,又是新项 ...

  9. 4.Java 加解密技术系列之 HMAC

    Java 加解密技术系列之 HMAC 序 背景 正文 代码 结束语 序 上一篇文章中简单的介绍了第二种单向加密算法 — —SHA,同时也给出了 SHA-1 的 Java 代码.有这方面需求的童鞋可以去 ...

随机推荐

  1. 脚本语言:Xmas(一)

    很偶然的一个想法,在从北京回成都的高铁上:我想要一个计算器.于是在火车上花了十来个小时,完成了一个模型:能够处理+-*/的优先级,以及"()",比如:1+(3+2)*4.这已是一年 ...

  2. 你说你精通CSS,真的吗?

    以前做项目的时候,学习了HTML和CSS,感觉这两个比较简单,在W3school里学习了一下之后,就觉得自己已经没问题了.可是,真正要做一个好看的页面,我还是要写好久.其实,对于CSS,我并没有像我以 ...

  3. 图文详解linux如何搭建lamp服务环境

    企业网站建设必然离不开服务器运维,一个稳定高效的服务器环境是保证网站正常运行的重要前提.本文小编将会详细讲解Linux系统上如何搭建配置高效的lamp服务环境,并在lamp环境中搭建起企业自己的网站. ...

  4. vue-router2 使用

    VUE-ROUTER2  API http://router.vuejs.org/zh-cn/api/router-link.html   1,安装vue-router npm install vue ...

  5. 读《effective C++》1

    条款一:视C++为一个语言联邦 学习C++半个月了,学了他的面向过程编程,面向对象编程(封装性,继承性,多态性),template泛型编程,开始只是觉得C++基础是面向对象,但是学了这么多块开始有点迷 ...

  6. C语言基础知识点整理(函数/变量/常量/指针/数组/结构体)

    函数 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ...

  7. margin外边距合并问题以及解决方式

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. stm32之USART学习

    首先,我是看着这位博主的文章受到的启发,进而加深了自己对USART的理解.下面是自己改装并实验过的程序. 原文:http://www.cnblogs.com/greatwgb/archive/2011 ...

  9. PMD教程

    1.单词 violations outline:错误大纲2.错误级别 红色 很高的错误 橙色 错误 黄色 很高的警告 绿色 警告 蓝色 输出信息3.提示 Avoid excessively long ...

  10. Sencha+cordova 构造 华丽手机程序,并讲讲,在商用项目中经常用到的cordova插件(一)

    采用 Sencha Architect 3 ,编辑设计,我只想说一个结论,jq能搞的 Sencha touch也能做到(只是 设计思路 更面向对象,学习知识量大点而已 ,不理解 MVC 就不用选了), ...