第二章——古典密码学及算法实现

news2025/1/11 23:44:49

凯撒加密

凯撒加密算法实现:

# 凯撒密码加密函数
def caesar_encrypt():
    string = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
              'v', 'w', 'x', 'y', 'z']
    # 密文列表
    cipher_text_list = []
    cipher = int(input("请输入你的密钥:"))
    plain_text = input("请输入你的明文:")

    length = len(plain_text)

    print("加密后的密文是:")
    for i in range(0,length):
        cipher_text_list.append(string[string.index(plain_text[i])+cipher])
        print(cipher_text_list[i],end="")

# 凯撒密码解密函数
def caesar_decrypt():
    string = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
              'v', 'w', 'x', 'y', 'z']
    # 明文列表
    plain_text_list = []
    cipher = int(input("请输入你的密钥:"))
    ciphertext = input("请输入你的密文:")
    length = len(ciphertext)

    print("解密后的明文是:")
    for i in range(0,length):
        plain_text_list.append(string[string.index(ciphertext[i])-cipher])
        print(plain_text_list[i],end="")

Playfair密码(流密码)

基于一个5×5字母矩阵。
该矩阵使用一个关键词(密钥)来构造。
构造方法:从左至右,从上至下依次填入关键词的字母(去除重复的字母),然后再以字母表顺序依次填入其他的字母。字母I和J被算作一个字母。

原理

P1、P2同行:对应的C1和C2分别是紧靠P1、P2右端的字母。其中第一列被看作是最后一列的右方。(解密时反向)
P1、P2同列:对应的C1和C2分别是紧靠P1、P2下方的字母。其中第一行看作是最后一行的下方。(解密时反向)
P1、P2不同行、不同列:C1和C2是由P1和P2确定的矩形的其它两角的字母,并且C1和P1、C2和P2同行。(解密时处理方法相同)
P1=P2:则插入一个字母于重复字母之间,并用前述方法处理。
若明文字母数为奇数时:则在明文的末端添加某个事先约定的字母作为填充。

Playfair密码—例子

密钥是:PLAYFAIR IS A DIGRAM CIPHER。
如果明文是:P=playfair cipher
明文两个一组: pl    ay    fa    ir    ci       ph    er
对应密文为:   LA    YF    PY   RS   MR    AM    CD

Playfair密码的解密

Playfair密码,加密时把字母i和j看作是同一个字符,解密时通过解密时得到明文的意义来区别字母i和j。

Playfair密码的特点:

1.有676(26*26)种双字母组合,因此识别各种双字母组合要困难得多。

2.各个字母组的频率要比单字母呈现出大得多的范围,使得频率分析困难得多。

3.Playfair密码仍然使许多明文语言的结构保存完好,使得密码分析者能够利用。 

Playfair加密算法实现:

# Playfair密码
 
#(创建密钥矩阵的算法小部分参考了其他人的做法,具体加解密核心代码则为原创)
# 字母表
letter_list = 'ABCDEFGHIKLMNOPQRSTUVWXYZ'
 
# 移除字符串中重复的字母
def remove_duplicates(key):
    key = key.upper()   # 转成大写字母组成的字符串
    _key = ''
    for ch in key:
        if ch == 'J':
            ch = 'I'
        if ch in _key:
            continue
        else:
            _key += ch
    return _key
 
