#!/usr/bin/python
#
# by Erik Osheim
import os, popen2

class Cipher:
    def __init__(self, password, seed='aes.py', hashtype='rmd160'):
        self.password = password
        self.seed     = seed
        self.hashtype = hashtype
    def encrypt(self, data):
        return encrypt_data(data, self.password, self.seed, self.hashtype)
    def decrypt(self, encrypted):
        return decrypt_data(encrypted, self.password, self.seed, self.hashtype)

def _check_aespipe():
    result = os.system('which aespipe > /dev/null')
    if result != 0:
        raise Exception, "Could not find aespipe; is it installed?"

def encrypt_data(data, password, seed='aes.py', hashtype='rmd160'):
    '''uses password to encrypt data'''
    _check_aespipe()
    cmd = "aespipe -S '%s' -H '%s' -p 0" % (seed, hashtype)
    (stdout, stdin, stderr) = popen2.popen3(cmd)
    stdin.write(password + '\n')
    stdin.write(data)
    stdin.close()
    encrypted = stdout.read()
    err = stderr.read()
    if err:
        raise Exception, "Problem: %s" % err
    return encrypted

def encrypt_path(path, data, password, seed='aes.py', hashtype='rmd160'):
    '''uses password to encrypt data and writes result to path'''
    encrypted = encrypt_data(data, password, seed, hashtype)
    f = open(path, 'w')
    f.write(encrypted)
    f.close()

def decrypt_data(encrypted, password, seed='aes.py', hashtype='rmd160'):
    '''uses password to decrypt data'''
    _check_aespipe()
    cmd = "aespipe -d -S '%s' -H '%s' -p 0" % (seed, hashtype)
    (stdout, stdin, stderr) = popen2.popen3(cmd)
    stdin.write(password + '\n')
    stdin.write(encrypted)
    stdin.close()
    data = stdout.read()
    err = stderr.read()
    if err:
        raise Exception, "Problem: %s" % err

    # data is null-padded at the end to align on 16 or 512 bytes boundaries
    i = len(data)
    while i > 1:
        if data[i-1] == '\x00':
            i -= 1
        else:
            break
    return data[:i]

def decrypt_path(path, password, seed='aes.py', hashtype='rmd160'):
    '''uses password to decrypt data from path'''
    f = open(path, 'r')
    encrypted = f.read()
    f.close()
    data = decrypt_data(encrypted, password, seed, hashtype)
    return data

if __name__ == "__main__":
    import optparse, sys

    parser = optparse.OptionParser()
    parser.set_defaults(mode='decrypt')
    parser.set_defaults(password='insecure1@3$5^')
    parser.set_defaults(filename='output.aes')

    parser.add_option('-e', dest='mode', action='store_const', const='encrypt',
                      help="perform encryption on data from stdin")
    parser.add_option('-d', dest='mode', action='store_const', const='decrypt',
                      help="perform decryption on data from stdin")
    parser.add_option('-f', dest='filename', action='store', metavar='FILENAME',
                      help="encrypt to/from FILENAME (default: output.aes)")
    parser.add_option('-p', dest='password', action='store', metavar='PASSWORD',
                      default="insecure1@3$5^",
                      help="use password PASSWORD (default: insecure1@3$5^)")

    (opts, args) = parser.parse_args()

    c = Cipher(opts.password)

    if opts.mode == 'encrypt':
        data = sys.stdin.read()
        encrypted = c.encrypt(data)
        f = open(opts.filename, 'w')
        f.write(encrypted)
        f.close()
        print "data written to %r." % opts.filename
    else:
        print "reading data from %r:" % opts.filename
        f = open(opts.filename, 'r')
        encrypted = f.read()
        f.close()
        data = c.decrypt(encrypted)
        print data