栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

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

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

目录

古典密码简介

移位变换:

多表代换:

加密算法思路

仿射变换加密

多表代换加密

例题:仿射变换

例题:多表代换


古典密码简介

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

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

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

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

移位变换:

加密:

解密:

其中为密钥,且满足,, 为的乘法逆元。

多表代换:

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

加密:

解密: 

  为密钥,为的可逆矩阵(即 0" src="https://latex.codecogs.com/gif.latex?%5Cleft%20%7C%20A%20%5Cright%20%7C%3E%200" />),且满足,为密文分组。

1.加密算法基础准备

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

# 本文件名:__uitl.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
        inv_a, _ = MathUtil.extendGcd(a, m)
        inv_a %= m
        return inv_a


    def modInvMatrix(A, m=26):
        """求矩阵A关于1模m的乘法逆元"""
        detA = np.linalg.det(A)
        invA = np.linalg.inv(A)
        Adjoint = detA * invA
        
        # 此处注意!求整数的乘法逆元,必须将detA搞整数
        # 因为计算精度的原因,算出的detA是很接近整数的小数
        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):
        """仿射变换1模26算法"""
        return (A * code + B) % 26


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


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

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


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

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

        return M



class InitDeal():
    
    def inputKey() -> list:
        """用户从键盘输入密钥 
        #  TODO验证输入密钥的有效性
        """

        key = []
        keyA = [[*map(eval, input("n请输入n阶密钥方阵A:n").split())]]
        N = len(*keyA)
        for i in range(N-1):
            keyA.append([*map(eval, input().split())])
        key.append(keyA)

        keyB = [[*map(eval, input("n请输入n维密钥向量B:n").split())]]
        key.append(keyB)

        return key


    def keyPreprocess(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)
        cipher_invA = MathUtil.modInvMatrix(A)
        keylist = [A, B, cipher_invA]

        return keylist
        

    def dealText(textstr, group_len):
        """将文本进行分组处理
        textstr: 字符串文本
        n: 分组长度
        """
        # 文本字符串去空格, 长度用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

2.仿射变换加密类的实现
# 导入上面基础准备写好的类
from __util import *


class AffineCipher():


    def __init__(self):
        self.inputkey  = "输入密钥,实例化类时需重写此属性"
        self.plaintext = "输入明文,实例化类时需重写此属性"
        self.ciphertext= "输入密文,实例化类时需重写此属性"


    def build(self):
        self.A, self.B = self.inputkey
        self.invA = MathUtil.modInvElem(self.A)


    def enCrypt(self):
        codelist = []
        cipherlist = []

        for i in self.plaintext:
            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):
        codelist = []
        plainlist = []

        for i in self.ciphertext:
            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()

    print("n请输入一对整数密钥(0~25且第一个数字与26互素): ")
    crypto.inputkey = [*map(eval, input().split())]
    crypto.build()

    crypto.plaintext = input("n请输入明文: ")
    print(crypto.enCrypt())

    crypto.ciphertext = input('n请输入密文: ')
    print(crypto.deCrypt())

3.多表代换加密类的实现
# 导入上面基础准备写好的类
from __util import *


class PolyalphabetCipher():

    def __init__(self):
        self.inputkey  = "输入密钥,实例化类时需重写此属性"
        self.plaintext = "输入明文,实例化类时需重写此属性"
        self.ciphertext= "输入密文,实例化类时需重写此属性"


    def build(self):
        key = InitDeal.keyPreprocess(self.inputkey)
        self.A, self.B, self.invA = key


    def enCrypt(self):
        ciphertext = ""
        codegroup = InitDeal.dealText(self.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):
        plaintext = ""
        codegroup = InitDeal.dealText(self.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()
    
    crypto.inputkey = InitDeal.inputKey()
    crypto.build()

    crypto.plaintext = input("n请输入明文: ")
    print(crypto.enCrypt())

    crypto.ciphertext = input('n请输入密文: ')
    print(crypto.deCrypt())

例题:仿射变换加密
from classcipher.affine import *


# 实例化加密对象, 并传入参数进行构建
crypto = AffineCipher()
crypto.inputkey   = [11, 23]
crypto.plaintext  = "THE NATIonAL SECURITY AGENCY"
crypto.ciphertext = "YWP KXYHVKXO NPTJCHYB XLPKTB"
crypto.build() 

text1 = crypto.enCrypt()
text2 = crypto.deCrypt()

print("仿射变换密钥: 11 23")
print("加密为: " + text1)

例题:多表代换加密
from classcipher.polyalphabet import *

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

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

print("加密为: " + crypto.enCrypt())

print("解密为: " + crypto.deCrypt())


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/354921.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号