Socket模拟加密数据传输

HTTPS

在上一篇文章中,我们简单描述了HTTPS的传输过程:

1.客户端发送TLS版本号,生成的随机数1和自己支持的加密方法(明文)

2.服务器返回确认的加密方法,服务端的证书,生成的随机数2(明文)

3.客户端验证证书有效(浏览器和操作系统内置),然后生成随机数3,并且用有效证书中的公钥加密这个随机数,加密传输给服务器。(非对称加密密文)

4.服务器使用自己的私钥解密这个密文,得到随机数3,此时双方都有了3个随机数(2个明文传输,1个密文传输),双方根据之前确定的加密算法,生成对话密钥(对称密钥)

5.之后的每次数据传输,都使用这个密钥对数据进行加密(对称加密密文)

本篇基于上述模型,在python中实现socket加密通信

socket基本通信

这里,我们再次请出密码学两位传奇人物:ALice和Bob,近似于客户端和服务器

ALice

import socket

alice_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
bob_address = ('127.0.0.1', 5000)  
alice_socket.connect(bob_address)

while True:
    message = input("请输入给Bob发送的信息:")
    message=str(message)
    alice_socket.send(message.encode('utf-8'))
    print("发送成功,请等待回复......")

    received_message = alice_socket.recv(1024)
    print(f"收到 Bob 的消息: {received_message.decode('utf-8')}")

Bob

import socket

bob_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
local_address = ('127.0.0.1', 5000)  
bob_socket.bind(local_address)

bob_socket.listen(1)
alice_socket, alice_address = bob_socket.accept()


print("消息接收中,请等待......")
while True:

    received_message = alice_socket.recv(1024)
    print(f"收到 Alice 的消息: {received_message.decode('utf-8')}")

    message = input("请输入发送给Alice的消息:")
    alice_socket.send(message.encode('utf-8'))
    print("发送成功,请等待回复......")

上述代码可以在本地模拟实现ALice和Bob的相互通信

加密算法

生成随机数

模型中,我们需要生成三个随机数,这里设计一个统一的随机数方法,使得生成的随机数符合一个既定的标准

def generate_num():
    characters = string.digits
    randomNum = ''.join(random.choice(characters) for _ in range(16))
    return randomNum

generate_num()每次运行都会返回一个16位随机纯数字的字符串

合成公钥

模型中,当双方都获取到了3个随机数后,会合成一个相同的对称密钥,这里要求根据3个随机数进行相同的数据处理操作,保证双方生成的对称密钥相同

def generate_sykey(s1, s2, s3):
    num1 = int(s1, 16)
    num2 = int(s2, 16)
    num3 = int(s3, 16)

    result = num1 + num2 + num3

    hex_result = hex(result)[2:]
    if len(hex_result) > 16:
        hex_result = hex_result[-16:]

    return hex_result

generate_sykey(s1, s2, s3),传入三个随机数,生成一个16位,值为16进制的字符串(合成算法可以设计得更加复杂,但是必须保证同样的输入获得一致的输出)

对称加密

在对称加密传输中,我们需要对发送的信息进行签名,然后对源信息和签名组合加密

def encrypt_message(SYkey, message, private):
    # 签名
    hash_message = rsa.compute_hash(message.encode('utf-8'), "SHA-256")
    signer = rsa.sign(hash_message, private, "SHA-256")
    b_message = message.encode('utf-8') + ",".encode('utf-8') + signer

    # 加密
    cipher = AES.new(SYkey.encode(), AES.MODE_EAX)
    ciphertext, tag = cipher.encrypt_and_digest(b_message)
    return ciphertext, tag, cipher.nonce
签名

加密时需要传入的参数:SYkey 对称密钥,message源数据,private个人私钥

首先对源数据进行hash,得到数据摘要hash_message

然后对数据摘要进行签名,得到signer签名

随后将源信息和签名组合,这里我们添加一个“,”来方便进行数据分割

加密

生成一个AES加密对象chiper

通过EAX加密模式,得到密文和一些参数

返回值:ciphertext(密文),nonce(随机数),tag(标记)三个值都需要获取并且全部传输给对方

对称解密

解析

数据接收方会得到ciphertext(密文),nonce(随机数),tag(标记)组合在一起的值,我们可以设计一个类来分割存储这个值(根据传输时的结构简单解析)

class Aes_Data():
    def __init__(self, ciphers):
        self.ciphertext = ciphers[:-32]
        self.nonce = ciphers[-32:-16]
        self.tag = ciphers[-16:]

这里需要注意,和传输时结构组合顺序一致,上述即ciphertext+nonce+tag顺序

解密

解析完成密文结构后,就可以进行解密了

