序言

为了加深对DES加密算法的理解,lvchen很贴心地布置了一道手算DES加密结果的题,从昨晚回寝算到今天中午才写完,主要是花时间把代码逻辑实现了一遍,加深记忆也便于后续重复使用。
笔者参考了经典的DES算法详解这篇博客的解析,博主翻译得通俗易懂,内容详实,应该算是能找到的DES讲解中说得最明白的一个版本了。
本文主要是以密码编码学与网络安全——原理与实践_第6版的课后习题3.11为例,实现DES加密算法中的

  • 56位密钥选取算法:PC1置换
  • 48位子密钥生成算法:PC2置换
  • 28位半密钥的循环左移算法
  • 64位明文初始置换算法:IP置换
  • 32位半明文扩展置换算法:E扩展函数
  • S盒置换算法:8个S-Box
  • P置换算法:P置换

习题3.11

笔者在百度文库里找到了这本教材的习题答案https://wenku.baidu.com/view/2079f354ff00bed5b9f31df5.html#,不过并不是很全,可能是教材版本不同,但是有这道习题的答案,所以正好可以拿来验证代码逻辑写得是否正确。

习题3.11答案

解题代码

DES加密算法的流程总结起来简单概括如下,详细过程可见经典的DES算法详解(下面图中置换阵里的数字代表的都是需要置换的串的每个位置的索引):

  • (1)将64位明文输入后先进行初始置换IP,再平均分割成左右各32位的两块L0L_0L0​和R0R_0R0​,将右边这块32位的明文通过扩展置换E增长到48位;

  • (2)将64位密钥输入后先经过PC1置换得到的56位密钥,再平均分割成左右各28位的两块,每块分别进行循环左移(步长由当前轮数决定),再将循环左移后的两块拼接起来得到新的56位密钥,最后经过PC2置换变成48位子密钥;

  • (3)将(1)(2)张得到的48位扩展明文与48位子密钥进行异或运算得到48位的一串字节AAA;

  • (4)将(3)中得到的结果分成6位一组,共计8组的8串字节,输入到8个S盒子中进行置换,置换算法如图所示

  • (5)8个S盒子的输出拼接起来就是32位的字节,对这个32位的字节用置换阵P再做一次置换

  • (6)最终计算(5)中输出的32位字节和32位字节的L0L_0L0​进行异或运算的值,将它作为R1R_1R1​输出到下一轮,R0R_0R0​则作为L1L_1L1​进入直接进入下一轮(习题中到L1L_1L1​R1R_1R1​就结束了,直接输出L1L_1L1​和R1R_1R1​拼接起来的结果就是密文)

  • (7)这样经过16轮后将L16与R16L_{16}与R_{16}L16​与R16​拼接,做最后一个初始逆置换(与初始置换相反的置换),得到最终的输出结果即为密文。

关于习题3.11的解题代码如下所示,写得很低效,仅供做题参考。事实上即便正确实现标准加密协议的算法逻辑也不要去用于实际加密,一定要用标准加密库如openssl或者keyczar,因为个人写的代码总是有除了逻辑外的漏洞可循(比如可以被计时攻击或者padding oracle或者更高端的攻击方法攻破)。

