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
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
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")