def decrypt_message(SYkey, public,ciphinfo):
    # 解密
    cipher = AES.new(SYkey.encode(), AES.MODE_EAX, nonce=ciphinfo.nonce)
    b_message = cipher.decrypt_and_verify(ciphinfo.ciphertext, ciphinfo.tag)
    b_message_list = b_message.split(b',')
    message = b_message_list[0].decode('utf-8')

    # 验证签名
    signer = b_message_list[1]
    temp_hash_message = rsa.compute_hash(message.encode('utf-8'), "SHA-256")
    try:
        rsa.verify(temp_hash_message, signer, public)
        return message
    except rsa.VerificationError:
        print("签名验证失败")

解密函数传入SYkey 对称密钥,public发送方公钥,ciphinfo解析完成的密文对象(带有ciphertext(密文),nonce(随机数),tag(标记))

首先建立解密AES对象,传入SYkey对称密钥和nonce随机数

然后进行AES解密,得到源信息+“,”(分隔符)+签名的的数据,分割后得到源信息和签名

验签

这里我们先将接受到的消息进行一次hash,得到接受的数据的临时摘要

然后使用rsa.verify()传入(临时摘要,签名,发送方的公钥),进行验签

验签成功,则返回源信息的数据。验签失败,则提示"签名验证失败",不返回数据。

加密通信

模型中,我们可以将通信过程分为两个阶段:加密连接阶段,加密通信阶段

加密连接阶段

本阶段需要达成两个目的:1.获取对方公钥,2.获取本次通信的对称密钥

ALice:

# 生成公钥私钥
(ALice_public, ALice_private) = rsa.newkeys(512)
ALice_public_str = ALice_public.save_pkcs1().decode()

# 1.生成随机数1,Alice的公钥
rand_num01 = Enconding.generate_num()
alice_socket.send((rand_num01 + "," + ALice_public_str).encode())

# 2.获取随机数2,Bob的公钥
received_message = alice_socket.recv(1024).decode()
code02 = received_message.split(",")
rand_num02 = code02[0]
Bob_public_str = code02[1].encode()
Bob_public = rsa.PublicKey.load_pkcs1(Bob_public_str)

# 3.生成随机数3,(公钥加密)
rand_num03 = Enconding.generate_num()
code03 = rsa.encrypt(rand_num03.encode(), Bob_public)
alice_socket.send(code03)

# 获取对称密钥
SYkey = Enconding.generate_sykey(rand_num01, rand_num02, rand_num03)

Bob:

# 生成公钥私钥
(Bob_public, Bob_private) = rsa.newkeys(512)
Bob_public_str=Bob_public.save_pkcs1().decode()

# 1.接收随机数1,和ALice的公钥
received_message = alice_socket.recv(1024).decode()
code01=received_message.split(",")
rand_num01=code01[0]
ALice_public=rsa.PublicKey.load_pkcs1(code01[1].encode())

# 2.生成随机数2,合并公钥传送
rand_num02=Enconding.generate_num()
alice_socket.send((rand_num02+","+Bob_public_str).encode())

# 3.获取随机数3,(私钥解密)
received_message = alice_socket.recv(1024)
rand_num03=rsa.decrypt(received_message,Bob_private).decode()

# 获取对称密钥
SYkey=Enconding.generate_sykey(rand_num01,rand_num02,rand_num03)

经过上述的几次传输,双方都得到了对方的公钥( _public)和相同的对称密钥(SYkey)

加密通信阶段

得到上述的参数后,我们终于可以进行加密通信了:
Alice

while True:
    # 发送消息给 Bob
    message = input("请输入给Bob发送的信息:")
    b_message,tag,nonce=Enconding.encrypt_message(SYkey,message,ALice_private)
    alice_socket.sendall(b_message+nonce+tag)

    print("发送成功,请等待回复......")

    # 接收 Bob 的消息
    received_message = alice_socket.recv(1024)
    chipinfp=Enconding.Aes_Data(received_message)
    message=Enconding.decrypt_message(SYkey,Bob_public,chipinfp)
    print(f"收到 Bob 的消息: {message}")

Bob

print("消息接收中,请等待......")
while True:

    received_message = alice_socket.recv(1024)
    chiperinfo=Enconding.Aes_Data(received_message)
    message=Enconding.decrypt_message(SYkey,ALice_public,chiperinfo)

    print(f"收到 Alice 的消息: {message}")

    # 发送消息给 Alice
    message = input("请输入发送给Alice的消息:")
    b_message,tag,nonce=Enconding.encrypt_message(SYkey,message,Bob_private)
    alice_socket.sendall(b_message+nonce+tag)
    print("发送成功,请等待回复......")