# -*- coding: UTF-8 -*-
# @Author: caoyang
# @Email: lzwcy110@163.com
# DES加密算法相关函数及密码编码学与网络安全(第6版)课后习题3.11答案import numpy as npIP = [                                                                     # 初始置换阵[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_1 = [                                                               # PC1置换阵: 64位-->56位, 去除8,16,24,32,40,48,56,64[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 = [                                                               # PC2子密钥生成置换阵: 56位-->48位, 去除9,18,22,25,35,38,43,54[14,17,11,24,1,5],[3,28,15,6,21,10],[23,19,12,4,25,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],
]E = [                                                                  # 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],
]S_BOX = [                                                              # 八个S盒子: 构成加密的非线性[[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],],                                                                    # S1[[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],],                                                                     # S2[[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],],                                                                     # S3[[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],],                                                                     # S4[[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],],                                                                     # S5[[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],],                                                                     # S6[[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],],                                                                     # S7[[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],],                                                                     # S8
]P = [                                                                  # 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],
]CYCLE_LEFT_STEP = [1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1]                        # 16轮循环左移中每轮应当左移的步长def xor(a,b):                                                            # 异或函数_a = np.array(a).reshape(-1,)                                        # 转为numpy格式便于操作_b = np.array(b).reshape(-1,)                                       # 转为numpy格式便于操作assert _a.shape[0]==_b.shape[0]                                        # 异或运算要求字节长度相同res = []for i,j in zip(_a,_b):res.append(i^j)return np.array(res)def get_key56(key64):                                                   # 从64位原始输入密钥生成加密操作只需要的56位密钥_key64 = np.array(key64)                                            # 转为numpy格式便于操作_key64 = _key64.reshape(-1,)                                        # 转为一维向量便于操作assert _key64.shape[0]==64                                            # 输入应当为64位密钥pc_1 = np.array(PC_1)                                              # 转为numpy格式便于操作pc_1 -= 1                                                           # 真实的索引都是从零开始算起的, 所以把转换矩阵元素减一对应上从零开始计算的索引res = []for row in pc_1:temp = []for i in row: temp.append(_key64[i])res.append(temp)key56 = np.array(res)c = key56[:4,:]                                                      # 前半部分d = key56[4:,:]                                                      # 后半部分return key56,c,ddef get_key48(key56):                                                     # 从56位密钥生成48位子密钥算法_key56 = np.array(key56)                                             # 转为numpy格式便于操作_key56 = _key56.reshape(-1,)                                        # 转为一维向量便于操作assert _key56.shape[0]==56                                            # 输入应当为56位密钥   pc_2 = np.array(PC_2)                                               # 转为numpy格式便于操作pc_2 -= 1                                                           # 真实的索引都是从零开始算起的, 所以把转换矩阵元素减一对应上从零开始计算的索引res = []for row in pc_2:temp = []for i in row: temp.append(_key56[i])res.append(temp)key48 = np.array(res)c = key48[:4,:]                                                      # 前半部分d = key48[4:,:]                                                      # 后半部分return key48,c,ddef cycle_left(key,step=1):                                              # 循环左移: 默认左移一格_key = np.array(key)                                                 # 转为numpy格式便于操作shape = _key.shape                                                  # 记录下原始的密钥shape, 便于左移后还原成相同shape返回_key = _key.reshape(-1,)                                             # 转为一维向量便于操作assert _key.shape[0]==28                                          # 循环左移的密钥长度应当是28new_key = _key.tolist()[1:]                                            # 去掉第一个位置的元素new_key.append(_key[0])                                                 # 把它放到末尾即可实现循环左移return np.array(new_key).reshape(shape)                                 # 还原成于输入密钥shape相同的密钥返回def initial_permute(plant_text):                                      # 初始置换IP_plant_text = np.array(plant_text)                                     # 转为numpy格式便于操作_plant_text = _plant_text.reshape(-1,)                              # 转为一维向量便于操作assert _plant_text.shape[0]==64                                       # 明文长度应当是64ip = np.array(IP)                                                   # 转为numpy格式便于操作ip -= 1                                                                 # 真实的索引都是从零开始算起的, 所以把转换矩阵元素减一对应上从零开始计算的索引res = []for row in ip:temp = []for i in row: temp.append(_plant_text[i])res.append(temp)res = np.array(res)l0 = res[:4,:]r0 = res[4:,:]return res,l0,r0def extend_permute(half_plant_text):                                   # 扩展置换E_half_plant_text = np.array(half_plant_text)                        # 转为numpy格式便于操作_half_plant_text = _half_plant_text.reshape(-1,)                    # 转为一维向量便于操作assert _half_plant_text.shape[0]==32                              # 输入应当为32位的密文(一半的密文)res = []index = 0for row in E:left_index = row[0]-1                                          # 扩展在左边的元素索引right_index = row[-1]-1                                            # 扩展在右边的元素索引res.append([_half_plant_text[left_index],_half_plant_text[index],_half_plant_text[index+1],_half_plant_text[index+2],_half_plant_text[index+3],_half_plant_text[right_index],])index += 4return np.array(res)def sbox_replace(xor_res):                                                # S盒子代换_xor_res = np.array(xor_res)                                        # 转为numpy格式便于操作_xor_res = _xor_res.reshape(-1,)                                    # 转为一维向量便于操作assert _xor_res.shape[0]==48                                      # S盒子对长度为48的字节进行操作res = []for i in range(0,48,6):temp = _xor_res[i:i+6]                                          # 每次取出六位row_index = temp[0]*2+temp[5]                                     # 行索引column_index = temp[1]*8 + temp[2]*4 + temp[3]*2 + temp[4]*1   # 列索引binary_string = bin(S_BOX[int(i/6)][row_index][column_index])[2:].zfill(4)temp = list(map(int,list(binary_string)))res.append(temp)return np.array(res)def p_permute(s_values):_s_values = np.array(s_values)                                       # 转为numpy格式便于操作_s_values = _s_values.reshape(-1,)                                  # 转为一维向量便于操作assert _s_values.shape[0]==32                                         # 输入应当为56位密钥   res = []for row in P:temp = []for i in row: temp.append(_s_values[i-1])res.append(temp)return np.array(res)       if __name__ == "__main__":'''# 示例数据: 可对比https://blog.csdn.net/z784561257/article/details/78174106key64 = ["0001","0011","0011","0100","0101","0111","0111","1001","1001","1011","1011","1100","1101","1111","1111","0001",]key64 = list(map(lambda x: list(map(int,list(x))),key64))plant_text = [0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0,0,0,1,0,1,0,1,1,0,0,1,1,1,1,0,0,0,1,0,0,1,1,0,1,0,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,1,1,]'''# 习题3.11的密钥与明文数据key64 = [[0,0,0,0],[0,0,0,1],[0,0,1,0],[0,0,1,1],[0,1,0,0],[0,1,0,1],[0,1,1,0],[0,1,1,1],[1,0,0,0],[1,0,0,1],[1,0,1,0],[1,0,1,1],[1,1,0,0],[1,1,0,1],[1,1,1,0],[1,1,1,1],]plant_text = [0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0,0,0,1,0,1,0,1,1,0,0,1,1,1,1,0,0,0,1,0,0,1,1,0,1,0,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,1,1,]# -----------------------------------------------------------------# a. 推导第一轮的子密钥K1key56,c0,d0 = get_key56(key64=key64)#print(key56)#print("#"*64)c1 = cycle_left(c0)d1 = cycle_left(d0)key56_new = np.vstack([c1,d1])#print(key56_new)#print("#"*64)key48,c,d = get_key48(key56=key56_new)print(key48)                                                         # 第一轮子密钥print("#"*64)# -----------------------------------------------------------------# b. 推导L0,R0res,l0,r0 = initial_permute(plant_text)#print(res)#print("#"*64)print(l0)print("-"*64)print(r0)print("#"*64)# -----------------------------------------------------------------# c. 扩展R0得到E[R0]ex_r0 = extend_permute(r0)print(ex_r0)print("#"*64)# -----------------------------------------------------------------# d. 计算A = E[R0] XOR K1A = xor(extend_permute(r0),key48)print(A)print("#"*64)# -----------------------------------------------------------------# e. 把d.的48位结果焚城6位一组(数据)的集合并求对应S盒代替的值s_values = sbox_replace(A)print(s_values)print("#"*64)# -----------------------------------------------------------------# f. 将e.的结果连接起来获得一个32位的结果BB = s_values.reshape(-1,)print(B)print("#"*64)# -----------------------------------------------------------------# g. 应用置换获得P(B)p_b = p_permute(B)print(p_b)print("#"*64)# -----------------------------------------------------------------# h. 计算R1 = P(B) XOR L0r1 = xor(p_b,l0)print(r1)print("#"*64)# -----------------------------------------------------------------# i. 写出密文l1 = r0.reshape(-1,)cipher = np.hstack([l1,r1])print(cipher)

