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)一起经过特殊加密算法处理后,使其变成复杂的加密密文发 ...
随机推荐
- TensorFlow问题:The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.
1. 问题描述 The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available o ...
- 浅谈python 复制(深拷贝,浅拷贝)
博客参考:点击这里 python中对象的复制以及浅拷贝,深拷贝是存在差异的,这儿我们主要以可变变量来演示,不可变变量则不存在赋值/拷贝上的问题(下文会有解释),具体差异如下文所示 1.赋值: a=[1 ...
- windows中vim-airline研究笔记
vim-airline网上的介绍与安装教程一大堆,我就不累述了 但是,在win下如何让airline插件正常显示箭头等特殊字符着实让我头疼了不少. 最初,我是用的monaco字体 但正如你所见,并没有 ...
- PHP 操作 进程时相关 信号的具体含义
SIGQUIT 建立CORE文件终止进程,并且生成core文件SIGILL 建立CORE文件 非法指令SIGTRAP 建立CORE文件 跟踪自陷SIGBUS ...
- 我的第一个python web开发框架(10)——工具函数包说明(一)
PS:原先是想直接进入功能开发,要用到什么函数时再创建,这样也容易熟悉每个函数的由来和使用方法,但考虑到这样操作,到时会经常在不同文件间切换,不好描述,容易造成混乱,所以还是使用函数库这种方式来说明. ...
- Fork/Join-Java并行计算框架
Java在JDK7之后加入了并行计算的框架Fork/Join,可以解决我们系统中大数据计算的性能问题.Fork/Join采用的是分治法,Fork是将一个大任务拆分成若干个子任务,子任务分别去计算,而J ...
- C基本类型
C基本类型有: char:8位,可添加修改符signed或是unsigned short:16位,同有singed和unsigned int:32位,同有singed和unsigned long:在3 ...
- 简易RPC框架-上下文
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- JPA 映射单向多对一的关联关系
1.首先在多的一端加入一的一端的实体类 //映射单向n-1的关联关 //使用@ManyToOne 来映射多对一的关系 //使用@JoinColumn 来映射外键/可以使用@ManyToOne的fetc ...
- Leetcode题解(25)
77. Combinations 题目 分析:求给定数字n,k的组合数,方法是采用深度搜索算法,代码如下(copy网上代码) class Solution { public: void dfs77(v ...
