古典密码-playfair密码

实验介绍:

playfair密码也是多表代换密码

一:编制密码表

playfair密码表是一个5x5的矩阵

密码表包括了所有26个字母
5x5等于25,那么多出的一个字母怎么办呢?
在规定中,字母i和j放入同一个格子
image

从左到右,从上到下把密钥填入矩阵,再按字母表顺序填入字母

矩阵已经有的字母不填入
image

二:格式化明文

将明文两个字母为一组分组

image

如果出现一组里两个字母相同的情况,在字母中间插入x

image

如果最后是奇数,我们还需要添加字母x

image

三:加密明文

如果一组明文在密码表的位置是对角线

对应的密文是对角线的镜像方向
明文wo 密文za ,w->z ,o->a
image

如果一组明文在密码表的位置是同一行

对应的密文是字母右移一位的字母
明文ai 密文na ,a->n , i -> a
image

如果一组明文在密码表的位置是同一列

对应的密文是字母下移一位的字母
明文gx 密文fg ,g->f , x -> g
image
明文: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)

posted on 2024-10-20 14:19  纤秾  阅读(21)  评论(0编辑  收藏  举报