Tests onions v3 are OK

master
Christophe Mehay 5 years ago committed by Christophe Mehay
parent 1ed76e069e
commit d043233429

@ -41,9 +41,6 @@ class Ed25519():
def as_key(self, h):
return 2**(self.length - 2) + (self.from_bytes(h) & key_mask)
def to_num(self, h):
return 2**(self.length - 2) + (self.from_bytes(h))
def secret_key(self):
""" pick a random secret key """
m = os.urandom(1024)
@ -60,7 +57,7 @@ class Ed25519():
return self.point_to_bytes(c)
def public_key_from_byte_key(self, hash):
c = self.outer(self.B, self.to_num(hash))
c = self.outer(self.B, int.from_bytes(hash[:32], 'little'))
return self.point_to_bytes(c)
def inverse(self, x):
@ -119,8 +116,10 @@ class Ed25519():
def inner(self, P, Q):
""" inner product on the curve, between two points """
x = (P.x * Q.y + Q.x * P.y) * self.inverse(1 + self.d * P.x * Q.x * P.y * Q.y)
y = (P.y * Q.y + P.x * Q.x) * self.inverse(1 - self.d * P.x * Q.x * P.y * Q.y)
x = (P.x * Q.y + Q.x * P.y) * \
self.inverse(1 + self.d * P.x * Q.x * P.y * Q.y)
y = (P.y * Q.y + P.x * Q.x) * \
self.inverse(1 - self.d * P.x * Q.x * P.y * Q.y)
return Point(x % self.q, y % self.q)
def outer(self, P, n):

