Below is the file 'addrhash.py' from this revision. You can also download the file.

#!/usr/bin/env python2.4

from Crypto.Hash import SHA256, HMAC
from Crypto.Cipher import AES
import sys
import config
import socket
import base64

def get_cipher():
    sha = SHA256.new()
    sha.update(config.aes_key)
    return AES.new(sha.digest())

def our_pton(ip_string):
    try:
        return verification_value() + socket.inet_pton(socket.AF_INET, ip_string)
    except socket.error:
        pass

def our_ntop(encoded):
    return socket.inet_ntop(socket.AF_INET, encoded)

def mac_value(val):
    m = HMAC.new(config.mac_key)
    m.update(val)
    return m.digest()[:12]

def wrap_with_hmac(val):
    return mac_value(val) + val

def strip_hmac_and_verify(val):
    their_mac, val = val[:12], val[12:]
    if their_mac != mac_value(val):
        raise Exception("HMAC does not verify!")
    return val

def encode(ip_string):
    enc = wrap_with_hmac(socket.inet_pton(socket.AF_INET, ip_string))
    enc = get_cipher().encrypt(enc)
    return base64.encodestring(enc).rstrip('\n').rstrip('==')

def decode(email_address):
    bytes = base64.decodestring(email_address + '==\n')
    if len(bytes) != 16:
        raise Exception("This is not a valid email address.")
    decoded = get_cipher().decrypt(bytes)
    decoded = strip_hmac_and_verify(decoded)
    return our_ntop(decoded)

if __name__ == '__main__':
    ops = {'dec' : decode, 'enc' : encode}
    if len(sys.argv) != 3 or not ops.has_key(sys.argv[1]):
        print >>sys.stderr, """\
Usage: %s <enc> <ip_address>
       %s <dec> <email_address>""" % (sys.argv[0], sys.argv[0])
        sys.exit(1)
    print ops[sys.argv[1]](sys.argv[2])