summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rsa/_version133.py4
-rw-r--r--rsa/_version200.py13
-rw-r--r--rsa/bigfile.py3
-rw-r--r--rsa/core.py5
-rw-r--r--rsa/key.py5
-rw-r--r--rsa/pem.py21
-rw-r--r--rsa/pkcs1.py35
-rw-r--r--rsa/randnum.py3
-rw-r--r--rsa/transform.py22
-rw-r--r--rsa/varblock.py3
-rw-r--r--tests/test_bigfile.py19
-rw-r--r--tests/test_load_save_keys.py8
-rw-r--r--tests/test_pkcs1.py20
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__))
diff --git a/rsa/key.py b/rsa/key.py
index 17bf69e..facde8e 100644
--- a/rsa/key.py
+++ b/rsa/key.py
@@ -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.
diff --git a/rsa/pem.py b/rsa/pem.py
index 9ea9f03..0875ec3 100644
--- a/rsa/pem.py
+++ b/rsa/pem.py
@@ -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)