其实有了前一篇文章《DES加密算法学习前奏》做为基础之后,要实现DES算法就是很容易的事了。
不过为了是自己不过于闭门造车,我还是从网上找了找源代码,有用java写的,有用C++写的,不过所有代码貌似都是一样的。为啥说是一样的呢?一开始写一个类,然后把所有的方法往类里面添,额,我猜测如果不是作者功力很高的话,很难一次就把这个给实现了。并且如果读者功力不是很高的话(譬如说我这样的),也是很难理解其中的调用关系的。还有一点值得一提的是网上流传的方法似乎都是可以直接对文本加密的,所以对于想研究算法的人来说,这无疑是个悲剧,你想呀,本来你想知道1+1=?,我告诉你说1+1+537674-637674+100000=2。这很纠结的。
由以上原因可以得出,我这里只是简单的把核心算法写了一下,如果大家要用它来加解密的话,需要自己扩展。当然,我也会继续扩展的。
好了,说算法,因为用的java实现,为了不至于写的时候乱了手脚,先把类图整理出来,然后就着图来说:
可以看到,我一共是分了三个类,一个接口。IConst接口中放的都是置换表。DESFunction类其实就是前篇文章的一个实现,可以说是DES基础方法类,里面包含DES实现的基本算法。DES类就是简单的调用了一下DESFunction类,组合其中的方法进行加密解密,其实DES中的两个方法decryption()和encryp()完全可以写成一个,因为其中的代码几乎是完全一样,不过为了分析方便,我还是给分开了写了。
关于这个貌似就这么多要说的了,分析好了之后其实很容易。因为源码太长了,所以直接打包上传到空间了,大家自行下载,这里只贴出DES类的源码,因为这个应该是比较重要吧。
package mydes; /** * DES类,用来加密二进制数据 * @author the5fire * blog:http://www.the5fire.net * */ public class DES { private DESFunction desFunction = new DESFunction(); /** * 传进二进制明文,返回DES加密后的密文 * @param M * @return */ public int[] encrypt(int[] M, int[] key) { int[] C = null; int[] M0 = new int[64]; int[][] L0 = new int[17][32]; int[][] R0 = new int[17][32]; int[][] subkey = null; int[] result = new int[64]; subkey = desFunction.getSubkey(key); M0 = desFunction.initReplace(M); for (int j = 0; j < 32; j++) { L0[0][j] = M0[j]; // 明文左侧的初始化 R0[0][j] = M0[j + 32]; // 明文右侧的初始化 } for (int i = 1; i < 17; i++) { int[] tmpR = desFunction.divPlus(L0[i-1], desFunction.coreFunction(R0[i-1], subkey[i-1])); for (int j = 0; j < 32; j++) { L0[i][j] = R0[i-1][j]; R0[i][j] = tmpR[j]; } } //进行赋值,R16放到左侧,也就是前面32位;L16放到右侧,也就是最后32位 for (int i = 0; i < 32; i++) { result[i] = R0[16][i]; } for (int i = 0; i < 32; i++) { result[32+i] = L0[16][i]; } C = desFunction.endReplace(result); return C; } /** * 传进DES加密后的密文,返回二进制明文 * @param C * @return */ public int[] decryption(int[] C, int[] K) { int[] M = null; int[] C0 = new int[64]; int[][] L0 = new int[17][32]; int[][] R0 = new int[17][32]; int[][] subkey = null; int[] result = new int[64]; subkey = desFunction.getSubkey(K); C0 = desFunction.initReplace(C); for (int j = 0; j < 32; j++) { L0[0][j] = C0[j]; // 明文左侧的初始化 R0[0][j] = C0[j + 32]; // 明文右侧的初始化 } for (int i = 1; i < 17; i++) { int[] tmpR = desFunction.divPlus(L0[i-1], desFunction.coreFunction(R0[i-1], subkey[16-i])); for (int j = 0; j < 32; j++) { L0[i][j] = R0[i-1][j]; R0[i][j] = tmpR[j]; } } //进行赋值,R16放到左侧,也就是前面32位;L16放到右侧,也就是最后32位 for (int i = 0; i < 32; i++) { result[i] = R0[16][i]; } for (int i = 0; i < 32; i++) { result[32+i] = L0[16][i]; } M = desFunction.endReplace(result); return M; } }
这里面L0[][]和R0[][]这个二维数组用的不太恰当,比较浪费空间,因为L0[i]和R0[i]只需要负责推导出L0[i+1]和R[i+1]就可以了,后面就不会再用到L0[i]和R0[i]了,这里用递归应该更好一点。不过这样思考起来更直观一点。
最后用书上的例子测试了一下,可以正常加解密。如果其中还有问题的话欢迎大家提醒。
源代码地址:http://u.115.com/file/f465ac9bfe(有效期30天,如果过期了你可以留言告诉我)
这是整个工程的打包,我用的是eclipse。