java des加密_对称密码——DES加密算法

前言

  1. 本篇博文将介绍对称密码算法中的DES密码的算法原理与代码实现(Java)

DES算法原理

DES加密算法是 对称加密 算法(加密和解密使用同一个密钥)中的一种,DES也是 分组密码 ,以64位为分组对明文进行加密。

DES算法会对明文进行16轮的迭代加密,具体的算法过程可以看下面这图(来自文末参考博文中的图,做了一些修改)。看一遍有点绕就那笔跟着走一遍。

91ad6b63a55a3794abc196f87ef8c4be.png

下面这张图是每次迭代的的一个提取,我们从中可以直接观察到的就是 迭代的两个规律

Li = Ri-1Ri = Li-1 ^ F(Ri-1, Ki)

上一轮的输出作为下一轮加密的输入(也就是迭代的过程)。同样, 子密钥也是迭代产生

cfa59bc1fb4a51e143b412fc7075064b.png

在总体概览了一遍后,我们可以将DES算法分为3部分来讲解。从第一张图从右往左,轮子密钥(子密钥)的生成、F函数的实现以及16次迭代的过程。

子密钥的产生

4ecd75c6c7e2b8e017c0571814ef574c.png

如图上的流程图所示,将所给的 初始64位密钥(若是密钥不足64位则前面加0补充至64位),经过PC-1置换压缩成56位 。然后 分成左右28位 ,表示成C0, D0。C0和D0按照循环左移表来分别循环左移,此处是第一次循环,所以循环左移1次,生成C1和D1。然后C1和D1合并成56位密钥 经过PC-2置换压缩成48位 的K1。

K2的生成过程:C1和D1分别循环左移1次,然后合并经过PC-2置换压缩成K2。Ki的生成就为Ci-1和Di-1分别循环左移,然后合并经过PC-2置换压缩而成。

PC-1 置换表 PC-2置换表 循环左移表

//PC-1置换表private int[] PC1={ 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, 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};//PC-2置换表 private int[] PC2={ 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};//循环左移次数表private int[] leftTable = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};

F函数的原理

F函数的内部还是比较复杂,不过问题不大。我们按照F函数内部执行顺序来可以分为以下几步:

  • Ri-1做一个E扩展,从 32位扩展成48位
  • Ri-1与Ki异或运算,然后将异或运算的结果 经过S盒选择压缩成32位
  • 从S盒出来的32位结果再经过P置换,就得到最终的32位Ri

Ri-1做扩散选择的表如下:

//E扩展private int[] ETable={ 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};

从S盒出来的32位结果经过的P表如下:

//P置换private 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};

在这三步中最为机密的就是S盒的选择压缩了。S盒是如何实现选择压缩呢?我们就要知道S的结构了。

S盒的结构

8a2a242b6c391f50da3e6614d7eae3fe.png

我们可以看出,进入S盒后将Ri-1与Ki异或的值分成8组,每组6位,分别进入S1-S8盒,然后从每个盒中出4位,合并成32位的结果。

若是还想探究6位变成4位是如何的变换的,就需要看下面这点介绍:

9323430da179d73623fc65f9c3464abb.png

我们以进入S!盒为例,假设进入的6位二进制数为101001,我们一般将 第一位和最后一位(从左到右)作为行坐标,中间四位作为纵坐标 找值。11即3行,0100即4列(从0开始编号),最后选出的值就为4,四位二进制表示则为0100。

16次的迭代加密

最初我们需要将初始的明文做一个IP置换,然后分成左右各32位即L0 R0,带入L0、R0去计算L1和R1。

16次迭代的规律为:

Li = Ri-1Ri = Li-1 ^ F(Ri-1, Ki)

最后,L16与R16直接交换赋给L17和R17(L17=R16, R17=L16),然后L17与R17合并后通过IP逆置换生成最终的密文。

以上,便是加密过程,解密可以说是加密的逆向过程。解密为何反向就可以解密,还需要各位看官另觅资料~

DES算法Java实现(完整)

package symmetricipher;/** * @description: 代码实现Des算法加解密* @author sakura * @date 2019年3月25日 下午12:52:21 *//* * 1.主要的一个迭代公式 Li=Ri Ri = Li-1 ⊕F(Li-1,Ki) * 2.整体可以分为 加解密运算 F函数的处理 子密钥的产生 * 3.子秘钥产生:64位经过PC-1密钥置换成56位 分为Ci Di左右各28为位 然后根据循环左移表来左移 最后经过PC-2置换成48位的密钥Ki * 4.F函数的处理:Li-1(32位)经过E盒扩展成48位; 48位的Li-1与 子秘钥Ki进行异或 ; * 异或的结果经过S盒(8个盒子 6进4出)生成32位;32位再经过P盒转换成最后32位F函数处理后的结果 * 5.加解密运算这边:先将明文做一个IP置换,然后将64位分成左右32位L0,R0 然后开始迭代 ;到第16次,做IP逆置换生成最终的密文 *  * 6.解密运算: * 加密反过来 *  */public class DES { //初始IP置换 private 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}; //IP逆置换 private int[] IP1={ 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};  //E扩展 private int[] ETable={ 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 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};  //S盒 private static final 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 } } };  //PC-1置换表 private int[] PC1={ 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, 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};  //PC-2置换表  private int[] PC2={ 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};  //循环左移次数表 private int[] leftTable = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};  //加密轮数16轮 private static final int LOOP = 16; private String[] keys = new String[LOOP]; private String[] pContent; private String[] cContent; private int originLength; //初始明文长度  //16个子密钥 private int[][] subKey = new int[16][48]; //存储16次的子密钥 private String content; private int pOriginLegth; //明文初始长度?  //构造函数 public DES(String key, String content) { this.content = content; pOriginLegth = content.getBytes().length; generateSubKey(key); }  //主函数入口 public static void main(String[] args) { String plainText = "SakuraOne"; System.out.println("明文: " + plainText); String key = "IAMKEY";  DES des = new DES(key,plainText);  byte[] c = des.group(plainText.getBytes(), true);//加密 System.out.println("密文:" + new String(c));  byte[] p = des.group(c, false); //解密 byte[] pd = new byte[plainText.getBytes().length]; System.arraycopy(p, 0, pd, 0, plainText.getBytes().length); System.out.println("解密后的明文:" + new String(pd));  }  /** *拆分分组 */ public byte[] group(byte[] plainText, boolean decryption) { //填充明文长度为64位的整数 originLength = plainText.length; int gNum; int rNum; gNum = originLength/8; rNum = 8-(originLength-gNum*8); byte[] pPadding; if(rNum<8) { pPadding = new byte[originLength+rNum]; System.arraycopy(plainText, 0, pPadding, 0, originLength); for(int i=0; i-1; i--) { loop(pIP, i, decryption, keysArray[i]); } }  /*===========IP逆置换=============*/ int[] c = new int[64]; for(int i=0; i

小结

这学期在上密码学的课程,课堂上听老师讲了对称加密算法中的DES算法,一直觉得挺绕。在上完实验课后勉强对其算法流程有了一个清晰认识。后面想着用算法实现或许会更明了, 于是写代码实现。确实,自己实现一遍后对算法会更理解。粗糙地记录了下DES加解密的实现,以供参考。解密算法的验证需要大家另觅资料,本篇博文就不再介绍了~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值