commit 116787a0ee17e46cd587a3a4a40239a53890039e Author: Patrick O'Doherty p@trickod.com Date: Sun Feb 26 15:32:02 2017 -0800
Completely deprecate pycrypto
Update the sign_descriptor_content in mocking.py to use cryptography.
Remove pycrypto from the requirements.txt --- requirements.txt | 1 - stem/prereq.py | 9 +++++---- test/mocking.py | 42 ++++++++++++++---------------------------- test/settings.cfg | 14 +++++++------- 4 files changed, 26 insertions(+), 40 deletions(-)
diff --git a/requirements.txt b/requirements.txt index 5fb3d12..6dc054c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ mock pyflakes pycodestyle -pycrypto tox cryptography diff --git a/stem/prereq.py b/stem/prereq.py index 4574771..bf935b4 100644 --- a/stem/prereq.py +++ b/stem/prereq.py @@ -85,7 +85,7 @@ def is_python_3(): @lru_cache() def is_crypto_available(): """ - Checks if the pycrypto functions we use are available. This is used for + Checks if the cryptography functions we use are available. This is used for verifying relay descriptor signatures.
:returns: **True** if we can use pycrypto and **False** otherwise @@ -94,9 +94,10 @@ def is_crypto_available(): from stem.util import log
try: - from Crypto.PublicKey import RSA - from Crypto.Util import asn1 - from Crypto.Util.number import long_to_bytes + from cryptography.utils import int_from_bytes, int_to_bytes + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives.serialization import load_der_public_key + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes return True except ImportError: log.log_once('stem.prereq.is_crypto_available', log.INFO, CRYPTO_UNAVAILABLE) diff --git a/test/mocking.py b/test/mocking.py index 0d9e6f0..8babe76 100644 --- a/test/mocking.py +++ b/test/mocking.py @@ -722,33 +722,19 @@ def sign_descriptor_content(desc_content): if not stem.prereq.is_crypto_available(): return desc_content else: - from Crypto.PublicKey import RSA - from Crypto.Util import asn1 - from Crypto.Util.number import long_to_bytes - - # generate a key - private_key = RSA.generate(1024) - - # get a string representation of the public key - seq = asn1.DerSequence() - seq.append(private_key.n) - seq.append(private_key.e) - seq_as_string = seq.encode() - public_key_string = base64.b64encode(seq_as_string) - - # split public key into lines 64 characters long - public_key_string = b'\n'.join([ - public_key_string[:64], - public_key_string[64:128], - public_key_string[128:], - ]) + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes + from cryptography.hazmat.primitives.asymmetric import rsa, padding + from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat + + private_key = rsa.generate_private_key(public_exponent=65537, key_size=1024, backend=default_backend()) + public_key = private_key.public_key()
- # generate the new signing key string + # Get a string representation of the public key
signing_key_token = b'\nsigning-key\n' # note the trailing '\n' is important here so as not to match the string elsewhere - signing_key_token_start = b'-----BEGIN RSA PUBLIC KEY-----\n' signing_key_token_end = b'\n-----END RSA PUBLIC KEY-----\n' - new_sk = signing_key_token + signing_key_token_start + public_key_string + signing_key_token_end + new_sk = signing_key_token + public_key.public_bytes(encoding=Encoding.PEM, format=PublicFormat.PKCS1)
# update the descriptor string with the new signing key
@@ -758,6 +744,7 @@ def sign_descriptor_content(desc_content):
# generate the new fingerprint string
+ seq_as_string = public_key.public_bytes(encoding=Encoding.DER, format=PublicFormat.PKCS1) key_hash = stem.util.str_tools._to_bytes(hashlib.sha1(seq_as_string).hexdigest().upper()) grouped_fingerprint = b''
@@ -799,16 +786,15 @@ def sign_descriptor_content(desc_content): # 2 bytes for the type info # 1 byte for the separator
- padding = b'' + digest_padding = b''
for x in range(125 - len(new_digest)): - padding += b'\xFF' - digestBuffer = b'\x00\x01' + padding + b'\x00' + new_digest + digest_padding += b'\xFF' + digest_buffer = b'\x00\x01' + digest_padding + b'\x00' + new_digest
# generate a new signature by signing the digest buffer with the private key
- (signature, ) = private_key.sign(digestBuffer, None) - signature_as_bytes = long_to_bytes(signature, 128) + signature_as_bytes = private_key.sign(digest_buffer, padding.PKCS1v15(), hashes.SHA1()) signature_base64 = base64.b64encode(signature_as_bytes)
signature_base64 = b'b'.join([ diff --git a/test/settings.cfg b/test/settings.cfg index 4913202..f9c6c62 100644 --- a/test/settings.cfg +++ b/test/settings.cfg @@ -144,14 +144,14 @@ pyflakes.ignore stem/__init__.py => undefined name 'long' pyflakes.ignore stem/__init__.py => undefined name 'unicode' pyflakes.ignore stem/control.py => undefined name 'controller' pyflakes.ignore stem/manual.py => undefined name 'unichr' -pyflakes.ignore stem/prereq.py => 'Crypto.PublicKey.RSA' imported but unused -pyflakes.ignore stem/prereq.py => 'Crypto.Util.asn1' imported but unused -pyflakes.ignore stem/prereq.py => 'Crypto.Util.number.long_to_bytes' imported but unused -pyflakes.ignore stem/prereq.py => 'RSA' imported but unused -pyflakes.ignore stem/prereq.py => 'asn1' imported but unused -pyflakes.ignore stem/prereq.py => 'unittest' imported but unused +pyflakes.ignore stem/prereq.py => 'cryptography.utils.int_to_bytes' imported but unused +pyflakes.ignore stem/prereq.py => 'cryptography.utils.int_from_bytes' imported but unused +pyflakes.ignore stem/prereq.py => 'cryptography.hazmat.backends.default_backend' imported but unused +pyflakes.ignore stem/prereq.py => 'cryptography.hazmat.primitives.serialization.load_der_public_key' imported but unused +pyflakes.ignore stem/prereq.py => 'cryptography.hazmat.primitives.ciphers.modes' imported but unused +pyflakes.ignore stem/prereq.py => 'cryptography.hazmat.primitives.ciphers.Cipher' imported but unused +pyflakes.ignore stem/prereq.py => 'cryptography.hazmat.primitives.ciphers.algorithms' imported but unused pyflakes.ignore stem/prereq.py => 'unittest.mock' imported but unused -pyflakes.ignore stem/prereq.py => 'long_to_bytes' imported but unused pyflakes.ignore stem/interpreter/__init__.py => undefined name 'raw_input' pyflakes.ignore stem/util/conf.py => undefined name 'unicode' pyflakes.ignore stem/util/test_tools.py => 'pyflakes' imported but unused