mirror of https://github.com/nucypher/nucypher.git
BytestringSplitter is now its own project.
parent
b35e5b9840
commit
7f21117cb7
|
@ -389,7 +389,7 @@ class Bob(Character):
|
||||||
|
|
||||||
# TODO: Make this much prettier
|
# TODO: Make this much prettier
|
||||||
header, signature, ursula_pubkey_sig, _hrac, (
|
header, signature, ursula_pubkey_sig, _hrac, (
|
||||||
port, interface, ttl) = dht_value_splitter(value, msgpack_remainder=True)
|
port, interface, ttl) = dht_value_splitter(value, msgpack_remainder=True)
|
||||||
|
|
||||||
if header != BYTESTRING_IS_URSULA_IFACE_INFO:
|
if header != BYTESTRING_IS_URSULA_IFACE_INFO:
|
||||||
raise TypeError("Unknown DHT value. How did this get on the network?")
|
raise TypeError("Unknown DHT value. How did this get on the network?")
|
||||||
|
@ -442,7 +442,7 @@ class Bob(Character):
|
||||||
# TODO: Make this prettier
|
# TODO: Make this prettier
|
||||||
header, _signature_for_ursula, pubkey_sig_alice, hrac, encrypted_treasure_map = \
|
header, _signature_for_ursula, pubkey_sig_alice, hrac, encrypted_treasure_map = \
|
||||||
dht_value_splitter(response.content, return_remainder=True)
|
dht_value_splitter(response.content, return_remainder=True)
|
||||||
tmap_messaage_kit = MessageKit.from_bytes(encrypted_treasure_map)
|
tmap_messaage_kit = AdventureKit.from_bytes(encrypted_treasure_map)
|
||||||
return tmap_messaage_kit
|
return tmap_messaage_kit
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
@ -574,8 +574,8 @@ class Ursula(Character, ProxyRESTServer):
|
||||||
def interface_dht_value(self):
|
def interface_dht_value(self):
|
||||||
signature = self.stamp(self.interface_hrac())
|
signature = self.stamp(self.interface_hrac())
|
||||||
return (
|
return (
|
||||||
BYTESTRING_IS_URSULA_IFACE_INFO + signature + self.stamp + self.interface_hrac()
|
BYTESTRING_IS_URSULA_IFACE_INFO + signature + self.stamp + self.interface_hrac()
|
||||||
+ msgpack.dumps(self.dht_interface_info())
|
+ msgpack.dumps(self.dht_interface_info())
|
||||||
)
|
)
|
||||||
|
|
||||||
def interface_hrac(self):
|
def interface_hrac(self):
|
||||||
|
|
|
@ -125,4 +125,4 @@ def generate_self_signed_certificate(common_name, curve, private_key=None, days_
|
||||||
# TODO: What domain here? Not localhost presumably - ENS? #146
|
# TODO: What domain here? Not localhost presumably - ENS? #146
|
||||||
cert = cert.add_extension(x509.SubjectAlternativeName([x509.DNSName(u"localhost")]), critical=False)
|
cert = cert.add_extension(x509.SubjectAlternativeName([x509.DNSName(u"localhost")]), critical=False)
|
||||||
cert = cert.sign(private_key, hashes.SHA512(), default_backend())
|
cert = cert.sign(private_key, hashes.SHA512(), default_backend())
|
||||||
return cert, private_key
|
return cert, private_key
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
from nkms.crypto.constants import PUBLIC_KEY_LENGTH, CAPSULE_LENGTH
|
from nkms.crypto.constants import PUBLIC_KEY_LENGTH, CAPSULE_LENGTH
|
||||||
from nkms.crypto.utils import BytestringSplitter
|
from bytestring_splitter import BytestringSplitter
|
||||||
from umbral.keys import UmbralPublicKey
|
from umbral.keys import UmbralPublicKey
|
||||||
from umbral.pre import Capsule
|
from umbral.pre import Capsule
|
||||||
|
from nkms.crypto.signature import Signature
|
||||||
|
|
||||||
|
|
||||||
key_splitter = BytestringSplitter((UmbralPublicKey, PUBLIC_KEY_LENGTH, {"as_b64": False}))
|
key_splitter = BytestringSplitter((UmbralPublicKey, PUBLIC_KEY_LENGTH, {"as_b64": False}))
|
||||||
capsule_splitter = BytestringSplitter((Capsule, CAPSULE_LENGTH))
|
capsule_splitter = BytestringSplitter((Capsule, CAPSULE_LENGTH))
|
||||||
|
signature_splitter = BytestringSplitter(Signature)
|
||||||
|
|
|
@ -1,131 +1,7 @@
|
||||||
from contextlib import suppress
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import msgpack
|
|
||||||
from umbral.keys import UmbralPublicKey
|
|
||||||
|
|
||||||
from nkms.crypto.api import keccak_digest
|
from nkms.crypto.api import keccak_digest
|
||||||
|
|
||||||
|
|
||||||
class BytestringSplitter(object):
|
|
||||||
|
|
||||||
def __init__(self, *message_types):
|
|
||||||
"""
|
|
||||||
:param message_types: A collection of types of messages to parse.
|
|
||||||
"""
|
|
||||||
self.message_types = []
|
|
||||||
if not message_types:
|
|
||||||
raise ValueError(
|
|
||||||
"Can't make a BytestringSplitter unless you specify what to split!")
|
|
||||||
|
|
||||||
for counter, message_type in enumerate(message_types):
|
|
||||||
# message_types can be tuples (with length and kwargs) or just classes.
|
|
||||||
if isinstance(message_types, tuple):
|
|
||||||
# Here, it's a tuple - these are our message types.
|
|
||||||
self.message_types.extend(message_types)
|
|
||||||
|
|
||||||
# We're ready to break out of the loop, because we
|
|
||||||
# already have our message type.
|
|
||||||
|
|
||||||
# However, before we do, let's address a possible mis-step
|
|
||||||
# by the user and offer a better error message.
|
|
||||||
with suppress(IndexError):
|
|
||||||
if isinstance(message_types[counter + 1], int):
|
|
||||||
raise TypeError("You can't specify the length of the message as a direct argument to the constructor. Instead, pass it as the second argument in a tuple (with the class as the first argument)")
|
|
||||||
# OK, cool - break.
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# OK, it's an object. If it's a tuple, we can just add it.
|
|
||||||
if isinstance(message_type, tuple):
|
|
||||||
self.message_types.append(message_type)
|
|
||||||
else:
|
|
||||||
# Otherwise, it's a class - turn it into a tuple for
|
|
||||||
# compatibility with get_message_meta later.
|
|
||||||
message_type_tuple = message_type,
|
|
||||||
self.message_types.append(message_type_tuple)
|
|
||||||
|
|
||||||
def __call__(self, splittable, return_remainder=False, msgpack_remainder=False):
|
|
||||||
if not any((return_remainder, msgpack_remainder)) and len(self) != len(splittable):
|
|
||||||
raise ValueError(
|
|
||||||
""""Wrong number of bytes to constitute message types {} -
|
|
||||||
need {}, got {} \n Did you mean to return the remainder?""".format(
|
|
||||||
self.message_types, len(self), len(splittable)))
|
|
||||||
if len(self) > len(splittable):
|
|
||||||
raise ValueError(
|
|
||||||
"""Not enough bytes to constitute
|
|
||||||
message types {} - need {}, got {}""".format(self.message_types,
|
|
||||||
len(self),
|
|
||||||
len(splittable)))
|
|
||||||
cursor = 0
|
|
||||||
message_objects = []
|
|
||||||
|
|
||||||
for message_type in self.message_types:
|
|
||||||
message_class, message_length, kwargs = self.get_message_meta(message_type)
|
|
||||||
expected_end_of_object_bytes = cursor + message_length
|
|
||||||
bytes_for_this_object = splittable[cursor:expected_end_of_object_bytes]
|
|
||||||
try:
|
|
||||||
message = message_class.from_bytes(bytes_for_this_object, **kwargs)
|
|
||||||
except AttributeError:
|
|
||||||
message = message_class(bytes_for_this_object, **kwargs)
|
|
||||||
|
|
||||||
message_objects.append(message)
|
|
||||||
cursor = expected_end_of_object_bytes
|
|
||||||
|
|
||||||
remainder = splittable[cursor:]
|
|
||||||
|
|
||||||
if msgpack_remainder:
|
|
||||||
message_objects.append(msgpack.loads(remainder))
|
|
||||||
elif return_remainder:
|
|
||||||
message_objects.append(remainder)
|
|
||||||
|
|
||||||
return message_objects
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return sum(self.get_message_meta(m)[1] for m in self.message_types)
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_message_meta(message_type):
|
|
||||||
try:
|
|
||||||
message_class = message_type[0]
|
|
||||||
except TypeError:
|
|
||||||
message_class = message_type
|
|
||||||
|
|
||||||
try:
|
|
||||||
# If a message length has been passed manually, it will be the second item.
|
|
||||||
message_length = message_type[1]
|
|
||||||
except TypeError:
|
|
||||||
# If not, we expect it to be an attribute on the first item.
|
|
||||||
message_length = message_class._EXPECTED_LENGTH
|
|
||||||
except AttributeError:
|
|
||||||
raise TypeError("No way to know the expected length. Either pass it as the second member of a tuple or set _EXPECTED_LENGTH on the class you're passing.")
|
|
||||||
|
|
||||||
try:
|
|
||||||
kwargs = message_type[2]
|
|
||||||
except (IndexError, TypeError):
|
|
||||||
kwargs = {}
|
|
||||||
|
|
||||||
return message_class, message_length, kwargs
|
|
||||||
|
|
||||||
def __add__(self, splitter):
|
|
||||||
return self.__class__(*self.message_types + splitter.message_types)
|
|
||||||
|
|
||||||
def __radd__(self, other):
|
|
||||||
return other + bytes(self)
|
|
||||||
|
|
||||||
|
|
||||||
class RepeatingBytestringSplitter(BytestringSplitter):
|
|
||||||
|
|
||||||
def __call__(self, splittable):
|
|
||||||
remainder = True
|
|
||||||
messages = []
|
|
||||||
while remainder:
|
|
||||||
message, remainder = super().__call__(splittable, return_remainder=True)
|
|
||||||
messages.append(message)
|
|
||||||
splittable = remainder
|
|
||||||
return messages
|
|
||||||
|
|
||||||
|
|
||||||
def fingerprint_from_key(public_key: Any):
|
def fingerprint_from_key(public_key: Any):
|
||||||
"""
|
"""
|
||||||
Hashes a key using keccak-256 and returns the hexdigest in bytes.
|
Hashes a key using keccak-256 and returns the hexdigest in bytes.
|
||||||
|
|
|
@ -2,8 +2,7 @@ import requests
|
||||||
from kademlia.node import Node
|
from kademlia.node import Node
|
||||||
|
|
||||||
from nkms.crypto.constants import CFRAG_LENGTH
|
from nkms.crypto.constants import CFRAG_LENGTH
|
||||||
from nkms.crypto.kits import MessageKit
|
from bytestring_splitter import RepeatingBytestringSplitter
|
||||||
from nkms.crypto.utils import RepeatingBytestringSplitter
|
|
||||||
from nkms.network.capabilities import ServerCapability
|
from nkms.network.capabilities import ServerCapability
|
||||||
|
|
||||||
from umbral.fragments import CapsuleFrag
|
from umbral.fragments import CapsuleFrag
|
||||||
|
|
|
@ -6,7 +6,7 @@ from nkms.characters import Ursula
|
||||||
from nkms.crypto.api import keccak_digest
|
from nkms.crypto.api import keccak_digest
|
||||||
from nkms.crypto.constants import PUBLIC_KEY_LENGTH
|
from nkms.crypto.constants import PUBLIC_KEY_LENGTH
|
||||||
from nkms.crypto.powers import SigningPower, EncryptingPower
|
from nkms.crypto.powers import SigningPower, EncryptingPower
|
||||||
from nkms.crypto.utils import BytestringSplitter
|
from bytestring_splitter import BytestringSplitter
|
||||||
from tests.utilities import MockNetworkyStuff
|
from tests.utilities import MockNetworkyStuff
|
||||||
from umbral.fragments import KFrag
|
from umbral.fragments import KFrag
|
||||||
from umbral.keys import UmbralPublicKey
|
from umbral.keys import UmbralPublicKey
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from nkms.crypto import api
|
|
||||||
from nkms.crypto.api import secure_random
|
from nkms.crypto.api import secure_random
|
||||||
from nkms.crypto.constants import KFRAG_LENGTH
|
|
||||||
from nkms.crypto.signature import Signature
|
from nkms.crypto.signature import Signature
|
||||||
from nkms.crypto.utils import BytestringSplitter
|
from bytestring_splitter import BytestringSplitter
|
||||||
from umbral.bignum import BigNum
|
|
||||||
from umbral.fragments import KFrag
|
|
||||||
from umbral.point import Point
|
|
||||||
|
|
||||||
|
|
||||||
def test_split_two_signatures():
|
def test_split_two_signatures():
|
||||||
|
|
Loading…
Reference in New Issue