凯撒密码

Python 凯撒密码:完整编程教程与源代码

完整的 Python 凯撒密码教程,包含源代码示例、GUI 应用程序、密码分析工具和专业实现。适合 Python 学习者和密码学程序员。

发布于 2025年8月11日
12 分钟阅读
密码学指南
Python Caesar cipher programming cover showing code snippets, IDE interface, algorithm implementation, and complete source code examples with syntax highlighting
Python 凯撒密码编程:完整教程与源代码示例

Python 已成为密码学教育和实用安全工具开发的首选语言,它将简洁性、可读性与强大的库完美融合,既让初学者能轻松理解复杂算法,又能支持专业级实现。凯撒密码是 Python 程序员学习密码学的理想起点——它具备清晰的数学基础,并能立即应用于实践,充分展示核心编程概念。

本 Python 教程你将构建的内容

🔧 基础凯撒密码函数 — 带错误处理的核心加密/解密算法 📊 密码分析工具 — 频率分析与自动解密函数 🖥️ GUI 应用程序 — 基于 Tkinter 的实时加密/解密交互界面 📁 文件处理 — 批量加密/解密整个文本文件,附进度指示 ⚡ 性能优化 — 适用于大规模文本处理的高效实现 🧪 测试套件 — 完整的单元测试,用于验证实现的正确性

本教程将带你系统地从基础函数出发,实现凯撒密码算法,直至构建包含 GUI 界面、自动密码分析工具和专业级实现的复杂应用程序。无论你是正在学习基础编程概念的 Python 初学者,还是希望探索密码学应用的资深开发者,都能在这里找到能加速学习和开发进程的实用技术与完整源代码示例。

教程按照从简单加密函数到高级特性的顺序系统推进,涵盖频率分析、自动解密、交互式 GUI 应用程序以及性能优化技术。每个代码示例均附有详细说明、最佳实践建议以及真实应用场景,将理论概念与实际编程技能紧密结合。

Python 在字符串操作、数学运算和用户界面开发方面的优势,使其特别适合密码学教育和工具创建。Python 丰富的标准库和第三方生态系统提供了构建复杂密码分析应用程序所需的一切,同时保持代码的清晰性和可维护性,便于学习与协作。

对于 Python 学习者而言,本项目通过一个引人入胜的实践应用,展示了函数、类、错误处理、文件操作和 GUI 开发等核心编程概念。密码学爱好者则能从中领略数学基础、算法分析以及将基础实现扩展为专业级工具的高级特性,这些工具适用于教育和研究场景。

Python 凯撒密码基础

理解算法

凯撒密码实现了一种简单的数学变换:将字母表中每个字母按固定数量的位置进行位移。在 Python 中,加密的数学表达式为 (x + n) % 26,其中 x 表示字母的位置(A=0、B=1,以此类推),n 为位移值。取模运算确保位移在字母表范围内循环——当计算结果超过 Z 时,自动回绕到开头。

Python 中的数学基础:

# 加密:(位置 + 位移) % 字母表大小
# 解密:(位置 - 位移) % 字母表大小

def get_letter_position(letter):
    """将字母转换为数字位置(A=0、B=1 等)"""
    return ord(letter.upper()) - ord('A')

def position_to_letter(position):
    """将数字位置转换回字母"""
    return chr(position + ord('A'))

字符处理注意事项: Python 内置的字符串方法和 ASCII 函数为字符操作提供了优雅的解决方案。ord() 函数将字符转换为 ASCII 值,chr() 则将 ASCII 值转换回字符。这种方式能同时处理大写和小写字母,同时保持凯撒密码运算所需的数学关系。

# ASCII 值操作示例
print(ord('A'))  # Output: 65
print(ord('Z'))  # Output: 90
print(chr(65))   # Output: 'A'
print(chr(90))   # Output: 'Z'

# 计算位移后的位置
letter = 'H'
shift = 3
position = ord(letter) - ord('A')  # H = position 7
new_position = (position + shift) % 26  # (7 + 3) % 26 = 10
result = chr(new_position + ord('A'))  # Position 10 = 'K'

Python 核心概念

字符串操作与迭代: 凯撒密码的实现高度依赖字符串处理和逐字符变换。Python 的字符串迭代能力与列表推导式提供了高效且可读的文本处理方式:

def process_text_basic(text, shift):
    """演示凯撒密码的基本字符串处理"""
    result = ""
    
    # 方式一:传统 for 循环
    for char in text:
        if char.isalpha():
            # 处理字母字符
            base = ord('A') if char.isupper() else ord('a')
            shifted = (ord(char) - base + shift) % 26
            result += chr(shifted + base)
        else:
            # 保留非字母字符
            result += char
    
    return result

# 方式二:列表推导式(更 Pythonic)
def process_text_comprehension(text, shift):
    """使用列表推导式写出更简洁的代码"""
    return ''.join([
        chr((ord(char) - ord('A') + shift) % 26 + ord('A'))
        if char.isupper() else
        chr((ord(char) - ord('a') + shift) % 26 + ord('a'))
        if char.islower() else char
        for char in text
    ])

模运算与边界情况: 取模运算符(%)能自动处理字母表回绕,但理解边界情况有助于构建健壮的实现:

def demonstrate_modulo_arithmetic():
    """演示取模运算如何处理字母表回绕"""
    examples = [
        ('Z', 1),   # Z + 1 应该变为 A
        ('A', -1),  # A - 1 应该变为 Z
        ('M', 13),  # 中间字母与 ROT13
        ('Z', 25)   # 最大位移
    ]
    
    for letter, shift in examples:
        pos = ord(letter) - ord('A')
        new_pos = (pos + shift) % 26
        result = chr(new_pos + ord('A'))
        print(f"{letter} + {shift} = {result}")
    
    # 正确处理负数位移
    def safe_modulo(value, modulus):
        """确保负数输入的结果为正数"""
        return ((value % modulus) + modulus) % modulus

完整 Python 实现指南

简单凯撒密码函数

以下是一个对初学者友好的完整实现,附有详细注释和错误处理:

def caesar_encrypt(text, shift):
    """
    使用凯撒密码对文本进行加密,位移量由参数指定。
    
    参数:
        text (str):待加密的明文
        shift (int):位移的位置数(正数向右,负数向左)
    
    返回值:
        str:加密后的密文
    
    示例:
        >>> caesar_encrypt("HELLO WORLD", 3)
        'KHOOR ZRUOG'
    """
    # 输入验证
    if not isinstance(text, str):
        raise TypeError("Text must be a string")
    if not isinstance(shift, int):
        raise TypeError("Shift must be an integer")
    
    # 将位移规范化到有效范围(0-25)
    shift = shift % 26
    
    result = []
    
    for char in text:
        if char.isalpha():
            # 判断是大写还是小写
            is_upper = char.isupper()
            
            # 转换为大写进行计算
            char_upper = char.upper()
            
            # 计算位移后的位置
            char_position = ord(char_upper) - ord('A')
            shifted_position = (char_position + shift) % 26
            
            # 转换回字符
            new_char = chr(shifted_position + ord('A'))
            
            # 保持原始大小写
            result.append(new_char if is_upper else new_char.lower())
        else:
            # 保留非字母字符(空格、标点、数字)
            result.append(char)
    
    return ''.join(result)


