python實(shí)現(xiàn)簡(jiǎn)易SSL的項(xiàng)目實(shí)踐
本篇博客使用python實(shí)現(xiàn)了一個(gè)簡(jiǎn)易的SSL,以幫助理解SSL的大致實(shí)現(xiàn)流程。
SSL(Secure Socket Layer)安全套接層是Netscape公司率先采用的網(wǎng)絡(luò)安全協(xié)議。它是在傳輸通信協(xié)議(TCP/IP)上實(shí)現(xiàn)的一種安全協(xié)議,采用公開密鑰技術(shù)。
運(yùn)行環(huán)境
- 操作系統(tǒng):浪潮云啟操作系統(tǒng) InLinux 23.12 LTS SP1
- python版本:3.9.9
- 使用的python包:cryptography、ownca、signify
浪潮云啟操作系統(tǒng)(InLinux)面向企業(yè)級(jí)業(yè)務(wù),提供自主可控、安全可靠的新一代服務(wù)器操作系統(tǒng),全面支持云計(jì)算、大數(shù)據(jù)、人工智能、物聯(lián)網(wǎng)等新型場(chǎng)景,具備性能高效、擴(kuò)展便捷、管理智能、內(nèi)生安全等特性。
運(yùn)行前準(zhǔn)備
# 安裝python yum install -y python # 安裝python包 pip install cryptography ownca signify
程序?qū)崿F(xiàn)與流程說明
本程序?qū)崿F(xiàn)了一個(gè)簡(jiǎn)易的SSL,共分為三個(gè)模塊:CA.py,server.py,client.py。
CA.py負(fù)責(zé)簽發(fā)證書,server.py與client.py通信,過程中會(huì)實(shí)現(xiàn)生成公私鑰對(duì)、會(huì)話密鑰等過程。為了簡(jiǎn)易性,server能夠從本地直接獲取證書,且只有server對(duì)client檢查證書。
程序流程如下:
- CA生成根證書、公私鑰對(duì)
- client生成公私鑰對(duì)、向CA發(fā)送CSR請(qǐng)求
- CA收到CSR請(qǐng)求,用私鑰簽名,向client發(fā)送簽名證書,client拿到證書
- client第一次向server發(fā)送數(shù)據(jù),并附帶證書信息
- server檢驗(yàn)證書信息,并生成session_key,利用client公鑰加密session_key,將密文發(fā)回給client,之后的對(duì)話用session_key驗(yàn)證。
- client解密session_key,利用消息和session_key生成MAC,向server發(fā)送消息并附帶MAC
- server收到消息并驗(yàn)證MAC,對(duì)話結(jié)束。
運(yùn)行截圖
CA.py

server.py

client.py

證書目錄:

