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.
 
 
 
 
 
 

192 lines
4.9 KiB

  1. # Toy25519.py - Toy Ed25519 arithmetic library with Strobelite interface.
  2. # This version of the Ed25519 library has the Edwards arithmetic, but no
  3. # hashing implemented for the signatures -- the hashing is done by Strobe lite.
  4. #
  5. # Written in 2011? by Daniel J. Bernstein <djb@cr.yp.to>
  6. # 2013 by Donald Stufft <donald@stufft.io>
  7. # 2013 by Alex Gaynor <alex.gaynor@gmail.com>
  8. # 2013 by Greg Price <price@mit.edu>
  9. # 2015 by Mike Hamburg <mike@shiftleft.org>
  10. #
  11. # To the extent possible under law, the author(s) have dedicated all copyright
  12. # and related and neighboring rights to this software to the public domain
  13. # worldwide. This software is distributed without any warranty.
  14. #
  15. # You should have received a copy of the CC0 Public Domain Dedication along
  16. # with this software. If not, see
  17. # <http://creativecommons.org/publicdomain/zero/1.0/>.
  18. """
  19. NB: This code is not safe for use with secret keys or secret data.
  20. The only safe use of this code is for verifying signatures on public messages.
  21. Functions for computing the public key of a secret key and for signing
  22. a message are included, namely publickey_unsafe and signature_unsafe,
  23. for testing purposes only.
  24. The root of the problem is that Python's long-integer arithmetic is
  25. not designed for use in cryptography. Specifically, it may take more
  26. or less time to execute an operation depending on the values of the
  27. inputs, and its memory access patterns may also depend on the inputs.
  28. This opens it to timing and cache side-channel attacks which can
  29. disclose data to an attacker. We rely on Python's long-integer
  30. arithmetic, so we cannot handle secrets without risking their disclosure.
  31. """
  32. import hashlib
  33. import operator
  34. import sys
  35. import os
  36. __version__ = "1.0.dev0"
  37. # Useful for very coarse version differentiation.
  38. PY3 = sys.version_info[0] == 3
  39. b = 256
  40. q = 2 ** 255 - 19
  41. l = 2 ** 252 + 27742317777372353535851937790883648493
  42. def inv(z):
  43. """$= z^{-1} \mod q$, for z != 0"""
  44. return pow(z,q-2,q)
  45. d = -121665 * inv(121666) % q
  46. I = pow(2, (q - 1) // 4, q)
  47. def xrecover(y):
  48. xx = (y * y - 1) * inv(d * y * y + 1)
  49. x = pow(xx, (q + 3) // 8, q)
  50. if (x * x - xx) % q != 0:
  51. x = (x * I) % q
  52. if (x * x - xx) % q != 0:
  53. # It ain't square!
  54. return None
  55. if x % 2 != 0:
  56. x = q-x
  57. return x
  58. def decodeint(s):
  59. s = bytearray(s)
  60. return sum(b<<(8*i) for i,b in enumerate(s))
  61. def encodeint(y,bytes=32):
  62. if y >= 1<<(8*bytes): return None
  63. return bytearray([
  64. (y>>(8*i)) & 0xFF
  65. for i in range(bytes)
  66. ])
  67. def decodepoint(s):
  68. ss = bytearray(s)
  69. xlo = ss[-1]>>7
  70. ss[-1] &= 0x7F
  71. y = decodeint(ss)
  72. if y >= q: return None
  73. x = xrecover(y)
  74. if x is None: return None
  75. if x & 1 != xlo: x = q - x
  76. P = (x, y, 1, (x*y) % q)
  77. return P
  78. def encodepoint(P):
  79. (x, y, z, t) = P
  80. zi = inv(z)
  81. x = (x * zi) % q
  82. y = (y * zi) % q
  83. ss = encodeint(y)
  84. ss[-1] ^= 0x80 * (x&1)
  85. return ss
  86. B = decodepoint(encodeint((4*inv(5)) % q))
  87. ident = (0, 1, 1, 0)
  88. def edwards_neg(point):
  89. (x,y,z,t) = point
  90. return (q-x)%q,y,z,(q-t)%q
  91. def edwards_add(P, Q):
  92. # This is formula sequence 'addition-add-2008-hwcd-3' from
  93. # http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
  94. (x1, y1, z1, t1) = P
  95. (x2, y2, z2, t2) = Q
  96. a = (y1-x1)*(y2-x2) % q
  97. b = (y1+x1)*(y2+x2) % q
  98. c = t1*2*d*t2 % q
  99. dd = z1*2*z2 % q
  100. e = b - a
  101. f = dd - c
  102. g = dd + c
  103. h = b + a
  104. x3 = e*f
  105. y3 = g*h
  106. t3 = e*h
  107. z3 = f*g
  108. return (x3 % q, y3 % q, z3 % q, t3 % q)
  109. def edwards_double(P):
  110. # MH: optimization not worth it.
  111. return edwards_add(P,P)
  112. def scalarmult(P, e):
  113. if e == 0:
  114. return ident
  115. Q = scalarmult(P, e // 2)
  116. Q = edwards_double(Q)
  117. if e & 1:
  118. Q = edwards_add(Q, P)
  119. return Q
  120. def scalarmult_B(e):
  121. # MH: optimization not worth it
  122. return scalarmult(B, e)
  123. class Toy25519:
  124. challenge_bytes = 32
  125. @staticmethod
  126. def get_pubkey(sk):
  127. return encodepoint(scalarmult_B(decodeint(sk)))
  128. @staticmethod
  129. def keygen():
  130. sk = bytearray(os.urandom((b+7)//8))
  131. return Toy25519.get_pubkey(sk),sk
  132. @staticmethod
  133. def ecdh(pk,sk):
  134. P = decodepoint(pk)
  135. if P is None: return None
  136. return encodepoint(scalarmult(P,8*decodeint(sk)))
  137. @staticmethod
  138. def sig_response(secret,esec,challenge):
  139. sl = decodeint(secret)
  140. el = decodeint(esec)
  141. cl = decodeint(challenge)
  142. response = (sl * cl + el) % l
  143. return encodeint(response)
  144. @staticmethod
  145. def sig_verify(pk,eph,challenge,response):
  146. P = decodepoint(pk)
  147. if P is None: return False
  148. MPC = scalarmult(edwards_neg(P),decodeint(challenge))
  149. BR = scalarmult_B(decodeint(response))
  150. EE = edwards_add(MPC,BR)
  151. return encodepoint(EE) == eph