コード例 #1
0
ファイル: hidden_service_v3.py プロジェクト: nmathewson/stem
    def test_descriptor_creation(self):
        """
    HiddenServiceDescriptorV3 creation.
    """

        # minimal descriptor

        self.assertTrue(HiddenServiceDescriptorV3.content().startswith(
            b'hs-descriptor 3\ndescriptor-lifetime 180\n'))
        self.assertEqual(180, HiddenServiceDescriptorV3.create().lifetime)

        # specify the parameters

        desc = HiddenServiceDescriptorV3.create(
            {
                'hs-descriptor': '4',
                'descriptor-lifetime': '123',
                'descriptor-signing-key-cert':
                '\n-----BEGIN ED25519 CERT-----\nmalformed block\n-----END ED25519 CERT-----',
                'revision-counter': '5',
                'superencrypted':
                '\n-----BEGIN MESSAGE-----\nmalformed block\n-----END MESSAGE-----',
                'signature': 'abcde',
            },
            validate=False)

        self.assertEqual(4, desc.version)
        self.assertEqual(123, desc.lifetime)
        self.assertEqual(
            None, desc.signing_cert
        )  # malformed cert dropped because validation is disabled
        self.assertEqual(5, desc.revision_counter)
        self.assertEqual(
            '-----BEGIN MESSAGE-----\nmalformed block\n-----END MESSAGE-----',
            desc.superencrypted)
        self.assertEqual('abcde', desc.signature)

        # include introduction points

        from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

        identity_key = Ed25519PrivateKey.generate()
        onion_address = HiddenServiceDescriptorV3.address_from_identity_key(
            identity_key)

        desc = HiddenServiceDescriptorV3.create(
            identity_key=identity_key,
            inner_layer=InnerLayer.create(introduction_points=[
                IntroductionPointV3.create_for_address('1.1.1.1', 9001),
                IntroductionPointV3.create_for_address('2.2.2.2', 9001),
                IntroductionPointV3.create_for_address('3.3.3.3', 9001),
            ]),
        )

        inner_layer = desc.decrypt(onion_address)
        self.assertEqual(3, len(inner_layer.introduction_points))
        self.assertEqual(
            '1.1.1.1',
            inner_layer.introduction_points[0].link_specifiers[0].address)
コード例 #2
0
ファイル: onionbalance.py プロジェクト: gits7r/onionbalance
    def load_config_file(self):
        config_data = util.read_config_data_from_file(self.config_path)
        logger.debug("Onionbalance config data: %s", config_data)

        # Do some basic validation
        if "services" not in config_data:
            logger.error("Config file is bad. 'services' is missing. Did you make it with onionbalance-config?")
            sys.exit(1)

        # More validation
        for service in config_data["services"]:
            if "key" not in service:
                logger.error("Config file is bad. 'key' is missing. Did you make it with onionbalance-config?")
                sys.exit(1)

            if "instances" not in service:
                logger.error("Config file is bad. 'instances' is missing. Did you make it with onionbalance-config?")
                sys.exit(1)

            for instance in service["instances"]:
                if "address" not in instance:
                    logger.error("Config file is wrong. 'address' missing from instance.")
                    sys.exit(1)

                # Validate that the onion address is legit
                try:
                    _ = HiddenServiceDescriptorV3.identity_key_from_address(instance["address"])
                except ValueError:
                    logger.error("Cannot load instance with address: '%s'.", instance["address"])
                    logger.error("If you are trying to run onionbalance for v2 onions, please use the --hs-version=v2 switch")
                    sys.exit(1)

        return config_data
