I'm using pycrypto's AES module, and am attempting to automate the padding of the plaintext (the size of the text to be encrypted must be a multiple of 16). However, my padding scheme sometimes fails to calculate the necessary padding correctly, and I'm not sure why.
Using the text 'foo bar', it fails, but if I do 'foo bars' it works. Randomized testing fails sometimes and not others. Any pointers as to what I might be doing wrong (code attached)? -davidc -- gpg-key: http://www.zettazebra.com/files/key.gpg
from Crypto import Hash, Cipher from Crypto.Cipher import AES from Crypto.Hash import SHA256 class EncryptedText: """A class to hide the details of encryption and decryption""" def __init__(self, text, key_phrase): key = SHA256.new(key_phrase) self.aes = AES.new(key.digest()) #self.encrypted_text = self.aes.encrypt(self._pad(text)) def _unpad(self, txt): """Remove padding from the given text""" for x in xrange(len(txt) - self.aes.block_size,len(txt)): if x == ord(txt[x]): if txt[x-1:] + self._gen_pad(txt[x-1:]): return txt[:x] return txt def _pad(self, txt): """Pad the given plaintext""" return txt + self._gen_pad(txt) def _gen_pad(self, txt): """Generate padding for the given plaintext""" pad_len = (len(txt)) % self.aes.block_size if pad_len > 0: return chr(pad_len) * pad_len return chr(self.aes.block_size) * self.aes.block_size def __repr__(self): return self.encrypted_text ## testing ## if __name__ == "__main__": import sys import random randomize = True text = 'foo bars' # if available, only test the text supplied by the user if len(sys.argv) > 1: randomize = False text = sys.argv[1] print 'plaintext: "%s"' % (text,) r = random.Random() cycles = 1 # pick a random number of test cycles if randomize: cycles = r.randrange(20) for testcycle in xrange(0, cycles): try: # generate a plaintext of random length and content if randomize: print print 'Test #%i' % testcycle text='' for x in xrange(0, r.randrange(1000)): text += chr(r.randrange(256)) # check to see if padding & unpadding yield appropriate results e = EncryptedText(text, 'blah') bs = e.aes.block_size p = e._pad(text) pd = SHA256.new(p).hexdigest() unp = e._unpad(p) unpd = SHA256.new(unp).hexdigest() print 'cipher block size: %i' % (bs,) print 'padded: "%s"' % (p,) print 'padded len: "%i"' % (len(p),) print 'unpadded: "%s"' % (unp,) print 'unpadded len: "%i"' % (len(unp),) print # ensure that original an unpadded text match, and that padded # text is completely divisible by the cipher block size if SHA256.new(text).digest() == SHA256.new(unp).digest() and \ len(p) % bs == 0: print "Test succeeded." else: print "Unpadded text does not match original plaintext, or " print "padded text is not divisible by the cipher block size: " print "Test failed." except Exception, e: print "Program error: " print "Test failed." print e
signature.asc
Description: This is a digitally signed message part
-- http://mail.python.org/mailman/listinfo/python-list