您的位置 首页 java

区块链中的密码学系列之对称加密算法DES(六)

1. 前言

DES 是一种数据加密标准( Data Encryption Standard) , 有30多年历史,是一种对称密码算法,是第一个得到广泛应用的密码算法,是一种分组加密算法,输入的明文为64位,密钥为64位(实际上只有56位,原因是每隔7个 比特 设置一个奇偶校验位),生成的密文分组长度为64位。但是现在已经不再安全。

课件来自我们老师上课的PPT。

2. Feistel网络

我们可以参考这里,Feistel讲解

下面简单说下:

Feistel网络利用乘积密码实现关键密码模块。所谓乘积密码就是顺序或循环地执行两个或多个基本密码模块,提高密码强度。其思想就是Shannon提出的利用乘积密码

实现扩散和混淆。

Feistel网络的加密结构:将2w bit明文分成为左右两半、长为1 w bit的段,以L和R表示。然后进行n轮迭代,其第i轮迭代的输入为上一轮(第i-1轮)输出。

其中Ki是第i轮用的子密钥, f是密码设计者选取或设计密码轮函数。 称这种分组密码 算法 为Feistel网络( Feistel Network) , 它保证加密和解密可采用同一算法实施。

每次迭代称为一轮(Round)。 相应函数f 称作轮函数。

Feistel网络的解密结构:Feistel解密过程本质上与加密过程一样。密文作为输入,使用子密钥Ki的次序与加密过程相反, Kn,Kn-1,…,K1。保证了加密与解密过程可采用同一算法。

3. DES算法框架

轮函数:

Li=Ri-1;

Ri=Li-1⊕f(Ri-1, Ki)。

4. DES加密模块

4.1 初始置换IP

4.2 DES的轮结构

扩充变换:扩充变换E的作用是将32比特的明文扩充为48比特。设m=m1m2…m31m32; c=c1c2…c47c48。满足E(m)=c, c1=m32,c2=m1,…,c7=m4,…,c48=m1。

8个S盒:

每个S盒Sj将6比特输入缩减为4比特输出。 8个S盒总共将48比特输入缩减为32比特输出。

每个S盒的输入为6比特串m=m1m2m3m4m5m6,输出为4比特串c=c1c2c3c4。

将m1m6, m2m3m4m5, c1c2c3c4都用10进制来表示,则在下表中位于m1m6 (0~3)行 m2m3m4m5 (0~15)列的数就是S盒的输出 c1c2c3c4(十进制转化成二进制)。

例如若S1的输入为100110,则通过查表(S1)输出应该是表中的第2(10)行第3(0011)列的数字8,所以二进制输出为1000。

置换P:

置换P将32比特的输入,改变位置顺序:输出的第1位为输入的第16位,输出的第2位为输入的第7位, …,输出的第32位为输入的第25位。

4.3 子密钥生成算法

64位密钥(8位奇偶校验位,有效位为56位)经过置换选择1、循环左移、置换选择2等变换,产生出16个48位长的子密钥。

置换选择1:

64位密钥分为8个字节。每个字节的前7位是真正的密钥位,第8位是奇偶校验位。奇偶校验位可以从前7位密钥位计算得出,不是随机的,因而不起密钥的作用。因此,DES真正的密钥只有56位。

置换选择1的作用有两个:一是从64位密钥中去掉8个奇偶校验位;二是把其余56位密钥位打乱重排,且将前28位作为C0,后28位作为D0。

置换选择1的矩阵如下:

循环左移:

每一次迭代,将 Ci -1和Di-1按照一定的位数循环左移分别得到Ci和Di。

  循环左移位数表如下:

置换选择2

将Ci和Di合并成一个56位的中间数据,置换选择2从中选择出一个48位的子密钥Ki。置换选择2的矩阵如下:

缩减变换PC-1, PC-2 : PC-1将64比特串缩为56比特; PC-2将56比特长的串缩为48比特。两个变换的输出比特顺序如下:

5. DES的加解密过程

DES的加密过程:

  1. 64位密钥经子密钥产生算法产生出16个48位子密钥:K1,K2,…,K16,分别供第1次,第2次,…,第16次加密迭代使用。
  2. 64位明文首先经过初始置换IP,将数据打乱重新排列并分成左右两半,左边32位构成L0,右边32位构成R0。
  3. 第i次加密迭代:由轮函数f实现子密钥Ki对Ri-1的加密,结果为32位的数据组f ( Ri-1 , Ki )。f ( Ri-1 , Ki )再与Li-1模2相加,又得到一个32位的数据组Li-1 ⊕ f ( Ri-1 , Ki )。以Li ⊕ f ( Ri-1 , Ki )作为下一次加密迭代的Ri,以Ri-1作为下一次加密迭代的Li ( i = 1,2,…,16)。
  4. 按照上一步的规则进行16次加密迭代。
  5. 第16次加密迭代结束后,以R16为左,L16为右,合并产生一个64位的数据组。再经过逆初始置换IP-1,将数据重新排列,便得到64位密文。

