仿射密码-简单易懂

该文章已生成可运行项目,

仿射密码(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"。我们将字母映射为数字后,使用加密公式进行加密。

  1. 对照字母表将每个字母转化为对应位置的数字:
    • H = 7, E = 4, L = 11, L = 11, O = 14
  2. 加密过程:
    • 对于 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的乘法逆元。

关键点:

  1. 模运算:这里的乘法逆元通常是在模n的情形下讨论的,也就是说我们关注的是在除以n之后的余数。
  2. 互质条件:在模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}")

然后根据经验判断一下明文。

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值