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

Attachment: signature.asc
Description: This is a digitally signed message part

-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to