test_ecdh.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. import re
  2. import base64
  3. import unittest
  4. from binascii import hexlify, unhexlify
  5. from Crypto.Util.py3compat import bord
  6. from Crypto.Hash import SHA256
  7. from Crypto.PublicKey import ECC
  8. from Crypto.SelfTest.st_common import list_test_cases
  9. from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof
  10. from Crypto.Protocol import DH
  11. from Crypto.Protocol.DH import (key_agreement,
  12. import_x25519_public_key,
  13. import_x25519_private_key,
  14. import_x448_public_key,
  15. import_x448_private_key)
  16. class FIPS_ECDH_Tests_KAT(unittest.TestCase):
  17. pass
  18. test_vectors_verify = load_test_vectors(("Protocol", ),
  19. "KAS_ECC_CDH_PrimitiveTest.txt",
  20. "ECC CDH Primitive (SP800-56A Section 5.7.1.2)",
  21. {
  22. 'qcavsx': lambda x: int(x, 16),
  23. 'qcavsy': lambda x: int(x, 16),
  24. 'diut': lambda x: int(x, 16),
  25. 'qiutx': lambda x: int(x, 16),
  26. 'qiuty': lambda x: int(x, 16),
  27. }) or []
  28. for idx, tv in enumerate(test_vectors_verify):
  29. # Stand-alone header with curve name
  30. if isinstance(tv, str):
  31. res = re.match(r"\[([A-Za-z0-9-]+)\]", tv)
  32. assert res
  33. curve_name = res.group(1)
  34. continue
  35. public_key = ECC.construct(curve=curve_name,
  36. point_x=tv.qcavsx,
  37. point_y=tv.qcavsy)
  38. private_key = ECC.construct(curve=curve_name,
  39. d=tv.diut)
  40. exp_response = tv.ziut
  41. def ecdh_test(self,
  42. public_key=public_key,
  43. private_key=private_key,
  44. exp_response=exp_response):
  45. z = key_agreement(
  46. static_pub=public_key,
  47. static_priv=private_key,
  48. kdf=lambda x: x)
  49. self.assertEqual(z, exp_response)
  50. def ecdh_test_rev(self,
  51. public_key=public_key,
  52. private_key=private_key,
  53. exp_response=exp_response):
  54. z = key_agreement(
  55. static_pub=public_key,
  56. static_priv=private_key,
  57. kdf=lambda x: x)
  58. self.assertEqual(z, exp_response)
  59. setattr(FIPS_ECDH_Tests_KAT, "test_verify_positive_%d" % idx, ecdh_test)
  60. if idx == 1:
  61. setattr(FIPS_ECDH_Tests_KAT, "test_verify_positive_rev_%d" % idx, ecdh_test_rev)
  62. class TestVectorsECDHWycheproof(unittest.TestCase):
  63. desc = "Wycheproof ECDH tests"
  64. def add_tests(self, filename):
  65. def curve(g):
  66. return g['curve']
  67. def private(u):
  68. return int(u['private'], 16)
  69. result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
  70. filename,
  71. "Wycheproof ECDH (%s)"
  72. % filename,
  73. group_tag={'curve': curve},
  74. unit_tag={'private': private},
  75. )
  76. self.tv += result
  77. def setUp(self):
  78. self.tv = []
  79. self.desc = None
  80. self.add_tests("ecdh_secp224r1_ecpoint_test.json")
  81. self.add_tests("ecdh_secp256r1_ecpoint_test.json")
  82. self.add_tests("ecdh_secp384r1_ecpoint_test.json")
  83. self.add_tests("ecdh_secp521r1_ecpoint_test.json")
  84. self.add_tests("ecdh_secp224r1_test.json")
  85. self.add_tests("ecdh_secp256r1_test.json")
  86. self.add_tests("ecdh_secp384r1_test.json")
  87. self.add_tests("ecdh_secp521r1_test.json")
  88. def shortDescription(self):
  89. return self.desc
  90. def test_verify(self, tv):
  91. if len(tv.public) == 0:
  92. return
  93. try:
  94. if bord(tv.public[0]) == 4: # SEC1
  95. public_key = ECC.import_key(tv.public, curve_name=tv.curve)
  96. else:
  97. public_key = ECC.import_key(tv.public)
  98. except ValueError:
  99. assert tv.warning or not tv.valid
  100. return
  101. private_key = ECC.construct(curve=tv.curve, d=tv.private)
  102. try:
  103. z = key_agreement(static_pub=public_key,
  104. static_priv=private_key,
  105. kdf=lambda x: x)
  106. except ValueError:
  107. assert not tv.valid
  108. except TypeError as e:
  109. assert not tv.valid
  110. assert "incompatible curve" in str(e)
  111. else:
  112. self.assertEqual(z, tv.shared)
  113. assert tv.valid
  114. def runTest(self):
  115. for tv in self.tv:
  116. self.desc = "Wycheproof ECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
  117. self.test_verify(tv)
  118. class ECDH_Tests(unittest.TestCase):
  119. static_priv = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg9VHFVKh2a1aVFifH\n+BiyNaRa2kttEg3165Ye/dJxJ7KhRANCAARImIEXro5ZOcyWU2mq/+d79FEZXtTA\nbKkz1aICQXihQdCMzRNbeNtC9LFLzhu1slRKJ2xsDAlw9r6w6vwtkRzr\n-----END PRIVATE KEY-----')
  120. static_pub = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgHhmv8zmZ+Nw8fsZd\ns8tlZflyfw2NE1CRS9DWr3Y3O46hRANCAAS3hZVUCbk+uk3w4S/YOraEVGG+WYpk\nNO/vrwzufUUks2GV2OnBQESe0EBk4Jq8gn4ij8Lvs3rZX2yT+XfeATYd\n-----END PRIVATE KEY-----').public_key()
  121. eph_priv = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGPdJmFFFKzLPspIr\nE1T2cEjeIf4ajS9CpneP0e2b3AyhRANCAAQBexAA5BYDcXHs2KOksTYUsst4HhPt\nkp0zkgI2virc3OGJFNGPaCCPfFCQJHwLRaEpiq3SoQlgoBwSc8ZPsl3y\n-----END PRIVATE KEY-----')
  122. eph_pub = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghaVZXElSEGEojFKF\nOU0JCpxWUWHvWQUR81gwWrOp76ShRANCAATi1Ib2K+YR3AckD8wxypWef7pw5PRw\ntBaB3RDPyE7IjHZC6yu1DbcXoCdtaw+F5DM+4zpl59n5ZaIy/Yl1BdIy\n-----END PRIVATE KEY-----')
  123. def test_1(self):
  124. # C(0, 2s)
  125. kdf = lambda x: SHA256.new(x).digest()
  126. z = key_agreement(
  127. kdf=kdf,
  128. static_pub=self.static_pub,
  129. static_priv=self.static_priv)
  130. self.assertEqual(hexlify(z),
  131. b"3960a1101d1193cbaffef4cc7202ebff783c22c6d2e0d5d530ffc66dc197ea9c")
  132. def test_2(self):
  133. # C(2e, 2s)
  134. kdf = lambda x: SHA256.new(x).digest()
  135. z = key_agreement(
  136. kdf=kdf,
  137. static_pub=self.static_pub,
  138. static_priv=self.static_priv,
  139. eph_pub=self.eph_pub,
  140. eph_priv=self.eph_priv)
  141. self.assertEqual(hexlify(z),
  142. b"7447b733d40c8fab2c633b3dc61e4a8c742f3a6af7e16fb0cc486f5bdb5d6ba2")
  143. def test_3(self):
  144. # C(1e, 2s)
  145. kdf = lambda x: SHA256.new(x).digest()
  146. z = key_agreement(
  147. kdf=kdf,
  148. static_pub=self.static_pub,
  149. static_priv=self.static_priv,
  150. eph_priv=self.eph_priv)
  151. self.assertEqual(hexlify(z),
  152. b"9e977ae45f33bf67f285d064d83e6632bcafe3a7d33fe571233bab4794ace759")
  153. def test_4(self):
  154. # C(1e, 2s)
  155. kdf = lambda x: SHA256.new(x).digest()
  156. z = key_agreement(
  157. kdf=kdf,
  158. static_pub=self.static_pub,
  159. static_priv=self.static_priv,
  160. eph_pub=self.eph_pub)
  161. self.assertEqual(hexlify(z),
  162. b"c9532df6aa7e9dbe5fe85da31ee25ff19c179c88691ec4b8328cc2036dcdadf2")
  163. def test_5(self):
  164. # C(2e, 1s) is not supported
  165. kdf = lambda x: SHA256.new(x).digest()
  166. self.assertRaises(ValueError,
  167. key_agreement,
  168. kdf=kdf,
  169. static_priv=self.static_priv,
  170. eph_pub=self.eph_pub,
  171. eph_priv=self.eph_priv)
  172. def test_6(self):
  173. # C(2e, 1s) is not supported
  174. kdf = lambda x: SHA256.new(x).digest()
  175. self.assertRaises(ValueError,
  176. key_agreement,
  177. kdf=kdf,
  178. static_pub=self.static_pub,
  179. eph_pub=self.eph_pub,
  180. eph_priv=self.eph_priv)
  181. def test_7(self):
  182. # C(2e, 0)
  183. kdf = lambda x: SHA256.new(x).digest()
  184. z = key_agreement(
  185. kdf=kdf,
  186. eph_pub=self.eph_pub,
  187. eph_priv=self.eph_priv)
  188. self.assertEqual(hexlify(z),
  189. b"feb257ebe063078b1391aac07913283d7b642ad7df61b46dfc9cd6f420bb896a")
  190. def test_8(self):
  191. # C(1e, 1s)
  192. kdf = lambda x: SHA256.new(x).digest()
  193. z = key_agreement(
  194. kdf=kdf,
  195. static_priv=self.static_priv,
  196. eph_pub=self.eph_pub)
  197. self.assertEqual(hexlify(z),
  198. b"ee4dc995117476ed57fd17ff0ed44e9f0466d46b929443bc0db9380317583b04")
  199. def test_9(self):
  200. # C(1e, 1s)
  201. kdf = lambda x: SHA256.new(x).digest()
  202. z = key_agreement(
  203. kdf=kdf,
  204. static_pub=self.static_pub,
  205. eph_priv=self.eph_priv)
  206. self.assertEqual(hexlify(z),
  207. b"2351cc2014f7c40468fa072b5d30f706eeaeef7507311cd8e59bab3b43f03c51")
  208. def test_10(self):
  209. # No private (local) keys
  210. kdf = lambda x: SHA256.new(x).digest()
  211. self.assertRaises(ValueError,
  212. key_agreement,
  213. kdf=kdf,
  214. static_pub=self.static_pub,
  215. eph_pub=self.eph_pub)
  216. def test_11(self):
  217. # No public (peer) keys
  218. kdf = lambda x: SHA256.new(x).digest()
  219. self.assertRaises(ValueError,
  220. key_agreement,
  221. kdf=kdf,
  222. static_priv=self.static_priv,
  223. eph_priv=self.eph_priv)
  224. def test_12(self):
  225. # failure if kdf is missing
  226. self.assertRaises(ValueError,
  227. key_agreement,
  228. static_pub=self.static_pub,
  229. static_priv=self.static_priv)
  230. class X25519_Tests(unittest.TestCase):
  231. def test_rfc7748_1(self):
  232. tvs = (
  233. ("a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
  234. "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
  235. "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552"),
  236. ("4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d",
  237. "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493",
  238. "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957"),
  239. )
  240. for tv1, tv2, tv3 in tvs:
  241. priv_key = DH.import_x25519_private_key(unhexlify(tv1))
  242. pub_key = DH.import_x25519_public_key(unhexlify(tv2))
  243. result = key_agreement(static_pub=pub_key,
  244. static_priv=priv_key,
  245. kdf=lambda x: x)
  246. self.assertEqual(result, unhexlify(tv3))
  247. def test_rfc7748_2(self):
  248. k = unhexlify("0900000000000000000000000000000000000000000000000000000000000000")
  249. priv_key = DH.import_x25519_private_key(k)
  250. pub_key = DH.import_x25519_public_key(k)
  251. result = key_agreement(static_pub=pub_key,
  252. static_priv=priv_key,
  253. kdf=lambda x: x)
  254. self.assertEqual(
  255. result,
  256. unhexlify("422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079")
  257. )
  258. for _ in range(999):
  259. priv_key = DH.import_x25519_private_key(result)
  260. pub_key = DH.import_x25519_public_key(k)
  261. k = result
  262. result = key_agreement(static_pub=pub_key,
  263. static_priv=priv_key,
  264. kdf=lambda x: x)
  265. self.assertEqual(
  266. result,
  267. unhexlify("684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51")
  268. )
  269. def test_rfc7748_3(self):
  270. tv1 = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"
  271. tv2 = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"
  272. tv3 = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"
  273. tv4 = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"
  274. tv5 = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
  275. alice_priv_key = DH.import_x25519_private_key(unhexlify(tv1))
  276. alice_pub_key = DH.import_x25519_public_key(unhexlify(tv2))
  277. bob_priv_key = DH.import_x25519_private_key(unhexlify(tv3))
  278. bob_pub_key = DH.import_x25519_public_key(unhexlify(tv4))
  279. secret = unhexlify(tv5)
  280. result1 = key_agreement(static_pub=alice_pub_key,
  281. static_priv=bob_priv_key,
  282. kdf=lambda x: x)
  283. result2 = key_agreement(static_pub=bob_pub_key,
  284. static_priv=alice_priv_key,
  285. kdf=lambda x: x)
  286. self.assertEqual(result1, secret)
  287. self.assertEqual(result2, secret)
  288. def test_weak(self):
  289. weak_keys = (
  290. "0000000000000000000000000000000000000000000000000000000000000000",
  291. "0100000000000000000000000000000000000000000000000000000000000000",
  292. "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800",
  293. "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157",
  294. "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
  295. "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
  296. "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
  297. # The implementation will accept these value, but only because
  298. # it will set the MSB to zero (as required by RFC7748, Section 5),
  299. # therefore leading to another public key (and to a point which is
  300. # not of low order anymore).
  301. # "cdeb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880",
  302. # "4c9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7",
  303. # "d9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
  304. # "daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
  305. # "dbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
  306. )
  307. for x in weak_keys:
  308. self.assertRaises(ValueError,
  309. DH.import_x25519_public_key,
  310. unhexlify(x))
  311. class X448_Tests(unittest.TestCase):
  312. def test_rfc7748_1(self):
  313. tvs = (
  314. ("3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3",
  315. "06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086",
  316. "ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f"),
  317. ("203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f",
  318. "0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db",
  319. "884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d"),
  320. )
  321. for tv1, tv2, tv3 in tvs:
  322. priv_key = DH.import_x448_private_key(unhexlify(tv1))
  323. pub_key = DH.import_x448_public_key(unhexlify(tv2))
  324. result = key_agreement(static_pub=pub_key,
  325. static_priv=priv_key,
  326. kdf=lambda x: x)
  327. self.assertEqual(result, unhexlify(tv3))
  328. def test_rfc7748_2(self):
  329. k = unhexlify("0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
  330. priv_key = DH.import_x448_private_key(k)
  331. pub_key = DH.import_x448_public_key(k)
  332. result = key_agreement(static_pub=pub_key,
  333. static_priv=priv_key,
  334. kdf=lambda x: x)
  335. self.assertEqual(
  336. result,
  337. unhexlify("3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113")
  338. )
  339. for _ in range(999):
  340. priv_key = DH.import_x448_private_key(result)
  341. pub_key = DH.import_x448_public_key(k)
  342. k = result
  343. result = key_agreement(static_pub=pub_key,
  344. static_priv=priv_key,
  345. kdf=lambda x: x)
  346. self.assertEqual(
  347. result,
  348. unhexlify("aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38")
  349. )
  350. def test_rfc7748_3(self):
  351. tv1 = "9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b"
  352. tv2 = "9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0"
  353. tv3 = "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d"
  354. tv4 = "3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609"
  355. tv5 = "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d"
  356. alice_priv_key = DH.import_x448_private_key(unhexlify(tv1))
  357. alice_pub_key = DH.import_x448_public_key(unhexlify(tv2))
  358. bob_priv_key = DH.import_x448_private_key(unhexlify(tv3))
  359. bob_pub_key = DH.import_x448_public_key(unhexlify(tv4))
  360. secret = unhexlify(tv5)
  361. result1 = key_agreement(static_pub=alice_pub_key,
  362. static_priv=bob_priv_key,
  363. kdf=lambda x: x)
  364. result2 = key_agreement(static_pub=bob_pub_key,
  365. static_priv=alice_priv_key,
  366. kdf=lambda x: x)
  367. self.assertEqual(result1, secret)
  368. self.assertEqual(result2, secret)
  369. def test_weak(self):
  370. weak_keys = (
  371. "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  372. "0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  373. "fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff",
  374. "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff",
  375. "00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
  376. )
  377. for x in weak_keys:
  378. self.assertRaises(ValueError,
  379. DH.import_x448_public_key,
  380. unhexlify(x))
  381. class TestVectorsX25519Wycheproof(unittest.TestCase):
  382. desc = "Wycheproof X25519 tests"
  383. def add_tests_hex(self, filename):
  384. def encoding(g):
  385. return g['type']
  386. def private(u):
  387. return unhexlify(u['private'])
  388. result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
  389. filename,
  390. "Wycheproof ECDH (%s)"
  391. % filename,
  392. group_tag={'encoding': encoding},
  393. unit_tag={'private': private}
  394. )
  395. self.tv += result
  396. def add_tests_ascii(self, filename):
  397. def encoding(g):
  398. return g['type']
  399. def public(u):
  400. return u['public']
  401. def private(u):
  402. return u['private']
  403. result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
  404. filename,
  405. "Wycheproof ECDH (%s)"
  406. % filename,
  407. group_tag={'encoding': encoding},
  408. unit_tag={'public': public,
  409. 'private': private}
  410. )
  411. self.tv += result
  412. def setUp(self):
  413. self.tv = []
  414. self.desc = None
  415. self.add_tests_hex("x25519_test.json")
  416. self.add_tests_hex("x25519_asn_test.json")
  417. self.add_tests_ascii("x25519_pem_test.json")
  418. self.add_tests_ascii("x25519_jwk_test.json")
  419. def shortDescription(self):
  420. return self.desc
  421. def test_verify(self, tv):
  422. if tv.encoding == "XdhComp":
  423. try:
  424. public_key = import_x25519_public_key(tv.public)
  425. except ValueError as e:
  426. assert tv.valid
  427. assert tv.warning
  428. assert "LowOrderPublic" in tv.flags
  429. assert "Invalid Curve25519" in str(e)
  430. return
  431. private_key = import_x25519_private_key(tv.private)
  432. elif tv.encoding in ("XdhAsnComp", "XdhPemComp"):
  433. try:
  434. public_key = ECC.import_key(tv.public)
  435. private_key = ECC.import_key(tv.private)
  436. except ECC.UnsupportedEccFeature as e:
  437. assert not tv.valid
  438. assert "Unsupported ECC" in str(e)
  439. return
  440. except ValueError:
  441. assert tv.valid
  442. assert tv.warning
  443. assert "LowOrderPublic" in tv.flags
  444. return
  445. elif tv.encoding == "XdhJwkComp":
  446. if 'y' in tv.public:
  447. return
  448. if 'x' not in tv.public:
  449. return
  450. if 'x' not in tv.private:
  451. return
  452. if tv.public.get('kty') != 'OKP':
  453. return
  454. if tv.public.get('crv') != 'X25519':
  455. return
  456. if tv.private.get('crv') != 'X25519':
  457. return
  458. def base64url_decode(input_str):
  459. input_str = input_str.replace('-', '+').replace('_', '/')
  460. padding = 4 - (len(input_str) % 4)
  461. if padding != 4:
  462. input_str += '=' * padding
  463. decoded_bytes = base64.b64decode(input_str)
  464. return decoded_bytes
  465. jwk_public = base64url_decode(tv.public['x'])
  466. jwk_private = base64url_decode(tv.private['d'])
  467. try:
  468. public_key = import_x25519_public_key(jwk_public)
  469. private_key = import_x25519_private_key(jwk_private)
  470. except ValueError as e:
  471. if tv.valid:
  472. assert tv.warning
  473. assert "LowOrderPublic" in tv.flags
  474. assert "Invalid Curve25519" in str(e)
  475. return
  476. else:
  477. assert "Incorrect length" in str(e)
  478. return
  479. except ValueError:
  480. assert tv.valid
  481. else:
  482. raise ValueError("Unknown encoding", tv.encoding)
  483. try:
  484. z = key_agreement(static_pub=public_key,
  485. static_priv=private_key,
  486. kdf=lambda x: x)
  487. except ValueError:
  488. assert not tv.valid
  489. except TypeError as e:
  490. assert not tv.valid
  491. assert "incompatible curve" in str(e)
  492. else:
  493. self.assertEqual(z, tv.shared)
  494. assert tv.valid
  495. def runTest(self):
  496. for tv in self.tv:
  497. self.desc = "Wycheproof XECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
  498. self.test_verify(tv)
  499. class TestVectorsX448Wycheproof(unittest.TestCase):
  500. desc = "Wycheproof X448 tests"
  501. def add_tests_hex(self, filename):
  502. def encoding(g):
  503. return g['type']
  504. def private(u):
  505. return unhexlify(u['private'])
  506. result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
  507. filename,
  508. "Wycheproof ECDH (%s)"
  509. % filename,
  510. group_tag={'encoding': encoding},
  511. unit_tag={'private': private}
  512. )
  513. self.tv += result
  514. def add_tests_ascii(self, filename):
  515. def encoding(g):
  516. return g['type']
  517. def public(u):
  518. return u['public']
  519. def private(u):
  520. return u['private']
  521. result = load_test_vectors_wycheproof(("Protocol", "wycheproof"),
  522. filename,
  523. "Wycheproof ECDH (%s)"
  524. % filename,
  525. group_tag={'encoding': encoding},
  526. unit_tag={'public': public,
  527. 'private': private}
  528. )
  529. self.tv += result
  530. def setUp(self):
  531. self.tv = []
  532. self.desc = None
  533. self.add_tests_hex("x448_test.json")
  534. self.add_tests_hex("x448_asn_test.json")
  535. self.add_tests_ascii("x448_pem_test.json")
  536. self.add_tests_ascii("x448_jwk_test.json")
  537. def shortDescription(self):
  538. return self.desc
  539. def test_verify(self, tv):
  540. if tv.encoding == "XdhComp":
  541. try:
  542. public_key = import_x448_public_key(tv.public)
  543. except ValueError as e:
  544. assert tv.valid
  545. assert tv.warning
  546. if len(tv.public) == 56:
  547. assert "LowOrderPublic" in tv.flags
  548. assert "Invalid Curve448" in str(e)
  549. else:
  550. assert "Incorrect Curve448" in str(e)
  551. return
  552. private_key = import_x448_private_key(tv.private)
  553. elif tv.encoding in ("XdhAsnComp", "XdhPemComp"):
  554. try:
  555. public_key = ECC.import_key(tv.public)
  556. private_key = ECC.import_key(tv.private)
  557. except ECC.UnsupportedEccFeature as e:
  558. assert not tv.valid
  559. assert "Unsupported ECC" in str(e)
  560. return
  561. except ValueError as e:
  562. assert tv.valid
  563. assert tv.warning
  564. assert "LowOrderPublic" in tv.flags or "NonCanonicalPublic" in tv.flags
  565. return
  566. elif tv.encoding == "XdhJwkComp":
  567. if 'y' in tv.public:
  568. return
  569. if 'x' not in tv.public:
  570. return
  571. if 'x' not in tv.private:
  572. return
  573. if tv.public.get('kty') != 'OKP':
  574. return
  575. if tv.public.get('crv') != 'X448':
  576. return
  577. if tv.private.get('crv') != 'X448':
  578. return
  579. def base64url_decode(input_str):
  580. input_str = input_str.replace('-', '+').replace('_', '/')
  581. padding = 4 - (len(input_str) % 4)
  582. if padding != 4:
  583. input_str += '=' * padding
  584. decoded_bytes = base64.b64decode(input_str)
  585. return decoded_bytes
  586. jwk_public = base64url_decode(tv.public['x'])
  587. jwk_private = base64url_decode(tv.private['d'])
  588. try:
  589. public_key = import_x448_public_key(jwk_public)
  590. private_key = import_x448_private_key(jwk_private)
  591. except ValueError as e:
  592. if tv.valid:
  593. assert tv.warning
  594. if len(tv.public['x']) == 75:
  595. assert "LowOrderPublic" in tv.flags or \
  596. "NonCanonicalPublic" in tv.flags
  597. assert "Invalid Curve448" in str(e)
  598. else:
  599. assert "Incorrect Curve448" in str(e)
  600. return
  601. else:
  602. assert "Incorrect length" in str(e)
  603. return
  604. except ValueError:
  605. assert tv.valid
  606. else:
  607. raise ValueError("Unknown encoding", tv.encoding)
  608. try:
  609. z = key_agreement(static_pub=public_key,
  610. static_priv=private_key,
  611. kdf=lambda x: x)
  612. except ValueError:
  613. assert not tv.valid
  614. except TypeError as e:
  615. assert not tv.valid
  616. assert "incompatible curve" in str(e)
  617. else:
  618. self.assertEqual(z, tv.shared)
  619. assert tv.valid
  620. def runTest(self):
  621. for tv in self.tv:
  622. self.desc = "Wycheproof XECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
  623. self.test_verify(tv)
  624. def get_tests(config={}):
  625. tests = []
  626. tests += list_test_cases(FIPS_ECDH_Tests_KAT)
  627. tests += [TestVectorsECDHWycheproof()]
  628. tests += list_test_cases(ECDH_Tests)
  629. tests += list_test_cases(X25519_Tests)
  630. tests += list_test_cases(X448_Tests)
  631. tests += [TestVectorsX25519Wycheproof()]
  632. tests += [TestVectorsX448Wycheproof()]
  633. slow_tests = config.get('slow_tests')
  634. if slow_tests:
  635. pass
  636. return tests
  637. if __name__ == '__main__':
  638. def suite():
  639. return unittest.TestSuite(get_tests())
  640. unittest.main(defaultTest='suite')