@ -32,6 +32,9 @@ class Onion(ABC):
_priv = None
_pub = None
_hidden_service_path = None
_priv_key_filename = None
_pub_key_filename = None
_host_filename = None
_version = None
def __init__(self,
@ -54,10 +57,9 @@ class Onion(ABC):
'Generate new private key'
...
@abstractmethod
def set_private_key_from_file(self, file: BinaryIO):
'Load private key from file'
...
self.set_private_key(file.read())
@abstractmethod
def set_private_key(self, key: bytes) -> None:
@ -69,15 +71,37 @@ class Onion(ABC):
'Generate pub key from priv key and save both in instance'
...
@abstractmethod
def load_hidden_service(self, path: str) -> None:
'Load key from hidden service'
...
if not os.path.isdir(path):
raise Exception(
'{path} should be an existing directory'.format(path=path)
)
if self._priv_key_filename not in os.listdir(path):
raise EmptyDirException(
'private_key file not found in {path}'.format(path=path)
)
with open(os.path.join(path, self._priv_key_filename), 'rb') as f:
self.set_private_key_from_file(f)
@abstractmethod
def write_hidden_service(self, path: str, force: bool = False) -> None:
'Write hidden service keys to directory'
...
def write_hidden_service(self, path: str = None,
force: bool = False) -> None:
path = path or self._hidden_service_path
if not path:
raise Exception('Missing hidden service path')
if not os.path.exists(path):
raise Exception(
'{path} should be an existing directory'.format(path=path)
)
if os.path.exists(
os.path.join(path, self._priv_key_filename)
) and not force:
raise Exception(
'Use force=True for non empty hidden service directory'
)
with open(os.path.join(path, self._priv_key_filename), 'wb') as f:
f.write(self._get_private_key_has_native())
with open(os.path.join(path, self._host_filename), 'w') as f:
f.write(self.onion_hostname)
def get_available_private_key_formats(self) -> list:
'Get private key export availables formats'
@ -115,7 +139,7 @@ class Onion(ABC):
...
@property
def onion_address(self) -> str:
def onion_hostname(self) -> str:
return "{onion}.onion".format(
onion=self.get_onion_str()
)
@ -129,6 +153,8 @@ class OnionV2(Onion):
'''
Tor onion address v2 implement
'''
_priv_key_filename = 'private_key'
_host_filename = 'hostname'
_version = 2
@ -144,10 +170,6 @@ class OnionV2(Onion):
'Add private key'
self._save_keypair(RSA.importKey(key.strip()))
def set_private_key_from_file(self, file: BinaryIO):
'Load private key from file'
self.set_private_key(file.read())
def _get_private_key_has_native(self) -> bytes:
'Get RSA private key like in PEM'
return self._get_private_key_has_pem()
@ -161,36 +183,6 @@ class OnionV2(Onion):
super().get_public_key()
return self._pub
def load_hidden_service(self, path: str) -> None:
if not os.path.isdir(path):
raise Exception(
'{path} should be an existing directory'.format(path=path)
)
if 'private_key' not in os.listdir(path):
raise EmptyDirException(
'private_key file not found in {path}'.format(path=path)
)
with open(os.path.join(path, 'private_key'), 'rb') as f:
self.set_private_key_from_file(f)
def write_hidden_service(self, path: str = None,
force: bool = False) -> None:
path = path or self._hidden_service_path
if not path:
raise Exception('Missing hidden service path')
if not os.path.exists(path):
raise Exception(
'{path} should be an existing directory'.format(path=path)
)
if os.path.exists(os.path.join(path, 'private_key')) and not force:
raise Exception(
'Use force=True for non empty hidden service directory'
)
with open(os.path.join(path, 'private_key'), 'wb') as f:
f.write(self._get_private_key_has_native())
with open(os.path.join(path, 'hostname'), 'w') as f:
f.write(self.onion_address)
def get_onion_str(self) -> str:
'Compute onion address string'
return b32encode(sha1(self._pub[22:]).digest()[:10]).decode().lower()
@ -204,7 +196,9 @@ class OnionV3(Onion):
_header_priv = b'== ed25519v1-secret: type0 ==\x00\x00\x00'
_header_pub = b'== ed25519v1-public: type0 ==\x00\x00\x00'
_test = False
_priv_key_filename = 'hs_ed25519_secret_key'
_pub_key_filename = 'hs_ed25519_public_key'
_host_filename = 'hostname'
_version = 3
@ -247,39 +241,12 @@ class OnionV3(Onion):
super().get_public_key()
return self._header_pub + self._pub
def load_hidden_service(self, path: str) -> None:
if not os.path.isdir(path):
raise Exception(
'{path} should be an existing directory'.format(path=path)
)
if 'hs_ed25519_secret_key' not in os.listdir(path):
raise EmptyDirException(
'hs_ed25519_secret_key file not found in {path}'.format(
path=path
)
)
with open(os.path.join(path, 'hs_ed25519_secret_key'), 'rb') as f:
self.set_private_key_from_file(f)
def write_hidden_service(self, path: str = None,
force: bool = False) -> None:
path = path or self._hidden_service_path
if not path:
raise Exception('Missing hidden service path')
if not os.path.exists(path):
raise Exception(
'{path} should be an existing directory'.format(path=path)
)
if os.path.exists(os.path.join(path, 'private_key')) and not force:
raise Exception(
'Use force=True for non empty hidden service directory'
)
with open(os.path.join(path, 'hs_ed25519_secret_key'), 'wb') as f:
f.write(self._get_private_key_has_native())
with open(os.path.join(path, 'hs_ed25519_public_key'), 'wb') as f:
super().write_hidden_service(path, force)
with open(os.path.join(path, self._pub_key_filename), 'wb') as f:
f.write(self.get_public_key())
with open(os.path.join(path, 'hostname'), 'w') as f:
f.write(self.onion_address)
def get_onion_str(self) -> str:
'Compute onion address string'

@ -1,3 +1,4 @@
import os
from base64 import b64decode
import pytest
@ -10,64 +11,76 @@ class _testOnion:
private_key = None
public_key = None
onion_address = None
onion_hostname = None
onion_cls = None
version = None
check_method = {
'priv': 'get_private_key',
'pub': 'get_public_key',
'onion': 'onion_hostname',
}
def generate_new_key(self):
return self.onion_cls().get_private_key()
def test_import_key(self):
o = self.onion_cls(private_key=self.private_key)
assert o.get_public_key() == self.public_key
assert o.onion_address == self.onion_address
assert o.onion_hostname == self.onion_hostname
assert o.get_private_key() == self.private_key
def test_generate_key(self):
o = self.onion_cls()
assert o.onion_address.endswith('.onion')
assert len(o.onion_address) == len(self.onion_address)
assert o.onion_hostname.endswith('.onion')
assert len(o.onion_hostname) == len(self.onion_hostname)
def test_import_file(self, fs):
fs.create_file('/test_tor/private_key', contents=self.private_key)
path = os.path.join('/test_tor', self.files['priv'])
fs.create_file(path, contents=self.private_key)
o = self.onion_cls()
with open('/test_tor/private_key', 'rb') as f:
path = os.path.join('/test_tor', self.files['priv'])
with open(path, 'rb') as f:
o.set_private_key_from_file(f)
assert o.onion_address == self.onion_address
assert o.onion_hostname == self.onion_hostname
def test_import_hidden_directory(self, tmpdir):
d = tmpdir.mkdir("hidden_directory")
f = d.join('private_key')
f = d.join(self.files['priv'])
f.write_binary(self.private_key)
o = self.onion_cls(hidden_service_path=d)
assert o.onion_address == self.onion_address
assert o.onion_hostname == self.onion_hostname
def test_write_hidden_directory(self, tmpdir):
d = tmpdir.mkdir("hidden_directory")
o = self.onion_cls(private_key=self.private_key)
o.write_hidden_service(path=str(d))
assert d.join('private_key').read() == self.private_key.decode()
assert d.join('hostname').read() == o.onion_address
for file_type, file in self.files.items():
method = getattr(o, self.check_method[file_type])
check = method() if callable(method) else method
check = check.encode() if isinstance(check, str) else check
assert d.join(file).read_binary() == check
def test_import_empty_hidden_directory(self, tmpdir):
d = tmpdir.mkdir("hidden_directory")
o = self.onion_cls(hidden_service_path=d)
o.write_hidden_service()
assert d.join('private_key').read() == o.get_private_key().decode()
assert d.join('hostname').read() == o.onion_address
assert d.join(self.files['priv']).read_binary() == o.get_private_key()
assert d.join(self.files['onion']).read() == o.onion_hostname
def test_import_hidden_directory_with_new_key(self, tmpdir):
d = tmpdir.mkdir("hidden_directory")
f = d.join('private_key')
f = d.join(self.files['priv'])
f.write_binary(self.generate_new_key())
o = self.onion_cls(hidden_service_path=d,
private_key=self.private_key)
with pytest.raises(Exception):
o.write_hidden_service()
o.write_hidden_service(force=True)
assert d.join('private_key').read() == o.get_private_key().decode()
assert d.join('hostname').read() == o.onion_address
assert d.join(self.files['priv']).read_binary() == o.get_private_key()
assert d.join(self.files['onion']).read() == o.onion_hostname
def test_version(self):
assert self.onion_cls().version == str(self.version)
@ -99,13 +112,13 @@ ZxIWGsO2PwHM1infkbhlBakR6DGQfpE31L1ZKTUxY0OexKbW088v8qCOfjD9Zk1i
80JP4xzfWQcwFZ5yM/0fkhm3zLXqXdEahvRthmFsS8OWusRs/04U247ryTm4k5S0
Ch5OTBuvMLzQ8W0yDwIDAQAB
''')
onion_address = 'wcet3bgkj4purdfx.onion'
onion_hostname = 'wcet3bgkj4purdfx.onion'
onion_cls = OnionV2
files_in_hidden_dir = {
files = {
'priv': 'private_key',
'pub': None,
'onion': 'hostname',
}
version = 2
@ -121,12 +134,12 @@ PT0gZWQyNTUxOXYxLXB1YmxpYzogdHlwZTAgPT0AAAC9kzftiea/kb+TWlCEVNpfUJLVk+rFIoMG
m9/hW13isA==
''')
onion_address = (
onion_hostname = (
'xwjtp3mj427zdp4tljiiivg2l5ijfvmt5lcsfaygtpp6cw254kykvpyd.onion'
)
onion_cls = OnionV3
files_in_hidden_dir = {
files = {
'priv': 'hs_ed25519_secret_key',
'pub': 'hs_ed25519_public_key',
'onion': 'hostname',

Loading…
Cancel
Save