python使用p12我的证书发送S/MIME加密,签名邮件

背景

部门某招投标信息爬虫由本人负责维护,天天定时爬取数据并经过公司邮箱(smtp)发送给各位大佬。某天公司的邮箱忽然升级为只能使用我的证书加密的邮件才能够发送邮件,因此研究了一下相关技术html

S/MIME加密简介

S/MIME是Secure/Multipurpose Internet Mail Extensions (安全多用途互联网邮件扩展协议)的缩写,是采用PKI技术的用数字证书给邮件主体签名和加密的国际标准协议。1992年,MIME(多用途互联网邮件扩展)协议编撰完成,用于互联网邮件服务器和网关之间通讯。该标准方法支持非ASCII编码的附件格式,意味着你能够发送附件并保证文件能够送达另外一端,可是附件有时会被篡改,没法确保邮件机密性和完整性。1995年,S/MIME(安全/多用途互联网邮件扩展)协议V1版本开发问世,对安全方面的功能进行了扩展,提供数字签名和邮件加密功能,邮件加密用来保护电子邮件的内容,数字签名用于验证发件人身份,防止身份冒用,并保护电子邮件完整性。1998年和1999年相继出台V2/V3版本并提交IETF造成系列RFC国际标准。node

未经S/MIME加密的邮件请求头python

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

通过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

咱们能够看见其中的区别,主要是邮件请求头的改变。下面咱们来实践一下安全

编程

1. p12证书文件

为了对邮件进行S/MIME加密,咱们首先要将p12证书文件转换为PEM证书文件。在这里不须要纠结p12证书文件与pem证书文件的区别,只须要知道SMIM加密或者签名须要pem证书文件服务器

下面咱们来讨论一下如何将p12证书文件转换,共有两种方法。注意,若是p12证书有密码的话,须要知道密码才能够进行下面的转换app

1. openssl

从p12中导出pem证书dom

openssl pkcs12 -in path.p12 -out newfile.crt.pem -clcerts -nokeys测试

从p12中导出私钥编码

openssl pkcs12 -in path.p12 -out newfile.key.pem -nocerts -nodes

运行以下

demo# openssl pkcs12 -in liang_zhibang2020.p12 -out newfile.crt.pem -clcerts -nokeys
Enter Import Password:

使用 openssl x509 -noout -text -in newfile.crt.pem查看一下刚才导出的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. 对邮件体进行S/MIME加密

邮件部分正常生成便可。只须要在smtpObj.sendmail(sender, receivers, msg)到处理便可。在这里咱们使用smime库来完成工做

1. 安装smime库

pip install smime

2. 打开刚才转换的pem证书文件(公钥

with open("newfile.crt.pem", "rb") as f

3. 调用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("邮件发送成功")

3. 对邮件进行S/MIME签名

在这里咱们须要使用M2Crypt库完成工做,固然M2Crypt也能够对邮件加密,验证等,可是安装过于繁琐,故未经测试,且咱们不须要对邮件签名

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\n')
    out.write('To: recipient@example.dom\n')
    out.write('Subject: M2Crypto S/MIME testing\n')
    s.write(out, p7, buf)

    print out.read()

    # Save the PRNG's state.
    Rand.save_file('randpool.dat')

参考

  1. https://tools.ietf.org/doc/python-m2crypto/howto.smime.html
  2. https://stackoverflow.com/questions/15144046/converting-pkcs12-certificate-into-pem-using-openssl
  3. https://stackoverflow.com/questions/6345786/python-reading-a-pkcs12-certificate-with-pyopenssl-crypto
  4. https://stackoverflow.com/questions/15144046/converting-pkcs12-certificate-into-pem-using-openssl
  5. https://blog.freessl.cn/how-to-use-smime-with-email/
  6. https://pypi.org/project/smime/
相关文章
相关标签/搜索