DES的算法实现原理详情请见
https://blog.csdn.net/qq_31236027/article/details/128209185
DES算法密钥获取详情请见
https://blog.csdn.net/qq_31236027/article/details/129224730
编码工具类获取详见
https://blog.csdn.net/qq_31236027/article/details/128579451
DES算法实现思路:
- 进行编码工具类的设计,主要设计以下几个方法:
- 字符串转二进制,用于明文加密
- 二进制转字符串,用于对解密二进制流与文本的转换
- 二进制转十六进制字符串,用于对加密后的文本进行传输和保存,防止出现乱码
- 十六进制转二进制,用于对加密后的文本进行解密
- 其他有需要的方法(如s盒的二进制转十进制)
- 进行密钥获取工具类的设计
- 进行des算法工具类的设计
密钥获取工具类的设计:
- 设计一个初始化方法和两个数组,用于密钥第一次选择置换和接收左右半部分的32位二进制结果。
- 初始化后进行16轮密钥的获取,最好能够存储在一个私有全局变量里,然后通过一个接口方法对外发布。(我这步没有做)
DES算法工具类的设计:
注意点:
- 将获取的16轮密钥保存在一个全局变量,解密需要使用(只需要逆置即可)
- 注意分组问题
- !!很重要的一点!!在加密后要将所有的十六进制流小写,大写的话会解密出现乱码。
最后上DES算法工具类实现代码:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329package des; import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import common.EncodeUtil; import common.IEncrytion; import common.EncodeUtil.EncodeRadix; /** * des加解密工具类 * @author zygswo * */ public class DesUtil implements IEncrytion{ /** * 加密轮数 */ public static final int ROUND_NB = 16; /** * 字符串长度 */ public static final int CHAR_LEN = 16; /** * 分组长度 */ public static final int DIV_LEN = 64 / CHAR_LEN; /** * 密钥对象 */ private KeyUtil subKeyObj = new KeyUtil().init(); public List<String> subKeys = Collections.synchronizedList(new ArrayList<>()); /** * 初始置换PC表 */ private static int[][] transferTable = { {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} }; /** * 扩展置换PC表 */ private static int[][] transferExtendTable = { {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} }; /** * p盒置换表 */ private static int[][] pTransferTable = { {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} }; /** * 逆初始置换PC-1表 */ private static int[][] transferReverseTable = { {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} }; /** * s盒置换表 */ private static int[][][] sBox = { { {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} }, { {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} }, { {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} }, { {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} }, { {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} }, { {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} }, { {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} }, { {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} } }; /** * 解密 * @param encrytedText 密文 * @return 明文 */ @Override public String decrypt(String encrytedText) { StringBuilder sb = new StringBuilder(); // CHAR_LEN = divLeng * 4 (16进制4位,转16位需要4个16进制位) int divLeng = 16; int length = encrytedText.length()% divLeng == 0 ? encrytedText.length()/divLeng : (encrytedText.length()/divLeng + 1); for (int i = 0; i<length; i++) { int startIndex = i * divLeng; int endIndex = (startIndex + divLeng) > encrytedText.length() ? encrytedText.length() : (startIndex + divLeng); String str1 = encrytedText.substring(startIndex, endIndex); sb.append( baseDecrypt(EncodeUtil.toBinary(str1,EncodeRadix.HEX)) ); } return sb.toString().trim(); } /** * 解密(64位一组) * @param encrytedText 密文 * @return */ private String baseDecrypt(String encrytedText) { //1.初始置换 //获取16组密钥 List<String> reversedSubkeys = new ArrayList<>(); for (int i = subKeys.size() -1; i >=0 ;i--) { reversedSubkeys.add(subKeys.get(i)); } //16次循环加密 return EncodeUtil.binaryToStr( loops(encrytedText, reversedSubkeys,false),CHAR_LEN ).trim(); } /** * 分组加密 * @param text 明文 * @return 密文 */ @Override public String encrypt(String text) { StringBuilder sb = new StringBuilder(); // DIV_LEN * CHAR_LEN = 64 // 根据DIV_LEN进行分组,如CHAR_LEN=16位,那么就每4个字符一组 int length = text.length()% DIV_LEN == 0 ? text.length()/DIV_LEN : (text.length()/DIV_LEN + 1); for (int i = 0; i<length; i++) { int startIndex = i * DIV_LEN; int endIndex = (startIndex + DIV_LEN) > text.length() ? text.length() : (startIndex + DIV_LEN); String str1 = text.substring(startIndex, endIndex); //尾部填充 while (str1.length() < DIV_LEN) { str1 += " "; } sb.append(baseEncrypt(str1)); } return sb.toString().toLowerCase().trim(); //注意,加密后一定要为小写,大写后会出错 } /** * 加密(每个密文都是64位) * @param text * @return */ private String baseEncrypt(String text) { //获取16组密钥 if (subKeys == null || subKeys.isEmpty()) { subKeys = subKeyObj.generateKey(); } //16次循环加密 return EncodeUtil.binaryToHexStr( loops(text, subKeys, true) ).trim(); } /** * 16轮循环加密 * @param step1Result 初始置换后的结果 * @param subKeys 16组子密钥 * @param isEncrypt 是否加密 * @return 循环加密结果 */ private String loops(String text, List<String> subKeys, boolean isEncrypt) { //1.初始置换 String str64bit = text; if (isEncrypt) { str64bit = EncodeUtil.strtoBinary(text,CHAR_LEN); } str64bit = swap(str64bit, transferTable); if (str64bit.length() != 64) { throw new IllegalArgumentException("初始置换后的结果不为64位"); } if (subKeys.size() != 16) { throw new IllegalArgumentException("加密密钥组数不为16组"); } //主体部分 String leftPart = str64bit.substring(0,32); //高位 String rightPart = str64bit.substring(32); //低位 for (String subKey: subKeys) { //右半边参与f函数运算 String temp = rightPart; //获取f函数结果 String fResult = fFunction(rightPart,subKey); //f函数结果与左半部分进行异或运算 rightPart = xor(fResult, leftPart); //左右交换 leftPart = temp; } //逆初始置换 return swap(rightPart+leftPart, transferReverseTable); } /** * f函数 * @param str32Bit 右半部分 * @param subKey 子密钥 * @return f函数结果 */ private String fFunction(String str32Bit, String subKey) { //1. 扩展运算,将rightPart32位转成48位 String str48Bit = swap(str32Bit, transferExtendTable); //2. 与密钥进行异或运算 String result = xor(str48Bit, subKey); char[] res = result.toCharArray(); //3. s盒运算 String[] sBoxTmp = new String[8]; StringBuilder sBoxResult = new StringBuilder(); //p盒运算用 for(int i=0; i<sBoxTmp.length; i++) { //每6位为一组输入(首位和末尾位为行索引,中间四位为列索引) int rowNb = Integer.valueOf( EncodeUtil.binaryToDec(res[i*6] + "" + res[i*6 + 5]) ); int colNb = Integer.valueOf( EncodeUtil.binaryToDec(res[i*6 + 1] + "" + res[i*6 + 2]+ res[i*6 + 3]+ res[i*6 + 4]) ); sBoxTmp[i] = EncodeUtil.decToBinary(sBox[i][rowNb][colNb]+"",4); } for(String res1: sBoxTmp) { sBoxResult.append(res1); } //4. p盒置换运算 return swap(sBoxResult.toString().trim(),pTransferTable); } /** * 异或运算 * @param text1 text1 * @param text2 text2 * @return */ private String xor(String text1, String text2) { if (text1 == null || text2 == null || text1.length() != text2.length()) { throw new IllegalArgumentException("异或运算失败"); } StringBuilder sb = new StringBuilder(); for (int i = 0; i < text1.length();i++) { char ch1 = text1.charAt(i); char ch2 = text2.charAt(i); sb.append((ch1) ^ (ch2)); } return sb.toString().trim(); } /** * 置换运算 * @param text 文本 * @param table 置换运算表 * @return 置换运算后结果 */ private String swap(String text,int[][] table) { char[] chs = text.toCharArray(); StringBuilder sb = new StringBuilder(); int rowNb = table.length; int colNb = table[0].length; for (int i = 0; i < rowNb * colNb;i++) { sb.append(chs[table[i/colNb][i%colNb] - 1]); } return sb.toString().trim(); } public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException { /** * desutil使用方法 * 1. 使用base64编码字符串 * 2. 使用des加密,获得16进制字符串 */ DesUtil util = new DesUtil(); String result = util.encrypt("{"code":200,"message":"成功!","data":{"id": "2103813902831"}}"); System.out.println("encrypt result=" + result); System.out.println("decrypt result = " + util.decrypt(result)); } }
存在的不足
- 密钥较短(64位),安全性能较差,很容易被破解
- 加密后文本较长
- 处理速度较慢
后续改进方案
- 缩短加密后文本长度
- 尝试使用多线程处理,加快处理速度。
- 尝试更长密钥的版本。
最后
以上就是刻苦电源最近收集整理的关于程序猿成长之路之密码学篇-DES算法详解的全部内容,更多相关程序猿成长之路之密码学篇-DES算法详解内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复