仿射密码(Affine Cipher) 是一种古典加密方法,它基于线性代数中的仿射变换。它是替代密码的一种类型,其中每个字母被映射到一个数字,并通过线性函数进行加密和解密。具体来说,放射密码使用了两个线性变换参数a和b,并且加密和解密过程依赖于模运算。
这是一张字母表以及字母对应位置的数字

直入主题
加密过程
放射密码的加密公式如下:
C=(aP+b) mod m
- P是明文字符对应的数字(例如,A = 0, B = 1, C = 2, ..., Z = 25)。
- C是加密后的密文字符对应的数字。
- a和 b(任意数,通常我们选择 0≤b<m)是密钥,其中 a和模 m互素(即 gcd(a,m)=1,确保 a有模反元素),m是字母表的大小(通常为 26)。我们需要找出在 1 到 25 之间(因为 a的值不能为 0)的与 26 互素的数。通过计算,a∈{1,3,5,7,9,11,15,17,19,21,23,25},任意挑以一个作为密钥就行,计算过程如此:
-
#判断互质数 import math for i in range(1,26): if math.gcd(i,26)==1: print(i) - mod m表示模 m运算,确保结果仍然是一个有效的字母表位置。
解密过程
解密公式如下:
P=a^-1(C−b) mod m
- a^-1是 a在模 m下的乘法逆元,满足 a⋅a^-1≡1mod m。
- C是密文字符对应的数字。
- P是解密后的明文字符对应的数字。
举个例子:
假设使用的密钥是 a=5,b=8,且明文为 "HELLO"。我们将字母映射为数字后,使用加密公式进行加密。
- 对照字母表将每个字母转化为对应位置的数字:
- H = 7, E = 4, L = 11, L = 11, O = 14
- 加密过程:
- 对于 H:C=(5⋅7+8) mod 26=43 mod 26=17 (对应 R)
- 对于 E:C=(5⋅4+8) mod 26=28 mod 26=2 (对应 C)
- 对于 L:C=(5⋅11+8) mod 26=63 mod 26=11 (对应 L)
- 对于 O:C=(5⋅14+8) mod 26=78 mod 26=0(对应 A)
密文就是 "RCLLA"。
解密过程
首先我们需要找到 a=5在模 26 下的逆元。通过扩展欧几里得算法可以找到 a^−1=21。
即解密公式为:
P=21(C−8) mod 26
介绍下乘法逆元:
乘法逆元(Multiplicative Inverse)是指在模运算下,一个数与它的乘法逆元相乘,其结果为 1。具体来说,给定一个整数a和一个模数n,如果存在一个整数 x使得:
a⋅x≡1(mod n)
那么x就是a的模n的乘法逆元。
关键点:
- 模运算:这里的乘法逆元通常是在模n的情形下讨论的,也就是说我们关注的是在除以n之后的余数。
- 互质条件:在模n下,a和n必须是互质的(即它们的最大公约数是 1),才能保证a存在乘法逆元。
例子:
-
考虑 a=3,n=7,我们要找到一个 x使得:
3⋅x≡1(mod7)
通过尝试 x=5,我们有:
3⋅5=15
15 除以 7 的余数是 1,即:
15≡1(mod7)
所以5就是3在模7下的乘法逆元。
现在我们知道21的来历了,也就是5⋅x≡1(mod 26),即5x+26y=1,用python写个算法计算下:
# 扩展欧几里得算法
def extended_gcd(a, b):
if a == 0:
return b, 0, 1
gcd, x1, y1 = extended_gcd(b % a, a)
x = y1 - (b // a) * x1
y = x1
return gcd, x, y
# 寻找 5 在模 26 下的逆元
a = 5
m = 26
gcd, x, y = extended_gcd(a, m)
# 如果 gcd 是 1,x 就是模反元素
if gcd == 1:
inverse = x % m
else:
inverse = None # 如果 gcd != 1,说明没有逆元
print(f"x={inverse}是5在模26下的逆元")
所以对于R: P=21(17−8) mod 26=189 mod 26=7 (对应H)...以此类推可以解出密文HELLO。
当然啦,要是我们不知道密钥a和b该怎么办?
直接爆破,因为密钥空间相对较小,特别是对于英文字母表的情况,
暴力破解仿射密码
放射密码的密钥包括两个参数:a和 b。
- a的可能值:如前所述,a必须满足与26互素的条件,在1到25之间,符合条件的a有12个。
- b的可能值:b的值可以是任意从0到25的整数,因为它是一个平移量。
因此,密钥空间的大小是 12×26=312,这意味着总共有 312 种不同的密钥组合。
我提供一个完整的爆破代码:
# 求模26下的乘法逆元
def mod_inverse(a, m):
for x in range(1, m):
if (a * x) % m == 1:
return x
return None # 如果找不到逆元
# 放射密码的解密公式
def affine_decrypt(ciphertext, a, b, m=26):
a_inv = mod_inverse(a, m) # 计算 a 的逆元
if a_inv is None:
return None # 如果没有逆元,跳过
plaintext = ""
for char in ciphertext:
if char in letter_to_num:
c = letter_to_num[char]
p = (a_inv * (c - b)) % m
plaintext += num_to_letter[p]
else:
plaintext += char # 保留非字母字符
return plaintext
# 暴力破解
def brute_force_affine(ciphertext):
possible_a_values = [1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25] # a的可能值,要求与26互素
all_possible_solutions = []
for a in possible_a_values:
for b in range(26):
decrypted_text = affine_decrypt(ciphertext, a, b)
if decrypted_text:
all_possible_solutions.append((a, b, decrypted_text))
return all_possible_solutions
# 示例密文
ciphertext = "RCLLA"
# 执行暴力破解
solutions = brute_force_affine(ciphertext)
# 输出所有可能的解密结果
for a, b, plaintext in solutions:
print(f"a = {a}, b = {b}: {plaintext}")
然后根据经验判断一下明文。

1万+

被折叠的 条评论
为什么被折叠?