主程序部分将习题a-j的结果都打印在了控制台里,对比上面的答案截图可以说明结果没有错误。

[0 0 0 0 1 0][1 1 0 0 0 0][0 0 1 0 0 1][1 0 0 1 1 1][1 0 0 1 1 0][1 1 0 1 0 0][1 0 0 1 1 0][1 0 0 1 0 1]]
################################################################
[[1 1 0 0 1 1 0 0][0 0 0 0 0 0 0 0][1 1 0 0 1 1 0 0][1 1 1 1 1 1 1 1]]
----------------------------------------------------------------
[[1 1 1 1 0 0 0 0][1 0 1 0 1 0 1 0][1 1 1 1 0 0 0 0][1 0 1 0 1 0 1 0]]
################################################################
[[0 1 1 1 1 0][1 0 0 0 0 1][0 1 0 1 0 1][0 1 0 1 0 1][0 1 1 1 1 0][1 0 0 0 0 1][0 1 0 1 0 1][0 1 0 1 0 1]]
################################################################
[0 1 1 1 0 0 0 1 0 0 0 1 0 1 1 1 0 0 1 1 0 0 1 0 1 1 1 0 0 0 0 1 0 1 0 1 11 0 0 1 1 1 1 0 0 0 0]
################################################################
[[0 0 0 0][1 1 0 0][0 0 1 0][0 0 0 1][0 1 1 0][1 1 0 1][0 1 0 1][0 0 0 0]]
################################################################
[0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 0 1 1 0 1 1 0 1 0 1 0 1 0 0 0 0]
################################################################
[[1 0 0 1 0 0 1 0][0 0 0 1 1 1 0 0][0 0 1 0 0 0 0 0][1 0 0 1 1 1 0 0]]
################################################################
[0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0 1 1 1 0 1 1 0 0 0 1 1 0 0 0 1 1]
################################################################
[1 1 1 1 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 1 0 0 0 0 1 0 1 0 1 0 1 0 0 1 0 1 11 1 0 0 0 0 1 1 1 0 0 1 1 1 0 1 1 0 0 0 1 1 0 0 0 1 1]

