原理


仿射密码是一种表单代换密码,字母表的每个字母相应的值使用一个简单的数学函数对应一个数值,再把对应数值转换成字母。

Java仿射密码加密解密代码_ci


加密函数:E(x) = (ax + b) (mod m),其中 a与m互质,x表示明文按照某种编码得到的数字,m是编码系统中字母的个数(通常都是26)。

解密函数:D(x) = a^{-1} (x - b) (mod m),其中 a^{-1} 是 a 在Z_{m}群的乘法逆元。


乘法逆元


了解一下乘法逆元 欧几里得算法求解乘法逆元——Python

#欧几里得算法求最大公约数
def get_gcd(a, b):
	k = a // b
	remainder = a % b
	while remainder != 0:
		a = b 
		b = remainder
		k = a // b
		remainder = a % b
	return b
	
#改进欧几里得算法求线性方程的x与y
def get_(a, b):
	if b == 0:
		return 1, 0
	else:
		k = a // b
		remainder = a % b		
		x1, y1 = get_(b, remainder)
		x, y = y1, x1 - k * y1			
	return x, y
	
a, b = input().split()
a, b = int(a), int(b)
 
#将初始b的绝对值进行保存
if b < 0:
	m = abs(b)
else:
	m = b
flag = get_gcd(a, b)
 
#判断最大公约数是否为1,若不是则没有逆元
if flag == 1:	
	x, y = get_(a, b)	
	x0 = x % m #对于Python '%'就是求模运算,因此不需要'+m'
	print(x0) #x0就是所求的逆元
else:
	print("Do not have!")

比如求5关于模26的乘法逆元

Java仿射密码加密解密代码_乘法逆元_02


理解原理之例子


下面举个例子
加密:
我们以 E(x)


脚本


下面是关于求仿射密码的python3脚本(自己写的,有错请指正):

#仿射密码解密
#改进欧几里得算法求线性方程的x与y
def get(a, b):
    if b == 0:
        return 1, 0
    else:
        k = a //b
        remainder = a % b
        x1, y1 = get(b, remainder)
        x, y =y1, x1 - k * y1
    return x, y
 
s = input("请输入解密字符:").upper()
a = int(input("请输入a:"))
b = int(input("请输入b:"))
 
#求a关于26的乘法逆元
x, y = get(a, 26)
a1 = x % 26
 
l= len(s)
for i in range(l):
    cipher = a1 * (ord(s[i])- 65 - b) % 26
    res=chr(cipher + 65)
    print(res, end='')

Java仿射密码加密解密代码_欧几里得算法_03


深度破解


首先,我们可以看到的是,仿射密码对于任意两个不同的字母,其最后得到的密文必然不一样,所以其也具有最通用的特点。当密文长度足够长时,我们可以使用频率分析的方法来解决。

其次,我们可以考虑如何攻击该密码。可以看出当a=1

时,仿射加密是凯撒加密。而一般来说,我们利用仿射密码时,其字符集都用的是字母表,一般只有26个字母,而不大于26的与26互素的个数一共有

ϕ(26)=ϕ(2)×ϕ(13)=12

算上b的偏移可能,一共有可能的密钥空间大小也就是

12×26=312

一般来说,对于该种密码,我们至少得是在已知部分明文的情况下才可以攻击。下面进行简单的分析。

这种密码由两种参数来控制,如果我们知道其中任意一个参数,那我们便可以很容易地快速枚举另外一个参数得到答案。

但是,假设我们已经知道采用的字母集,这里假设为26个字母,我们还有另外一种解密方式,我们只需要知道两个加密后的字母 y1,y2

即可进行解密。那么我们还可以知道

y1=(ax1+b)(mod26) y2=(ax2+b)(mod26)

两式相减,可得

y1−y2=a(x1−x2)(mod26)

这里 y1,y2

已知,如果我们知道密文对应的两个不一样的字符 x1 与 x2 ,那么我们就可以很容易得到 a ,进而就可以得到 b 了。


破解举例


放射密码分析目标:求a,b

方法:求出频率最高的两个字母,只需要猜出两个字母的变换,就能得到a,b

英文统计规律:

Java仿射密码加密解密代码_Java仿射密码加密解密代码_04


我们用CAP来分析一个例子

密文:FMXVEDKAPHFERBNDKRXRSREFMORUDSDKDVSHVUFEDKAPRKDLYEVLRHHRH

频率分析:

我们可以看到r(8次)和d(7次)最高

Java仿射密码加密解密代码_ci_05


根据英文明文分布规律,我们假设r对应e,d对应t,r的序号是17,e是4,d是3,t是19

所以我们可以列出两个方程

17=(4a+b)mod26

3=(19a+b)mod26

解出方程a=6,b=19因为a和26现在的最大公约数是2,不是1,所以假设不成立

我们继续假设r是e的加密,e是t的加密,得到a=8,不满足,继续假设r是e的加密,k是t的加密,a=3,b=5,是一个合法的秘钥。

点击ciphers中的Affine,

Java仿射密码加密解密代码_欧几里得算法_06


a,b分别填3,5,解密,得到明文algorithmsarequitegeneraldefinitionsofarithmeticprocesses

Java仿射密码加密解密代码_Java仿射密码加密解密代码_07