密码学

本文最后更新于:1 年前

密码学实验课程设计

一、古典密码

仿射密码

简介

仿射加密在本质上还是一个置换密码:如果说移位密码是一个常数级别的置换,那么,仿射加密是一个一次级别的置换

加密原理

假设X,Y,A,B是Z26整数环中的元素,A和B为密钥,X是原文,Y是密文

加密函数:Y=(AX+B)%26

解密函数:Y=(AX+B)%26,得到:X=(A的逆元)*(Y-B)%26

原理很简单,代码实现也比较简单

代码实现

各个函数作用

gcd(a,b)a,b的最大公因子
findModReverse(a,m)  计算a模m的逆元
encode(a,b,s)       仿射加密
decode(a,b,s)		仿射解密

利用扩展的欧几里得算法求逆元

def gcd(a,b):  # 求出最大公因数
    while a!=0:
        a,b = b%a,a
    return b

def findModReverse(a,m): #扩展欧几里得算法求模逆
    if gcd(a,m)!=1:
        return None
    u1,u2,u3 = 1,0,a
    v1,v2,v3 = 0,1,m
    while v3!=0:
        q = u3//v3
        v1,v2,v3,u1,u2,u3 = (u1-q*v1),(u2-q*v2),(u3-q*v3),v1,v2,v3
    return u1%m

完整代码如下

def gcd(a,b):  # 求出最大公因数
    while a!=0:
        a,b = b%a,a
    return b

def findModReverse(a,m): #扩展欧几里得算法求模逆
    if gcd(a,m)!=1:
        return None
    u1,u2,u3 = 1,0,a
    v1,v2,v3 = 0,1,m
    while v3!=0:
        q = u3//v3
        v1,v2,v3,u1,u2,u3 = (u1-q*v1),(u2-q*v2),(u3-q*v3),v1,v2,v3
    return u1%m

def encode(a,b,s):
    result = ""          # 保存加密结果
    s = s.upper()		 # 全部转换为大写,方便计算
    for i in range(0,len(s)):
        s2 = chr((a*(ord(s[i])-65)+b)%26 + 65)  #使用加密公式 Y=(AX+B)%26
        result = result +s2
    print(result.lower())

def decode(a,b,s):
    a1 = findModReverse(a,26)
    result = ""
    s = s.upper()
    for i in range(0, len(s)):
        s2 = chr((a1 * (ord(s[i]) - 65 - b)) % 26 + 65) # 使用解密公式X=(A的逆元)*(Y-B)%26
        result = result + s2
    print(result.lower())

def s_decode(a,b,s):
    letter ='abcdefghijklmnopqrstuvwxyz'
    letter = letter.upper()
    s = s.upper()
    result = ""
    for i in s:
        for j in range(0,len(letter)):
            if i == letter[(a*j+b)%26]:
                result = result+letter[j]
    print(result.lower())

def main():										# 主函数入口
    answer = input(f'请输入所需的操作:编码/E or 解码/D: ')
    try:
        if answer.upper() == 'E':
            a = int(input('请输入a:'))
            b = int(input('请输入b:'))
            s = input('请输入需要加密的字符:')
            encode(a, b, s)
        elif answer.upper() == 'D':
            a = int(input('请输入a:'))
            b = int(input('请输入b:'))
            s = input('请输入需要解密的字符:')
            decode(a, b, s)  # 利用逆元解密
            # s_decode(a,b,s)   # 暴力枚举每一个字符
        else:
            print('输入错误!')
    except KeyError:
        print('请勿输入空格!')

if __name__ == '__main__':
    main()
# a = 7, b = 22
# plain = firstthesentenceandthentheevidencesaidthequeen
# crypto = falszztysyjzyjkywjrztyjztyynaryjkyswarztyegyyj

加解密结果如图所示

image-20201223225306141

image-20201223225317161

破解仿射密码

这里使用了加解密中的 gcd findModReverse,找出26以内且与26互素的所有数的逆元,并存放在一个列表中

def findAllre():    # 找出所有小于26且与26互素的数
    re_all = []
    for i in range(1,26):
        if gcd(i,26) == 1:
            res = findModReverse(i,26)
            re_all.append(res)
    #re_all.sort()
    return re_all

完整代码如下

def gcd(a,b):  # 求出最大公因数
    while a!=0:
        a,b = b%a,a
    return b

def findModReverse(a,m): #扩展欧几里得算法求模逆
    if gcd(a,m)!=1:
        return None
    u1,u2,u3 = 1,0,a
    v1,v2,v3 = 0,1,m
    while v3!=0:
        q = u3//v3
        v1,v2,v3,u1,u2,u3 = (u1-q*v1),(u2-q*v2),(u3-q*v3),v1,v2,v3
    return u1%m

def findAllre():    # 找出所有小于26且与26互素的数
    re_all = []
    for i in range(1,26):
        if gcd(i,26) == 1:
            res = findModReverse(i,26)
            re_all.append(res)
    #re_all.sort()
    return re_all

def decode(s):
    re_all = findAllre()
    for k1 in re_all:
        for k2 in range(0, 26):
            result = ""
            for i in range(len(s)):
                s2 = chr(((int(k1) * (ord(s[i]) - 97 - k2)) % 26 + 97))
                result = result + s2
            print("k1=" + str(findModReverse(k1,26)) + ", k2=" + str(k2) + " plaintext = " + result)