コード例 #3
0
    def _load_v3_master_key_from_file(self, master_key_path):
        """
        Load a private key straight from a Tor instance (no OBv3 keys supported)
        and return the private key and onion address.
        """
        try:
            with open(master_key_path, 'rb') as handle:
                pem_key_bytes = handle.read()
        except EnvironmentError as e:
            logger.error("Unable to read service private key file ('%s')", e)
            sys.exit(1)

        try:
            master_private_key = tor_ed25519.load_tor_key_from_disk(pem_key_bytes)
        except ValueError:
            logger.error("Please provide path to a valid Tor master key")
            sys.exit(1)
        identity_pub_key = master_private_key.public_key()
        identity_pub_key_bytes = identity_pub_key.public_bytes(encoding=serialization.Encoding.Raw,
                                                               format=serialization.PublicFormat.Raw)
        master_onion_address = HiddenServiceDescriptorV3.address_from_identity_key(identity_pub_key_bytes)

        # remove the trailing .onion
        master_onion_address = master_onion_address.replace(".onion", "")

        self.v3_loaded_key_from_file = True

        return master_private_key, master_onion_address
コード例 #4
0
  def test_outer_layer_creation(self):
    """
    Outer layer creation.
    """

    from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

    # minimal layer

    self.assertTrue(OuterLayer.content().startswith(b'desc-auth-type x25519\ndesc-auth-ephemeral-key '))
    self.assertEqual('x25519', OuterLayer.create().auth_type)

    # specify the parameters

    desc = OuterLayer.create({
      'desc-auth-type': 'foo',
      'desc-auth-ephemeral-key': 'bar',
      'auth-client': [
        'JNil86N07AA epkaL79NtajmgME/egi8oA qosYH4rXisxda3X7p9b6fw',
        '1D8VBAh9hdM 6K/uO3sRqBp6URrKC7GB6Q ElwRj5+6SN9kb8bRhiiQvA',
      ],
      'encrypted': '\n-----BEGIN MESSAGE-----\nmalformed block\n-----END MESSAGE-----',
    })

    self.assertEqual('foo', desc.auth_type)
    self.assertEqual('bar', desc.ephemeral_key)
    self.assertEqual('-----BEGIN MESSAGE-----\nmalformed block\n-----END MESSAGE-----', desc.encrypted)

    self.assertEqual({
      '1D8VBAh9hdM': AuthorizedClient(id = b'1D8VBAh9hdM', iv = b'6K/uO3sRqBp6URrKC7GB6Q', cookie = b'ElwRj5+6SN9kb8bRhiiQvA'),
      'JNil86N07AA': AuthorizedClient(id = b'JNil86N07AA', iv = b'epkaL79NtajmgME/egi8oA', cookie = b'qosYH4rXisxda3X7p9b6fw'),
    }, desc.clients)

    self.assertEqual(EXPECTED_OUTER_LAYER, str(desc))

    # create an inner layer then decrypt it

    revision_counter = 5
    blinded_key = stem.util._pubkey_bytes(Ed25519PrivateKey.generate())
    subcredential = HiddenServiceDescriptorV3._subcredential(Ed25519PrivateKey.generate(), blinded_key)

    outer_layer = OuterLayer.create(
      inner_layer = InnerLayer.create(
        introduction_points = [
          IntroductionPointV3.create_for_address('1.1.1.1', 9001),
        ]
      ),
      revision_counter = revision_counter,
      subcredential = subcredential,
      blinded_key = blinded_key,
    )

    inner_layer = InnerLayer._decrypt(outer_layer, revision_counter, subcredential, blinded_key)

    self.assertEqual(1, len(inner_layer.introduction_points))
    self.assertEqual('1.1.1.1', inner_layer.introduction_points[0].link_specifiers[0].address)
コード例 #5
0
  def test_decryption(self):
    """
    Decrypt our descriptor and validate its content.
    """

    desc = HiddenServiceDescriptorV3.from_str(HS_DESC_STR)
    inner_layer = desc.decrypt(HS_ADDRESS)

    self.assertEqual(INNER_LAYER_STR, str(inner_layer))
    self.assertEqual(OUTER_LAYER_STR.rstrip('\x00'), str(inner_layer.outer))