def caesar_decrypt(ciphertext, shift):
    """
    通过反向位移解密凯撒密码。
    
    参数:
        ciphertext (str):待解密的密文
        shift (int):加密时使用的位移值
    
    返回值:
        str:解密后的明文
    """
    return caesar_encrypt(ciphertext, -shift)


# 测试实现
if __name__ == "__main__":
    # 基础测试示例
    plaintext = "Hello, World! This is a test message."
    shift_value = 3
    
    print(f"Original: {plaintext}")
    
    encrypted = caesar_encrypt(plaintext, shift_value)
    print(f"Encrypted: {encrypted}")
    
    decrypted = caesar_decrypt(encrypted, shift_value)
    print(f"Decrypted: {decrypted}")
    
    # 验证加密/解密的往返正确性
    assert plaintext == decrypted, "Encryption/decryption failed!"
    print("✓ Encryption/decryption successful!")

包含多项特性的增强版本

这个高级实现包含配置选项、自定义字母表和专业错误处理:

import string
import re
from typing import Optional, Union

class AdvancedCaesarCipher:
    """
    具备多项特性与配置的高级凯撒密码实现。
    """
    
    def __init__(self, 
                 preserve_case: bool = True,
                 preserve_non_alpha: bool = True,
                 custom_alphabet: Optional[str] = None):
        """
        使用配置选项初始化密码器。
        
        参数:
            preserve_case:是否保持字母原始大小写
            preserve_non_alpha:是否保留非字母字符不变
            custom_alphabet:自定义字母表字符串(默认:英文 A-Z)
        """
        self.preserve_case = preserve_case
        self.preserve_non_alpha = preserve_non_alpha
        self.alphabet = custom_alphabet or string.ascii_uppercase
        self.alphabet_size = len(self.alphabet)
        
        # 创建查找字典以提升性能
        self.char_to_index = {char: i for i, char in enumerate(self.alphabet)}
        self.index_to_char = {i: char for i, char in enumerate(self.alphabet)}
    
    def encrypt(self, text: str, shift: int) -> str:
        """
        使用凯撒密码加密文本。
        
        参数:
            text:待加密的文本
            shift:位移值(正数表示右移)
        
        返回值:
            加密后的文本
        """
        return self._transform_text(text, shift)
    
    def decrypt(self, ciphertext: str, shift: int) -> str:
        """
        解密凯撒密码文本。
        
        参数:
            ciphertext:待解密的密文
            shift:加密时使用的位移值
        
        返回值:
            解密后的文本
        """
        return self._transform_text(ciphertext, -shift)
    
    def _transform_text(self, text: str, shift: int) -> str:
        """
        使用指定位移对文本进行变换的内部方法。
        """
        if not text:
            return ""
        
        shift = shift % self.alphabet_size
        result = []
        
        for char in text:
            if char.upper() in self.char_to_index:
                # 处理字母字符
                char_upper = char.upper()
                old_index = self.char_to_index[char_upper]
                new_index = (old_index + shift) % self.alphabet_size
                new_char = self.index_to_char[new_index]
                
                # 应用大小写保留
                if self.preserve_case and char.islower():
                    new_char = new_char.lower()
                
                result.append(new_char)
            else:
                # 处理非字母字符
                if self.preserve_non_alpha:
                    result.append(char)
                # 否则跳过该字符
        
        return ''.join(result)
    
    def bulk_encrypt(self, texts: list, shift: int) -> list:
        """
        使用相同位移批量加密多个文本。
        
        参数:
            texts:待加密的文本列表
            shift:位移值
        
        返回值:
            加密后的文本列表
        """
        return [self.encrypt(text, shift) for text in texts]
    
    def try_all_shifts(self, ciphertext: str) -> dict:
        """
        尝试所有可能的位移值进行解密。
        
        参数:
            ciphertext:待解密的密文
        
        返回值:
            将位移值映射到解密结果的字典
        """
        results = {}
        for shift in range(self.alphabet_size):
            decrypted = self.decrypt(ciphertext, shift)
            results[shift] = decrypted
        return results
    
    def analyze_frequency(self, text: str) -> dict:
        """
        分析给定文本中的字母频率。
        
        参数:
            text:待分析的文本
        
        返回值:
            将字母映射到其频率的字典
        """
        # 转换为大写并仅保留字母字符
        clean_text = ''.join(char.upper() for char in text if char.upper() in self.alphabet)
        total_chars = len(clean_text)
        
        if total_chars == 0:
            return {}
        
        frequency = {}
        for char in self.alphabet:
            count = clean_text.count(char)
            frequency[char] = count / total_chars
        
        return frequency


# 使用示例与测试
def demonstrate_advanced_features():
    """演示高级密码特性"""
    
    # 使用默认设置初始化密码器
    cipher = AdvancedCaesarCipher()
    
    # 测试数据
    test_message = "The Quick Brown Fox Jumps Over The Lazy Dog! 123"
    shift = 13  # ROT13
    
    print("=== Advanced Caesar Cipher Demo ===")
    print(f"Original: {test_message}")
    
    # 基本加密/解密
    encrypted = cipher.encrypt(test_message, shift)
    print(f"Encrypted (ROT13): {encrypted}")
    
    decrypted = cipher.decrypt(encrypted, shift)
    print(f"Decrypted: {decrypted}")
    
    # 尝试所有可能的位移
    print("\n=== All Possible Shifts ===")
    all_shifts = cipher.try_all_shifts("KHOOR")
    for shift_val, result in all_shifts.items():
        print(f"Shift {shift_val:2d}: {result}")
    
    # 频率分析
    print("\n=== Frequency Analysis ===")
    sample_text = "This is a sample text for frequency analysis testing"
    frequencies = cipher.analyze_frequency(sample_text)
    
    # 按频率降序排序
    sorted_freq = sorted(frequencies.items(), key=lambda x: x[1], reverse=True)
    print("Letter frequencies:")
    for letter, freq in sorted_freq[:10]:  # 前 10 个
        if freq > 0:
            print(f"  {letter}: {freq:.3f} ({freq*100:.1f}%)")
    
    # 自定义字母表示例
    print("\n=== Custom Alphabet Example ===")
    custom_cipher = AdvancedCaesarCipher(custom_alphabet="0123456789")
    numbers = "1234567890"
    encrypted_nums = custom_cipher.encrypt(numbers, 3)
    print(f"Numbers: {numbers}")
    print(f"Shifted:  {encrypted_nums}")


if __name__ == "__main__":
    demonstrate_advanced_features()

面向对象实现

以下是适合生产环境使用的完整专业级类实现:

import json
import os
from pathlib import Path
from typing import Dict, List, Optional, Tuple
import logging

