>>> import rotor
>>> r = rotor.newrotor('pymailcgi') # can be decrypted in new process
>>> r.decrypt('* _\344\011pY') # use "\ascii" escapes for two chars
'spam123'
Our secret module by default simply used rotor to encrypt and did no additional
encoding of its own. It relies on URL encoding when the password is embedded in a
URL parameter and on HTML escaping when the password is embedded in hidden
form fields. For URLs, the following sorts of calls occur:
>>> from secret import encode, decode
>>> x = encode('abc$#<>&+') # CGI scripts do this
>>> x
' \323a\016\317\326\023\0163'
>>> import urllib.parse # urlencode does this
>>> y = urllib.parse.quote_plus(x)
>>> y
'+%d3a%0e%cf%d6%13%0e3'
>>> a = urllib.parse.unquote_plus(y) # cgi.FieldStorage does this
>>> a
' \323a\016\317\326\023\0163'
>>> decode(a) # CGI scripts do this
'abc$#<>&+'
Although rotor itself is not a widely viable option today, these same techniques can be
used with other encryption schemes.
Manual data encryption: PyCrypto
A variety of encryption tools are available in the third-party public domain, including
the popular Python Cryptography Toolkit, also known as PyCrypto. This package adds
built-in modules for private and public key algorithms such as AES, DES, IDEA, and
RSA encryption, provides a Python module for reading and decrypting PGP files, and
much more. Here is an example of using AES encryption, run after installing PyCrypto
on my machine with a Windows self-installer:
>>> from Crypto.Cipher import AES>>> AES.block_size16
>>> mykey = 'pymailcgi'.ljust(16, '-') # key must be 16, 24, or 32 bytes
>>> mykey
'pymailcgi-------'
>>>
>>> password = 'Already got one.' # length must be multiple of 16
>>> aesobj1 = AES.new(mykey, AES.MODE_ECB)
>>> cyphertext = aesobj1.encrypt(password)
>>> cyphertext
'\xfez\x95\xb7\x07_"\xd4\xb6\xe3r\x07g~X]'
>>>
>>> aesobj2 = AES.new(mykey, AES.MODE_ECB)
>>> aesobj2.decrypt(cyphertext)
'Already got one.'
1280 | Chapter 16: The PyMailCGI Server