[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Move some stuff back to hsv3_crypto.
commit 9ffca2043c66544c0d54885ae3d19b10dcc652f1
Author: George Kadianakis <desnacked@xxxxxxxxxx>
Date: Thu Oct 10 20:56:17 2019 +0300
Move some stuff back to hsv3_crypto.
These functions are gonna be used both by the decoding code and the encoding
code.
We are now starting to write an encode-to-decode unittest and when debuggin the
descriptor encryption it's very useful to have the encryption-related code
centralized in one function.
---
stem/descriptor/hidden_service.py | 31 +++++--------
stem/descriptor/hsv3_crypto.py | 98 +++++++++++++++++++++++++++++++++++++++
2 files changed, 110 insertions(+), 19 deletions(-)
diff --git a/stem/descriptor/hidden_service.py b/stem/descriptor/hidden_service.py
index 4a75bc88..305dfaf7 100644
--- a/stem/descriptor/hidden_service.py
+++ b/stem/descriptor/hidden_service.py
@@ -42,7 +42,9 @@ import stem.util.connection
import stem.util.str_tools
import stem.util.tor_tools
-from stem.descriptor.certificate import Ed25519Certificate
+import stem.descriptor.hsv3_crypto as hsv3_crypto
+
+from stem.descriptor.certificate import Ed25519Certificate, CertType
from stem.descriptor import (
PGP_BLOCK_END,
@@ -263,7 +265,7 @@ class IntroductionPointV3(object):
return body
class AuthorizedClient(collections.namedtuple('AuthorizedClient', ['id', 'iv', 'cookie'])):
- """
+ """
Client authorized to use a v3 hidden service.
.. versionadded:: 1.8.0
@@ -318,9 +320,6 @@ def _decrypt_layer(encrypted_block, constant, revision_counter, subcredential, b
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
- def pack(val):
- return struct.pack('>Q', val)
-
if encrypted_block.startswith('-----BEGIN MESSAGE-----\n') and encrypted_block.endswith('\n-----END MESSAGE-----'):
encrypted_block = encrypted_block[24:-22]
@@ -336,14 +335,10 @@ def _decrypt_layer(encrypted_block, constant, revision_counter, subcredential, b
ciphertext = encrypted[SALT_LEN:-MAC_LEN]
expected_mac = encrypted[-MAC_LEN:]
- kdf = hashlib.shake_256(blinded_key + subcredential + pack(revision_counter) + salt + constant)
- keys = kdf.digest(S_KEY_LEN + S_IV_LEN + MAC_LEN)
+ secret_key, secret_iv, mac_key = hsv3_crypto.get_desc_keys(blinded_key, constant,
+ subcredential, revision_counter, salt, )
- secret_key = keys[:S_KEY_LEN]
- secret_iv = keys[S_KEY_LEN:S_KEY_LEN + S_IV_LEN]
- mac_key = keys[S_KEY_LEN + S_IV_LEN:]
-
- mac = hashlib.sha3_256(pack(len(mac_key)) + mac_key + pack(len(salt)) + salt + ciphertext).digest()
+ mac = hsv3_crypto.get_desc_encryption_mac(mac_key, salt, ciphertext)
if mac != expected_mac:
raise ValueError('Malformed mac (expected %s, but was %s)' % (expected_mac, mac))
@@ -844,6 +839,7 @@ class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor):
super(HiddenServiceDescriptorV3, self).__init__(raw_contents, lazy_load = not validate)
self._inner_layer = None
+ self._outer_layer = None
entries = _descriptor_components(raw_contents, validate)
if validate:
@@ -889,15 +885,12 @@ class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor):
if not blinded_key:
raise ValueError('No signing key is present')
- # credential = H('credential' | public-identity-key)
- # subcredential = H('subcredential' | credential | blinded-public-key)
-
identity_public_key = HiddenServiceDescriptorV3._public_key_from_address(onion_address)
- credential = hashlib.sha3_256(b'credential%s' % (identity_public_key)).digest()
- subcredential = hashlib.sha3_256(b'subcredential%s%s' % (credential, blinded_key)).digest()
- outer_layer = OuterLayer._decrypt(self.superencrypted, self.revision_counter, subcredential, blinded_key)
- self._inner_layer = InnerLayer._decrypt(outer_layer, self.revision_counter, subcredential, blinded_key)
+ subcredential = hsv3_crypto.get_subcredential(identity_public_key, blinded_key)
+
+ self._outer_layer = OuterLayer._decrypt(self.superencrypted, self.revision_counter, subcredential, blinded_key)
+ self._inner_layer = InnerLayer._decrypt(self._outer_layer, self.revision_counter, subcredential, blinded_key)
return self._inner_layer
diff --git a/stem/descriptor/hsv3_crypto.py b/stem/descriptor/hsv3_crypto.py
index bd090265..ed4ad7b8 100644
--- a/stem/descriptor/hsv3_crypto.py
+++ b/stem/descriptor/hsv3_crypto.py
@@ -57,3 +57,101 @@ class HSv3PublicBlindedKey(object):
"""
ext.slow_ed25519.checkvalid(signature, message, self.public_key)
+"""
+subcredential
+
+ subcredential = H("subcredential" | credential | blinded-public-ke
+ credential = H("credential" | public-identity-key)
+"""
+def get_subcredential(public_identity_key, blinded_key):
+ cred_bytes_constant = "credential".encode()
+ subcred_bytes_constant = "subcredential".encode()
+
+ credential = hashlib.sha3_256(b"%s%s" % (cred_bytes_constant, public_identity_key)).digest()
+ subcredential = hashlib.sha3_256(b"%s%s%s" % (subcred_bytes_constant, credential, blinded_key)).digest()
+
+ return subcredential
+
+
+"""
+Basic descriptor logic:
+
+ SALT = 16 bytes from H(random), changes each time we rebuld the
+ descriptor even if the content of the descriptor hasn't changed.
+ (So that we don't leak whether the intro point list etc. changed)
+
+ secret_input = SECRET_DATA | subcredential | INT_8(revision_counter)
+
+ keys = KDF(secret_input | salt | STRING_CONSTANT, S_KEY_LEN + S_IV_LEN + MAC_KEY_LEN)
+
+ SECRET_KEY = first S_KEY_LEN bytes of keys
+ SECRET_IV = next S_IV_LEN bytes of keys
+ MAC_KEY = last MAC_KEY_LEN bytes of keys
+
+
+Layer data:
+
+ 2.5.1.1. First layer encryption logic
+ SECRET_DATA = blinded-public-key
+ STRING_CONSTANT = "hsdir-superencrypted-data"
+
+ 2.5.2.1. Second layer encryption keys
+ SECRET_DATA = blinded-public-key | descriptor_cookie
+ STRING_CONSTANT = "hsdir-encrypted-data"
+"""
+
+SALT_LEN = 16
+MAC_LEN = 32
+
+S_KEY_LEN = 32
+S_IV_LEN = 16
+MAC_KEY_LEN = 32
+
+"""
+
+Descriptor encryption
+
+"""
+
+def pack(val):
+ return struct.pack('>Q', val)
+
+
+def get_desc_keys(secret_data, string_constant,
+ subcredential, revision_counter, salt):
+ """
+ secret_input = SECRET_DATA | subcredential | INT_8(revision_counter)
+
+ keys = KDF(secret_input | salt | STRING_CONSTANT, S_KEY_LEN + S_IV_LEN + MAC_KEY_LEN)
+
+ SECRET_KEY = first S_KEY_LEN bytes of keys
+ SECRET_IV = next S_IV_LEN bytes of keys
+ MAC_KEY = last MAC_KEY_LEN bytes of keys
+
+ where
+
+ 2.5.1.1. First layer encryption logic
+ SECRET_DATA = blinded-public-key
+ STRING_CONSTANT = "hsdir-superencrypted-data"
+
+ 2.5.2.1. Second layer encryption keys
+ SECRET_DATA = blinded-public-key | descriptor_cookie
+ STRING_CONSTANT = "hsdir-encrypted-data"
+ """
+ secret_input = b"%s%s%s" % (secret_data, subcredential, pack(revision_counter))
+
+ kdf = hashlib.shake_256(secret_input + salt + string_constant)
+
+ keys = kdf.digest(S_KEY_LEN + S_IV_LEN + MAC_LEN)
+
+ secret_key = keys[:S_KEY_LEN]
+ secret_iv = keys[S_KEY_LEN:S_KEY_LEN + S_IV_LEN]
+ mac_key = keys[S_KEY_LEN + S_IV_LEN:]
+
+ return secret_key, secret_iv, mac_key
+
+def get_desc_encryption_mac(key, salt, ciphertext):
+
+ mac = hashlib.sha3_256(pack(len(key)) + key + pack(len(salt)) + salt + ciphertext).digest()
+ return mac
+
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits