M2Crypto == Python + OpenSSL + SWIG.
M2Crypto makes available to the Python programmer the following:
RSA, DSA, DH, message digests, HMACs, symmetric ciphers
SSL functionality to implement clients and servers
S/MIME
This document is a brief tutorial on using M2Crypto's S/MIME functionality.
S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC 2312] - provides a consistent way to send and receive secure MIME data. Based on the popular Internet MIME standard, S/MIME provides the following cryptographic security services for electronic messaging applications - authentication, message integrity and non-repudiation of origin (using digital signatures) and privacy and data security (using encryption).
S/MIME is built on the PKCS #7 standard. [PKCS7]
S/MIME implemented in Netscape Messenger and Microsoft Outlook.
The Python programmer accesses M2Crypto's S/MIME functionality through the M2Crypto.SMIME.SMIME class. Typically, an SMIME object is instantiated; the object is then set up for the relevant operation (sign, encrypt, decrypt or verify); finally, the operation is invoked on the object.
M2Crypto.SMIME.SMIME makes extensive use of M2Crypto.BIO: M2Crypto.BIO is a Python abstraction of the BIO abstraction in OpenSSL. A commonly used BIO abstraction in M2Crypto is M2Crypto.BIO.MemoryBuffer, which implements a memory-based file-like object, similar to StringIO.
To generate a digital signature, a signer's private key and public key certificate are required; both must be in PEM format, although they need not be in separate files.
Suppose the signer's private key is in signer-key.pem
, his certificate is in
signer-cert.pem
and the message to be signed is the following text string:
"a sign of our times". The following code demonstrates how to generate a signature:
from M2Crypto import BIO, Rand, SMIME, X509 def makebuf(text): return BIO.MemoryBuffer(text) # Make a MemoryBuffer of the message. buf = makebuf('a sign of our times') # Instantiate an SMIME object; set it up; sign the buffer. s = SMIME.SMIME() s.load_key('signer-key.pem', 'signer-cert.pem') p7 = s.sign(buf)
Now p7 contains a PKCS#7 signature blob, wrapped in an SMIME.PKCS7 object. Note that buf has been consumed by sign() and has to be recreated.
Next, we send the signed message via SMTP:
# Recreate buf. buf = makebuf('a sign of our times') # Output p7 in mail-friendly format. out = BIO.MemoryBuffer() out.write('To: ngps@post1.com') out.write('Subject: M2Crypto S/MIME') s.write(out, p7, buf) # Send via SMTP. import smtplib smtp = smtplib.SMTP() smtp.connect('localhost') smtp.sendmail('ngps@post1.com', 'ngps@post1.com', out.read()) smtp.quit()