python實(shí)現(xiàn)簡易SSL的項(xiàng)目實(shí)踐
本篇博客使用python實(shí)現(xiàn)了一個(gè)簡易的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è)簡易的SSL,共分為三個(gè)模塊:CA.py,server.py,client.py。
CA.py負(fù)責(zé)簽發(fā)證書,server.py與client.py通信,過程中會(huì)實(shí)現(xiàn)生成公私鑰對(duì)、會(huì)話密鑰等過程。為了簡易性,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)簡易SSL的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)python實(shí)現(xià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-01Python中列表(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-08python3+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-03Python opencv圖像基本操作學(xué)習(xí)之灰度圖轉(zhuǎn)換
使用opencv將圖片轉(zhuǎn)為灰度圖主要有兩種方法,第一種是將彩色圖轉(zhuǎn)為灰度圖,第二種是在使用OpenCV讀取圖片的時(shí)候直接讀取為灰度圖,今天通過實(shí)例代碼講解Python opencv圖像基本操作學(xué)習(xí)之灰度圖轉(zhuǎn)換,感興趣的朋友一起看看吧2023-02-02