# 根据密钥建立密码表
def create_matrix(key):
    key = remove_duplicates(key)  # 移除密钥中的重复字母
    key = key.replace(' ', '')  # 去除密钥中的空格
 
    for ch in letter_list:  # 根据密钥获取新组合的字母表
        if ch not in key:
            key += ch
    # 密码表
    keys = [[i for j in range(5)] for i in range(5)]
    for i in range(len(key)):  # 将新的字母表里的字母逐个填入密码表中,组成5*5的矩阵
        keys[i // 5][i % 5] = key[i]  # j用来定位字母表的行
    return keys
 
# 获取字符在密码表中的位置
def get_matrix_index(ch, keys):
    for i in range(5):
        for j in range(5):
            if ch == keys[i][j]:
                return i, j   # i为行,j为列
 
def get_ctext(ch1, ch2, keys):
    index1 = get_matrix_index(ch1, keys)
    index2 = get_matrix_index(ch2, keys)
    r1, c1, r2, c2 = index1[0], index1[1], index2[0], index2[1]
    if r1 == r2:
        ch1 = keys[r1][(c1+1) % 5]
        ch2 = keys[r2][(c2+1) % 5]
    elif c1 == c2:
        ch1 = keys[(r1+1) % 5][c1]
        ch2 = keys[(r2+1) % 5][c2]
    else:
        ch1 = keys[r1][c2]
        ch2 = keys[r2][c1]
    text = ''
    text += ch1
    text += ch2
    return text
 
def get_ptext(ch1, ch2, keys):
    index1 = get_matrix_index(ch1, keys)
    index2 = get_matrix_index(ch2, keys)
    r1, c1, r2, c2 = index1[0], index1[1], index2[0], index2[1]
    if r1 == r2:
        ch1 = keys[r1][(c1-1) % 5]
        ch2 = keys[r2][(c2-1) % 5]
    elif c1 == c2:
        ch1 = keys[(r1-1) % 5][c1]
        ch2 = keys[(r2-1) % 5][c2]
    else:
        ch1 = keys[r1][c2]
        ch2 = keys[r2][c1]
    text = ''
    text += ch1
    text += ch2
    return text
 
def playfair_encode(plaintext, key):
    plaintext = plaintext.replace(" ", "")
    plaintext = plaintext.upper()
    plaintext = plaintext.replace("J", "I")
    plaintext = list(plaintext)
    plaintext.append('#')
    plaintext.append('#')
 
    keys = create_matrix(key)
    ciphertext = ''
    i = 0
    while plaintext[i] != '#':
        if plaintext[i] == plaintext[i+1]:
            plaintext.insert(i+1, 'X')
        if plaintext[i+1] == '#':
            plaintext[i+1] = 'X'
        ciphertext += get_ctext(plaintext[i], plaintext[i+1], keys)
        i += 2
    return ciphertext
 
def playfair_decode(ciphertext, key):
    keys = create_matrix(key)
    i = 0
    plaintext = ''
    while i < len(ciphertext):
        plaintext += get_ptext(ciphertext[i], ciphertext[i+1], keys)
        i += 2
    _plaintext = ''
    _plaintext += plaintext[0]
    for i in range(1, len(plaintext)-1):
        if plaintext[i] != 'X':
            _plaintext += plaintext[i]
        elif plaintext[i] == 'X':
            if plaintext[i-1] != plaintext[i+1]:
                _plaintext += plaintext[i]
    _plaintext += plaintext[-1]
    _plaintext = _plaintext.lower()
    return _plaintext
 
 
# plaintext = 'balloon'
# key = 'monarchy'
plaintext = input('明文:')
key = input('密钥:')
ciphertext = playfair_encode(plaintext, key)
print('加密后的密文:' + ciphertext)
plaintext = playfair_decode(ciphertext, key)
print('解密后的明文:' + plaintext)

Vigenere密码(流密码)

原理

16世纪法国数学家Blaise de Vigenere于1568年发明的,是著名的多表代替密码的例子

使用一个词组作为密钥密钥中的每一个字母用来确定一个代替表,每一个密钥字母被用来加密一个明文字母。等所有的密钥字母使用完后,密钥再循环使用.

若明文序列为

:

密钥序列为:

则密文序列为:

 这也是序列密码的一般加密形式

Vigenere密码——例子

明文:She is listening.
密钥:Pascal。

明文:She is listening.
密钥:Pascal。

Vigenere密码可以看做若干个加法密码的联合 

Vigenere密码加解密算法实现:

ef VigenereEncrypto(message, key):
    msLen = len(message)
    keyLen = len(key)
    message = message.upper()
    key = key.upper()
    raw = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"# 明文空间
    # 定义加密后的字符串
    ciphertext = ""
    # 开始加密
    for i in range(0, msLen):
        # 轮询key的字符
        j = i % keyLen
        # 判断字符是否为英文字符,不是则直接向后面追加且继续
        if message[i] not in raw:
            ciphertext += message[i]
            continue
        encodechr = chr((ord(message[i]) - ord("A") + ord(key[j]) - ord("A")) % 26 + ord("A"))
        # 追加字符
        ciphertext += encodechr
    # 返回加密后的字符串
    return ciphertext
if __name__ == "__main__":
    message = "Hello, World!"
    key = "key"
    text = VigenereEncrypto(message, key)
    print(text)
def VigenereDecrypto(ciphertext, key):
    msLen = len(ciphertext)
    keyLen = len(key)
    key = key.upper()
    raw = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"# 密文空间
    plaintext = ""
    for i in range(0, msLen):# 开始解密
        # 轮询key的字符
        j = i % keyLen
        # 判断字符是否为英文字符,不是则直接向后面追加且继续
        if ciphertext[i] not in raw:
            plaintext += ciphertext[i]
            continue
        decodechr = chr((ord(ciphertext[i]) - ord("A") - ord(key[j]) - ord("A")) % 26 + ord("A"))
        # 追加字符
        plaintext += decodechr
    # 返回加密后的字符串
    return plaintext
if __name__=="__main__":
    ciphertext = "RIJVS, AMBPB!"
    key = "key"
    text = VigenereDecrypto(ciphertext, key)
    print(text)
import VigenereDecrypto
import VigenereEncrypto
def main():
    info = '''==========********=========='''# 开始加密
    print(info, "\n------维吉尼亚加密算法------")
    print(info)
    # 读取测试文本文档
    message = open("test.txt","r+").read()
    print("读取测试文本文档:test.txt")
    print("开始加密!")
    # 输入key
    key = input("请输入密钥:")
    # 进入加密算法
    CipherText = VigenereEncrypto.VigenereEncrypto(message, key)
    # 写入密文文本文档
    C = open("CipherText.txt", "w+")
    C.write(CipherText)
    C.close()
    print("加密后得到的密文是: \n" + CipherText)
    # 开始解密
    print(info, "\n------维吉尼亚解密算法------")
    print(info)
    # 读取加密文本文档
    print("读取密文文本文档:CipherText.txt")
    Ciphertext = open("CipherText.txt", "r+").read()
    # 进入解密算法
    print("开始解密!")
    Plaintext = VigenereDecrypto.VigenereDecrypto(Ciphertext, key)
    P = open("PlainText.txt", "w+")
    # 写入解密文本文档
    P.write(Plaintext)
    P.close()
    print("解密后得到的明文是 : \n" + Plaintext)
if __name__=="__main__":
    main()

Hill密码:(分组密码)

原理:

1.输入矩阵K
2.求det(K)取mod 26,  即K1=mod(det(K),26)=25
3.求K1的逆元,即25-1mod26=25
4.求伴随矩阵,K2=inv(K)*det(K)
5.求逆矩阵, K3=K2.*25   (这里K1-1mod26=25)
6.取模 mod(K3,26)

疑问:既然能直接能函数求逆矩阵,那为什么还要用(行列式逆元*伴随矩阵)求逆矩阵呢?

  由公式1可以知道求逆矩阵时需要用到行列式逆元,但是公式用的是行列式的倒数(线性代数),所以需要多求一下。

Hill加密算法实现:

# -*- coding: utf-8 -*-
"""
Created on Tue Oct 10 16:09:37 2023

@author: lenovo
"""

import numpy as np

# 求在模m下任意一个数的乘法逆元
def Multi_Inverse(x,m):
    # 输入:求一个数x在模m下的乘法逆元
    # y的取值范围为[0,m)
    y = 0
    while(y < m):
        res = (x * y) % m
        if res == 1:
            print("在模%d下,加密密钥行列式值为%d,它的乘法逆元为%d" % (m,x,y))
            break
        else:
            y = y + 1
            if y == m:
                print(x,"在模",m,"下,不存在乘法逆元!")
                return 0
    return y

# 求伴随矩阵
def Adjoint_Mat(K,K_det,m):
    # 输入:矩阵K,矩阵的行列式值K_det,模m
    # 对K矩阵求逆,得到K的逆矩阵K1
    K1 = np.linalg.inv(K)
    # 求K矩阵的伴随矩阵
    K2 = K1 * K_det % m
    # 由于伴随矩阵得到的可能是浮点数矩阵,故需要对其进行四舍五入取整
    # 并将每个元素成员强制转换为int类型
    K2 = np.around(K2)
    K2 = K2.astype(np.int)
    return K2

# 求解密密钥k
def Decrypt_Key(K,m):
    # 求K矩阵的行列式值det(K),模m
    K_det = np.linalg.det(K)
    K2 = Adjoint_Mat(K, K_det, m)
    # 求det(K)在模26下的乘法逆元
    y = Multi_Inverse(K_det, m)
    # 求Hill加密的解密秘钥
    K3 = y * K2 % m
    return K3

# 将矩阵(二维数组)ascii码转字符
def ascii2_char(array1):
    plaintext = ''
    row = array1.shape[0]
    col = array1.shape[1]
    for i in range(row):
        for j in range(col):
            plaintext = plaintext + chr(array1[i][j])
    return plaintext

# 将明文转换为ascii码值矩阵,行数与加密密钥保持一致
def char2ascii2(plaintext,row,m):
    # 输入:明文plaintext,加密矩阵的行数row,模m
    l1 = [0,0,0]
    l2 = []
    for i in range(len(plaintext)):
        j = i % row  #多少行(一列多少个元素)说明每个分组有多少个元素
        if (i > 0 and i % row == 0):
            l2.append(l1)
            l1 = [0, 0, 0]
        l1[j] = ord(plaintext[i])
    print('中间变量l1:',l1)
    l2.append(l1)
    print('中间变量l2:',l2)
    m1 = np.array(l2)
# =============================================================================
#   np.array()的作用就是把列表转化为数组,也可以说是用来产生数组
# =============================================================================
    print('中间变量m1:',m1)
    m1 = np.reshape(m1,(m1.shape[1],m1.shape[0]))
# =============================================================================
#   reshape函数:将二维数组m1转换成另一个二维数组,形状为(m1.shape[1],m1.shape[0])即(3,10)
# =============================================================================
    print('中间变量m1_',m1)
    m1 = m1 % m
    return m1

if __name__ == "__main__":
    # K矩阵,即加密密钥
    K = np.array([[17,17,5],[21,18,21],[2,2,19]], dtype=int)
    # 解密密钥k,模m
    m = 256
    k = Decrypt_Key(K,m)
    print("Hill密码的解密秘钥为:\n",k)

    # 明文
    plaintext = 'Programming is a happy thing'
    print("原始明文内容:\n",plaintext)

    
    row = K.shape[0] # shape()函数求加密密钥矩阵K的行数row
    # 将明文转换为ascii码值矩阵,行数与加密密钥保持一致
    # m1为明文ascii码值矩阵
    m1 = char2ascii2(plaintext,row,m)
    print('明文矩阵:\n',m1)
    # 加密过程,m2为加密后的矩阵
    m2 = np.dot(K,m1) % 256
# =============================================================================
#     矩阵积计算不遵循交换律,np.dot(a,b)和np.dot(b,a)得到的结果是不同的
# =============================================================================
    Ciphertext = ascii2_char(m2)
    print("密文内容:\n",Ciphertext)

    # 解密过程,m3为加密后的矩阵
    m3 = np.dot(k,m2) % 256
    decrypt_text = ascii2_char(m3)
    print("解密结果:\n", decrypt_text)

明文矩阵过程类似下面,但上面代码中明文字符排列顺序为:从左到右,从上到下

                                           下面例子中明文字符排列顺序为:从上到下,从左到右

 


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1080802.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于ChatGPT+词向量/词嵌入实现相似商品推荐系统

最近一个项目有个业务场景是相似商品推荐&#xff0c;给一个商品描述(比如 WIENER A/B 7IN 5/LB FZN )&#xff0c;系统给出商品库中最相似的TOP 5种商品&#xff0c;这种单纯的推荐系统用词向量就可以实现&#xff0c;不过&#xff0c;这个项目特点是商品库巨大&#xff0c;有…

SQL中for xml path 的用法

1. 用法 是一种将查询结果转换为 XML 格式的方法。它可以将查询结果中的每一行转换为一个 XML 元素&#xff0c;并且可以指定元素的名称和属性。 2. 应用示例 有一张学生选修课程的表&#xff0c;如下图所示 希望整合成下图所示效果 --建表 if object_id(StudentInfo,u) is…

webrtc用clang编译支持h264,支持msvc调用库

webrtc遇到困扰&#xff1a; 如果msvc编译&#xff0c;ffmpeg编译失败&#xff0c;需要替换ffmpeg库。如果用clang编译&#xff0c;vs或qt调用dll又存在崩溃。 经过反复尝试找到解决方法&#xff1a; 一、编译 1、编译参数 //我得环境配置 set DEPOT_TOOLS_UPDATE0 set DEP…

解决linux终端启动后不能自动加载环境变量配置(个人配置文件)详解

文章目录 设备环境问题阐述解决方法 设备环境 WSL2 Ubuntu-20.04 本教程适配所有linux&#xff0c;不管你是虚拟机还是WSL或者其他的平台。 问题阐述 由于专业课的要求&#xff0c;需要在Linux中新建一个用户&#xff0c;然后转到这个用户来完成专业课的各种实践要求。有可…

HttpServletRequest对象与RequestDispatcher对象

一、HttpServletRequest对象 1.介绍 在Servlet API中&#xff0c;定义了一个HttpServletRequest接口&#xff0c;它继承自ServletRequest接口&#xff0c;专门用来封装HTTP请求消息。由于HTTP请求消息分为请求行、请求消息头和请求消息体三部分&#xff0c;因此&#xff0c;在…

Android免杀小结

目录 msfvenom 自动生成 自带免杀 工具免杀 Thefatrat backdoor-apk old-fatrat msfVenom嵌入式方法 venom 工具小记 加壳 源码免杀 加壳 源码混淆 数据通信 启动和运行方式修改 对抗反编译 反编译工具崩溃 ZIP文件格式对抗 ZIP通用位伪加密 AndroidManife…

暴涨100万粉仅用一个月,B站内容趋势前线洞察

- 导语 在这个9月&#xff0c;B站涌现多位黑马UP主&#xff0c;有的UP主自入驻B站以来&#xff0c;一个月的时间就涨粉百万晋升为头部UP主&#xff0c;有的UP主因内容受到B站百万年轻人的追捧&#xff0c;展现账号爆发力。 接下来&#xff0c;飞瓜数据&#xff08;B站版&…

智慧工地:助力数字建造、智慧建造、安全建造、绿色建造

智慧工地管理系统融合计算机技术、物联网、视频处理、大数据、云计算等&#xff0c;为工程项目管理提供先进的技术手段&#xff0c;构建施工现场智能监控系统&#xff0c;有效弥补传统监理中的缺陷&#xff0c;对人、机、料、法、环境的管理由原来的被动监督变成全方位的主动管…

将 mysql 数据迁移到 clickhouse (最新版)

一、前驱知识 已经在mysql中插入了海量的数据了&#xff0c;这个时候mysql 承载不了这么大的数据&#xff0c;并且数据只需要查询&#xff0c;修改和删除非常少&#xff0c;并且不需要支持事务&#xff0c;这个时候需要换一个底层存储&#xff0c;这里选用的是 clickhouse 来进…

智能视频分析系统AI智能分析网关V3触发告警图片不显示该如何解决?

AI智能分析网关V3包含有20多种算法&#xff0c;包括人脸、人体、车辆、车牌、行为分析、烟火、入侵、聚集、安全帽、反光衣等等&#xff0c;可应用在安全生产、通用园区、智慧食安、智慧城管、智慧煤矿等场景中。将网关硬件结合我们的视频监控系统EasyCVR一起使用&#xff0c;可…

vue3插件——vue-web-screen-shot——实现页面截图功能

最近在看前同事发我的vue3框架时&#xff0c;发现他们有个功能是要实现页面截图功能。 vue3插件——vue-web-screen-shot——实现页面截图功能 效果图如下&#xff1a;1.操作步骤1.1在项目中添加vvue-web-screen-shot组件1.2在项目入口文件导入组件——main.ts1.3在需要使用的页…

对话天润云CEO吴强,未来所有企业都要用AI重构一遍 | AIGC入局者栏目

近日&#xff0c;铅笔道联合知乎&#xff0c;与天润云&#xff08;又称“天润融通”&#xff09;创始人兼CEO吴强先生深度交流&#xff0c;大模型如何提升客户联络效率以帮助企业完成变革。 吴强认为&#xff1a;“丰富、专业的语料决定了大模型的能力&#xff0c;企业生产过程…

小程序, 多选项

小程序, 多选项 <view class"my-filter-btnwrap"><block wx:for"{{archiveList}}" wx:key"index"><view class"my-filter-btnitem text-ellipsis {{item.checked ? active : }}" data-index"{{index}}" wx…

Vuex的同步存值与取值及异步请求

前言 1.概念 Vuex是一个用于管理Vue.js应用程序中状态的状态管理模式和库。Vue.js是一个流行的JavaScript框架&#xff0c;用于构建用户界面&#xff0c;而Vuex则专门用于管理应用程序的状态&#xff0c;以确保状态在整个应用程序中保持一致和可维护。 2.Vuex的特点&#xf…

uniapp-vue3微信小程序实现全局分享

uniapp-vue3微信小程序实现全局分享 文章目录 uniapp-vue3微信小程序实现全局分享微信小程序官方文档的分享说明onShareAppMessage(Object object)onShareTimeline() uniapp 官方文档的分享说明onShareAppMessage(OBJECT) 实现全局分享代码结构如下share.js文件内容main.js注意…

XML是不是主要用做配置文件?

2023年10月11日&#xff0c;周三下午 这几天发现tomcat的配置文件主要是用XML文件来写的&#xff0c; 于是就有了这个问题。 是的,XML非常适合用来做配置文件。 XML作为配置文件的主要优点: 可读性强。XML使用标签结构组织数据,内容清晰易懂。跨语言和跨平台。XML作为纯文本…

一站式新零售管理系统提供商,数字化收银系统与连锁门店运营优化

在数字化时代&#xff0c;连锁超市行业正面临巨大的转型压力。消费者对购物体验的需求不断提升&#xff0c;线上线下购物的融合趋势明显&#xff0c;同时物流、供应链和库存管理也变得越来越复杂。面对日益激烈的竞争和消费者需求的变化&#xff0c;连锁超市亟需通过数字化手段…

Linux:I/O 5种模型

图片来源&#xff1a;https://pdai.tech/md/java/io/java-io-model.html

手机APP也可以学习Sui啦,通过EasyA开启你的学习之旅

Sui基金会与EasyA合作&#xff0c;开发了一门面向初学者的Sui课程。这一适用于Android和iOS移动端的学习体验&#xff0c;是进入更广泛的Sui社区和生态系统的入口。在这门课程中&#xff0c;学习者将以有趣和互动的方式获得对Sui的基本了解&#xff0c;最终能够在测试网络上部署…

Qt如何实现动态背景-视频背景

前言 需求&#xff1a;加载视频作为视频背景&#xff0c;在上层可以进行图片的动画化&#xff0c;或是进行其他操作。 几种方法&#xff1a; 1、直接将视频弄成一个QDialog&#xff0c; 然后再上层在弄一个QDialog,背景透明即可。但遇到一个问题&#xff0c;QDialog没办法局…