DES的解密过程:

  1. 64位密钥经子密钥产生算法产生出16个48位子密钥:K1,K2,…,K16,分别供第1次,第2次,…,第16次解密迭代使用。
  2. 64位密文首先经过初始置换IP,将数据打乱重新排列并分成左右两半,左边32位构成R16,右边32位构成L16。
  3. 第17-i次解密迭代:由轮函数f实现子密钥Ki对Li的解密,结果为32位的数据组f ( Li , Ki )。f ( Li , Ki )再与Ri模2相加,又得到一个32位的数据组Ri ⊕ f ( Li , Ki )。以Ri ⊕ f ( Li , Ki )作为下一次解密迭代的Li-1,以Li作为下一次解密迭代的Li-1 ( i = 16,15,…,1)。
  4. 按照上一步的规则进行16次解密迭代。
  5. 第16次解密迭代结束后,以L0为左,R0为右,合并产生一个64位的数据组。再经过逆初始置换IP-1,将数据重新排列,便得到64位明文。

6. DES的安全性

DES算法中除了S盒是非线性变换外,其余变换均为线性变换,所以DES安全的关键是S盒(保密 )。因为算法中使用了16次迭代,从而使得改变输入明文或密钥中的1位,密文都会发生大约32位的变化,具有良好的雪崩效应,大大提高了保密性。S盒用来提供混淆,使明文、密钥、密文之间的关系错综复杂,而P置换用来提供扩散,把S盒提供的混淆作用充分扩散开来。这样,S盒和P置换互相配合,形成了很强的抗差分攻击和抗线性攻击能力,其中抗差分攻击能力更强些。

7. DES加密的一个例子

取16进制明文X: 0123456789ABCDEF

密钥K为: 133457799BBCDFF1

去掉奇偶校验位以二进制形式表示的密钥是

00010010011010010101101111001001101101111011011111

111000

应用IP,我们得到:

L0=11001100000000001100110011111111

L1=R0=11110000101010101111000010101010

然后进行16轮加密。

最后对L16, R16使用IP-1得到密文: 85E813540F0AB405

8. java 版的DES算法

DES工具类:

