Implement a secure ICS protocol targeting LoRa Node151 microcontroller for controlling irrigation.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

100 lines
3.7 KiB

  1. """
  2. A wrapper around a C implementation of STROBE.
  3. Copyright (c) Mike Hamburg, Cryptography Research, 2016.
  4. I will need to contact legal to get a license for this; in the mean time it is
  5. for example purposes only.
  6. """
  7. from __future__ import absolute_import
  8. from ctypes import *
  9. from Strobe.Strobe import AuthenticationFailed,I,A,C,T,M,K # TODO
  10. class CStrobe_Failed(Exception):
  11. """Thrown when a MAC fails, or some internal exception occurred."""
  12. pass
  13. PATH = "../c/build/"
  14. _libstrobe = CDLL(PATH+"libstrobe.so.1")
  15. class CStrobe_Container(Array):
  16. _strobe_size = c_size_t.in_dll(_libstrobe,"strobe_abi_sizeof_strobe_s").value
  17. _type_ = c_ulong
  18. _length_ = int(1 + (_strobe_size-1)//sizeof(c_ulong))
  19. _libstrobe.strobe_abi_overhead_for_transaction.argtypes = (c_uint32,)
  20. _libstrobe.strobe_abi_overhead_for_transaction.restype = c_ssize_t
  21. _libstrobe.strobe_abi_attach_buffer.argtypes = (CStrobe_Container,POINTER(c_ubyte),c_size_t)
  22. _libstrobe.strobe_abi_attach_buffer.restype = None
  23. _libstrobe.strobe_init.argtypes = (CStrobe_Container,POINTER(c_ubyte),c_size_t)
  24. _libstrobe.strobe_init.restype = None
  25. _libstrobe.strobe_duplex.argtypes = (CStrobe_Container,c_uint32,POINTER(c_ubyte),c_size_t)
  26. _libstrobe.strobe_duplex.restype = c_ssize_t
  27. class CStrobe(object):
  28. def __init__(self, proto):
  29. self.container = CStrobe_Container()
  30. proto = self.bufferize(proto)
  31. _libstrobe.strobe_init(self.container,proto,sizeof(proto))
  32. @staticmethod
  33. def bufferize(data):
  34. return (c_ubyte * len(data))(*bytearray(data))
  35. def operate(self, flags, data, more=False, meta_flags=A|M, metadata=None):
  36. # TODO: test operate() with generated metadata
  37. meta_out = bytearray()
  38. if (not more) and (metadata is not None):
  39. meta_out = self.operate(meta_flags, metadata)
  40. if more: flags |= 1<<28
  41. if (flags & (I|T) != (I|T)) and (flags & (I|A) != A):
  42. # Operation takes no input
  43. assert isinstance(data,int)
  44. datalen = data
  45. data = None
  46. else:
  47. data = self.bufferize(data)
  48. datalen = len(data)
  49. if (flags & (I|A) != (I|A)) and (flags & (I|T) != T):
  50. # Operation produces no output
  51. output = None
  52. outputlen = 0
  53. else:
  54. oh = _libstrobe.strobe_abi_overhead_for_transaction(flags)
  55. output = (c_ubyte * (datalen + oh))()
  56. outputlen = sizeof(output)
  57. if flags & I:
  58. # On inbound, the output is app side
  59. a,alen,t,tlen = output,outputlen,data,datalen
  60. else:
  61. # On outbound, the output is transport side
  62. a,alen,t,tlen = data,datalen,output,outputlen
  63. _libstrobe.strobe_abi_attach_buffer(self.container,t,tlen)
  64. ret = _libstrobe.strobe_duplex(self.container,flags,a,alen)
  65. if (ret < 0): raise CStrobe_failed()
  66. if output is None: return meta_out
  67. else: return bytearray(output) + meta_out
  68. def ad (self,data, **kw): return self.operate(0b0010,data,**kw)
  69. def key (self,data, **kw): return self.operate(0b0110,data,**kw)
  70. def prf (self,data, **kw): return self.operate(0b0111,data,**kw)
  71. def send_clr(self,data, **kw): return self.operate(0b1010,data,**kw)
  72. def recv_clr(self,data, **kw): return self.operate(0b1011,data,**kw)
  73. def send_enc(self,data, **kw): return self.operate(0b1110,data,**kw)
  74. def recv_enc(self,data, **kw): return self.operate(0b1111,data,**kw)
  75. def send_mac(self,data=16,**kw): return self.operate(0b1100,data,**kw)
  76. def recv_mac(self,data ,**kw): return self.operate(0b1101,data,**kw)
  77. def ratchet (self,data=32,**kw): return self.operate(0b0100,data,**kw)