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.
 
 
 
 
 
 

128 lines
4.8 KiB

  1. """
  2. Equivalent implementation of STROBE, based on CSHAKE. Doesn't implement the
  3. key tree. Designed to show that STROBE is equivalent to an instance of cSHAKE.
  4. Copyright (c) Mike Hamburg, Cryptography Research, 2016.
  5. I will need to contact legal to get a license for this; in the mean time it is
  6. for example purposes only.
  7. """
  8. from __future__ import absolute_import
  9. from Strobe.Keccak import cSHAKE128
  10. from Strobe.Strobe import AuthenticationFailed
  11. class StrobeCShake(object):
  12. def __init__(self,proto,prim=cSHAKE128,copy_of=None):
  13. if copy_of is None:
  14. self.prim = prim("STROBEv1.0.2")
  15. self.st = self.prim()
  16. self.rate = self.st.rate_bytes - 2
  17. self.output = bytearray(self.rate)
  18. self.begin_off = 0
  19. self.dir = None
  20. self.proto = proto
  21. self.duplex(0x12,proto)
  22. else:
  23. self.rate,self.begin_off,self.dir,self.proto,self.st = \
  24. (copy_of.rate,copy_of.begin_off,copy_of.dir,
  25. copy_of.proto,copy_of.st.copy())
  26. self.output = copy_of.output.copy()
  27. self.prim = copy_of.prim
  28. def __repr__(self):
  29. return "StrobeCShake(\"%s\",%s)" % (self.proto, repr(self.prim))
  30. def copy(self): return Strobe(None,copy_of=self)
  31. def deepcopy(self): return self.copy()
  32. def duplex(self,op,data,more=False,meta_op=0b10010,metadata=None):
  33. """
  34. STROBE main duplexing mode, as in Strobe.py
  35. """
  36. (I,A,C,T,M,K) = ((op>>i) & 1 for i in range(6))
  37. assert (op >= 0 and op <= 0x3F)
  38. assert not K # Unimplemented!
  39. def runF():
  40. padlen = len(self.output)
  41. self.st.update(bytearray([self.begin_off]))
  42. self.output = self.st.digest(self.rate)
  43. if padlen == 0:
  44. self.st.update([self.st.suffix ^ 0x80])
  45. else:
  46. self.st.update(
  47. [self.st.suffix]+(padlen-1)*[0x00]+[0x80])
  48. self.begin_off = 0
  49. meta_out = bytearray(0)
  50. if not more:
  51. # Begin the operation. First apply metadata if there is any
  52. if metadata is not None:
  53. if T and I and (meta_op & 0b1000):
  54. # Receive data, so receive meta-op as well.
  55. meta_op |= 0b1
  56. meta_out = self.duplex(meta_op,metadata)
  57. # Mark the beginning of the operation.
  58. self.st.update([self.begin_off])
  59. self.output = self.output[1:]
  60. self.begin_off = self.rate-len(self.output)
  61. if len(self.output) == 0: runF()
  62. # Mark the mode; if the mode uses cipher then run F
  63. if T and self.dir is None: self.dir = I
  64. adjDirOp = op ^ (self.dir if T else 0)
  65. self.st.update([adjDirOp])
  66. self.output = self.output[1:]
  67. if len(self.output) == 0 or C or K: runF()
  68. # Change to byte array
  69. data = bytearray(data)
  70. main_out = bytearray()
  71. # OK, this is the actual duplex routine
  72. while len(data):
  73. can_do = min(len(data), len(self.output))
  74. wrk = data[0:can_do]
  75. update_after = I or not T
  76. if not update_after: self.st.update(wrk)
  77. if C:
  78. for i in range(can_do):
  79. wrk[i] ^= self.output[i]
  80. if update_after: self.st.update(wrk)
  81. main_out += wrk
  82. self.output = self.output[can_do:]
  83. data = data[can_do:]
  84. if len(self.output) == 0:
  85. runF()
  86. if (A and I) or (T and not I):
  87. return meta_out + main_out
  88. elif (I,T,A) == (True,True,False):
  89. # Check the MAC (or recv_zero, but don't do that)
  90. assert not more # Technically well-defined, but has a side channel
  91. any_data = 0
  92. for d in main_out: any_data |= d
  93. if d: raise Exception("MAC failed")
  94. # No data, but maybe there is metadata.
  95. return meta_out
  96. def ad (self,data, **kw): return self.duplex(0b0010,data,**kw)
  97. def key (self,data, **kw): return self.duplex(0b0110,data,**kw)
  98. def prf (self,data, **kw): return self.duplex(0b0111,data,**kw)
  99. def send_clr(self,data, **kw): return self.duplex(0b1010,data,**kw)
  100. def recv_clr(self,data, **kw): return self.duplex(0b1011,data,**kw)
  101. def send_enc(self,data, **kw): return self.duplex(0b1110,data,**kw)
  102. def recv_enc(self,data, **kw): return self.duplex(0b1111,data,**kw)
  103. def send_mac(self,data=16,**kw): return self.duplex(0b1100,data,**kw)
  104. def recv_mac(self,data ,**kw): return self.duplex(0b1101,data,**kw)
  105. def ratchet (self,data=32,**kw): return self.duplex(0b0100,data,**kw)