class ProfessionalCaesarCipher:
    """
    具备全面特性的专业级凯撒密码实现。
    
    特性:
    - 多种加密/解密模式
    - 文件处理能力
    - 配置管理
    - 日志记录与错误处理
    - 统计分析工具
    - 导出/导入功能
    """
    
    # 用于密码分析的英文字母频率
    ENGLISH_FREQ = {
        'A': 0.08167, 'B': 0.01492, 'C': 0.02782, 'D': 0.04253,
        'E': 0.12702, 'F': 0.02228, 'G': 0.02015, 'H': 0.06094,
        'I': 0.06966, 'J': 0.00153, 'K': 0.00772, 'L': 0.04025,
        'M': 0.02406, 'N': 0.06749, 'O': 0.07507, 'P': 0.01929,
        'Q': 0.00095, 'R': 0.05987, 'S': 0.06327, 'T': 0.09056,
        'U': 0.02758, 'V': 0.00978, 'W': 0.02360, 'X': 0.00150,
        'Y': 0.01974, 'Z': 0.00074
    }
    
    def __init__(self, config_file: Optional[str] = None):
        """
        使用可选配置初始化密码器。
        
        参数:
            config_file:JSON 配置文件路径
        """
        # 设置日志记录
        logging.basicConfig(level=logging.INFO)
        self.logger = logging.getLogger(__name__)
        
        # 默认配置
        self.config = {
            'preserve_case': True,
            'preserve_spaces': True,
            'preserve_punctuation': True,
            'default_shift': 3,
            'alphabet': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        }
        
        # 如果提供了配置文件则加载
        if config_file and os.path.exists(config_file):
            self.load_config(config_file)
        
        self.alphabet_size = len(self.config['alphabet'])
        
    def load_config(self, config_file: str) -> None:
        """从 JSON 文件加载配置。"""
        try:
            with open(config_file, 'r') as f:
                user_config = json.load(f)
                self.config.update(user_config)
            self.logger.info(f"Configuration loaded from {config_file}")
        except Exception as e:
            self.logger.error(f"Failed to load config: {e}")
            raise
    
    def save_config(self, config_file: str) -> None:
        """将当前配置保存到 JSON 文件。"""
        try:
            with open(config_file, 'w') as f:
                json.dump(self.config, f, indent=2)
            self.logger.info(f"Configuration saved to {config_file}")
        except Exception as e:
            self.logger.error(f"Failed to save config: {e}")
            raise
    
    def encrypt(self, text: str, shift: Optional[int] = None) -> str:
        """
        使用凯撒密码加密文本。
        
        参数:
            text:待加密的文本
            shift:位移值(为 None 时使用默认值)
        
        返回值:
            加密后的文本
        """
        if shift is None:
            shift = self.config['default_shift']
        
        self.logger.debug(f"Encrypting text with shift {shift}")
        return self._transform(text, shift)
    
    def decrypt(self, ciphertext: str, shift: Optional[int] = None) -> str:
        """
        解密凯撒密码文本。
        
        参数:
            ciphertext:待解密的密文
            shift:加密时使用的位移值
        
        返回值:
            解密后的文本
        """
        if shift is None:
            shift = self.config['default_shift']
        
        self.logger.debug(f"Decrypting text with shift {shift}")
        return self._transform(ciphertext, -shift)
    
    def _transform(self, text: str, shift: int) -> str:
        """内部变换方法。"""
        if not text:
            return ""
        
        shift = shift % self.alphabet_size
        result = []
        
        for char in text:
            if char.upper() in self.config['alphabet']:
                # 变换字母字符
                is_lower = char.islower()
                char_upper = char.upper()
                
                old_pos = self.config['alphabet'].index(char_upper)
                new_pos = (old_pos + shift) % self.alphabet_size
                new_char = self.config['alphabet'][new_pos]
                
                if self.config['preserve_case'] and is_lower:
                    new_char = new_char.lower()
                
                result.append(new_char)
            elif char.isspace() and self.config['preserve_spaces']:
                result.append(char)
            elif not char.isalnum() and self.config['preserve_punctuation']:
                result.append(char)
            # 如果所有保留选项均不适用则跳过该字符
        
        return ''.join(result)
    
    def process_file(self, input_file: str, output_file: str, 
                    shift: int, encrypt: bool = True) -> None:
        """
        对整个文件应用凯撒密码处理。
        
        参数:
            input_file:输入文件路径
            output_file:输出文件路径
            shift:位移值
            encrypt:True 表示加密,False 表示解密
        """
        try:
            with open(input_file, 'r', encoding='utf-8') as infile:
                content = infile.read()
            
            if encrypt:
                processed_content = self.encrypt(content, shift)
                operation = "encrypted"
            else:
                processed_content = self.decrypt(content, shift)
                operation = "decrypted"
            
            with open(output_file, 'w', encoding='utf-8') as outfile:
                outfile.write(processed_content)
            
            self.logger.info(f"File {operation} successfully: {input_file} -> {output_file}")
            
        except Exception as e:
            self.logger.error(f"File processing failed: {e}")
            raise
    
    def frequency_analysis(self, text: str) -> Dict[str, float]:
        """
        对文本执行频率分析。
        
        参数:
            text:待分析的文本
        
        返回值:
            字母频率字典
        """
        # 清洗文本(仅保留大写字母)
        clean_text = ''.join(c.upper() for c in text if c.upper() in self.config['alphabet'])
        
        if not clean_text:
            return {}
        
        total_chars = len(clean_text)
        frequencies = {}
        
        for char in self.config['alphabet']:
            count = clean_text.count(char)
            frequencies[char] = count / total_chars
        
        return frequencies
    
    def chi_squared_analysis(self, text: str) -> List[Tuple[int, float]]:
        """
        执行卡方分析以找出最可能的位移值。
        
        参数:
            text:待分析的密文
        
        返回值:
            按分数排序的 (位移, 卡方分数) 元组列表
        """
        results = []
        
        for shift in range(self.alphabet_size):
            # 使用该位移尝试解密
            decrypted = self.decrypt(text, shift)
            frequencies = self.frequency_analysis(decrypted)
            
            # 计算卡方统计量
            chi_squared = 0.0
            for char in self.config['alphabet']:
                observed = frequencies.get(char, 0.0)
                expected = self.ENGLISH_FREQ[char]
                if expected > 0:
                    chi_squared += ((observed - expected) ** 2) / expected
            
            results.append((shift, chi_squared))
        
        # 按卡方值排序(越小越好)
        results.sort(key=lambda x: x[1])
        return results
    
    def auto_decrypt(self, ciphertext: str, num_candidates: int = 3) -> List[Tuple[int, str, float]]:
        """
        使用统计分析自动尝试解密凯撒密码。
        
        参数:
            ciphertext:待解密的密文
            num_candidates:返回的最佳候选数量
        
        返回值:
            (位移, 解密文本, 分数) 元组列表
        """
        chi_squared_results = self.chi_squared_analysis(ciphertext)
        candidates = []
        
        for shift, score in chi_squared_results[:num_candidates]:
            decrypted = self.decrypt(ciphertext, shift)
            candidates.append((shift, decrypted, score))
        
        return candidates
    
    def export_results(self, results: dict, filename: str) -> None:
        """
        将分析结果导出到 JSON 文件。
        
        参数:
            results:待导出的结果字典
            filename:输出文件名
        """
        try:
            with open(filename, 'w') as f:
                json.dump(results, f, indent=2)
            self.logger.info(f"Results exported to {filename}")
        except Exception as e:
            self.logger.error(f"Export failed: {e}")
            raise


