diff options
author | Yesudeep Mangalapilly <yesudeep@gmail.com> | 2011-08-11 02:38:13 +0530 |
---|---|---|
committer | Yesudeep Mangalapilly <yesudeep@gmail.com> | 2011-08-11 02:38:13 +0530 |
commit | e97d0d730367ad3b49efc712c01509500939c904 (patch) | |
tree | d780c2c3d49075c3c26ce587c17e5b1c9921f5b0 | |
parent | aed6e8657bc316ccd6964a33c04bd650e9951ae2 (diff) | |
download | rsa-git-e97d0d730367ad3b49efc712c01509500939c904.tar.gz |
Porting to Python 3 complete. All tests except pyasn1 stuff pass.
-rw-r--r-- | rsa/_version133.py | 4 | ||||
-rw-r--r-- | rsa/_version200.py | 13 | ||||
-rw-r--r-- | rsa/bigfile.py | 3 | ||||
-rw-r--r-- | rsa/core.py | 5 | ||||
-rw-r--r-- | rsa/key.py | 5 | ||||
-rw-r--r-- | rsa/pem.py | 21 | ||||
-rw-r--r-- | rsa/pkcs1.py | 35 | ||||
-rw-r--r-- | rsa/randnum.py | 3 | ||||
-rw-r--r-- | rsa/transform.py | 22 | ||||
-rw-r--r-- | rsa/varblock.py | 3 | ||||
-rw-r--r-- | tests/test_bigfile.py | 19 | ||||
-rw-r--r-- | tests/test_load_save_keys.py | 8 | ||||
-rw-r--r-- | tests/test_pkcs1.py | 20 |
13 files changed, 94 insertions, 67 deletions
diff --git a/rsa/_version133.py b/rsa/_version133.py index 1adae42..230a03c 100644 --- a/rsa/_version133.py +++ b/rsa/_version133.py @@ -27,6 +27,8 @@ import sys import types import zlib +from rsa._compat import byte + # Display a warning that this insecure version is imported. import warnings warnings.warn('Insecure version of the RSA module is imported as %s, be careful' @@ -78,7 +80,7 @@ def int2bytes(number): string = "" while number > 0: - string = "%s%s" % (chr(number & 0xFF), string) + string = "%s%s" % (byte(number & 0xFF), string) number /= 256 return string diff --git a/rsa/_version200.py b/rsa/_version200.py index c297aee..8e3f452 100644 --- a/rsa/_version200.py +++ b/rsa/_version200.py @@ -18,6 +18,7 @@ import os import random import sys import types +from rsa._compat import byte # Display a warning that this insecure version is imported. import warnings @@ -78,7 +79,7 @@ def int2bytes(number): string = "" while number > 0: - string = "%s%s" % (chr(number & 0xFF), string) + string = "%s%s" % (byte(number & 0xFF), string) number /= 256 return string @@ -95,19 +96,19 @@ def to64(number): raise TypeError("You must pass a long or an int") if 0 <= number <= 9: #00-09 translates to '0' - '9' - return chr(number + 48) + return byte(number + 48) if 10 <= number <= 35: - return chr(number + 55) #10-35 translates to 'A' - 'Z' + return byte(number + 55) #10-35 translates to 'A' - 'Z' if 36 <= number <= 61: - return chr(number + 61) #36-61 translates to 'a' - 'z' + return byte(number + 61) #36-61 translates to 'a' - 'z' if number == 62: # 62 translates to '-' (minus) - return chr(45) + return byte(45) if number == 63: # 63 translates to '_' (underscore) - return chr(95) + return byte(95) raise ValueError(u'Invalid Base64 value: %i' % number) diff --git a/rsa/bigfile.py b/rsa/bigfile.py index f930944..26063f1 100644 --- a/rsa/bigfile.py +++ b/rsa/bigfile.py @@ -39,6 +39,7 @@ used to denote the block sizes. ''' from rsa import key, common, pkcs1, varblock +from rsa._compat import byte def encrypt_bigfile(infile, outfile, pub_key): '''Encrypts a file, writing it to 'outfile' in VARBLOCK format. @@ -56,7 +57,7 @@ def encrypt_bigfile(infile, outfile, pub_key): blocksize = key_bytes - 11 # keep space for PKCS#1 padding # Write the version number to the VARBLOCK file - outfile.write(chr(varblock.VARBLOCK_VERSION)) + outfile.write(byte(varblock.VARBLOCK_VERSION)) # Encrypt and write each block for block in varblock.yield_fixedblocks(infile, blocksize): diff --git a/rsa/core.py b/rsa/core.py index d984b89..fbc108a 100644 --- a/rsa/core.py +++ b/rsa/core.py @@ -19,11 +19,12 @@ This is the actual core RSA implementation, which is only defined mathematically on integers. ''' -import types + +from rsa._compat import is_integer def assert_int(var, name): - if type(var) in (types.IntType, types.LongType): + if is_integer(var): return raise TypeError('%s should be an integer, not %s' % (name, var.__class__)) @@ -26,6 +26,7 @@ of pyasn1. ''' import logging +from rsa._compat import b import rsa.prime import rsa.pem @@ -386,7 +387,7 @@ class PrivateKey(AbstractKey): @return: a PrivateKey object ''' - der = rsa.pem.load_pem(keyfile, 'RSA PRIVATE KEY') + der = rsa.pem.load_pem(keyfile, b('RSA PRIVATE KEY')) return cls._load_pkcs1_der(der) def _save_pkcs1_pem(self): @@ -396,7 +397,7 @@ class PrivateKey(AbstractKey): ''' der = self._save_pkcs1_der() - return rsa.pem.save_pem(der, 'RSA PRIVATE KEY') + return rsa.pem.save_pem(der, b('RSA PRIVATE KEY')) def find_p_q(nbits, getprime_func=rsa.prime.getprime, accurate=True): ''''Returns a tuple of two different primes of nbits bits each. @@ -17,6 +17,7 @@ '''Functions that load and write PEM-encoded files.''' import base64 +from rsa._compat import b, is_bytes def _markers(pem_marker): '''Returns the start and end PEM markers @@ -26,8 +27,11 @@ def _markers(pem_marker): ''' - return ('-----BEGIN %s-----' % pem_marker, - '-----END %s-----' % pem_marker) + if is_bytes(pem_marker): + pem_marker = pem_marker.decode('utf-8') + + return (b('-----BEGIN %s-----' % pem_marker), + b('-----END %s-----' % pem_marker)) def load_pem(contents, pem_marker): '''Loads a PEM file. @@ -49,7 +53,7 @@ def load_pem(contents, pem_marker): pem_lines = [] in_pem_part = False - for line in contents.split('\n'): + for line in contents.splitlines(): line = line.strip() # Skip empty lines @@ -74,7 +78,7 @@ def load_pem(contents, pem_marker): break # Load fields - if ':' in line: + if b(':') in line: continue pem_lines.append(line) @@ -87,9 +91,10 @@ def load_pem(contents, pem_marker): raise ValueError('No PEM end marker "%s" found' % pem_end) # Base64-decode the contents - pem = ''.join(pem_lines) + pem = b('').join(pem_lines) return base64.decodestring(pem) + def save_pem(contents, pem_marker): '''Saves a PEM file. @@ -104,7 +109,7 @@ def save_pem(contents, pem_marker): (pem_start, pem_end) = _markers(pem_marker) - b64 = base64.encodestring(contents).replace('\n', '') + b64 = base64.encodestring(contents).replace(b('\n'), b('')) pem_lines = [pem_start] for block_start in range(0, len(b64), 64): @@ -112,7 +117,7 @@ def save_pem(contents, pem_marker): pem_lines.append(block) pem_lines.append(pem_end) - pem_lines.append('') + pem_lines.append(b('')) - return '\n'.join(pem_lines) + return b('\n').join(pem_lines) diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py index 9686cf9..8c6d290 100644 --- a/rsa/pkcs1.py +++ b/rsa/pkcs1.py @@ -31,15 +31,16 @@ SUCH INFORMATION to your users. import hashlib import os +from rsa._compat import b from rsa import common, transform, core, varblock # ASN.1 codes that describe the hash algorithm used. HASH_ASN1 = { - 'MD5': '\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10', - 'SHA-1': '\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14', - 'SHA-256': '\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20', - 'SHA-384': '\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30', - 'SHA-512': '\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40', + 'MD5': b('\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10'), + 'SHA-1': b('\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'), + 'SHA-256': b('\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'), + 'SHA-384': b('\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30'), + 'SHA-512': b('\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40'), } HASH_METHODS = { @@ -82,7 +83,7 @@ def _pad_for_encryption(message, target_length): ' space for %i' % (msglength, max_msglength)) # Get random padding - padding = '' + padding = b('') padding_length = target_length - msglength - 3 # We remove 0-bytes, so we'll end up with less padding than we've asked for, @@ -94,14 +95,14 @@ def _pad_for_encryption(message, target_length): # after removing the 0-bytes. This increases the chance of getting # enough bytes, especially when needed_bytes is small new_padding = os.urandom(needed_bytes + 5) - new_padding = new_padding.replace('\x00', '') + new_padding = new_padding.replace(b('\x00'), b('')) padding = padding + new_padding[:needed_bytes] assert len(padding) == padding_length - return ''.join(['\x00\x02', + return b('').join([b('\x00\x02'), padding, - '\x00', + b('\x00'), message]) @@ -133,9 +134,9 @@ def _pad_for_signing(message, target_length): padding_length = target_length - msglength - 3 - return ''.join(['\x00\x01', - padding_length * '\xff', - '\x00', + return b('').join([b('\x00\x01'), + padding_length * b('\xff'), + b('\x00'), message]) @@ -227,12 +228,12 @@ def decrypt(crypto, priv_key): cleartext = transform.int2bytes(decrypted, blocksize) # If we can't find the cleartext marker, decryption failed. - if cleartext[0:2] != '\x00\x02': + if cleartext[0:2] != b('\x00\x02'): raise DecryptionError('Decryption failed') # Find the 00 separator between the padding and the message try: - sep_idx = cleartext.index('\x00', 2) + sep_idx = cleartext.index(b('\x00'), 2) except ValueError: raise DecryptionError('Decryption failed') @@ -303,12 +304,12 @@ def verify(message, signature, pub_key): clearsig = transform.int2bytes(decrypted, blocksize) # If we can't find the signature marker, verification failed. - if clearsig[0:2] != '\x00\x01': + if clearsig[0:2] != b('\x00\x01'): raise VerificationError('Verification failed') # Find the 00 separator between the padding and the payload try: - sep_idx = clearsig.index('\x00', 2) + sep_idx = clearsig.index(b('\x00'), 2) except ValueError: raise VerificationError('Verification failed') @@ -361,7 +362,7 @@ def _find_method_hash(method_hash): ''' - for (hashname, asn1code) in HASH_ASN1.iteritems(): + for (hashname, asn1code) in HASH_ASN1.items(): if not method_hash.startswith(asn1code): continue diff --git a/rsa/randnum.py b/rsa/randnum.py index a6a635b..275da0f 100644 --- a/rsa/randnum.py +++ b/rsa/randnum.py @@ -21,6 +21,7 @@ import os from rsa import common, transform +from rsa._compat import byte def read_random_bits(nbits): '''Reads 'nbits' random bits. @@ -38,7 +39,7 @@ def read_random_bits(nbits): if rbits > 0: randomvalue = ord(os.urandom(1)) randomvalue >>= (8 - rbits) - randomdata = chr(randomvalue) + randomdata + randomdata = byte(randomvalue) + randomdata return randomdata diff --git a/rsa/transform.py b/rsa/transform.py index 2778729..57629ec 100644 --- a/rsa/transform.py +++ b/rsa/transform.py @@ -19,12 +19,13 @@ From bytes to a number, number to bytes, etc. ''' -import types import binascii from rsa import common +from rsa._compat import byte, is_integer, b -def bytes2int(bytes): + +def bytes2int(raw_bytes): r"""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. @@ -36,7 +37,8 @@ def bytes2int(bytes): """ - return int(binascii.hexlify(bytes), 16) + return int(binascii.hexlify(raw_bytes), 16) + def int2bytes(number, block_size=None): r'''Converts a number to a string of bytes. @@ -68,9 +70,9 @@ def int2bytes(number, block_size=None): ''' # Type checking - if type(number) not in (types.LongType, types.IntType): + if not is_integer(number): raise TypeError("You must pass an integer for 'number', not %s" % - number.__class__) + type(number).__name__) if number < 0: raise ValueError('Negative numbers cannot be used: %i' % number) @@ -83,18 +85,18 @@ def int2bytes(number, block_size=None): 'is %i' % (needed_bytes, block_size)) # Convert the number to bytes. - bytes = [] + raw_bytes = [] while number > 0: - bytes.insert(0, chr(number & 0xFF)) + raw_bytes.insert(0, byte(number & 0xFF)) number >>= 8 # Pad with zeroes to fill the block if block_size is not None: - padding = (block_size - needed_bytes) * '\x00' + padding = (block_size - needed_bytes) * b('\x00') else: - padding = '' + padding = b('') - return padding + ''.join(bytes) + return padding + b('').join(raw_bytes) if __name__ == '__main__': diff --git a/rsa/varblock.py b/rsa/varblock.py index b8bd899..51e04fc 100644 --- a/rsa/varblock.py +++ b/rsa/varblock.py @@ -31,6 +31,7 @@ This file format is called the VARBLOCK format, in line with the varint format used to denote the block sizes. ''' +from rsa._compat import byte VARBLOCK_VERSION = 1 @@ -88,7 +89,7 @@ def write_varint(outfile, value): if value > 0: to_write |= 0x80 - outfile.write(chr(to_write)) + outfile.write(byte(to_write)) written_bytes += 1 return written_bytes diff --git a/tests/test_bigfile.py b/tests/test_bigfile.py index 02e052e..974da8b 100644 --- a/tests/test_bigfile.py +++ b/tests/test_bigfile.py @@ -1,9 +1,10 @@ '''Tests block operations.''' +from rsa._compat import b try: - from StringIO import StringIO + from StringIO import StringIO as BytesIO except ImportError: - from io import StringIO + from io import BytesIO import unittest2 import rsa @@ -17,17 +18,17 @@ class BigfileTest(unittest2.TestCase): pub_key, priv_key = rsa.newkeys((6 + 11) * 8) # Encrypt the file - message = '123456Sybren' - infile = StringIO(message) - outfile = StringIO() + message = b('123456Sybren') + infile = BytesIO(message) + outfile = BytesIO() bigfile.encrypt_bigfile(infile, outfile, pub_key) # Test crypto = outfile.getvalue() - cryptfile = StringIO(crypto) - clearfile = StringIO() + cryptfile = BytesIO(crypto) + clearfile = BytesIO() bigfile.decrypt_bigfile(cryptfile, clearfile, priv_key) self.assertEquals(clearfile.getvalue(), message) @@ -45,7 +46,7 @@ class BigfileTest(unittest2.TestCase): pub_key, priv_key = rsa.newkeys((34 + 11) * 8) # Sign the file - msgfile = StringIO('123456Sybren') + msgfile = BytesIO(b('123456Sybren')) signature = pkcs1.sign(msgfile, priv_key, 'MD5') # Check the signature @@ -53,7 +54,7 @@ class BigfileTest(unittest2.TestCase): pkcs1.verify(msgfile, signature, pub_key) # Alter the message, re-check - msgfile = StringIO('123456sybren') + msgfile = BytesIO(b('123456sybren')) self.assertRaises(pkcs1.VerificationError, pkcs1.verify, msgfile, signature, pub_key) diff --git a/tests/test_load_save_keys.py b/tests/test_load_save_keys.py index fabe92f..fc1a1aa 100644 --- a/tests/test_load_save_keys.py +++ b/tests/test_load_save_keys.py @@ -24,13 +24,13 @@ Comment: something blah Stuff after the key -----END CONFUSING STUFF----- -''' % B64PRIV_DER) +''' % B64PRIV_DER.decode("utf-8")) CLEAN_PRIVATE_PEM = b('''\ -----BEGIN RSA PRIVATE KEY----- %s -----END RSA PRIVATE KEY----- -''' % B64PRIV_DER) +''' % B64PRIV_DER.decode("utf-8")) PUBLIC_PEM = b(''' -----BEGIN CONFUSING STUFF----- @@ -44,13 +44,13 @@ Comment: something blah Stuff after the key -----END CONFUSING STUFF----- -''' % B64PUB_DER) +''' % B64PUB_DER.decode("utf-8")) CLEAN_PUBLIC_PEM = b('''\ -----BEGIN RSA PUBLIC KEY----- %s -----END RSA PUBLIC KEY----- -''' % B64PUB_DER) +''' % B64PUB_DER.decode("utf-8")) class DerTest(unittest2.TestCase): diff --git a/tests/test_pkcs1.py b/tests/test_pkcs1.py index d8fb1b4..82a3775 100644 --- a/tests/test_pkcs1.py +++ b/tests/test_pkcs1.py @@ -5,6 +5,7 @@ import unittest2 import rsa from rsa import pkcs1 +from rsa._compat import byte, is_integer, b, is_bytes class BinaryTest(unittest2.TestCase): @@ -29,8 +30,17 @@ class BinaryTest(unittest2.TestCase): message = struct.pack('>IIII', 0, 0, 0, 1) encrypted = pkcs1.encrypt(message, self.pub) + def _ord(a): + if is_integer(a): + return a + else: + return ord(a) + # Alter the encrypted stream - encrypted = encrypted[:5] + chr(ord(encrypted[5]) + 1) + encrypted[6:] + a = encrypted[5] + if is_bytes(a): + a = ord(a) + encrypted = encrypted[:5] + byte(a + 1) + encrypted[6:] self.assertRaises(pkcs1.DecryptionError, pkcs1.decrypt, encrypted, self.priv) @@ -54,7 +64,7 @@ class SignatureTest(unittest2.TestCase): def test_sign_verify(self): '''Test happy flow of sign and verify''' - message = 'je moeder' + message = b('je moeder') print("\tMessage: %r" % message) signature = pkcs1.sign(message, self.priv, 'SHA-256') @@ -65,16 +75,16 @@ class SignatureTest(unittest2.TestCase): def test_alter_message(self): '''Altering the message should let the verification fail.''' - signature = pkcs1.sign('je moeder', self.priv, 'SHA-256') + signature = pkcs1.sign(b('je moeder'), self.priv, 'SHA-256') self.assertRaises(pkcs1.VerificationError, pkcs1.verify, - 'mijn moeder', signature, self.pub) + b('mijn moeder'), signature, self.pub) def test_sign_different_key(self): '''Signing with another key should let the verification fail.''' (otherpub, _) = rsa.newkeys(512) - message = 'je moeder' + message = b('je moeder') signature = pkcs1.sign(message, self.priv, 'SHA-256') self.assertRaises(pkcs1.VerificationError, pkcs1.verify, message, signature, otherpub) |