对称加密算法DES的实现

一、实验目的

1、了解对称密码体制基本原理

2、掌握编程语言实现对称加密、解密

二、实验原理

       DES 使用一个 56 位的密钥以及附加的 8 位奇偶校验位,产生最大 64 位的分组大小。这是一个迭代的分组密码,使用称为 Feistel 的技术,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行“异或”运算;接着交换这两半,这一过程会继续下去,但最后一个循环不交换。DES 使用 16 个循环,使用异或,置换,代换,移位操作四种基本运算。DES算法的入口参数有三个:Key、Data、Mode。Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。

三、实验代码

class DES():# 初始化DES加密的参数def __init__(self,key: str):# 初始数据置换表IP,用于初始IP置换self.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,]# 密钥初始置换表PC_1,用于获得最初的56位密钥self.PC_1 = [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,用于获得子密钥self.PC_2 = [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,]# 密钥每一轮的对应左移位数self.k0 = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, ]# E扩展表,用于将右半部分数据Rn从32位置换成48位self.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盒,将48位数据代替为32位数据self.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,],[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,],]# P盒置换表,S盒代替运算的32位输出按照P盒进行置换self.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,]# 最终置换表IP_1,用于逆置换self.IP_1 = [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,]# 设置密钥self.K = self.convert_to_2(key)# 进制转换——字符串转为二进制def convert_to_2(self, string: str) -> str:# 将字符串转成bytes类型,再转成liststr_list = list(bytes(string, 'utf8'))result = []for num in str_list:# 用bin(num)将当前字节转换为二进制,然后使用[2:]切片操作去掉二进制字符串前面的"0b"标识。# 用zfill(8)函数给二进制字符串添加前导零,确保二进制字符串长度为8位# 一个字节由8个二进制位组成,保持一致性result.append(bin(num)[2:].zfill(8))# 将结果列表中的所有二进制字符串连接return "".join(result)# 进制转换——二进制转成字符串def convert_to_str(self, binary: str) -> str:# 将二进制字符串分组,每8位为一组bin_list = [binary[i:i + 8] for i in range(0, len(binary), 8)]# 存储每个8位二进制数字所代表的整数值list_int = []for b in bin_list:# 将当前8位二进制数转换为对应的十进制整数list_int.append(int(b, 2))# 将整数列表转换为字节序列,再解码得到字符串result = bytes(list_int).decode()return result# 对明文二进制进行分块,每64位为一块def get_block(self, binary: str) -> list:# 首先获取给定二进制字符串的长度len_binary = len(binary)if len_binary % 64 != 0:# 如果不能整除,说明按每64块分块不能刚好分块,需要添加前导零。new_binary = ("0" * (64 - (len_binary % 64))) + binary# 分块return [new_binary[i:i + 64] for i in range(0, len(new_binary), 64)]else:# 能被64整除,就不用补零,直接分块return [binary[j:j + 64] for j in range(0, len(binary), 64)]# 按照给定的置换表进行置换def replace(self, table: str, replace_table: list) -> str:new_table = ""for i in replace_table:# 因为列表的索引是从0开始的,而替换表中的位置索引是从1开始的,所以需要进行减1的操作。new_table += table[i - 1]return new_table# 返回加密过程中16轮的子密钥def get_sonkey(self):# 56位密钥由密钥初始置换表(PC_1)置换默认密钥获得key = self.replace(self.K, self.PC_1)# 将56位的密钥分成两部分,每部分28位left_key = key[0:28]right_key = key[28:56]# 存储子密钥keys = []for i in range(0, 16):# 由轮换表确定当前轮次的移动次数move = self.k0[i]# 对左右部分分别进行移位操作move_left = left_key[move:28] + left_key[0:move]move_right = right_key[move:28] + right_key[0:move]# 更新left_key和right_keyleft_key = move_leftright_key = move_right# 合并形成当前轮次的子密钥move_key = left_key + right_key# 按照密钥压缩置换表(PC_2)进行置换,得到长度为48位的子密钥ki,并将其添加到keys列表中。ki = self.replace(move_key, self.PC_2)keys.append(ki)# 返回加密过程中的16轮子密钥。return keys# 异或操作def xor(self, xor1: str, xor2: str):size = len(xor1)result = ""for i in range(0, size):result += '0' if xor1[i] == xor2[i] else '1'return result# S盒代替def s_box(self, xor_result: str):result = ""# 迭代8轮,每轮处理6位二进制数据for i in range(0, 8):# 将48位数据分为8组,循环进行block = xor_result[i * 6:(i + 1) * 6]# 首尾比特得行数line = int(block[0] + block[5], 2)# 中间四位比特得列数column = int(block[1:5], 2)# 在S盒中查找,将所得转为二进制并通过[2:]切片去除二进制字符串的前缀"0b"res = bin(self.S[i][line * column])[2:]if len(res) < 4:# 如果结果的长度不足4位,则在左边用'0'进行填充res = '0' * (4 - len(res)) + resresult += res# result中存储了经过S盒替换后的32位二进制数据return result# F函数,进行E扩展,与key异或操作,S盒替代及P盒置换操作后返回32位01字符串def F_function(self, right: str, key: str):# 对right进行E扩展e_result = self.replace(right, self.E)# 与key 进行异或操作xor_result = self.xor(e_result, key)# 进入S盒子s_result = self.s_box(xor_result)# 进行P置换p_result = self.replace(s_result, self.P)return p_result# 16轮迭代加密def iteration(self, bin_plaintext: str, key_list: list):# 分组切分left = bin_plaintext[0:32]right = bin_plaintext[32:64]for i in range(0, 16):# L(n) = R(n-1)# R(n) = L(n-1)⊕F(R(n-1),K(n))next_left = rightf_result = self.F_function(right, key_list[i])next_right = self.xor(left, f_result)left = next_leftright = next_right# 最后R在左边,L在右边return right + left# DES加密函数def encrypt(self, plaintext):# 将给定明文转换为二进制plaintext_2 = self.convert_to_2(plaintext)# 将二进制明文分为64位一组的块plaintext_block = self.get_block(plaintext_2)# 存储加密后的分组ciphertext_block = []# 获取生成的16个子密钥列表key_list = self.get_sonkey()for block in plaintext_block:# 初代IP置换replaced_IP = self.replace(block, self.IP)# 16轮迭代操作ite_result = self.iteration(replaced_IP, key_list)# 逆IP置换replaced_IP_1 = self.replace(ite_result, self.IP_1)# 密文块replaced_IP_1添加到ciphertext_block列表中,以便后续拼接ciphertext_block.append(replaced_IP_1)ciphertext = ''.join(ciphertext_block)return ciphertext#DES解密函数def decrypt(self, ciphertext):# 存储解密后的分组plaintext_block = []# 获取生成的16个子密钥列表key_list = self.get_sonkey()# 解密时密钥的使用顺序与加密时的顺序应当相反。key_list = key_list[::-1]# 将二进制密文分为64位一组的块ciphertext_block = [ciphertext[i:i + 64] for i in range(0, len(ciphertext), 64)]for block in ciphertext_block:# 初代IP置换replaced_IP = self.replace(block, self.IP)# 16轮迭代操作ite = self.iteration(replaced_IP, key_list)# 逆IP置换replaced_IP_1 = self.replace(ite, self.IP_1)# 明文块replaced_IP_1添加到plaintext_block列表中,以便后续拼接plaintext_block.append(replaced_IP_1)# 拼接,并移除其中的所有全零块。# 消除加密过程中可能引入的填充块,使得最终的二进制明文表示更加紧凑和直观。plaintext = ''.join(plaintext_block).replace('00000000', '')# 将二进制明文转为字符串返回return self.convert_to_str(plaintext)def main():#select = input("输入1加密;输入2解密;输入3退出程序;请输入:\n")while True:select = input("输入1加密;输入2解密;输入3退出程序;请输入:\n")if select == '1':plaintext = input("输入要加密的明文:")key = input("输入要加密的密钥:")des = DES(key)  # 创建DES对象时传入密钥ciphertext = des.encrypt(plaintext)print("加密得:{}".format(ciphertext))elif select == '2':ciphertext = input("输入要解密的密文:")key = input("输入要解密的密钥:")des = DES(key)  # 创建DES对象时传入密钥plaintext = des.decrypt(ciphertext)print("解密得:{}".format(plaintext))elif select == '3':breakelse:print("重新选择!")select = input("输入1加密;输入2解密;输入3退出程序;请输入:\n")  # 重新获取选择if __name__ == '__main__':main()

 四、运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/17551.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

