@@ -32,6 +32,7 @@
**SIGNING** signing a signing key with an identity key
**LINK_CERT** TLS link certificate signed with ed25519 signing key
**AUTH** authentication key signed with ed25519 signing key
XXX update with hsv3 stuff
============== ===========
.. data:: ExtensionType (enum)
@@ -69,8 +70,9 @@
ED25519_HEADER_LENGTH = 40
ED25519_SIGNATURE_LENGTH = 64
ED25519_ROUTER_SIGNATURE_PREFIX = b'Tor router descriptor signature v1'
ED25519_HSV3_DESCRIPTOR_PREFIX = b'Tor onion service descriptor sig v3'

CertType = stem.util.enum.UppercaseEnum('SIGNING', 'LINK_CERT', 'AUTH')
CertType = stem.util.enum.UppercaseEnum('SIGNING', 'LINK_CERT', 'AUTH', 'DESC_SIGNING', 'IP_AUTH', 'IP_ENC')
ExtensionType = stem.util.enum.Enum(('HAS_SIGNING_KEY', 4),)
ExtensionFlag = stem.util.enum.UppercaseEnum('AFFECTS_VALIDATION', 'UNKNOWN')

@@ -158,6 +160,12 @@ def __init__(self, version, encoded, decoded):
self.type = CertType.AUTH
elif cert_type == 7:
raise ValueError('Ed25519 certificate cannot have a type of 7. This is reserved for RSA identity cross-certification.')
elif cert_type == 8:
self.type = CertType.DESC_SIGNING # short-term desc signing key
elif cert_type == 9:
self.type = CertType.IP_AUTH # intro-point auth key
elif cert_type == 0xb: # XXX spec uses hex
self.type = CertType.IP_ENC # [0B] ed25519 key derived from the curve25519 intro point encryption key,
else:
raise ValueError("BUG: Ed25519 certificate type is decoded from one byte. It shouldn't be possible to have a value of %i." % cert_type)

@@ -237,8 +245,15 @@ def validate(self, server_descriptor):
descriptor_content = server_descriptor.get_bytes()
signing_key = None

if server_descriptor.ed25519_master_key:
print(f"### certificate: {server_descriptor.certificate}")
print(f"### certificate.key: {server_descriptor.certificate.key}")
print(f"### extensions: {server_descriptor.certificate.extensions}")
if hasattr(server_descriptor, "ed25519_master_key") and server_descriptor.ed25519_master_key:
signing_key = Ed25519PublicKey.from_public_bytes(base64.b64decode(stem.util.str_tools._to_bytes(server_descriptor.ed25519_master_key) + b'='))
elif server_descriptor.certificate:
# XXX hacky
signing_key = Ed25519PublicKey.from_public_bytes(self.extensions[0].data)
print(f"### certificate.key: {signing_key}")
else:
for extension in self.extensions:
if extension.type == ExtensionType.HAS_SIGNING_KEY:
@@ -249,23 +264,58 @@ def validate(self, server_descriptor):
raise ValueError('Server descriptor missing an ed25519 signing key')

try:
signing_key.verify(self.signature, base64.b64decode(stem.util.str_tools._to_bytes(self.encoded))[:-ED25519_SIGNATURE_LENGTH])
print(f"### encoded: {self.encoded}")
signed_bytes = base64.b64decode(stem.util.str_tools._to_bytes(self.encoded))[:-ED25519_SIGNATURE_LENGTH]
print(f"### len(signed_bytes) = {len(signed_bytes)}")
print(f"### signed_bytes[0] = {hex(signed_bytes[0])}")
print(f"### signed_bytes[-1] = {hex(signed_bytes[-1])}")
signing_key.verify(self.signature, signed_bytes)
except InvalidSignature:
raise ValueError('Ed25519KeyCertificate signing key is invalid (Signature was forged or corrupt)')

# ed25519 signature validates descriptor content up until the signature itself

if b'router-sig-ed25519 ' not in descriptor_content:
raise ValueError("Descriptor doesn't have a router-sig-ed25519 entry.")
# XXX this is hacky. basically, i needed to add the "else" case for Hsv3Descriptors
if type(server_descriptor).__name__ == "ServerDescriptor":
if b'router-sig-ed25519 ' not in descriptor_content:
raise ValueError("Descriptor doesn't have a router-sig-ed25519 entry.")

signed_content = descriptor_content[:descriptor_content.index(b'router-sig-ed25519 ') + 19]
descriptor_sha256_digest = hashlib.sha256(ED25519_ROUTER_SIGNATURE_PREFIX + signed_content).digest()
signed_content = descriptor_content[:descriptor_content.index(b'router-sig-ed25519 ') + 19]
descriptor_sha256_digest = hashlib.sha256(ED25519_ROUTER_SIGNATURE_PREFIX + signed_content).digest()

