转发注明出处: http://www.cnblogs.com/0zcl/p/6105825.html

一、基本概念

  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,列表及下标就会变化,这样就得重新循环插入才行!

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

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

 #处理一组字线是重复明文字母
def deal_repeat(list_clear_text):
count = 0 #计算列表中有多少组是不同的
flag = False
for i in range(len(list_clear_text)):
if(i % 2 == 1): #列表中的第d奇数个
if(list_clear_text[i] == list_clear_text[i-1]): #第奇数个与前一个(偶数)是否相同
list_clear_text.insert(i, "Z") #有重复明文字母则插入一个填充字母Z 并且退出循环
break
if (list_clear_text[i] != list_clear_text[i - 1]):
count += 1
if count == int(len(list_clear_text) / 2):
flag = True 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)

     for i in range(len(decryption_list)):
if i % 2 == 0:
if i+2 < len(decryption_list) and \
decryption_list[i] == decryption_list[i+2] and decryption_list[i+1] == "Z":
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那样循环删除?这样搞,我有几条命都不够用来打代码。有没有简单的?啪啪啪。灵光一现,我可以从后往前删除,这样就不怕列表下标变化了,用一个空列表来装我要删除元素的下标。

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

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

于是,测试如下:

 Please input E for encryption or D for decryption:E