コード例 #6
0
ファイル: hidden_service_v3.py プロジェクト: nmathewson/stem
 def test_identity_key_from_address(self):
     self.assertEqual(
         HS_PUBKEY,
         HiddenServiceDescriptorV3.identity_key_from_address(HS_ADDRESS))
     self.assertRaisesWith(
         ValueError, "'boom.onion' isn't a valid hidden service v3 address",
         HiddenServiceDescriptorV3.identity_key_from_address, 'boom')
     self.assertRaisesWith(
         ValueError, 'Bad checksum (expected def7 but was 842e)',
         HiddenServiceDescriptorV3.identity_key_from_address, '5' * 56)
コード例 #7
0
    def load_v3_master_key(self, master_key_path):
        if master_key_path: # load key from file
            return self._load_v3_master_key_from_file(master_key_path)
        else: # generate new v3 key
            master_private_key = Ed25519PrivateKey.generate()
            master_public_key = master_private_key.public_key()
            master_pub_key_bytes = master_public_key.public_bytes(encoding=serialization.Encoding.Raw,
                                                                  format=serialization.PublicFormat.Raw)
            master_onion_address = HiddenServiceDescriptorV3.address_from_identity_key(master_pub_key_bytes)
            # cut out the onion since that's what the rest of the code expects
            master_onion_address = master_onion_address.replace(".onion", "")

            return master_private_key, master_onion_address
コード例 #8
0
ファイル: service.py プロジェクト: vporton/onionbalance
    def _load_service_keys(self, service_config_data, config_path):
        # First of all let's load up the private key
        key_fname = service_config_data['key']
        config_directory = os.path.dirname(config_path)
        if not os.path.isabs(key_fname):
            key_fname = os.path.join(config_directory, key_fname)

        try:
            with open(key_fname, 'rb') as handle:
                pem_key_bytes = handle.read()
        except EnvironmentError as e:
            logger.critical("Unable to read service private key file ('%s')",
                            e)
            raise BadServiceInit

        # Get the service private key
        # First try with the OBv3 PEM format
        identity_priv_key = None
        try:
            identity_priv_key = serialization.load_pem_private_key(
                pem_key_bytes, password=None, backend=default_backend())
        except ValueError as e:
            logger.warning(
                "Service private key not in OBv3 format ('%s'). Trying tor's format...",
                e)

        # If the key was not in OBv3 PEM format, try the Tor binary format
        if not identity_priv_key:
            try:
                identity_priv_key = tor_ed25519.load_tor_key_from_disk(
                    pem_key_bytes)
                self.is_priv_key_in_tor_format = True
            except ValueError as e:
                logger.warning(
                    "Service private key not in Tor format either ('%s'). Aborting.",
                    e)
                raise BadServiceInit

        # Get onion address
        identity_pub_key = identity_priv_key.public_key()
        identity_pub_key_bytes = identity_pub_key.public_bytes(
            encoding=serialization.Encoding.Raw,
            format=serialization.PublicFormat.Raw)
        onion_address = HiddenServiceDescriptorV3.address_from_identity_key(
            identity_pub_key_bytes)

        logger.warning("Loaded onion %s from %s", onion_address, key_fname)

        return identity_priv_key, onion_address