missing_padding = len(server_descriptor.ed25519_signature) % 4
signature_bytes = base64.b64decode(stem.util.str_tools._to_bytes(server_descriptor.ed25519_signature) + b'=' * missing_padding)
missing_padding = len(server_descriptor.ed25519_signature) % 4
signature_bytes = base64.b64decode(stem.util.str_tools._to_bytes(server_descriptor.ed25519_signature) + b'=' * missing_padding)

try:
verify_key = Ed25519PublicKey.from_public_bytes(self.key)
verify_key.verify(signature_bytes, descriptor_sha256_digest)
except InvalidSignature:
raise ValueError('Descriptor Ed25519 certificate signature invalid (Signature was forged or corrupt)')
try:
verify_key = Ed25519PublicKey.from_public_bytes(self.key)
verify_key.verify(signature_bytes, descriptor_sha256_digest)
except InvalidSignature:
raise ValueError('Descriptor Ed25519 certificate signature invalid (Signature was forged or corrupt)')
else:
if b'signature' not in descriptor_content:
raise ValueError("Descriptor doesn't have a signature entry")

signed_content = ED25519_HSV3_DESCRIPTOR_PREFIX + descriptor_content[:descriptor_content.index(b'signature ')]
print(f"### signed_content: {signed_content}")
print(f"### len(signed_content) = {len(signed_content)}")
print(f"### signed_content[0] = {hex(signed_content[0])}")
print(f"### signed_content[-1] = {hex(signed_content[-1])}")
descriptor_sha256_digest = hashlib.sha256(signed_content).digest()
print(f"### sha256(descriptor): {descriptor_sha256_digest}")

missing_padding = len(server_descriptor.signature) % 4
signature_bytes = base64.b64decode(stem.util.str_tools._to_bytes(server_descriptor.signature) + b'=' * missing_padding)
try:
# key_bytes = self.extensions[0].data
key_bytes = self.key
print(f"### signature_bytes: {signature_bytes}")
print(f"### len(signature_bytes): {len(signature_bytes)}")
print(f"### key_bytes: {key_bytes}")
print(f"### len(key_bytes): {len(key_bytes)}")
verify_key = Ed25519PublicKey.from_public_bytes(key_bytes)
print(f"### verify_key: {verify_key}")
# XXX !!! looks like tor is signing the whole content and not a hash digest
#verify_key.verify(signature_bytes, descriptor_sha256_digest)
verify_key.verify(signature_bytes, signed_content)
except InvalidSignature:
raise ValueError('Descriptor Ed25519 certificate signature invalid (Signature was forged or corrupt)')
@@ -0,0 +1,348 @@
import base64
import binascii
import collections
import hashlib
import io
import struct

import stem.prereq
import stem.util.connection
import stem.util.str_tools
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

from stem.descriptor import (
PGP_BLOCK_END,
Descriptor,
_descriptor_content,
_descriptor_components,
_read_until_keywords,
_bytes_for_block,
_value,
_parse_simple_line,
_parse_timestamp_line,
_parse_key_block,
_random_date,
_random_crypto_blob,
)

if stem.prereq._is_lru_cache_available():
from functools import lru_cache
else:
from stem.util.lru_cache import lru_cache

REQUIRED_FIELDS = {
'hs-descriptor',
'descriptor-lifetime',
'descriptor-signing-key-cert',
'revision-counter',
'superencrypted',
'signature',
}


INTRODUCTION_POINTS_ATTR = {
'link_specifier': None,
'onion_key': None,
'auth_key': None,
'enc_key': None,
'enc_key_cert': None,
'legacy_key': None,
'legacy_key_cert': None,
}

# introduction-point fields that can only appear once

SINGLE_INTRODUCTION_POINT_FIELDS = [
'introduction-point',
'onion-key',
'auth-key',
'enc-key',
'enc-key-cert',
'legacy-key',
'legacy-key-cert',
]

class IntroductionPoints(collections.namedtuple('IntroductionPoints', INTRODUCTION_POINTS_ATTR.keys())):
pass


def _parse_file(descriptor_file, validate = False, onion_address = None, **kwargs):
while True:
descriptor_content = _read_until_keywords('signature', descriptor_file)

# we've reached the 'signature', now include the pgp style block
block_end_prefix = PGP_BLOCK_END.split(' ', 1)[0]
descriptor_content += _read_until_keywords(block_end_prefix, descriptor_file, True)

