[tor-commits] [stem/master] Only import crypto modules if available
atagar at torproject.org
atagar at torproject.org
Sun Oct 6 02:07:34 UTC 2019
commit ec4d6f99e55b2ca62b7def152d31364de605c2fd
Author: Damian Johnson <atagar at torproject.org>
Date: Wed Sep 4 17:34:00 2019 -0700
Only import crypto modules if available
Stem has a soft dependency on the cryptography module. If unavailable we should
gracefully degrade or explicitly error with a message saying that cryptography
is required.
Also, cryptography's ed25519 class is pretty new, so folks will have outdated
module versions for a while...
======================================================================
ERROR: test_for_decrypt
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/atagar/Desktop/stem/test/unit/descriptor/hidden_service_v3.py", line 43, in test_for_decrypt
onion_address="sltib6sxkuxh2scmtuvd5w2g7pahnzkovefxpo4e4ptnkzl5kkq5h2ad.onion"))
File "/home/atagar/Desktop/stem/stem/descriptor/__init__.py", line 442, in parse_file
for desc in parse(descriptor_file):
File "/home/atagar/Desktop/stem/stem/descriptor/__init__.py", line 545, in _parse_metrics_file
for desc in stem.descriptor.hidden_service._parse_file(descriptor_file, desc_type, validate = validate, **kwargs):
File "/home/atagar/Desktop/stem/stem/descriptor/hidden_service.py", line 156, in _parse_file
yield desc_type(bytes.join(b'', descriptor_content), validate, **kwargs)
File "/home/atagar/Desktop/stem/stem/descriptor/hidden_service.py", line 571, in __init__
plaintext = self.decrypt_descriptor(desc_signing_cert)
File "/home/atagar/Desktop/stem/stem/descriptor/hidden_service.py", line 579, in decrypt_descriptor
identity_public_key = stem.descriptor.hsv3_crypto.decode_address(self.onion_address)
File "/home/atagar/Desktop/stem/stem/descriptor/hsv3_crypto.py", line 30, in decode_address
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
ImportError: No module named ed25519
---
stem/descriptor/hidden_service.py | 20 +++++++++++---------
stem/descriptor/hsv3_crypto.py | 16 ++++++++++++----
stem/prereq.py | 10 +++++++++-
3 files changed, 32 insertions(+), 14 deletions(-)
diff --git a/stem/descriptor/hidden_service.py b/stem/descriptor/hidden_service.py
index 5397d057..150ba368 100644
--- a/stem/descriptor/hidden_service.py
+++ b/stem/descriptor/hidden_service.py
@@ -31,6 +31,8 @@ import collections
import hashlib
import io
+import stem.descriptor.certificate
+import stem.descriptor.hsv3_crypto
import stem.prereq
import stem.util.connection
import stem.util.str_tools
@@ -470,9 +472,6 @@ class HiddenServiceDescriptorV2(BaseHiddenServiceDescriptor):
return introduction_points
-import stem.descriptor.certificate
-import stem.descriptor.hsv3_crypto as hsv3_crypto
-from cryptography.hazmat.primitives import serialization
class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor):
"""
@@ -568,29 +567,32 @@ class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor):
# ASN XXX need to verify descriptor signing certificate (for now we trust Tor to do it)
# ASN XXX need to verify descriptor signature (for now we trust Tor to do it)
- plaintext = self.decrypt_descriptor(desc_signing_cert)
+ if not skip_crypto_validation and stem.prereq.is_crypto_available():
+ plaintext = self.decrypt_descriptor(desc_signing_cert)
def decrypt_descriptor(self, desc_signing_cert):
# Get crypto material.
# ASN XXX Extract to its own function and assign them to class variables
+ from cryptography.hazmat.primitives import serialization
+
blinded_key_bytes = desc_signing_cert.get_signing_key()
- identity_public_key = hsv3_crypto.decode_address(self.onion_address)
+ identity_public_key = stem.descriptor.hsv3_crypto.decode_address(self.onion_address)
identity_public_key_bytes = identity_public_key.public_bytes(encoding=serialization.Encoding.Raw,
format=serialization.PublicFormat.Raw)
assert(len(identity_public_key_bytes) == 32)
assert(len(blinded_key_bytes) == 32)
- subcredential_bytes = hsv3_crypto.get_subcredential(identity_public_key_bytes, blinded_key_bytes)
+ subcredential_bytes = stem.descriptor.hsv3_crypto.get_subcredential(identity_public_key_bytes, blinded_key_bytes)
####################################### Do the decryption ###################################
- outter_layer_plaintext = hsv3_crypto.decrypt_outter_layer(self.superencrypted, self.revision_counter,
+ outter_layer_plaintext = stem.descriptor.hsv3_crypto.decrypt_outter_layer(self.superencrypted, self.revision_counter,
identity_public_key_bytes, blinded_key_bytes, subcredential_bytes)
# ATAGAR XXX this parsing function is a hack. need to replace it with some stem parsing.
- inner_layer_ciphertext = hsv3_crypto.parse_superencrypted_plaintext(outter_layer_plaintext)
+ inner_layer_ciphertext = stem.descriptor.hsv3_crypto.parse_superencrypted_plaintext(outter_layer_plaintext)
- inner_layer_plaintext = hsv3_crypto.decrypt_inner_layer(inner_layer_ciphertext, self.revision_counter,
+ inner_layer_plaintext = stem.descriptor.hsv3_crypto.decrypt_inner_layer(inner_layer_ciphertext, self.revision_counter,
identity_public_key_bytes, blinded_key_bytes, subcredential_bytes)
print(inner_layer_plaintext)
diff --git a/stem/descriptor/hsv3_crypto.py b/stem/descriptor/hsv3_crypto.py
index de88b7ac..8f304c52 100644
--- a/stem/descriptor/hsv3_crypto.py
+++ b/stem/descriptor/hsv3_crypto.py
@@ -1,10 +1,7 @@
import base64
import hashlib
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
-from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
-from cryptography.hazmat.backends import default_backend
-
+import stem.prereq
"""
Onion addresses
@@ -32,6 +29,14 @@ def decode_address(onion_address_str):
:raises: ValueError
"""
+
+ # TODO: note the module version
+
+ if not stem.prereq.is_crypto_available(ed25519 = True):
+ raise ImportError('Onion address decoding requires cryptography version XXX')
+
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
+
if (len(onion_address_str) != 56 + len(".onion")):
raise ValueError("Wrong address length")
@@ -149,6 +154,9 @@ def _ciphertext_mac_is_valid(key, salt, ciphertext, mac):
def _decrypt_descriptor_layer(ciphertext_blob_b64, revision_counter,
public_identity_key, subcredential,
secret_data, string_constant):
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+ from cryptography.hazmat.backends import default_backend
+
# decode the thing
ciphertext_blob = base64.b64decode(ciphertext_blob_b64)
diff --git a/stem/prereq.py b/stem/prereq.py
index 4cb51113..0aadb35a 100644
--- a/stem/prereq.py
+++ b/stem/prereq.py
@@ -114,11 +114,13 @@ def is_sqlite_available():
return False
-def is_crypto_available():
+def is_crypto_available(ed25519 = False):
"""
Checks if the cryptography functions we use are available. This is used for
verifying relay descriptor signatures.
+ :param bool ed25519: check for ed25519 support
+
:returns: **True** if we can use the cryptography module and **False**
otherwise
"""
@@ -134,6 +136,12 @@ def is_crypto_available():
if not hasattr(rsa.RSAPrivateKey, 'sign'):
raise ImportError()
+ # TODO: Check when the cryptography module's ed25519 class was added
+ # (it's not present in 2.0.3).
+
+ if ed25519:
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
+
return True
except ImportError:
from stem.util import log
More information about the tor-commits
mailing list