def main():
   # criphertext = 'falszztysyjzyjkywjrztyjztyynaryjkyswarztyegyyj'
    criphertext = input("请输入要破解的密文: ")
    criphertext = criphertext.lower()
    print("---------"*3+"strat attck"+"---------"*3)
    decode(criphertext)

if __name__ == '__main__':
     main()

效果如下

image-20201223170037595

维吉尼亚密码

1.简介

维吉尼亚密码(又译维热纳尔密码)是使用一系列凯撒密码组成密码字母表的加密算法,属于多表密码的一种简单形式。

维吉尼亚密码曾多次被发明。该方法最早记录在吉奥万·巴蒂斯塔·贝拉索( Giovan Battista Bellaso)于1553年所著的书《吉奥万·巴蒂斯塔·贝拉索先生的密码》(意大利语:La cifra del. Sig. Giovan Battista Bellaso)中。然而,后来在19世纪时被误传为是法国外交官布莱斯·德·维吉尼亚(Blaise De Vigenère)所创造,因此现在被称为“维吉尼亚密码”。

维吉尼亚密码以其简单易用而著称,同时初学者通常难以破解,因而又被称为“不可破译的密码”。这也让很多人使用维吉尼亚密码来加密的目的就是为了将其破解。

2.加解密原理

image-20201223225441528

加解密代码

# 将密钥处理成和密文/明文一样长
def solve_key(s,key):
    nkey = key
    while len(nkey) < len(s):
        nkey = nkey+key
    nkey = nkey[:len(s)]
    return nkey

# 加密函数
def encode(s,key):
    print('加密后的结果: ',end='')
    s1 = s.upper()
    key1 = solve_key(s, key)
    key1 = key1.upper()

    result = ""
    for i in range(0,len(s)):
        s2 = chr(abs(((ord(s1[i])-65)+(ord(key1[i])-65)) % 26) + 65)
        result = result + s2
    print(result.lower())

# 解密函数
def decode(s,key):
    print('解密后的结果: ', end='')
    s1 = s.upper()
    key1 = solve_key(s, key)
    key1 = key1.upper()

    result = ""
    for i in range(0, len(s)):
        s2 = chr(((ord(s1[i]) - 65) - (ord(key1[i]) - 65)) % 26 + 65)
        result = result + s2
    print(result.lower())

def main():
    while 1:
        # 函数入口
        answer = input(f'请输入所需的操作:编码/E or 解码/D:  ')
        try:
            if answer.upper() == 'E':
                key = input('请输入密钥: ')
                key = "".join(filter(str.isalpha, key))
                s = input('请输入明文: ')
                s = "".join(filter(str.isalpha, s))  # 将字符串中的非字母字符去掉
                # print(s)
                encode(s, key)
            elif answer.upper() == 'D':
                key = input('请输入密钥: ')
                key = "".join(filter(str.isalpha, key))
                s = input('请输入密文: ')
                s = "".join(filter(str.isalpha, s))
                decode(s, key)
            else:
                print('输入错误!')
        except KeyError:
            print('请检查输入是否正确!')

if __name__ == '__main__':
    main()

二、序列密码

LFSR

代码实现

def lsrf(inti, top):
    sum = 0
    inti2 = "0"*len(inti)
    inti2 = list(inti2)
    inti1 = ''
    for i in range(len(inti)):
        if top[i] == "1":
            sum += int(inti[i])
    sum = sum % 2
    for i in range(len(inti)):
        if i == 0:
            inti2[i] = str(sum)
        else:
            inti2[i] = inti[i - 1]
    inti1 = inti1.join(inti2)
    return inti1

def main():
    inti_str = str(input("请输入初始化序列:"))
    inti_str = inti_str[::-1]
    inti_str_backup = inti_str
    top = str(input("请输入本原多项式:"))
    top = top[::-1]
    for i in range(2 ** len(inti_str) + 1):
        if inti_str_backup == inti_str and i != 0 and i == 2 ** len(inti_str) - 1:
            print("第{0}次".format(i), inti_str_backup)
            print("是本原多项式且周期是" + str(i))
            break
        elif inti_str_backup == inti_str and i != 0 and i != 2 ** len(inti_str) - 1:
            print("第{0}次".format(i), inti_str_backup)
            print("不是本原多项式且周期是" + str(i))
            break
        print("第{0}次".format(i), inti_str_backup)
        inti_str_backup = lsrf(inti_str_backup, top)

if __name__ == '__main__':
    main()

选择本原多项式和初始序列如下

100000000001000000
011100010100100101

程序运行结果

image-20201223222649800

RC4

完整代码

import hashlib
import base64

# S盒初始化置换,Key为密钥
def Rc4_init(S, Key):
    j = 0
    Key = Key.encode('UTF-8')
    Key = hashlib.md5(Key).hexdigest()  # 长度为32的字符串
    tmp = []
    for i in range(256):
        S.append(i)
        tmp.append(Key[i % len(Key)])
    for i in range(256):
        j = (j + S[i] + ord(tmp[i])) % 256
        S[i], S[j] = S[j], S[i]             # 交换S[i],S[j]

def rc4_Encode(S, plaintext):
    i = j = 0
    result = ''
    for a in plaintext:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        t = (S[i] + S[j]) % 256
        k = chr(ord(a) ^ S[t])
        result += k
    result = base64.b64encode(result.encode('UTF-8'))
    result = result.decode()
    return result


