From 254ba4b0bb790c5fd8c277ec3076a4a577df98e8 Mon Sep 17 00:00:00 2001 From: Erik Osheim Date: Thu, 21 May 2009 10:24:29 -0400 Subject: [PATCH] refactor aes.py, aes-buffer to use pycrypto --HG-- branch : pmacs2 --- aes.py | 133 +++++++++------------------------------------ application.py | 6 +- buffer/__init__.py | 27 +++++---- buffer/aes.py | 13 +++++ 4 files changed, 56 insertions(+), 123 deletions(-) mode change 100755 => 100644 aes.py create mode 100644 buffer/aes.py diff --git a/aes.py b/aes.py old mode 100755 new mode 100644 index 8f46153..67a3316 --- a/aes.py +++ b/aes.py @@ -1,112 +1,29 @@ -#!/usr/bin/python -# -# by Erik Osheim -import os -from subprocess import Popen, PIPE +import Crypto.Hash.SHA256 +import Crypto.Cipher.AES -class Cipher(object): - '''Cipher represents a particular hashing strategy (password, seed, and type). Cipher can encrypt or decrypt data.''' - def __init__(self, password, seed='aes.py', hashtype='rmd160'): +class Crypter(object): + ALIGNMENT = 16 + def __init__(self, password, salt='aes.py'): 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) + self.salt = salt + self.hash = Crypto.Hash.SHA256.new(password + salt) + self.cipher = Crypto.Cipher.AES.new(self.hash.digest()) -def _check_aespipe(): - '''This function checks if we have the "aespipe" binary in $PATH''' - 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() - args = ["aespipe", "-S", seed, "-H", hashtype, "-p", "0"] - p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) - (stdout, stdin, stderr) = (p.stdout, p.stdin, p.stderr) - 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() - args = ["aespipe", "-d", "-S", seed, "-H", hashtype, "-p", "0"] - p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) - (stdout, stdin, stderr) = (p.stdout, p.stdin, p.stderr) - 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 + def pad(self, s): + xtra = len(s) % self.ALIGNMENT + if xtra: + return s + '\x00' * (self.ALIGNMENT - xtra) 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 + return s + + def unpad(self, s): + l = len(s) + while l > 0 and s[l - 1] == '\x00': + l -= 1 + return s[:l] + + def encrypt(self, data): + return self.cipher.encrypt(self.pad(data)) + + def decrypt(self, data): + return self.unpad(self.cipher.decrypt(self.pad(data))) diff --git a/application.py b/application.py index 11cb700..d322794 100755 --- a/application.py +++ b/application.py @@ -5,7 +5,7 @@ import traceback from subprocess import Popen, PIPE, STDOUT import buffer, buffer.about, buffer.color, buffer.console, buffer.data -import buffer.fs +import buffer.fs, buffer.aes import bufferlist, color, completer, ispell, keyinput, method, minibuffer import mode, util, window from point import Point @@ -369,7 +369,7 @@ class Application(object): if not password: raise Exception, "password is required" if not os.path.exists(path) or os.path.isfile(path): - b = buffer.AesBuffer(path, password, name=name) + b = buffer.aes.AesBuffer(path, password, name=name) else: raise Exception, "not a file or dir: %r" % path try: @@ -1014,7 +1014,7 @@ class Application(object): def open_aes_file(path, name=None, binary=False): if os.path.isfile(path) or not os.path.exists(path): p = getpass.getpass("Please enter the AES password: ") - return buffer.AesBuffer(path, p, name) + return buffer.aes.AesBuffer(path, p, name) else: raise Exception, "can't open %r; unsupported file type" % path def open_plain_file(path, name=None, binary=False): diff --git a/buffer/__init__.py b/buffer/__init__.py index 3aa3e2b..a9ff49c 100644 --- a/buffer/__init__.py +++ b/buffer/__init__.py @@ -1,7 +1,8 @@ from util import defaultdict import codecs, datetime, grp, os, pwd, re, shutil, stat, string import fcntl, select, pty, threading -import aes, dirutil, regex, highlight, lex, term +#import aes, dirutil, regex, highlight, lex, term +import dirutil, regex, highlight, lex, term from point import Point from subprocess import Popen, PIPE, STDOUT from keyinput import MAP @@ -665,6 +666,7 @@ class FileBuffer(Buffer): temp_path = self._temp_path() shutil.copyfile(self.path, temp_path) + try: data = self.make_string() if self.windows[0].mode.savetabs: @@ -674,8 +676,9 @@ class FileBuffer(Buffer): f2 = self._open_file_w(self.path, preserve=False) f2.write(self.bytemark + data) f2.close() - except: + except Exception, e: if exists: shutil.copyfile(temp_path, self.path) + raise e else: self.store_checksum(data) self.modified = False @@ -684,16 +687,16 @@ class FileBuffer(Buffer): self.path = path self.save() -class AesBuffer(FileBuffer): - btype = 'aesfile' - def __init__(self, path, password, name=None): - '''fb = FileBuffer(path)''' - FileBuffer.__init__(self, path, name) - self.password = password - def read_filter(self, data): - return aes.decrypt_data(data, self.password) - def write_filter(self, data): - return aes.encrypt_data(data, self.password) +#class AesBuffer(FileBuffer): +# btype = 'aesfile' +# def __init__(self, path, password, name=None): +# '''fb = FileBuffer(path)''' +# FileBuffer.__init__(self, path, name) +# self.password = password +# def read_filter(self, data): +# return aes.decrypt_data(data, self.password) +# def write_filter(self, data): +# return aes.encrypt_data(data, self.password) class Binary32Buffer(FileBuffer): btype = 'bin32file' diff --git a/buffer/aes.py b/buffer/aes.py new file mode 100644 index 0000000..e0b60cb --- /dev/null +++ b/buffer/aes.py @@ -0,0 +1,13 @@ +import aes +from buffer import FileBuffer + +class AesBuffer(FileBuffer): + btype = 'aesfile' + def __init__(self, path, password, name=None): + '''ab = AesBuffer(path, password)''' + FileBuffer.__init__(self, path, name) + self.crypter = aes2.Crypter(password) + def read_filter(self, data): + return self.crypter.decrypt(data) + def write_filter(self, data): + return self.crypter.encrypt(data)