三十八、Python(pytest框架-上)

一、介绍 框架&#xff08;framework&#xff09;&#xff1a;框架是为解决一类事情的功能集合。 pytest框架&#xff1a;pytest框架是单元测试框架&#xff0c;这是第三方框架想要使用必须要安装&#xff0c;可以使用pytest来作为自动化测试执行框架&#xff0c;用来管理测试…

《Django 5 By Example》阅读笔记:p165-p210

《Django 5 By Example》学习第6天&#xff0c;p165-p210总结&#xff0c;总计46页。 一、技术总结 1.bookmarks项目 (1)登录认证 作者这里使用的是Django自带的auth。 (2)上传头像 图片处理&#xff0c;使用Pillow。 (3)扩展user 扩展user模型与自带的user使用外键进行…

shell基础(3)

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团…

JVM面试题总结

1.介绍一下JVM的内存结构 JDK1.8及以后&#xff0c;JVM主要分为元空间、堆、虚拟机栈、本地方法栈、程序计数器五个部分&#xff0c;另外还有一个直接内存部分&#xff0c;是直接属于操作系统的。 其中元空间、堆是线程共享的&#xff0c;虚拟机栈、本地方法栈、程序计数器是线…

小新Pro 14 AHP9 2024款(83D3)原装oem预装系统Win11恢复安装包下载

