前言
终于放假了,整理一波之前密码学的报告和笔记;
正文
简述
仿射密码,是古典密码里面比较经典的替换密码,在我看来就是将移位密码和数乘密码结合到了一起;
加密方程:C=(k1*M+k2)mod26
;
解密方程:M=(C-k2)*(k1^-1)mod26
;
其中k1必须与26互素,这样才可以产生k1的逆元用于解密;没有对k1的限制,可能无法解密。
代码分析
加密算法
这里的p为需要加密的明文,k1,k2就是上述的两个**,先看明文需要加密几个字母,有几个字母就产生几轮循环,每次循环将字母先转换为0~25的数字,然后进行数乘和移位变换,然后再转换为字符,存储在一个字符变量c中,直到循环结束为止,这就得到了密文;
#仿射加密
def fangshe(p,k1,k2):
c=""
for i in range(len(p)):
temp=chr((((ord(p[i])-ord('a'))*k1+k2)%26)+ord('a'))
c+=temp
return c
判断最大公因数
如果需要解密,则必须要使得k1能够产生对26的逆元,即要使k1和26互素,所以判断k1和26是否最大公约数为1;
#判断最大公因数
def gcd(x,y):
if x>y:
temp=y
else:
temp=x
for i in range(1,temp+1):
if((x%i==0) and (y%i==0)):
s=i
return s
解密算法
解密首先要判断k1和26是否互素,互素才可以解密,在互素的前提下计算k1对于26的逆元:k1_re,然后用解密放生进行循环解密即可输出明文;
#仿射解密
def decode(a,b,str1):
c1=""
if(gcd(a,26)==1):
for i in range(26):
if((a*i)%26==1):
k1_re=i
break
for i in range(len(str1)):
temp=chr((((ord(str1[i])-ord('a'))-b)*k1_re)%26+ord('a'))
c1+=temp
return c1
完整代码
刚写python,比较丑…
# -*- coding: utf-8 -*-
#仿射加密
def fangshe(p,k1,k2):
c=""
for i in range(len(p)):
temp=chr((((ord(p[i])-ord('a'))*k1+k2)%26)+ord('a'))
c+=temp
return c
#判断最大公因数
def gcd(x,y):
if x>y:
temp=y
else:
temp=x
for i in range(1,temp+1):
if((x%i==0) and (y%i==0)):
s=i
return s
#仿射解密
def decode(a,b,str1):
c1=""
if(gcd(a,26)==1):
for i in range(26):
if((a*i)%26==1):
k1_re=i
break
for i in range(len(str1)):
temp=chr((((ord(str1[i])-ord('a'))-b)*k1_re)%26+ord('a'))
c1+=temp
return c1
def main():
print 8*"*"+" EncryptInput "+8*"*"
p=raw_input("Please enter the plain:")
k1=input("Please enter k1:")
k2=input("Please enter k2:")
print 8*"*"+" Encryption "+8*"*"
c=fangshe(p,k1,k2)
print ("Cipher:"+c)
print "\n"+8*"*"+" DecryptInput "+8*"*"
C=raw_input("Please enter the Cipher:")
key1=input("Please enter k1:")
key2=input("Please enter k2:")
print 8*"*"+" Decryption "+8*"*"
plain=decode(key1,key2,C)
print "Plain:"+plain
if __name__ == '__main__':
main()
运行结果及正确性
输入明文hellocumt,k1=7,k2=2加密所得的密文用仿射解密得出原来的明文,所以正确性得到验证
安全性分析
1.仿射密码对于任意两个不同的字母,其最后得到的密文肯定不一样;所以当密文长度足够长时,我们可以使用频率分析的方法来解决。利用仿射密码时,一般只有 26 个字母,而不大于 26 的与 26 互素的个数一共有12个,算上偏移量,也就是大概12x26=312种可能性。
一般来说,对于该种密码,至少得是在已知部分明文的情况下才可以攻击。下面进行简单的分析。
已知部分明密文对:y1=(ax1+b)mod26
y2=(ax2+b)(mod26)
两式相减:y1−y2=a(x1−x2)(mod26)
很容易得到a,得到了a即可解出b
2.对密文直接用312个**空间进行暴破,脚本如下:
#coding:utf-8
plain="zebbwqmif"
c=""
k=[1,3,5,7,9,11,15,17,19,21,23,25]
for i in range(12):
for j in range(26):
c=""
for x in range(len(plain)):
res=chr((ord(plain[x])-ord('a')-j)*k[i]%26+ord('a'))
c+=res
print c#+'\n'
if c=="hellocumt":
print 8*"*"+"find it"+8*"*"
运行结果:找到有意义的密文