博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
信息安全-1:python之playfair密码算法详解[原创]
阅读量:4919 次
发布时间:2019-06-11

本文共 12749 字,大约阅读时间需要 42 分钟。

转发注明出处:

 

一、基本概念

 

  1. 古典密码是基于字符替换的密码。加密技术有:Caesar(恺撒)密码、Vigenere(维吉尼尔)密码、Playfair密码、Hill密码……
  2. 明文:未经过加密的信息;密文:加密后的信息
  3. 加密解密的过程:如下图

 

 

二、Caesar密码

  这里我先简单讲下恺撒密码,咸觉挺简单的,后面再主要讲Playfair算法原理与编程。

基本原理:

在开拓罗马帝国的时候,恺撒担心信使会阅读他送给士兵的命令,因此发明了对命令进行加密的算法--恺撒密码器

恺撒密码器挺简单的:把字母表中的每个字母向前循环移动3位

  • 加密信息将字母向前移动三位
  • 解密信息将字母向后移动三位
  • 移动的位数是关键,称之为密钥
  • 加密和解密的密钥是相同的,我们称之为对称密码器

 

数学表达

恺撒密码的加密算法表示为:C=E(p)=(p+3) mod 26

恺撒密码的解密算法表示为:p=D(C)=(C-3) mod 26

 

改进的恺撒密码

明文的发送方和接收方事先协商好一个密钥K(1<=K<=25),则:

恺撒密码的加密算法表示为:C=E(p)=(p+K) mod 26

恺撒密码的解密算法表示为:p=D(C)=(C-K) mod 26

 

 

三、Playfair密码

基本原理

Playfair算法基于一个5*5的字母矩阵,该矩阵使用一个关键词构造,方法是按从左到右、从上到下顺序,填入关键词的字母(去除重复字母)后,将字母表其作余字母填入。

例如: 关键词取:monarchy时,字母矩阵为下图如示(矩阵只能放25个字母,I与J同)

 

加密规则(重要)

Playfair加密算法是先将明文按两个字母一组进行分组,然后在矩阵中找对应的密文。

取密文的规则如下:

  1. 若明文出现相同字母在一组,则在重复的明文字母中插入一个填充字母(eg:z)进行分隔后重新分组(eg: balloon被重新分组为ba lz lo on)
  2. 若分组到最后一组时只有一个字母,则补充字母z
  3. 若明文字母在矩阵中同行,则循环取其右边下一个字母为密文(矩阵最右边的下一个是最左边的第一个)(eg: ar被加密为RM)
  4. 若明文字母在矩阵中同列,则循环取其下边下一个字母为密文(矩阵最下边的下一个是最上边的第一个)(eg: mu被加密为CM)
  5. 若明文字母在矩阵中不同行不同列,则取其同行且与同组另一字母同列的字母为密文(eg: hs被加密为BP,ea被加密为IM或JM)

PS:上述规则第一次看时挺烦的,但照着例子看就一定可以看懂的!

举例(这个例子后面测试会用到的):

明文为we are discovered save yourself,分组成为we ar ed is co ve re ds av ey ou rs el fz; 

用上述矩阵加密后的密文为:UG RM KC SX HM UF MK BT OX GC MV AT LU KV

 

 

 四、Playfair算法编程

这里我不想直接贴代码。想仔细说下编程的思路以及中间遇到的一些问题。因为刚开始百度参考别人的博客都是直接贴代码,没说思路,看代码又不大懂。搞得我都是自己编的代码。

 

流程图(重要)

我画的流程图网址https://www.processon.com/diagraming/5839ae8de4b086d1e7cba620

前程明亮

妈呀!流程图已经把我想说的大都说了~~尴尬~

如果加密做了,解密真的很简单的。接下来说下我遇到的几个问题,卡住挺久的~

 

 

 问题及分析

 问题1. 一组字母是重复明文字母,则插入字母Z(我设的,你也可以设别的),如何实现??