public class DESUtil {
 //置换选择1矩阵
 static int[] replace1C = {
 57, 49, 41, 33, 25, 17, 9, 
 1, 58, 50, 42, 34, 26, 18, 
 10, 2, 59, 51, 43, 35, 27, 
 19, 11, 3, 60, 52, 44, 36
 };
 static int[] replace1D = {
 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
 };
​
 //循环左移位数表
 static int[] moveNum = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
​
 //置换选择2矩阵
 static int[] replace2 = {
 14, 17, 11, 24, 1, 5, 
 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
 };
​
 //初始置换矩阵
 static int[] IP = {
 58, 50, 42, 34, 26, 18, 10, 2, 
 60, 52, 44, 36, 28, 20, 12, 4, 
 62, 54, 46, 38, 30, 22, 14, 6, 
 64, 56, 48, 40, 32, 24, 16, 8, 
 57, 49, 41, 33, 25, 17, 9, 1, 
 59, 51, 43, 35, 27, 19, 11, 3, 
 61, 53, 45, 37, 29, 21, 13, 5, 
 63, 55, 47, 39, 31, 23, 15, 7
 };
​
 //选择运算矩阵
 static int[] E = {
 32, 1, 2, 3, 4, 5, 
 4, 5, 6, 7, 8, 9, 
 8, 9, 10, 11, 12, 13, 
 12, 13, 14, 15, 16, 17, 
 16, 17, 18, 19, 20, 21, 
 20, 21, 22, 23, 24, 25, 
 24, 25, 26, 27, 28, 29, 
 28, 29, 30, 31, 32, 1
 };
​
 //代替函数组
 static int[][][] S = {
 //S1
 {
 {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, 
 { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, 
 { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, 
 {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}
 }, 
 //S2
 {
 {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, 
 { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, 
 { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, 
 {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}
 }, 
 //S3
 {
 {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, 
 {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, 
 {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, 
 { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}
 }, 
 //S4
 {
 { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, 
 {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, 
 {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, 
 { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}
 }, 
 //S5
 {
 { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, 
 {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, 
 { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, 
 {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}
 }, 
 //S6
 {
 {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, 
 {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, 
 { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, 
 { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}
 }, 
 //S7
 {
 { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, 
 {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, 
 { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, 
 { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}
 }, 
 //S8
 {
 {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, 
 { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, 
 { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, 
 { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}
 }
 };
​
 //置换运算矩阵
 static int[] P = {
 16, 7, 20, 21, 
 29, 12, 28, 17, 
 1, 15, 23, 26, 
 5, 18, 31, 10, 
 2, 8, 24, 14, 
 32, 27, 3, 9, 
 19, 13, 30, 6, 
 22, 11, 4, 25
 };
​
 //逆初始置换矩阵
 static int[] rIP = {
 40, 8, 48, 16, 56, 24, 64, 32, 
 39, 7, 47, 15, 55, 23, 63, 31, 
 38, 6, 46, 14, 54, 22, 62, 30, 
 37, 5, 45, 13, 53, 21, 61, 29, 
 36, 4, 44, 12, 52, 20, 60, 28, 
 35, 3, 43, 11, 51, 19, 59, 27, 
 34, 2, 42, 10, 50, 18, 58, 26, 
 33, 1, 41, 9, 49, 17, 57, 25
 };
​
/***************************子密钥的产生**********************************************************************/
 /**
 * 子密钥的产生
 * @param sKey 64位密钥
 * @return 16个48位子密钥
 */
 static  byte [][] generateKeys(byte[] sKey) {
 byte[] C = new byte[28];
 byte[] D = new byte[28];
 byte[][] keys = new byte[16][48];
 //置换选择1
 //一是从64位密钥中去掉8个奇偶校验位;二是把其余56位密钥位打乱重排
 for (int i = 0; i < 28; i++) {
 C[i] = sKey[replace1C[i] - 1];
 D[i] = sKey[replace1D[i] - 1];
 }
​
 for (int i = 0; i < 16; i++) {
 //循环左移
 C = RSHR(C, moveNum[i]);
 D = RSHR(D, moveNum[i]);
 //置换选择2
 for (int j = 0; j < 48; j++) {
 if (replace2[j] <= 28) 
 keys[i][j] = C[replace2[j] - 1];
 else 
 keys[i][j] = D[replace2[j] - 29];
 }
 }
 return keys;
 }
 /**
 * 循环左移
 * @param b 数组
 * @param n 位数
 * @return
 */
 static byte[] RSHR(byte[] b, int n) {
 String s = new String(b);
 s = (s + s.substring(0, n)).substring(n);
 return s.getBytes();
 }
​
/**********************初始置换IP**************************************************************************/
 /**
 * 初始置换IP
 * @param text 64位数据
 * @return
 */
 static byte[] IP(byte[] text) {
 byte[] newtext = new byte[64];
 for (int i = 0; i < 64; i++) 
 newtext[i] = text[IP[i] - 1];
 return newtext;
 }
​
/**********************轮函数**************************************************************************/
 /**
 * 轮函数
 * @param A 32位输入
 * @param K 48位子密钥
 * @return 32位输出
 */
 static byte[] f(byte[] A, byte[] K) {
 byte[] t = new byte[48];
 byte[] r = new byte[32];
 byte[] result = new byte[32];
 //选择运算E,扩充变换为48bit
 for (int i = 0; i < 48; i++) 
 t[i] = A[E[i] - 1];
 //模2相加,逐位异或,得到一个48位的结果
 for (int i = 0; i < 48; i++) 
 t[i] = (byte) (t[i] ^ K[i]);
 //代替函数组S, 8个S盒总共将48比特输入缩减为32比特输出。
 for (int i = 0, a = 0; i < 48; i += 6, a += 4) {
 int j = t[i] * 2 + t[i + 5]; //b1b6
 int k = t[i + 1] * 8 + t[i + 2] * 4 + t[i + 3] * 2 + t[i + 4]; //b2b3b4b5
 byte[] b = Integer.toBinaryString(S[i / 6][j][k] + 16).substring(1).getBytes();
 for (int n = 0; n < 4; n++) 
 r[a + n] = (byte) (b[n] - '0');
 }
 //置换运算P,重新打乱顺序输出
 for (int i = 0; i < 32; i++) 
 result[i] = r[P[i] - 1];
 return result;
 }
/**********************逆初始置换IP^-1**************************************************************************/
 /**
 * 逆初始置换IP^-1
 * @param text 64位数据
 * @return
 */
 static byte[] rIP(byte[] text) {
 byte[] newtext = new byte[64];
 for (int i = 0; i < 64; i++) 
 newtext[i] = text[rIP[i] - 1];
 return newtext;
 }
}
 

DES实现类:

public class DES {
 /**
 * 加密
 * @param plaintext 64位明文
 * @param sKey 64位密钥
 * @return 64位密文
 */
 static byte[] encrypt(byte[] plaintext, byte[] sKey) {
 byte[][] L = new byte[17][32];
 byte[][] R = new byte[17][32];
 byte[] ciphertext = new byte[64];
 //子密钥的产生
 byte[][] K = DESUtil.generateKeys(sKey);
 //初始置换IP
 plaintext = DESUtil.IP(plaintext);
 //将明文分成左半部分L0和右半部分R0
 for (int i = 0; i < 32; i++) {
 L[0][i] = plaintext[i];
 R[0][i] = plaintext[i + 32];
 }
 //加密迭代
 for (int i = 1; i <= 16; i++) {
 L[i] = R[i - 1];
 R[i] = xor(L[i - 1], DESUtil.f(R[i - 1], K[i - 1]));
 }
 //以R16为左半部分,L16为右半部分合并
 for (int i = 0; i < 32; i++) {
 ciphertext[i] = R[16][i];
 ciphertext[i + 32] = L[16][i];
 }
 //逆初始置换IP^-1
 ciphertext = DESUtil.rIP(ciphertext);
 return ciphertext;
 }
​
 /**
 * 解密
 * @param ciphertext 64位密文
 * @param sKey 64位密钥
 * @return 64位明文
 */
 static byte[] decrypt(byte[] ciphertext, byte[] sKey) {
 byte[][] L = new byte[17][32];
 byte[][] R = new byte[17][32];
 byte[] plaintext = new byte[64];
 //子密钥的产生
 byte[][] K = DESUtil.generateKeys(sKey);
 //初始置换IP
 ciphertext = DESUtil.IP(ciphertext);
 //将密文分成左半部分R16和右半部分L16
 for (int i = 0; i < 32; i++) {
 R[16][i] = ciphertext[i];
 L[16][i] = ciphertext[i + 32];
 }
 //解密迭代
 for (int i = 16; i >= 1; i--) {
 L[i - 1] = xor(R[i], DESUtil.f(L[i], K[i - 1]));
 R[i - 1] = L[i];
 R[i] = xor(L[i - 1], DESUtil.f(R[i - 1], K[i - 1]));
 }
 //以L0为左半部分,R0为右半部分合并
 for (int i = 0; i < 32; i++) {
 plaintext[i] = L[0][i];
 plaintext[i + 32] = R[0][i];
 }
 //逆初始置换IP^-1
 plaintext = DESUtil.rIP(plaintext);
 return plaintext;
 }
​
 /**
 * 两数组异或
 * @param a
 * @param b
 * @return
 */
 static byte[] xor(byte[] a, byte[] b) {
 byte[] c = new byte[a. length ];
 for (int i = 0; i < a.length; i++) 
 c[i] = (byte) (a[i] ^ b[i]);
 return c;
 }
}
 

DES测试:

​
public class TestDES {
 public static void main(String[] args) {
 String strKey = "0011000100110010001100110011010000110101001101100011011100111000";
 byte[] sKey = strKey.getBytes();
 for (int i = 0; i < sKey.length; i++) 
 sKey[i] -= '0';
 System.out.print("密钥:");
 printByteArr(sKey);
 String strPlain = "0011000000110001001100100011001100110100001101010011011000110111";
 byte[] plaintext = strPlain.getBytes();
 for (int i = 0; i < plaintext.length; i++) 
 plaintext[i] -= '0';
 System.out.print("明文:");
 printByteArr(plaintext);
 byte[] ciphertext = DES.encrypt(plaintext, sKey);
 System.out.print("密文:");
 printByteArr(ciphertext);
 byte[] plainText = DES.decrypt(ciphertext, sKey);
 System.out.print("明文:");
 printByteArr(plainText);
 }
​
 static void printByteArr(byte[] b) {
 for (int i = 0; i < b.length; i++) {
 System.out.print(b[i]);
 if (i % 8 == 7) 
 System.out.print(" ");
 }
 System.out.println();
 }
}
 

测试结果:

9. 3DES

为提高安全性, 并利用实现DES的现有软硬件, 将DES算法在多密钥下重复使用。

三重DES:

两个密钥的三重DES。C=Ek1[Dk2[Ek1[P]]]

三个密钥的三重DES。C=Ek3[Dk2[Ek1[P]]]

10. 结束语

我们学习了DES加密算法。DES作为对称加密,其实现还是比较复杂的。我们来简单回顾下,DES的加密过程。首先,我们需要生成16*48位的子密钥(子密钥的生成需要三步,即置换选择1,循环左移和置换选择2)。然后执行轮函数(分为四步,分别是扩充变换E,与密钥按位异或,S盒变换,P盒变换)。最后进行逆初始变换即可得到加密后的密文。

解密与之类似。不再赘述。

文章来源:智云一二三科技

文章标题:区块链中的密码学系列之对称加密算法DES(六)

文章地址:https://www.zhihuclub.com/190313.shtml

关于作者: 智云科技

热门文章

网站地图