代碼
CA.py
import ownca.ownca
import socket
from cryptography import x509
from cryptography.x509 import NameOID
ca = ownca.CertificateAuthority(ca_storage='./myCA',common_name='myCA')
print("myCA initialized")
HOST = "127.0.0.1" # Standard loopback interface address (localhost)
PORT = 11111 # Port to listen on (non-privileged ports are > 1023)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(5)
print("myCA server is running...")
while True:
conn, addr = server_socket.accept()
print(f"Connected by {addr}")
data = conn.recv(2048)
csr = x509.load_pem_x509_csr(data)
try:
# sign the CSR, if success, the certificate will generate and store
ca.sign_csr(csr,csr.public_key(),maximum_days=825)
except Exception as e:
print(e)
# extract CN from CSR
common_name = csr.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
# load the issued certificate from existing file
load_cert = ca.load_certificate(common_name)
print('Successfully sign for ' + common_name)
# Send the certificate bytes
send_data = load_cert.cert_bytes
conn.sendall(send_data)
conn.close()
client.py
import socket
import pickle
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, hmac
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa, padding
def generateCSR(common_name, private_key):
csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
# Provide various details about who we are.
x509.NameAttribute(NameOID.COUNTRY_NAME, u"CN"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Beijing"),
# x509.NameAttribute(NameOID.LOCALITY_NAME, u"Richmond"),
# x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Organization"),
x509.NameAttribute(NameOID.COMMON_NAME, common_name),
])).sign(private_key, hashes.SHA256())
return csr
def RSADecryption(cipher, private_key):
msg = private_key.decrypt(
cipher,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return msg
# Generate the RSA private key
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
cn = input("Input common name: ")
csr = generateCSR(cn, private_key)
public_key = private_key.public_key()
# public_key = csr.public_key()
csr_bytes = csr.public_bytes(serialization.Encoding.PEM)
print(cn + ": Key Pair and CSR generated!")
HOST = "127.0.0.1" # The server's hostname or IP address
CA_PORT = 11111 # The CA server port
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, CA_PORT))
s.sendall(csr_bytes) # send the generated CSR
cert_data = s.recv(2048)
print(cn + " signing finished!, part of the cert:")
print(cert_data[:40] + b'...')
print('================================================')
Server_PORT = 22222 # The Server port
session_key = b''
msg = b''
hMAC = b''
public_key_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, Server_PORT))
# send all params to the Server
params = [cn, cert_data, public_key_pem, session_key, msg, hMAC]
data = pickle.dumps(params)
s.sendall(data)
data = s.recv(2048)
print("Received from Server: ")
session_key = RSADecryption(data, private_key)
print("Session key decrypted:",session_key)
msg = b'This is messgae from ' + cn.encode('utf-8') + b'.\n'
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, Server_PORT))
msg = msg * 10
h = hmac.HMAC(session_key,hashes.SHA256())
h.update(msg)
hMAC = h.finalize()
# Send all params with valid session_key, msg and hMAC
params = [cn, cert_data, public_key_pem, session_key, msg, hMAC]
data = pickle.dumps(params)
s.sendall(data)
data = s.recv(2048)
print(data)
server.py
import os
import pickle
import socket
import ownca
from cryptography.hazmat.primitives import hashes, hmac
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_pem_public_key
from signify.x509 import CertificateStore, VerificationContext, Certificate
ca = ownca.CertificateAuthority(ca_storage='./myCA',common_name='myCA')
print("Successfully load the CA certificate")
HOST = "127.0.0.1"
PORT = 22222
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen()
print("Server is running...")
# generate a list of random bytes as Session key
def generateSessionKey(byte_num=16):
return os.urandom(byte_num)
# Encrypt the msg using RSA
def RSAEncryption(msg, public_key):
cipher = public_key.encrypt(
msg,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return cipher
while True:
conn, addr = server_socket.accept()
print(f"Connected by {addr}")
data = conn.recv(2048)
# find all params from the received data
params = pickle.loads(data)
cn = params[0]
cert_from_cli_pem = params[1]
public_key_pem = params[2] # for encrypting the session_key
session_key = params[3]
msg = params[4]
hMAC_to_check = params[5]
# if no session built
if not session_key:
try:
# Using Signify to verify the certificate
# Raise exception if verification error
trust_store = CertificateStore([Certificate.from_pem(ca.cert_bytes)], trusted=True)
context = VerificationContext(trust_store)
Certificate.from_pem(cert_from_cli_pem).verify(context)
except Exception as e:
print(cn + "Verification error: ", e)
conn.sendall(b"Verification error!\n")
conn.close()
continue
finally:
print(cn + " Verification success!")
# load cert from stu_pem and find the public_key
public_key = load_pem_public_key(public_key_pem)
session_key = generateSessionKey()
print(cn + " Session key generated:",session_key)
cipher = RSAEncryption(session_key,public_key)
conn.sendall(cipher)
# valid session key
else:
h = hmac.HMAC(session_key, hashes.SHA256())
h.update(msg)
try:
h.verify(hMAC_to_check)
except Exception as e:
print(cn + " MAC Verification wrong:",e)
conn.close()
continue
finally:
print(cn + " MAC Verification success!")
print(msg)
conn.sendall(b'MAC Verification success!')
conn.close()
參考資料
到此這篇關(guān)于python實(shí)現(xiàn)簡(jiǎn)易SSL的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)python實(shí)現(xiàn)簡(jiǎn)易SSL內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解pandas中Series()和DataFrame()的區(qū)別與聯(lián)系
本文主要介紹了詳解pandas中Series()和DataFrame()的區(qū)別與聯(lián)系,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
Python中列表(List) 的三種遍歷(序號(hào)和值)方法小結(jié)
這篇文章主要介紹了Python中列表(List) 的三種遍歷(序號(hào)和值)方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
通過Python 獲取Android設(shè)備信息的輕量級(jí)框架
今天跟大家分享一下,如何通過Python實(shí)現(xiàn)一個(gè)輕量級(jí)的庫來獲取電腦上連接的Android設(shè)備信息,需要的朋友參考下吧2017-12-12
詳解python?sklearn中的數(shù)據(jù)預(yù)處理方法
本篇文章主要講解Python的sklearn庫中常用的數(shù)據(jù)預(yù)處理方法,主要介紹工具中的內(nèi)容,即該庫中的相關(guān)方法包含的常用接口和基本使用,希望對(duì)大家有所幫助2023-08-08
python3+PyQt5實(shí)現(xiàn)支持多線程的頁面索引器應(yīng)用程序
這篇文章主要為大家詳細(xì)介紹了python3+PyQt5實(shí)現(xiàn)支持多線程的頁面索引器應(yīng)用程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04
時(shí)間序列預(yù)測(cè)中的數(shù)據(jù)滑窗操作實(shí)例(python實(shí)現(xiàn))
滑動(dòng)窗口操作非常普遍,非常有用,它們也很容易在Python中實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于時(shí)間序列預(yù)測(cè)中的數(shù)據(jù)滑窗操作python實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2022-03-03
Python opencv圖像基本操作學(xué)習(xí)之灰度圖轉(zhuǎn)換
使用opencv將圖片轉(zhuǎn)為灰度圖主要有兩種方法,第一種是將彩色圖轉(zhuǎn)為灰度圖,第二種是在使用OpenCV讀取圖片的時(shí)候直接讀取為灰度圖,今天通過實(shí)例代碼講解Python opencv圖像基本操作學(xué)習(xí)之灰度圖轉(zhuǎn)換,感興趣的朋友一起看看吧2023-02-02

