【古典密码】 凯撒密码 移位变换 仿射变换 多表代换 Python

本文附有丰富的代码,故文章冗长,请对照目录查阅,各大板块均有上下文提示

目录

古典密码简介

仿射变换:

多表代换:

1.加密算法基础准备

2.仿射变换加密类的实现

3.多表代换加密类的实现

例题:仿射变换加密

例题:多表代换加密


古典密码简介

        古典密码主要有置换和代换的方法。置换:字母重新排列,字母本身不变,但其位置改变了(凯撒密码、移位变换)。代换:将明文中的字符替代成其他字符(仿射变换、多表代换)。

        在线性空间的变化中,古典加密就是移动并拉伸物体,让物体变得与原来不一样;解密解释将物体移动回去拉伸回去,恢复物体的原样。

        凯撒密码 移位变换 仿射变换可以理解为单表代换,这三种古典密码实质上可以归根于多表代换的特殊形式——单表代换,即一个字母一组。

        在此文中,考虑到凯撒密码、移位密码的简单性,仅介绍仿射变换、多表代换加密。加密算法的详细内容请自行查阅,以下仅列出变换公式

仿射变换:

加密:c \equiv am+b(mod 26)

解密:m \equiv a^{-1}(b-c)(mod 26)

其中a,b为密钥,且满足0\leq a,b\leq 25gcd(a, 26) = 1, a^{-1}a的乘法逆元。

多表代换:

将n个字母长的明文M分成M1,M2···Mi对每个分组:

加密:C_{_{i}}\equiv AM_{_{i}} + B(mod 26)

解密: M_{_{i}}\equiv A^{-1}(C_{_{i}}-B)(mod 26)

 (A,B) 为密钥,An\times n的可逆矩阵(即\left | A \right |> 0),且满足gcd(\left | A \right |, N) = 1C_{_{i}}为密文分组。

1.加密算法基础准备

        在这两种古典加密中最重要的是求逆元,即 a 的乘法逆元 a^{-1}A 的加密逆元 A^{-1}。两个逆元均用扩展欧几里得法。因此将扩展欧几里得、求逆元等算法封装在 类MathUitl 仿射变换、多表代换等加解密算法封装在 类TransAlgor 中,以供加解密使用。另一个 类IintiDeal 用与处理密钥输入等,现在不用关心。重要的地方均有注解,没注解就是你也一定会看懂!

# 本代码文件名:__util.py

import numpy as np

