转发注明出处: 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. Asp.net Boilerplate之AbpSession扩展

    当前Abp版本1.2,项目类型为MVC5. 以属性的形式扩展AbpSession,并在"记住我"后,下次自动登录也能获取到扩展属性的值,版权归"角落的白板报"所 ...

  2. React 入门教程

    React 起源于Facebook内部项目,是一个用来构建用户界面的 javascript 库,相当于MVC架构中的V层框架,与市面上其他框架不同的是,React 把每一个组件当成了一个状态机,组件内 ...

  3. .Net中的AOP系列之构建一个汽车租赁应用

    返回<.Net中的AOP>系列学习总目录 本篇目录 开始一个新项目 没有AOP的生活 变更的代价 使用AOP重构 本系列的源码本人已托管于Coding上:点击查看. 本系列的实验环境:VS ...

  4. nginx的使用

    1.nginx的下载 解压后文件目录: 2.nginx的常用命令 nginx -s stop 强制关闭  nginx -s quit 安全关闭  nginx -s reload 改变配置文件的时候,重 ...

  5. Android 5.0 到 Android 6.0 + 的深坑之一 之 .so 动态库的适配

    (原创:http://www.cnblogs.com/linguanh) 目录: 前序 一,问题描述 二,为何会如此"无情"? 三,目前存在该问题的知名SDK 四,解决方案,1 对 ...

  6. # PHP - 使用PHPMailer发邮件

    PHPMailer支持多种邮件发送方式,使用起来非常简单 1.下载PHPMailer https://github.com/PHPMailer/PHPMailer,下载完成加压后, 把下边的两个文件复 ...

  7. AFNetworking 3.0 源码解读(十一)之 UIButton/UIProgressView/UIWebView + AFNetworking

    AFNetworking的源码解读马上就结束了,这一篇应该算是倒数第二篇,下一篇会是对AFNetworking中的技术点进行总结. 前言 上一篇我们总结了 UIActivityIndicatorVie ...

  8. [C#] C# 知识回顾 - 特性 Attribute

    C# 知识回顾 - 特性 Attribute [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5911289.html 目录 特性简介 使用特性 特性 ...

  9. springmvc+mybatis+spring 整合 bootstrap html5

    A 调用摄像头拍照,自定义裁剪编辑头像 [新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统]B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单;  技 ...

  10. 每天一个设计模式-7 生成器模式(Builder)

    每天一个设计模式-7 生成器模式(Builder) 一.实际问题 在讨论工厂方法模式的时候,提到了一个导出数据的应用框架,但是并没有涉及到导出数据的具体实现,这次通过生成器模式来简单实现导出成文本,X ...