设计文档
姓名:贾昊龙
学号:18307130049
主体思路
- 通过socket编程首先先建立好明文传输的链接
- hello阶段(如果是SSL的话,这里是SSL中握手协议的作用,并且后面的一些过程也是该协议)
- 在这里,客户端通过链接来向服务器发送客户端所支持的协议以及加密算法,并生成随机数random1在这里参考了TLS协议分析这篇blog以及SSL/TLS链接的建立的blog,在这里采用AES-RSA-MD5作为cipher suit
- 服务器返回消息,在AES-RSA-MD5上与客户端达成一致,生成random 2
- 证书发送及认证(certificate)阶段
- 首先服务器将自己的证书下发给客户端,让客户端进行验证,之后客户端验证后从证书中取出公钥
- 由于难以自行形成证书,所以可以通过把简写的CA.txt文件当作证书,通过私钥验签的方式验证身份
- 密钥交换
- 使用RSA密钥交换方式,客户端生成session key
- 将明文和计算的hash值进行连接
- AES将明文+mac一起进行加密传输
函数解释
server
函数 解释 send_CA() 利用私钥加密CA证书发送给客户端 key_exchanging() 使用私钥解密客户端发来的用公钥加密的sessionkey deAes() AES解密过程 verify_mac() MD5计算收到的会话信息产生的hash值 getplaintext() 验证客户端封装的hash值和重新计算的hash值是否匹配 msg() 监听并打印会话信息 client
函数 解释 verify_ca() 客户端用公钥进行验签过程 key_exchanging() 使用公钥加密sessionkey并发送给服务器 enAes() AES加密过程 enmac() MD5计算发送的信息产生的hash值并组装 add_to_16() 将信息扩展位数成16整数倍 msg() 加密信息发送到服务器
具体实现
Socket Connection
建立socket连接的过程如下
首先是server
服务器创建socket对象,绑定对应端口以及IP,等待接收连接
import socket #创建socket对象s,基于internet地址和tcp协议 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #绑定本地端口8001 s.bind(("127.0.0.1", 8001)) #在本地8001端口监听,最大连接数量6 s.listen(6) # 接受来自客户端的连接 connection, address = s.accept() print("服务器:Waiting for connection...")
其次是client
import socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(('127.0.0.1', 8001))
Hello阶段
server
服务器等待客户的发送过来的消息,并且根据对方可用的加密算法来选择自己的加密算法,在这里直接假设双方只支持AES-RSA-MD5的cipher suit
data = connection.recv(1024) #the message received print('客户端: '+data.decode('utf-8')) #hello,this is a hello message from the client x = ' OK.Let''s use the AES-RSA-MD5. '
client
客户端通过已经建立好的链接来想想服务器发送消息,消息的主要目的是发送支持的加密算法,由服务器来选择相应的加密算法,在这里采用AES-RSA-MD5
x = 'hello,this is a hello message from the client.Can we use AES-RSA-MD5?' print('客户端:'+x) client.send(x.encode('utf-8'))
证书发送及认证(certificate&Verify)阶段
server
当彼此选好了加密算法之后,服务器将证书发给客户端,并且用私钥数字签名的方式交付给客户端来进行CA的验证
x1 = '\n服务器: These are my information, please check.' print('服务器:'+x+x1) connection.send((x+x1).encode('utf-8')) #私钥加密CA证书发送给客户端 def send_CA(): with open('private_key_ca.pem') as privatefile: p = privatefile.read() privkey = rsa.PrivateKey.load_pkcs1(p) x = '\nserver''s private key is as following' print(x+'\n'+p) with open('CA') as content: ca = content.read() print('服务端\n'+ca) a = rsa.sign(ca.encode('utf-8'), privkey, 'SHA-1') return a signature = send_CA() connection.sendto(signature, address)
client
客户端拿到证书之后用公钥的解密并且进行验证
def verify_ca(data): with open('public_key_ca.pem') as publickfile: p = publickfile.read() pubkey = rsa.PublicKey.load_pkcs1(p) print('---------CA公钥---------\n'+p) with open('CA') as content: ca = content.read() print(ca) try: rsa.verify(ca.encode('utf-8'), data, pubkey) print('验证成功') except: print('验证失败') data = client.recv(1024) verify_ca(data)
密钥交换
client
采取24位长的 ‘0singdancerapbasketball0’作为session key(直接设置),之后就是用公钥进行加密,然后发送给服务器
def key_exchanging(): secretkey = '0singdancerapbasketball0' with open('public_key_ca.pem') as publicfile: p = publicfile.read() pubkey = rsa.PublicKey.load_pkcs1(p) crypto = rsa.encrypt(secretkey.encode('utf-8'), pubkey) return crypto print('开始密钥交换,用公钥来对session key进行加密然后发送') client.send(key_exchanging())
server
服务器用私钥解密,获得session key
def key_exchanging(data): with open('private_key_ca.pem') as privatefile: p = privatefile.read() privkey = rsa.PrivateKey.load_pkcs1(p) secretkey = rsa.decrypt(data, privkey) return secretkey print('开始密钥交换,等待对称密钥') data = connection.recv(1024) secretkey = key_exchanging(data).decode('utf-8') print('服务器:客户端发过来的对称密钥为:{'+secretkey+'}(忽略大括号)')
哈希值的计算
- client
- 利用MD5来计算session的哈希值,并且之后加载到上面,中间的split为18307130049JHL,而由于加密信息的无规律,基本不会出现和split相同的内容进而引起对内容的解释的错误
def enmac(plaintext):
h1 = hashlib.md5()
h1.update(plaintext.encode('utf-8'))
x = plaintext+'18307130049JHL'+h1.hexdigest()
print('明文+hash:'+x)
return x
server
而服务器端也需要计算哈希值,根据得到的session的内容来计算哈希值,与客户端的哈希值进行匹配
def verify_mac(plaintext): h1 = hashlib.md5() h1.update(plaintext.encode('utf-8')) return h1.hexdigest() def getplaintext(textandmac): str = textandmac.split('18307130049JHL') if(str[1] != verify_mac(str[0])): return 'false' else: return str[0]
AES加密
client
将明文+hash的内容利用session key进行加密并传输
def encAes(x): key = '0singdancerapbasketball0' #24位密钥 text = x aes = AES.new(str.encode(key), AES.MODE_ECB) # 采用ECB加密模式 encrypted_text = str(base64.encodebytes(aes.encrypt(add_to_16(text))), encoding='utf8').replace('\n', '') # 加密 print('加密结果为:', encrypted_text) return encrypted_text def msg(client): while True: re_data = input() ciphertext = encAes(enmac(re_data)) client.send(ciphertext.encode('utf-8')) print('------------------------------------------------') print('验证交互信息') print('------------------------------------------------') print('用户请输入\n[只支持英文信息]') msg(client)
server
在服务端,将利用session来进行解密
def deAes(text, key): aes = AES.new(str.encode(key), AES.MODE_ECB) # 采用ECB加密模式 decrypted_text = str(aes.decrypt(base64.decodebytes(bytes(text, encoding='utf8'))).rstrip(b'\0').decode("utf8")) # 解密 return decrypted_text def msg(connection): while True: try: data = connection.recv(1024) ciphertext = data.decode('utf-8') textandmac = deAes(ciphertext, secretkey) plaintext = getplaintext(textandmac) if(plaintext == 'false'): print('mac值false,退出') return else: print('mac值相同验证通过') print('客户端:', plaintext) except: print('connection failed') return print('------------------------------------------------') print('验证交互信息') print('------------------------------------------------') print('等待用户输入') msg(connection)
运行截图
下面是一些运行截图
首先是运行server.py之后运行client.py(server图片–client图片–server图片–client图片)
附CA
-------------Verify--------------
Sequence num:01010101
Version:X.509
Public key Algorithm: RSA
date:2020.10.28-2020.11.28
Server:jhl
split:18307130049JHL
--------------DONE---------------
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMhK8UrmtY+iSUrQhhcxAA8eAgB99gpKjbx8uo15geRbcr3pqR192Wdm
UcyXoZ7MH+FEtQ4v14awNsoub0NcgUepHj2xzzat7pes4NZz/9YCLEgFA+5/VnKn
ez5FoHwfQT58XsXFXKOni35sMIVEgoCLdURELd09nBsGCqzR9tiVAgMBAAE=
-----END RSA PUBLIC KEY-----
回顾
首先,先了解一下什么是TLS/SSL以及他们的作用
相当于是在应用层和在运输层之间添加了一个SSL协议层,而SSL协议分为了两层,一层是SSL记录协议:是为上层的数据提供数据的封装加密等等;而SSL握手协议:是在数据传输开始之前,双方进行身份确认,协商机密算法,交换加密密钥的过程
关于TLS/SSL建立连接以及握手的过程
阶段一
- Client Hello,发送random 1,客户端支持的加密算法的组合列表等
- Server Hello,从客户端发送的加密算法的组合列表中进行选择,生成random 2
阶段二(服务器鉴别以及密钥交换)
- 服务器将自己的证书CA发送给客户端,让客户端进行验证,客户端验证后从CA中取出对应的公钥
- 可要求客户端上报CA,
- 通知客户端Server Hello结束
客户鉴别和密钥交换
- 验证好服务端的CCA之后,取出公钥,将session key用公钥加密之后发送给服务器,服务器用私钥解密之后获得session key
阶段四
- 计算session对应的hash值,之后双方在进行通信的过程中,如果两个hash值匹配了,说明对应的session会话过程建立起来了,之后将hash值放在明文后面,并且用session key来进行加密
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!