ci: Use black instead of flake8
It results in mostly the same style, plus it’s configurable via pyprojects.toml.
This commit is contained in:
		@@ -16,3 +16,11 @@ repos:
 | 
			
		||||
        pass_filenames: false
 | 
			
		||||
        language: system
 | 
			
		||||
        stages: [push]
 | 
			
		||||
      - id: black
 | 
			
		||||
        name: black
 | 
			
		||||
        description: "Black: The uncompromising Python code formatter"
 | 
			
		||||
        entry: poetry run black
 | 
			
		||||
        args: ["--diff"]
 | 
			
		||||
        language: system
 | 
			
		||||
        require_serial: true
 | 
			
		||||
        types_or: [python, pyi]
 | 
			
		||||
 
 | 
			
		||||
@@ -7,13 +7,13 @@ from nacl.signing import SigningKey
 | 
			
		||||
 | 
			
		||||
from secret_handshake import SHSClient
 | 
			
		||||
 | 
			
		||||
with open(os.path.expanduser('~/.ssb/secret')) as f:
 | 
			
		||||
with open(os.path.expanduser("~/.ssb/secret")) as f:
 | 
			
		||||
    config = yaml.safe_load(f)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def main():
 | 
			
		||||
    server_pub_key = b64decode(config['public'][:-8])
 | 
			
		||||
    client = SHSClient('localhost', 8008, SigningKey.generate(), server_pub_key)
 | 
			
		||||
    server_pub_key = b64decode(config["public"][:-8])
 | 
			
		||||
    client = SHSClient("localhost", 8008, SigningKey.generate(), server_pub_key)
 | 
			
		||||
    await client.open()
 | 
			
		||||
 | 
			
		||||
    async for msg in client:
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ from nacl.signing import SigningKey
 | 
			
		||||
 | 
			
		||||
from secret_handshake import SHSServer
 | 
			
		||||
 | 
			
		||||
with open(os.path.expanduser('~/.ssb/secret')) as f:
 | 
			
		||||
with open(os.path.expanduser("~/.ssb/secret")) as f:
 | 
			
		||||
    config = yaml.safe_load(f)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -17,11 +17,12 @@ async def _on_connect(conn):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def main():
 | 
			
		||||
    server_keypair = SigningKey(b64decode(config['private'][:-8])[:32])
 | 
			
		||||
    server = SHSServer('localhost', 8008, server_keypair)
 | 
			
		||||
    server_keypair = SigningKey(b64decode(config["private"][:-8])[:32])
 | 
			
		||||
    server = SHSServer("localhost", 8008, server_keypair)
 | 
			
		||||
    server.on_connect(_on_connect)
 | 
			
		||||
    await server.listen()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
loop = get_event_loop()
 | 
			
		||||
loop.run_until_complete(main())
 | 
			
		||||
loop.run_forever()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										78
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										78
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							@@ -53,6 +53,46 @@ setuptools = {version = "*", markers = "python_version >= \"3.12\""}
 | 
			
		||||
[package.extras]
 | 
			
		||||
dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "black"
 | 
			
		||||
version = "23.10.1"
 | 
			
		||||
description = "The uncompromising code formatter."
 | 
			
		||||
optional = false
 | 
			
		||||
python-versions = ">=3.8"
 | 
			
		||||
