DES对称加密算法简析
1 对称加密算法
在了解DES算法前,先加单介绍一下对称加密算法,因为DES属于对称加密算法的一种。
对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yao)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。
原理如下图:
2 DES算法简介
2.1 概述
DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。需要注意的是,在某些文献中,作为算法的DES称为数据加密算法(Data Encryption Algorithm,DEA),已与作为标准的DES区分开来。
2.2 发展历史
美国国家标准局1973年开始研究除国防部外的其它部门的计算机系统的数据加密标准,于1973年5月15日和1974年8月27日先后两次向公众发出了征求加密算法的公告。加密算法要达到的目的(通常称为DES 密码算法要求)主要为以下四点:
☆提供高质量的数据保护,防止数据未经授权的泄露和未被察觉的修改;
☆具有相当高的复杂性,使得破译的开销超过可能获得的利益,同时又要便于理解和掌握;
☆DES密码体制的安全性应该不依赖于算法的保密,其安全性仅以加密密钥的保密为基础;
☆实现经济,运行有效,并且适用于多种完全不同的应用。
1977年1月,美国政府颁布:采纳IBM公司设计的方案作为非机密数据的正式数据加密标准(DES Data Encryption Standard)。
2.3 算法原理
DES 使用一个 56 位的密钥以及附加的 8 位奇偶校验位,产生最大 64 位的分组大小。这是一个迭代的分组密码,使用称为 Feistel 的技术,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行“异或”运算;接着交换这两半,这一过程会继续下去,但最后一个循环不交换。DES 使用 16 个循环,使用异或,置换,代换,移位操作四种基本运算。
DES算法的入口参数有三个:Key、Data、Mode。
Key为8个字节共64位,是DES算法的工作密钥;
Data也为8个字节64位,是要被加密或被解密的数据;
Mode为DES的工作方式,有两种:加密或解密。
DES算法是这样工作的:
如Mode为加密,则用Key 去把数据Data进行加密, 生成Data的密码形式(64位)作为DES的输出结果;
如Mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式(64位)作为DES的输出结果。
在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、MAC等)在公共通信网中传输的安全性和可靠性。
通过定期在通信网络的源端和目的端同时改用新的Key,便能更进一步提高数据的保密性,这正是现在金融交易网络的流行做法。
2.4 应用
目前在国内,随着三金工程尤其是金卡工程的启动,DES算法在POS、ATM、磁卡及智能卡(IC卡)、加油站、高速公路收费站等领域被广泛应用,以此来实现关键数据的保密,如信用卡持卡人的PIN的加密传输,IC卡与POS间的双向认证、金融交易数据包的MAC校验等,均用到DES算法。
2.5 java代码实现
package xin.dreaming.des; import java.security.SecureRandom;
import java.util.Arrays; import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec; import org.junit.Test;
/**
*
* @author DREAMING.XIN
*
*/
public class DESUtils { /**
* 生成随机密钥
*
* @param size
* 位数
* @return
*/
public static String generateRandomKey(int size) {
StringBuilder key = new StringBuilder();
String chars = "0123456789ABCDEF";
for (int i = 0; i < size; i++) {
int index = (int) (Math.random() * (chars.length() - 1));
key.append(chars.charAt(index));
}
return key.toString();
} /**
* DES加密
*
* @param key
* 密钥信息
* @param content
* 待加密信息
* @return
* @throws Exception
*/
public static byte[] encodeDES(byte[] key, byte[] content) throws Exception {
// 不是8的倍数的,补足
if (key.length % 8 != 0) {
int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
byte[] temp = new byte[groups * 8];
Arrays.fill(temp, (byte) 0);
System.arraycopy(key, 0, temp, 0, key.length);
key = temp;
} // 不是8的倍数的,补足
byte[] srcBytes = content;
if (srcBytes.length % 8 != 0) {
int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
srcBytes = new byte[groups * 8];
Arrays.fill(srcBytes, (byte) 0);
System.arraycopy(content, 0, srcBytes, 0, content.length);
} IvParameterSpec iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv, sr);
byte[] tgtBytes = cipher.doFinal(srcBytes);
return tgtBytes;
} /**
* DES解密
*
* @param key
* 密钥信息
* @param content
* 待加密信息
* @return
* @throws Exception
*/
public static byte[] decodeDES(byte[] key, byte[] content) throws Exception {
// 不是8的倍数的,补足
if (key.length % 8 != 0) {
int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
byte[] temp = new byte[groups * 8];
Arrays.fill(temp, (byte) 0);
System.arraycopy(key, 0, temp, 0, key.length);
key = temp;
}
// 不是8的倍数的,补足
byte[] srcBytes = content;
if (srcBytes.length % 8 != 0) {
int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
srcBytes = new byte[groups * 8];
Arrays.fill(srcBytes, (byte) 0);
System.arraycopy(content, 0, srcBytes, 0, content.length);
} IvParameterSpec iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv, sr);
byte[] tgtBytes = cipher.doFinal(content);
return tgtBytes;
} @Test
public void desTest() throws Exception{
//获取随机密钥
String key = generateRandomKey(16);
System.out.println("随机密钥:"+key);
String str = "DREAMING.XIN";
//des加密
byte[] encodeDES = encodeDES(key.getBytes(), str.getBytes());
System.out.println("加密结果:"+encodeDES); //des解密
byte[] decodeDES = decodeDES(key.getBytes(), encodeDES);
System.out.println("减密结果: "+new String(decodeDES));
} }
执行结果:
随机密钥:AB09C55631425D67
加密结果:[B@19fc4e
减密结果: DREAMING.XIN
3 3DES加密算法
3.1 概述
3.2 java代码实现
package xin.dreaming.des; import java.security.Security;
import java.util.Arrays; import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Test; public class TripleDESUtils { /**
* 生成随机密钥
*
* @param size
* 位数
* @return
*/
public static String generateRandomKey(int size) {
StringBuilder key = new StringBuilder();
String chars = "0123456789ABCDEF";
for (int i = 0; i < size; i++) {
int index = (int) (Math.random() * (chars.length() - 1));
key.append(chars.charAt(index));
}
return key.toString();
} /**
* 3DES加密
*
* @param key
* 密钥信息
* @param content
* 待加密信息
* @return
* @throws Exception
*/
public static byte[] encode3DES(byte[] key, byte[] content) throws Exception {
Security.addProvider(new BouncyCastleProvider());
// 不是8的倍数的,补足
if (key.length % 8 != 0) {
int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
byte[] temp = new byte[groups * 8];
Arrays.fill(temp, (byte) 0);
System.arraycopy(key, 0, temp, 0, key.length);
key = temp;
}
// 长度为16位,转换成24位的密钥
if (key.length == 16) {
byte[] temp = new byte[24];
System.arraycopy(key, 0, temp, 0, key.length);
System.arraycopy(key, 0, temp, key.length, temp.length - key.length);
key = temp;
} // 不是8的倍数的,补足
byte[] srcBytes = content;
if (srcBytes.length % 8 != 0) {
int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
srcBytes = new byte[groups * 8];
Arrays.fill(srcBytes, (byte) 0);
System.arraycopy(content, 0, srcBytes, 0, content.length);
} SecretKey deskey = new SecretKeySpec(key, "DESede");
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, deskey);
byte[] temp = cipher.doFinal(srcBytes);
byte[] tgtBytes = new byte[content.length];
System.arraycopy(temp, 0, tgtBytes, 0, tgtBytes.length);
return tgtBytes;
} /**
* 3DES解密
*
* @param key
* 密钥
* @param content
* 待解密信息
* @return
* @throws Exception
*/
public static byte[] decode3DES(byte[] key, byte[] content) throws Exception {
// 不是8的倍数的,补足
if (key.length % 8 != 0) {
int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
byte[] temp = new byte[groups * 8];
Arrays.fill(temp, (byte) 0);
System.arraycopy(key, 0, temp, 0, key.length);
key = temp;
}
// 长度为16位,转换成24位的密钥
if (key.length == 16) {
byte[] temp = new byte[24];
System.arraycopy(key, 0, temp, 0, key.length);
System.arraycopy(key, 0, temp, key.length, temp.length - key.length);
key = temp;
} // 不是8的倍数的,补足
byte[] srcBytes = content;
if (srcBytes.length % 8 != 0) {
int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
srcBytes = new byte[groups * 8];
Arrays.fill(srcBytes, (byte) 0);
System.arraycopy(content, 0, srcBytes, 0, content.length);
} SecretKey deskey = new SecretKeySpec(key, "DESede");
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, deskey);
byte[] tgtBytes = cipher.doFinal(srcBytes);
return tgtBytes;
} /**
* 二进制转十六进制字符串。每一个字节转为两位十六进制字符串。
*/
public static String byte2hex(byte[] b) {
String hs = "";
String stmp = "";
for (int i = 0; i < b.length; i++) {
stmp = Integer.toHexString(b[i] & 0XFF);
if (stmp.length() == 1) {
hs = hs + "0" + stmp;
} else {
hs = hs + stmp;
}
}
return hs.toUpperCase();
} /**
* <b>概要:</b>
* 十六进制转二进制
* @param hex
* @return
* @throws IllegalArgumentException
*/
public static byte[] hex2byte(String hex) throws IllegalArgumentException {
if (hex.length() % 2 != 0) {
throw new IllegalArgumentException();
}
if (hex.startsWith("0x")) {
hex = hex.substring(2);
}
char[] arr = hex.toCharArray();
byte[] b = new byte[hex.length() / 2];
for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
String swap = "" + arr[i++] + arr[i];
int byteint = Integer.parseInt(swap, 16) & 0xFF;
b[j] = new Integer(byteint).byteValue();
}
return b;
} /**
* 3DES加密模式
*/
public static String encrypt(String value,String key) {
try {
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "DESede");
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedByte = cipher.doFinal(value.getBytes());
String encodedByte = byte2hex(encryptedByte);
return encodedByte;
} catch(Exception e) {
e.printStackTrace();
return null;
}
} /**
* <b>概要:</b>
* 3DES解密
* @param value
* @param key
* @return
*/
public static String decrypt(String value,String key) {
try { SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "DESede");
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decryptedByte = cipher.doFinal(hex2byte(value));
return new String(decryptedByte);
} catch(Exception e) {
e.printStackTrace();
return null;
}
} @Test
public void TripleDESTest() throws Exception { // 获取随机密钥
String key = generateRandomKey(24);
System.out.println("随机密钥:" + key);
String str = "DREAMING.XIN";
// des加密
String encodeDES = encrypt( str,key);
System.out.println("3DES加密结果:" + encodeDES); // des解密
String decodeDES = decrypt(encodeDES, key);
System.out.println("减密结果: " + decodeDES);
}
}
运行结果:
补充说明:
1、3DES的密钥必须是24位的byte数组
否则会报错:如图,我生成23位密钥进行测试,报错如下:
2、加密结果的编码方式要一致
从byte数组转成字符串,一般有两种方式,base64处理和十六进制处理。
参考:
1、https://www.zhihu.com/question/36767829
2、https://baike.baidu.com/item/DES/210508?fr=aladdin
3、https://baike.baidu.com/item/对称加密算法/211953?fr=aladdin
DES对称加密算法简析的更多相关文章
- JAVA加密解密DES对称加密算法
下面用DES对称加密算法(设定一个密钥,然后对所有的数据进行加密)来简单举个例子. 首先,生成一个密钥KEY. 我把它保存到key.txt中.这个文件就象是一把钥匙.谁拥有它,谁就能解开我们的类文件. ...
- DES对称加密算法详解和c++代码实现(带样例和详细的中间数据)
特点: 1.DES是对称性加密算法,即加密和解密是对称的,用的是同一个密钥 2.DES只处理二进制数据,所以需要将明文转换成为2进制数据 3.DES每次处理64位的数据,所以应该将明文切割成64位的分 ...
- DES对称加密算法实现:Java,C#,Golang,Python
数据加密标准(DES,Data Encryption Standard,简写DES)是一种采用块密码加密的对称密钥算法,加密分组长度为64位,其中8.16.24.32.40.48.56.64 等8位是 ...
- 对称加密算法-DES以及DESede算法
一.简述 对称加密算法就是能将数据加解密.加密的时候用密钥对数据进行加密,解密的时候使用同样的密钥对数据进行解密. DES是美国国家标准研究所提出的算法.因为加解密的数据安全性和密钥长度成正比.des ...
- pyDes 实现 Python 版的 DES 对称加密/解密--转
https://my.oschina.net/leejun2005/blog/586451 手头有个 Java 版的 DES 加密/解密程序,最近想着将其 Python 重构下,方便后续脚本解析,捣鼓 ...
- [转] 对称加密算法DES、3DES
转自:http://www.blogjava.net/amigoxie/archive/2014/07/06/415503.html 1.对称加密算法 1.1 定义 对称加密算法是应用较早的加密算法, ...
- 常用加密算法的Java实现总结(二) ——对称加密算法DES、3DES和AES
1.对称加密算法 1.1 定义 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理后,使其变成复杂的加密密文发 ...
- 对称加密算法DES,3重DES,TDEA,Blowfish,RC5,IDEA,AES。
对称加密算法:DES,3重DES,TDEA,Blowfish,RC5,IDEA,AES. 1.对称加密算法 1.1 定义 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文 ...
- 对称加密算法DES、3DES和AES 原理总结(转载)
1.对称加密算法 1.1 定义 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理后,使其变成复杂的加密密文发 ...
随机推荐
- 张高兴的 Windows 10 IoT 开发笔记:ToF Sensor VL53L0X
GitHub : https://github.com/ZhangGaoxing/windows-iot-demo/tree/master/VL53L0X
- UVa12325, Zombie's Treasure Chest
反正书上讲的把我搞得晕头转向的,本来就困,越敲越晕...... 转网上一个大神写的吧,他分析的很好(个人感觉比书上的清楚多了) 转:http://blog.csdn.net/u010536683/ar ...
- centos安装SWFtools服务(pdf2swf)
第一步:下载swftools-0.9.2.tar.gz 第二步:swftools tar -xzvf swftools-0.9.2.tar.gz cd swftools-0.9.2 ./configu ...
- jquery入门知识点总结(转)
一.jquery的加载方法 $(document).ready(function(){js代码}); $(function(){js代码});(一般使用这个); 注意点1:使用jquery必须先导入函 ...
- parameterType 和 resultType
parameterType #{} 和 ${} 1.#{}实现的是向prepareStatement中的预处理语句中设置参数值,sql语句中#{}表示一个占位符即?. 2.使用占位符#{}可以有效防止 ...
- Windows中 MySQL5.7.17解压版安装步骤
1.先去MySQL官网下载.当前最新版是5.7.19,可能安装方法不同了,本人测试没有安装成功,若有安装成功的朋友,希望分享一下安装步骤. 个人推荐下载MySQL5.7.17,官方下载网址:https ...
- 实验之-----------修改oracle实例名
--查询当前数据库实例名称: SQL> select instance_name,status from v$instance; INSTANCE_NAME STATUS------------ ...
- 本地文件与服务器文件同步shell脚本。
#!/bin/sh read -t 30 -p "请输入项目名:" name echo -e "\n" echo "项目名为:$name" ...
- android开发第一天
今天可以说是我正式投入android怀抱的第一天吧,按着自己的兴趣,努力地吸取知识.听了程老师的课,也觉得收获很多,毕竟以前都是看着书本或者网页教程来学习,第一次有人这么直接地跟你教授着,说着一些你听 ...
- python爬虫如何入门
学爬虫是循序渐进的过程,作为零基础小白,大体上可分为三个阶段,第一阶段是入门,掌握必备的基础知识,第二阶段是模仿,跟着别人的爬虫代码学,弄懂每一行代码,第三阶段是自己动手,这个阶段你开始有自己的解题思 ...