class MathUtil():
    """ 数学运算工具类 """

    def extendGcd(a, b):
        """扩展欧几里德算法"""
        if b == 0:
            return 1, 0
        else:
            x, y = MathUtil.extendGcd(b, a % b)
            x, y = y, x - (a//b) * y
            return x, y

    def modInvElem(a:int, m=26):
        """求整数a关于1模m的乘法逆元"""
        if (np.gcd(a, m) !=1): return -1
        inva, _ = MathUtil.extendGcd(a, m)
        inva %= m
        return inva

    def modInvMatrix(A, m=26):
        """求矩阵A关于1模m的乘法逆元"""
        detA = np.linalg.det(A)
        invA = np.linalg.inv(A)
        Adjoint = detA * invA
 
        inv_detA = MathUtil.modInvElem(round(detA), m)
        cipher_invA = ((inv_detA % m) * Adjoint) % m
        cipher_invA = np.round(cipher_invA).astype(int)

        return cipher_invA


class TransAlgor():
    """ 变换算法工具类 """

    def affine(code, A, B, m=26):
        """仿射变换1模26算法"""
        return (A * code + B) % m

    def invAffine(code, invA, B, m=26):
        """仿射变换1模26逆算法"""
        return invA * (code - B) % m

    def polyalphabet(code:list, A, B, m=26) -> list:
        """多表代换1模26算法"""
        group_len = len(B)
        code = np.mat(code).reshape(group_len,1)

        C = ((np.dot(A, code) + B) % m).reshape(-1)
        C = C.tolist()[0]

        return C

    def invpolyalpha(code:list, invA, B, m=26) -> list:
        """多表代换1模26逆算法"""
        group_len = len(B)
        code = np.mat(code).reshape(group_len, 1)

        M = (np.dot(invA, (code - B)) % m).reshape(-1)
        M = M.tolist()[0]

        return M


class InitDeal():
    """ 键盘输入处理类 """

    def inputKey() -> list:
        """ 用户从键盘输入密钥 """
        keyA = [[*map(eval, input("\n请输入n阶密钥方阵A:\n").split())]]
        for _ in range(len(*keyA) - 1):
            keyA.append([*map(eval, input().split())])
        keyB = [*map(eval, input("\n请输入n维密钥向量B:\n").split())]
        key = [keyA, keyB]

        return key

    def keyProcess(inputkey):
        """ 输入密钥进行处理->逆元cipher_invA等密钥 """
        A, B = inputkey
        group_len = len(B)
        A = np.mat(A).reshape(group_len,group_len)
        B = np.mat(B).reshape(group_len,1)
        try: cipher_invA = MathUtil.modInvMatrix(A)
        except: return False
        keylist = [A, B, cipher_invA]

        return keylist
        
    def dealText(textstr, group_len):
        """ 将文本进行分组处理
            @textstr: 字符串文本
            @group_len: 分组长度
        """
        # 文本字符串去空格, 长度用z补全, 如"abcabc" 
        textstr = textstr.replace(" ", "")
        blank = len(textstr) % group_len
        if blank != 0:
            textstr = textstr + (group_len-blank) * "z"

        # 统一转换成小写0~25编码列表, 如[0,1,2,0,1,2]
        textlist = list(textstr.lower())
        codelist = [ord(i)-97 for i in textlist]

        # 将编码列表进行分组, 即编码子向量, 如[[0,1,2],[0,1,2]]
        codegroup = []
        for i in range(0, len(codelist), group_len):
            codegroup.append(codelist[i:i+group_len])

        return codegroup


class HerkCode():
    """ 自定义编码类 """

    def enCode(text):
        """ 53编码 by Herk
            @text: 待编码的字符串, 如"abc"
            @return: 对应的编码流, 即"010203"
        """
        pool = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
        code = [(2-len(str(pool.index(i))))*'0'+str(pool.index(i)) for i in text]

        return ''.join(code)

    def deCode(code):
        """ 53解码 by Herk
            @code: 待解码的数字流, 如"010203"
            @return: 对应的字符串, 即为"abc"
        """
        pool = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
        text = [pool[int(code[i:i+2])] for i in range(0, len(code), 2)]

        return ''.join(text)

2.仿射变换加密类的实现

# 本代码文件名: affine.py
# 导入上面基础准备写好的类

from __util import *


class AffineCipher():
    """ 仿射变换加密 """
    
    def __init__(self, inputkey=None):
        """ 密钥初始化构建
            @inputkey: 例如[1, 3]
            若密钥为空则从键盘输入
        """
        self.inputkey  = inputkey
        self.buildKey()

    def buildKey(self):
        """ 生成相关密钥数据 """
        if self.inputkey == None:
            tips = "输入一对密钥: "      # 例如输入: 1 3 
            self.inputkey = [*map(eval, input(tips).split())]
        self.A, self.B = self.inputkey # 处理输入密钥, 得到密钥a,b
        self.invA = MathUtil.modInvElem(self.A) # 计算密钥a的逆元

    def enCrypt(self, messag):
        """ 仿射变化加密
            @messag: 明文字符串
            @return: 密文字符串
        """
        codelist = []
        cipherlist = []

        for i in messag:
            codelist.append(ord(i))

        for i in codelist:
            if 65 <= i <= 90:
                i -= 65
                i = TransAlgor.affine(i, self.A, self.B) + 65
            elif 97 <= i <= 122:
                i -= 97
                i = TransAlgor.affine(i, self.A, self.B) + 97
            cipherlist.append(chr(i))

        ciphertext = ''.join(cipherlist)

        return ciphertext

    def deCrypt(self, cipher):
        """ 仿射变换解密
            @cipher: 密文字符串
            @return: 明文字符串
        """
        codelist = []
        plainlist = []

        for i in cipher:
            codelist.append(ord(i))

        for i in codelist:
            if 65 <= i <= 90:
                i -= 65
                i = TransAlgor.invAffine(i, self.invA, self.B) + 65
            elif 97 <= i <= 122:
                i -= 97
                i = TransAlgor.invAffine(i, self.invA, self.B) + 97
            plainlist.append(chr(i))

        plaintext = ''.join(plainlist)

        return plaintext


if __name__ == '__main__':

    crypto = AffineCipher()

    messag = input("输入明文: ")
    print("加密结果:", crypto.enCrypt(messag))

    cipher = input("输入密文: ")
    print("解密结果:", crypto.deCrypt(cipher))

3.多表代换加密类的实现

# 本代码文件名: polyalphabet.py
# 导入上面基础准备写好的类

from __util import *


class PolyalphabetCipher():
    """ 多表代换加密 """
    
    def __init__(self, inputkey=None):
        """ 实例化类时需要复写的属性 """
        self.inputkey  = inputkey
        self.buildKey()

    def buildKey(self):
        """ 实例化对象后 必须构建密钥 """
        if self.inputkey == None:
            self.inputkey = InitDeal.inputKey()
        key = InitDeal.keyProcess(self.inputkey)
        self.A, self.B, self.invA = key

    def enCrypt(self, plaintext):
        """ 加密算法 返回密文 """
        ciphertext = ""
        codegroup = InitDeal.dealText(plaintext, len(self.B))

        for group in codegroup:
            group = TransAlgor.polyalphabet(group, self.A, self.B)
            group = [chr(i+97) for i in group] # 密文编码->字母串列表
            group = ''.join(group)             # 字母串列表->密文串
            ciphertext = ciphertext + group + " "

        return ciphertext

    def deCrypt(self, ciphertext):
        """ 加密算法 返回明文 """
        plaintext = ""
        codegroup = InitDeal.dealText(ciphertext, len(self.B))

        for group in codegroup:
            group = TransAlgor.invpolyalpha(group, self.invA, self.B)
            group = [chr(i+97) for i in group] # 明文编码->字母串列表
            group = ''.join(group)             # 字母串列表->明文串
            plaintext = plaintext + group + " "

        return plaintext


if __name__ == '__main__':

    crypto = PolyalphabetCipher()

    plaintext = input("输入明文: ")
    print("加密结果:", crypto.enCrypt(plaintext))

    ciphertext = input("输入密文: ")
    print("解密结果:", crypto.deCrypt(ciphertext))

例题:仿射变换加密

from affine import *

key = [7, 21]
messag = "security"
cipher = "vlxijh"

crypto = AffineCipher(key)
print("仿射变换密钥对为: 7 21")
print("security 加密为:", crypto.enCrypt(messag))
print("vlxijh   解密为:", crypto.deCrypt(cipher))

例题:多表代换加密

from polyalphabet import *

keyA = [[11, 2, 19],
        [5, 23, 25],
        [20, 7, 17]]
keyB =  [ 0, 0,  0]

# 实例化加密对象, 并传入参数进行构建
key = [keyA, keyB]
plaintext  = "your pin no is four one two six"
ciphertext = "wgi fgj tmr lhh xth wbx zps brb"

crypto = PolyalphabetCipher(key)
print("密钥为:", key)
print("加密为:", crypto.enCrypt(plaintext))
print("解密为:", crypto.deCrypt(ciphertext))

### 实现单代换加密或凯撒密码 凯撒密码是一种基于字母移位的替换型密码,在这种情况下,明文字母被固定数量位置后的字母所替代。例如,当移位数为3时,“A”会变成“D”,“B”变为“E”。对于更复杂的单代换,则可以采用任意映射关系来代替固定的移位。 下面展示了一个简单的Python函数用于执行标准版的凯撒加密[^1]: ```python def caesar_cipher_encrypt(text, shift): encrypted_text = "" for char in text.upper(): if 'A' <= char <= 'Z': shifted_char = chr(((ord(char) - ord('A') + shift) % 26) + ord('A')) encrypted_text += shifted_char else: encrypted_text += char return encrypted_text ``` 此代码片段遍历输入字符串`text`中的每一个字符,并将其转换成大写字母处理;如果遇到非英文字母则保持不变。接着计算新字符的位置并通过ASCII码值构建新的密文字符。最后返回整个加密过的信息串作为结果。 为了实现更加灵活的单代换加密方案,可以通过预定义一个字典来进行特定字符间的映射: ```python import string def substitution_cipher_encrypt(plaintext, cipher_table): ciphertext = [] for letter in plaintext.lower(): if letter.isalpha(): index = string.ascii_lowercase.index(letter) substituted_letter = cipher_table[index] ciphertext.append(substituted_letter) else: ciphertext.append(letter) return ''.join(ciphertext).upper() ``` 这里使用了`string`模块里的属性获取所有的小写英文字符列,并依据给定的`cipher_table`(即替代),将原文本里对应的每个字母换成指定的新字母。注意这里的例子假设只针对小写的英文字母做变换,其他符号保留原样输出。 #### 凯撒密码的特点和局限性 尽管凯撒密码易于理解和实施,但它并不是一种安全可靠的加密方式。由于仅存在有限种可能的变化模式(总共只有25种不同的偏移量),因此很容易受到频率分析攻击而被破译出来。现代计算机可以在极短时间内尝试所有的可能性组合从而恢复原始消息的内容[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值