Re: Crypto plaintext padding (SOLVED)

2007-05-08 Thread David Clymer
On Sun, 2007-05-06 at 11:39 -0400, David Clymer wrote:
> 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)?

Nevermind. After I walked away from it for a bit, the mistake was
obvious. I was using the modulus of the text length by the block size
directly, rather than the block size minus that number:

--- /home/david/Desktop/test.py 2007-05-06 13:38:52.0 -0400
+++ test.py 2007-05-06 13:39:38.0 -0400
@@ -9,12 +9,12 @@
 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))
+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 len(txt[x:]) == ord(txt[x]):
 if txt[x-1:] + self._gen_pad(txt[x-1:]):
 return txt[:x]
 return txt
@@ -25,7 +25,7 @@

 def _gen_pad(self, txt):
 """Generate padding for the given plaintext"""
-pad_len = (len(txt)) % self.aes.block_size
+pad_len = self.aes.block_size - (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

-- 
gpg-key: http://www.zettazebra.com/files/key.gpg


signature.asc
Description: This is a digitally signed message part
-- 
http://mail.python.org/mailman/listinfo/python-list

Crypto plaintext padding

2007-05-08 Thread David Clymer

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