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


    凯撒加密

    凯撒加密算法实现

    1. # 凯撒密码加密函数
    2. def caesar_encrypt():
    3. string = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
    4. 'v', 'w', 'x', 'y', 'z']
    5. # 密文列表
    6. cipher_text_list = []
    7. cipher = int(input("请输入你的密钥:"))
    8. plain_text = input("请输入你的明文:")
    9. length = len(plain_text)
    10. print("加密后的密文是:")
    11. for i in range(0,length):
    12. cipher_text_list.append(string[string.index(plain_text[i])+cipher])
    13. print(cipher_text_list[i],end="")
    14. # 凯撒密码解密函数
    15. def caesar_decrypt():
    16. string = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
    17. 'v', 'w', 'x', 'y', 'z']
    18. # 明文列表
    19. plain_text_list = []
    20. cipher = int(input("请输入你的密钥:"))
    21. ciphertext = input("请输入你的密文:")
    22. length = len(ciphertext)
    23. print("解密后的明文是:")
    24. for i in range(0,length):
    25. plain_text_list.append(string[string.index(ciphertext[i])-cipher])
    26. 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加密算法实现:

    1. # Playfair密码
    2. #(创建密钥矩阵的算法小部分参考了其他人的做法,具体加解密核心代码则为原创)
    3. # 字母表
    4. letter_list = 'ABCDEFGHIKLMNOPQRSTUVWXYZ'
    5. # 移除字符串中重复的字母
    6. def remove_duplicates(key):
    7. key = key.upper() # 转成大写字母组成的字符串
    8. _key = ''
    9. for ch in key:
    10. if ch == 'J':
    11. ch = 'I'
    12. if ch in _key:
    13. continue
    14. else:
    15. _key += ch
    16. return _key
    17. # 根据密钥建立密码表
    18. def create_matrix(key):
    19. key = remove_duplicates(key) # 移除密钥中的重复字母
    20. key = key.replace(' ', '') # 去除密钥中的空格
    21. for ch in letter_list: # 根据密钥获取新组合的字母表
    22. if ch not in key:
    23. key += ch
    24. # 密码表
    25. keys = [[i for j in range(5)] for i in range(5)]
    26. for i in range(len(key)): # 将新的字母表里的字母逐个填入密码表中,组成5*5的矩阵
    27. keys[i // 5][i % 5] = key[i] # j用来定位字母表的行
    28. return keys
    29. # 获取字符在密码表中的位置
    30. def get_matrix_index(ch, keys):
    31. for i in range(5):
    32. for j in range(5):
    33. if ch == keys[i][j]:
    34. return i, j # i为行,j为列
    35. def get_ctext(ch1, ch2, keys):
    36. index1 = get_matrix_index(ch1, keys)
    37. index2 = get_matrix_index(ch2, keys)
    38. r1, c1, r2, c2 = index1[0], index1[1], index2[0], index2[1]
    39. if r1 == r2:
    40. ch1 = keys[r1][(c1+1) % 5]
    41. ch2 = keys[r2][(c2+1) % 5]
    42. elif c1 == c2:
    43. ch1 = keys[(r1+1) % 5][c1]
    44. ch2 = keys[(r2+1) % 5][c2]
    45. else:
    46. ch1 = keys[r1][c2]
    47. ch2 = keys[r2][c1]
    48. text = ''
    49. text += ch1
    50. text += ch2
    51. return text
    52. def get_ptext(ch1, ch2, keys):
    53. index1 = get_matrix_index(ch1, keys)
    54. index2 = get_matrix_index(ch2, keys)
    55. r1, c1, r2, c2 = index1[0], index1[1], index2[0], index2[1]
    56. if r1 == r2:
    57. ch1 = keys[r1][(c1-1) % 5]
    58. ch2 = keys[r2][(c2-1) % 5]
    59. elif c1 == c2:
    60. ch1 = keys[(r1-1) % 5][c1]
    61. ch2 = keys[(r2-1) % 5][c2]
    62. else:
    63. ch1 = keys[r1][c2]
    64. ch2 = keys[r2][c1]
    65. text = ''
    66. text += ch1
    67. text += ch2
    68. return text
    69. def playfair_encode(plaintext, key):
    70. plaintext = plaintext.replace(" ", "")
    71. plaintext = plaintext.upper()
    72. plaintext = plaintext.replace("J", "I")
    73. plaintext = list(plaintext)
    74. plaintext.append('#')
    75. plaintext.append('#')
    76. keys = create_matrix(key)
    77. ciphertext = ''
    78. i = 0
    79. while plaintext[i] != '#':
    80. if plaintext[i] == plaintext[i+1]:
    81. plaintext.insert(i+1, 'X')
    82. if plaintext[i+1] == '#':
    83. plaintext[i+1] = 'X'
    84. ciphertext += get_ctext(plaintext[i], plaintext[i+1], keys)
    85. i += 2
    86. return ciphertext
    87. def playfair_decode(ciphertext, key):
    88. keys = create_matrix(key)
    89. i = 0
    90. plaintext = ''
    91. while i < len(ciphertext):
    92. plaintext += get_ptext(ciphertext[i], ciphertext[i+1], keys)
    93. i += 2
    94. _plaintext = ''
    95. _plaintext += plaintext[0]
    96. for i in range(1, len(plaintext)-1):
    97. if plaintext[i] != 'X':
    98. _plaintext += plaintext[i]
    99. elif plaintext[i] == 'X':
    100. if plaintext[i-1] != plaintext[i+1]:
    101. _plaintext += plaintext[i]
    102. _plaintext += plaintext[-1]
    103. _plaintext = _plaintext.lower()
    104. return _plaintext
    105. # plaintext = 'balloon'
    106. # key = 'monarchy'
    107. plaintext = input('明文:')
    108. key = input('密钥:')
    109. ciphertext = playfair_encode(plaintext, key)
    110. print('加密后的密文:' + ciphertext)
    111. plaintext = playfair_decode(ciphertext, key)
    112. print('解密后的明文:' + plaintext)

    Vigenere密码(流密码)

    原理

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

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

    若明文序列为

    :

    密钥序列为:

    则密文序列为:

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

    Vigenere密码——例子

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

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

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

    Vigenere密码加解密算法实现:

    1. ef VigenereEncrypto(message, key):
    2. msLen = len(message)
    3. keyLen = len(key)
    4. message = message.upper()
    5. key = key.upper()
    6. raw = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"# 明文空间
    7. # 定义加密后的字符串
    8. ciphertext = ""
    9. # 开始加密
    10. for i in range(0, msLen):
    11. # 轮询key的字符
    12. j = i % keyLen
    13. # 判断字符是否为英文字符,不是则直接向后面追加且继续
    14. if message[i] not in raw:
    15. ciphertext += message[i]
    16. continue
    17. encodechr = chr((ord(message[i]) - ord("A") + ord(key[j]) - ord("A")) % 26 + ord("A"))
    18. # 追加字符
    19. ciphertext += encodechr
    20. # 返回加密后的字符串
    21. return ciphertext
    22. if __name__ == "__main__":
    23. message = "Hello, World!"
    24. key = "key"
    25. text = VigenereEncrypto(message, key)
    26. print(text)
    27. def VigenereDecrypto(ciphertext, key):
    28. msLen = len(ciphertext)
    29. keyLen = len(key)
    30. key = key.upper()
    31. raw = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"# 密文空间
    32. plaintext = ""
    33. for i in range(0, msLen):# 开始解密
    34. # 轮询key的字符
    35. j = i % keyLen
    36. # 判断字符是否为英文字符,不是则直接向后面追加且继续
    37. if ciphertext[i] not in raw:
    38. plaintext += ciphertext[i]
    39. continue
    40. decodechr = chr((ord(ciphertext[i]) - ord("A") - ord(key[j]) - ord("A")) % 26 + ord("A"))
    41. # 追加字符
    42. plaintext += decodechr
    43. # 返回加密后的字符串
    44. return plaintext
    45. if __name__=="__main__":
    46. ciphertext = "RIJVS, AMBPB!"
    47. key = "key"
    48. text = VigenereDecrypto(ciphertext, key)
    49. print(text)
    50. import VigenereDecrypto
    51. import VigenereEncrypto
    52. def main():
    53. info = '''==========********=========='''# 开始加密
    54. print(info, "\n------维吉尼亚加密算法------")
    55. print(info)
    56. # 读取测试文本文档
    57. message = open("test.txt","r+").read()
    58. print("读取测试文本文档:test.txt")
    59. print("开始加密!")
    60. # 输入key
    61. key = input("请输入密钥:")
    62. # 进入加密算法
    63. CipherText = VigenereEncrypto.VigenereEncrypto(message, key)
    64. # 写入密文文本文档
    65. C = open("CipherText.txt", "w+")
    66. C.write(CipherText)
    67. C.close()
    68. print("加密后得到的密文是: \n" + CipherText)
    69. # 开始解密
    70. print(info, "\n------维吉尼亚解密算法------")
    71. print(info)
    72. # 读取加密文本文档
    73. print("读取密文文本文档:CipherText.txt")
    74. Ciphertext = open("CipherText.txt", "r+").read()
    75. # 进入解密算法
    76. print("开始解密!")
    77. Plaintext = VigenereDecrypto.VigenereDecrypto(Ciphertext, key)
    78. P = open("PlainText.txt", "w+")
    79. # 写入解密文本文档
    80. P.write(Plaintext)
    81. P.close()
    82. print("解密后得到的明文是 : \n" + Plaintext)
    83. if __name__=="__main__":
    84. main()

    Hill密码:(分组密码)

    原理:

    一直对这个加密矩阵搞不懂,后来搜了搜,发现加密矩阵是一个n×n的矩阵,明文为n维向量,恍然大悟

    伪代码解释:

            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加密算法实现:

    1. # -*- coding: utf-8 -*-
    2. """
    3. Created on Tue Oct 10 16:09:37 2023
    4. @author: lenovo
    5. """
    6. import numpy as np
    7. # 求在模m下任意一个数的乘法逆元
    8. def Multi_Inverse(x,m):
    9. # 输入:求一个数x在模m下的乘法逆元
    10. # y的取值范围为[0,m)
    11. y = 0
    12. while(y < m):
    13. res = (x * y) % m
    14. if res == 1:
    15. print("在模%d下,加密密钥行列式值为%d,它的乘法逆元为%d" % (m,x,y))
    16. break
    17. else:
    18. y = y + 1
    19. if y == m:
    20. print(x,"在模",m,"下,不存在乘法逆元!")
    21. return 0
    22. return y
    23. # 求伴随矩阵
    24. def Adjoint_Mat(K,K_det,m):
    25. # 输入:矩阵K,矩阵的行列式值K_det,模m
    26. # 对K矩阵求逆,得到K的逆矩阵K1
    27. K1 = np.linalg.inv(K)
    28. # 求K矩阵的伴随矩阵
    29. K2 = K1 * K_det % m
    30. # 由于伴随矩阵得到的可能是浮点数矩阵,故需要对其进行四舍五入取整
    31. # 并将每个元素成员强制转换为int类型
    32. K2 = np.around(K2)
    33. K2 = K2.astype(np.int)
    34. return K2
    35. # 求解密密钥k
    36. def Decrypt_Key(K,m):
    37. # 求K矩阵的行列式值det(K),模m
    38. K_det = np.linalg.det(K)
    39. K2 = Adjoint_Mat(K, K_det, m)
    40. # 求det(K)在模26下的乘法逆元
    41. y = Multi_Inverse(K_det, m)
    42. # 求Hill加密的解密秘钥
    43. K3 = y * K2 % m
    44. return K3
    45. # 将矩阵(二维数组)ascii码转字符
    46. def ascii2_char(array1):
    47. plaintext = ''
    48. row = array1.shape[0]
    49. col = array1.shape[1]
    50. for i in range(row):
    51. for j in range(col):
    52. plaintext = plaintext + chr(array1[i][j])
    53. return plaintext
    54. # 将明文转换为ascii码值矩阵,行数与加密密钥保持一致
    55. def char2ascii2(plaintext,row,m):
    56. # 输入:明文plaintext,加密矩阵的行数row,模m
    57. l1 = [0,0,0]
    58. l2 = []
    59. for i in range(len(plaintext)):
    60. j = i % row
    61. if (i > 0 and i % row == 0):
    62. l2.append(l1)
    63. l1 = [0, 0, 0]
    64. l1[j] = ord(plaintext[i])
    65. print('中间变量l1:',l1)
    66. l2.append(l1)
    67. print('中间变量l2:',l2)
    68. m1 = np.array(l2)
    69. # =============================================================================
    70. # np.array()的作用就是把列表转化为数组,也可以说是用来产生数组
    71. # =============================================================================
    72. print('中间变量m1:',m1)
    73. m1 = np.reshape(m1,(m1.shape[1],m1.shape[0]))
    74. # =============================================================================
    75. # reshape函数:将二维数组m1转换成另一个二维数组,形状为(m1.shape[1],m1.shape[0])即(310
    76. # =============================================================================
    77. print('中间变量m1_',m1)
    78. m1 = m1 % m
    79. return m1
    80. if __name__ == "__main__":
    81. # K矩阵,即加密密钥
    82. K = np.array([[17,17,5],[21,18,21],[2,2,19]], dtype=int)
    83. # 解密密钥k,模m
    84. m = 256
    85. k = Decrypt_Key(K,m)
    86. print("Hill密码的解密秘钥为:\n",k)
    87. # 明文
    88. plaintext = 'Programming is a happy thing'
    89. print("原始明文内容:\n",plaintext)
    90. row = K.shape[0] # shape()函数求加密密钥矩阵K的行数row
    91. # 将明文转换为ascii码值矩阵,行数与加密密钥保持一致
    92. # m1为明文ascii码值矩阵
    93. m1 = char2ascii2(plaintext,row,m)
    94. print('明文矩阵:\n',m1)
    95. # 加密过程,m2为加密后的矩阵
    96. m2 = np.dot(K,m1) % 256
    97. # =============================================================================
    98. # 矩阵积计算不遵循交换律,np.dot(a,b)和np.dot(b,a)得到的结果是不同的
    99. # =============================================================================
    100. Ciphertext = ascii2_char(m2)
    101. print("密文内容:\n",Ciphertext)
    102. # 解密过程,m3为加密后的矩阵
    103. m3 = np.dot(k,m2) % 256
    104. decrypt_text = ascii2_char(m3)
    105. print("解密结果:\n", decrypt_text)


     

  • 相关阅读:
    重新认识AUTOSAR Interface
    VM装Windows虚拟机扩容
    牛顿插值多项式
    管理多个项目的主要挑战与应对方法
    linux文件IO的光标移动
    《Web安全基础》01. 基础知识
    [附源码]计算机毕业设计基于Springboot三星小区车辆登记系统
    CSDN每日一题学习训练——Python版(输入起始和结束的正整数,求其两个正整数之间的偶数和、两数相加)
    【Docker】Docker安装Nginx配置静态资源
    华纳云:Ubuntu下开启php调试模式报错如何解决
  • 原文地址:https://blog.csdn.net/m0_66039322/article/details/133703428