📜 一、恩尼格玛机:从战场传奇到计算机先驱

1940年,德国U型潜艇在大西洋横行,它们使用的“恩尼格玛”密码机被宣称永远无法被破解。这种形似打字机的设备,能将明文变成看似随机的乱码,而接收方只要设置相同的初始状态,就能一键还原。

恩尼格玛的核心创意在于:每次按键后,转子会转动,使同一个字母每次加密结果都不同。再加上插线板(Steckerbrett)交换字母对,让总密钥空间达到天文数字——1.58 × 10²⁰ 种可能。

然而,波兰数学家 Marian Rejewski 和后来的英国布莱切利园团队(包括图灵)利用密码机的一个致命缺陷(明文中的固定短语和反射器导致字母永不自映射)成功破解,将战争缩短了至少两年。

今天我们不需要复杂的机械,只需 Python 就能复现这台传奇机器,并拥有完整GUI界面。项目文件我放在了文末,下面先看核心功能。

💻 二、代码解剖:每个部件如何工作?

整个程序包含五个关键类,分别对应真实的恩尼格玛机的五个物理部件。

nngm.py
Plugboard 插线板:交换字母对
Rotor 转子:接线 + 接口 + 正向像映射
Reflector 反射器:固定字母映射
EnigmaMachine 整机集成:步进、加解密
EnigmaAPP 图形界面(tkinter)

🧩 1. 插线板 —— 字母乱配

真实插线板允许操作员用线缆连接一对字母,比如A↔B。加密时A会变成B,B变成A。代码中用字典存储映射:

class Plugboard:
    def __init__(self, pairs=None):
        self.mapping = {c: c for c in string.ascii_uppercase}
        if pairs:
            for a, b in pairs:
                self.mapping[a] = b
                self.mapping[b] = a
    def map(self, char):
        return self.mapping.get(char, char)

🎡 2. 转子 —— 核心加密引擎

恩尼格玛通常有3个转子(后来有4个),每个转子内部有26条“杂乱”的接线,例如历史转子I的接线为:

A→E, B→K, C→M, D→F, ...

除此之外,每个转子还有一个缺口字母(notch),当转子转到该位置时,会触发相邻转子转动——这就是著名的双步进机制。

代码中的Rotor类同时实现了正向映射(键盘→反射器)和反向映射(反射器→键盘),因为电流经过反射器后要再逆向穿过转子一次。

class Rotor:
    def __init__(self, rotor_type, ring_setting=0, position=0):
        wiring, notch = ROTOR_SPECS[rotor_type]
        self.wiring = wiring          # 正向接线表
        self.rev_wiring = ...         # 反向接线表(预计算)
        self.notch = notch
        self.ring_setting = ring_setting  # 环偏移
        self.position = position          # 当前字母位置

    def forward_map(self, char_in):
        # 经过环偏移和当前位置后,查表并返回输出字母的编号
        ...

    def backward_map(self, char_in):
        # 反向过程
        ...

环设置 (Ringstellung) 是一个细微但重要的概念:它可以改变转子内部接线的“零点”,相当于给转子加了一个偏移,增强密钥空间。

🔁 3. 反射器 —— 让加解密对称

反射器是一块固定接线的半转子,它将信号从最后一个转子接收后,映射到另一条线路再送回转子组。因为反射器不转动,这保证了恩尼格玛机的加解密完全对称——用相同配置加密两次即可还原。

class Reflector:
    def __init__(self, reflector_type):
        self.wiring = REFLECTOR_SPECS[reflector_type]  # 如B型:"YRUHQSLDPXNGOKMIEBFZCWVJAT"
    def map(self, char_in):
        return ord(self.wiring[char_in]) - 65

⚙️ 4. 整机集成与双步进模拟

EnigmaMachine类整合了插线板、转子组和反射器,并提供encrypt_char()方法模拟一次按键的完整流程:

键盘 → 插线板 → 右转子 → 中转子 → 左转子 → 反射器 → 左转子 → 中转子 → 右转子 → 插线板 → 灯板

其中最复杂的逻辑是转子步进。真实恩尼格玛机的步进不是简单的“最右转子每按键走一步,满26步带动左边一个”——而是存在“双步进”陷阱:当中转子处于自身缺口位置时,下一次按键会同时转动中转子和左转子。

def _step_rotors(self):
    # 最右转子总是转动
    self.rotors[-1].rotate()
    # 检查此前传递的转动信号(从左→右)
    for i in range(len(self.rotors) - 2, -1, -1):
        if self.next_turn[i]:
            self.rotors[i].rotate()
    # 生成本次转动信号(下一次使用)
    for i in range(len(self.rotors) - 1):
        self.next_turn[i] = self.rotors[i + 1].is_at_notch

🖥️ 5. GUI —— 密码机三标签页

GUI方面,分成三个标签页:

📝 加密/解密页

1、大文本框输入原文/密文

2、绿色按钮加密,橙色按钮解密,自动处理非字母字符

3、一键复制输出结果

🔧 机器配置页

1、预设配置:一键加载默认、历史实例、海军型、C型反射器配置

转子表格:三个转子依次排开,可直接下拉选择型号、环设置、初始位置。缺口字母自动随型号变化

2、反射器选择:B/C两型

3、插线板可视化:画布显示A-Z两排字母,用红色曲线连接交换对,下拉框智能过滤已用字母

🧭 转子状态页

1、三个转子的图形化展示,中央大字母显示当前位置

2、上方显示上一字母,下方显示下一字母

3、转子下方标注环设置和缺口位置

4、金色箭头指示信号流向(右→中→左→反射器)

5、支持手动设置转子位置、重置、单步转动

🎮 三、如何使用?三步上手

1、启动程序

python3 nngm.py

2、快速体验

  1. 在「机器配置」页,选择预设 默认 (I-II-III, B, AAA-AAA) → 点击「加载预设」→「应用配置」

  2. 切换到「加密/解密」页,输入 HELLO WORLD,点击「🔒 加密」

  3. 看到一串乱码(例如 KMVG JQZHK),再点击「🔓 解密」,即可解密密文

3、动手调整

  1. 改转子顺序:把右转子从III换成I,再次加密同一句话,结果完全不同

  2. 添加插线板连接:比如让A↔B,C↔D,观察输出变化

  3. 手动转动转子:在「转子状态」页点“单步”,看转子窗口字母变化

Github Enigma机代码https://github.com/Jasonobama/enigma

更多推荐