适用品牌机型 &#xff1a;LENOVO联想【83D3】 链接&#xff1a;https://pan.baidu.com/s/10RAxNdvYPWJ21b_4--Y7Xw?pwdo5ju 提取码&#xff1a;o5ju 联想原装出厂Windows11系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office365办公软…

【论文笔记】Towards Privacy-Aware Sign Language Translation at Scale

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: Towards Privacy-Aware Si…

Spring:bean的配置

对于bean的配置中&#xff0c;主要会讲解bean基础配置,bean的别名配置,bean的作用范围配置(重点),这三部分内容&#xff1a; bean基础配置 id与class配置 bean的name属性 bean的别名配置 bean作用范围scope配置 scope使用后续思考 介绍完scope属性以后&#xff0c;我们…

贴代码框架PasteForm特性介绍之markdown和richtext

简介 PasteForm是贴代码推出的 “新一代CRUD” &#xff0c;基于ABPvNext&#xff0c;目的是通过对Dto的特性的标注&#xff0c;从而实现管理端的统一UI&#xff0c;借助于配套的PasteBuilder代码生成器&#xff0c;你可以快速的为自己的项目构建后台管理端&#xff01;目前管…

【RK3588 Linux 5.x 内核编程】-内核中的链表(Linked List)及使用

内核中的链表(Linked List)及使用 文章目录 内核中的链表(Linked List)及使用1、Linked List介绍2、Linux内核中的链表3、链表的操作3.1链表初始化3.2 创建节点3.3 添加节点3.4 删除节点3.5 替换节点3.6 移动节点3.7 链表旋转3.8 链表检测3.9 链表分割与合并3.10 链表遍历4、驱…

