summaryrefslogtreecommitdiff
path: root/rsa
diff options
context:
space:
mode:
authorSybren A. Stüvel <sybren@stuvel.eu>2019-08-04 15:02:20 +0200
committerSybren A. Stüvel <sybren@stuvel.eu>2019-08-04 17:05:58 +0200
commitded036cf988b0cf4b20002d88434282f30762638 (patch)
treed927a9732226093ffcdf7400808ae45f5b9e6c37 /rsa
parent65a81053d596c62ad2532c7e0e38e68ef61304bd (diff)
downloadrsa-git-ded036cf988b0cf4b20002d88434282f30762638.tar.gz
Removed compatibility code for Python 2.7 and 3.4
Diffstat (limited to 'rsa')
-rw-r--r--rsa/_compat.py109
-rw-r--r--rsa/cli.py6
-rw-r--r--rsa/common.py2
-rw-r--r--rsa/core.py4
-rw-r--r--rsa/key.py1
-rw-r--r--rsa/machine_size.py74
-rw-r--r--rsa/parallel.py3
-rw-r--r--rsa/pem.py6
-rw-r--r--rsa/pkcs1.py1
-rw-r--r--rsa/pkcs1_v2.py1
-rw-r--r--rsa/prime.py1
-rw-r--r--rsa/randnum.py4
-rw-r--r--rsa/transform.py165
-rw-r--r--rsa/util.py2
14 files changed, 20 insertions, 359 deletions
diff --git a/rsa/_compat.py b/rsa/_compat.py
index 71197a5..843583c 100644
--- a/rsa/_compat.py
+++ b/rsa/_compat.py
@@ -16,77 +16,12 @@
"""Python compatibility wrappers."""
-from __future__ import absolute_import
-
import itertools
import sys
from struct import pack
-MAX_INT = sys.maxsize
-MAX_INT64 = (1 << 63) - 1
-MAX_INT32 = (1 << 31) - 1
-MAX_INT16 = (1 << 15) - 1
-
-PY2 = sys.version_info[0] == 2
-
-# Determine the word size of the processor.
-if MAX_INT == MAX_INT64:
- # 64-bit processor.
- MACHINE_WORD_SIZE = 64
-elif MAX_INT == MAX_INT32:
- # 32-bit processor.
- MACHINE_WORD_SIZE = 32
-else:
- # Else we just assume 64-bit processor keeping up with modern times.
- MACHINE_WORD_SIZE = 64
-
-if PY2:
- integer_types = (int, long)
- range = xrange
- zip = itertools.izip
-else:
- integer_types = (int, )
- range = range
- zip = zip
-
-
-def write_to_stdout(data):
- """Writes bytes to stdout
-
- :type data: bytes
- """
- if PY2:
- sys.stdout.write(data)
- else:
- # On Py3 we must use the buffer interface to write bytes.
- sys.stdout.buffer.write(data)
-
-
-def is_bytes(obj):
- """
- Determines whether the given value is a byte string.
-
- :param obj:
- The value to test.
- :returns:
- ``True`` if ``value`` is a byte string; ``False`` otherwise.
- """
- return isinstance(obj, bytes)
-
-def is_integer(obj):
- """
- Determines whether the given value is an integer.
-
- :param obj:
- The value to test.
- :returns:
- ``True`` if ``value`` is an integer; ``False`` otherwise.
- """
- return isinstance(obj, integer_types)
-
-
-def byte(num):
+def byte(num):## XXX
"""
Converts a number between 0 and 255 (both inclusive) to a base-256 (byte)
representation.
@@ -117,46 +52,4 @@ def xor_bytes(b1, b2):
:returns:
Bytes object, result of XOR operation.
"""
- if PY2:
- return ''.join(byte(ord(x) ^ ord(y)) for x, y in zip(b1, b2))
-
return bytes(x ^ y for x, y in zip(b1, b2))
-
-
-def get_word_alignment(num, force_arch=64,
- _machine_word_size=MACHINE_WORD_SIZE):
- """
- Returns alignment details for the given number based on the platform
- Python is running on.
-
- :param num:
- Unsigned integral number.
- :param force_arch:
- If you don't want to use 64-bit unsigned chunks, set this to
- anything other than 64. 32-bit chunks will be preferred then.
- Default 64 will be used when on a 64-bit machine.
- :param _machine_word_size:
- (Internal) The machine word size used for alignment.
- :returns:
- 4-tuple::
-
- (word_bits, word_bytes,
- max_uint, packing_format_type)
- """
- max_uint64 = 0xffffffffffffffff
- max_uint32 = 0xffffffff
- max_uint16 = 0xffff
- max_uint8 = 0xff
-
- if force_arch == 64 and _machine_word_size >= 64 and num > max_uint32:
- # 64-bit unsigned integer.
- return 64, 8, max_uint64, "Q"
- elif num > max_uint16:
- # 32-bit unsigned integer
- return 32, 4, max_uint32, "L"
- elif num > max_uint8:
- # 16-bit unsigned integer.
- return 16, 2, max_uint16, "H"
- else:
- # 8-bit unsigned integer.
- return 8, 1, max_uint8, "B"
diff --git a/rsa/cli.py b/rsa/cli.py
index 6450af4..77bd4ee 100644
--- a/rsa/cli.py
+++ b/rsa/cli.py
@@ -19,8 +19,6 @@
These scripts are called by the executables defined in setup.py.
"""
-from __future__ import with_statement, print_function
-
import abc
import sys
from optparse import OptionParser
@@ -83,7 +81,7 @@ def keygen():
outfile.write(data)
else:
print('Writing private key to stdout', file=sys.stderr)
- rsa._compat.write_to_stdout(data)
+ sys.stdout.buffer.write(data)
class CryptoOperation(object):
@@ -189,7 +187,7 @@ class CryptoOperation(object):
outfile.write(outdata)
else:
print('Writing output to stdout', file=sys.stderr)
- rsa._compat.write_to_stdout(outdata)
+ sys.stdout.buffer.write(outdata)
class EncryptOperation(CryptoOperation):
diff --git a/rsa/common.py b/rsa/common.py
index f7aa2d1..a4337f6 100644
--- a/rsa/common.py
+++ b/rsa/common.py
@@ -14,8 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from rsa._compat import zip
-
"""Common functionality shared by several modules."""
diff --git a/rsa/core.py b/rsa/core.py
index b3114d9..0660881 100644
--- a/rsa/core.py
+++ b/rsa/core.py
@@ -20,11 +20,9 @@ This is the actual core RSA implementation, which is only defined
mathematically on integers.
"""
-from rsa._compat import is_integer
-
def assert_int(var, name):
- if is_integer(var):
+ if isinstance(var, int):
return
raise TypeError('%s should be an integer, not %s' % (name, var.__class__))
diff --git a/rsa/key.py b/rsa/key.py
index 1004412..1565967 100644
--- a/rsa/key.py
+++ b/rsa/key.py
@@ -36,7 +36,6 @@ of pyasn1.
import logging
import warnings
-from rsa._compat import range
import rsa.prime
import rsa.pem
import rsa.common
diff --git a/rsa/machine_size.py b/rsa/machine_size.py
deleted file mode 100644
index 2a871b8..0000000
--- a/rsa/machine_size.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Detection of 32-bit and 64-bit machines and byte alignment."""
-
-import sys
-
-MAX_INT = sys.maxsize
-MAX_INT64 = (1 << 63) - 1
-MAX_INT32 = (1 << 31) - 1
-MAX_INT16 = (1 << 15) - 1
-
-# Determine the word size of the processor.
-if MAX_INT == MAX_INT64:
- # 64-bit processor.
- MACHINE_WORD_SIZE = 64
-elif MAX_INT == MAX_INT32:
- # 32-bit processor.
- MACHINE_WORD_SIZE = 32
-else:
- # Else we just assume 64-bit processor keeping up with modern times.
- MACHINE_WORD_SIZE = 64
-
-
-def get_word_alignment(num, force_arch=64,
- _machine_word_size=MACHINE_WORD_SIZE):
- """
- Returns alignment details for the given number based on the platform
- Python is running on.
-
- :param num:
- Unsigned integral number.
- :param force_arch:
- If you don't want to use 64-bit unsigned chunks, set this to
- anything other than 64. 32-bit chunks will be preferred then.
- Default 64 will be used when on a 64-bit machine.
- :param _machine_word_size:
- (Internal) The machine word size used for alignment.
- :returns:
- 4-tuple::
-
- (word_bits, word_bytes,
- max_uint, packing_format_type)
- """
- max_uint64 = 0xffffffffffffffff
- max_uint32 = 0xffffffff
- max_uint16 = 0xffff
- max_uint8 = 0xff
-
- if force_arch == 64 and _machine_word_size >= 64 and num > max_uint32:
- # 64-bit unsigned integer.
- return 64, 8, max_uint64, "Q"
- elif num > max_uint16:
- # 32-bit unsigned integer
- return 32, 4, max_uint32, "L"
- elif num > max_uint8:
- # 16-bit unsigned integer.
- return 16, 2, max_uint16, "H"
- else:
- # 8-bit unsigned integer.
- return 8, 1, max_uint8, "B"
diff --git a/rsa/parallel.py b/rsa/parallel.py
index a3fe312..ef9f07f 100644
--- a/rsa/parallel.py
+++ b/rsa/parallel.py
@@ -24,11 +24,8 @@ Introduced in Python-RSA 3.1.
"""
-from __future__ import print_function
-
import multiprocessing as mp
-from rsa._compat import range
import rsa.prime
import rsa.randnum
diff --git a/rsa/pem.py b/rsa/pem.py
index 2ddfae8..0650e64 100644
--- a/rsa/pem.py
+++ b/rsa/pem.py
@@ -18,15 +18,13 @@
import base64
-from rsa._compat import is_bytes, range
-
def _markers(pem_marker):
"""
Returns the start and end PEM markers, as bytes.
"""
- if not is_bytes(pem_marker):
+ if not isinstance(pem_marker, bytes):
pem_marker = pem_marker.encode('ascii')
return (b'-----BEGIN ' + pem_marker + b'-----',
@@ -49,7 +47,7 @@ def load_pem(contents, pem_marker):
"""
# We want bytes, not text. If it's text, it can be converted to ASCII bytes.
- if not is_bytes(contents):
+ if not isinstance(contents, bytes):
contents = contents.encode('ascii')
(pem_start, pem_end) = _markers(pem_marker)
diff --git a/rsa/pkcs1.py b/rsa/pkcs1.py
index 84f0e3b..310f22c 100644
--- a/rsa/pkcs1.py
+++ b/rsa/pkcs1.py
@@ -31,7 +31,6 @@ to your users.
import hashlib
import os
-from rsa._compat import range
from rsa import common, transform, core
# ASN.1 codes that describe the hash algorithm used.
diff --git a/rsa/pkcs1_v2.py b/rsa/pkcs1_v2.py
index 5f9c7dd..6242a71 100644
--- a/rsa/pkcs1_v2.py
+++ b/rsa/pkcs1_v2.py
@@ -20,7 +20,6 @@ This module implements certain functionality from PKCS#1 version 2. Main
documentation is RFC 2437: https://tools.ietf.org/html/rfc2437
"""
-from rsa._compat import range
from rsa import (
common,
pkcs1,
diff --git a/rsa/prime.py b/rsa/prime.py
index 3d63542..a45f659 100644
--- a/rsa/prime.py
+++ b/rsa/prime.py
@@ -20,7 +20,6 @@ Implementation based on the book Algorithm Design by Michael T. Goodrich and
Roberto Tamassia, 2002.
"""
-from rsa._compat import range
import rsa.common
import rsa.randnum
diff --git a/rsa/randnum.py b/rsa/randnum.py
index 310acaa..1f0a4e5 100644
--- a/rsa/randnum.py
+++ b/rsa/randnum.py
@@ -19,9 +19,9 @@
# Source inspired by code by Yesudeep Mangalapilly <yesudeep@gmail.com>
import os
+import struct
from rsa import common, transform
-from rsa._compat import byte
def read_random_bits(nbits):
@@ -40,7 +40,7 @@ def read_random_bits(nbits):
if rbits > 0:
randomvalue = ord(os.urandom(1))
randomvalue >>= (8 - rbits)
- randomdata = byte(randomvalue) + randomdata
+ randomdata = struct.pack("B", randomvalue) + randomdata
return randomdata
diff --git a/rsa/transform.py b/rsa/transform.py
index 628d0af..bce9f74 100644
--- a/rsa/transform.py
+++ b/rsa/transform.py
@@ -19,16 +19,10 @@
From bytes to a number, number to bytes, etc.
"""
-from __future__ import absolute_import
+import math
-import binascii
-from struct import pack
-from rsa._compat import byte, is_integer
-from rsa import common, machine_size
-
-
-def bytes2int(raw_bytes):
+def bytes2int(raw_bytes: bytes) -> int:
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.
@@ -39,110 +33,14 @@ def bytes2int(raw_bytes):
8405007
"""
+ return int.from_bytes(raw_bytes, 'big', signed=False)
- return int(binascii.hexlify(raw_bytes), 16)
-
-
-def _int2bytes(number, block_size=None):
- r"""Converts a number to a string of bytes.
-
- Usage::
-
- >>> _int2bytes(123456789)
- b'\x07[\xcd\x15'
- >>> bytes2int(_int2bytes(123456789))
- 123456789
-
- >>> _int2bytes(123456789, 6)
- b'\x00\x00\x07[\xcd\x15'
- >>> bytes2int(_int2bytes(123456789, 128))
- 123456789
-
- >>> _int2bytes(123456789, 3)
- Traceback (most recent call last):
- ...
- OverflowError: Needed 4 bytes for number, but block size is 3
- @param number: the number to convert
- @param block_size: the number of bytes to output. If the number encoded to
- bytes is less than this, the block will be zero-padded. When not given,
- the returned block is not padded.
-
- @throws OverflowError when block_size is given and the number takes up more
- bytes than fit into the block.
+def int2bytes(number: int, fill_size: int=0) -> bytes:
"""
+ Convert an unsigned integer to bytes (big-endian)::
- # Type checking
- if not is_integer(number):
- raise TypeError("You must pass an integer for 'number', not %s" %
- number.__class__)
-
- if number < 0:
- raise ValueError('Negative numbers cannot be used: %i' % number)
-
- # Do some bounds checking
- if number == 0:
- needed_bytes = 1
- raw_bytes = [b'\x00']
- else:
- needed_bytes = common.byte_size(number)
- raw_bytes = []
-
- # You cannot compare None > 0 in Python 3x. It will fail with a TypeError.
- if block_size and block_size > 0:
- if needed_bytes > block_size:
- raise OverflowError('Needed %i bytes for number, but block size '
- 'is %i' % (needed_bytes, block_size))
-
- # Convert the number to bytes.
- while number > 0:
- raw_bytes.insert(0, byte(number & 0xFF))
- number >>= 8
-
- # Pad with zeroes to fill the block
- if block_size and block_size > 0:
- padding = (block_size - needed_bytes) * b'\x00'
- else:
- padding = b''
-
- return padding + b''.join(raw_bytes)
-
-
-def bytes_leading(raw_bytes, needle=b'\x00'):
- """
- Finds the number of prefixed byte occurrences in the haystack.
-
- Useful when you want to deal with padding.
-
- :param raw_bytes:
- Raw bytes.
- :param needle:
- The byte to count. Default \x00.
- :returns:
- The number of leading needle bytes.
- """
-
- leading = 0
- # Indexing keeps compatibility between Python 2.x and Python 3.x
- _byte = needle[0]
- for x in raw_bytes:
- if x == _byte:
- leading += 1
- else:
- break
- return leading
-
-
-def int2bytes(number, fill_size=None, chunk_size=None, overflow=False):
- """
- Convert an unsigned integer to bytes (base-256 representation)::
-
- Does not preserve leading zeros if you don't specify a chunk size or
- fill size.
-
- .. NOTE:
- You must not specify both fill_size and chunk_size. Only one
- of them is allowed.
+ Does not preserve leading zeros if you don't specify a fill size.
:param number:
Integer value
@@ -150,15 +48,6 @@ def int2bytes(number, fill_size=None, chunk_size=None, overflow=False):
If the optional fill size is given the length of the resulting
byte string is expected to be the fill size and will be padded
with prefix zero bytes to satisfy that length.
- :param chunk_size:
- If optional chunk size is given and greater than zero, pad the front of
- the byte string with binary zeros so that the length is a multiple of
- ``chunk_size``.
- :param overflow:
- ``False`` (default). If this is ``True``, no ``OverflowError``
- will be raised when the fill_size is shorter than the length
- of the generated byte sequence. Instead the byte sequence will
- be returned as is.
:returns:
Raw bytes (base-256 representation).
:raises:
@@ -171,42 +60,12 @@ def int2bytes(number, fill_size=None, chunk_size=None, overflow=False):
if number < 0:
raise ValueError("Number must be an unsigned integer: %d" % number)
- if fill_size and chunk_size:
- raise ValueError("You can either fill or pad chunks, but not both")
-
- # Ensure these are integers.
- number & 1
-
- raw_bytes = b''
-
- # Pack the integer one machine word at a time into bytes.
- num = number
- word_bits, _, max_uint, pack_type = machine_size.get_word_alignment(num)
- pack_format = ">%s" % pack_type
- while num > 0:
- raw_bytes = pack(pack_format, num & max_uint) + raw_bytes
- num >>= word_bits
- # Obtain the index of the first non-zero byte.
- zero_leading = bytes_leading(raw_bytes)
- if number == 0:
- raw_bytes = b'\x00'
- # De-padding.
- raw_bytes = raw_bytes[zero_leading:]
-
- length = len(raw_bytes)
- if fill_size and fill_size > 0:
- if not overflow and length > fill_size:
- raise OverflowError(
- "Need %d bytes for number, but fill size is %d" %
- (length, fill_size)
- )
- raw_bytes = raw_bytes.rjust(fill_size, b'\x00')
- elif chunk_size and chunk_size > 0:
- remainder = length % chunk_size
- if remainder:
- padding_size = chunk_size - remainder
- raw_bytes = raw_bytes.rjust(length + padding_size, b'\x00')
- return raw_bytes
+ bytes_required = max(1, math.ceil(number.bit_length() / 8))
+
+ if fill_size > 0:
+ return number.to_bytes(fill_size, 'big')
+
+ return number.to_bytes(bytes_required, 'big')
if __name__ == '__main__':
diff --git a/rsa/util.py b/rsa/util.py
index 29d5eb1..c44d04c 100644
--- a/rsa/util.py
+++ b/rsa/util.py
@@ -16,8 +16,6 @@
"""Utility functions."""
-from __future__ import with_statement, print_function
-
import sys
from optparse import OptionParser