From f0945ec93a511761a4efc17278186bbdf31fd862 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Thu, 1 Dec 2022 18:20:41 -0800 Subject: [PATCH 1/7] make printing ctype arrays pretty. Slightly buggy in that it assumes all arrays are numbers though.. --- syote_comms.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/syote_comms.py b/syote_comms.py index 79e8ba6..07f9ed1 100644 --- a/syote_comms.py +++ b/syote_comms.py @@ -25,14 +25,21 @@ import os import unittest -from ctypes import Structure, POINTER, CFUNCTYPE, pointer, sizeof +from ctypes import Array, Structure, POINTER, CFUNCTYPE, pointer, sizeof from ctypes import c_uint8, c_uint16, c_ssize_t, c_size_t, c_uint64, c_int from ctypes import CDLL class StructureRepr(object): + @staticmethod + def __specialrepr(obj): + if isinstance(obj, Array): + return '[ %s ]' % ', '.join(hex(x) for x in obj) + + return repr(obj) + def __repr__(self): #pragma: no cover return '%s(%s)' % (self.__class__.__name__, ', '.join('%s=%s' % - (k, getattr(self, k)) for k, v in self._fields_)) + (k, self.__specialrepr(getattr(self, k))) for k, v in self._fields_)) class PktBuf(Structure): _fields_ = [ From f4e3ac0fcf4286579d9f31417392314605ab8306 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Sat, 3 Dec 2022 09:12:48 -0800 Subject: [PATCH 2/7] fix running with shared keys... --- lora.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lora.py b/lora.py index 058df08..0d5f5a9 100644 --- a/lora.py +++ b/lora.py @@ -352,8 +352,8 @@ async def main(): if args.shared_key is not None: skdata = pathlib.Path(args.shared_key).read_bytes() - lorakwargs = dict(shared_key=skdata) - commsinitargs = (lorakwargs['shared_key'], ) + lorakwargs = dict(shared=skdata) + commsinitargs = (make_pktbuf(lorakwargs['shared']), None, None) else: privkeydata = pathlib.Path(args.privkey).read_text().strip() privkey = X25519.frombytes(codecs.decode(privkeydata, 'hex')) From 2ea0bcd42aaa24b0fba1cda47e1d37b65e6fdad8 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Sat, 3 Dec 2022 10:21:03 -0800 Subject: [PATCH 3/7] clean up test output, and verify that the error message is correct.. --- loraserv.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/loraserv.py b/loraserv.py index e60b3b0..3ec990b 100644 --- a/loraserv.py +++ b/loraserv.py @@ -1,5 +1,6 @@ import argparse import asyncio +import io import multicast import sys import unittest @@ -168,10 +169,15 @@ class TestLoraServ(unittest.IsolatedAsyncioTestCase): @timeout(2) async def test_argerrors(self): - # it'd be nice to silence the usage output here - with self.assertRaises(SystemExit) as cm, \ - patch.dict(sys.__dict__, dict(argv=[ 'name', ])): - await main() + with io.StringIO() as fp: + with self.assertRaises(SystemExit) as cm, \ + patch.dict(sys.__dict__, dict(argv=[ 'name', ], + stderr=fp)): + await main() + + errout = fp.getvalue() + + self.assertEqual(errout, 'usage: name [-h] [-a maddr] serdev\nname: error: the following arguments are required: serdev\n') self.assertEqual(cm.exception.code, 2) From e1c5f656a70589f2773f2bc9b1a7980d53e6d13a Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Sat, 3 Dec 2022 11:16:10 -0800 Subject: [PATCH 4/7] fix misspelling of by --- RS485HID.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RS485HID.md b/RS485HID.md index bd24f31..431e57a 100644 --- a/RS485HID.md +++ b/RS485HID.md @@ -75,7 +75,7 @@ Keying ------ There are two keys involved, the initiator key, which is made w/ the -Makefile, but issuing the command: +Makefile, by issuing the command: ``` bmake hid_priv_key ``` From f9d398eca802534c053fa69796b0e2f8de5a984f Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Sat, 3 Dec 2022 11:17:31 -0800 Subject: [PATCH 5/7] add tests for python version round trip... and minor fix for seeding This also makes sure that the command works, and verifies that a previous fix did fix things... this also sets up for testing the public key version as well.. --- dummy.py | 9 +++++++ lora.py | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 dummy.py diff --git a/dummy.py b/dummy.py new file mode 100644 index 0000000..ce6342e --- /dev/null +++ b/dummy.py @@ -0,0 +1,9 @@ +import sys + +class TestAttr(object): + @staticmethod + def dummy_func(msg): + print('got msg:', repr(msg)) + sys.stdout.flush() + + return msg diff --git a/lora.py b/lora.py index 0d5f5a9..3f4b392 100644 --- a/lora.py +++ b/lora.py @@ -29,9 +29,15 @@ import functools import itertools import os import pathlib +import shutil +import subprocess import sys +import tempfile import unittest +from unittest.mock import patch +from subprocess import DEVNULL, PIPE + from Strobe.Strobe import Strobe, KeccakF from Strobe.Strobe import AuthenticationFailed @@ -375,7 +381,7 @@ async def main(): # seed the RNG prngseed = os.urandom(64) - syote_comms.strobe_seed_prng((c_uint8 * + syote_comms._lib.strobe_seed_prng((c_uint8 * len(prngseed))(*prngseed), len(prngseed)) # Create the state for testing @@ -1535,3 +1541,77 @@ class TestLoRaNodeMulticast(unittest.IsolatedAsyncioTestCase): with self.assertRaises(asyncio.CancelledError): await task + +class TestLORAmain(unittest.TestCase): + def setUp(self): + # setup temporary directory + d = pathlib.Path(tempfile.mkdtemp()).resolve() + self.basetempdir = d + self.tempdir = d / 'subdir' + self.tempdir.mkdir() + self.origcwd = os.getcwd() + + os.chdir(pathlib.Path(__file__).parent) + + def tearDown(self): + btd = self.basetempdir + self.tempdir = None + self.basetempdir = None + shutil.rmtree(btd) + + os.chdir(self.origcwd) + self.origcwd = None + + def test_sharedkey(self): + keys = [] + + # shared key test + keyfile = self.basetempdir / 'shared.key' + with keyfile.open('w') as fp: + fp.write(os.urandom(16).hex()) + + keys.append(('shared', [ [ '-s', keyfile ] ] * 2)) + + # pub key test + init_key = X25519.gen() + resp_key = X25519.gen() + + for name, (initargs, respargs) in keys: + with self.subTest(name=name): + self.run_program_keyargs(initargs, respargs) + + def run_program_keyargs(self, initargs, respargs): + try: + # XXX - macosx specific library path var + with patch.dict(os.environ, + dict(DYLD_LIBRARY_PATH=self.origcwd)): + resp = subprocess.Popen([ 'python', __file__, + '-r', 'dummy:TestAttr.dummy_func' ] + + respargs, stdin=DEVNULL, stderr=PIPE, + stdout=PIPE) + + init = subprocess.Popen([ 'python', __file__ ] + + initargs + [ 'ping' ], stdin=DEVNULL, stderr=PIPE, + stdout=DEVNULL) + + # make sure the command completes + initret = init.wait(2) + self.assertEqual(initret, 0) + + # terminate responder + respret = resp.terminate() + stdout, errout = resp.communicate() + + # make sure we got the message + self.assertEqual(stdout, b"got msg: b'\\x04'\n") + + self.assertEqual(errout, b'') + + finally: + init.terminate() + _, errout = init.communicate() + self.assertEqual(errout, b'') + + resp.terminate() + _, errout = resp.communicate() + self.assertEqual(errout, b'') From fad1e9fe2282f4e292a543bb3d8915900b71a0d8 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Sat, 3 Dec 2022 12:45:28 -0800 Subject: [PATCH 6/7] add test for pk version of the commands... One missing thing is the ability to generate public keys from private keys for running the code standalone.. --- lora.py | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/lora.py b/lora.py index 3f4b392..07329bb 100644 --- a/lora.py +++ b/lora.py @@ -1576,19 +1576,36 @@ class TestLORAmain(unittest.TestCase): init_key = X25519.gen() resp_key = X25519.gen() + f = {} + for i in [ 'init', 'resp' ]: + key = locals()['%s_key' % i] + + for j in [ 'pub', 'priv' ]: + data = getattr(key, 'get%s' % j)().hex() + file = self.basetempdir / ('%s_%s.key' % (i, j)) + f['%s_%s_key_file' % (i, j)] = file + + with file.open('w') as fp: + fp.write(data) + + keys.append(('pk', ( + [ '-k', f['init_priv_key_file'], + '-p', f['resp_pub_key_file'] ], + [ '-k', f['resp_priv_key_file'], + '-p', f['init_pub_key_file'] ] + ))) for name, (initargs, respargs) in keys: - with self.subTest(name=name): + # XXX - macosx specific library path var + with self.subTest(name=name), patch.dict(os.environ, + dict(DYLD_LIBRARY_PATH=self.origcwd)): self.run_program_keyargs(initargs, respargs) def run_program_keyargs(self, initargs, respargs): try: - # XXX - macosx specific library path var - with patch.dict(os.environ, - dict(DYLD_LIBRARY_PATH=self.origcwd)): - resp = subprocess.Popen([ 'python', __file__, - '-r', 'dummy:TestAttr.dummy_func' ] + - respargs, stdin=DEVNULL, stderr=PIPE, - stdout=PIPE) + resp = subprocess.Popen([ 'python', __file__, + '-r', 'dummy:TestAttr.dummy_func' ] + + respargs, stdin=DEVNULL, stderr=PIPE, + stdout=PIPE) init = subprocess.Popen([ 'python', __file__ ] + initargs + [ 'ping' ], stdin=DEVNULL, stderr=PIPE, @@ -1608,10 +1625,12 @@ class TestLORAmain(unittest.TestCase): self.assertEqual(errout, b'') finally: - init.terminate() + init.kill() _, errout = init.communicate() + #print(repr(errout)) + #sys.stdout.flush() self.assertEqual(errout, b'') - resp.terminate() + resp.kill() _, errout = resp.communicate() self.assertEqual(errout, b'') From 77cd0a655872a5bd64b890102127d256235e7cc3 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Sat, 3 Dec 2022 12:51:40 -0800 Subject: [PATCH 7/7] support generating a private/public key pair by running this... Need to think a bit more as it requires the test library, which isn't immediately available... Likely need to make this a proper package and put the library there.. --- syote_comms.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/syote_comms.py b/syote_comms.py index 07f9ed1..d8bd667 100644 --- a/syote_comms.py +++ b/syote_comms.py @@ -225,6 +225,12 @@ def comms_process_wrap(state, input): return outbuf._from() +if __name__ == '__main__': + key = X25519.gen() + + print(key.getpriv().hex()) + print(key.getpub().hex()) + class TestX25519(unittest.TestCase): PUBLIC_BYTES = EC_PUBLIC_BYTES PRIVATE_BYTES = EC_PRIVATE_BYTES