Skip to content

Commit 62abca7

Browse files
committed
Added block padding to be able to work with leading zeroes, breaks all kind of stuff
1 parent 0060065 commit 62abca7

4 files changed

Lines changed: 70 additions & 11 deletions

File tree

rsa/__init__.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@ def decode64chops(string):
4242

4343
return chops
4444

45+
def block_size(n):
46+
'''Returns the block size in bytes, given the public key.
47+
48+
The block size is determined by the 'n=p*q' component of the key.
49+
'''
50+
51+
# Set aside 2 bits so setting of safebit won't overflow modulo n.
52+
nbits = rsa.common.bit_size(n) - 2
53+
nbytes = nbits / 8
54+
55+
return nbytes
56+
57+
4558
def chopstring(message, key, n, int_op):
4659
"""Chops the 'message' into integers that fit into n.
4760
@@ -56,13 +69,10 @@ def chopstring(message, key, n, int_op):
5669
Used by 'encrypt' and 'sign'.
5770
"""
5871

59-
msglen = len(message)
60-
mbits = msglen * 8
6172

62-
# Set aside 2 bits so setting of safebit won't overflow modulo n.
63-
nbits = rsa.common.bit_size(n) - 2
73+
nbytes = block_size(n)
6474

65-
nbytes = nbits / 8
75+
msglen = len(message)
6676
blocks = msglen / nbytes
6777

6878
if msglen % nbytes > 0:
@@ -90,14 +100,25 @@ def gluechops(string, key, n, funcref):
90100

91101
messageparts = []
92102
chops = decode64chops(string) #Decode base64 strings into integer chops
103+
104+
nbytes = block_size(n)
93105

94106
for chop in chops:
95107
value = funcref(chop, key, n) #Decrypt each chop
96108
block = rsa.transform.int2bytes(value)
109+
110+
# Pad block with 0-bytes until we have reached the block size
111+
blocksize = len(block)
112+
padsize = nbytes - blocksize
113+
if padsize < 0:
114+
raise ValueError('Block larger than block size (%i > %i)!' %
115+
(blocksize, nbytes))
116+
elif padsize > 0:
117+
block = '\x00' * padsize + block
118+
97119
messageparts.append(block)
98120

99121
# Combine decrypted strings into a msg
100-
101122
return ''.join(messageparts)
102123

103124
def encrypt(message, key):

rsa/transform.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ def bit_size(number):
1212
return int(math.ceil(math.log(number,2)))
1313

1414
def bytes2int(bytes):
15-
"""Converts a list of bytes or a string to an integer
15+
"""Converts a list of bytes or an 8-bit string to an integer.
16+
17+
When using unicode strings, encode it to some encoding like UTF8 first.
1618
1719
>>> (((128 * 256) + 64) * 256) + 15
1820
8405007

tests/test_binary.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'''Tests string operations.'''
2+
3+
import struct
4+
import unittest
5+
6+
import rsa
7+
8+
class BinaryTest(unittest.TestCase):
9+
10+
def setUp(self):
11+
(self.pub, self.priv) = rsa.newkeys(64)
12+
13+
def test_enc_dec(self):
14+
15+
message = struct.pack('>IIII', 0, 0, 0, 1) + 20 * '\x00'
16+
print "\tMessage: %r" % message
17+
18+
encrypted = rsa.encrypt(message, self.pub)
19+
print "\tEncrypted: %r" % encrypted
20+
21+
decrypted = rsa.decrypt(encrypted, self.priv)
22+
print "\tDecrypted: %r" % decrypted
23+
24+
self.assertEqual(message, decrypted)
25+
26+
def test_sign_verify(self):
27+
28+
message = struct.pack('>IIII', 0, 0, 0, 1) + 20 * '\x00'
29+
print "\tMessage: %r" % message
30+
31+
signed = rsa.sign(message, self.priv)
32+
print "\tSigned: %r" % signed
33+
34+
verified = rsa.verify(signed, self.pub)
35+
print "\tVerified: %r" % verified
36+
37+
self.assertEqual(message, verified)

tests/test_strings.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ def setUp(self):
1111

1212
def test_enc_dec(self):
1313

14-
# TODO: test with unicode strings and non-ascii chars
15-
message = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
14+
message = u"Euro=\u20ac ABCDEFGHIJKLMNOPQRSTUVWXYZ".encode('utf-8')
1615
print "\tMessage: %s" % message
1716

1817
encrypted = rsa.encrypt(message, self.pub)
@@ -25,8 +24,8 @@ def test_enc_dec(self):
2524

2625
def test_sign_verify(self):
2726

28-
# TODO: test with unicode strings and non-ascii chars
29-
message = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
27+
message = u"Euro=\u20ac ABCDEFGHIJKLMNOPQRSTUVWXYZ".encode('utf-8')
28+
print "\tMessage: %s" % message
3029

3130
signed = rsa.sign(message, self.priv)
3231
print "\tSigned: %s" % signed

0 commit comments

Comments
 (0)