5.Java 加解密技术系列之 DES
Java 加解密技术系列之 DES
- 序
- 背景
- 概念
- 基本原理
- 主要流程
- 分组模式
- 代码实现
- 结束语
序
几篇文章讲的都是单向加密算法,其中涉及到了 BASE64、MD5、SHA、HMAC
等几个比较常见的加解密算法。这篇文章,以及后面几篇,打算介绍几个对称加密算法,比如:DES、3DES(TripleDES)、AES
等。那么,这篇文章主要是对 DES 大概讲一下。
背景
讨论 DES
之前,首先了解一下什么是对称加密算法吧。对于对称加密算法,他应用的时间比较早,技术相对来说比较成熟,在对称加密算法中,数据发信方将明文(原始数
据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆
算法对密文进行解密,才能使其恢复成可读明文。
概念
全称为“Data Encryption Standard”,中文名为“数据加密标准”,是一种使用密钥加密的块算法。DES
算法为密码体制中的对称密码体制,又被称为美国数据加密标准,是 1972 年美国 IBM 公司研制的对称密码体制加密算法。 明文按 64
位进行分组,密钥长 64 位,密钥事实上是 56 位参与 DES 运算(第8、16、24、32、40、48、56、64
位是校验位, 使得每个密钥都有奇数个 1)分组后的明文组和 56 位的密钥按位替代或交换的方法形成密文组的加密方法。
基本原理
64 位中的 56 位,这样才具有高的安全性。
主要流程
- 初始置换
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的更多相关文章
- Java 加解密技术系列之 DES
序 前几篇文章讲的都是单向加密算法.当中涉及到了 BASE64.MD5.SHA.HMAC 等几个比較常见的加解密算法. 这篇文章,以及后面几篇.打算介绍几个对称加密算法.比方:DES.3DES(Tri ...
- Java 加解密技术系列文章
Java 加解密技术系列之 总结 Java 加解密技术系列之 DH Java 加解密技术系列之 RSA Java 加解密技术系列之 PBE Java 加解密技术系列之 AES Java 加解密技术系列 ...
- 10.Java 加解密技术系列之 DH
Java 加解密技术系列之 DH 序 概念 原理 代码实现 结果 结束语 序 上一篇文章中简单的介绍了一种非对称加密算法 — — RSA,今天这篇文章,继续介绍另一种非对称加密算法 — — DH.当然 ...
- 8.Java 加解密技术系列之 PBE
Java 加解密技术系列之 PBE 序 概念 原理 代码实现 结束语 序 前 边的几篇文章,已经讲了几个对称加密的算法了,今天这篇文章再介绍最后一种对称加密算法 — — PBE,这种加密算法,对我的认 ...
- 7.java 加解密技术系列之 AES
java 加解密技术系列之 AES 序 概念 原理 应用 代码实现 结束语 序 这篇文章继续介绍对称加密算法,至于今天的主角,不用说,也是个厉害的角色 — — AES.AES 的出现,就是为了来替代原 ...
- 6. Java 加解密技术系列之 3DES
Java 加解密技术系列之 3DES 序 背景 概念 原理 代码实现 结束语 序 上一篇文章讲的是对称加密算法 — — DES,这篇文章打算在 DES 的基础上,继续多讲一点,也就是 3 重 DES ...
- 11.Java 加解密技术系列之 总结
Java 加解密技术系列之 总结 序 背景 分类 常用算法 原理 关于代码 结束语 序 上一篇文章中简单的介绍了第二种非对称加密算法 — — DH,这种算法也经常被叫做密钥交换协议,它主要是针对密钥的 ...
- 9.Java 加解密技术系列之 RSA
Java 加解密技术系列之 RSA 序 概念 工作流程 RSA 代码实现 加解密结果 结束语 序 距 离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版.上线,又是新项 ...
- 4.Java 加解密技术系列之 HMAC
Java 加解密技术系列之 HMAC 序 背景 正文 代码 结束语 序 上一篇文章中简单的介绍了第二种单向加密算法 — —SHA,同时也给出了 SHA-1 的 Java 代码.有这方面需求的童鞋可以去 ...
随机推荐
- .Net 分布式技术比较
内容转自于 http://www.mamicode.com/info-detail-585547.html .NET 分布式技术比较 1. MSMQ(Microsoft Message Queue) ...
- zoom动画,实现图片点击预览效果
参考:https://developer.android.google.cn/training/animation/zoom.html 1.创建Views 下面的布局包括了你想要zoom的大版本和小版 ...
- EasyUi基础学习(一)—基本组件(上)
一.概述 jQuery EasyUI是一组基于jQuery的UI插件集合体,而jQuery EasyUI的目标就是帮助web开发者更轻松的打造出功能丰富并且美观的UI界面.开发者不需要编写复 ...
- 在jsp中用一数组存储了数据库表中某一字段的值,然后在页面中输出其中的值。
List<String> list = new ArrayList<String>(); String sql = "select userName from us ...
- SVG格式转Visio的vsd格式方法,附带C#动态调用Office的Com组件方法
SVG格式可以直接显示在网页上面,用来实现诸如统计Chart图表.流程图.组织结构图的功能.为了使图像可以下载下来以便于修改,可以将SVG转为Visio的vsd格式.方法很简单,主要是使用Visio组 ...
- [转]html中offsetTop、clientTop、scrollTop、offsetTop各属性介绍
HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth scrollHeight: 获取对象的滚动高度. scrollLeft:设置或获取位于对 ...
- kindeditor修改图片上传路径-使用webapi上传图片到图片服务器
kindeditor是一个非常好用的富文本编辑器,它的简单使用我就不再介绍了. 在这里我着重介绍一些使用kindeditor修改图片上传路径并通过webapi上传图片到图片服务器的方案. 因为我使用的 ...
- 做一个完整的纯react-naitve安卓应用【从环境安装到应用发布】
前提:从来没有写过android 跟 ios 应用,是一个小前端.前一段时间玩了一下 react-native 感觉还不错,应用代码还未开源. 环境: win7 成果: ...
- 使用RandomAccessFile类对文件进行读写
1. RandomAccessFile类简介 前面一篇随笔<File类遍历目录及文件>中有说到,File类只能用于表示文件或目录的名称.大小等信息,而不能用于文件内容的访问.而当需要访 ...
- 业务订单号生成算法,每秒50W左右,不同机器保证不重复,包含日期可读性好
参考snowflace算法,基本思路: 序列12位(更格式化的输出后,性能损耗导致每毫秒生成不了这么多,所以可以考虑减少这里的位,不过留着也并无影响) 机器位10位 毫秒为左移 22位 上述几个做或运 ...