永夜星河主题特效2(星河背景 + 闪烁文字+点击星星 + 文字弹出特效)

目录 图片展示 星河背景 闪烁文字点击星星 文字弹出特效 特效介绍&#xff1a; 使用方式&#xff1a; 图片展示 星河背景 闪烁文字点击星星 文字弹出特效 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8">&l…

通过JS实现下载图片到本地教程分享

今天分享的这个方法我之前自己试了一下&#xff0c;感觉还行&#xff0c;原理就是通过<a>标签的新增属性实现的&#xff0c;然后可以强制触发下载功能&#xff0c;废话不多说&#xff0c;直接上教程。 首先在HTML写下面的代码: <a href"img.jpg" download…

Harmony错题本--@Preview标注上依然无法预览

初学HarmonyOs开发&#xff0c;写了一个超级简单的组件&#xff0c;但是代码上没有什么问题&#xff0c;DevEco Studio却无法完成预览 代码如下&#xff1a; // 单纯的右键-> ArkTsFile的话&#xff0c;可以创建一个组件。 // 原因是&#xff0c;之前我们学过通过右键->…

【linux学习指南】VSCode部署Ubantu云服务器,与Xshell进行本地通信文件编写

文章目录 &#x1f4dd;前言&#x1f320; 步骤&#x1f309;测试同步 &#x1f6a9;总结 &#x1f4dd;前言 本文目的是讲使用Vscode连接Ubantu,与本地Xshell建立通信同步文件编写。 查看本机系统相关信息&#xff1a; cat /etc/lsb*DISTRIB_IDUbuntu: 表示这是 Ubuntu 发行…

ES-针对某个字段去重后-获取某个字段值的所有值

针对上面表的数据&#xff0c;现在想根据age分组&#xff0c;并获取每个分组后的name有哪些(去重后)。 select age, GROUP_CONCAT(DISTINCT(name)) from testtable group by age ; 结果&#xff1a; 如果想要增加排序&#xff1a; SELECT age, GROUP_CONCAT(DISTINCT name)…

基于java+SpringBoot+Vue的在线考试系统设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven mysql5.7或8.0等等组成&#x…

一文详细深入总结服务器选型

1. 题记&#xff1a; 服务器选型工作是项目规划检讨的一项非常重要的工作&#xff0c;本文详细深入总结服务器选型。 2. 服务器基础知识概览 2.1 服务器的定义与功能 2.1 .1 定义 服务器是一种高性能计算机&#xff0c;其设计目的是在网络中提供服务。它可以处理来自多个客…

Linux 入门——基本指令1

目录 一背景知识的简介 二 入门相关指令的使用 一.背景知识的简介 1.认识 Linux &#xff0c;了解Linux 的相关背景 其实Linux 是从 Unix 发展而来的。 Linux&#xff0c;一般指GNU/Linux&#xff08;单独的Linux内核并不可直接使用&#xff0c;一般搭配GNU套件&#xff0…

2024年数维杯国际赛赛题浅析-助攻快速选题

本届数维杯我们将选择 MCM的B题以及ICM的D题进行助攻&#xff0c;具体助攻时间轴如下所示 11.15 12&#xff1a;00 更新赛题翻译、相关文献资料、选题建议、赛题难度 11.15 16&#xff1a;00 更新人工精翻版本赛题、数据预处理代码 11.15 24&#xff1a;00 更新完整解题思路…

w038基于SpringBoot的网上租赁系统设计与实现

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0…

windows 安装Ubuntu 后如何使用

windows 安装Ubuntu 后如何使用 youtube链接 https://www.youtube.com/watch?vPaEcQmgEz78哔哩哔哩视频 https://www.bilibili.com/video/BV1tW42197za/?spm_id_from333.999.0.0两个视频是一样的安装Ubuntu 安装docker的教程&#xff0c;不执行docker的安装即可 安装完毕后…