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