files = [
 | 
			
		||||
    {file = "black-23.10.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69"},
 | 
			
		||||
    {file = "black-23.10.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:1b917a2aa020ca600483a7b340c165970b26e9029067f019e3755b56e8dd5916"},
 | 
			
		||||
    {file = "black-23.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c74de4c77b849e6359c6f01987e94873c707098322b91490d24296f66d067dc"},
 | 
			
		||||
    {file = "black-23.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b4d10b0f016616a0d93d24a448100adf1699712fb7a4efd0e2c32bbb219b173"},
 | 
			
		||||
    {file = "black-23.10.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b15b75fc53a2fbcac8a87d3e20f69874d161beef13954747e053bca7a1ce53a0"},
 | 
			
		||||
    {file = "black-23.10.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace"},
 | 
			
		||||
    {file = "black-23.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d56124b7a61d092cb52cce34182a5280e160e6aff3137172a68c2c2c4b76bcb"},
 | 
			
		||||
    {file = "black-23.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f157a8945a7b2d424da3335f7ace89c14a3b0625e6593d21139c2d8214d55ce"},
 | 
			
		||||
    {file = "black-23.10.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:cfcce6f0a384d0da692119f2d72d79ed07c7159879d0bb1bb32d2e443382bf3a"},
 | 
			
		||||
    {file = "black-23.10.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:33d40f5b06be80c1bbce17b173cda17994fbad096ce60eb22054da021bf933d1"},
 | 
			
		||||
    {file = "black-23.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840015166dbdfbc47992871325799fd2dc0dcf9395e401ada6d88fe11498abad"},
 | 
			
		||||
    {file = "black-23.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:037e9b4664cafda5f025a1728c50a9e9aedb99a759c89f760bd83730e76ba884"},
 | 
			
		||||
    {file = "black-23.10.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:7cb5936e686e782fddb1c73f8aa6f459e1ad38a6a7b0e54b403f1f05a1507ee9"},
 | 
			
		||||
    {file = "black-23.10.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:7670242e90dc129c539e9ca17665e39a146a761e681805c54fbd86015c7c84f7"},
 | 
			
		||||
    {file = "black-23.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed45ac9a613fb52dad3b61c8dea2ec9510bf3108d4db88422bacc7d1ba1243d"},
 | 
			
		||||
    {file = "black-23.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:6d23d7822140e3fef190734216cefb262521789367fbdc0b3f22af6744058982"},
 | 
			
		||||
    {file = "black-23.10.1-py3-none-any.whl", hash = "sha256:d431e6739f727bb2e0495df64a6c7a5310758e87505f5f8cde9ff6c0f2d7e4fe"},
 | 
			
		||||
    {file = "black-23.10.1.tar.gz", hash = "sha256:1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258"},
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[package.dependencies]
 | 
			
		||||
click = ">=8.0.0"
 | 
			
		||||
mypy-extensions = ">=0.4.3"
 | 
			
		||||
packaging = ">=22.0"
 | 
			
		||||
pathspec = ">=0.9.0"
 | 
			
		||||
platformdirs = ">=2"
 | 
			
		||||
 | 
			
		||||
[package.extras]
 | 
			
		||||
colorama = ["colorama (>=0.4.3)"]
 | 
			
		||||
d = ["aiohttp (>=3.7.4)"]
 | 
			
		||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
 | 
			
		||||
uvloop = ["uvloop (>=0.15.2)"]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "build"
 | 
			
		||||
version = "1.0.3"
 | 
			
		||||
@@ -278,6 +318,20 @@ setuptools = "*"
 | 
			
		||||
[package.extras]
 | 
			
		||||
test = ["mock (>=3.0.0)", "pytest"]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "click"
 | 
			
		||||
version = "8.1.7"
 | 
			
		||||
description = "Composable command line interface toolkit"
 | 
			
		||||
optional = false
 | 
			
		||||
python-versions = ">=3.7"
 | 
			
		||||
files = [
 | 
			
		||||
    {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
 | 
			
		||||
    {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[package.dependencies]
 | 
			
		||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "colorama"
 | 
			
		||||
version = "0.4.6"
 | 
			
		||||
@@ -595,6 +649,17 @@ files = [
 | 
			
		||||
    {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "mypy-extensions"
 | 
			
		||||
version = "1.0.0"
 | 
			
		||||
description = "Type system extensions for programs checked with the mypy type checker."
 | 
			
		||||
optional = false
 | 
			
		||||
python-versions = ">=3.5"
 | 
			
		||||
files = [
 | 
			
		||||
    {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
 | 
			
		||||
    {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "nodeenv"
 | 
			
		||||
version = "1.8.0"
 | 
			
		||||
@@ -620,6 +685,17 @@ files = [
 | 
			
		||||
    {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pathspec"
 | 
			
		||||
version = "0.11.2"
 | 
			
		||||
description = "Utility library for gitignore style pattern matching of file paths."
 | 
			
		||||
optional = false
 | 
			
		||||
python-versions = ">=3.7"
 | 
			
		||||
files = [
 | 
			
		||||
    {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
 | 
			
		||||
    {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "platformdirs"
 | 
			
		||||
version = "3.11.0"
 | 
			
		||||
@@ -1184,4 +1260,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
 | 
			
		||||
[metadata]
 | 
			
		||||
lock-version = "2.0"
 | 
			
		||||
python-versions = "^3.12"
 | 
			
		||||
content-hash = "ea2b635a53716be43ebfd83e9e810998913f10f5da1cd5bf778c57b92c6836bb"
 | 
			
		||||
content-hash = "4f9ec52a576209d59ea926bd2e332f5f06b4b2158c2ea348185704d21c63bd73"
 | 
			
		||||
 
 | 
			
		||||
@@ -23,10 +23,14 @@ pytest-asyncio = "^0.21.1"
 | 
			
		||||
pytest-mock = "^3.12.0"
 | 
			
		||||
pre-commit = "^3.5.0"
 | 
			
		||||
commitizen = "^3.12.0"
 | 
			
		||||
black = "^23.10.1"
 | 
			
		||||
 | 
			
		||||
[tool.poetry.group.docs.dependencies]
 | 
			
		||||
sphinx = "^7.2.6"
 | 
			
		||||
 | 
			
		||||
[tool.black]
 | 
			
		||||
line-length = 120
 | 
			
		||||
 | 
			
		||||
[tool.commitizen]
 | 
			
		||||
name = "cz_conventional_commits"
 | 
			
		||||
tag_format = "$version"
 | 
			
		||||
 
 | 
			
		||||
@@ -21,4 +21,4 @@
 | 
			
		||||
 | 
			
		||||
from .network import SHSClient, SHSServer
 | 
			
		||||
 | 
			
		||||
__all__ = ('SHSClient', 'SHSServer')
 | 
			
		||||
__all__ = ("SHSClient", "SHSServer")
 | 
			
		||||
 
 | 
			
		||||
@@ -8,21 +8,21 @@ from .util import inc_nonce, split_chunks
 | 
			
		||||
 | 
			
		||||
HEADER_LENGTH = 2 + 16 + 16
 | 
			
		||||
MAX_SEGMENT_SIZE = 4 * 1024
 | 
			
		||||
TERMINATION_HEADER = (b'\x00' * 18)
 | 
			
		||||
TERMINATION_HEADER = b"\x00" * 18
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_stream_pair(reader, writer, **kwargs):
 | 
			
		||||
    """Return a tuple with `(unbox_stream, box_stream)` (reader/writer).
 | 
			
		||||
 | 
			
		||||
    :return: (:class:`secret_handshake.boxstream.UnboxStream`,
 | 
			
		||||
              :class:`secret_handshake.boxstream.BoxStream`) """
 | 
			
		||||
              :class:`secret_handshake.boxstream.BoxStream`)"""
 | 
			
		||||
    box_args = {
 | 
			
		||||
        'key': kwargs['encrypt_key'],
 | 
			
		||||
        'nonce': kwargs['encrypt_nonce'],
 | 
			
		||||
        "key": kwargs["encrypt_key"],
 | 
			
		||||
        "nonce": kwargs["encrypt_nonce"],
 | 
			
		||||
    }
 | 
			
		||||
    unbox_args = {
 | 
			
		||||
        'key': kwargs['decrypt_key'],
 | 
			
		||||
        'nonce': kwargs['decrypt_nonce'],
 | 
			
		||||
        "key": kwargs["decrypt_key"],
 | 
			
		||||
        "nonce": kwargs["decrypt_nonce"],
 | 
			
		||||
    }
 | 
			
		||||
    return UnboxStream(reader, **unbox_args), BoxStream(writer, **box_args)
 | 
			
		||||
 | 
			
		||||
@@ -49,7 +49,7 @@ class UnboxStream(object):
 | 
			
		||||
            self.closed = True
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        length = struct.unpack('>H', header[:2])[0]
 | 
			
		||||
        length = struct.unpack(">H", header[:2])[0]
 | 
			
		||||
        mac = header[2:]
 | 
			
		||||
 | 
			
		||||
        data = await self.reader.readexactly(length)
 | 
			
		||||
@@ -78,7 +78,7 @@ class BoxStream(object):
 | 
			
		||||
    def write(self, data):
 | 
			
		||||
        for chunk in split_chunks(data, MAX_SEGMENT_SIZE):
 | 
			
		||||
            body = self.box.encrypt(chunk, inc_nonce(self.nonce))[24:]
 | 
			
		||||
            header = struct.pack('>H', len(body) - 16) + body[:16]
 | 
			
		||||
            header = struct.pack(">H", len(body) - 16) + body[:16]
 | 
			
		||||
 | 
			
		||||
            hdrbox = self.box.encrypt(header, self.nonce)[24:]
 | 
			
		||||
            self.writer.write(hdrbox)
 | 
			
		||||
@@ -87,4 +87,4 @@ class BoxStream(object):
 | 
			
		||||
            self.writer.write(body[16:])
 | 
			
		||||
 | 
			
		||||
    def close(self):
 | 
			
		||||
        self.writer.write(self.box.encrypt(b'\x00' * 18, self.nonce)[24:])
 | 
			
		||||
        self.writer.write(self.box.encrypt(b"\x00" * 18, self.nonce)[24:])
 | 
			
		||||
 
 | 
			
		||||
@@ -23,17 +23,17 @@ import hashlib
 | 
			
		||||
import hmac
 | 
			
		||||
from base64 import b64decode
 | 
			
		||||
 | 
			
		||||
from nacl.bindings import (crypto_box_afternm, crypto_box_open_afternm,
 | 
			
		||||
                           crypto_scalarmult)
 | 
			
		||||
from nacl.bindings import crypto_box_afternm, crypto_box_open_afternm, crypto_scalarmult
 | 
			
		||||
from nacl.exceptions import CryptoError
 | 
			
		||||
from nacl.public import PrivateKey
 | 
			
		||||
from nacl.signing import VerifyKey
 | 
			
		||||
 | 
			
		||||
APPLICATION_KEY = b64decode('1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s=')
 | 
			
		||||
APPLICATION_KEY = b64decode("1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s=")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SHSError(Exception):
 | 
			
		||||
    """A SHS exception."""
 | 
			
		||||
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -45,8 +45,9 @@ class SHSCryptoBase(object):
 | 
			
		||||
 | 
			
		||||
    def _reset_keys(self, ephemeral_key):
 | 
			
		||||
        self.local_ephemeral_key = ephemeral_key
 | 
			
		||||
        self.local_app_hmac = (hmac.new(self.application_key, bytes(ephemeral_key.public_key), digestmod='sha512')
 | 
			
		||||
                               .digest()[:32])
 | 
			
		||||
        self.local_app_hmac = hmac.new(
 | 
			
		||||
            self.application_key, bytes(ephemeral_key.public_key), digestmod="sha512"
 | 
			
		||||
        ).digest()[:32]
 | 
			
		||||
 | 
			
		||||
    def generate_challenge(self):
 | 
			
		||||
        """Generate and return a challenge to be sent to the server."""
 | 
			
		||||
@@ -57,7 +58,7 @@ class SHSCryptoBase(object):
 | 
			
		||||
        assert len(data) == 64
 | 
			
		||||
        sent_hmac, remote_ephemeral_key = data[:32], data[32:]
 | 
			
		||||
 | 
			
		||||
        h = hmac.new(self.application_key, remote_ephemeral_key, digestmod='sha512')
 | 
			
		||||
        h = hmac.new(self.application_key, remote_ephemeral_key, digestmod="sha512")
 | 
			
		||||
        self.remote_app_hmac = h.digest()[:32]
 | 
			
		||||
        ok = self.remote_app_hmac == sent_hmac
 | 
			
		||||
 | 
			
		||||
@@ -78,11 +79,11 @@ class SHSCryptoBase(object):
 | 
			
		||||
    def get_box_keys(self):
 | 
			
		||||
        shared_secret = hashlib.sha256(self.box_secret).digest()
 | 
			
		||||
        return {
 | 
			
		||||
            'shared_secret': shared_secret,
 | 
			
		||||
            'encrypt_key': hashlib.sha256(shared_secret + bytes(self.remote_pub_key)).digest(),
 | 
			
		||||
            'decrypt_key': hashlib.sha256(shared_secret + bytes(self.local_key.verify_key)).digest(),
 | 
			
		||||
            'encrypt_nonce': self.remote_app_hmac[:24],
 | 
			
		||||
            'decrypt_nonce': self.local_app_hmac[:24]
 | 
			
		||||
            "shared_secret": shared_secret,
 | 
			
		||||
            "encrypt_key": hashlib.sha256(shared_secret + bytes(self.remote_pub_key)).digest(),
 | 
			
		||||
            "decrypt_key": hashlib.sha256(shared_secret + bytes(self.local_key.verify_key)).digest(),
 | 
			
		||||
            "encrypt_nonce": self.remote_app_hmac[:24],
 | 
			
		||||
            "decrypt_nonce": self.local_app_hmac[:24],
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -91,7 +92,7 @@ class SHSServerCrypto(SHSCryptoBase):
 | 
			
		||||
        assert len(data) == 112
 | 
			
		||||
        a_bob = crypto_scalarmult(bytes(self.local_key.to_curve25519_private_key()), self.remote_ephemeral_key)
 | 
			
		||||
        box_secret = hashlib.sha256(self.application_key + self.shared_secret + a_bob).digest()
 | 
			
		||||
        self.hello = crypto_box_open_afternm(data, b'\x00' * 24, box_secret)
 | 
			
		||||
        self.hello = crypto_box_open_afternm(data, b"\x00" * 24, box_secret)
 | 
			
		||||
        signature, public_key = self.hello[:64], self.hello[64:]
 | 
			
		||||
        signed = self.application_key + bytes(self.local_key.verify_key) + self.shared_hash
 | 
			
		||||
        pkey = VerifyKey(public_key)
 | 
			
		||||
@@ -99,14 +100,15 @@ class SHSServerCrypto(SHSCryptoBase):
 | 
			
		||||
        # will raise an exception if verification fails
 | 
			
		||||
        pkey.verify(signed, signature)
 | 
			
		||||
        self.remote_pub_key = pkey
 | 
			
		||||
        b_alice = crypto_scalarmult(bytes(self.local_ephemeral_key),
 | 
			
		||||
                                    bytes(self.remote_pub_key.to_curve25519_public_key()))
 | 
			
		||||
        b_alice = crypto_scalarmult(
 | 
			
		||||
            bytes(self.local_ephemeral_key), bytes(self.remote_pub_key.to_curve25519_public_key())
 | 
			
		||||
        )
 | 
			
		||||
        self.box_secret = hashlib.sha256(self.application_key + self.shared_secret + a_bob + b_alice).digest()[:32]
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def generate_accept(self):
 | 
			
		||||
        okay = self.local_key.sign(self.application_key + self.hello + self.shared_hash).signature
 | 
			
		||||
        d = crypto_box_afternm(okay, b'\x00' * 24, self.box_secret)
 | 
			
		||||
        d = crypto_box_afternm(okay, b"\x00" * 24, self.box_secret)
 | 
			
		||||
        return d
 | 
			
		||||
 | 
			
		||||
    def clean(self, new_ephemeral_key=None):
 | 
			
		||||
@@ -159,8 +161,7 @@ class SHSClientCrypto(SHSCryptoBase):
 | 
			
		||||
        b_alice = crypto_scalarmult(bytes(curve_lkey), self.remote_ephemeral_key)
 | 
			
		||||
        self.b_alice = b_alice
 | 
			
		||||
        # this is hash(K | a * b | a * B | A * b)
 | 
			
		||||
        self.box_secret = hashlib.sha256(self.application_key + self.shared_secret + self.a_bob +
 | 
			
		||||
                                         b_alice).digest()
 | 
			
		||||
        self.box_secret = hashlib.sha256(self.application_key + self.shared_secret + self.a_bob + b_alice).digest()
 | 
			
		||||
 | 
			
		||||
        nonce = b"\x00" * 24
 | 
			
		||||
 | 
			
		||||
@@ -168,7 +169,7 @@ class SHSClientCrypto(SHSCryptoBase):
 | 
			
		||||
            # let's use the box secret to unbox our encrypted message
 | 
			
		||||
            signature = crypto_box_open_afternm(data, nonce, self.box_secret)
 | 
			
		||||
        except CryptoError:
 | 
			
		||||
            raise SHSError('Error decrypting server acceptance message')
 | 
			
		||||
            raise SHSError("Error decrypting server acceptance message")
 | 
			
		||||
 | 
			
		||||
        # we should have received sign(B)[K | H | hash(a * b)]
 | 
			
		||||
        # let's see if that signature can verify the reconstructed data on our side
 | 
			
		||||
 
 | 
			
		||||
@@ -77,13 +77,13 @@ class SHSServer(SHSEndpoint):
 | 
			
		||||
    async def _handshake(self, reader, writer):
 | 
			
		||||
        data = await reader.readexactly(64)
 | 
			
		||||
        if not self.crypto.verify_challenge(data):
 | 
			
		||||
            raise SHSClientException('Client challenge is not valid')
 | 
			
		||||
            raise SHSClientException("Client challenge is not valid")
 | 
			
		||||
 | 
			
		||||
        writer.write(self.crypto.generate_challenge())
 | 
			
		||||
 | 
			
		||||
        data = await reader.readexactly(112)
 | 
			
		||||
        if not self.crypto.verify_client_auth(data):
 | 
			
		||||
            raise SHSClientException('Client auth is not valid')
 | 
			
		||||
            raise SHSClientException("Client auth is not valid")
 | 
			
		||||
 | 
			
		||||
        writer.write(self.crypto.generate_accept())
 | 
			
		||||
 | 
			
		||||
@@ -125,21 +125,22 @@ class SHSClient(SHSDuplexStream, SHSEndpoint):
 | 
			
		||||
        SHSEndpoint.__init__(self)
 | 
			
		||||
        self.host = host
 | 
			
		||||
        self.port = port
 | 
			
		||||
        self.crypto = SHSClientCrypto(client_kp, server_pub_key, ephemeral_key=ephemeral_key,
 | 
			
		||||
                                      application_key=application_key)
 | 
			
		||||
        self.crypto = SHSClientCrypto(
 | 
			
		||||
            client_kp, server_pub_key, ephemeral_key=ephemeral_key, application_key=application_key
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    async def _handshake(self, reader, writer):
 | 
			
		||||
        writer.write(self.crypto.generate_challenge())
 | 
			
		||||
 | 
			
		||||
        data = await reader.readexactly(64)
 | 
			
		||||
        if not self.crypto.verify_server_challenge(data):
 | 
			
		||||
            raise SHSClientException('Server challenge is not valid')
 | 
			
		||||
            raise SHSClientException("Server challenge is not valid")
 | 
			
		||||
 | 
			
		||||
        writer.write(self.crypto.generate_client_auth())
 | 
			
		||||
 | 
			
		||||
        data = await reader.readexactly(80)
 | 
			
		||||
        if not self.crypto.verify_server_accept(data):
 | 
			
		||||
            raise SHSClientException('Server accept is not valid')
 | 
			
		||||
            raise SHSClientException("Server accept is not valid")
 | 
			
		||||
 | 
			
		||||
    async def open(self):
 | 
			
		||||
        reader, writer = await asyncio.open_connection(self.host, self.port)
 | 
			
		||||
 
 | 
			
		||||
@@ -26,29 +26,31 @@ from secret_handshake.util import AsyncBuffer, async_comprehend
 | 
			
		||||
 | 
			
		||||
from .test_crypto import CLIENT_ENCRYPT_KEY, CLIENT_ENCRYPT_NONCE
 | 
			
		||||
 | 
			
		||||
MESSAGE_1 = (b'\xcev\xedE\x06l\x02\x13\xc8\x17V\xfa\x8bZ?\x88B%O\xb0L\x9f\x8e\x8c0y\x1dv\xc0\xc9\xf6\x9d\xc2\xdf\xdb'
 | 
			
		||||
             b'\xee\x9d')
 | 
			
		||||
MESSAGE_1 = (
 | 
			
		||||
    b"\xcev\xedE\x06l\x02\x13\xc8\x17V\xfa\x8bZ?\x88B%O\xb0L\x9f\x8e\x8c0y\x1dv\xc0\xc9\xf6\x9d\xc2\xdf\xdb" b"\xee\x9d"
 | 
			
		||||
)
 | 
			
		||||
MESSAGE_2 = b"\x141\xd63\x13d\xd1\xecZ\x9b\xd0\xd4\x03\xcdR?'\xaa.\x89I\x92I\xf9guL\xaa\x06?\xea\xca/}\x88*\xb2"
 | 
			
		||||
MESSAGE_3 = (b'\xcbYY\xf1\x0f\xa5O\x13r\xa6"\x15\xc5\x9d\r.*\x0b\x92\x10m\xa6(\x0c\x0c\xc61\x80j\x81)\x800\xed\xda'
 | 
			
		||||
             b'\xad\xa1')
 | 
			
		||||
MESSAGE_CLOSED = b'\xb1\x14hU\'\xb5M\xa6"\x03\x9duy\xa1\xd4evW,\xdcE\x18\xe4+ C4\xe8h\x96\xed\xc5\x94\x80'
 | 
			
		||||
MESSAGE_3 = (
 | 
			
		||||
    b'\xcbYY\xf1\x0f\xa5O\x13r\xa6"\x15\xc5\x9d\r.*\x0b\x92\x10m\xa6(\x0c\x0c\xc61\x80j\x81)\x800\xed\xda' b"\xad\xa1"
 | 
			
		||||
)
 | 
			
		||||
MESSAGE_CLOSED = b"\xb1\x14hU'\xb5M\xa6\"\x03\x9duy\xa1\xd4evW,\xdcE\x18\xe4+ C4\xe8h\x96\xed\xc5\x94\x80"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.asyncio
 | 
			
		||||
async def test_boxstream():
 | 
			
		||||
    buffer = AsyncBuffer()
 | 
			
		||||
    box_stream = BoxStream(buffer, CLIENT_ENCRYPT_KEY, CLIENT_ENCRYPT_NONCE)
 | 
			
		||||
    box_stream.write(b'foo')
 | 
			
		||||
    box_stream.write(b"foo")
 | 
			
		||||
    buffer.seek(0)
 | 
			
		||||
    assert await buffer.read() == MESSAGE_1
 | 
			
		||||
 | 
			
		||||
    pos = buffer.tell()
 | 
			
		||||
    box_stream.write(b'foo')
 | 
			
		||||
    box_stream.write(b"foo")
 | 
			
		||||
    buffer.seek(pos)
 | 
			
		||||
    assert await buffer.read() == MESSAGE_2
 | 
			
		||||
 | 
			
		||||
    pos = buffer.tell()
 | 
			
		||||
    box_stream.write(b'bar')
 | 
			
		||||
    box_stream.write(b"bar")
 | 
			
		||||
    buffer.seek(pos)
 | 
			
		||||
    assert await buffer.read() == MESSAGE_3
 | 
			
		||||
 | 
			
		||||
@@ -65,7 +67,7 @@ async def test_unboxstream():
 | 
			
		||||
 | 
			
		||||
    unbox_stream = UnboxStream(buffer, CLIENT_ENCRYPT_KEY, CLIENT_ENCRYPT_NONCE)
 | 
			
		||||
    assert not unbox_stream.closed
 | 
			
		||||
    assert (await async_comprehend(unbox_stream)) == [b'foo', b'foo', b'bar']
 | 
			
		||||
    assert (await async_comprehend(unbox_stream)) == [b"foo", b"foo", b"bar"]
 | 
			
		||||
    assert unbox_stream.closed
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,11 +27,11 @@ from nacl.signing import SigningKey
 | 
			
		||||
 | 
			
		||||
from secret_handshake.crypto import SHSClientCrypto, SHSServerCrypto
 | 
			
		||||
 | 
			
		||||
APP_KEY = hashlib.sha256(b'app_key').digest()
 | 
			
		||||
SERVER_KEY_SEED = b'\xcaw\x01\xc2cQ\xfd\x94\x9f\x14\x84\x0c0<l\xd8\xe4\xf5>\x12\\\x96\xcd\x9b\x0c\x02z&\x96!\xe0\xa2'
 | 
			
		||||
CLIENT_KEY_SEED = b'\xbf\x02<\xd3e\x9d\xac-\xd1\x9e-{\xe5q\x90\x03\x11\xba\x8cSQ\xa0\xc3p~\x89\xe6\xeeb\xaa\x1c\x17'
 | 
			
		||||
APP_KEY = hashlib.sha256(b"app_key").digest()
 | 
			
		||||
SERVER_KEY_SEED = b"\xcaw\x01\xc2cQ\xfd\x94\x9f\x14\x84\x0c0<l\xd8\xe4\xf5>\x12\\\x96\xcd\x9b\x0c\x02z&\x96!\xe0\xa2"
 | 
			
		||||
CLIENT_KEY_SEED = b"\xbf\x02<\xd3e\x9d\xac-\xd1\x9e-{\xe5q\x90\x03\x11\xba\x8cSQ\xa0\xc3p~\x89\xe6\xeeb\xaa\x1c\x17"
 | 
			
		||||
SERVER_EPH_KEY_SEED = b"ed\x1c\x01\x03s\x04\xdc\x8e`\xd6Z\xd0u;\xcbX\x91\xd8ZO\xf8\xf0\xd6'\xd5\xb1Yy\x13yH"
 | 
			
		||||
CLIENT_EPH_KEY_SEED = b'u8\xd0\xe3\x85d_Pz\x0c\xf5\xfd\x15\xce2p#\xb0\xf0\x9f\xe6!\xe1\xcb\xf6\x93\t\xebr{1\x8b'
 | 
			
		||||
CLIENT_EPH_KEY_SEED = b"u8\xd0\xe3\x85d_Pz\x0c\xf5\xfd\x15\xce2p#\xb0\xf0\x9f\xe6!\xe1\xcb\xf6\x93\t\xebr{1\x8b"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture()
 | 
			
		||||
@@ -49,28 +49,38 @@ def client():
 | 
			
		||||
    return SHSClientCrypto(client_key, bytes(server_key.verify_key), client_eph_key, application_key=APP_KEY)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CLIENT_CHALLENGE = (b'd\xe8\xccD\xec\xb9E\xbb\xaa\xa7\x7f\xe38\x15\x16\xef\xca\xd22u\x1d\xfe<\xe7j'
 | 
			
		||||
                    b'\xd7\xf0uc\xf0r\xf3\x7f\t\x18\xec\x8c\xf7\xff\x8e\xa9\xc83\x13\x18R\x16\x1d'
 | 
			
		||||
                    b'\xe5\xc6K\xae\x94\xdbVt\x84\xdc\x1c@+D\x1c%')
 | 
			
		||||
CLIENT_AUTH = (b'\xf2\xaf?z\x15\x10\xd0\xf0\xdf\xe3\x91\xfe\x14\x1c}z\xab\xeey\xf5\xef\xfc\xa1EdV\xf2T\x95s[!$z'
 | 
			
		||||
               b'\xeb\x8f\x1b\x96JP\x17^\x92\xc8\x9e\xb4*5`\xf2\x8fI.\x93\xb9\x14:\xca@\x06\xff\xd1\xf1J\xc8t\xc4'
 | 
			
		||||
               b'\xd8\xc3$[\xc5\x94je\x83\x00%\x99\x10\x16\xb1\xa2\xb2\xb7\xbf\xc9\x88\x14\xb9\xbb^\tzq\xa4\xef\xc5'
 | 
			
		||||
               b'\xf5\x1f7#\xed\x92X\xb2\xe3\xe5\x8b[t3')
 | 
			
		||||
SERVER_CHALLENGE = (b'S\\\x06\x8d\xe5\xeb&*\xb8\x0bp\xb3Z\x8e\\\x85\x14\xaa\x1c\x8di\x9d\x7f\xa9\xeawl\xb9}\x85\xc3ik'
 | 
			
		||||
                    b'\x0c ($E\xb4\x8ax\xc4)t<\xd7\x8b\xd6\x07\xb7\xecw\x84\r\xe1-Iz`\xeb\x04\x89\xd6{')
 | 
			
		||||
SERVER_ACCEPT = (b'\xb4\xd0\xea\xfb\xfb\xf6s\xcc\x10\xc4\x99\x95"\x13 y\xa6\xea.G\xeed\x8d=t9\x88|\x94\xd1\xbcK\xd47'
 | 
			
		||||
                 b'\xd8\xbcG1h\xac\xd0\xeb*\x1f\x8d\xae\x0b\x91G\xa1\xe6\x96b\xf2\xda90u\xeb_\xab\xdb\xcb%d7}\xb5\xce'
 | 
			
		||||
                 b'(k\x15\xe3L\x9d)\xd5\xa1|:')
 | 
			
		||||
INTER_SHARED_SECRET = (b'vf\xd82\xaeU\xda]\x08\x9eZ\xd6\x06\xcc\xd3\x99\xfd\xce\xc5\x16e8n\x9a\x04\x04\x84\xc5\x1a'
 | 
			
		||||
                       b'\x8f\xf2M')
 | 
			
		||||
BOX_SECRET = b'\x03\xfe\xe3\x8c u\xbcl^\x17eD\x96\xa3\xa6\x880f\x11\x7f\x85\xf2:\xa3[`\x06[#l\xbcr'
 | 
			
		||||
CLIENT_CHALLENGE = (
 | 
			
		||||
    b"d\xe8\xccD\xec\xb9E\xbb\xaa\xa7\x7f\xe38\x15\x16\xef\xca\xd22u\x1d\xfe<\xe7j"
 | 
			
		||||
    b"\xd7\xf0uc\xf0r\xf3\x7f\t\x18\xec\x8c\xf7\xff\x8e\xa9\xc83\x13\x18R\x16\x1d"
 | 
			
		||||
    b"\xe5\xc6K\xae\x94\xdbVt\x84\xdc\x1c@+D\x1c%"
 | 
			
		||||
)
 | 
			
		||||
CLIENT_AUTH = (
 | 
			
		||||
    b"\xf2\xaf?z\x15\x10\xd0\xf0\xdf\xe3\x91\xfe\x14\x1c}z\xab\xeey\xf5\xef\xfc\xa1EdV\xf2T\x95s[!$z"
 | 
			
		||||
    b"\xeb\x8f\x1b\x96JP\x17^\x92\xc8\x9e\xb4*5`\xf2\x8fI.\x93\xb9\x14:\xca@\x06\xff\xd1\xf1J\xc8t\xc4"
 | 
			
		||||
    b"\xd8\xc3$[\xc5\x94je\x83\x00%\x99\x10\x16\xb1\xa2\xb2\xb7\xbf\xc9\x88\x14\xb9\xbb^\tzq\xa4\xef\xc5"
 | 
			
		||||
    b"\xf5\x1f7#\xed\x92X\xb2\xe3\xe5\x8b[t3"
 | 
			
		||||
)
 | 
			
		||||
SERVER_CHALLENGE = (
 | 
			
		||||
    b"S\\\x06\x8d\xe5\xeb&*\xb8\x0bp\xb3Z\x8e\\\x85\x14\xaa\x1c\x8di\x9d\x7f\xa9\xeawl\xb9}\x85\xc3ik"
 | 
			
		||||
    b"\x0c ($E\xb4\x8ax\xc4)t<\xd7\x8b\xd6\x07\xb7\xecw\x84\r\xe1-Iz`\xeb\x04\x89\xd6{"
 | 
			
		||||
)
 | 
			
		||||
SERVER_ACCEPT = (
 | 
			
		||||
    b'\xb4\xd0\xea\xfb\xfb\xf6s\xcc\x10\xc4\x99\x95"\x13 y\xa6\xea.G\xeed\x8d=t9\x88|\x94\xd1\xbcK\xd47'
 | 
			
		||||
    b"\xd8\xbcG1h\xac\xd0\xeb*\x1f\x8d\xae\x0b\x91G\xa1\xe6\x96b\xf2\xda90u\xeb_\xab\xdb\xcb%d7}\xb5\xce"
 | 
			
		||||
    b"(k\x15\xe3L\x9d)\xd5\xa1|:"
 | 
			
		||||
)
 | 
			
		||||
INTER_SHARED_SECRET = (
 | 
			
		||||
    b"vf\xd82\xaeU\xda]\x08\x9eZ\xd6\x06\xcc\xd3\x99\xfd\xce\xc5\x16e8n\x9a\x04\x04\x84\xc5\x1a" b"\x8f\xf2M"
 | 
			
		||||
)
 | 
			
		||||
BOX_SECRET = b"\x03\xfe\xe3\x8c u\xbcl^\x17eD\x96\xa3\xa6\x880f\x11\x7f\x85\xf2:\xa3[`\x06[#l\xbcr"
 | 
			
		||||
 | 
			
		||||
SHARED_SECRET = b'UV\xad*\x8e\xce\x88\xf2\x87l\x13iZ\x12\xd7\xa6\xd1\x9c-\x9d\x07\xf5\xa96\x03w\x11\xe5\x96$m\x1d'
 | 
			
		||||
CLIENT_ENCRYPT_KEY = (b'\xec\x1f,\x82\x9f\xedA\xc0\xda\x87[\xf9u\xbf\xac\x9cI\xa5T\xd1\x91\xff\xa8.\xd0 \xfbU\xc7\x14'
 | 
			
		||||
                      b')\xc7')
 | 
			
		||||
CLIENT_DECRYPT_KEY = b'\xf9e\xa0As\xb2=\xb7P~\xf3\xf9(\xfd\x7f\xfe\xb7TZhn\xd7\x8c=\xea.o\x9e\x8c9)\x10'
 | 
			
		||||
CLIENT_ENCRYPT_NONCE = b'S\\\x06\x8d\xe5\xeb&*\xb8\x0bp\xb3Z\x8e\\\x85\x14\xaa\x1c\x8di\x9d\x7f\xa9'
 | 
			
		||||
CLIENT_DECRYPT_NONCE = b'd\xe8\xccD\xec\xb9E\xbb\xaa\xa7\x7f\xe38\x15\x16\xef\xca\xd22u\x1d\xfe<\xe7'
 | 
			
		||||
SHARED_SECRET = b"UV\xad*\x8e\xce\x88\xf2\x87l\x13iZ\x12\xd7\xa6\xd1\x9c-\x9d\x07\xf5\xa96\x03w\x11\xe5\x96$m\x1d"
 | 
			
		||||
CLIENT_ENCRYPT_KEY = (
 | 
			
		||||
    b"\xec\x1f,\x82\x9f\xedA\xc0\xda\x87[\xf9u\xbf\xac\x9cI\xa5T\xd1\x91\xff\xa8.\xd0 \xfbU\xc7\x14" b")\xc7"
 | 
			
		||||
)
 | 
			
		||||
CLIENT_DECRYPT_KEY = b"\xf9e\xa0As\xb2=\xb7P~\xf3\xf9(\xfd\x7f\xfe\xb7TZhn\xd7\x8c=\xea.o\x9e\x8c9)\x10"
 | 
			
		||||
CLIENT_ENCRYPT_NONCE = b"S\\\x06\x8d\xe5\xeb&*\xb8\x0bp\xb3Z\x8e\\\x85\x14\xaa\x1c\x8di\x9d\x7f\xa9"
 | 
			
		||||
CLIENT_DECRYPT_NONCE = b"d\xe8\xccD\xec\xb9E\xbb\xaa\xa7\x7f\xe38\x15\x16\xef\xca\xd22u\x1d\xfe<\xe7"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_handshake(client, server):
 | 
			
		||||
@@ -100,12 +110,12 @@ def test_handshake(client, server):
 | 
			
		||||
    client_keys = client.get_box_keys()
 | 
			
		||||
    server_keys = server.get_box_keys()
 | 
			
		||||
 | 
			
		||||
    assert client_keys['shared_secret'] == SHARED_SECRET
 | 
			
		||||
    assert client_keys['encrypt_key'] == CLIENT_ENCRYPT_KEY
 | 
			
		||||
    assert client_keys['decrypt_key'] == CLIENT_DECRYPT_KEY
 | 
			
		||||
    assert client_keys['encrypt_nonce'] == CLIENT_ENCRYPT_NONCE
 | 
			
		||||
    assert client_keys['decrypt_nonce'] == CLIENT_DECRYPT_NONCE
 | 
			
		||||
    assert client_keys["shared_secret"] == SHARED_SECRET
 | 
			
		||||
    assert client_keys["encrypt_key"] == CLIENT_ENCRYPT_KEY
 | 
			
		||||
    assert client_keys["decrypt_key"] == CLIENT_DECRYPT_KEY
 | 
			
		||||
    assert client_keys["encrypt_nonce"] == CLIENT_ENCRYPT_NONCE
 | 
			
		||||
    assert client_keys["decrypt_nonce"] == CLIENT_DECRYPT_NONCE
 | 
			
		||||
 | 
			
		||||
    assert client_keys['shared_secret'] == server_keys['shared_secret']
 | 
			
		||||
    assert client_keys['encrypt_key'] == server_keys['decrypt_key']
 | 
			
		||||
    assert client_keys['encrypt_nonce'] == server_keys['decrypt_nonce']
 | 
			
		||||
    assert client_keys["shared_secret"] == server_keys["shared_secret"]
 | 
			
		||||
    assert client_keys["encrypt_key"] == server_keys["decrypt_key"]
 | 
			
		||||
    assert client_keys["encrypt_nonce"] == server_keys["decrypt_nonce"]
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ from secret_handshake.util import AsyncBuffer
 | 
			
		||||
 | 
			
		||||
class DummyCrypto(object):
 | 
			
		||||
    """Dummy crypto module, pretends everything is fine."""
 | 
			
		||||
 | 
			
		||||
    def verify_server_challenge(self, data):
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
@@ -39,23 +40,23 @@ class DummyCrypto(object):
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def generate_challenge(self):
 | 
			
		||||
        return b'CHALLENGE'
 | 
			
		||||
        return b"CHALLENGE"
 | 
			
		||||
 | 
			
		||||
    def generate_client_auth(self):
 | 
			
		||||
        return b'AUTH'
 | 
			
		||||
        return b"AUTH"
 | 
			
		||||
 | 
			
		||||
    def verify_client_auth(self, data):
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def generate_accept(self):
 | 
			
		||||
        return b'ACCEPT'
 | 
			
		||||
        return b"ACCEPT"
 | 
			
		||||
 | 
			
		||||
    def get_box_keys(self):
 | 
			
		||||
        return {
 | 
			
		||||
            'encrypt_key': b'x' * 32,
 | 
			
		||||
            'encrypt_nonce': b'x' * 32,
 | 
			
		||||
            'decrypt_key': b'x' * 32,
 | 
			
		||||
            'decrypt_nonce': b'x' * 32
 | 
			
		||||
            "encrypt_key": b"x" * 32,
 | 
			
		||||
            "encrypt_nonce": b"x" * 32,
 | 
			
		||||
            "decrypt_key": b"x" * 32,
 | 
			
		||||
            "decrypt_nonce": b"x" * 32,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    def clean(self):
 | 
			
		||||
@@ -68,8 +69,8 @@ def _dummy_boxstream(stream, **kwargs):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _client_stream_mocker():
 | 
			
		||||
    reader = AsyncBuffer(b'xxx')
 | 
			
		||||
    writer = AsyncBuffer(b'xxx')
 | 
			
		||||
    reader = AsyncBuffer(b"xxx")
 | 
			
		||||
    writer = AsyncBuffer(b"xxx")
 | 
			
		||||
 | 
			
		||||
    async def _create_mock_streams(host, port):
 | 
			
		||||
        return reader, writer
 | 
			
		||||
@@ -78,8 +79,8 @@ def _client_stream_mocker():
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _server_stream_mocker():
 | 
			
		||||
    reader = AsyncBuffer(b'xxx')
 | 
			
		||||
    writer = AsyncBuffer(b'xxx')
 | 
			
		||||
    reader = AsyncBuffer(b"xxx")
 | 
			
		||||
    writer = AsyncBuffer(b"xxx")
 | 
			
		||||
 | 
			
		||||
    async def _create_mock_server(cb, host, port):
 | 
			
		||||
        await cb(reader, writer)
 | 
			
		||||
@@ -90,18 +91,18 @@ def _server_stream_mocker():
 | 
			
		||||
@pytest.mark.asyncio
 | 
			
		||||
async def test_client(mocker):
 | 
			
		||||
    reader, writer, _create_mock_streams = _client_stream_mocker()
 | 
			
		||||
    mocker.patch('asyncio.open_connection', new=_create_mock_streams)
 | 
			
		||||
    mocker.patch('secret_handshake.boxstream.BoxStream', new=_dummy_boxstream)
 | 
			
		||||
    mocker.patch('secret_handshake.boxstream.UnboxStream', new=_dummy_boxstream)
 | 
			
		||||
    mocker.patch("asyncio.open_connection", new=_create_mock_streams)
 | 
			
		||||
    mocker.patch("secret_handshake.boxstream.BoxStream", new=_dummy_boxstream)
 | 
			
		||||
    mocker.patch("secret_handshake.boxstream.UnboxStream", new=_dummy_boxstream)
 | 
			
		||||
 | 
			
		||||
    from secret_handshake import SHSClient
 | 
			
		||||
 | 
			
		||||
    client = SHSClient('shop.local', 1111, SigningKey.generate(), os.urandom(32))
 | 
			
		||||
    client = SHSClient("shop.local", 1111, SigningKey.generate(), os.urandom(32))
 | 
			
		||||
    client.crypto = DummyCrypto()
 | 
			
		||||
 | 
			
		||||
    await client.open()
 | 
			
		||||
    reader.append(b'TEST')
 | 
			
		||||
    assert (await client.read()) == b'TEST'
 | 
			
		||||
    reader.append(b"TEST")
 | 
			
		||||
    assert (await client.read()) == b"TEST"
 | 
			
		||||
    client.disconnect()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -116,11 +117,11 @@ async def test_server(mocker):
 | 
			
		||||
        resolve.set()
 | 
			
		||||
 | 
			
		||||
    reader, writer, _create_mock_server = _server_stream_mocker()
 | 
			
		||||
    mocker.patch('asyncio.start_server', new=_create_mock_server)
 | 
			
		||||
    mocker.patch('secret_handshake.boxstream.BoxStream', new=_dummy_boxstream)
 | 
			
		||||
    mocker.patch('secret_handshake.boxstream.UnboxStream', new=_dummy_boxstream)
 | 
			
		||||
    mocker.patch("asyncio.start_server", new=_create_mock_server)
 | 
			
		||||
    mocker.patch("secret_handshake.boxstream.BoxStream", new=_dummy_boxstream)
 | 
			
		||||
    mocker.patch("secret_handshake.boxstream.UnboxStream", new=_dummy_boxstream)
 | 
			
		||||
 | 
			
		||||
    server = SHSServer('shop.local', 1111, SigningKey.generate(), os.urandom(32))
 | 
			
		||||
    server = SHSServer("shop.local", 1111, SigningKey.generate(), os.urandom(32))
 | 
			
		||||
    server.crypto = DummyCrypto()
 | 
			
		||||
 | 
			
		||||
    server.on_connect(_on_connect)
 | 
			
		||||
 
 | 
			
		||||
@@ -23,14 +23,16 @@ import struct
 | 
			
		||||
from io import BytesIO
 | 
			
		||||
 | 
			
		||||
NONCE_SIZE = 24
 | 
			
		||||
MAX_NONCE = (8 * NONCE_SIZE)
 | 
			
		||||
MAX_NONCE = 8 * NONCE_SIZE
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AsyncBuffer(BytesIO):
 | 
			
		||||
    """Just a BytesIO with an async read method."""
 | 
			
		||||
 | 
			
		||||
    async def read(self, n=None):
 | 
			
		||||
        v = super(AsyncBuffer, self).read(n)
 | 
			
		||||
        return v
 | 
			
		||||
 | 
			
		||||
    readexactly = read
 | 
			
		||||
 | 
			
		||||
    def append(self, data):
 | 
			
		||||
@@ -50,10 +52,10 @@ async def async_comprehend(generator):
 | 
			
		||||
 | 
			
		||||
def inc_nonce(nonce):
 | 
			
		||||
    num = bytes_to_long(nonce) + 1
 | 
			
		||||
    if num > 2 ** MAX_NONCE:
 | 
			
		||||
    if num > 2**MAX_NONCE:
 | 
			
		||||
        num = 0
 | 
			
		||||
    bnum = long_to_bytes(num)
 | 
			
		||||
    bnum = b'\x00' * (NONCE_SIZE - len(bnum)) + bnum
 | 
			
		||||
    bnum = b"\x00" * (NONCE_SIZE - len(bnum)) + bnum
 | 
			
		||||
    return bnum
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -78,24 +80,24 @@ def long_to_bytes(n, blocksize=0):
 | 
			
		||||
    blocksize.
 | 
			
		||||
    """
 | 
			
		||||
    # after much testing, this algorithm was deemed to be the fastest
 | 
			
		||||
    s = b('')
 | 
			
		||||
    s = b("")
 | 
			
		||||
    pack = struct.pack
 | 
			
		||||
    while n > 0:
 | 
			
		||||
        s = pack('>I', n & 0xffffffff) + s
 | 
			
		||||
        s = pack(">I", n & 0xFFFFFFFF) + s
 | 
			
		||||
        n = n >> 32
 | 
			
		||||
    # strip off leading zeros
 | 
			
		||||
    for i in range(len(s)):
 | 
			
		||||
        if s[i] != b('\000')[0]:
 | 
			
		||||
        if s[i] != b("\000")[0]:
 | 
			
		||||
            break
 | 
			
		||||
    else:
 | 
			
		||||
        # only happens when n == 0
 | 
			
		||||
        s = b('\000')
 | 
			
		||||
        s = b("\000")
 | 
			
		||||
        i = 0
 | 
			
		||||
    s = s[i:]
 | 
			
		||||
    # add back some pad bytes.  this could be done more efficiently w.r.t. the
 | 
			
		||||
    # de-padding being done above, but sigh...
 | 
			
		||||
    if blocksize > 0 and len(s) % blocksize:
 | 
			
		||||
        s = (blocksize - len(s) % blocksize) * b('\000') + s
 | 
			
		||||
        s = (blocksize - len(s) % blocksize) * b("\000") + s
 | 
			
		||||
    return s
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -108,9 +110,9 @@ def bytes_to_long(s):
 | 
			
		||||
    unpack = struct.unpack
 | 
			
		||||
    length = len(s)
 | 
			
		||||
    if length % 4:
 | 
			
		||||
        extra = (4 - length % 4)
 | 
			
		||||
        s = b('\000') * extra + s
 | 
			
		||||
        extra = 4 - length % 4
 | 
			
		||||
        s = b("\000") * extra + s
 | 
			
		||||
        length = length + extra
 | 
			
		||||
    for i in range(0, length, 4):
 | 
			
		||||
        acc = (acc << 32) + unpack('>I', s[i:i+4])[0]
 | 
			
		||||
        acc = (acc << 32) + unpack(">I", s[i : i + 4])[0]
 | 
			
		||||
    return acc
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user