# 演示与测试
def main():
    """演示专业凯撒密码实现。"""
    
    # 初始化密码器
    cipher = ProfessionalCaesarCipher()
    
    # 测试消息
    message = """
    The Caesar cipher is one of the earliest known and simplest ciphers.
    It is a type of substitution cipher in which each letter in the plaintext
    is 'shifted' a certain number of places down the alphabet.
    """
    
    print("=== Professional Caesar Cipher Demo ===")
    print(f"Original message:\n{message}")
    
    # 使用默认位移加密
    encrypted = cipher.encrypt(message)
    print(f"\nEncrypted:\n{encrypted}")
    
    # 解密
    decrypted = cipher.decrypt(encrypted)
    print(f"\nDecrypted:\n{decrypted}")
    
    # 演示自动解密(模拟未知位移)
    test_cipher = "WKH TXLFN EURZQ IRA MXPSV RYHU WKH ODCB GRJ"
    print(f"\n=== Auto-Decryption Demo ===")
    print(f"Unknown ciphertext: {test_cipher}")
    
    candidates = cipher.auto_decrypt(test_cipher, num_candidates=5)
    print("\nTop candidates:")
    for i, (shift, text, score) in enumerate(candidates, 1):
        print(f"{i}. Shift {shift:2d} (χ² = {score:.3f}): {text}")
    
    # 频率分析
    print(f"\n=== Frequency Analysis ===")
    frequencies = cipher.frequency_analysis(message)
    sorted_freq = sorted(frequencies.items(), key=lambda x: x[1], reverse=True)
    
    print("Top letter frequencies:")
    for letter, freq in sorted_freq[:10]:
        if freq > 0:
            print(f"  {letter}: {freq:.3f} ({freq*100:.1f}%)")


if __name__ == "__main__":
    main()

GUI 应用程序开发

基于 Tkinter 的界面

以下是使用 Python 内置 Tkinter 库构建的完整 GUI 应用程序:

import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox, filedialog
import threading
from typing import Optional

