2018-2019-2 20165221课程设计学习-week3

2018-2019-2 20165221课程设计学习-week3

目录


一 . 深入了解Openssl

#### 概念理解: > 在计算机网络上,OpenSSL是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。这个包广泛被应用在互联网的网页服务器上。

二 . 拷贝虚拟机搭建环境

- 完全克隆网络对抗实验用到的kali机,新建```课程设计的kali``` ![](https://img2018.cnblogs.com/blog/1322987/201905/1322987-20190524203051376-284688748.png)
  • 参考链接 , 下载并安装pyOpenSSL, 选择安装的版本为 pyOpenSSL-0.11.winxp32-py2.7.msi
  • 将其放到桌面上,使用openssl命令生成私钥
    openssl genrsa -out private.pem -f4 1024 来生成私钥,指数值为10001

三 . 测试基于RSA的加解密

1 . 先完成相关配置,确定对Hello,20165221!进行加解密:

  • 从私钥private.pem导出公钥public.pem

  • 将字符串”Hello 20165221!”存放到文件msg.bin作为测试数据:

2 . 进行加密:

  • 输入指令openssl rsautl -in msg.bin -out 20165221.enc -inkey public.pem -pubin -encrypt -pkcs,使用前面生成的公钥public.pem对测试数据msg.bin进行加密,得到加密后的数据20165221.enc
  • 查看加密后的数据:

3 . 进行解密:

  • 使用私钥private.pem对加密后的数据20165221.enc进行解密,并将结果存放到20165221.dec文件中:
openssl rsautl -in 20165221.enc -out 20165221.dec -inkey private.pem -decrypt -pkcs

  • 查看解密后的内容:

  • 即成功完成一次加解密!!

4 . 指令详解:

  • in选项指定待解密的数据文件msg.bin.enc
  • out 选项指定解密后的输出文件msg.bin.dec
  • inkey 选项指定用于解密的私钥Key.pem,由于输入是私钥,所以不再需要使用选项-pubin
  • decrypt 选项表明这里是进行解密操作
  • pkcs 选项指定解密处理过程中数据的填充方式,对于填充,可选项有:-pkcs, -oaep, -ssl, -raw,默认是-pkcs,即按照PKCS#1 v1.5规范进行填充

四 . python实现非对称加解密

- 因为加解密是基于Python下的cryptograhpy库,先安装该库```sudo pip3 install cryptography```: - 查看验证呢过环境是否完整,```python --version```: ![](https://img2018.cnblogs.com/blog/1322987/201905/1322987-20190525092030145-28419986.png)
  • 还是之前的Hello,20165221!进行加解密,这次将加解密的文件放到一起,是为rsa-加解密.py
#!/usr/bin/env python3

# 导入cryptography库的相关模块和函数
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization

from cryptography.hazmat.primitives.asymmetric import padding

# 定义辅助函数,用于打印16进制数据
def dump_hex(buffer, sep=' ', indent=0, line_size=16):
    """
    辅助函数,将bytes数组以如下格式打印输出:
    0000: 40 71 37 d0 80 32 7f 04 d9 6d fb fc f7 6a 7d d4
    0010: 48 ad 75 79 7a 0d 6c 55 01 ed 45 d5 1e 75 33 a6
    :param buffer: 待打印数据
    :param sep: 各16进制数据之间的分隔符,默认用空格' '分隔
    :param indent: 打印输出前是否需要缩进,默认不缩进
    :param line_size: 每行输出16进制的数量,默认1行输出16个
    :return: 无返回值
    """
    # 计算缩进空格数
    leading = '%s' % ' '*indent
    # 循环打印每行16进制数据
    for x in range(0, len(buffer), line_size):
        # 打印缩进字符和当前行数据的起始地址
        print('%s%04X: ' % (leading, x), end='')
        # 将当前行数据制作成列表list,并打印
        line = ['%02x' % i for i in buffer[x:x+line_size]]
        print(*line, sep=sep, end='
')


# 加密函数
def encrypt(src_file_name, dst_file_name, public_key_file_name):
    """
    对原始数据文件使用指定的公钥进行加密,并将加密输出到目标文件中
    :param src_file_name: 原始数据文件
    :param dst_file_name: 加密输出文件
    :param public_key_file_name: 用于加密的公钥
    :return: 加密结果的bytes数组
    """
    # 读取原始数据
    data_file = open(src_file_name, 'rb')
    data = data_file.read()
    data_file.close()

    # 读取公钥数据
    key_file = open(public_key_file_name, 'rb')
    key_data = key_file.read()
    key_file.close()

    # 从公钥数据中加载公钥 
    public_key = serialization.load_pem_public_key(
        key_data,
        backend=default_backend()
        )

    # 使用公钥对原始数据进行加密,使用PKCS#1 v1.5的填充方式
    out_data = public_key.encrypt(
        data,
        padding.PKCS1v15()
    )

    # 将加密结果输出到目标文件中
    # write encrypted data
    out_data_file = open(dst_file_name, 'wb')
    out_data_file.write(out_data)
    out_data_file.close()

    # 返回加密结果
    return out_data


# 解密函数
def decrypt(src_file_name, dst_file_name, private_key_file_name):
    """
    对原始数据文件使用指定的私钥进行解密,并将结果输出到目标文件中
    :param src_file_name: 原始数据文件
    :param dst_file_name: 解密输出文件
    :param private_key_file_name: 用于解密的私钥
    :return: 解密结果的bytes数组
    """
    # 读取原始数据
    data_file = open(src_file_name, 'rb')
    data = data_file.read()
    data_file.close()

    # 读取私钥数据
    key_file = open(private_key_file_name, 'rb')
    key_data = key_file.read()
    key_file.close()

    # 从私钥数据中加载私钥
    private_key = serialization.load_pem_private_key(
        key_data,
        password=None,
        backend=default_backend()
    )

    # 使用私钥对数据进行解密,使用PKCS#1 v1.5的填充方式
    out_data = private_key.decrypt(
        data,
        padding.PKCS1v15()
    )

    # 将解密结果输出到目标文件中
    out_data_file = open(dst_file_name, 'wb')
    out_data_file.write(out_data)
    out_data_file.close()

    # 返回解密结果
    return out_data

if __name__ == "__main__":
    data_file_name = r'msg.bin'
    encrypted_file_name = r'msg.bin.encrypted'
    decrypted_file_name = r'msg.bin.decrypted'

    private_key_file_name = r'Key.pem'
    public_key_file_name = r'Key_pub.pem'

    # 先对数据加密
    data = encrypt(data_file_name, encrypted_file_name, public_key_file_name)
    # 打印加密结果
    print("encrypted data:")
    dump_hex(data)

    # 对数据进行解密
    data = decrypt(encrypted_file_name, decrypted_file_name, private_key_file_name)
    # 打印解密结果
    print("decrypted data:")
    dump_hex(data)

  • 运行刚刚的rsa-加解密.py,使用指令python3 rsa-加解密.py

  • 与源文件对比,发现解密成功:

  • 对于解密后的数据msg.bin.decrypted和原始数据msg.bin,二者的md5校验值是一样的,也证明了解密成功!


五 . 基于Python和OpenSSL实现的SSL网络通信

- 首先用openssl生成相关的证书: ```openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout key.pem``` ![](https://img2018.cnblogs.com/blog/1322987/201905/1322987-20190525104522462-1322684543.png) - 紧接着配置证书的相关信息: ![](https://img2018.cnblogs.com/blog/1322987/201905/1322987-20190525104554148-1034443295.png) - **对于客户端**:发送6次100byte的数据,显示客户端发送时长,以及客户端数据的时长,并显示平均时长: ![](https://img2018.cnblogs.com/blog/1322987/201905/1322987-20190525105057231-1190897776.png)
  • 对于服务端:接收客户端的数据,并向客户端发送1000byte的数据,显示服务端收到时间,发送时间,以及平均时间:
  • 并且获取证书的具体信息:

六 . 代码链接

- [代码链接](https://gitee.com/tx0630/course_design_for_201810192) ![](https://img2018.cnblogs.com/blog/1322987/201905/1322987-20190524215620668-412103868.png) ![](https://img2018.cnblogs.com/blog/1322987/201905/1322987-20190525110528099-542687150.png)



七 . 本周学习总结

- 这周尝试了一下基于Python的rsa的加解密,还是挺有趣的,虽然学习的过程是波折的,但学到的喜悦也是真是的啦! - 尝试SSL通信的成功也很有意思,这次课设自己还是有收获的,就是有点后悔之前没有好好学,但是,现在还想也不算迟吧....
  • 附SSL网络通信的代码:
  • 服务器端

    import socket
    import ssl,time
    sock=socket.socket()
    print("建立套接字成功")
    sock.bind(("127.0.0.1", 443))
    print("绑定成功")
    sock.listen(1)
    def input_pro(connstream,data):
        print("接收到的客户端数据长度是",len(data))
        return True
    def doclient(connstream):
        recvtime=0
        sendtime=0
        n=0
        t1=time.clock()
        data=connstream.recv(1024)
        t2=time.clock()
        print("服务端接收客户端数据的时间",t2-t1)
        while data:
            if not input_pro(connstream,data):
                break
            n=n+1
            t3 = time.clock()
            connstream.send(b'b' * 1000)
            t4 = time.clock()
            sendtime += t4 - t3
            print("服务端发送数据时长", t4 - t3)
            t3 = time.clock()
            data = connstream.recv(1024)
            t4 = time.clock()
            recvtime += t4 - t3
            print("服务端接收客户端数据时间", t4 - t3)
        print("平均发送时间是",sendtime/n,"平均接收时间是",recvtime/n,)
        return True
    while True:
        #接受连接并返回(conn,address),
        # 其中conn是新的套接字对象,
        # 可以用来接收和发送数据。
        # address是连接客户端的地址。
        conn,addr=sock.accept()
        print("客户端的套接字数据接收到了")
        connstream=ssl.wrap_socket(conn,"key.pem","cert.pem",server_side=True)
        try:
            doclient(connstream)
        finally:
            connstream.shutdown(socket.SHUT_RDWR)
            connstream.close()

  • 客户端:
    import socket, ssl, pprint, time
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    ssl_s=ssl.wrap_socket(s,cert_reqs=ssl.CERT_REQUIRED,ca_certs="cert.pem")
    ssl_s.connect(("127.0.0.1", 443))
    print("套接字连接成功")
    n=0
    sendtime=0
    recvtime=0
    while n<6:
        n=n+1
        t1=time.clock()
        ssl_s.send(b'a'*100)
        t2=time.clock()
        sendtime+=t2-t1
        print("发送时长",t2-t1)
        t1=time.clock()
        data=ssl_s.recv(1024)
        t2=time.clock()
        recvtime+=t2-t1
        print("接收时长",t2-t1)
        print(len(data))
    print("平均接收时间",sendtime/n,"平均发送时间",recvtime/n)
    print("生成的证书信息")
    pprint.pprint(ssl_s.getpeercert())
    ssl_s.close()

参考资料

原文地址:https://www.cnblogs.com/0630tx/p/10920219.html