if descriptor_content:
if descriptor_content[0].startswith(b'@type'):
descriptor_content = descriptor_content[1:]

yield Hsv3Descriptor(bytes.join(b'', descriptor_content), validate, onion_address=onion_address, **kwargs)
else:
break # done parsing file


def _parse_hs_descriptor_line(descriptor, entries):
value = _value('hs-descriptor', entries)

if value.isdigit():
descriptor.hs_descriptor = int(value)
else:
raise ValueError('version line must have a positive integer value: %s' % value)


def _parse_create2_formats_line(descriptor, entries):
value = _value('create2-formats', entries)

if value.isdigit():
descriptor.create2_formats = int(value)
else:
raise ValueError('create2-formats line must have a positive integer value: %s' % value)


def _parse_identity_ed25519_line(descriptor, entries):
_parse_key_block('descriptor-signing-key-cert', 'ed25519_certificate', 'ED25519 CERT')(descriptor, entries)

if descriptor.ed25519_certificate:
cert_lines = descriptor.ed25519_certificate.split('\n')

if cert_lines[0] == '-----BEGIN ED25519 CERT-----' and cert_lines[-1] == '-----END ED25519 CERT-----':
descriptor.certificate = stem.descriptor.certificate.Ed25519Certificate.parse(''.join(cert_lines[1:-1]))


def _parse_superencrypted_line(descriptor, entries):
_, block_type, block_contents = entries['superencrypted'][0]

if not block_contents or block_type != 'MESSAGE':
raise ValueError("'superencrypted' should be followed by a MESSAGE block, but was a %s" % block_type)

descriptor.superencrypted_encoded = block_contents

try:
descriptor.introduction_points_content = _bytes_for_block(block_contents)
except TypeError:
raise ValueError("'introduction-points' isn't base64 encoded content:\n%s" % block_contents)

descriptor.introduction_points_salt = descriptor.introduction_points_content[:16]
descriptor.introduction_points_encrypted = descriptor.introduction_points_content[16:-32]
descriptor.introduction_points_mac = descriptor.introduction_points_content[-32:]




def _parse_hs_descriptor_lifetime(descriptor, entries):
value = _value('descriptor-lifetime', entries)

if value.isdigit():
descriptor.descriptor_lifetime = int(value)
else:
raise ValueError('descriptor-lifetime line must have a positive integer value: %s' % value)


def _parse_revision_counter(descriptor, entries):
value = _value('revision-counter', entries)

if value.isdigit():
descriptor.revision_counter = int(value)
else:
raise ValueError('revision-counter line must have a positive integer value: %s' % value)


_parse_signature = _parse_simple_line('signature', 'signature')


class Hsv3Descriptor(Descriptor):
"""
"""

TYPE_ANNOTATION_NAME = 'hsv3-descriptor'

ATTRIBUTES = {
'hs_descriptor': (None, _parse_hs_descriptor_line),
'descriptor_lifetime': (None, _parse_hs_descriptor_lifetime),
'descriptor_signing_key_cert': (None, _parse_identity_ed25519_line),
'revision_counter': (None, _parse_revision_counter),
'superencrypted_encoded': (None, _parse_superencrypted_line),
'create2-formats': (None, _parse_create2_formats_line),
'signature': (None, _parse_signature),
}

PARSER_FOR_LINE = {
'hs-descriptor': _parse_hs_descriptor_line,
'descriptor-lifetime': _parse_hs_descriptor_lifetime,
'descriptor-signing-key-cert': _parse_identity_ed25519_line,
'revision-counter': _parse_revision_counter,
'superencrypted': _parse_superencrypted_line,
'create2-formats': _parse_create2_formats_line,
'signature': _parse_signature,
}

def __init__(self, raw_contents, validate = False, skip_crypto_validation = False, onion_address = None):
print(f"FUCK: onion_address: {onion_address}")
self.onion_address = onion_address
super(Hsv3Descriptor, self).__init__(raw_contents, lazy_load = not validate)
entries = _descriptor_components(raw_contents, validate, non_ascii_fields = ('introduction-points'))

if validate:
for keyword in REQUIRED_FIELDS:
if keyword not in entries:
raise ValueError("Hidden service descriptor must have a '%s' entry" % keyword)
elif keyword in entries and len(entries[keyword]) > 1:
raise ValueError("The '%s' entry can only appear once in a hidden service descriptor" % keyword)

if 'hs-descriptor' != list(entries.keys())[0]:
raise ValueError("Hidden service descriptor must start with a 'hs-descriptor' entry")
elif 'signature' != list(entries.keys())[-1]:
raise ValueError("Hidden service descriptor must end with a 'signature' entry")