def rc4_Decode(S, criphtext):
    i = j = 0
    criphtext = base64.b64decode(criphtext)
    criphtext = str(criphtext.decode())
    result = ''
    for a in criphtext:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        t = (S[i] + S[j]) % 256
        k = chr(ord(a) ^ S[t])
        result += k
    return result

def main():
    while 1:
        order = input("请输入指令,加密/E,解密/D :")
        if order.upper() =='E':
            plaintext = input('请输入明文: ')
            key = input("请输入密钥: ")
            s = []
            Rc4_init(s, key)
            cryphtext = rc4_Encode(s, plaintext)
            print("密文为: ", cryphtext)
            print('\n')

        else:
            cryphtext = input("请输入密文: ")
            key = input("请输入密钥: ")
            s = []
            Rc4_init(s, key)
            plaintext = rc4_Decode(s, cryphtext)
            print("明文为: ", plaintext)
            print('\n')
if __name__ == '__main__':
    main()

三、DES

DEC_ECB模式

# 两字符进行异或运算
def xor(str1, str2):
    res = ""
    for i in range(0, len(str1)):
        xor_res = int(str1[i], 10)^int(str2[i], 10)
        if xor_res == 1:
            res += '1'
        else:
            res += '0'
    return res

# 处理字符串,将每个字符串都转成八位二进制数
def str_process(str):
    res = ""
    for i in str:
        tmp = bin(ord(i))[2:]
        tmp = (8 - len(tmp)) * '0' + tmp  # 不够八位则在前面补 0
        res += tmp
    return res

# PC-1盒处理
def key_change_1(str):
    change_table = [57,49,41,33,25,17,9,1,
                 58,50,42,34,26,18,10,
                 2,59,51,43,35,27,19,11,
                 3,60,52,44,36,63,55,47,
                 39,31,23,15,7,62,54,46,
                 38,30,22,14,6,61,53,45,
                 37,29,21,13,5,28,20,12,4]
    res = ""
    for i in change_table:
        res += str[i-1]
    return res

# PC-2盒处理
def key_change_2(str):
    change_table = [14,17,11,24,1,5,3,28,
                 15,6,21,10,23,19,12,4,
                 26,8,16,7,27,20,13,2,
                 41,52,31,37,47,55,30,40,
                 51,45,33,48,44,49,39,56,
                 34,53,46,42,50,36,29,32]
    res = ""
    for i in change_table:
        res += str[i-1]
    return res


# 循环左移
def left_run(str, num):
    tmp_str = str[num:len(str)]
    tmp_str = tmp_str+str[0:num]
    return tmp_str


# 生成16个子密钥
def key_gen(str):
    key_list = []
    key_change_res = key_change_1(str)
    key_c = key_change_res[0:28]
    key_d = key_change_res[28:]
    num = [0, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
    for i in range(1, 17): #共16轮
        key_c = left_run(key_c, num[i])
        key_d = left_run(key_d, num[i])
        key_yiwei = key_c + key_d
        key_res = key_change_2(key_yiwei)
        key_list.append(key_res)
    return key_list

# IP盒处理
def begin_change(str):
    change_table = [58,50,42,34,26,18,10,2,
                   60,52,44,36,28,20,12,4,
                   62,54,46,38,30,22,14,6,
                   64,56,48,40,32,24,16,8,
                   57,49,41,33,25,17,9,1,
                   59,51,43,35,27,19,11,3,
                   61,53,45,37,29,21,13,5,
                   63,55,47,39,31,23,15,7]
    res = ""
    for i in change_table:
        res += str[i-1]
    return res


# E盒处理  32位->48位
def E_box(str):
    change_table = [32,1,2,3,4,5,4,5,
                    6,7,8,9,8,9,10,11,
                    12,13,12,13,14,15,16,17,
                    16,17,18,19,20,21,20,21,
                    22,23,24,25,24,25,26,27,
                    28,29,28,29,30,31,32,1]
    res = ""
    for i in change_table:
        res += str[i-1]
    return res

# s盒处理   48位->32位
def S_box(str):
    j = 0
    s_list = [[14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13],
              [15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9],
              [10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12],
              [7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14],
              [2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3],
              [12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13],
              [4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12],
              [13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11]
              ]
    res = ""
    for i in range(0, len(str), 6):
        begin_s = str[i:i + 6]
        row = int(begin_s[0] + begin_s[5], 2)  #第一位和第六位作为行
        col = int(begin_s[1:5], 2)             #中间四位作为列
        index = s_list[j][row * 16 + col]
        num = bin(index)[2:]                   #将匹配的数字转换位二进制数
        for k in range(0, 4 - len(num)):       #不够4位则补0
            num = "0" + num
        res += num
        j = j + 1
    return res

# p盒处理   置换操作
def P_box(str):
    res = ""
    change_table = [16,7,20,21,29,12,28,17,
                    1,15,23,26,5,18,31,10,
                    2,8,24,14,32,27,3,9,
                    19,13,30,6,22,11,4,25]
    for i in change_table:
        res += str[i - 1]
    return res

# F函数
def F_function(str, key):  # R(32位)->E盒(48位)->与key的子密钥异或->S盒->P置换
    str_e_res = E_box(str)            # 将 E 异或 S  P 集合到一个函数种,便于调用
    xor_res = xor(str_e_res, key)
    str_s_res = S_box(xor_res)
    str_p_res = P_box(str_s_res)
    return str_p_res

# 逆IP盒
def IP_re(str):
    res = ""
    ip_list = [40,8,48,16,56,24,64,32,
               39,7,47,15,55,23,63,31,
               38,6,46,14,54,22,62,30,
               37,5,45,13,53,21,61,29,
               36,4,44,12,52,20,60,28,
               35,3,43,11,51,19,59,27,
               34,2,42,10,50,18,58,26,
               33,1,41,9,49,17,57,25 ]
    for i in ip_list:
        res += str[i-1]
    return res


# DES加密操作
def DESencode(text, key):
    text_bin = str_process(text)     # 将字符转换为二进制数
    text_IP = begin_change(text_bin)  # 明文初始置换
    key_bin = str_process(key)      # 将密钥转换位二进制数
    key_list = key_gen(key_bin) # key_lsst 数组中存放着十六个子密钥

    text_left = text_IP[0:32]     # R0
    text_right = text_IP[32:]     # L0

    for i in range(0, 15):      # 十五轮加密

        mes_tmp = text_right     # 临时变量用于左右两部分交换
        text_right = xor(F_function(text_right, key_list[i]) , text_left) #F 函数的作用 R(32位)->E盒(48位)->与key的子密钥异或(32位)->S盒(32位)->P置换(32位)
        text_left = mes_tmp
    fin_right = text_right       # 第十六轮加密
    fin_left = xor(F_function(text_right, key_list[15]), text_left)
    criph_text = fin_left + fin_right
    criph_text = IP_re(criph_text)     #  IP逆置换
    return criph_text

# 针对一组的解密程序
def DESdecode(text, key):  #密文直接输64位2进制
    key_bin = str_process(key)    # 将密钥转换为二进制数
    key_list = key_gen(key_bin)   # 生成的十六个子密钥
    text = begin_change(text)   # 先初始值换 与加密过程相反
    cipher_left = text[0:32]    # R16
    cipher_right = text[32:]    # L16
    i = 15
    while i > 0:                # 十五轮加密 反过来
        cipher_tmp = cipher_right   #设置一个临时变量用于后面的交换
        cipher_right = xor(cipher_left, F_function(cipher_right, key_list[i]))    # F 函数的作用 R(32位)->E盒(48位)->与key的子密钥异或(32位)->S盒(32位)->P置换(32位)
                                                                                  # F 函数处理完后与L(32位)异或
        cipher_left = cipher_tmp    # 左右交换完成
        i = i - 1
    left_text = xor(cipher_left, F_function(cipher_right, key_list[0])) # 一
    right_text = cipher_right                                           # 二 三 这三步是第十六轮加密
    plain_bin = left_text + right_text                                  #
    plain_bin = IP_re(plain_bin)                                        #
    plain_text = ""
    for i in range(0, len(plain_bin), 8):
        plain_text += chr(int(plain_bin[i:i + 8], 2))
    return plain_text


def Divide_text(order,text,key):    # 将明文或者明文分组 明文分成8个字符一组,密文则分成64bit一组
    block_text = []
    res = ""
    length = 0
    if order == "E":
        length = 8
    else:
        length = 64
    i = 0
    while text[i:i+length] != "":
        block_text.append(text[i:i+length])
        i += length

    if order == 'E':
        if len(block_text[-1]) != 8:       # 最后一组明文如果不够八个字符则添加 + 补齐八个  否则程序会报错
            block_text[-1] = block_text[-1] + '+' * (8 - len(block_text[-1]))
        for text in block_text:             # 分别对每组加密
            res += DESencode(text, key)
    else:
        for text in block_text:             # 对密文解密
            res += DESdecode(text, key)
    return res

def main():
    while 1:
        plaintext = ''
        ciphertext = ''
        key = ''
        order = input("加密请按E,解密请按D:")
        if order == 'E':
            plaintext = input("请输入明文:")
            key = input("请输入密钥:")
            ciphertext = Divide_text(order, plaintext, key)
            print("密文是:")
            print(ciphertext)
        else:
            ciphertext = input("请输入密文:")
            key = input("请输入密钥:")
            plaintext = Divide_text(order, ciphertext, key)
            print("明文是:")
            print(plaintext)

if __name__ == '__main__':
    main()

DES_CBC模式

只需要修改ECB模式中的 Divide_text 部分

def Divide_text(order,text,key):    # 将明文或者明文分组 明文分成8个字符一组,密文则分成64bit一组
    block_text = []
    IV = 'aaaaaaaa'                 # 初始化向量
    IV_bin = str_process(IV)
    res = ""
    length = 0
    if order == "E":
        length = 8
    else:
        length = 64
    i = 0
    while text[i:i+length] != "":
        block_text.append(text[i:i+length])
        i += length
    tmp = ""
    # 加密
    if order == 'E':
        if len(block_text[-1]) != 8:       # 最后一组明文如果不够八个字符则添加 + 补齐八个  否则程序会报错
            block_text[-1] = block_text[-1] + '+' * (8 - len(block_text[-1]))

        for i in range(len(block_text)):             # 分别对每组加密
            if i == 0 :
                tmp = DESencode(block_text[i],key, IV_bin)
                res += tmp
            else:
                tmp = DESencode(block_text[i],key,tmp)
                res += tmp
    # 解密
    else:
        for i in range(len(block_text)):
            if i == 0:
                tmp = block_text[i]
                res += DESdecode(block_text[i], key, IV_bin)
            else:
                res += DESdecode(block_text[i], key, tmp)
                tmp = block_text[i]
    return res

四、RSA

# -*- coding = utf - 8 -*-
#@Time : 2020/12/23 14:24
#@Author : sunzy
#@File : rsa.py

from Crypto.Util.number import *
import random

# 模重复平方法
def fast_mod(p,q,n):     # p为底数,p为指数
    res = 1
    while q:
        if q & 1:
            res = (res * p) % n
        q >>= 1             # 右移1位
        p = (p * p) % n
    return res

# 计算出d
#这个扩展欧几里得算法求模逆,用于求d
def caculateD(a, m):
    u1,u2,u3 = 1,0,a
    v1,v2,v3 = 0,1,m
    while v3!=0:
        q = u3//v3
        v1,v2,v3,u1,u2,u3 = (u1-q*v1),(u2-q*v2),(u3-q*v3),v1,v2,v3
    return u1%m


# 将字符转化为十六进制字符串
def str2Hex(m):
    return "".join("{:02x}".format(ord(x)) for x in m)

# 素性检验:采用 Miler-Rabin 检验法
# 所有的𝑟 ∈ [0, 𝑠 − 1],若𝑎^𝑑 ≠ 1(𝑚𝑜𝑑 𝑛)且𝑎^((2^𝑟)*𝑑) ≠ −1(𝑚𝑜𝑑 𝑛),则𝑛是合数。否则,𝑛有 3/4的概率为素数
def miller_rabin(n):
    s = n - 1
    t = 0
    while s % 2 == 0:  # n,s,t之间的关系为 n = 2^s * t
        s = s // 2
        t += 1
    for trials in range(10):   # 可以多增加几轮保证大概率为素数
        a = random.randrange(2, n - 1) # 随机生成a
        v = pow(a, s, n)               # 验证 a^(n-1) mod n
        if v != 1:
            i = 0
            while v != (n - 1):
                if i == t - 1:
                    return False
                else:
                    i = i + 1
                    v = (v ** 2) % n
    return True
# 生成素数 先生成1024位的奇数,再进行素性检验,通过则生成该素数
def genPrime(b=1024):
    while True:                             # 设置死循环直到生成素数才退出
        res = "1"
        for i in range(b-2):
            res += str(random.randint(0,1))
        res += "1"                              # 最后一位为1保证为奇数
        res = int(res,2)
        if miller_rabin(res):
            return res                          # 直到该数通过素数检验才推出循环

def genE(phi_n):
    while True:
        e = genPrime(b=random.randint(3,13))  #随机生成e
        if e < 2000 :                  # e不能太小
            continue
        if phi_n%e != 0:               # 保证e不能被phi整除
            return e

def RSAEncode(m, e, n):               # 加密公式 m^e mod n
    m = int(str2Hex(m), 16)           # 将字符转换为二进制
    c = fast_mod(m, e, n)
    return c

def RSADecode(c, d, n):                 # 加密公式 c^d mod n
    plaintext = fast_mod(c,d,n)
    plaintext = str(long_to_bytes(plaintext).decode()) # 将数字转换为字符
    return plaintext


def main():
    # 生成两个大素数p和q
    print("Generate p,q and e, please wait... ")
    p = genPrime()
    q = genPrime()
    print ("p = "+str(p))
    print ("q = "+str(q))
    n = p*q
    print ("n = "+str(n))
    # 用欧拉定理计算 phi_n
    phi_n = (p-1)*(q-1)
    # 生成e
    e = genE(phi_n)
    print ("e = "+str(e))
    # m = "Hello world!"
    m = str(input('请输入明文: '))
    # 加密算法
    Cryphtext = RSAEncode(m, e, n)
    print ("The Ciphertext is: "+str(Cryphtext))
    # 解密算法
    d = caculateD(e, phi_n)
    Plaintext = RSADecode(Cryphtext, d, n)
    print ("The Plaintext is: "+Plaintext)
if __name__ == '__main__':
    main()

五、MD5

# -*- coding = utf - 8 -*-
#@Time : 2020/12/18 21:50
#@Author : sunzy
#@File : MD5.py

import math
# 定义初始向量abcd,并将其转换成2进制,且补0到32位
# 标准的幻数(物理顺序)是(A=(01234567)16,B=(89ABCDEF)16,C=(FEDCBA98)16,D=(76543210)16)。如果在程序中定义应该是:
# (A=0X67452301L,B=0XEFCDAB89L,C=0X98BADCFEL,D=0X10325476L)
ABCD_list = ['67452301','efcdab89','98badcfe','10325476']
for i in range(len(ABCD_list)):
    tmp = bin(int(ABCD_list[i], 16))[2:]
    if len(tmp) < 32:
        tmp = (32 - len(tmp)) * '0' + tmp
    ABCD_list[i] = tmp
A0,B0,C0,D0 = ABCD_list[0], ABCD_list[1], ABCD_list[2], ABCD_list[3]

# 生成第1-64个式子的第i个32比特常数
Ti = []
for i in range(0, 64):
    result = (int(4294967296 * abs(math.sin(i + 1)))) & 0xffffffff
    result = bin(result)[2:]
    if len(result) < 32:
        result = (32 - len(result)) * '0' + result
    Ti.append(result)

# 实现x,y的逐比特与
def and1(x, y):
    res = ''
    for i in range(0, len(x)):
        res += str(int(x[i])&int(y[i]))
    return res
# 实现x,y的逐比特或
def or1(x, y):
    res = ''
    for i in range(0, len(x)):
        res += str(int(x[i])|int(y[i]))
    return res
# 实现x,y的逐比特异或
def xor(x, y):
    res = ''
    for i in range(0, len(x)):
        res += str(int(x[i])^int(y[i]))
    return res
# 实现x的逐比特逻辑反
def reverse(x):
    res = ''
    for i in range(0, len(x)):
        res += str((int(x[i], 2) + 1) % 2)
    return res

# 实现x的循环左移
def shift(x, i):
    res = ''
    for t in range(0, len(x) - i):
        res = res + x[t + i:t + i + 1]   # 先保存 x[i:]  再保存x[:i]
    for y in range(0, i):
        res = res + x[y:y + 1]
    return res

# 实现整数模2的三十二次方加法
def add(x, y):
    a = int(x,2)  #先将二进制转换成十进制
    b = int(y,2)
    res = (a + b)%(2**32)
    res = str(bin(res)[2:])
    if len(res) != 32:    # 补充到32位
        res = (32-len(res))*'0'+res
    return res

# 定义f,g,h,i函数
def ffunc(x, y, z):  # ((x&y)|((~x)&z))
    t = and1(x, y)
    t1 = reverse(x)
    t2 = and1(t1, z)
    return or1(t, t2)

def gfunc(x, y, z):  # ((x&z)|(y&(~z)))
    t = and1(x, z)
    t1 = reverse(z)
    t2 = and1(y, t1)
    return or1(t, t2)

def hfunc(x, y, z): # (x^y^z)
    t1 = xor(x, y)
    t2 = xor(t1, z)
    return t2

def ifunc(x, y, z): # (y^(x|(~z)))
    t = reverse(z)
    t1 = or1(x, t)
    return xor(y, t1)

def fill(text):
    text1 = ''
    for i in text:
        t = str(ord(i))
        t = str(bin(int(t, 10))[2:])
        if len(t) < 8:                 # 将每个字符转换成8位二进制数
            for num in range(8 - len(t)):
                t = '0' + t
        text1 = text1 + t
    length = len(text1)
    length1 = 512 - len(text1) - 65    # length1是要填充0的位数
    text1 = text1 + '1'                # 第一位添加 0
    text1 = text1 + '0'*length1        # 将其补充到 N*512+448  N可以为0
    text2 = bin(length)[2:]            # 将字符长度转换成二进制数
    if len(text2) < 8:                 #  填充后面64位,先填充字符串的长度,再补0
        text2 = '0'*(8 - len(text2)) + text2

    length2 = 64 - len(text2)
    text2 = text2 + '0'*length2        # 填充后面64位,先填充字符串的长度,再补0
    return text1 + text2

# 将最后得到的ABCD逆序输出  最后一步使用
def reverse_order(a):
    res = a[24:32] + a[16:24] + a[8:16] + a[0:8]
    return res

# 输入要加密的明文
password = input("请输入要加密的信息:")
# 填充算法
x = fill(password)


j = 0
M = []
for i in range(0,len(x),32):   # 将512位分成十六组
    M.append(x[i:i+32])
    M[j] = M[j][24:32] + M[j][16:24] + M[j][8:16] + M[j][0:8]
    j+=1

# md5算法的第一步
A,B,C,D= A0,B0,C0,D0  #为第五步 相加原始的A,B,C,D做备份

# md5算法的第二步
AA,BB,CC,DD = A,B,C,D

# md5算法的第三步
# 第一轮     每轮A,B,C,D都处理四次,四轮就是十六次,一共六十四次
for i in range(4):                  # f函数
    A = add(B, shift(add(A, add(add(ffunc(B, C, D), M[4*i]), Ti[4 * i])), 7))
    D = add(A, shift(add(D, add(add(ffunc(A, B, C), M[4*i+1]), Ti[4 * i + 1])), 12))
    C = add(D, shift(add(C, add(add(ffunc(D, A, B), M[4*i+2]), Ti[4 * i + 2])), 17))
    B = add(C, shift(add(B, add(add(ffunc(C, D, A), M[4*i+3]), Ti[4 * i + 3])), 22))

# 第二轮
k = 1
j = 16
for i in range(4):
    A = add(B, shift(add(A, add(add(gfunc(B, C, D), M[(k+5*(4*i))%16]), Ti[j + i * 4])), 5))
    D = add(A, shift(add(D, add(add(gfunc(A, B, C), M[(k+5*(4*i+1))%16]), Ti[j + i * 4 + 1])), 9))
    C = add(D, shift(add(C, add(add(gfunc(D, A, B), M[(k+5*(4*i+2))%16]), Ti[j + i * 4 + 2])), 14))
    B = add(C, shift(add(B, add(add(gfunc(C, D, A), M[(k+5*(4*i+3))%16]), Ti[j + i * 4 + 3])), 20))

# 第三轮
k = 5
j = 32
for i in range(4):
    A = add(B, shift(add(A, add(add(hfunc(B, C, D), M[(k+i*4*3)%16]), Ti[j + i * 4])), 4))
    D = add(A, shift(add(D, add(add(hfunc(A, B, C), M[(k+(i*4+1)*3)%16]), Ti[j + i * 4 + 1])), 11))
    C = add(D, shift(add(C, add(add(hfunc(D, A, B), M[(k+(i*4+2)*3)%16]), Ti[j + i * 4 + 2])), 16))
    B = add(C, shift(add(B, add(add(hfunc(C, D, A), M[(k+(i*4+3)*3)%16]), Ti[j + i * 4 + 3])), 23))

# 第四轮
k = 0
j = 48
for i in range(4):
    A = add(B, shift(add(A, add(add(ifunc(B, C, D), M[(k+(i*4)*7)%16]), Ti[j + i * 4])), 6))
    D = add(A, shift(add(D, add(add(ifunc(A, B, C), M[(k+(i*4+1)*7)%16]), Ti[j + i * 4 + 1])), 10))
    C = add(D, shift(add(C, add(add(ifunc(D, A, B), M[(k+(i*4+2)*7)%16]), Ti[j + i * 4 + 2])), 15))
    B = add(C, shift(add(B, add(add(ifunc(C, D, A), M[(k+(i*4+3)*7)%16]), Ti[j + i * 4 + 3])), 21))
# 第五步  将计算出的A,B,C,D与初始的相加,并赋值
A,B,C,D = add(A, AA),add(B, BB),add(C, CC),add(D, DD)
# 输出得到的密文

ciphertext = reverse_order(A) + reverse_order(B) + reverse_order(C) + reverse_order(D)
cipher = ciphertext
ciphertext = str(hex(int(ciphertext, 2))[2:])   # 将二进制数转换为十六进制数
ciphertext = '0'*(32-len(ciphertext))+ciphertext # 为了避免第一个数字为零时无法显示出来
print("hash值(小写):",ciphertext)
print("hash值(大写):",ciphertext.upper())

六、综合实验

6.1 实验内容

现在,Alice想通过公共信道给Bob传输一份秘密文件(文件非常大)。又知道,很多人和机构想得到这份文件。需要设计一个通信模型,来保证文件的机密性和完整性。

现在很多人想要得到这份文件,那么,可能会有很多人在假冒Bob的身份,来请求得到这个文件,需要对Bob身份进行验证;也有可能是很多人得不到文件,就假冒Alice的身份,想要给Bob发送文件,如果有人发送恶意文件给Bob,Bob发现不是想要的文件,但这个文件给Bob电脑安装了后门,等他接受了正确的文件,就存在泄漏的风险,所以需要对Alice身份进行验证。

6.2 分析实验需求

现在很多人想要得到这份文件,那么,可能会有很多人在假冒Bob的身份,来请求得到这个文件,需要对Bob身份进行验证;也有可能是很多人得不到文件,就假冒Alice的身份,想要给Bob发送文件,如果有人发送恶意文件给Bob,Bob发现不是想要的文件,但这个文件给Bob电脑安装了后门,等他接受了正确的文件,就存在泄漏的风险,所以需要对Alice身份进行验证。

根据分析,所得结果如下:

  1. 传输的是秘密文件,所以可能存在人冒充bob接收文件,所以Alice在与传输文件之前需要对bob的身份进行认证,而且bob防止被欺骗也需要对Alice的身份进行认证,这里可以采用第二类签名算法。

  2. 在确认彼此身份后需要将文件通过公共信道传输,但是可能存在攻击人劫持,所以需要对文件内容加密,而文件内容很大,考虑到加密速度问题,所以采用对称加密算法。

  3. 采用对称加密算法需要密钥,而这里使用随机生成的密钥。并且这个密钥也需要传给bob用于解密,但是公共信道不安全,所以也需要对该密钥进行加密。考虑到密钥长度不是很大,所以可以采用公钥加密算法,而且公钥加密算法可以解决传输此次加密使用的密钥,提高安全性和效率。

  4. Bob收到密文和加密后的密钥,使用自己的私钥解密出对称加密算法使用的密钥,然后使用密钥解密密文后向Alice发送确认消息,确保bob收到消息。

  5. 确认消息也要使用到第一步使用的签名算法。

6.3 程序流程图

image-20210202142616269

6.4 完整代码

Alice

# -*- coding = utf - 8 -*-
#@Time : 2021/1/3 23:17
#@Author : sunzy
#@File : Alice.py

from RSA import *
from DES import *
from MD5 import *
from file_decode import *
import socket

n_bob = 81836285346168841919828227774710209132464519960137459236348092425786962849543
n = 44531776921047477359676235110843825307036514195195627878765712056028758572817
d = 34159352569920789505556306994405309761109146525598570740717995833480670158209
e = 65537

name = "This is alice."

client = socket.socket()
client.connect(('127.0.0.1',8888))  # 本机地址和端口

data = client.recv(1024)
print(str(data, "utf-8"),end="")
client.send(b'1')
print("等待bob验证自身身份...")

# alice送出自己的身份信息和签名值
client.send(bytes(name,'utf-8'))             # alice发送身份明文信息
client.recv(1024).decode()
hash_name = md5(name)
crpto_name = str(RSAEncode(hash_name, d, n)) # 发送对hash值加密后的值
crpto_name = bytes(crpto_name,'utf-8')
client.send(crpto_name)

print(client.recv(1024).decode())             # 接收身份认证的结果
#接收bob身份hash并验证
print("验证bob身份...",end="")
a=input()

bob_name = client.recv(512).decode()          # bob发送过来的身份明文信息
client.send(b'1')

hash_name = client.recv(512).decode()         # bob使用自己的私钥加密身份明文信息hash值后的值
plain_text = RSADecode(int(hash_name),e,n_bob) # 使用bob的公钥解密上一步的值

client.send(b'1')
if plain_text == md5(bob_name):          # 验证是不是bob
    print(bob_name)
    print("验证通过!")
else:
    exit("验证错误!")


while 1:
    a = input()
    bin_key = gen_key()         # 随机生成64位的 DES加密明文使用的密钥
    int_key = int(bin_key,2)    # 将其转换为十进制数,便于后面使用RSA算法加密
    print("随机产生对称密钥:",int_key)  # 每次传输随机产生一个密钥更加安全

    plain = read_file()    # 读取文件内容
    bin_cipher = DES_encode(plain, bin_key) # 使用DES算法加密内容

    a = input()
    int_key = fast_mod(int_key,e,n_bob)   # 加密DES的密钥 e是bob的公钥
    print("加密对称密钥")

    print("传输密钥...")               # 传输加密后DES密钥
    client.sendall(bytes(str(int_key),"utf-8"))
    client.recv(512)

    length = str(len(bin_cipher))     # 传输发送内容的长度
    length = bytes(length,"utf-8")    # 方便其接收
    client.send(length)

    print("传输密文...")
    client.sendall(bytes(str(bin_cipher),"utf-8")) #发送密文
    message = client.recv(512).decode()
    client.send(b'1')
    crypt_message = client.recv(512).decode()
    hash_message = RSADecode(int(crypt_message),e,n_bob)
    if hash_message == md5(message):
        print(message)
    print("文件传输结束!")
    break
client.close()

Bob

# -*- coding = utf - 8 -*-
#@Time : 2021/1/3 23:17
#@Author : sunzy
#@File : bob.py

import socket
import libnum
from RSA import *
from DES import *
from MD5 import *

name = "This is bob."


n = 81836285346168841919828227774710209132464519960137459236348092425786962849543
n_alice = 44531776921047477359676235110843825307036514195195627878765712056028758572817
d = 39540198292360595989919600111176873707392294831248672388670326288876701993673
e = 65537

# e_alice = 2081

server = socket.socket() #创建对象
server.bind(("localhost",8888))#绑定 ip和端口
server.listen()  #监听
#等待连接
print('Waiting connection...')
#接受请求,返回套接字对象和IP+端口号
con,addr = server.accept()
con.send(bytes("Welcome connect!\n开始加密传输:\n","utf-8"))
con.recv(1024)

# 验证alice身份
print("验证alice身份...")
a = input()
alice_name = con.recv(512).decode()  # alice 的明文信息
con.send(b'1')
hash_name = con.recv(512).decode()   # alice 用私钥加密明文的hash值
plain_text = RSADecode(int(hash_name),e,n_alice) # 用alice 的公钥解密出hash值
if plain_text == md5(alice_name):   # 判断上一步的值与md5函数加密是否相同
    print(alice_name)               # 如果二者相同则可以保证对方是alice,这里的安全性是由公钥算法和hash函数保证
    print("验证通过!")               # 因为只有alice有自己的私钥,hash函数的存在防止伪造明文攻击
    con.send(bytes("您通过了验证!","utf-8"))
else:
    exit("这不是alice,验证错误!")
#送出自己的身份信息和签名值
print("等待alice验证自身身份...")

con.send(bytes(name,'utf-8'))    # 向alice发送身份信息的明文
con.recv(1024).decode()

hash_name = md5(name)            # 明文信息的hash值
crpto_name = str(RSAEncode(hash_name, d, n))  # 使用自己的私钥加密上一步的hash值
crpto_name = bytes(crpto_name,'utf-8')        # 发送给alice
con.send(crpto_name)
con.recv(1024)

while 1:
    data = con.recv(1024)    # 接收alice发送的使用公钥算法加密后的DES的密钥
    data = data.decode()
    int_key = int(data)
    print("被加密后的密钥:",int_key)
    int_key = fast_mod(int_key, d, n)  # 使用私钥d解密出DES密钥
    print("解密后的密钥", int_key)

    print("----"*10)         # 接收密文的长度(为了方便存储)
    con.send(b'1')
    length = con.recv(1024)
    length = int(length.decode())
    buff = []
    size = 0
    while size < length:    # 开始接受密文
        dat = con.recv(1024)
        size += len(dat.decode())
        buff.append(dat)
    data = b''.join(buff)
    bin_cipher = data.decode()

    cipher = bin_to_str(bin_cipher)
    bin_key = bin(int_key)[2:]      # 将密钥转换成二进制数
    print("解密传输内容:")
    print(libnum.b2s(DES_decode(cipher, bin_key))) #打印出解密后的明文
    message = "Bob received the file successfully!"
    con.send(bytes(message,'utf-8'))
    con.recv(1024).decode()
    hash_message = md5(message)
    crypt_message = str(RSAEncode(hash_message,d,n))
    con.send(bytes(crypt_message,'utf-8'))
    break

server.close()

file_decode

# -*- coding = utf - 8 -*-
#@Time : 2021/1/3 23:17
#@Author : sunzy
#@File : file_decode.py


import random
import socket
import re
from RSA import *
from DES import *
from MD5 import *

def gen_key():  # 生成64位的对称加密的密钥
    list = []
    for i in range(64):
        c = random.choice(['0', '1'])
        list.append(c)
    res = "".join(list)
    return res

def read_file():
    try:
        f = open('text.txt','r', encoding = 'utf-8')
        text = f.read()
        f.close()
        print("读取成功!")
        return text
    except IOError:
        print("读取错误!")


def bin_to_str(bin_str) :   # 8位二进制转字符,用于bob收到密后使用
    res = ""
    tmp = re.findall(r'.{8}',bin_str)
    for i in tmp :
        res += chr(int(i,2))
    return res

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

 目录

Copyright © 2020 my blog
载入天数... 载入时分秒...