Python趣味编程:手把手带你玩转凯撒到仿射古典密码(收藏版)

本文通过Python实战,带你轻松入门古典密码学。从不到10行的凯撒密码到需要模运算的仿射密码,用代码直观展示移位加密原理。文章包含开发环境设置、加密解密实现、频率分析破解等实战案例,并揭示这些古老密码对现代算法(如AES)的启发。特别适合零基础小白,通过动手编程自然理解模运算、逆元等数学概念,附赠密码工具包开发思路和进阶练习。

用Python实战古典密码:从凯撒到仿射的趣味编程之旅

密码学总给人一种高深莫测的印象,尤其是那些充满数学符号的教科书,常让初学者望而生畏。但你知道吗?用几十行Python代码就能亲手实现凯撒大帝用来传递军情的加密方法,还能用同样的思路破解简单的密文。本文将带你用程序员的视角重新认识这些古老的加密艺术——不需要死记硬背数学公式,而是在敲代码的过程中自然理解模运算、逆元等概念。

1. 开发环境准备

工欲善其事,必先利其器。我们选择Python不仅因为它语法简洁,更因其丰富的运算符和数据结构特别适合演示密码算法。建议使用Python 3.8+版本,任何编辑器或IDE都可以,但Jupyter Notebook的交互特性可能更适合边学边试。

安装完成后,先确认几个基础工具包:

python --version # 确认版本
pip install numpy # 可选,用于高级数学运算

提示:虽然本文会从基础讲起,但假设读者已经了解Python的基本语法如变量、循环和函数定义。如果遇到不熟悉的语法,可以随时查阅Python官方文档。

2. 凯撒密码:移位加密的活化石

公元前58年,凯撒在征服高卢的战争中发明了这种将字母按固定位数移位的加密方法。现代程序员可以用不到10行代码还原这个古老智慧:

def caesar_cipher(text, shift):
 result = []
 for char in text:
 if char.isupper():
 result.append(chr((ord(char) + shift - 65) % 26 + 65))
 elif char.islower():
 result.append(chr((ord(char) + shift - 97) % 26 + 97))
 else:
 result.append(char)
 return ''.join(result)

# 示例用法
plaintext = "Attack at dawn!"
shift = 3
ciphertext = caesar_cipher(plaintext, shift) # 加密
print(ciphertext) # 输出: Dwwdfn dw gdzq!

这段代码的核心在于模运算% 26,它确保了字母表循环移位——当’Z’后移3位时会回到’C’。要解密只需使用负的shift值:

original = caesar_cipher(ciphertext, -shift)
print(original) # 输出: Attack at dawn!

凯撒密码的脆弱性体现在几个方面:

  • 仅有26种可能的密钥(shift值)
  • 字母频率分析可以轻松破解
  • 无法抵抗暴力穷举攻击

3. 仿射密码:凯撒的数学升级版

仿射变换将凯撒密码的简单移位升级为线性变换,其加密公式为:

E(x) = (a*x + b) mod 26

其中a必须与26互质(即gcd(a,26)=1),这样才能保证存在乘法逆元用于解密。

先实现一个求最大公约数的函数,这是检查a是否合法的前提:

def gcd(a, b):
 while b != 0:
 a, b = b, a % b
 return a

完整的仿射加密实现:

def affine_encrypt(text, a, b):
 result = []
 for char in text:
 if char.isupper():
 x = ord(char) - 65
 result.append(chr((a * x + b) % 26 + 65))
 elif char.islower():
 x = ord(char) - 97
 result.append(chr((a * x + b) % 26 + 97))
 else:
 result.append(char)
 return ''.join(result)

解密需要找到a的模逆元a⁻¹,满足(a * a⁻¹) mod 26 = 1。扩展欧几里得算法可以高效计算这个值:

def modinv(a, m):
 g, x, y = extended_gcd(a, m)
 if g != 1:
 raise ValueError('模逆不存在')
 return x % m

