流密码: 传输过程中数据流的每一位都被加密, 密钥流需要提前通过某种安全的方式提供给双方. 而处于实用的原因, 后来我们可以通过共享的短密钥与约定的算法来在发送方和接收方产生相同的密钥流来进行加密, 这样肯定是一种不错的方法.
分组密码: 将明文的一个分组作为加密的对象, 与流密码相比就是每次加密的单位大小不同. 典型的分组大小是64位, 128位, 256位等.
扩散: 使明文的统计特征消散在密文中
混淆: 使密文的统计特征与密钥的取值之间的关系更加模糊
Feistel将一个分组分为等长的两部分(L0和R0), 经过一轮的迭代分组会变为L1和R1, 经典的方法是进行16轮迭代, 所以也就是生成L16和R16. 解密就是这个迭代的逆过程.
下面的方程解释迭代的过程
其中 Ki K i 是第i轮的密钥, F是一种对输入的处理方法, 这个处理方法相对比较复杂, 在本文的后面会展开来说
参考了Apollon_krj的博客, 很好地解释了子秘钥产生的过程
首先我们给出两张流程图, 和之前的Feistle加密一样都是分组交替加密, 但是DES又引入了其他的机制, 接下来我们将一部分一部分地展开来讲
我们先从明文被加工的过程讲起, 这个过程就像经历一条生产流水线一样
那么你可能会问了, 初始置换如何进行的? 函数F内部是怎么样进行处理的? 末置换是怎么样进行处理的? 不要着急, 我们接下来就会一个一个地解答你的问题
比如我们使用如下的矩阵来将64位的明文进行初始置换和末置换
我们发现第一行第一列为40, 也就是说分组A的第1位是分组P的第40位, 我们还发现第一行第二列为8, 也就是说分组A的第2位是分组P的第8位, 以此类推
F函数比较复杂, 但是我们还是来一步一步地来分解, 首先给出其流程图
我们发现, 对于R(i-1), 他经历了如下几个过程
看到这么复杂的过程是不是有点晕, 不慌, 我们还是一步一步分解
通过如图的扩展E置换的矩阵, 经过类似于初始置换的映射方法进行扩展, 将32位的串A扩展为48位的串B
首先由于DES是16轮循环,所以需要由64bit的随机密钥Key生成16个子密钥Ki(i从0~15),Key共64bit,但是其每个字节的最后一位都用不到(即第8、16、24、32、40、48、56、64位共8位),所以先通过初始置换将64bit的密钥转换为56bit。而转换是根据密钥转换表(编程时一系列表均用数组来存储)来操作的,如下所示:
该表共有56个元素(可以看到不包含8、16、24、32、40、48、56、64),代表了转换后的56bit的位置(即output的下标)。
比如:第1位(下标为0,位置为1)的值为57, 则获取原来的第57位的bit值(0或1),作为置换后的第1位的bit值。依次类推
经过置换的key变为56bit,该56bit分为左右两半部分:left_key和right_key,各28bit,然后左右两部分分别循环左移一定位数n。n的大小根据这是第几轮来决定,如下表所示(最多循环左移两位,最少一位):
经过移位的左右两部分合并为56bit,然后经过压缩置换将56bit压缩为48bit,则产生一个子密钥Ki,经过16轮循环产生16个子密钥(对应DES结构图)。而压缩置换的压缩表如下:
S盒的作用是什么? 那就是将48位串压缩为32位串.
其原理图如图
可以看到一个S盒里有8个S-BOX, 一个盒子对应着一个特殊的矩阵, 比如如下给出了8个盒子各自的矩阵
对于其中的一个矩阵, 通过如下方式压缩
我们可以看到, 每个6位串的第1位和第6位合起来决定选择矩阵中的第几行, 中间四位决定选择第几列, 这样就保证了之前的扩展位在之后的压缩中会被舍弃而不会影响到数据的正确性.
关于S-box有以下几点需要关注
P盒的作用是什么? 那就是将32位串映射为32位串.
这个映射的过程通过如下的矩阵来实现