古典密码-playfair密码
实验介绍:
playfair密码也是多表代换密码
一:编制密码表
playfair密码表是一个5x5的矩阵
密码表包括了所有26个字母
5x5等于25,那么多出的一个字母怎么办呢?
在规定中,字母i和j放入同一个格子
从左到右,从上到下把密钥填入矩阵,再按字母表顺序填入字母
矩阵已经有的字母不填入
二:格式化明文
将明文两个字母为一组分组
如果出现一组里两个字母相同的情况,在字母中间插入x
如果最后是奇数,我们还需要添加字母x
三:加密明文
如果一组明文在密码表的位置是对角线
对应的密文是对角线的镜像方向
明文wo 密文za ,w->z ,o->a
如果一组明文在密码表的位置是同一行
对应的密文是字母右移一位的字母
明文ai 密文na ,a->n , i -> a
如果一组明文在密码表的位置是同一列
对应的密文是字母下移一位的字母
明文gx 密文fg ,g->f , x -> g
明文:aoaizhongguo
密文:zanavmxofgfxxi
四:解密密文及python加密代码
解密密文就是把向下移动的改成向上移动,向右改成向左,对角线的还是镜像方向
加密代码
点击查看代码
#格式化明文,使相邻两个相同字母加入x,并凑成偶数个字符数
def FormatPlainText(strText):
#strText.replace(" ","")
top=len(strText)#获得明文的长度
lsPlain=list()
print("明文长度是:",top)
if(top%2)==0:#even,当明文长度为偶数长,即可以完全配对,不需要在明文串末尾补充约定的字母
for index in range(0,top,2):#range函数有3个参数的:第1个表示左边界,第2个表示右边界,第3个表示步长,含左不含右,即范围(也是index取值)为0,2,4,...,top-1
if(strText[index]==strText[index+1]):#2个配对的字母相同,则需要在这2个字母之间添加一个字母“x”,再赋给新列表lsPlain
lsPlain.append(strText[index])
lsPlain.append('x')
lsPlain.append(strText[index+1])
else:#不同的配对字母直接赋给新列表lsPlain
lsPlain.append(strText[index])
lsPlain.append(strText[index+1])
else:#odd,当明文长度为奇数长度,最后一个字符会单出来
for index in range(0,top-1,2):#不包含最后一个字符
if(strText[index]==strText[index+1]):#2个配对的字母相同,则需要在这2个字母之间添加一个字母“x”,再赋给新列表lsPlain
lsPlain.append(strText[index])
lsPlain.append('x')
lsPlain.append(strText[index+1])
else:#不同的配对字母直接赋给新列表lsPlain
lsPlain.append(strText[index])
lsPlain.append(strText[index+1])
lsPlain.append(strText[top-1])
if(len(lsPlain)%2)!=0:#若得到的列表lsPlain不是偶数长度,则在最后补充上约定的字符“x”
lsPlain.append('x')
# print("\nformated plain text:", " ".join(lsPlain))
print("\n处理配对后的明文为:", " ".join(lsPlain))
return lsPlain
#格式化秘钥,使消除重复字符,并添加后续a-z字母,同时使i,j当成i或j处理
def FormatKey(strKey):
lsKey=list()
strKeyLen=len(strKey)#获得密钥长度
i=0
#print("\nformating the orignal key...")
while(i<strKeyLen):
if lsKey.count(strKey[i])==0:#判断lsKey中有没有重复的strKey[i],如果没有,则strKey[i]作为新的字母附加到新密钥lsKey中
lsKey.append(strKey[i])
i+=1
#print("\norginal key formated:","".join(lsKey))
#print("\nstart to add a to z except j...")
#下面的for循环时将26个英文字母中不在密钥strKey中的那些字母再附加到新密钥lsKey中
for ch in range(ord('a'),ord('z')+1):#range函数有2个参数的:第1个表示左边界,第2个表示右边界,含左不含右,即ch取值范围是ord('a'),ord('b'),...,ord('z')26个数值
if lsKey.count(chr(ch))==0:#判断ch对应的字符有没有重复的,没有重复的,直接赋到新密钥列表lsKey中,有重复的则不处理,即不加到lsKey新密钥列表中
lsKey.append(chr(ch))
#去掉j
lsKey.remove('j')#移除列表lsKey中j值的第一个匹配项,即去除第一个j值,因为在刚刚上面的for循环里已经处理了重复的字母,所以这里就是将j字母从lsKey中去除
print("\n处理的密钥25个字符为:"," ".join(lsKey))#处理后的lsKey是25个字母
print("\n密钥长度为:",len(lsKey))
return lsKey
def Cipher(lsMyKey,lsMyPlain):#用处理后的密钥lsMyKey对处理后的明文lsMyPlain进行加密
lsResult=list()
print("\n=============5*5密码表=========")
for ch in lsMyKey:#将密钥lsMykey字符串处理得到对应的5*5密码表
if(lsMyKey.index(ch)%5)==0:#每5个字符显示在一行
print("")
# print("\n")
print(ch,end=" ")
print("\n==================================\n 开始加密...\n")
top=len(lsMyPlain)
intCurrPre=intCurrNext=0
intCurrPreRow=intCurrPreCol=0
intCurrNextRow=intCurrNextCol=0
intTempRow=intTempCol=intPos=0
for index in range(0,top,2):
intCurrPre=lsMyKey.index(lsMyPlain[index])#获得明文index位置上的字母值对应在密钥中的位置,当前还是针对一维的密钥串
intCurrNext=lsMyKey.index(lsMyPlain[index+1])#获得明文index+1位置上字母值对应在密钥中的位置,当前还是针对一维的密钥串
intCurrPreRow=intCurrPre//5#获得明文index位置上的字母值在二维密码表中的行值
intCurrPreCol=intCurrPre%5#获得明文index位置上的字母值在二维密码表中的列值
print("第",index,"个明文字母",lsMyPlain[index],",在密码一维表中位置为:",intCurrPre,",在密码二维表中行列值为(",intCurrPreRow,",",intCurrPreCol,")")
intCurrNextRow=intCurrNext//5#获得明文index+1位置上的字母值在二维密码表中的行值
intCurrNextCol=intCurrNext%5#获得明文index+1位置上的字母值在二维密码表中的列值
print("第",index+1,"个明文字母",lsMyPlain[index+1],",在密码一维表中位置为:",intCurrNext,",在密码二维表中行列值为(",intCurrNextRow,",",intCurrNextCol,")\n")
#1 same row,different col
if(intCurrPreRow==intCurrNextRow) and (intCurrPreCol!=intCurrNextCol):#对相同行,不同列的2个字母进行加密
# print("same row,different column\n")
print("配对的2个明文字母在相同行,不同列,将每个字母的同一行右边相邻的字母作为对应的密文:\n")
#配对的第1个字符
intTempCol=(intCurrPreCol+1)%5#获得相邻右边一列的列值
intPos=intCurrPreRow*5+intTempCol#获取相邻右边一列字母在lsMyKey字符串中的实际位置
print("得到的第",index,"个密文字母为",lsMyKey[intPos],",在密码一维表中位置为:",intPos,",在密码二维表中行列值为(",intCurrPreRow,",",intTempCol,")")
lsResult.append(lsMyKey[intPos])#将获得的密文加到lsResult中
# 配对的第2个字符
intTempCol=(intCurrNextCol+1)%5
intPos=intCurrNextRow*5+intTempCol
print("得到的第",index+1,"个密文字母为",lsMyKey[intPos],",在密码一维表中位置为:",intPos,",在密码二维表中行列值为(",intCurrNextRow,",",intTempCol,")")
lsResult.append(lsMyKey[intPos])
print("===============================")
#2 same column,different row
if(intCurrPreRow!=intCurrNextRow) and (intCurrPreCol==intCurrNextCol):#对相同列,不同行的2个字母进行加密
# print("same column,different row\n")
print("配对的2个明文字母在相同列,不同行,将每个字母的同一列下边相邻的字母作为对应的密文:\n")
#配对的第1个字符
intTempRow=(intCurrPreRow+1)%5#获得相邻下边一行的行值
intPos=intTempRow*5+intCurrPreCol#获得相邻下边一行字母在lsMyKey字符串中的实际位置
print("得到的第",index,"个密文字母为",lsMyKey[intPos],",在密码一维表中位置为:",intPos,",在密码二维表中行列值为(",intTempRow,",",intCurrPreCol,")")
lsResult.append(lsMyKey[intPos])
#配对的第2个字符
intTempRow=(intCurrNextRow+1)%5
intPos=intTempRow*5+intCurrNextCol
print("得到的第",index+1,"个密文字母为",lsMyKey[intPos],",在密码一维表中位置为:",intPos,",在密码二维表中行列值为(",intTempRow,",",intCurrNextCol,")")
lsResult.append(lsMyKey[intPos])#将获得的密文加到lsResult中
print("===============================")
#3 different row,different col
if(intCurrPreRow!=intCurrNextRow) and (intCurrPreCol!=intCurrNextCol):#对不同列,不同行的2个字母进行加密
# print("different row,different column\n")
print("配对的2个明文字母在不同行,不同列,配对字母各自所在行作为本方密文字母所在行,将配对字母各自所在列作为对方密文字母所在列:\n")
#配对的第1个字符
intTempCol=intCurrNextCol#获得配对的另一个字母所在列
intPos=intCurrPreRow*5+intTempCol#获得本字母所在行,配对的另一字母所在列上对应的字符,即是本字母加密后的密文
print("得到的第",index,"个密文字母为",lsMyKey[intPos],",在密码一维表中位置为:",intPos,",在密码二维表中行列值为(",intCurrPreRow,",",intTempCol,")")
lsResult.append(lsMyKey[intPos])
#配对的第2个字符
intTempCol=intCurrPreCol#获得配对的另一个字母所在列
intPos=intCurrNextRow*5+intTempCol#获得本字母所在行,配对的另一字母所在列上对应的字符,即是本字母加密后的密文
print("得到的第",index+1,"个密文字母为",lsMyKey[intPos],",在密码一维表中位置为:",intPos,",在密码二维表中行列值为(",intCurrNextRow,",",intTempCol,")")
lsResult.append(lsMyKey[intPos])
print("===============================")
print("加密结果为:","".join(lsResult))
return lsResult
#main
txtPlain="woaizhongguo"
#txtPlain="Mysecretisinthetreeholes"
print("明文为:",txtPlain.lower())#
#txtKey="playfair"
txtKey="xiannong"
print("密钥为:",txtKey.lower())
lsNewPlain=FormatPlainText(txtPlain.lower())
#消除重复后添加后续字母,并且i,j都当成i处理
lsNewKey=FormatKey(txtKey.lower())
Cipher(lsNewKey,lsNewPlain)