class CaesarCipherGUI:
    """
    凯撒密码操作的完整 GUI 应用程序。
    
    特性:
    - 实时加密/解密
    - 文件处理
    - 自动密码分析
    - 结果导出
    - 用户友好界面
    """
    
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Caesar Cipher Tool - Professional Edition")
        self.root.geometry("800x600")
        
        # 初始化后端密码器
        self.cipher = ProfessionalCaesarCipher()
        
        # 创建 GUI 元素
        self.setup_gui()
        
        # 绑定事件
        self.setup_events()
    
    def setup_gui(self):
        """创建并排列 GUI 元素。"""
        
        # 主选项卡面板
        self.notebook = ttk.Notebook(self.root)
        self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 创建选项卡
        self.create_encrypt_tab()
        self.create_decrypt_tab()
        self.create_analysis_tab()
        self.create_file_tab()
        
        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("Ready")
        status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN)
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)
    
    def create_encrypt_tab(self):
        """创建加密选项卡。"""
        encrypt_frame = ttk.Frame(self.notebook)
        self.notebook.add(encrypt_frame, text="Encrypt")
        
        # 输入区域
        input_frame = ttk.LabelFrame(encrypt_frame, text="Input Text")
        input_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        self.encrypt_input = scrolledtext.ScrolledText(input_frame, height=10)
        self.encrypt_input.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 控件区域
        control_frame = ttk.Frame(encrypt_frame)
        control_frame.pack(fill=tk.X, padx=10, pady=5)
        
        ttk.Label(control_frame, text="Shift:").pack(side=tk.LEFT)
        self.encrypt_shift = tk.IntVar(value=3)
        shift_spin = ttk.Spinbox(control_frame, from_=1, to=25, textvariable=self.encrypt_shift, width=10)
        shift_spin.pack(side=tk.LEFT, padx=(5, 10))
        
        ttk.Button(control_frame, text="Encrypt", command=self.encrypt_text).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="Clear", command=self.clear_encrypt).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="Copy Result", command=self.copy_encrypt_result).pack(side=tk.LEFT, padx=5)
        
        # 输出区域
        output_frame = ttk.LabelFrame(encrypt_frame, text="Encrypted Text")
        output_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        self.encrypt_output = scrolledtext.ScrolledText(output_frame, height=10, state=tk.DISABLED)
        self.encrypt_output.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
    
    def create_decrypt_tab(self):
        """创建解密选项卡。"""
        decrypt_frame = ttk.Frame(self.notebook)
        self.notebook.add(decrypt_frame, text="Decrypt")
        
        # 输入区域
        input_frame = ttk.LabelFrame(decrypt_frame, text="Encrypted Text")
        input_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        self.decrypt_input = scrolledtext.ScrolledText(input_frame, height=8)
        self.decrypt_input.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 控件区域
        control_frame = ttk.Frame(decrypt_frame)
        control_frame.pack(fill=tk.X, padx=10, pady=5)
        
        ttk.Label(control_frame, text="Shift:").pack(side=tk.LEFT)
        self.decrypt_shift = tk.IntVar(value=3)
        shift_spin = ttk.Spinbox(control_frame, from_=1, to=25, textvariable=self.decrypt_shift, width=10)
        shift_spin.pack(side=tk.LEFT, padx=(5, 10))
        
        ttk.Button(control_frame, text="Decrypt", command=self.decrypt_text).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="Auto Decrypt", command=self.auto_decrypt).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="Clear", command=self.clear_decrypt).pack(side=tk.LEFT, padx=5)
        
        # 输出区域
        output_frame = ttk.LabelFrame(decrypt_frame, text="Decrypted Text")
        output_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        self.decrypt_output = scrolledtext.ScrolledText(output_frame, height=8, state=tk.DISABLED)
        self.decrypt_output.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
    
    def create_analysis_tab(self):
        """创建密码分析选项卡。"""
        analysis_frame = ttk.Frame(self.notebook)
        self.notebook.add(analysis_frame, text="Analysis")
        
        # 输入区域
        input_frame = ttk.LabelFrame(analysis_frame, text="Text to Analyze")
        input_frame.pack(fill=tk.X, padx=10, pady=5)
        
        self.analysis_input = scrolledtext.ScrolledText(input_frame, height=6)
        self.analysis_input.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 控件区域
        control_frame = ttk.Frame(analysis_frame)
        control_frame.pack(fill=tk.X, padx=10, pady=5)
        
        ttk.Button(control_frame, text="Analyze All Shifts", command=self.analyze_all_shifts).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="Frequency Analysis", command=self.frequency_analysis).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="Export Results", command=self.export_analysis).pack(side=tk.LEFT, padx=5)
        
        # 结果区域
        results_frame = ttk.LabelFrame(analysis_frame, text="Analysis Results")
        results_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        # 结果树形视图
        columns = ('Shift', 'Score', 'Preview')
        self.analysis_tree = ttk.Treeview(results_frame, columns=columns, show='headings', height=8)
        
        for col in columns:
            self.analysis_tree.heading(col, text=col)
            self.analysis_tree.column(col, width=100)
        
        # 树形视图滚动条
        scrollbar = ttk.Scrollbar(results_frame, orient=tk.VERTICAL, command=self.analysis_tree.yview)
        self.analysis_tree.configure(yscrollcommand=scrollbar.set)
        
        self.analysis_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=5)
        
        # 详细结果显示
        detail_frame = ttk.LabelFrame(analysis_frame, text="Detailed Result")
        detail_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        self.analysis_detail = scrolledtext.ScrolledText(detail_frame, height=6, state=tk.DISABLED)
        self.analysis_detail.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 绑定树形视图选择事件
        self.analysis_tree.bind('<<TreeviewSelect>>', self.on_analysis_select)
    
    def create_file_tab(self):
        """创建文件处理选项卡。"""
        file_frame = ttk.Frame(self.notebook)
        self.notebook.add(file_frame, text="File Processing")
        
        # 文件选择
        file_select_frame = ttk.LabelFrame(file_frame, text="File Selection")
        file_select_frame.pack(fill=tk.X, padx=10, pady=5)
        
        # 输入文件
        ttk.Label(file_select_frame, text="Input File:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=2)
        self.input_file_var = tk.StringVar()
        ttk.Entry(file_select_frame, textvariable=self.input_file_var, width=50).grid(row=0, column=1, padx=5, pady=2)
        ttk.Button(file_select_frame, text="Browse", command=self.browse_input_file).grid(row=0, column=2, padx=5, pady=2)
        
        # 输出文件
        ttk.Label(file_select_frame, text="Output File:").grid(row=1, column=0, sticky=tk.W, padx=5, pady=2)
        self.output_file_var = tk.StringVar()
        ttk.Entry(file_select_frame, textvariable=self.output_file_var, width=50).grid(row=1, column=1, padx=5, pady=2)
        ttk.Button(file_select_frame, text="Browse", command=self.browse_output_file).grid(row=1, column=2, padx=5, pady=2)
        
        # 处理选项
        options_frame = ttk.LabelFrame(file_frame, text="Processing Options")
        options_frame.pack(fill=tk.X, padx=10, pady=5)
        
        ttk.Label(options_frame, text="Shift:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=2)
        self.file_shift = tk.IntVar(value=3)
        ttk.Spinbox(options_frame, from_=1, to=25, textvariable=self.file_shift, width=10).grid(row=0, column=1, padx=5, pady=2, sticky=tk.W)
        
        self.file_operation = tk.StringVar(value="encrypt")
        ttk.Radiobutton(options_frame, text="Encrypt", variable=self.file_operation, value="encrypt").grid(row=0, column=2, padx=20, pady=2)
        ttk.Radiobutton(options_frame, text="Decrypt", variable=self.file_operation, value="decrypt").grid(row=0, column=3, padx=5, pady=2)
        
        # 处理按钮
        ttk.Button(options_frame, text="Process File", command=self.process_file).grid(row=1, column=0, columnspan=4, pady=10)
        
        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(file_frame, variable=self.progress_var, mode='indeterminate')
        self.progress_bar.pack(fill=tk.X, padx=10, pady=5)
    
    def setup_events(self):
        """设置事件绑定。"""
        # 实时加密/解密
        self.encrypt_input.bind('<KeyRelease>', self.on_encrypt_change)
        self.decrypt_input.bind('<KeyRelease>', self.on_decrypt_change)
        
        # 位移变化事件
        self.encrypt_shift.trace('w', self.on_encrypt_change)
        self.decrypt_shift.trace('w', self.on_decrypt_change)
    
    def encrypt_text(self):
        """对输入框中的文本进行加密。"""
        text = self.encrypt_input.get(1.0, tk.END).strip()
        if not text:
            return
        
        try:
            shift = self.encrypt_shift.get()
            encrypted = self.cipher.encrypt(text, shift)
            
            self.encrypt_output.config(state=tk.NORMAL)
            self.encrypt_output.delete(1.0, tk.END)
            self.encrypt_output.insert(1.0, encrypted)
            self.encrypt_output.config(state=tk.DISABLED)
            
            self.status_var.set(f"Text encrypted with shift {shift}")
        except Exception as e:
            messagebox.showerror("Error", f"Encryption failed: {str(e)}")
    
    def decrypt_text(self):
        """对输入框中的文本进行解密。"""
        text = self.decrypt_input.get(1.0, tk.END).strip()
        if not text:
            return
        
        try:
            shift = self.decrypt_shift.get()
            decrypted = self.cipher.decrypt(text, shift)
            
            self.decrypt_output.config(state=tk.NORMAL)
            self.decrypt_output.delete(1.0, tk.END)
            self.decrypt_output.insert(1.0, decrypted)
            self.decrypt_output.config(state=tk.DISABLED)
            
            self.status_var.set(f"Text decrypted with shift {shift}")
        except Exception as e:
            messagebox.showerror("Error", f"Decryption failed: {str(e)}")
    
    def auto_decrypt(self):
        """使用密码分析自动解密。"""
        text = self.decrypt_input.get(1.0, tk.END).strip()
        if not text:
            messagebox.showwarning("Warning", "Please enter text to decrypt")
            return
        
        try:
            candidates = self.cipher.auto_decrypt(text, num_candidates=1)
            if candidates:
                shift, decrypted, score = candidates[0]
                
                self.decrypt_output.config(state=tk.NORMAL)
                self.decrypt_output.delete(1.0, tk.END)
                self.decrypt_output.insert(1.0, decrypted)
                self.decrypt_output.config(state=tk.DISABLED)
                
                self.decrypt_shift.set(shift)
                self.status_var.set(f"Auto-decrypted with shift {shift} (χ² score: {score:.3f})")
            else:
                messagebox.showinfo("Info", "Unable to determine correct decryption")
        except Exception as e:
            messagebox.showerror("Error", f"Auto-decryption failed: {str(e)}")
    
    def analyze_all_shifts(self):
        """使用所有可能的位移分析文本。"""
        text = self.analysis_input.get(1.0, tk.END).strip()
        if not text:
            messagebox.showwarning("Warning", "Please enter text to analyze")
            return
        
        try:
            # 清除之前的结果
            for item in self.analysis_tree.get_children():
                self.analysis_tree.delete(item)
            
            # 执行卡方分析
            results = self.cipher.chi_squared_analysis(text)
            
            # 存储结果以供详细查看
            self.analysis_results = {}
            
            for shift, score in results:
                decrypted = self.cipher.decrypt(text, shift)
                preview = decrypted[:50] + ("..." if len(decrypted) > 50 else "")
                
                # 插入树形视图
                self.analysis_tree.insert('', tk.END, values=(shift, f"{score:.3f}", preview))
                
                # 存储完整结果
                self.analysis_results[shift] = decrypted
            
            self.status_var.set(f"Analysis complete - {len(results)} candidates found")
        except Exception as e:
            messagebox.showerror("Error", f"Analysis failed: {str(e)}")
    
    def frequency_analysis(self):
        """对输入文本执行频率分析。"""
        text = self.analysis_input.get(1.0, tk.END).strip()
        if not text:
            messagebox.showwarning("Warning", "Please enter text to analyze")
            return
        
        try:
            frequencies = self.cipher.frequency_analysis(text)
            
            # 创建频率显示内容
            freq_text = "Letter Frequency Analysis:\n\n"
            sorted_freq = sorted(frequencies.items(), key=lambda x: x[1], reverse=True)
            
            for letter, freq in sorted_freq:
                if freq > 0:
                    freq_text += f"{letter}: {freq:.3f} ({freq*100:.1f}%)\n"
            
            # 在详细区域显示
            self.analysis_detail.config(state=tk.NORMAL)
            self.analysis_detail.delete(1.0, tk.END)
            self.analysis_detail.insert(1.0, freq_text)
            self.analysis_detail.config(state=tk.DISABLED)
            
            self.status_var.set("Frequency analysis complete")
        except Exception as e:
            messagebox.showerror("Error", f"Frequency analysis failed: {str(e)}")
    
    def on_analysis_select(self, event):
        """处理分析结果中的选择事件。"""
        selection = self.analysis_tree.selection()
        if selection:
            item = self.analysis_tree.item(selection[0])
            shift = int(item['values'][0])
            
            if shift in self.analysis_results:
                result_text = self.analysis_results[shift]
                
                self.analysis_detail.config(state=tk.NORMAL)
                self.analysis_detail.delete(1.0, tk.END)
                self.analysis_detail.insert(1.0, f"Shift {shift} result:\n\n{result_text}")
                self.analysis_detail.config(state=tk.DISABLED)
    
    def on_encrypt_change(self, *args):
        """处理加密选项卡中的变化。"""
        # 可选:实现实时加密
        pass
    
    def on_decrypt_change(self, *args):
        """处理解密选项卡中的变化。"""
        # 可选:实现实时解密
        pass
    
    def clear_encrypt(self):
        """清空加密字段。"""
        self.encrypt_input.delete(1.0, tk.END)
        self.encrypt_output.config(state=tk.NORMAL)
        self.encrypt_output.delete(1.0, tk.END)
        self.encrypt_output.config(state=tk.DISABLED)
    
    def clear_decrypt(self):
        """清空解密字段。"""
        self.decrypt_input.delete(1.0, tk.END)
        self.decrypt_output.config(state=tk.NORMAL)
        self.decrypt_output.delete(1.0, tk.END)
        self.decrypt_output.config(state=tk.DISABLED)
    
    def copy_encrypt_result(self):
        """将加密结果复制到剪贴板。"""
        result = self.encrypt_output.get(1.0, tk.END).strip()
        if result:
            self.root.clipboard_clear()
            self.root.clipboard_append(result)
            self.status_var.set("Result copied to clipboard")
    
    def browse_input_file(self):
        """浏览选择输入文件。"""
        filename = filedialog.askopenfilename(
            title="Select Input File",
            filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
        )
        if filename:
            self.input_file_var.set(filename)
    
    def browse_output_file(self):
        """浏览选择输出文件。"""
        filename = filedialog.asksaveasfilename(
            title="Select Output File",
            defaultextension=".txt",
            filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
        )
        if filename:
            self.output_file_var.set(filename)
    
    def process_file(self):
        """使用凯撒密码处理文件。"""
        input_file = self.input_file_var.get()
        output_file = self.output_file_var.get()
        
        if not input_file or not output_file:
            messagebox.showwarning("Warning", "Please select both input and output files")
            return
        
        try:
            shift = self.file_shift.get()
            operation = self.file_operation.get()
            
            # 启动进度指示
            self.progress_bar.start()
            
            # 在独立线程中处理文件,防止 GUI 冻结
            def process_thread():
                try:
                    encrypt = (operation == "encrypt")
                    self.cipher.process_file(input_file, output_file, shift, encrypt)
                    
                    # 在主线程中更新 GUI
                    self.root.after(0, lambda: self.file_process_complete(operation, shift))
                except Exception as e:
                    self.root.after(0, lambda: self.file_process_error(str(e)))
            
            threading.Thread(target=process_thread, daemon=True).start()
            
        except Exception as e:
            self.progress_bar.stop()
            messagebox.showerror("Error", f"File processing failed: {str(e)}")
    
    def file_process_complete(self, operation, shift):
        """处理文件处理完成事件。"""
        self.progress_bar.stop()
        self.status_var.set(f"File {operation}ed successfully with shift {shift}")
        messagebox.showinfo("Success", f"File {operation}ed successfully!")
    
    def file_process_error(self, error_message):
        """处理文件处理错误事件。"""
        self.progress_bar.stop()
        self.status_var.set("File processing failed")
        messagebox.showerror("Error", f"File processing failed: {error_message}")
    
    def export_analysis(self):
        """导出分析结果。"""
        if not hasattr(self, 'analysis_results') or not self.analysis_results:
            messagebox.showwarning("Warning", "No analysis results to export")
            return
        
        filename = filedialog.asksaveasfilename(
            title="Export Analysis Results",
            defaultextension=".json",
            filetypes=[("JSON files", "*.json"), ("All files", "*.*")]
        )
        
        if filename:
            try:
                self.cipher.export_results(self.analysis_results, filename)
                messagebox.showinfo("Success", f"Results exported to {filename}")
            except Exception as e:
                messagebox.showerror("Error", f"Export failed: {str(e)}")
    
    def run(self):
        """启动 GUI 应用程序。"""
        self.root.mainloop()


# 运行应用程序
if __name__ == "__main__":
    app = CaesarCipherGUI()
    app.run()

密码分析与破解工具

自动解码器实现

以下是用于破解凯撒密码的综合密码分析工具包:

import re
import math
from collections import Counter
from typing import List, Dict, Tuple, Optional
import json

class CaesarCryptanalyst:
    """
    用于破解凯撒密码的高级密码分析工具包。
    
    特性:
    - 多种分析方法
    - 语言检测
    - 统计评分
    - 基于词典的验证
    - 自动报告生成
    """
    
    # 英文字母频率(标准参考值)
    ENGLISH_FREQ = {
        'A': 8.167, 'B': 1.492, 'C': 2.782, 'D': 4.253, 'E': 12.702,
        'F': 2.228, 'G': 2.015, 'H': 6.094, 'I': 6.966, 'J': 0.153,
        'K': 0.772, 'L': 4.025, 'M': 2.406, 'N': 6.749, 'O': 7.507,
        'P': 1.929, 'Q': 0.095, 'R': 5.987, 'S': 6.327, 'T': 9.056,
        'U': 2.758, 'V': 0.978, 'W': 2.360, 'X': 0.150, 'Y': 1.974,
        'Z': 0.074
    }
    
    # 用于验证的常见英文单词
    COMMON_WORDS = {
        'THE', 'AND', 'FOR', 'ARE', 'BUT', 'NOT', 'YOU', 'ALL', 'CAN', 'HER',
        'WAS', 'ONE', 'OUR', 'HAD', 'BY', 'HIS', 'IS', 'IT', 'AN', 'AS',
        'THAT', 'HAVE', 'FROM', 'OR', 'OF', 'TO', 'IN', 'BEEN', 'HAS',
        'WERE', 'SAID', 'EACH', 'WHICH', 'THEIR', 'TIME', 'WILL', 'ABOUT',
        'IF', 'UP', 'OUT', 'MANY', 'THEN', 'THEM', 'THESE', 'SO', 'SOME',
        'HE', 'SHE', 'WE', 'BE', 'MY', 'AT', 'WITH', 'ON', 'DO', 'NO'
    }
    
    # 用于增强分析的二元字母组频率
    ENGLISH_BIGRAMS = {
        'TH': 3.882543, 'HE': 3.681391, 'IN': 2.283899, 'ER': 2.178042,
        'AN': 2.971208, 'ED': 1.53346, 'ND': 1.632781, 'TO': 1.693717,
        'EN': 1.383239, 'TI': 1.636312, 'ES': 1.159737, 'OR': 1.053385,
        'TE': 1.200944, 'OF': 1.056429, 'BE': 1.058438, 'HA': 1.018601,
        'AR': 0.975560, 'OU': 0.920865, 'AS': 0.860210, 'AT': 0.751699
    }
    
    def __init__(self, custom_dictionary: Optional[List[str]] = None):
        """
        使用可选自定义词典初始化密码分析器。
        
        参数:
            custom_dictionary:用于验证的附加单词
        """
        self.dictionary = self.COMMON_WORDS.copy()
        if custom_dictionary:
            self.dictionary.update(word.upper() for word in custom_dictionary)
    
    def analyze_frequency(self, text: str) -> Dict[str, float]:
        """
        以百分比计算字母频率。
        
        参数:
            text:待分析的文本
        
        返回值:
            将字母映射到频率百分比的字典
        """
        # 清洗文本(仅保留字母字符,转为大写)
        clean_text = ''.join(c.upper() for c in text if c.isalpha())
        
        if not clean_text:
            return {}
        
        total_letters = len(clean_text)
        letter_counts = Counter(clean_text)
        
        # 转换为百分比
        frequencies = {}
        for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
            count = letter_counts.get(letter, 0)
            frequencies[letter] = (count / total_letters) * 100
        
        return frequencies
    
    def chi_squared_score(self, observed_freq: Dict[str, float]) -> float:
        """
        计算观测频率与期望频率之间的卡方统计量。
        
        参数:
            observed_freq:观测到的字母频率(以百分比表示)
        
        返回值:
            卡方分数(越低越接近英文)
        """
        chi_squared = 0.0
        
        for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
            observed = observed_freq.get(letter, 0.0)
            expected = self.ENGLISH_FREQ[letter]
            
            if expected > 0:
                chi_squared += ((observed - expected) ** 2) / expected
        
        return chi_squared
    
    def index_of_coincidence(self, text: str) -> float:
        """
        计算文本的重合指数。
        
        参数:
            text:待分析的文本
        
        返回值:
            重合指数值
        """
        # 清洗文本
        clean_text = ''.join(c.upper() for c in text if c.isalpha())
        n = len(clean_text)
        
        if n < 2:
            return 0.0
        
        # 统计字母频率
        letter_counts = Counter(clean_text)
        
        # 使用公式计算重合指数:Σ(ni(ni-1)) / (N(N-1))
        ic_sum = sum(count * (count - 1) for count in letter_counts.values())
        ic = ic_sum / (n * (n - 1))
        
        return ic
    
    def bigram_analysis(self, text: str) -> Dict[str, float]:
        """
        分析二元字母组(两个字母的组合)频率。
        
        参数:
            text:待分析的文本
        
        返回值:
            二元字母组频率字典
        """
        clean_text = ''.join(c.upper() for c in text if c.isalpha())
        
        if len(clean_text) < 2:
            return {}
        
        bigrams = [clean_text[i:i+2] for i in range(len(clean_text) - 1)]
        total_bigrams = len(bigrams)
        
        if total_bigrams == 0:
            return {}
        
        bigram_counts = Counter(bigrams)
        
        # 转换为百分比
        bigram_freq = {}
        for bigram, count in bigram_counts.items():
            bigram_freq[bigram] = (count / total_bigrams) * 100
        
        return bigram_freq
    
    def dictionary_score(self, text: str) -> float:
        """
        根据找到的有效英文单词数量对文本评分。
        
        参数:
            text:待评分的文本
        
        返回值:
            在词典中找到的单词百分比
        """
        # 提取单词(连续字母序列)
        words = re.findall(r'[A-Za-z]+', text.upper())
        
        if not words:
            return 0.0
        
        valid_words = sum(1 for word in words if word in self.dictionary)
        return (valid_words / len(words)) * 100
    
    def composite_score(self, text: str) -> float:
        """
        计算结合多种分析方法的综合评分。
        
        参数:
            text:待评分的文本
        
        返回值:
            综合评分(越高越好)
        """
        if not text.strip():
            return 0.0
        
        # 计算各项单独评分
        freq_analysis = self.analyze_frequency(text)
        chi_squared = self.chi_squared_score(freq_analysis)
        ic_score = self.index_of_coincidence(text)
        dict_score = self.dictionary_score(text)
        
        # 归一化并组合评分
        # 卡方越低越好,因此取其逆值
        normalized_chi = max(0, 100 - chi_squared)
        
        # 英文的重合指数约为 0.067,根据接近程度评分
        ic_target = 0.067
        ic_normalized = max(0, 100 - abs(ic_score - ic_target) * 1000)
        
        # 加权组合
        composite = (
            normalized_chi * 0.4 +  # 频率分析权重 40%
            ic_normalized * 0.3 +   # 重合指数权重 30%
            dict_score * 0.3        # 词典单词权重 30%
        )
        
        return composite
    
    def caesar_breaker(self, ciphertext: str, num_results: int = 5) -> List[Dict]:
        """
        使用多种分析方法全面破解凯撒密码。
        
        参数:
            ciphertext:待分析的密文
            num_results:返回的最佳结果数量
        
        返回值:
            按质量排序的分析结果列表
        """
        results = []
        
        for shift in range(26):
            # 使用当前位移解密
            decrypted = self._apply_shift(ciphertext, -shift)
            
            # 计算各种评分
            freq_analysis = self.analyze_frequency(decrypted)
            chi_squared = self.chi_squared_score(freq_analysis)
            ic_score = self.index_of_coincidence(decrypted)
            dict_score = self.dictionary_score(decrypted)
            composite = self.composite_score(decrypted)
            
            # 创建结果条目
            result = {
                'shift': shift,
                'decrypted_text': decrypted,
                'chi_squared': chi_squared,
                'index_of_coincidence': ic_score,
                'dictionary_score': dict_score,
                'composite_score': composite,
                'frequency_analysis': freq_analysis
            }
            
            results.append(result)
        
        # 按综合评分降序排序
        results.sort(key=lambda x: x['composite_score'], reverse=True)
        
        return results[:num_results]
    
    def _apply_shift(self, text: str, shift: int) -> str:
        """
        对文本应用凯撒密码位移。
        
        参数:
            text:待位移的文本
            shift:位移量
        
        返回值:
            位移后的文本
        """
        result = []
        
        for char in text:
            if char.isalpha():
                base = ord('A') if char.isupper() else ord('a')
                shifted = (ord(char) - base + shift) % 26
                result.append(chr(shifted + base))
            else:
                result.append(char)
        
        return ''.join(result)
    
    def detailed_analysis_report(self, ciphertext: str, output_file: Optional[str] = None) -> str:
        """
        生成详细的密码分析报告。
        
        参数:
            ciphertext:待分析的密文
            output_file:可选的报告保存文件路径
        
        返回值:
            格式化的分析报告
        """
        print("Performing comprehensive Caesar cipher analysis...")
        
        # 获取分析结果
        results = self.caesar_breaker(ciphertext, num_results=10)
        
        # 构建报告
        report = []
        report.append("=" * 80)
        report.append("CAESAR CIPHER CRYPTANALYSIS REPORT")
        report.append("=" * 80)
        report.append(f"\nOriginal Ciphertext ({len(ciphertext)} characters):")
        report.append("-" * 50)
        report.append(ciphertext[:200] + ("..." if len(ciphertext) > 200 else ""))
        
        # 总体统计
        report.append(f"\nCiphertext Statistics:")
        report.append("-" * 30)
        
        original_ic = self.index_of_coincidence(ciphertext)
        report.append(f"Index of Coincidence: {original_ic:.6f}")
        
        letter_count = sum(1 for c in ciphertext if c.isalpha())
        report.append(f"Alphabetic characters: {letter_count}")
        
        # 最佳候选
        report.append(f"\nTop Decryption Candidates:")
        report.append("-" * 40)
        
        for i, result in enumerate(results, 1):
            report.append(f"\n{i}. Shift {result['shift']:2d} (Score: {result['composite_score']:.2f})")
            report.append(f"   χ² = {result['chi_squared']:.3f}, IC = {result['index_of_coincidence']:.6f}, Dict = {result['dictionary_score']:.1f}%")
            
            preview = result['decrypted_text'][:100]
            if len(result['decrypted_text']) > 100:
                preview += "..."
            report.append(f"   Preview: {preview}")
        
        # 最佳候选的详细分析
        if results:
            best = results[0]
            report.append(f"\nDetailed Analysis - Best Candidate (Shift {best['shift']}):")
            report.append("-" * 50)
            
            # 完整解密文本
            report.append(f"\nComplete Decrypted Text:")
            report.append(best['decrypted_text'])
            
            # 频率分析
            report.append(f"\nLetter Frequency Analysis:")
            sorted_freq = sorted(best['frequency_analysis'].items(), 
                               key=lambda x: x[1], reverse=True)
            
            for letter, freq in sorted_freq:
                expected = self.ENGLISH_FREQ[letter]
                diff = freq - expected
                report.append(f"  {letter}: {freq:5.2f}% (expected {expected:5.2f}%, diff {diff:+5.2f}%)")
        
        report_text = "\n".join(report)
        
        # 如有需要则保存到文件
        if output_file:
            with open(output_file, 'w', encoding='utf-8') as f:
                f.write(report_text)
            print(f"Report saved to: {output_file}")
        
        return report_text
    
    def interactive_analysis(self):
        """
        交互式命令行密码分析工具。
        """
        print("=== Interactive Caesar Cipher Cryptanalyst ===")
        print("Enter 'help' for commands, 'quit' to exit")
        
        while True:
            try:
                command = input("\nCryptanalyst> ").strip().lower()
                
                if command == 'quit':
                    print("Goodbye!")
                    break
                elif command == 'help':
                    self._show_help()
                elif command.startswith('analyze '):
                    ciphertext = command[8:]
                    if ciphertext:
                        results = self.caesar_breaker(ciphertext, num_results=3)
                        self._display_results(results)
                    else:
                        print("Usage: analyze <ciphertext>")
                elif command.startswith('report '):
                    ciphertext = command[7:]
                    if ciphertext:
                        report = self.detailed_analysis_report(ciphertext)
                        print(report)
                    else:
                        print("Usage: report <ciphertext>")
                else:
                    print(f"Unknown command: {command}")
                    print("Type 'help' for available commands")
                    
            except KeyboardInterrupt:
                print("\nGoodbye!")
                break
            except Exception as e:
                print(f"Error: {e}")
    
    def _show_help(self):
        """显示帮助信息。"""
        help_text = """
Available Commands:
  analyze <text>  - Quick analysis of ciphertext
  report <text>   - Detailed analysis report
  help           - Show this help message
  quit           - Exit the program

Example:
  analyze KHOOR ZRUOG
  report WKH TXLFN EURZQ IRA
        """
        print(help_text)
    
    def _display_results(self, results: List[Dict]):
        """以格式化表格显示分析结果。"""
        print(f"\n{'Rank':<4} {'Shift':<5} {'Score':<6} {'χ²':<8} {'Dict%':<6} {'Preview':<30}")
        print("-" * 65)
        
        for i, result in enumerate(results, 1):
            preview = result['decrypted_text'][:30].replace('\n', ' ')
            print(f"{i:<4} {result['shift']:<5} {result['composite_score']:<6.1f} "
                  f"{result['chi_squared']:<8.3f} {result['dictionary_score']:<6.1f} {preview}")


# 演示与测试
def main():
    """演示密码分析功能。"""
    
    # 初始化密码分析器
    analyst = CaesarCryptanalyst()
    
    # 测试用例
    test_cases = [
        ("KHOOR ZRUOG", "Simple greeting"),
        ("WKH TXLFN EURZQ IRA MXPSV RYHU WKH ODCB GRJ", "Classic pangram"),
        ("FDHVDU FLSKHU LV RQH RI WKH HDULHVW NQRZQ DQG VLPSOHVW FLSKHUV", "Description text")
    ]
    
    print("=== Caesar Cipher Cryptanalysis Demo ===")
    
    for ciphertext, description in test_cases:
        print(f"\n{description}: {ciphertext}")
        print("-" * 60)
        
        results = analyst.caesar_breaker(ciphertext, num_results=3)
        
        for i, result in enumerate(results, 1):
            print(f"{i}. Shift {result['shift']:2d} (Score: {result['composite_score']:.1f}): "
                  f"{result['decrypted_text']}")
    
    # 交互模式选项
    print(f"\n=== Interactive Mode Available ===")
    print("To start interactive analysis, call: analyst.interactive_analysis()")


if __name__ == "__main__":
    main()

结论

本完整 Python 凯撒密码教程提供了从基础函数到具备 GUI 界面和高级密码分析能力的专业级应用程序的完整实现。从简单加密函数到复杂工具的进阶过程,充分展示了 Python 在密码学教育和实用安全应用方面的多样性。

核心学习成果:

  1. 基础实现:掌握带有适当错误处理和边界情况管理的基础凯撒密码算法
  2. 高级特性:实现具备配置管理、文件处理和性能优化的专业级类
  3. GUI 开发:使用 Tkinter 创建用于交互加密和分析的用户友好应用程序
  4. 密码分析技能:开发利用统计分析和模式识别自动破解凯撒密码的工具
  5. 最佳实践:应用 Python 编码规范、文档编写、测试和专业软件开发实践

实际应用场景:

  • 教育工具:用于密码学教育的互动学习应用程序
  • 安全评估:用于分析遗留系统中经典密码实现的工具
  • 编程教育:演示多种 Python 概念和库的综合示例
  • 研究应用:用于密码算法研究和开发的可扩展框架

完整的源代码示例提供了可立即使用的实现,适合学习、教学和实际应用开发。每个实现均包含详细的文档、错误处理和可扩展特性,既支持教育用途,也适用于专业开发。

持续学习的下一步:

  • 探索更复杂的经典密码,如维吉尼亚密码和四方密码
  • 研究现代密码算法及其实现
  • 学习高级密码分析技术和统计分析方法
  • 使用 Flask 或 Django 框架开发基于 Web 的应用程序
  • 为开源密码库和教育资源做出贡献

请记住:尽管凯撒密码在现代应用中无法提供任何安全保障,但它为理解密码学原理、算法实现和安全分析方法论提供了极好的基础,而这些知识同样适用于当代密码系统和安全实践。

完整源代码仓库

本教程所有源代码示例均可在结构完整的 GitHub 仓库中获取,仓库还包含额外资源、扩展示例和全面的文档。仓库内容包括:

  • 基础实现,附详细注释和学习练习
  • 高级特性,包含性能基准测试和优化技术
  • GUI 应用程序,附完整源代码和安装说明
  • 密码分析工具,具备广泛的统计分析能力
  • 项目模板,适用于教育作业和实际应用
  • 测试套件,包含全面的测试用例和验证示例

访问完整集合:Python 凯撒密码教程仓库,定期更新,接受社区贡献,为全球学习者和教育者持续提供支持。

关于本文

本文是我们综合 凯撒密码 教程系列的一部分。继续了解古典密码学,并探索我们的交互式密码工具。

更多 凯撒密码 教程

试用 凯撒密码 工具

通过我们的交互式凯撒密码工具,将所学知识付诸实践。

试用 凯撒密码 工具