DES全称为Data ,为密码体制中的对称密码体制,所谓对称加密就是加密和解密的过程使用相同的算法,是加密中最弱的算法,但是性能最好。
概述:
DES采用分组加密方法,以64位为一个最小分组对数据加密(明文8个字节为一个分组,每字节8位(bit)),每 组单独加密处理。
密钥长64位,但密钥事实上是56位参与DES运算(第8、16、24、32、40、48、56、64位是校验位,使得每个密钥都有奇数个1),分组后的明文组和56位的密钥按位替代或交换的方法形成密文组。
密文长度和明文长度相同,为64位,DES的加密和解密算法相同,但解密子密钥与加密子密钥的使用顺序刚好相反。
算法步骤
本部分参考《物联网信息安全》第一版,桂小林版
算法主要分为三步,流程图先给出
第一步:
对输入的64位的明文分组进行固定的“初始置换”( ,IP),即按固定的规则(后文解释)重新排列明文分组的64位二进制数据,再将重排后的64位数据前后32位分为独立64位明文的左右两个部分,前32位记为L0,后32位记为R0。
第二步:
进行16轮相同函数的迭代处理。将上一轮输出的Ri-1(注:i=1.....15)直接作为Li输入,同时将Ri-1与第i个48位的子密钥Ki经“轮函数f”转换后,得到一个32位的中间结果,再将此中间结果与上一轮的Li-1做异或运算,并将得到的新的32位结果作为下一轮的Ri。如此往复,迭代处理16次。每次的子密钥不同,16个子密钥的生成与轮函数在后面单独阐述。(是交换两个半分组java aes加密解密算法 密码学加密算法——DES实现与验证(Java),一轮运算的左半分组输入是上一轮的右半分组的输出)
第三步:
将第16轮迭代结果左右两半组L16、R16直接合并为64位 (L16,R16), 输入到初始逆置换来消除初始置换的影响。这一步的输出结果即为加密过程的密文。
初始置换
置换表中的数字为1~64,意为输入的64位二进制明文或密文数据从左至右的位置序号。置换表中的数字位置即为置换后java aes加密解密算法,数字对应的原位置数据在输出的64位序列中新的位置序号。比如表中第一个数字58,58表示输入64位明文或密文二进制数据的第58位;而58位于表中第一位,则表示将原二进制数的第58位置换到输出的第1位。
轮函数
工作流程如下,主要为4步
第一步:扩展E变换( box,E盒),即将输入的32位数据扩展为48位。其扩展E变换如表3-3所示,表中元素的意义与初始置换表基本相同,按行顺序,从左至右共48位。比如第一个元素为32,表示48位输出结果的第一位数据为原输入32位数据中的第32位上的数据。
第二步:将第一步输出结果的48位二进制数据与48位子密钥K按位做异或运算,结果自然为48位。然后将运算结果的48位二进制数据自左到右以6位为一组,共分8组。
第三步:将8组6位二进制数据分别进入8个不同的S盒,每个S盒输入6位二进制数据,输出4位二进制数据(S盒相对复杂,后面单独阐述),然后再将8个S盒输出的8组4位数据,依次连接.重新合并为32位数据。
第四步:将上一步合并生成的32位数据,经p盒( box)置换,输出新的32数据。
按行的顺序从左到右java aes加密解密算法,表中第i个位置对应的数据j表示为输出的第i位为输入的第j位数据。P 盒输出的32位数据即为轮函数的最终输出结果。
S盒
S盒( box)是DES的核心部分。通过S盒定义的非线性替换,DES实现了明文消息在密文消息空间上的随机非线性分布。S盒的非线性替换特征意味着,给定一组输入输出值,很难预计所有S盒的输出。共有8种不同的S盒,每个S盒将接收6位输入数据,通过定义的非线性映射变换为4位输出。一个S盒有一个16列4行数表,它的每个元素是一个4位二进制数,通常表示成十进制数0~15。
S盒的替代运算规则:设输入6位二进制数据为,则以b1b6饥足组成的二进制数为行号,组成的二进制数为列号,取出S盒中行列交点处的数,并转换成二进制输出。由于表中十进制数的范围是0~15,以二进制表示正好4位。下面以6 位输入数据经 Si盒变换为例进行说明。
DES子密钥
DES加密过程中需要16个48位的子密钥。子密钥由用户提供64位密钥 ,经16轮迭代运算依次生成。DES子密钥生成算法如图3所示,主要可分为如下三个阶段。
第一阶段:用户提供8个字符密钥,转换成ASCII码的64位,经置换选择1(如表所示),去除8个奇偶校验位,并重新排列各位,置换选择1如表3-6所示,表中各位置上的元素意义与前面置换相同。由表可知,8、16、24、32、40、48、56、64位舍去了,重新组合后得56位。由于舍去规则是固定的,因而实际使用的初始密钥只有56位。
第二阶段:将上一步置换选择后生成的56位密钥,分成左右两部分,前28位记为C0,后28位记为D0。然后分别将28位的C0,D0循环左移位一次,移位后分别得到的G、D,作为下一轮子密钥生成的位输入。每轮迭代循环左移位的次数遵循固定的规则,每轮左移次数如表所示。
第三阶段:将C、D合并得到56位数据(C1,D1),经表中的置换选择2,也就是经固定的规则,置换选出重新排列的48位二进制数据,即为子密钥化K1。
将C1,D1作下一轮的输入,采用前面相同的二、三两个阶段进行迭代,即可得到K2,依此类推,经过16轮迭代即可生成16个48位的子密钥。
实现代码
由于DES加密常用于网络传输,所以用JAVA来实现,有很多封装好的包,只需要就行。
DES算法有三个入口参数:明文、密钥、模式(加密or解密)
先定义一个类
<pre>import FileOperate.FileOperate;
import ParseSystemUtil.ParseSystemUtil;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
final class DESEncryptTools {
<p>
//加密算是是[des][9]
private static final String ALGORITHM = "DES";
//转换格式
private static final String TRANSFORMATION = "DES/ECB/PKCS5Padding";
/* DES在实际应用中有多种模式(ECB、CBC、CBR等)和填充方式(PKCS5Padding、NoPadding、ZeroPadding)
此处以最为广泛使用的ECB模式、PKCS5填充举例
*/
//利用8个字节64位的key给src加密
@SuppressWarnings("unused")
public static byte[] encrypt(byte[] src, byte[] key) {//加密函数
try {
//加密
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM);
KeySpec keySpec = new DESKeySpec(key);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new SecureRandom());
byte[] enMsgBytes = cipher.doFinal(src);
return enMsgBytes;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//利用8个字节64位的key给src解密
@SuppressWarnings("unused")
public static byte[] decrypt(byte[] encryptBytes, byte[] key) {//解密函数
try {
//解密
//Cipher deCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
Cipher deCipher = Cipher.getInstance(TRANSFORMATION);
SecretKeyFactory deDecretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM);
KeySpec deKeySpec = new DESKeySpec(key);
SecretKey deSecretKey = deDecretKeyFactory.generateSecret(deKeySpec);
deCipher.init(Cipher.DECRYPT_MODE, deSecretKey, new SecureRandom());
byte[] deMsgBytes = deCipher.doFinal(encryptBytes);
return deMsgBytes;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
再定义一个测试函数blic class DesMainTest {
private static String key = "12345678";//密钥
public static void main(String[] args) throws Exception {
System.out.println("DES密钥算法测试:");
String msg = null;
try {
msg = FileOperate.fileRead("D:\\IDEA_java\\src\\DES\\test.txt");
System.out.println("文件读取成功,明文为:" + msg);
System.out.println("明文长度:" + msg.getBytes().length * 8+"bit");
System.out.println("密钥长度:" + key.getBytes().length * 8+"bit");
} catch (Exception e) {
System.out.println(e.getMessage().toString());
}
long startTime = System.nanoTime();
byte[] encryptBytes = DESEncryptTools.encrypt(msg.getBytes(), key.getBytes());
String hexStrResult = ParseSystemUtil.parseByte2HexStr(encryptBytes);
System.out.println("加密后的16进制密文为:" + hexStrResult);
// 此处密文长度计算不可用String类型的hexStrResult求长度,必须用Byte[]型的encryptBytes
System.out.println("密文长度:" + returnActualLength(encryptBytes) * 8+"bit");
long endTime = System.nanoTime();
System.out.println("加密耗时:" + (endTime - startTime) + "ns");
try {
FileOperate.fileWrite("D:\\IDEA_java\\src\\DES\\密文.txt", new String(encryptBytes));
} catch (Exception e) {
System.out.println(e.getMessage().toString());
}
startTime = System.nanoTime();
byte[] deMsgBytes = DESEncryptTools.decrypt(encryptBytes, key.getBytes());
System.out.println("解密后的明文为:" + new String(deMsgBytes));
endTime = System.nanoTime();
System.out.println("明文长度:" + returnActualLength(deMsgBytes) * 8+"bit");
System.out.println("解密耗时:" + (endTime - startTime) + "ns");
try {
FileOperate.fileWrite("D:\\IDEA_java\\src\\DES\\明文.txt", new String(deMsgBytes));
} catch (Exception e) {
System.out.println(e.getMessage().toString());
}
}
public static int returnActualLength(byte[] data) {//计算Byte[]到底占用几个字节
int i = 0;
for (; i = 201103L
include
include
include
include
include
include
include
include
include
endif
// C++
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
if __cplusplus >= 201103L
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
include
endif
bool key[66], C[29], D[29];
int k(0);
int table1[56] = { 57,49,41,33,25,17,9,1 //置换选择表1,用于从64位初始密钥中选择56位
,58,50,42,34,26,18,10,2
,59,51,43,35,27,19,11,3
,60,52,44,36,63,55,47,39
,31,23,15,7,62,54,46,38
,30,22,14,6,61,53,45,37
,29,21,13,5,28,20,12,4 };
int table2[48] = { 14,17,11,24,1,5, //置换选择表2,将得到的56位进行置换选择2,得到真正的圈密钥
3,28,15,6,21,10,
23,19,12,4,26,8,
16,7,27,20,13,2,
41,52,31,37,47,55,
30,40,51,45,33,48,
44,49,39,56,34,53,
46,42,50,36,29,32 };
int dis[16] = { 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 };//C寄存器和D寄存器循环左移的位数
void to_binary(int n) //将10进制数转换为4位2进制数
{
int K = k + 3;
while (n)
{
key[K--] = n % 2;
n /= 2;
}
while (k