BytestringSplitter is now its own project.

pull/189/head
jMyles 2018-04-01 18:52:30 -07:00 committed by tuxxy
parent b35e5b9840
commit 7f21117cb7
7 changed files with 13 additions and 141 deletions

View File

@ -389,7 +389,7 @@ class Bob(Character):
# TODO: Make this much prettier
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:
raise TypeError("Unknown DHT value. How did this get on the network?")
@ -442,7 +442,7 @@ class Bob(Character):
# TODO: Make this prettier
header, _signature_for_ursula, pubkey_sig_alice, hrac, encrypted_treasure_map = \
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
else:
assert False
@ -574,8 +574,8 @@ class Ursula(Character, ProxyRESTServer):
def interface_dht_value(self):
signature = self.stamp(self.interface_hrac())
return (
BYTESTRING_IS_URSULA_IFACE_INFO + signature + self.stamp + self.interface_hrac()
+ msgpack.dumps(self.dht_interface_info())
BYTESTRING_IS_URSULA_IFACE_INFO + signature + self.stamp + self.interface_hrac()
+ msgpack.dumps(self.dht_interface_info())
)
def interface_hrac(self):

View File

@ -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
cert = cert.add_extension(x509.SubjectAlternativeName([x509.DNSName(u"localhost")]), critical=False)
cert = cert.sign(private_key, hashes.SHA512(), default_backend())
return cert, private_key
return cert, private_key

View File

@ -1,7 +1,10 @@
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.pre import Capsule
from nkms.crypto.signature import Signature
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)

View File

@ -1,131 +1,7 @@
from contextlib import suppress
from typing import Any
import msgpack
from umbral.keys import UmbralPublicKey
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):
"""
Hashes a key using keccak-256 and returns the hexdigest in bytes.

View File

@ -2,8 +2,7 @@ import requests
from kademlia.node import Node
from nkms.crypto.constants import CFRAG_LENGTH
from nkms.crypto.kits import MessageKit
from nkms.crypto.utils import RepeatingBytestringSplitter
from bytestring_splitter import RepeatingBytestringSplitter
from nkms.network.capabilities import ServerCapability
from umbral.fragments import CapsuleFrag

View File

@ -6,7 +6,7 @@ from nkms.characters import Ursula
from nkms.crypto.api import keccak_digest
from nkms.crypto.constants import PUBLIC_KEY_LENGTH
from nkms.crypto.powers import SigningPower, EncryptingPower
from nkms.crypto.utils import BytestringSplitter
from bytestring_splitter import BytestringSplitter
from tests.utilities import MockNetworkyStuff
from umbral.fragments import KFrag
from umbral.keys import UmbralPublicKey

View File

@ -1,13 +1,7 @@
import pytest
from nkms.crypto import api
from nkms.crypto.api import secure_random
from nkms.crypto.constants import KFRAG_LENGTH
from nkms.crypto.signature import Signature
from nkms.crypto.utils import BytestringSplitter
from umbral.bignum import BigNum
from umbral.fragments import KFrag
from umbral.point import Point
from bytestring_splitter import BytestringSplitter
def test_split_two_signatures():