实现两个主机之间的密钥分发和加密传输

  • 前言:之前密码学实验课已经用python分别写过AES和RSA,本次内容要求是使用RSA进行密钥分配,使用AES进行加密传输。
    具体要求如下:
编写一段程序,实现两个主机之间的密钥分发和加密传输。
要求:
(1)用RSA算法实现两个主机之间的密钥分发,分发的密钥是“12345678”;
(2)用分发的密钥和AES加密算法,实现两个主机之间的加密数据传输,传输的数据是“NPU”;
(3)两个步骤在程序中自动执行完,无手动参与;程序可以在同一台主机上完成,但数据必须经过网络传输(可以本地发送,本地接收);
(4)RSA和AES算法必须是源码编译得到,不能直接用编译过的库文件;RSA和AES算法的源码可以来自于网络或其他任意渠道;
(5)用Python或C/C++语言实现程序,写出实现技术文档。

分析需要新做的内容是第三条,在一个程序中自动执行,且数据需要经过网络传输,初步计划用socket套接字来实现。

1、Socket通信

参考https://blog.csdn.net/resilient/article/details/82796061

创建文件,修改权限


AFDC563F-091F-494D-A16A-8525166B8094.png

开启Apache
Mac中有自带的Apache服务,不用再安装软件,开启/关闭命令如下

sudo apachectl  start    // 开启
sudo apachectl  stop      // 关闭
sudo apachectl  restart 

浏览器中输入 127.0.0.1 ,如果开启成功,显示结果如下:


96339C32-E4CC-4E04-AFF4-5A5F74BDF54D.png

按照教程并不能实现,尝试使用python进行实现。
使用无连接的UDP

客户端代码如下

from socket import *
class UdpClient:
   serverName = '127.0.0.1'  //服务器名
   serverPort = 12000  //端口号
   socketAddress = (serverName, serverPort)
   def __init__(self):
       #define the type of socket is IPv4 and Udp
       self.clientSocket = socket(AF_INET, SOCK_DGRAM)
       while True:
           message = input("Input a lowercase sentence\n")
           self.clientSocket.sendto(message.encode('utf-8'), self.socketAddress)
           returnMessage, serverAddress = self.clientSocket.recvfrom(2048)
           if not returnMessage:
               break
           print("The peersocket is: %s:%s" %(serverAddress[0], serverAddress[1]))
           print("The return message is: %s" %returnMessage.decode('utf-8'))
if __name__ == '__main__':
   client = UdpClient()

这个程序的功能是把用户输入的内容用utf-8进行编码,传输出去,并且接受服务器端传来的数据,使用的是self.clientSocket.recvfrom()

服务器端如下:

from socket import *

serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind(('',serverPort))
print('Waiting for connection...')
while True:
    message, clientAddress = serverSocket.recvfrom(2048)
    print('Receive Message: %s' %message.decode('utf-8'))
    modifiedMessage = message.decode('utf-8').upper()
    serverSocket.sendto(modifiedMessage.encode('utf-8'), clientAddress)

代码流程和刚才差不多,也是设置端口,进行绑定,接受数据,把数据转成大写,发送给客户端

1DEBF1EE-258D-41A2-A321-6B18DBFE438F.png

完成!

2、RSA实现密钥分发

在刚才的基础上加入RSA加密传递明文,参考之前的记录。
由于文件较大代码较多,分在不同的文件中再进行调用逻辑会更加清晰一些

  • 存在的一个小问题是:要传递的密钥为12345678,如果当作数字来传输,数值较大,可能会由于它超过了要模的值,在计算的时候会出现错误。
    解决方法是:把数字分割为4个一组,并且传递明文的长度一共是多少。在接收端分别解密,并把它拼在一起,作为数字长度。

  • 遇到的问题:如何传递函数。现在的数还是str, 在加密时应该先转为int。
    一直报错

5B7050C6-7922-4728-9FF6-FE2036AAD483.png

后来发现是重复用M了。但是修改之后仍然不行,可能是字符串分割转换的时候有问题了。

加上这句 temp_M = int(temp_M,10),也不行。

4EAB9C8A-3AE2-4E83-9947-6EF43B65DB5C.png

查阅资料发现是因为使用的是python3,/除法要变成 // ,问题解决。

  • 再次出错,把刚才UDP socket的class改成def了,再改回来,就可以传输了。以为可以,但是实际上还是不行。

  • 尝试按照发送的框架,把RSA嵌套在内部 =。=
    可以实现,但要注意一些小细节,密钥产生是在服务器端

357D0EAD-C30D-4D17-B075-13BE814B7E5E.png

分组解密收到的字符串应该连接起来