消息发送时,先使用加密函数encrypt_message()对消息进行加密和签名,得到b_message+nonce+tag,合并传输给对方

消息接收时,先将接受的数据解析成chiperinfo,传入解密函数decrypt_message()进行解密和验签

验证

未加密通信

测试程序中,不使用加密,Alice向Bob发送“你好”,使用Wireshark抓包可以得到UTF-8编码的明文数据

image-20240605111850471

使用python解码可以解析到源数据

image-20240605112425046

加密通信

使用加密,然后通过wireshark抓包,

image-20240605113634876

我们知道,解密需要(对称密钥,密文,对方公钥)

在加密数据传输中,对称密钥是通过随机数自己生成的,不在网络中流通,所以即使窃听者得到了密文,公钥,也无法解密数据,我们的实现了加密通信!

image-20240605112749666

  • 46
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
// C/C++, 利用OpenSSL库对Socket传输进行安全加密(RSA+AES) // 1. 利用RSA安全传输AES生成密钥所需的Seed(32字节) // 2. 利用AES_encrypt/AES_decrypt对Socket上面的业务数据进行AES加密/解密 // --- // * 理论上只需要AES就能保证全部流程,但由于AES加密所需要的AES-KEY是一个结构 // * 这个一个结构,如果通过网络进行传输,就需要对它进行网络编码,OpenSSL里面没有现成的API // * 所以就引入RSA来完成首次安全的传输,保证Seed不会被窃听 // * 同样,只使用RSA也能完成全部流程,但由于RSA的处理效率比AES低, // * 所以在业务数据传输加密上还是使用AES // --- // 下面的代码包含了上述传输加密流程所需的所有步骤(OpenSSL部分) // 在实际的Socket应用开发时,需要将这些步骤插入到Client/Server网络通信的特定阶段 // --- // 为能完成代码的编译和执行,需要先安装OpenSSL执行库及开发库 // 以Debian为例,需要安装openssl 和 libssl-dev // 编译命令: g++ -o rsa-encrypt rsa-encrypt.cpp -lcrypto // --- // 所需的OpenSSL主要的API及功能描述 // 1. RSA_generate_key() 随机生成一个RSA密钥对,供RSA加密/解密使用 // 2. i2d_RSAPublicKey() 将RSA密钥对里面的公钥提出到一个BUF,用于网络传输给对方 // 3. d2i_RSAPublicKey() 将从网络传过来的公钥信息生成一个加密使用的RSA(它里面只有公钥) // 4. RSA_public_encrypt() 使用RSA的公钥对数据进行加密 // 5. RSA_private_decrypt() 使用RSA的私钥对数据进行加密 // 6. AES_set_encrypt_key() 根据Seed生成AES密钥对中的加密密钥 // 7. AES_set_decrypt_key() 根据Seed生成AES密钥对中的解密密钥 // 8. AES_encrypt() 使用AES加密密钥对数据进行加密 // 9. AES_decrypt() 使用AES解密密钥对数据进行解密 // --- // 一个典型的安全Socket的建立流程, 其实就是如何将Server随机Seed安全发给Client // -- C: Client S:Server // C: RSA_generate_key() --> RSAKey --> i2d_RSAPublicKey(RSAKey) --> RSAPublicKey // C: Send(RSAPublicKey) TO Server // S: Recv() --> RSAPublicKey --> d2i_RSAPublicKey(RSAPublicKey) --> RSAKey // S: Rand() --> Seed --> RSA_public_encrypt(RSAKey, Seed) --> EncryptedSeed // S: Send(EncryptedSeed) TO Client // C: Recv() --> EncryptedSeed --> RSA_private_decrypt(RSAKey, EncryptedSeed) --> Seed // --- 到此, Client和Server已经完成完成传输Seed的处理 // --- 后面的流程是它们怎样使用这个Seed来进行业务数据的安全传输 // C: AES_set_encrypt_key(Seed) --> AESEncryptKey // C: AES_set_decrypt_key(Seed) --> AESDecryptKey // S: AES_set_encrypt_key(Seed) --> AESEncryptKey // S: AES_set_decrypt_key(Seed) --> AESDecryptKey // --- Client传输数据给Server // C: AES_encrypt(AESEncryptKey, Data) --> EncryptedData --> Send() --> Server // S: Recv() --> EncryptedData --> AES_decrypt(AESDecryptKey, EncryptedData) --> Data // --- Server传输数据给Client // S: AES_encrypt(AESEncryptKey, Data) --> EncryptedData --> Send() --> Client // C: Recv() --> EncryptedData --> AES_decrypt(AESDecryptKey, EncryptedData) --> Data / ========================================================================================= */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值