summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSybren A. St?vel <sybren@stuvel.eu>2011-06-20 01:06:39 +0200
committerSybren A. St?vel <sybren@stuvel.eu>2011-06-20 01:06:39 +0200
commit8fac5909a294f7c2271c3ccfffd93815895e8195 (patch)
tree0cea32fbadc8bab97e509d7f095b5564ae810b0e
parent35212ea3acf09c3483bf64d7fbc4e6cacb346270 (diff)
downloadrsa-8fac5909a294f7c2271c3ccfffd93815895e8195.tar.gz
Added block padding to be able to work with leading zeroes, breaks all kind of stuff
-rwxr-xr-xrsa/__init__.py33
-rw-r--r--rsa/transform.py4
-rw-r--r--tests/test_binary.py37
-rw-r--r--tests/test_strings.py7
4 files changed, 70 insertions, 11 deletions
diff --git a/rsa/__init__.py b/rsa/__init__.py
index d9999ae..7fda4e1 100755
--- a/rsa/__init__.py
+++ b/rsa/__init__.py
@@ -42,6 +42,19 @@ def decode64chops(string):
return chops
+def block_size(n):
+ '''Returns the block size in bytes, given the public key.
+
+ The block size is determined by the 'n=p*q' component of the key.
+ '''
+
+ # Set aside 2 bits so setting of safebit won't overflow modulo n.
+ nbits = rsa.common.bit_size(n) - 2
+ nbytes = nbits / 8
+
+ return nbytes
+
+
def chopstring(message, key, n, int_op):
"""Chops the 'message' into integers that fit into n.
@@ -56,13 +69,10 @@ def chopstring(message, key, n, int_op):
Used by 'encrypt' and 'sign'.
"""
- msglen = len(message)
- mbits = msglen * 8
- # Set aside 2 bits so setting of safebit won't overflow modulo n.
- nbits = rsa.common.bit_size(n) - 2
+ nbytes = block_size(n)
- nbytes = nbits / 8
+ msglen = len(message)
blocks = msglen / nbytes
if msglen % nbytes > 0:
@@ -90,14 +100,25 @@ def gluechops(string, key, n, funcref):
messageparts = []
chops = decode64chops(string) #Decode base64 strings into integer chops
+
+ nbytes = block_size(n)
for chop in chops:
value = funcref(chop, key, n) #Decrypt each chop
block = rsa.transform.int2bytes(value)
+
+ # Pad block with 0-bytes until we have reached the block size
+ blocksize = len(block)
+ padsize = nbytes - blocksize
+ if padsize < 0:
+ raise ValueError('Block larger than block size (%i > %i)!' %
+ (blocksize, nbytes))
+ elif padsize > 0:
+ block = '\x00' * padsize + block
+
messageparts.append(block)
# Combine decrypted strings into a msg
-
return ''.join(messageparts)
def encrypt(message, key):
diff --git a/rsa/transform.py b/rsa/transform.py
index 9cd1ef3..6719dcb 100644
--- a/rsa/transform.py
+++ b/rsa/transform.py
@@ -12,7 +12,9 @@ def bit_size(number):
return int(math.ceil(math.log(number,2)))
def bytes2int(bytes):
- """Converts a list of bytes or a string to an integer
+ """Converts a list of bytes or an 8-bit string to an integer.
+
+ When using unicode strings, encode it to some encoding like UTF8 first.
>>> (((128 * 256) + 64) * 256) + 15
8405007
diff --git a/tests/test_binary.py b/tests/test_binary.py
new file mode 100644
index 0000000..f770b72
--- /dev/null
+++ b/tests/test_binary.py
@@ -0,0 +1,37 @@
+'''Tests string operations.'''
+
+import struct
+import unittest
+
+import rsa
+
+class BinaryTest(unittest.TestCase):
+
+ def setUp(self):
+ (self.pub, self.priv) = rsa.newkeys(64)
+
+ def test_enc_dec(self):
+
+ message = struct.pack('>IIII', 0, 0, 0, 1) + 20 * '\x00'
+ print "\tMessage: %r" % message
+
+ encrypted = rsa.encrypt(message, self.pub)
+ print "\tEncrypted: %r" % encrypted
+
+ decrypted = rsa.decrypt(encrypted, self.priv)
+ print "\tDecrypted: %r" % decrypted
+
+ self.assertEqual(message, decrypted)
+
+ def test_sign_verify(self):
+
+ message = struct.pack('>IIII', 0, 0, 0, 1) + 20 * '\x00'
+ print "\tMessage: %r" % message
+
+ signed = rsa.sign(message, self.priv)
+ print "\tSigned: %r" % signed
+
+ verified = rsa.verify(signed, self.pub)
+ print "\tVerified: %r" % verified
+
+ self.assertEqual(message, verified)
diff --git a/tests/test_strings.py b/tests/test_strings.py
index c5803e4..8baa63d 100644
--- a/tests/test_strings.py
+++ b/tests/test_strings.py
@@ -11,8 +11,7 @@ class StringTest(unittest.TestCase):
def test_enc_dec(self):
- # TODO: test with unicode strings and non-ascii chars
- message = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ message = u"Euro=\u20ac ABCDEFGHIJKLMNOPQRSTUVWXYZ".encode('utf-8')
print "\tMessage: %s" % message
encrypted = rsa.encrypt(message, self.pub)
@@ -25,8 +24,8 @@ class StringTest(unittest.TestCase):
def test_sign_verify(self):
- # TODO: test with unicode strings and non-ascii chars
- message = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ message = u"Euro=\u20ac ABCDEFGHIJKLMNOPQRSTUVWXYZ".encode('utf-8')
+ print "\tMessage: %s" % message
signed = rsa.sign(message, self.priv)
print "\tSigned: %s" % signed