# print(f"### entries: {entries}")
self._parse(entries, validate)

if not skip_crypto_validation and stem.prereq.is_crypto_available():
print(f"#### descriptor_signing_key_cert: {self.descriptor_signing_key_cert}")
print(f"#### certificate: {self.certificate}")
print(f"#### signature: {self.signature}")
signed_digest = self.certificate.validate(self)
# self.blinded_public_key1 = self.certificate.key # easy to mix these up :)
# self.blinded_public_key2 = self.certificate.extensions[0].data # easy to mix these up :)
# XXX does the above validate()^ do enough?
# XXX do we need to compute and store the below digest?
# digest_content = self._content_range('hs-descriptor ', '\nsignature ')
# content_digest = hashlib.sha1(digest_content).hexdigest().upper()

# if signed_digest != content_digest:
# raise ValueError('Decrypted digest does not match local digest (calculated: %s, local: %s)' % (signed_digest, content_digest))

# SECRET_DATA = blinded-public-key
# STRING_CONSTANT = "hsdir-superencrypted-data"
# credential = H("credential" | public-identity-key)
# subcredential = H("subcredential" | credential | blinded-public-key).
# subcredential = H("subcredential" | H("credential" | public-identity-key) | blinded-public-key)
# public-identity-key comes from the onion address
# blinded-public-key comes from the cert in the descriptor
# onion_address = base32(PUBKEY || CHECKSUM || VERSION) + ".onion"
onion_addr_bytes = base64.b32decode(self.onion_address.upper())
print(f"onion_addr_bytes: {onion_addr_bytes}")
pubkey, checksum, version = struct.unpack('!32s2sb', onion_addr_bytes)
print(f"pubkey: {pubkey}")
print(f"checksum: {checksum}")
print(f"version: {version}")
# XXX verify checksum
self.public_identity_key = pubkey
credential = hashlib.sha3_256(b"credential" + self.public_identity_key).digest()
subcredential1 = hashlib.sha3_256(b"subcredential" + credential + self.certificate.key).digest()
subcredential2 = hashlib.sha3_256(b"subcredential" + credential + self.certificate.extensions[0].data).digest()

print(f"subcredential1: {subcredential1}")
print(f"subcredential2: {subcredential2}")
# secret_input = SECRET_DATA | subcredential | INT_8(revision_counter)
secret_input1 = self.certificate.key + subcredential1 + struct.pack('>Q', self.revision_counter)
secret_input2 = self.certificate.extensions[0].data + subcredential2 + struct.pack('>Q', self.revision_counter)
print(f"secret_input1: {secret_input1}")
print(f"secret_input2: {secret_input2}")
kdf1 = hashlib.shake_256()
kdf2 = hashlib.shake_256()
kdf1.update(secret_input1 + self.introduction_points_salt + b"hsdir-superencrypted-data")
kdf2.update(secret_input2 + self.introduction_points_salt + b"hsdir-superencrypted-data")
keys1 = hashlib.shake_256.digest(kdf1, 32 + 16 + 32)
keys2 = hashlib.shake_256.digest(kdf2, 32 + 16 + 32)
print(f"keys1: {keys1}")
print(f"keys2: {keys2}")
# 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
sec_key1 = keys1[:32]
sec_key2 = keys2[:32]
sec_iv1 = keys1[32:32+16]
sec_iv2 = keys2[32:32+16]
mac_key1 = keys1[32+16:]
mac_key2 = keys2[32+16:]
cipher1 = Cipher(algorithms.AES(sec_key1), modes.CTR(sec_iv1), default_backend())
cipher2 = Cipher(algorithms.AES(sec_key2), modes.CTR(sec_iv2), default_backend())
decryptor1 = cipher1.decryptor()
decryptor2 = cipher2.decryptor()
decrypted1 = decryptor1.update(self.introduction_points_encrypted) + decryptor1.finalize()
decrypted2 = decryptor2.update(self.introduction_points_encrypted) + decryptor2.finalize()
print(f"decrypted1: {decrypted1}")
print(f"decrypted2: {decrypted2}")
end_index = decrypted2.find(b"\n-----END MESSAGE-----", 0)
self.first_layer_plaintext = decrypted2[:end_index+len("\n-----END MESSAGE-----")]
begin = self.first_layer_plaintext.find(b"\n-----BEGIN MESSAGE-----\n")
begin += len(b"\n-----BEGIN MESSAGE-----\n")
end = self.first_layer_plaintext.find(b"\n-----END MESSAGE-----", 0)
self.second_layer_ciphertext_b64 = self.first_layer_plaintext[begin:end]
self.second_layer_ciphertext = base64.b64decode(self.second_layer_ciphertext_b64)
print(f"second_layer_ciphertext_b64: {self.second_layer_ciphertext_b64}")