EEA30047-8118-4558-BB49-BFDEA9A07A6A.png

上面这样是不正确的,应该使用向list尾部增加元素的方法,用.append
尝试如下:

M_de.append(decrypedmessage)

res = ''.join(M_de)

要加入一个密钥传输停止的标志

if (decrypedmessage == 'stop'):
        break;

传输这边可以了,解码的有些错误。数字和字符串还是有一些不一样的,把原来打算传输的stop换为404,表示传输结束。【有一定的隐患,如果要传输的内容恰好为404,就会认为是停止传输了】

有一句报错:invalid literal for int() with base 10:
改正:```stop_sign = str(404)``

再次改正:接收端不能停止的原因是:我发送的明文是404,解密后变成了其他的。应该在发送之前先加密再发送

C = Encry(int(stop_sign),e,n)
self.clientSocket.sendto(str(C).encode('utf-8'), self.socketAddress)

记住,在加密函数里面要用到的是数字,其他时候是字符串

  • 仍然存在的问题:接收端没法停,不知道密钥分发已经结束了
    循环条件尝试改为:while (decrypedmessage != str(404))

先放弃了...老师催作业了

07.15继续

  • 输出404的格式,对照看怎们能判断出来


    09C470FA-50CB-4021-973D-394B3271A956.png

输出发现其实是int型。while判断用int,下面.join用str,res = ''.join(str(M_de))

client端经常报错的原因是:如果恰好是4的倍数,循环次数控制不当,总会多一次而无法正确加密。改正方法:for i in range(ceil(lenOfM/4)):
成功

  • 删掉加在最后的404。类型是list
    方法:先获取长度,
lenofres = len(M_de)
res = ''
for i in range(lenofres - 1):
    res = res + str(M_de[i])

3、AES加密要传输的内容

  • 先把原来的代码加进去,慢慢改错。把文件的长读取改为对三个字符的读取,尾部还是需要加00部全的。

  • 修改密钥为刚才传输的,直接在代码中修改了(这是一个缺点,导致修改密钥时还要在AES代码中修改,但是来不及完善了)

修改完成

ADC974C8-48C2-4DC4-964C-DDC7FA3BBB9C.png

再修改一点输出格式即可。

客户端代码:

#coding:utf-8
from socket import *
import random
import math
import AES_en
import binascii

class UdpClient:
   serverName = '127.0.0.1'
   serverPort = 12000
   socketAddress = (serverName, serverPort)
   def __init__(self):
       #define the type of socket is IPv4 and Udp
       self.clientSocket = socket(AF_INET, SOCK_DGRAM)
   
       def power(x,k,r):
           #    print("求幂运算运算",x,k,r)
           m=k
           t=1
           while(m>0):
               m=m//2
               t=t*2
           m=k
           y=1
           while(t>1):
               t=t//2
               y=(y*y)%r  #在运算的过程中取模 简化运算
               if (m>=t):
                   y=(y*x)%r
                   m=m-t
           return y


       #加密
       def Encry(M,e,n):

           C_encry=power(M,e,n)
           return C_encry

       #解密
       def Decry(C,d,n):
           M_decry=power(C,d,n)
           return M_decry


       e = int(input("输入对方的公钥e = "))
       n = int(input("输入对方的公钥n = "))
       
       M_input=input("输入要传递的会话密钥:")
       M_input = str(M_input)
       lenOfM = len(M_input)
       stop_sign = str(404)
       
       for i in range(int(math.ceil(lenOfM/4))):
           temp_M = M_input[(i)*4:(i+1)*4]
           temp_M = int(temp_M,10)
           C=Encry(temp_M,e,n)  #加密
           
           message = C
           self.clientSocket.sendto(str(message).encode('utf-8'), self.socketAddress)
#           returnMessage, serverAddress = self.clientSocket.recvfrom(2048)
#           if not returnMessage:
#               break
#           print("The peersocket is: %s:%s" %(serverAddress[0], serverAddress[1]))
#           print("The return message is: %s" %returnMessage.decode('utf-8'))
       C = Encry(int(stop_sign),e,n)
       self.clientSocket.sendto(str(C).encode('utf-8'), self.socketAddress)
       
       CCC = 'NPU'
       sread = CCC
       mood = (len(sread))%16
       print("MOOD:",mood)
       part_M1 = CCC
       while(len(part_M1)<16):
           part_M1 = part_M1 + str(0)
       M_temp1=binascii.b2a_hex(part_M1)
       C_temp=AES_en.EncryptionAES(M_temp1)
       CCC1 = ''.join(C_temp)

       print("M1",CCC1)
       print("SSSMMM!:",mood)
       
       self.clientSocket.sendto(str(CCC1).encode('utf-8'), self.socketAddress)
if __name__ == '__main__':
   client = UdpClient()

服务器端代码:

# encoding: utf-8

from socket import *
import random
import math
import AES_de
import binascii

#求d最大公因数
def Greatest_common_factor(a,b):
    while a%b !=0:
        temp=a
        a=b
        b=(temp%b)
            #    print('!!!a=',a,'b=',b)
    return b;

#检测是否是素数 //这里用的是费马小定理,还可以用拉宾米勒算法
def check_prime(s):
    sign=1
    for check_times in range(20):   #检测20次
        b=random.randint(1,10000)  #b是随机的正整数
        if Greatest_common_factor(b,s) ==1:
            if b**(s-1)%s ==1:
                pass
            #print('AAA')
            else:
                sign=0
                #print('BBB')
                break

        else:
            sign=0
            #print('CCC')
            break

                
    if sign==1:
        print(s,'is prime')
    else:
        print(s,'is not prime')
    return sign

#选择e的值
def select_e(fi):
    e=random.randint(1,fi)
    while(Greatest_common_factor(e,fi)!=1):
        e=random.randint(1,fi)
    return e

#生成d的值
def compute_d(e,fi):
    for k in range(10000000):
        
        mod_temp=(k*fi+1)%e
        if (mod_temp==0):
            commen_factor=Greatest_common_factor((k*fi+1)//e,fi)
            if commen_factor==1:
                d=mod_temp
                break
    d=(k*fi+1)/e
    print("d is:")
    print(d)
    return d

#求幂运算的优化
def power(x,k,r):
    #    print("求幂运算运算",x,k,r)
    m=k
    t=1
    while(m>0):
        m=m/2
        t=t*2
    m=k
    y=1
    while(t>1):
        t=t/2
        y=(y*y)%r  #在运算的过程中取模 简化运算
        if (m>=t):
            y=(y*x)%r
            m=m-t
    return y


#加密
def Encry(M,e,n):
    C_encry=power(M,e,n)
    return C_encry

#解密
def Decry(C,d,n):
    M_decry=power(C,d,n)
    return M_decry

#下面是RSA的步骤

#生成p
while 1:
    p=random.randint(10,10000)
    if p%2 ==0:
        pass
    else:
        if check_prime(p)== 1:
            break
print("p is",p)

#生成q
while 1:
    q=random.randint(10,10000)
    if q%2 ==0:
        pass
    else:
        if check_prime(q)== 1:
            break
print("q is",q)
print("\n")

n=p*q
fi=(p-1)*(q-1)
e=select_e(fi)

print("e is")
print(e)
print("fi is")
print(fi)
print("n is")
print(n)

d=compute_d(e,fi)


print("密钥分配阶段,等待对方输入...")

#解密
def Decry(C,d,n):
    M_decry=power(C,d,n)
    return M_decry

serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind(('',serverPort))
print('Waiting for connection...')
M_de = []
decrypedmessage = ''
while (decrypedmessage != int(404)) :
    message, clientAddress = serverSocket.recvfrom(2048)
    print('Receive: %s' %message.decode('utf-8'))
#    modifiedMessage = message.decode('utf-8').upper()
    decrypedmessage = Decry(int(message.decode('utf-8')),d,n)
    print(decrypedmessage)
    print(type(decrypedmessage))
#    if (decrypedmessage == str(404)):
#        print("AAA")
#        break;
#    modifiedMessage = message.decode('utf-8')
#    serverSocket.sendto(modifiedMessage.encode('utf-8'), clientAddress)
    M_de.append(decrypedmessage)
    print(M_de)

lenofres = len(M_de)
res = ''
for i in range(lenofres - 1):
    res = res + str(M_de[i])

#res = ''.join(str(M_de))
print("解密后的密钥为:")

print(res)

while True:
    message, clientAddress = serverSocket.recvfrom(2048)
    print('message : %s' %message.decode('utf-8'))

    C = message
    res = []

    for arr in range(0,len(C),32):
        part_M1 = C[arr:arr+32]
        M_temp1 = AES_de.DecryptionAES(part_M1)
        M_temp2 = ''.join(M_temp1)
        M_temp3 = binascii.a2b_hex(M_temp2)
        res.append(M_temp3)
    CCC = ''.join(res)

    t=0
    for i in range(16):
        if(CCC[len(CCC)-16+i] == '0'):
            t = i
            break
    print(CCC[len(CCC)-16:len(CCC)])

    resss = CCC[0:len(CCC)-16+t]
    print("AAA",resss)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351