分享学习共同进步

【日常】DES加密算法python实现_以密码编码学与网络安全——原理与实践(第六版)课后习题3.11为例相关推荐

  1. 密码编码学与网络安全——原理与实践(第八版)——第一章:信息与网络安全概念

    密码编码学与网络安全--原理与实践(第八版) 第一章:信息与网络安全概念 1.1网络空间安全.信息安全和网络安全 1.2OSI安全架构 1.3安全攻击 1.4安全服务 1.5安全机制 1.6密码学 1 ...

  2. 【密码学Sage代码】椭圆曲线加密/解密(基于《密码编码学与网络安全——原理与实践(第七版)》)

    [密码学Sage代码]椭圆曲线加密/解密(基于<密码编码学与网络安全--原理与实践(第七版)>) 教材内容: 实践的Sage代码: #[静水流深Sage代码]使用椭圆曲线密码体制进行加密/ ...

  3. 密码编码学与网络安全———原理与实践(第八版)第三章笔记

    第3章 传统加密技术 学习目标 简要介绍对称密码的主要概念. 解释密码分析和穷举攻击的差异. 理解单表代替密码的操作. 理解多表代替密码的操作. 简要介绍Hill密码. 目录 第3章 传统加密技术 3 ...

  4. 密码编码学与网络安全----原理与实践(第八版)---第9章笔记

    第九章 公钥密码学与RSA 学习目标: 概述公钥密码体制的基本原理. 阐述公钥密码体制的两个不同应用. 列举和解释公钥密码体制的要求. 概述RSA算法. 理解计时攻击. 总结算法复杂性的相关问题. 公 ...

  5. 《密码编码学与网络安全》William Stalling著---学习笔记(三)【知识点速过】【网络安全与Internet安全概览】

    提示:博文有点长,请保持耐心哦~ 前两篇文章: <密码编码学与网络安全>William Stalling著-学习笔记(一)[知识点速过][传统密码+经典对称加密算法+经典公钥密码算法+密码 ...

  6. 密码编码学与网络安全(2):对称密码之传统加密技术

    对称密码之传统加密技术 关于对称加密 对称密码模型 密码编码学 密码分析学与穷举攻击 古典加密算法 代替技术 置换技术 转轮机 隐写术 关于对称加密 对称加密,也称为传统加密或单密钥加密,是20世纪7 ...

  7. 《密码编码学与网络安全》William Stalling著---学习笔记(二)【知识点速过】【数字签名+密钥管理分发+用户认证】

    提示:博文有点长,请保持耐心哦~ 前一篇文章: <密码编码学与网络安全>William Stalling著-学习笔记(一)[知识点速过][传统密码+经典对称加密算法+经典公钥密码算法+密码 ...

  8. des加密算法python代码_python des加密算法代码(pydes模块加密)

    python加密解密模块:pyDES模块,用来提供 DES.Triple-DES 的加密算法. 专题教程: DES加密算法,DES加密解密 python des加密解密算法 例子,Python DES ...

  9. 密码编码学与网络安全期末考试笔记

    文章目录 M 记忆的部分 1 计算机安全核心的三个目标:CIA 三元组 2 一次一密 OTP(one time password) 3 对称密码与非对称密码的对比 4 分组加密工作模式 5 AES(A ...

  10. 《Python语言程序设计》王恺 机械工业出版社 第六章课后习题答案

    第六章 字符串 6.5 课后习题 (1)Python 中,创建字符串时,可以使用单引号.双引号和三引号 (2)Python 中,使用字符串的 split 方法可以按照指定的分隔符对字符串进行切割,返回 ...

最新文章

  1. Linux之vim中翻页的命令
  2. pjsip学习笔记二
  3. 30道最常问的Java基础面试题
  4. yum安装时出现:Cannot retrieve metalink for repository: epel. Please verify its path and try again...
  5. 分享到系统面板_win7电脑没有nvidia控制面板怎么办【解决方法】
  6. 《Python编程从入门到实践》记录之range、min、max、sum函数
  7. oracle日期类型格式转换,Oracle日期类型转换格式
  8. 3 个很酷的 Python 库,可以节省您的时间和精力
  9. 模拟电子技术基础-什么是放大?
  10. word2003邮件合并后保留小数点位数问题
  11. Unity手机震动,Unity -> android 震动
  12. 全面理解-Flutter(万字长文,【性能优化实战】
  13. 一次与笨神,阿飞近距离接触修改JVM
  14. java基础之this关键字_繁星漫天_新浪博客
  15. 鲜檬“0元旅拍”出圈,婚纱摄影洗牌“加速”
  16. 昨晚,我用python帮隔壁小姐姐P证件照 自拍,然后发现。。。
  17. 基于Cocoa And Web Kit框架的safari插件开发
  18. 对话系统-“问答型”单轮对话:FAQ检索式对话系统【步骤:①用户意图判断、②文本检索召回、③文本匹配计算排序】【搜索引擎的最终形态】
  19. 山东理工大学计算机学院答辩,计算机学院毕业设计规范与流程-山东理工大学-计算机科学与技术学院.doc...
  20. 高焕堂《嵌入式UML设计》读书笔记_第三章

热门文章

  1. 透过华为军团看科技之变(五):智慧园区
  2. FL studio 20简易入门教程 -- 第五篇 -- 乐器调制界面
  3. 图像的灰度化和二值化
  4. 新建文件没有word、ppt、excel,office图标显示为白色,不能正常显示
  5. android ndk adk 旧版本下载
  6. 分布式机器学习第3章 分布式机器学习框架
  7. 重症监护室(ICU)100260
  8. 在云服务器上搭建Kali系统-最新kali2021.3版本+避坑指南
  9. 离散数学:快速又准确地求解主合取范式和主析取范式 (配凑大法好)
  10. SQLite的主键外键