コード例 #9
0
    def load_config_file(self):
        config_data = util.read_config_data_from_file(self.config_path)
        logger.debug("Onionbalance config data: %s", config_data)

        # Do some basic validation
        if "services" not in config_data:
            raise ConfigError(
                "Config file is bad. 'services' is missing. Did you make it with onionbalance-config?"
            )

        # More validation
        for service in config_data["services"]:
            if "key" not in service:
                raise ConfigError(
                    "Config file is bad. 'key' is missing. Did you make it with onionbalance-config?"
                )

            if "instances" not in service:
                raise ConfigError(
                    "Config file is bad. 'instances' is missing. Did you make it with "
                    "onionbalance-config?")

            if not service["instances"]:
                raise ConfigError(
                    "Config file is bad. No backend instances are set. Onionbalance needs at least 1."
                )

            for instance in service["instances"]:
                if "address" not in instance:
                    raise ConfigError(
                        "Config file is wrong. 'address' missing from instance."
                    )

                if not instance["address"]:
                    raise ConfigError(
                        "Config file is bad. Address field is not set.")

                # Validate that the onion address is legit
                try:
                    _ = HiddenServiceDescriptorV3.identity_key_from_address(
                        instance["address"])
                except ValueError:
                    raise ConfigError(
                        "Cannot load instance with address: '{}'. If you are trying to run onionbalance "
                        "for v2 onions, please use the --hs-version=v2 switch".
                        format(instance["address"]))

        return config_data
コード例 #10
0
  def test_blinding(self):
    """
    Create a descriptor with key blinding.
    """

    from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

    expected_blinded_key = b'\xb5\xefEA\xfaI\x1a\xd8*p\xcd\x97\x01\x90O\xa8p\xd3\x10\x16\x8e-\x19\xab+\x92\xbc\xf6\xe7\x92\xc2k'

    desc = HiddenServiceDescriptorV3.create(
      identity_key = Ed25519PrivateKey.from_private_bytes(b'a' * 32),
      blinding_nonce = b'a' * 32,
    )

    self.assertEqual(64, len(desc.signing_cert.signature))
    self.assertEqual(expected_blinded_key, desc.signing_cert.signing_key())
コード例 #11
0
  def test_required_fields(self):
    """
    Check that we require the mandatory fields.
    """

    line_to_attr = {
      'hs-descriptor': 'version',
      'descriptor-lifetime': 'lifetime',
      'descriptor-signing-key-cert': 'signing_cert',
      'revision-counter': 'revision_counter',
      'superencrypted': 'superencrypted',
      'signature': 'signature',
    }

    for line in stem.descriptor.hidden_service.REQUIRED_V3_FIELDS:
      desc_text = HiddenServiceDescriptorV3.content(exclude = (line,))
      expect_invalid_attr_for_text(self, desc_text, line_to_attr[line], None)
コード例 #12
0
    def __init__(self, onion_address, identity_priv_key, blinding_param,
                 intro_points, is_first_desc):
        # Timestamp of the last attempt to assemble this descriptor
        self.last_publish_attempt_ts = None
        # Timestamp we last uploaded this descriptor
        self.last_upload_ts = None
        # Set of responsible HSDirs for last time we uploaded this descriptor
        self.responsible_hsdirs = None

        # Start generating descriptor
        desc_signing_key = Ed25519PrivateKey.generate()

        # Get the intro points for this descriptor and recertify them!
        recertified_intro_points = []
        for ip in intro_points:
            recertified_intro_points.append(
                self._recertify_intro_point(ip, desc_signing_key))

        rev_counter = self._get_revision_counter(identity_priv_key,
                                                 is_first_desc)

        v3_desc_inner_layer = InnerLayer.create(
            introduction_points=recertified_intro_points)
        v3_desc = HiddenServiceDescriptorV3.create(
            blinding_nonce=blinding_param,
            identity_key=identity_priv_key,
            signing_key=desc_signing_key,
            inner_layer=v3_desc_inner_layer,
            revision_counter=int(rev_counter),
        )

        # TODO stem should probably initialize it itself so that it has balance
        # between descriptor creation (where this is not inted) and descriptor
        # parsing (where this is inited)
        v3_desc._inner_layer = v3_desc_inner_layer

        # Check max size is within range
        if len(str(v3_desc)) > params.MAX_DESCRIPTOR_SIZE:
            logger.error(
                "Created descriptor is too big (%d intros). Consider "
                "relaxing number of instances or intro points per instance "
                "(see N_INTROS_PER_INSTANCE)")
            raise BadDescriptor

        super().__init__(onion_address, v3_desc)
