test_ecdh.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. import re
  2. import unittest
  3. from binascii import hexlify
  4. from Crypto.Util.py3compat import bord
  5. from Crypto.Hash import SHA256
  6. from Crypto.PublicKey import ECC
  7. from Crypto.SelfTest.st_common import list_test_cases
  8. from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof
  9. from Crypto.Protocol.DH import key_agreement
  10. class FIPS_ECDH_Tests_KAT(unittest.TestCase):
  11. pass
  12. test_vectors_verify = load_test_vectors(("Protocol", ),
  13. "KAS_ECC_CDH_PrimitiveTest.txt",
  14. "ECC CDH Primitive (SP800-56A Section 5.7.1.2)",
  15. {
  16. 'qcavsx': lambda x: int(x, 16),
  17. 'qcavsy': lambda x: int(x, 16),
  18. 'diut': lambda x: int(x, 16),
  19. 'qiutx': lambda x: int(x, 16),
  20. 'qiuty': lambda x: int(x, 16),
  21. }) or []
  22. for idx, tv in enumerate(test_vectors_verify):
  23. # Stand-alone header with curve name
  24. if isinstance(tv, str):
  25. res = re.match(r"\[([A-Za-z0-9-]+)\]", tv)
  26. assert res
  27. curve_name = res.group(1)
  28. continue
  29. public_key = ECC.construct(curve=curve_name,
  30. point_x=tv.qcavsx,
  31. point_y=tv.qcavsy)
  32. private_key = ECC.construct(curve=curve_name,
  33. d=tv.diut)
  34. exp_response = tv.ziut
  35. def ecdh_test(self,
  36. public_key=public_key,
  37. private_key=private_key,
  38. exp_response=exp_response):
  39. z = key_agreement(
  40. static_pub=public_key,
  41. static_priv=private_key,
  42. kdf=lambda x: x)
  43. self.assertEqual(z, exp_response)
  44. def ecdh_test_rev(self,
  45. public_key=public_key,
  46. private_key=private_key,
  47. exp_response=exp_response):
  48. z = key_agreement(
  49. static_pub=public_key,
  50. static_priv=private_key,
  51. kdf=lambda x: x)
  52. self.assertEqual(z, exp_response)
  53. setattr(FIPS_ECDH_Tests_KAT, "test_verify_positive_%d" % idx, ecdh_test)
  54. if idx == 1:
  55. setattr(FIPS_ECDH_Tests_KAT, "test_verify_positive_rev_%d" % idx, ecdh_test_rev)
  56. class TestVectorsECDHWycheproof(unittest.TestCase):
  57. desc = "Wycheproof ECDH tests"
  58. def add_tests(self, filename):
  59. def curve(g):
  60. return g['curve']
  61. def private(u):
  62. return int(u['private'], 16)
  63. result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
  64. filename,
  65. "Wycheproof ECDH (%s)"
  66. % filename,
  67. group_tag={'curve': curve},
  68. unit_tag={'private': private},
  69. )
  70. self.tv += result
  71. def setUp(self):
  72. self.tv = []
  73. self.desc = None
  74. self.add_tests("ecdh_secp224r1_ecpoint_test.json")
  75. self.add_tests("ecdh_secp256r1_ecpoint_test.json")
  76. self.add_tests("ecdh_secp384r1_ecpoint_test.json")
  77. self.add_tests("ecdh_secp521r1_ecpoint_test.json")
  78. self.add_tests("ecdh_secp224r1_test.json")
  79. self.add_tests("ecdh_secp256r1_test.json")
  80. self.add_tests("ecdh_secp384r1_test.json")
  81. self.add_tests("ecdh_secp521r1_test.json")
  82. def shortDescription(self):
  83. return self.desc
  84. def test_verify(self, tv):
  85. if len(tv.public) == 0:
  86. return
  87. try:
  88. if bord(tv.public[0]) == 4: # SEC1
  89. public_key = ECC.import_key(tv.public, curve_name=tv.curve)
  90. else:
  91. public_key = ECC.import_key(tv.public)
  92. except ValueError:
  93. assert tv.warning or not tv.valid
  94. return
  95. private_key = ECC.construct(curve=tv.curve, d=tv.private)
  96. try:
  97. z = key_agreement(static_pub=public_key,
  98. static_priv=private_key,
  99. kdf=lambda x: x)
  100. except ValueError:
  101. assert not tv.valid
  102. except TypeError as e:
  103. assert not tv.valid
  104. assert "incompatible curve" in str(e)
  105. else:
  106. self.assertEqual(z, tv.shared)
  107. assert tv.valid
  108. def runTest(self):
  109. for tv in self.tv:
  110. self.desc = "Wycheproof ECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
  111. self.test_verify(tv)
  112. class ECDH_Tests(unittest.TestCase):
  113. static_priv = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg9VHFVKh2a1aVFifH\n+BiyNaRa2kttEg3165Ye/dJxJ7KhRANCAARImIEXro5ZOcyWU2mq/+d79FEZXtTA\nbKkz1aICQXihQdCMzRNbeNtC9LFLzhu1slRKJ2xsDAlw9r6w6vwtkRzr\n-----END PRIVATE KEY-----')
  114. static_pub = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgHhmv8zmZ+Nw8fsZd\ns8tlZflyfw2NE1CRS9DWr3Y3O46hRANCAAS3hZVUCbk+uk3w4S/YOraEVGG+WYpk\nNO/vrwzufUUks2GV2OnBQESe0EBk4Jq8gn4ij8Lvs3rZX2yT+XfeATYd\n-----END PRIVATE KEY-----').public_key()
  115. eph_priv = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGPdJmFFFKzLPspIr\nE1T2cEjeIf4ajS9CpneP0e2b3AyhRANCAAQBexAA5BYDcXHs2KOksTYUsst4HhPt\nkp0zkgI2virc3OGJFNGPaCCPfFCQJHwLRaEpiq3SoQlgoBwSc8ZPsl3y\n-----END PRIVATE KEY-----')
  116. eph_pub = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghaVZXElSEGEojFKF\nOU0JCpxWUWHvWQUR81gwWrOp76ShRANCAATi1Ib2K+YR3AckD8wxypWef7pw5PRw\ntBaB3RDPyE7IjHZC6yu1DbcXoCdtaw+F5DM+4zpl59n5ZaIy/Yl1BdIy\n-----END PRIVATE KEY-----')
  117. def test_1(self):
  118. # C(0, 2s)
  119. kdf = lambda x: SHA256.new(x).digest()
  120. z = key_agreement(
  121. kdf=kdf,
  122. static_pub=self.static_pub,
  123. static_priv=self.static_priv)
  124. self.assertEqual(hexlify(z),
  125. b"3960a1101d1193cbaffef4cc7202ebff783c22c6d2e0d5d530ffc66dc197ea9c")
  126. def test_2(self):
  127. # C(2e, 2s)
  128. kdf = lambda x: SHA256.new(x).digest()
  129. z = key_agreement(
  130. kdf=kdf,
  131. static_pub=self.static_pub,
  132. static_priv=self.static_priv,
  133. eph_pub=self.eph_pub,
  134. eph_priv=self.eph_priv)
  135. self.assertEqual(hexlify(z),
  136. b"7447b733d40c8fab2c633b3dc61e4a8c742f3a6af7e16fb0cc486f5bdb5d6ba2")
  137. def test_3(self):
  138. # C(1e, 2s)
  139. kdf = lambda x: SHA256.new(x).digest()
  140. z = key_agreement(
  141. kdf=kdf,
  142. static_pub=self.static_pub,
  143. static_priv=self.static_priv,
  144. eph_priv=self.eph_priv)
  145. self.assertEqual(hexlify(z),
  146. b"9e977ae45f33bf67f285d064d83e6632bcafe3a7d33fe571233bab4794ace759")
  147. def test_4(self):
  148. # C(1e, 2s)
  149. kdf = lambda x: SHA256.new(x).digest()
  150. z = key_agreement(
  151. kdf=kdf,
  152. static_pub=self.static_pub,
  153. static_priv=self.static_priv,
  154. eph_pub=self.eph_pub)
  155. self.assertEqual(hexlify(z),
  156. b"c9532df6aa7e9dbe5fe85da31ee25ff19c179c88691ec4b8328cc2036dcdadf2")
  157. def test_5(self):
  158. # C(2e, 1s) is not supported
  159. kdf = lambda x: SHA256.new(x).digest()
  160. self.assertRaises(ValueError,
  161. key_agreement,
  162. kdf=kdf,
  163. static_priv=self.static_priv,
  164. eph_pub=self.eph_pub,
  165. eph_priv=self.eph_priv)
  166. def test_6(self):
  167. # C(2e, 1s) is not supported
  168. kdf = lambda x: SHA256.new(x).digest()
  169. self.assertRaises(ValueError,
  170. key_agreement,
  171. kdf=kdf,
  172. static_pub=self.static_pub,
  173. eph_pub=self.eph_pub,
  174. eph_priv=self.eph_priv)
  175. def test_7(self):
  176. # C(2e, 0)
  177. kdf = lambda x: SHA256.new(x).digest()
  178. z = key_agreement(
  179. kdf=kdf,
  180. eph_pub=self.eph_pub,
  181. eph_priv=self.eph_priv)
  182. self.assertEqual(hexlify(z),
  183. b"feb257ebe063078b1391aac07913283d7b642ad7df61b46dfc9cd6f420bb896a")
  184. def test_8(self):
  185. # C(1e, 1s)
  186. kdf = lambda x: SHA256.new(x).digest()
  187. z = key_agreement(
  188. kdf=kdf,
  189. static_priv=self.static_priv,
  190. eph_pub=self.eph_pub)
  191. self.assertEqual(hexlify(z),
  192. b"ee4dc995117476ed57fd17ff0ed44e9f0466d46b929443bc0db9380317583b04")
  193. def test_9(self):
  194. # C(1e, 1s)
  195. kdf = lambda x: SHA256.new(x).digest()
  196. z = key_agreement(
  197. kdf=kdf,
  198. static_pub=self.static_pub,
  199. eph_priv=self.eph_priv)
  200. self.assertEqual(hexlify(z),
  201. b"2351cc2014f7c40468fa072b5d30f706eeaeef7507311cd8e59bab3b43f03c51")
  202. def test_10(self):
  203. # No private (local) keys
  204. kdf = lambda x: SHA256.new(x).digest()
  205. self.assertRaises(ValueError,
  206. key_agreement,
  207. kdf=kdf,
  208. static_pub=self.static_pub,
  209. eph_pub=self.eph_pub)
  210. def test_11(self):
  211. # No public (peer) keys
  212. kdf = lambda x: SHA256.new(x).digest()
  213. self.assertRaises(ValueError,
  214. key_agreement,
  215. kdf=kdf,
  216. static_priv=self.static_priv,
  217. eph_priv=self.eph_priv)
  218. def test_12(self):
  219. # failure if kdf is missing
  220. self.assertRaises(ValueError,
  221. key_agreement,
  222. static_pub=self.static_pub,
  223. static_priv=self.static_priv)
  224. def get_tests(config={}):
  225. tests = []
  226. tests += list_test_cases(FIPS_ECDH_Tests_KAT)
  227. tests += [TestVectorsECDHWycheproof()]
  228. tests += list_test_cases(ECDH_Tests)
  229. slow_tests = config.get('slow_tests')
  230. if slow_tests:
  231. pass
  232. return tests
  233. if __name__ == '__main__':
  234. def suite():
  235. return unittest.TestSuite(get_tests())
  236. unittest.main(defaultTest='suite')