我刚开始的做法是循环明文列表,依次找出第奇数(为什么不先找偶数?先找偶数之后就得去找下一个元素(奇数),怕下标越界)个元素,然后比较奇数前面一个元素(偶数)是否相同,相同则插入字母Z。然而问题来了?每次我插入一个Z,列表及下标就会变化,这样就得重新循环插入才行!

1     for i in range(len(list_clear_text)):2         if(i % 2 == 1):   #列表中的第d奇数个3             if(list_clear_text[i] == list_clear_text[i-1]):   #第奇数个与前一个(偶数)是否相同4                 list_clear_text.insert(i, "Z")   #有重复明文字母则插入一个填充字母Z 并且退出循环5                 break

然后我们用个while循环调用上面代码就可以了。接下来的问题是:如何退出while循环,即如何判断列表没有一组字母是重复的明文字母。这里我想了想,决定用一个count来计数,每一组明文字母不相同时,则count+1,当 count == int(len(list_clear_text) / 2)时便可退出循环!

1 #处理一组字线是重复明文字母 2 def deal_repeat(list_clear_text): 3     count = 0    #计算列表中有多少组是不同的 4     flag = False 5     for i in range(len(list_clear_text)): 6         if(i % 2 == 1):   #列表中的第d奇数个 7             if(list_clear_text[i] == list_clear_text[i-1]):   #第奇数个与前一个(偶数)是否相同 8                 list_clear_text.insert(i, "Z")   #有重复明文字母则插入一个填充字母Z 并且退出循环 9                 break10             if (list_clear_text[i] != list_clear_text[i - 1]):11                 count += 112                 if count == int(len(list_clear_text) / 2):13                     flag = True14 15     return list_clear_text,flag   #返回的是元组 (list_clear_text, flag)

啪啪啪!问题解决!接下来说个解密时遇到的问题。

 

问题2:解密时先判断列表最后一个是否Z,是的话删除,接着问题来了,如何删除加密时在一组重复的明文中填充的字母Z???

我刚开始的做法是先判断(decryption_list[i]为第偶数个,若与decryption_list[i+2]相同,并且中间decryption_list[i+1] == "Z"等于Z,则删除中间的Z)

1     for i in range(len(decryption_list)):2         if i % 2 == 0:3             if i+2 < len(decryption_list) and \4                             decryption_list[i] == decryption_list[i+2] and decryption_list[i+1] == "Z":5                 delete_list.pop(i+1)

为了方便看上面的判断,我贴下测试:

请输入明文:aabbbcccc['a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'c']['a', 'Z', 'a', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c']['a', 'Z', 'a', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c', 'Z']      #最后添加字母Z

问题来了,和问题1一样,每删除一个Z,列表与下标也随之变化了啊!怎么办??像问题1那样循环删除?这样搞,我有几条命都不够用来打代码。有没有简单的?啪啪啪。灵光一现,我可以从后往前删除,这样就不怕列表下标变化了,用一个空列表来装我要删除元素的下标。

1     delete_list = [] 2     for i in range(len(decryption_list)): 3         if i % 2 == 0:          #第偶数个 4             #不越界 5             if i+2 < len(decryption_list) and \ 6                             decryption_list[i] == decryption_list[i+2] and decryption_list[i+1] == "Z": 7                 delete_list.append(i+1) 8                 #decryption_list.pop(i+1) 9     delete_list.reverse()     #反序,从后往前删除,每次删完下标就不会再变化,我真是太聪明了!10     for i in delete_list:11         print(i)12         decryption_list.pop(i)

 

 

问题3:我设定的是插入Z,当时我想的是如果一组重复的明文刚好是zz,那还能插入Z(我设定的)?以及如果明文列表最后一个刚好是z,那我还能在最后补充Z??

于是,测试如下:

1 Please input E for encryption or D for decryption:E 2 请输入明文:aabbbcccczz 3 ['a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'z', 'z'] 4 ['a', 'Z', 'a', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c', 'z', 'z'] 5 ['a', 'Z', 'a', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c', 'z', 'z', 'Z'] 6 加密成功!密文:RXBJDXDHDUDUDUUU 7 Please input E for encryption or D for decryption:D 8 请输入密文(大写字母/偶数):RXBJDXDHDUDUDUUU 9 1110 911 512 113 解密成功!明文:AABBBCCCCZZ14 Please input E for encryption or D for decryption:E15 请输入明文:aazzbbbcccczz16 ['a', 'a', 'z', 'z', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'z', 'z']17 ['a', 'Z', 'a', 'z', 'z', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c', 'z', 'z']18 ['a', 'Z', 'a', 'z', 'z', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c', 'z', 'z', 'Z']19 加密成功!密文:RXRXXDDXDHDUDUDUUU20 Please input E for encryption or D for decryption:D21 请输入密文(大写字母/偶数):RXRXXDDXDHDUDUDUUU22 1323 1124 725 126 解密成功!明文:AAZZBBBCCCCZZ27 Please input E for encryption or D for decryption:
View Code

通过测试,也没问题,因为解密时会把多余的Z删除。(看来我想多了~)

 

 

问题4: 好尴尬的BUG

加密时,不论时文abc, 还是abcz,加密后的密文均为BJDU,那惨了,那BJDU解密时,是abc?还是abcz??

Please input E for encryption or D for decryption:E请输入明文(小写字母):ABC['A', 'B', 'C']['A', 'B', 'C']['A', 'B', 'C', 'Z']加密成功!密文:BJDUPlease input E for encryption or D for decryption:D请输入密文(大写字母/偶数):BJDU解密成功!明文:ABCPlease input E for encryption or D for decryption:E请输入明文(小写字母):abcz['a', 'b', 'c', 'z']['a', 'b', 'c', 'z']['a', 'b', 'c', 'z']加密成功!密文:BJDUPlease input E for encryption or D for decryption:D请输入密文(大写字母/偶数):BJDU解密成功!明文:ABCPlease input E for encryption or D for decryption:

不管了,大家不必死钻这个BUG,如果有啥好办法可以与我交流下,我吃饭去了……

 

 五、总结

 

  • 有半个月没用python了,列表操作有些竟然忘了。尴尬~
  • list.pop()删除指定下标的元素,默认删除最后一个元素
  • 列表的list.reverse()返回值是None
  • 方法return 1,2  其实是返回一个元组(1, 2)
  • print(int(7/2)) 输出3

 

 

 源代码

 

1 # 5*5的矩阵, I与J同, 注意是大写的,也可以自己定义矩阵(不要重复)  2 SECRET_LIST = [["M","O","N","A","R"],  3                ["C","H","Y","B","D"],  4                ["E","F","G","J","K"],  5                ["L","P","Q","S","T"],  6                ["U","V","W","X","Z"]]  7   8 #加密  9 def encryption(clear_text): 10     #去除空格与逗号 11     clear_text = clear_text.replace(" ", "").replace(",", "") 12     list_clear_text = list(clear_text)   #字符串转化为列表 13     print(list_clear_text) 14     #两个字母为一组,在重复的明文字母中插入填充字母Z 15     flag = False 16     while not flag: 17         list_clear_text = deal_repeat(list_clear_text)[0] 18         flag = deal_repeat(list_clear_text)[1] 19     print(list_clear_text) 20     #若分组到最后一组时只有一个字母,则补充字母Z 21     if len(list_clear_text) % 2 == 1: 22         list_clear_text.append("Z") 23     print(list_clear_text) 24     #加密的核心代码 25     encryption_list = core_encryption(list_clear_text)  #返回密文列表 26     return ("").join(encryption_list) 27  28  29 #处理一组字线是重复明文字母 30 def deal_repeat(list_clear_text): 31     count = 0    #计算列表中有多少组是不同的 32     flag = False 33     for i in range(len(list_clear_text)): 34         if(i % 2 == 1):   #列表中的第d奇数个 35             if(list_clear_text[i] == list_clear_text[i-1]):   #第奇数个与前一个(偶数)是否相同 36                 list_clear_text.insert(i, "Z")   #有重复明文字母则插入一个填充字母Z 并且退出循环 37                 break 38             if (list_clear_text[i] != list_clear_text[i - 1]): 39                 count += 1 40                 if count == int(len(list_clear_text) / 2): 41                     flag = True 42  43     return list_clear_text,flag   #返回的是元组 (list_clear_text, flag) 44  45 #获得字母在矩阵中的行与列 46 def get_rows_columns(alphabet): 47     if alphabet == "I":  #矩阵中只有25个字母,I同J 48         alphabet = "J" 49     for i in range(len(SECRET_LIST)): 50         for j in range(len(SECRET_LIST[i])): 51             if (SECRET_LIST[i][j] == alphabet): 52                 return i,j 53  54  55 # 加密的核心代码,先找出每一组字母在5*5矩阵 的行与列 56 def core_encryption(list_clear_text): 57     encryption_list = [] 58     for i in range(len(list_clear_text)): 59         if(i % 2 == 0): 60             x = list_clear_text[i].upper()   #将一组字母转为大写,因为矩阵的字母全是大写的 61             y = list_clear_text[i+1].upper() 62             x_tuple = get_rows_columns(x)   #返回元组形式 63             y_tuple = get_rows_columns(y) 64             # print(x_tuple) 65             # print(y_tuple) 66             if x_tuple[0] == y_tuple[0]:   #若明文字母在矩阵中同行 67                 x_secret = SECRET_LIST[x_tuple[0]][(x_tuple[1] + 1) % 5] 68                 y_secret = SECRET_LIST[y_tuple[0]][(y_tuple[1] + 1) % 5] 69             elif x_tuple[1] == y_tuple[1]:  #若明文字母在矩阵中同列 70                 x_secret = SECRET_LIST[(x_tuple[0] + 1) % 5][x_tuple[1]] 71                 y_secret = SECRET_LIST[(y_tuple[0] + 1) % 5][y_tuple[1]] 72             else:      #若明文字母在矩阵中不同行不同列 73                 x_secret = SECRET_LIST[x_tuple[0]][y_tuple[1]] 74                 y_secret = SECRET_LIST[y_tuple[0]][x_tuple[1]] 75             encryption_list.append(x_secret) 76             encryption_list.append(y_secret) 77     return encryption_list      #返回字母加密后的列表 78  79  80 #解密核心代码,返回解密后的明文列表,密文肯定是偶数的,每一组密文字母也肯定是不同的 81 def core_decryption(list_cipher_text): 82     decryption_list = [] 83     for i in range(len(list_cipher_text)): 84         if(i % 2 == 0): 85             x = list_cipher_text[i] 86             y = list_cipher_text[i+1] 87             x_tuple = get_rows_columns(x)   #返回元组形式 88             y_tuple = get_rows_columns(y) 89             if x_tuple[0] == y_tuple[0]:   #若密文字母在矩阵中同行 90                 x_clear = SECRET_LIST[x_tuple[0]][(x_tuple[1] - 1) % 5] 91                 y_clear = SECRET_LIST[y_tuple[0]][(y_tuple[1] - 1) % 5] 92             elif x_tuple[1] == y_tuple[1]:  #若密文字母在矩阵中同列 93                 x_clear = SECRET_LIST[(x_tuple[0] - 1) % 5][x_tuple[1]] 94                 y_clear = SECRET_LIST[(y_tuple[0] - 1) % 5][y_tuple[1]] 95             else:      #若密文字母在矩阵中不同行不同列 96                 x_clear = SECRET_LIST[x_tuple[0]][y_tuple[1]] 97                 y_clear = SECRET_LIST[y_tuple[0]][x_tuple[1]] 98             decryption_list.append(x_clear) 99             decryption_list.append(y_clear)100     return decryption_list       #返回解密后的明文列表(需进一步处理,eg:去掉Z)101 102 #解密103 def decryption(cipher_text):104     cipher_text = cipher_text.replace(" ", "").replace(",", "")105     list_cipher_text = list(cipher_text.strip())   #将密文转化为列表106     decryption_list = core_decryption(list_cipher_text)   #调用函数107     if decryption_list[-1] == "Z":      #若列表最后一个元素是Z,则删除108         decryption_list.pop(-1)109     #找出列表应该删除的下标110     delete_list = []111     for i in range(len(decryption_list)):112         if i % 2 == 0:          #第偶数个113             #不越界114             if i+2 < len(decryption_list) and \115                             decryption_list[i] == decryption_list[i+2] and decryption_list[i+1] == "Z":116                 delete_list.append(i+1)117                 #decryption_list.pop(i+1)118     delete_list.reverse()     #反序,从后往前删除,每次删完下标就不会再变化,我真是太聪明了!119     for i in delete_list:120         print(i)121         decryption_list.pop(i)122     return "".join(decryption_list)123 124 125 126 if __name__ == "__main__":127     while True:128         choice = input("Please input E for encryption or D for decryption:")129         if choice.strip() != "E" and choice.strip() != "D":130             print("Input Error")131         #加密132         if choice.strip() == "E":133             clear_text = input("请输入明文:")134             print("加密成功!密文:%s" % encryption(clear_text))135         #解密136         if choice.strip() == "D":137             cipher_text = input("请输入密文(大写字母/偶数):")138             print("解密成功!明文:%s" % decryption(cipher_text))
View Code

 

 测试用例

1 Please input E for encryption or D for decryption:E 2 请输入明文:we are discovered save yourself 3 ['w', 'e', 'a', 'r', 'e', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'e', 'd', 's', 'a', 'v', 'e', 'y', 'o', 'u', 'r', 's', 'e', 'l', 'f'] 4 ['w', 'e', 'a', 'r', 'e', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'e', 'd', 's', 'a', 'v', 'e', 'y', 'o', 'u', 'r', 's', 'e', 'l', 'f'] 5 ['w', 'e', 'a', 'r', 'e', 'd', 'i', 's', 'c', 'o', 'v', 'e', 'r', 'e', 'd', 's', 'a', 'v', 'e', 'y', 'o', 'u', 'r', 's', 'e', 'l', 'f', 'Z'] 6 加密成功!密文:UGRMKCSXHMUFMKBTOXGCMVATLUKV 7 Please input E for encryption or D for decryption:D 8 请输入密文(大写字母/偶数):UGRMKCSXHMUFMKBTOXGCMVATLUKV 9 解密成功!明文:WEAREDJSCOVEREDSAVEYOURSELF10 Please input E for encryption or D for decryption:E11 请输入明文:aabbbcccc12 ['a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'c']13 ['a', 'Z', 'a', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c']14 ['a', 'Z', 'a', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c', 'Z']15 加密成功!密文:RXBJDXDHDUDUDU16 Please input E for encryption or D for decryption:D17 请输入密文(大写字母/偶数):RXBJDXDHDUDUDU18 1119 920 521 122 解密成功!明文:AABBBCCCC23 Please input E for encryption or D for decryption:
View Code

 

转载于:https://www.cnblogs.com/0zcl/p/6105825.html

你可能感兴趣的文章
vi编辑器的使用(2)
查看>>
QTP——改变Excel的单元格颜色
查看>>
C# 判断网络文件是否存在
查看>>
CodeForces 449B - Jzzhu and Cities
查看>>
常用sql语句
查看>>
Android学习笔记-保存数据的实现方法2-SharedPreferences
查看>>
python接口自动化1
查看>>
java this关键字
查看>>
JAVA8之数据流Stream
查看>>
关于控制反转(IOC)容器 ,依赖注入(DI)模式必读文章收集
查看>>
20131214-EditPlus快捷键-第二十一天
查看>>
安装Windows服务,一直提示系统正在关机的错误。
查看>>
wake,awake,waken,awaken的区别
查看>>
MySQL 字符串拼接
查看>>
iOS-回收键盘的几种方法
查看>>
knockoutJS学习笔记09:使用mapping插件
查看>>
API开发之接口安全(二)-----sign校验
查看>>
bzoj 1047 单调队列
查看>>
Windows Phone开发之路(11) 方向处理之动态布局
查看>>
数据分析笔试题
查看>>