def extended_gcd(a, b):
 if a == 0:
 return (b, 0, 1)
 else:
 g, y, x = extended_gcd(b % a, a)
 return (g, x - (b // a) * y, y)

现在可以完成解密函数:

def affine_decrypt(ciphertext, a, b):
 a_inv = modinv(a, 26)
 result = []
 for char in ciphertext:
 if char.isupper():
 y = ord(char) - 65
 result.append(chr((a_inv * (y - b)) % 26 + 65))
 elif char.islower():
 y = ord(char) - 97
 result.append(chr((a_inv * (y - b)) % 26 + 97))
 else:
 result.append(char)
 return ''.join(result)

参数选择示例:

  • 合法参数:a=5, b=8(因为gcd(5,26)=1)
  • 非法参数:a=4, b=7(gcd(4,26)=2≠1)
# 完整示例
a, b = 5, 8
plain = "Hello Cryptography!"
cipher = affine_encrypt(plain, a, b) # 'Jqttw Kpixgbpikjca!'
decrypted = affine_decrypt(cipher, a, b) # 恢复原文

4. 从古典到现代:密码学思维演进

虽然这些古典密码已不再安全,但它们蕴含的核心思想在现代密码学中依然闪耀:

古典概念 现代对应 应用实例
字母移位 比特置换 DES加密的P-box
仿射变换 线性扩散层 AES的MixColumns
多表代换 非线性替换 AES的S-box
密钥空间 安全参数 RSA的模数位数

现代AES算法虽然复杂,但其核心的SubBytes阶段本质上也是一种替换(尽管是在GF(2⁸)有限域上),而ShiftRows则继承了凯撒移位的精髓。

密码设计黄金法则:

  1. 混淆(Confusion):使密钥与密文关系复杂

  2. 扩散(Diffusion):让明文单个比特影响多个密文比特

  3. 密钥空间足够大:抵抗暴力破解

  4. 算法公开:安全只依赖于密钥保密

5. 实战:破解凯撒密码

理解加密的最好方式就是尝试破解。对于凯撒密码,即使不知道shift值,我们也能通过频率分析或暴力尝试来破译:

def crack_caesar(ciphertext):
 # 英语字母频率表
 freq = [8.2, 1.5, 2.8, 4.3, 12.7, 2.2, 2.0, 6.1, 7.0,
 0.2, 0.8, 4.0, 2.4, 6.7, 7.5, 1.9, 0.1, 6.0,
 6.3, 9.1, 2.8, 1.0, 2.4, 0.2, 2.0, 0.1]

 best_shift = 0
 min_diff = float('inf')

 for shift in range(26):
 decrypted = caesar_cipher(ciphertext, -shift)
 count = [0]*26
 total = 0

 for c in decrypted.lower():
 if 'a' <= c <= 'z':
 count[ord(c)-97] += 1
 total += 1

 if total == 0:
 continue

 # 计算卡方统计量
 chi_sq = 0
 for i in range(26):
 observed = count[i]
 expected = total * freq[i] / 100
 chi_sq += (observed - expected)2 / expected

 if chi_sq < min_diff:
 min_diff = chi_sq
 best_shift = shift

 return best_shift

这个破解器通过比较解密文本与英语字母的标准频率分布,找出最可能的shift值。虽然对短文本可能不准,但对于超过100个字母的密文通常能正确识别。

6. 密码学编程的常见陷阱

在实现密码算法时,有几个容易踩坑的地方值得特别注意:

字符编码问题:

  • ASCII码与字母序号的转换要准确(A=65还是0?)
  • 非字母字符(空格、标点)的处理策略
  • Unicode字符可能导致的意外行为

模运算细节:

# 负数取模的两种处理方式
-5 % 26 # Python中结果为21
math.fmod(-5, 26) # 结果为-5.0

性能考量:
对于长文本,纯Python实现可能较慢。可以考虑:

  • 使用字符串的translate方法
  • 对numpy数组进行向量化操作
  • 对性能关键部分用Cython加速

一个优化后的凯撒加密版本:

def caesar_fast(text, shift):
 shift = shift % 26
 lower = str.maketrans(
 'abcdefghijklmnopqrstuvwxyz',
 'abcdefghijklmnopqrstuvwxyz'[shift:] +
 'abcdefghijklmnopqrstuvwxyz'[:shift])
 upper = str.maketrans(
 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[shift:] +
 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[:shift])
 return text.translate(lower).translate(upper)

7. 扩展应用:构建密码工具包

将上述函数封装成类,可以创建一个简单的密码工具包:

class ClassicalCipher:
 def __init__(self):
 self.english_freq = [...] # 频率表

 def caesar(self, text, shift, decrypt=False):
 if decrypt:
 shift = -shift
 # 实现代码...

 def affine(self, text, a, b, decrypt=False):
 if decrypt:
 # 解密逻辑
 else:
 # 加密逻辑

 @staticmethod
 def gcd(a, b):
 # 实现代码...

 def frequency_analysis(self, text):
 # 统计字母频率
 return freq_dict

 def crack_caesar(self, ciphertext):
 # 破解实现
 return most_likely_shift

这个类可以进一步扩展支持维吉尼亚密码、置换密码等其他古典加密方法。对于想继续探索的读者,可以考虑实现:

  1. 多表代换的维吉尼亚密码

  2. 基于关键词的字母表置换

  3. 结合加密与文件IO的完整应用

  4. 简单的加密通信协议

密码学编程最迷人的地方在于,你能亲眼看到抽象的数学概念如何转化为实际可运行的代码。当你的程序成功解密一段古老密文时,那种穿越时空与凯撒对话的奇妙感觉,是单纯理论学习无法给予的。

《网络安全从零到精通全套学习大礼包》

96节从入门到精通的全套视频教程免费领取

如果你也想通过学网络安全技术去帮助就业和转行,我可以把我自己亲自录制的96节 从零基础到精通的视频教程以及配套学习资料无偿分享给你。

请添加图片描述

网络安全学习路线图

想要学习 网络安全,作为新手一定要先按照路线图学习方向不对,努力白费。对于从来没有接触过网络安全的同学,我帮大家准备了从零基础到精通学习成长路线图以及学习规划。可以说是最科学最系统的学习路线,大家跟着这个路线图学习准没错。

请添加图片描述

配套实战项目/源码

所有视频教程所涉及的实战项目和项目源码

在这里插入图片描述

学习电子书籍

学习网络安全必看的书籍和文章的PDF,市面上网络安全书籍确实太多了,这些是我精选出来的

在这里插入图片描述

面试真题/经验

请添加图片描述

以上资料如何领取?

img

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