コード例 #13
0
    def __init__(self, desc_text, onion_address):
        """
        Parse a descriptor in 'desc_text' and return an ReceivedDescriptor object.

        Raises BadDescriptor if the descriptor cannot be used.
        """
        try:
            v3_desc = HiddenServiceDescriptorV3.from_str(desc_text)
            v3_desc.decrypt(onion_address)
        except ValueError as err:
            logger.warning("Descriptor is corrupted (%s).", err)
            raise BadDescriptor

        self.received_ts = datetime.datetime.utcnow()

        logger.debug("Successfuly decrypted descriptor for %s!", onion_address)

        super().__init__(onion_address, v3_desc)
コード例 #14
0
ファイル: test_v3_keys.py プロジェクト: zscole/onionbalance
    def test_load_tor_privkey(self):
        privkey_bytes = binascii.unhexlify(PRIVKEY_FILE_HEX)
        privkey = tor_ed25519.load_tor_key_from_disk(privkey_bytes)
        pubkey = privkey.public_key()

        # Make sure that the fake instances are right
        self.assertTrue(isinstance(privkey, Ed25519PrivateKey))
        self.assertTrue(isinstance(pubkey, Ed25519PublicKey))

        # Make sure that the public key matches the onion address
        onion_addr_pubkey_bytes = HiddenServiceDescriptorV3.identity_key_from_address(
            ONION_ADDR)
        self.assertEqual(onion_addr_pubkey_bytes, pubkey.public_bytes())

        # Check that signature verification works
        msg = b"07-04-2020 weird days"
        msg_sig = privkey.sign(msg)
        onion_addr_pubkey = tor_ed25519.TorEd25519PublicKey(
            onion_addr_pubkey_bytes)
        onion_addr_pubkey.verify(msg_sig, msg)

        # Now check that it won't just verify any message
        self.assertRaises(Exception, onion_addr_pubkey.verify, msg_sig,
                          b"another message another day")

        # Now check that stem will accept this
        self.assertEqual(stem.util._pubkey_bytes(privkey),
                         pubkey.public_bytes())
        self.assertEqual(stem.util._pubkey_bytes(pubkey),
                         pubkey.public_bytes())

        # Now check that blinding can work
        blinded_key_bytes = stem.descriptor.hidden_service._blinded_pubkey(
            privkey, b"a" * 32)
        blinded_key = tor_ed25519.TorEd25519PublicKey(blinded_key_bytes)
        signature = tor_ed25519._blinded_sign_with_tor_key(
            b"haha", privkey, blinded_key_bytes, b"a" * 32)

        blinded_key.verify(signature, b"haha")
コード例 #15
0
    def _load_service_keys(self, service_config_data, config_path):
        # First of all let's load up the private key
        key_fname = service_config_data['key']
        config_directory = os.path.dirname(config_path)
        if not os.path.isabs(key_fname):
            key_fname = os.path.join(config_directory, key_fname)

        with open(key_fname, 'rb') as handle:
            pem_key_bytes = handle.read()

        identity_priv_key = serialization.load_pem_private_key(
            pem_key_bytes, password=None, backend=default_backend())

        # Get onion address
        identity_pub_key = identity_priv_key.public_key()
        identity_pub_key_bytes = identity_pub_key.public_bytes(
            encoding=serialization.Encoding.Raw,
            format=serialization.PublicFormat.Raw)
        onion_address = HiddenServiceDescriptorV3.address_from_identity_key(
            identity_pub_key_bytes)

        logger.warning("Loaded onion %s from %s", onion_address, key_fname)

        return identity_priv_key, onion_address
コード例 #16
0
 def test_address_from_identity_key(self):
   self.assertEqual(HS_ADDRESS, HiddenServiceDescriptorV3.address_from_identity_key(HS_PUBKEY))