# XXX only doing non-client-auth for now
inner_salt = self.second_layer_ciphertext[:16]
inner_encrypted = self.second_layer_ciphertext[16:-32]
inner_mac = self.second_layer_ciphertext[-32:]
credential_inner = hashlib.sha3_256(b"credential" + self.public_identity_key).digest()
subcredential_inner = hashlib.sha3_256(b"subcredential" + credential_inner + self.certificate.extensions[0].data).digest()
secret_input_inner = self.certificate.extensions[0].data + subcredential_inner + struct.pack('>Q', self.revision_counter)
kdf_inner = hashlib.shake_256()
kdf_inner.update(secret_input_inner + inner_salt + b"hsdir-encrypted-data")
keys_inner = hashlib.shake_256.digest(kdf_inner, 32 + 16 + 32)
print(f"keys_inner: {keys_inner}")
print(f"len(keys_inner): {len(keys_inner)}")
sec_key_inner = keys_inner[:32]
sec_iv_inner = keys_inner[32:32+16]
mac_key_inner = keys_inner[32+16:]
cipher_inner = Cipher(algorithms.AES(sec_key_inner), modes.CTR(sec_iv_inner), default_backend())
decryptor_inner = cipher_inner.decryptor()
self.decrypted_inner = decryptor_inner.update(inner_encrypted) + decryptor_inner.finalize()
print(f"decrypted_inner: {self.decrypted_inner.decode()}")
else:
self._entries = entries

@staticmethod
def _parse_introduction_points(content):
"""
Provides the parsed list of IntroductionPoints for the unencrypted content.
"""

introduction_points = []
content_io = io.BytesIO(content)

while True:
content = b''.join(_read_until_keywords('introduction-point', content_io, ignore_first = True))

if not content:
break # reached the end

attr = dict(INTRODUCTION_POINTS_ATTR)
entries = _descriptor_components(content, False)

for keyword, values in list(entries.items()):
value, block_type, block_contents = values[0]
if keyword in SINGLE_INTRODUCTION_POINT_FIELDS and len(values) > 1:
raise ValueError("'%s' can only appear once in an introduction-point block, but appeared %i times" % (keyword, len(values)))
elif keyword == 'introduction-point':
attr['link_specifier'] = value
elif keyword == 'onion-key':
attr['onion_key'] = value
elif keyword == 'auth-key':
attr['auth_key'] = stem.descriptor.certificate.Ed25519Certificate.parse(
''.join(block_contents.splitlines()[1:-1]))
elif keyword == 'enc-key':
attr['enc_key'] = value
elif keyword == 'enc-key-cert':
attr['enc_key_cert'] = stem.descriptor.certificate.Ed25519Certificate.parse(
''.join(block_contents.splitlines()[1:-1]))
elif keyword == 'legacy-key':
attr['legacy_key'] = block_contents
elif keyword == 'legacy-key-cert':
attr['legacy_key_cert'] = block_contents

introduction_points.append(IntroductionPoints(**attr))

return introduction_points

@lru_cache()
def introduction_points(self, authentication_cookie = None):
content = self.decrypted_inner[self.decrypted_inner.find(b'\n')+1:]
return Hsv3Descriptor._parse_introduction_points(content)
@@ -0,0 +1,224 @@
hs-descriptor 3
descriptor-lifetime 180
descriptor-signing-key-cert
-----BEGIN ED25519 CERT-----
AQgABl5+AQoPXRnCGEOxIup3AcjQXb8npNiUFm2Qv7A6JKk/K+EuAQAgBAD18iUD
nbkUblnUvTHzipq4bcr6aPyFVB42Ptobg4xr8s3VjHiJtjs9MDEdr6nXS7UlyhEl
78vsuFEvLp7cvAgGxYY1xGXdn5RdHMCdi8W9yZLKMQX9OuJckmp1C6q+cA4=
-----END ED25519 CERT-----
revision-counter 42
superencrypted
-----BEGIN MESSAGE-----
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
eFym149F56B0yg5FR85Arg==
-----END MESSAGE-----
signature Of+jvQKzH9ot2NV5twlDO2CFbzLSB4absWTwG58TCHb+TWgQi3z6SZIoTnGGY/uicJgEkCN++bZZR49GiyHyCQ