本主题主要是通过一个例子说明SSL的过程与机制。
一、理解SSL的加密过程与机制
SSL加密机制实际是一种信任机制,这个在现实有很多例子:比如印章就是一种信任机制。尽快常用加密技术不完全类似印章的原理,但本质都差不多。
SSL中数据通信都采用加密,其加密的机制使用的是CA签名加密机制。
1. 对称加密与非对称加密
加密算法分为两种:对称加密和非对称加密。
|- 对称加密就是发送双发使用相同的密钥对消息进行加解密,常见的对称加密为DES、3DES,AES等。
|- 非对称加密是发送双方各自拥有一对公钥私钥,其中公钥是公开的,私钥是保密的。当发送方向接收方发送消息时,发送方利用接收方的公钥对消息进行加密,接收方收到消息后,利用自己的私钥解密就能得到消息的明文。其中非对称加密方法有RSA、Elgamal、ECC等。
CA加密机制就是一种非对称加密机制。
2. 数字签名
数字签名在网络通讯中的过程如下:
|- 当通信A端向B端发送信息时,会将报文生成报文摘要,同时对报文摘要进行hash计算,得到hash值,然后对hash值进行加密,然后将加密的hash值放置在报文后面,这个加密后的hash值就称为签名。
|- 通信A端将报文、签名和数字证书一同发送给B端。B端收到这些信息后,会首先验证签名,利用签名算法对签名进行解密,得到报文摘要的hash值,然后将得到的报文生成报文摘要并利用签名hash算法生成新的hash值,通过对比这两个hash值是否一致,就能判断信息是否完整,是否是由真正的通信A端发送的。
数字签名有两个作用:
|- 确认消息发送方可靠
|- 确认消息完整准确。
3. SSL加密过程
-
使用openssl工具生成CA证书
产生一个证书文件与私钥。 -
使用openssl工具生成需要签名的服务器(或者客户端)证书与私钥。
产生一个待签名证书与私钥。 -
使用openssl工具,用CA证书对服务器证书签名。
产生一个签名证书
二、 使用openssl工具产生CA签名证书实现
1. 产生CA根证书与私钥
openssl req -newkey rsa:2048 -passout pass:123456 -keyout ca_rsa_private.pem -x509 -days 365 -out ca.crt -subj "/C=CN/ST=SC/L=CD/O=MAGE/OU=TEACHING/CN=NO/emailAddress=1234567@qq.com"
使用的是RSA非对称加密,两个重要参数说明:
-keyout ca_rsa_private.pem :指定生成的密钥文件;
-out ca.crt:指定生成证书的文件。
在终端执行输出:
localhost:certs yangqiang$ openssl req -newkey rsa:2048 -passout pass:123456 -keyout ca_rsa_private.pem -x509 -days 365 -out ca.crt -subj "/C=CN/ST=SC/L=CD/O=MEGE/OU=TEACHING/CN=NO/emailAddress=1234567@qq.com"
Generating a 2048 bit RSA private key
....................+++
...............+++
writing new private key to 'ca_rsa_private.pem'
-----

2. 产生服务器(或者客户端)待签名证书与私钥
openssl req -newkey rsa:2048 -passout pass:server -keyout server_rsa_private.pem -out server.csr -subj "/C=CN/ST=BJ/L=CP/O=MAGEZongbu/OU=MNGT/CN=SERVER/emailAddress=38395870@qq.com"
其中两个关注的参数说明:
|- -out server.csr 指定生成的待签名证书。
|- -keyout server_rsa_private.pem 指定生成的服务器(或者客户端)私钥。
|- -passout pass:server 密码(这个在服务器加载整数与私钥的时候,需要每次都输入,如果不想输入,可以生成没有密码的私钥。)
localhost:certs yangqiang$ openssl req -newkey rsa:2048 -passout pass:server -keyout server_rsa_private.pem -out server.csr -subj "/C=CN/ST=BJ/L=CP/O=MAGEZongbu/OU=MNGT/CN=SERVER/emailAddress=38395870@qq.com"
Generating a 2048 bit RSA private key
......................................................................+++
................................+++
writing new private key to 'server_rsa_private.pem'
-----

3. 对服务器证书进行签名
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca_rsa_private.pem -passin pass:123456 -CAcreateserial -out server.crt
重要参数说明:
|- -in server.csr 需要签名的整数。
|- -CA ca.crt 根证书
|- -CAkey ca_rsa_private.pem 根证书私钥
|- -out server.crt 生成的签名证书(可以使用的)
localhost:certs yangqiang$ openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca_rsa_private.pem -passin pass:123456 -CAcreateserial -out server.crt
Signature ok
subject=/C=CN/ST=BJ/L=CP/O=MAGEZongbu/OU=MNGT/CN=SERVER/emailAddress=38395870@qq.com
Getting CA Private Key

三、使用python实现SSL服务器认证加密
也可以实现客户认证加密,也可以实现双向认证加密。
1. ssl模块的API结构
使用help与dir可以仔细阅ssl模块的帮助与API结构,实际上核心的类就两个:
|- SSLContext
|- SSLSocket
在help中可以看到其继承结构如下:
|- socket.socket(_socket.socket)
|- SSLSocket
|- 包含socket中方法,也包含SSL特色的网络通信操作函数。
|- _ssl._SSLContext(builtins.object)
|- SSLContext
|- init(self, protocol=<_SSLMethod.PROTOCOL_TLS: 2>) :指定版本
|- load_cert_chain(self, /, certfile, keyfile=None, password=None) :加载证书与私钥
|- wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, server_hostname=None, session=None):对socket通信进行签名加密处理。
import ssl
# print(dir(ssl))
# print(dir(ssl.SSLContext))
# help(ssl.SSLContext)
# help(ssl.SSLSocket)
# print(dir(ssl.SSLSocket))
2. SSL socket服务器端实现
# coding = utf-8
import ssl
import socket
# 1. 创建SSL上下文,需要指定版本,缺省的是PROTOCOL_TLS,我们指定服务器签名PROTOCOL_TLS_SERVER
# 这一步的关键是选择合适的版本,每个不同的版本之间是不互融的。
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
# 2. 加载证书与服务器私钥
ctx.load_cert_chain(certfile='./certs/server.crt', # 服务器已经签名的证书
keyfile='./certs/server_rsa_private.pem', # 服务器私钥
password='server') # 生成服务器时输入的密码(这里不指定,就需要输入)
# 3. 创建socket
server_socket = socket.socket(
socket.AF_INET,
socket.SOCK_STREAM,
socket.IPPROTO_TCP)
# 4. 使用ctx创建一个包装器socket,该socket具有签名加密功能。
ssl_server_socket = ctx.wrap_socket(
sock=server_socket, # 被包装的socket
server_side=True) # 指定是服务器测签名加密
# 5. 正常的socket通信操作
# 绑定服务器地址
ssl_server_socket.bind(('', 8443)) # 443时SSL通用端口,注意使用元组表示地址格式
# 监听
ssl_server_socket.listen(2)
while True:
# 接受客户连接
print('等待客户连接!')
client_socket, client_address = ssl_server_socket.accept()
print('有客户连接:', client_address)
# 接受客户数据
info = client_socket.recv(1024).decode("utf-8")
print(f"从客户{client_address}接受的信息{info}")
# 给客户发送一个信息
client_socket.send('来自服务器的信息!收到没有?'.encode('utf-8'))
client_socket.close()
break
ssl_server_socket.close()
下面是输出次效果:
等待客户连接!
有客户连接: ('127.0.0.1', 52427)
从客户('127.0.0.1', 52427)接受的信息来自客户的数据!
3. SSL socket客户端实现
# coding = utf-8
import ssl
import socket
# 1.创建SSL通信上下文
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# 2.加载根证书
ctx.load_verify_locations('./certs/ca.crt')
# 3.创建一个客户端socket
client_socket = socket.socket(
socket.AF_INET,
socket.SOCK_STREAM,
socket.IPPROTO_TCP)
# 4.创建socket包装器,实现SSL通信
ssl_client_socket = ctx.wrap_socket(
sock=client_socket,
server_side=False,
server_hostname='SERVER') # 这个值是识别创建服务器证书的产品名,就是CN指定的名字
# 5.通用的socket通信模式
# 连接到服务器
ssl_client_socket.connect(('127.0.0.1',8443))
# 发送数据
ssl_client_socket.send('来自客户的数据!'.encode('utf-8'))
# 接受数据
info = ssl_client_socket.recv(1024).decode("utf-8")
print(f"从服务器接受的信息:{info}")
ssl_client_socket.close()
下面是输出效果:
从服务器接受的信息:来自服务器的信息!收到没有?
这里只是通过证书说明SSL中的签名加密过程,在这个基础上,可以实现客户端签名认证与双向签名认证。
注意:上面两个程序不能同时在ipython中执行,因为ipython是单线程,服务器运行起来,客户端没有办法执行。
备注:
本文使用的三个指令:
openssl req -newkey rsa:2048 -passout pass:123456 -keyout ca_rsa_private.pem -x509 -days 365 -out ca.crt -subj "/C=CN/ST=SC/L=CD/O=MEGE/OU=TEACHING/CN=NO/emailAddress=1234567@qq.com"
openssl req -newkey rsa:2048 -passout pass:server -keyout server_rsa_private.pem -out server.csr -subj "/C=CN/ST=BJ/L=CP/O=MAGEZongbu/OU=MNGT/CN=SERVER/emailAddress=38395870@qq.com"
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca_rsa_private.pem -passin pass:123456 -CAcreateserial -out server.crt
网友评论