python使用p12个人证书发送S/MIME加密,签名邮件
背景
部門某招投標(biāo)信息爬蟲由本人負(fù)責(zé)維護(hù),每天定時(shí)爬取數(shù)據(jù)并通過公司郵箱(smtp)發(fā)送給各位大佬。某天公司的郵箱突然升級為只能使用個(gè)人證書加密的郵件才可以發(fā)送郵件,所以研究了一下相關(guān)技術(shù)
S/MIME加密簡介
S/MIME是Secure/Multipurpose Internet Mail Extensions (安全多用途互聯(lián)網(wǎng)郵件擴(kuò)展協(xié)議)的縮寫,是采用PKI技術(shù)的用數(shù)字證書給郵件主體簽名和加密的國際標(biāo)準(zhǔn)協(xié)議。1992年,MIME(多用途互聯(lián)網(wǎng)郵件擴(kuò)展)協(xié)議編撰完成,用于互聯(lián)網(wǎng)郵件服務(wù)器和網(wǎng)關(guān)之間通信。該標(biāo)準(zhǔn)方法支持非ASCII編碼的附件格式,意味著你可以發(fā)送附件并保證文件可以送達(dá)另一端,但是附件有時(shí)會被篡改,無法確保郵件機(jī)密性和完整性。1995年,S/MIME(安全/多用途互聯(lián)網(wǎng)郵件擴(kuò)展)協(xié)議V1版本開發(fā)問世,對安全方面的功能進(jìn)行了擴(kuò)展,提供數(shù)字簽名和郵件加密功能,郵件加密用來保護(hù)電子郵件的內(nèi)容,數(shù)字簽名用于驗(yàn)證發(fā)件人身份,防止身份冒用,并保護(hù)電子郵件完整性。1998年和1999年相繼出臺V2/V3版本并提交IETF形成系列RFC國際標(biāo)準(zhǔn)。
未經(jīng)S/MIME加密的郵件請求頭
Content-Type: multipart/mixed; boundary="===============1169690444=="
MIME-Version: 1.0
Subject: =?utf-8?b?dGhpcyBpcyBmb3IgdGVzdA==?=
From: potatso@xxx.com
To: potatso@xxx.com
--===============1169690444==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
base64
經(jīng)過S/MIME處理后的郵件體
Subject: =?utf-8?b?dGhpcyBpcyBmb3IgdGVzdA==?=
From: potatso@xxx.com
To: potatso@xxx.com
MIME-Version: 1.0
Content-Type: application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=smime.p7m
MIIHvQYJKoZIhvcNAQcDoIIHrjCCB6oCAQAxgdIwgc8CAQAwOjAuMQswCQYDVQQG
我們可以看見其中的區(qū)別,主要是郵件請求頭的改變。下面我們來實(shí)踐一下
編程
1. p12證書文件
為了對郵件進(jìn)行S/MIME加密,我們首先要將p12證書文件轉(zhuǎn)換為PEM證書文件。在這里不需要糾結(jié)p12證書文件與pem證書文件的區(qū)別,只需要知道SMIM加密或者簽名需要pem證書文件
下面我們來討論一下如何將p12證書文件轉(zhuǎn)換,共有兩種方法。注意,如果p12證書有密碼的話,需要知道密碼才可以進(jìn)行下面的轉(zhuǎn)換
1. openssl
從p12中導(dǎo)出pem證書
openssl pkcs12 -in path.p12 -out newfile.crt.pem -clcerts -nokeys
從p12中導(dǎo)出私鑰
openssl pkcs12 -in path.p12 -out newfile.key.pem -nocerts -nodes
運(yùn)行如下
demo# openssl pkcs12 -in liang_zhibang2020.p12 -out newfile.crt.pem -clcerts -nokeys
Enter Import Password:
使用 openssl x509 -noout -text -in newfile.crt.pem查看一下剛才導(dǎo)出的pem證書
root@LAPTOP-1KRDI4T2:/mnt/c/Users/liang/PycharmProjects/demo# openssl x509 -noout -text -in newfile.crt.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 7969397651085804113 (0x6e98fcf0a2cd4251)
Signature Algorithm: sha1WithRSAEncryption
.............
2. python pyopenssl
這種不如第一種簡便,代碼如下
import OpenSSL
from OpenSSL import crypto
# open it, using password. Supply/read your own from stdin.
p12 = crypto.load_pkcs12(open("cert.p12", 'rb').read(), b"passwd")
# get various properties of said file.
# note these are PyOpenSSL objects, not strings although you
# can convert them to PEM-encoded strings.
print(p12.get_certificate()) # (獲取證書
print(p12.get_privatekey()) # 獲取私鑰
print(p12.get_ca_certificates()) # 查看ca chain
public_key = OpenSSL.crypto.dump_publickey(??? OpenSSL.crypto.FILETYPE_PEM,??? p12.get_certificate().get_pubkey())
privatekey = crypto.dump_privatekey(crypto.FILETYPE_PEM,
p12.get_privatekey())
2. 對郵件體進(jìn)行S/MIME加密
郵件部分正常生成即可。只需要在smtpObj.sendmail(sender, receivers, msg)處處理即可。在這里我們使用smime庫來完成工作
1. 安裝smime庫
pip install smime
2. 打開剛才轉(zhuǎn)換的pem證書文件(公鑰
with open("newfile.crt.pem", "rb") as f
3. 調(diào)用encrypt加密
smtpObj.sendmail(sender, receivers, smime.encrypt(msg.as_string(), f.read()))
完整代碼如下
with open("newfile.crt.pem", "rb") as f:
print(smime.encrypt(msg.as_string(), f.read()))
smtpObj.sendmail(sender, receivers, smime.encrypt(msg.as_string(),
f.read()))
print("郵件發(fā)送成功")
3. 對郵件進(jìn)行S/MIME簽名
在這里我們需要使用M2Crypt庫完成工作,當(dāng)然M2Crypt也可以對郵件加密,驗(yàn)證等,但是安裝過于繁瑣,故未經(jīng)測試,且我們不需要對郵件簽名
from M2Crypto import BIO, Rand, SMIME
def makebuf(text):
return BIO.MemoryBuffer(text)
# Make a MemoryBuffer of the message.
buf = makebuf('a sign of our times')
# Seed the PRNG.
Rand.load_file('randpool.dat', -1)
# Instantiate an SMIME object; set it up; sign the buffer.
s = SMIME.SMIME()
s.load_key('signer_key.pem', 'signer.pem')
p7 = s.sign(buf)
p7 now contains a PKCS #7 signature blob wrapped in an M2Crypto.SMIME.PKCS7 object. Note that buf has been consumed by sign() and has to be recreated if it is to be used again.
We may now send the signed message via SMTP. In these examples, we shall not do so; instead, we'll render the S/MIME output in mail-friendly format, and pretend that our messages are sent and received correctly.
# Recreate buf.
buf = makebuf('a sign of our times')
# Output p7 in mail-friendly format.
out = BIO.MemoryBuffer()
out.write('From: sender@example.dom
')
out.write('To: recipient@example.dom
')
out.write('Subject: M2Crypto S/MIME testing
')
s.write(out, p7, buf)
print out.read()
# Save the PRNG's state.
Rand.save_file('randpool.dat')
參考
https://tools.ietf.org/doc/python-m2crypto/howto.smime.html
https://stackoverflow.com/questions/15144046/converting-pkcs12-certificate-into-pem-using-openssl
https://stackoverflow.com/questions/6345786/python-reading-a-pkcs12-certificate-with-pyopenssl-crypto
https://stackoverflow.com/questions/15144046/converting-pkcs12-certificate-into-pem-using-openssl
https://blog.freessl.cn/how-to-use-smime-with-email/
https://pypi.org/project/smime/
總結(jié)
以上是生活随笔為你收集整理的python使用p12个人证书发送S/MIME加密,签名邮件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: goods.java_javaweb网上
- 下一篇: 初识Windows窗体(包括各种控件,属