请输入明文:aabbbcccczz
['a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'z', 'z']
['a', 'Z', 'a', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c', 'z', 'z']
['a', 'Z', 'a', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c', 'z', 'z', 'Z']
加密成功!密文:RXBJDXDHDUDUDUUU
Please input E for encryption or D for decryption:D
请输入密文(大写字母/偶数):RXBJDXDHDUDUDUUU
11
9
5
1
解密成功!明文:AABBBCCCCZZ
Please input E for encryption or D for decryption:E
请输入明文:aazzbbbcccczz
['a', 'a', 'z', 'z', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'z', 'z']
['a', 'Z', 'a', 'z', 'z', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c', 'z', 'z']
['a', 'Z', 'a', 'z', 'z', 'b', 'b', 'Z', 'b', 'c', 'c', 'Z', 'c', 'Z', 'c', 'z', 'z', 'Z']
加密成功!密文:RXRXXDDXDHDUDUDUUU
Please input E for encryption or D for decryption:D
请输入密文(大写字母/偶数):RXRXXDDXDHDUDUDUUU
13
11
7
1
解密成功!明文:AAZZBBBCCCCZZ
Please input E for encryption or D for decryption:

通过测试,也没问题,因为解密时会把多余的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']
加密成功!密文:BJDU
Please input E for encryption or D for decryption:D
请输入密文(大写字母/偶数):BJDU
解密成功!明文:ABC
Please input E for encryption or D for decryption:E
请输入明文(小写字母):abcz
['a', 'b', 'c', 'z']
['a', 'b', 'c', 'z']
['a', 'b', 'c', 'z']
加密成功!密文:BJDU
Please input E for encryption or D for decryption:D
请输入密文(大写字母/偶数):BJDU
解密成功!明文:ABC
Please 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

 源代码

 # 5*5的矩阵, I与J同, 注意是大写的,也可以自己定义矩阵(不要重复)
SECRET_LIST = [["M","O","N","A","R"],
["C","H","Y","B","D"],
["E","F","G","J","K"],
["L","P","Q","S","T"],
["U","V","W","X","Z"]] #加密
def encryption(clear_text):
#去除空格与逗号
clear_text = clear_text.replace(" ", "").replace(",", "")
list_clear_text = list(clear_text) #字符串转化为列表
print(list_clear_text)
#两个字母为一组,在重复的明文字母中插入填充字母Z
flag = False
while not flag:
list_clear_text = deal_repeat(list_clear_text)[0]
flag = deal_repeat(list_clear_text)[1]
print(list_clear_text)
#若分组到最后一组时只有一个字母,则补充字母Z
if len(list_clear_text) % 2 == 1:
list_clear_text.append("Z")
print(list_clear_text)
#加密的核心代码
encryption_list = core_encryption(list_clear_text) #返回密文列表
return ("").join(encryption_list) #处理一组字线是重复明文字母
def deal_repeat(list_clear_text):
count = 0 #计算列表中有多少组是不同的
flag = False
for i in range(len(list_clear_text)):
if(i % 2 == 1): #列表中的第d奇数个
if(list_clear_text[i] == list_clear_text[i-1]): #第奇数个与前一个(偶数)是否相同
list_clear_text.insert(i, "Z") #有重复明文字母则插入一个填充字母Z 并且退出循环
break
if (list_clear_text[i] != list_clear_text[i - 1]):
count += 1
if count == int(len(list_clear_text) / 2):
flag = True return list_clear_text,flag #返回的是元组 (list_clear_text, flag) #获得字母在矩阵中的行与列
def get_rows_columns(alphabet):
if alphabet == "I": #矩阵中只有25个字母,I同J
alphabet = "J"
for i in range(len(SECRET_LIST)):
for j in range(len(SECRET_LIST[i])):
if (SECRET_LIST[i][j] == alphabet):
return i,j # 加密的核心代码,先找出每一组字母在5*5矩阵 的行与列
def core_encryption(list_clear_text):
encryption_list = []
for i in range(len(list_clear_text)):
if(i % 2 == 0):
x = list_clear_text[i].upper() #将一组字母转为大写,因为矩阵的字母全是大写的
y = list_clear_text[i+1].upper()
x_tuple = get_rows_columns(x) #返回元组形式
y_tuple = get_rows_columns(y)
# print(x_tuple)
# print(y_tuple)
if x_tuple[0] == y_tuple[0]: #若明文字母在矩阵中同行
x_secret = SECRET_LIST[x_tuple[0]][(x_tuple[1] + 1) % 5]
y_secret = SECRET_LIST[y_tuple[0]][(y_tuple[1] + 1) % 5]
elif x_tuple[1] == y_tuple[1]: #若明文字母在矩阵中同列
x_secret = SECRET_LIST[(x_tuple[0] + 1) % 5][x_tuple[1]]
y_secret = SECRET_LIST[(y_tuple[0] + 1) % 5][y_tuple[1]]
else: #若明文字母在矩阵中不同行不同列
x_secret = SECRET_LIST[x_tuple[0]][y_tuple[1]]
y_secret = SECRET_LIST[y_tuple[0]][x_tuple[1]]
encryption_list.append(x_secret)
encryption_list.append(y_secret)
return encryption_list #返回字母加密后的列表 #解密核心代码,返回解密后的明文列表,密文肯定是偶数的,每一组密文字母也肯定是不同的
def core_decryption(list_cipher_text):
decryption_list = []
for i in range(len(list_cipher_text)):
if(i % 2 == 0):
x = list_cipher_text[i]
y = list_cipher_text[i+1]
x_tuple = get_rows_columns(x) #返回元组形式
y_tuple = get_rows_columns(y)
if x_tuple[0] == y_tuple[0]: #若密文字母在矩阵中同行
x_clear = SECRET_LIST[x_tuple[0]][(x_tuple[1] - 1) % 5]
y_clear = SECRET_LIST[y_tuple[0]][(y_tuple[1] - 1) % 5]
elif x_tuple[1] == y_tuple[1]: #若密文字母在矩阵中同列
x_clear = SECRET_LIST[(x_tuple[0] - 1) % 5][x_tuple[1]]
y_clear = SECRET_LIST[(y_tuple[0] - 1) % 5][y_tuple[1]]
else: #若密文字母在矩阵中不同行不同列
x_clear = SECRET_LIST[x_tuple[0]][y_tuple[1]]
y_clear = SECRET_LIST[y_tuple[0]][x_tuple[1]]
decryption_list.append(x_clear)
decryption_list.append(y_clear)
return decryption_list #返回解密后的明文列表(需进一步处理,eg:去掉Z) #解密
def decryption(cipher_text):
cipher_text = cipher_text.replace(" ", "").replace(",", "")
list_cipher_text = list(cipher_text.strip()) #将密文转化为列表
decryption_list = core_decryption(list_cipher_text) #调用函数
if decryption_list[-1] == "Z": #若列表最后一个元素是Z,则删除
decryption_list.pop(-1)
#找出列表应该删除的下标
delete_list = []
for i in range(len(decryption_list)):
if i % 2 == 0: #第偶数个
#不越界
if i+2 < len(decryption_list) and \
decryption_list[i] == decryption_list[i+2] and decryption_list[i+1] == "Z":
delete_list.append(i+1)
#decryption_list.pop(i+1)
delete_list.reverse() #反序,从后往前删除,每次删完下标就不会再变化,我真是太聪明了!
for i in delete_list:
print(i)
decryption_list.pop(i)
return "".join(decryption_list) if __name__ == "__main__":
while True:
choice = input("Please input E for encryption or D for decryption:")
if choice.strip() != "E" and choice.strip() != "D":
print("Input Error")
#加密
if choice.strip() == "E":
clear_text = input("请输入明文:")
print("加密成功!密文:%s" % encryption(clear_text))
#解密
if choice.strip() == "D":
cipher_text = input("请输入密文(大写字母/偶数):")
print("解密成功!明文:%s" % decryption(cipher_text))

 测试用例

 Please input E for encryption or D for decryption:E
请输入明文:we are discovered save yourself
['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']
['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']
['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']
加密成功!密文:UGRMKCSXHMUFMKBTOXGCMVATLUKV
Please input E for encryption or D for decryption:D
请输入密文(大写字母/偶数):UGRMKCSXHMUFMKBTOXGCMVATLUKV
解密成功!明文:WEAREDJSCOVEREDSAVEYOURSELF
Please input E for encryption or D for decryption:E
请输入明文: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']
加密成功!密文:RXBJDXDHDUDUDU
Please input E for encryption or D for decryption:D
请输入密文(大写字母/偶数):RXBJDXDHDUDUDU
11
9
5
1
解密成功!明文:AABBBCCCC
Please input E for encryption or D for decryption:

信息安全-1:python之playfair密码算法详解[原创]的更多相关文章

  1. 密码算法详解——AES

    0 AES简介 1997年1月2号,美国国家标准技术研究所宣布希望征集一个安全性能更高的加密算法(AES)[3],用以取代DES.我们知道DES的密钥长度是64 bits,但实际加解密中使用的有效长度 ...

  2. 密码算法详解——DES

    0 DES简介 在20世纪60年代后期,IBM公司成立了一个由Horst Feistel负责的计算机密码学研究项目.1971年设计出密码算法LUCIFER后,该项目宣告结束.LUCIFER被卖给了伦敦 ...

  3. AES密码算法详解(转自https://www.cnblogs.com/luop/p/4334160.html)

    0 AES简介 我们知道数据加密标准(Data Encryption Standard: DES)的密钥长度是56比特,因此算法的理论安全强度是256.但二十世纪中后期正是计算机飞速发展的阶段,元器件 ...

  4. 密码算法详解——Simon

    0 Simon简介 详细文档请直接阅读参考文献[1]. Simon是由NSA设计的轻量级分组密码算法(LIGHTWEIGHT BLOCK CIPHER).主要应用于硬件或软件条件受限(例如:芯片面积要 ...

  5. python 几个简单算法详解

    一.冒泡排序 基本思想:它的思路很有特点循环,两两向后比较.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数 ...

  6. 机器学习经典算法详解及Python实现--基于SMO的SVM分类器

    原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector  ...

  7. SILC超像素分割算法详解(附Python代码)

    SILC算法详解 一.原理介绍 SLIC算法是simple linear iterative cluster的简称,该算法用来生成超像素(superpixel) 算法步骤: 已知一副图像大小M*N,可 ...

  8. 第三十一节,目标检测算法之 Faster R-CNN算法详解

    Ren, Shaoqing, et al. “Faster R-CNN: Towards real-time object detection with region proposal network ...

  9. Python中的高级数据结构详解

    这篇文章主要介绍了Python中的高级数据结构详解,本文讲解了Collection.Array.Heapq.Bisect.Weakref.Copy以及Pprint这些数据结构的用法,需要的朋友可以参考 ...

随机推荐

  1. 【小程序分享篇 二 】web在线踢人小程序,维持用户只能在一个台电脑持登录状态

    最近离职了, 突然记起来还一个小功能没做, 想想也挺简单,留下代码和思路给同事做个参考. 换工作心里挺忐忑, 对未来也充满了憧憬与担忧.(虽然已是老人, 换了N次工作了,但每次心里都和忐忑). 写写代 ...

  2. NodeJs之Path

    Path模块 NodeJs提供的Path模块,使得我们可以对文件路径进行简单的操作. API var path = require('path'); var path_str = '\\Users\\ ...

  3. DDD初学指南

    去年就打算总结一下,结果新换的工作特别忙,就迟迟没有认真动手.主要内容是很多初学DDD甚至于学习很长时间的同学没有弄明白DDD是什么,适合什么情况.这世界上没有银弹,抛开了适合的场景孤立的去研究DDD ...

  4. ASP.NET Core的路由[2]:路由系统的核心对象——Router

    ASP.NET Core应用中的路由机制实现在RouterMiddleware中间件中,它的目的在于通过路由解析为请求找到一个匹配的处理器,同时将请求携带的数据以路由参数的形式解析出来供后续请求处理流 ...

  5. JQuery easyUI DataGrid 创建复杂列表头(译)

    » Create column groups in DataGrid The easyui DataGrid has ability to group columns, as the followin ...

  6. swift 中关于open ,public ,fileprivate,private ,internal,修饰的说明

    关于 swift 中的open ,public ,fileprivate,private, internal的区别 以下按照修饰关键字的访问约束范围 从约束的限定范围大到小的排序进行说明 open,p ...

  7. HTML5游戏源码 飞翔的字母 可自定义内容

    相信大家都玩过飞翔的小鸟吧,当然,可能已经有很多人因为这个游戏砸了不少手机.吼吼. 废话不多说,回到主题,源码如下. 博客园上传空间大小有限制,没法上传了,需要打包源码的朋友们请留言邮箱地址.当然还有 ...

  8. linux yum命令详解

    yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器.基於RPM包管理,能够从指定的服务器自动下载RP ...

  9. Jexus Web Server 完全傻瓜化图文配置教程(基于Ubuntu 12.04.3 64位)[内含Hyper-v 2012虚拟机镜像下载地址]

    1. 前言 近日有感许多新朋友想尝试使用Jexus,不过绝大多数都困惑徘徊在Linux如何安装啊,如何编译Mono啊,如何配置Jexus啊...等等基础问题,于是昨日向宇内流云兄提议,不如搞几个配置好 ...

  10. 从Maya中把模型搬运至网页的过程

    虽然利用threejs来在网页中渲染3d模型不是第一次折腾了,但是还是遇到了各种问题.总结下我所遇到的问题,希望能给正在使用threejs的小伙伴一个帮助. 一.所使用的软件与开发环境 Maya201 ...