Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

450 řádky
15 KiB

  1. import os
  2. import sys
  3. import shutil
  4. import subprocess
  5. import pytest
  6. from binascii import unhexlify
  7. try:
  8. import unittest2 as unittest
  9. except ImportError:
  10. import unittest
  11. from .curves import (
  12. NIST192p,
  13. NIST224p,
  14. NIST256p,
  15. NIST384p,
  16. NIST521p,
  17. BRAINPOOLP160r1,
  18. SECP112r2,
  19. SECP128r1,
  20. )
  21. from .curves import curves
  22. from .ecdh import (
  23. ECDH,
  24. InvalidCurveError,
  25. InvalidSharedSecretError,
  26. NoKeyError,
  27. NoCurveError,
  28. )
  29. from .keys import SigningKey, VerifyingKey
  30. from .ellipticcurve import CurveEdTw
  31. if "--fast" in sys.argv: # pragma: no cover
  32. curves = [SECP112r2, SECP128r1]
  33. @pytest.mark.parametrize(
  34. "vcurve",
  35. curves,
  36. ids=[curve.name for curve in curves],
  37. )
  38. def test_ecdh_each(vcurve):
  39. if isinstance(vcurve.curve, CurveEdTw):
  40. pytest.skip("ECDH is not supported for Edwards curves")
  41. ecdh1 = ECDH(curve=vcurve)
  42. ecdh2 = ECDH(curve=vcurve)
  43. ecdh2.generate_private_key()
  44. ecdh1.load_received_public_key(ecdh2.get_public_key())
  45. ecdh2.load_received_public_key(ecdh1.generate_private_key())
  46. secret1 = ecdh1.generate_sharedsecret_bytes()
  47. secret2 = ecdh2.generate_sharedsecret_bytes()
  48. assert secret1 == secret2
  49. def test_ecdh_both_keys_present():
  50. key1 = SigningKey.generate(BRAINPOOLP160r1)
  51. key2 = SigningKey.generate(BRAINPOOLP160r1)
  52. ecdh1 = ECDH(BRAINPOOLP160r1, key1, key2.verifying_key)
  53. ecdh2 = ECDH(private_key=key2, public_key=key1.verifying_key)
  54. secret1 = ecdh1.generate_sharedsecret_bytes()
  55. secret2 = ecdh2.generate_sharedsecret_bytes()
  56. assert secret1 == secret2
  57. def test_ecdh_no_public_key():
  58. ecdh1 = ECDH(curve=NIST192p)
  59. with pytest.raises(NoKeyError):
  60. ecdh1.generate_sharedsecret_bytes()
  61. ecdh1.generate_private_key()
  62. with pytest.raises(NoKeyError):
  63. ecdh1.generate_sharedsecret_bytes()
  64. class TestECDH(unittest.TestCase):
  65. def test_load_key_from_wrong_curve(self):
  66. ecdh1 = ECDH()
  67. ecdh1.set_curve(NIST192p)
  68. key1 = SigningKey.generate(BRAINPOOLP160r1)
  69. with self.assertRaises(InvalidCurveError) as e:
  70. ecdh1.load_private_key(key1)
  71. self.assertIn("Curve mismatch", str(e.exception))
  72. def test_generate_without_curve(self):
  73. ecdh1 = ECDH()
  74. with self.assertRaises(NoCurveError) as e:
  75. ecdh1.generate_private_key()
  76. self.assertIn("Curve must be set", str(e.exception))
  77. def test_load_bytes_without_curve_set(self):
  78. ecdh1 = ECDH()
  79. with self.assertRaises(NoCurveError) as e:
  80. ecdh1.load_private_key_bytes(b"\x01" * 32)
  81. self.assertIn("Curve must be set", str(e.exception))
  82. def test_set_curve_from_received_public_key(self):
  83. ecdh1 = ECDH()
  84. key1 = SigningKey.generate(BRAINPOOLP160r1)
  85. ecdh1.load_received_public_key(key1.verifying_key)
  86. self.assertEqual(ecdh1.curve, BRAINPOOLP160r1)
  87. def test_ecdh_wrong_public_key_curve():
  88. ecdh1 = ECDH(curve=NIST192p)
  89. ecdh1.generate_private_key()
  90. ecdh2 = ECDH(curve=NIST256p)
  91. ecdh2.generate_private_key()
  92. with pytest.raises(InvalidCurveError):
  93. ecdh1.load_received_public_key(ecdh2.get_public_key())
  94. with pytest.raises(InvalidCurveError):
  95. ecdh2.load_received_public_key(ecdh1.get_public_key())
  96. ecdh1.public_key = ecdh2.get_public_key()
  97. ecdh2.public_key = ecdh1.get_public_key()
  98. with pytest.raises(InvalidCurveError):
  99. ecdh1.generate_sharedsecret_bytes()
  100. with pytest.raises(InvalidCurveError):
  101. ecdh2.generate_sharedsecret_bytes()
  102. def test_ecdh_invalid_shared_secret_curve():
  103. ecdh1 = ECDH(curve=NIST256p)
  104. ecdh1.generate_private_key()
  105. ecdh1.load_received_public_key(
  106. SigningKey.generate(NIST256p).get_verifying_key()
  107. )
  108. ecdh1.private_key.privkey.secret_multiplier = ecdh1.private_key.curve.order
  109. with pytest.raises(InvalidSharedSecretError):
  110. ecdh1.generate_sharedsecret_bytes()
  111. # https://github.com/scogliani/ecc-test-vectors/blob/master/ecdh_kat/secp192r1.txt
  112. # https://github.com/scogliani/ecc-test-vectors/blob/master/ecdh_kat/secp256r1.txt
  113. # https://github.com/coruus/nist-testvectors/blob/master/csrc.nist.gov/groups/STM/cavp/documents/components/ecccdhtestvectors/KAS_ECC_CDH_PrimitiveTest.txt
  114. @pytest.mark.parametrize(
  115. "curve,privatekey,pubkey,secret",
  116. [
  117. pytest.param(
  118. NIST192p,
  119. "f17d3fea367b74d340851ca4270dcb24c271f445bed9d527",
  120. "42ea6dd9969dd2a61fea1aac7f8e98edcc896c6e55857cc0"
  121. "dfbe5d7c61fac88b11811bde328e8a0d12bf01a9d204b523",
  122. "803d8ab2e5b6e6fca715737c3a82f7ce3c783124f6d51cd0",
  123. id="NIST192p-1",
  124. ),
  125. pytest.param(
  126. NIST192p,
  127. "56e853349d96fe4c442448dacb7cf92bb7a95dcf574a9bd5",
  128. "deb5712fa027ac8d2f22c455ccb73a91e17b6512b5e030e7"
  129. "7e2690a02cc9b28708431a29fb54b87b1f0c14e011ac2125",
  130. "c208847568b98835d7312cef1f97f7aa298283152313c29d",
  131. id="NIST192p-2",
  132. ),
  133. pytest.param(
  134. NIST192p,
  135. "c6ef61fe12e80bf56f2d3f7d0bb757394519906d55500949",
  136. "4edaa8efc5a0f40f843663ec5815e7762dddc008e663c20f"
  137. "0a9f8dc67a3e60ef6d64b522185d03df1fc0adfd42478279",
  138. "87229107047a3b611920d6e3b2c0c89bea4f49412260b8dd",
  139. id="NIST192p-3",
  140. ),
  141. pytest.param(
  142. NIST192p,
  143. "e6747b9c23ba7044f38ff7e62c35e4038920f5a0163d3cda",
  144. "8887c276edeed3e9e866b46d58d895c73fbd80b63e382e88"
  145. "04c5097ba6645e16206cfb70f7052655947dd44a17f1f9d5",
  146. "eec0bed8fc55e1feddc82158fd6dc0d48a4d796aaf47d46c",
  147. id="NIST192p-4",
  148. ),
  149. pytest.param(
  150. NIST192p,
  151. "beabedd0154a1afcfc85d52181c10f5eb47adc51f655047d",
  152. "0d045f30254adc1fcefa8a5b1f31bf4e739dd327cd18d594"
  153. "542c314e41427c08278a08ce8d7305f3b5b849c72d8aff73",
  154. "716e743b1b37a2cd8479f0a3d5a74c10ba2599be18d7e2f4",
  155. id="NIST192p-5",
  156. ),
  157. pytest.param(
  158. NIST192p,
  159. "cf70354226667321d6e2baf40999e2fd74c7a0f793fa8699",
  160. "fb35ca20d2e96665c51b98e8f6eb3d79113508d8bccd4516"
  161. "368eec0d5bfb847721df6aaff0e5d48c444f74bf9cd8a5a7",
  162. "f67053b934459985a315cb017bf0302891798d45d0e19508",
  163. id="NIST192p-6",
  164. ),
  165. pytest.param(
  166. NIST224p,
  167. "8346a60fc6f293ca5a0d2af68ba71d1dd389e5e40837942df3e43cbd",
  168. "af33cd0629bc7e996320a3f40368f74de8704fa37b8fab69abaae280"
  169. "882092ccbba7930f419a8a4f9bb16978bbc3838729992559a6f2e2d7",
  170. "7d96f9a3bd3c05cf5cc37feb8b9d5209d5c2597464dec3e9983743e8",
  171. id="NIST224p",
  172. ),
  173. pytest.param(
  174. NIST256p,
  175. "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534",
  176. "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"
  177. "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
  178. "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b",
  179. id="NIST256p-1",
  180. ),
  181. pytest.param(
  182. NIST256p,
  183. "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5",
  184. "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae"
  185. "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
  186. "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67",
  187. id="NIST256p-2",
  188. ),
  189. pytest.param(
  190. NIST256p,
  191. "1accfaf1b97712b85a6f54b148985a1bdc4c9bec0bd258cad4b3d603f49f32c8",
  192. "a2339c12d4a03c33546de533268b4ad667debf458b464d77443636440ee7fec3"
  193. "ef48a3ab26e20220bcda2c1851076839dae88eae962869a497bf73cb66faf536",
  194. "2d457b78b4614132477618a5b077965ec90730a8c81a1c75d6d4ec68005d67ec",
  195. id="NIST256p-3",
  196. ),
  197. pytest.param(
  198. NIST256p,
  199. "207c43a79bfee03db6f4b944f53d2fb76cc49ef1c9c4d34d51b6c65c4db6932d",
  200. "df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed"
  201. "422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4",
  202. "96441259534b80f6aee3d287a6bb17b5094dd4277d9e294f8fe73e48bf2a0024",
  203. id="NIST256p-4",
  204. ),
  205. pytest.param(
  206. NIST256p,
  207. "59137e38152350b195c9718d39673d519838055ad908dd4757152fd8255c09bf",
  208. "41192d2813e79561e6a1d6f53c8bc1a433a199c835e141b05a74a97b0faeb922"
  209. "1af98cc45e98a7e041b01cf35f462b7562281351c8ebf3ffa02e33a0722a1328",
  210. "19d44c8d63e8e8dd12c22a87b8cd4ece27acdde04dbf47f7f27537a6999a8e62",
  211. id="NIST256p-5",
  212. ),
  213. pytest.param(
  214. NIST256p,
  215. "f5f8e0174610a661277979b58ce5c90fee6c9b3bb346a90a7196255e40b132ef",
  216. "33e82092a0f1fb38f5649d5867fba28b503172b7035574bf8e5b7100a3052792"
  217. "f2cf6b601e0a05945e335550bf648d782f46186c772c0f20d3cd0d6b8ca14b2f",
  218. "664e45d5bba4ac931cd65d52017e4be9b19a515f669bea4703542a2c525cd3d3",
  219. id="NIST256p-6",
  220. ),
  221. pytest.param(
  222. NIST384p,
  223. "3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b1"
  224. "5618b6818a661774ad463b205da88cf699ab4d43c9cf98a1",
  225. "a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e76459"
  226. "2efda27fe7513272734466b400091adbf2d68c58e0c50066"
  227. "ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b66"
  228. "1efedf243451915ed0905a32b060992b468c64766fc8437a",
  229. "5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f4"
  230. "0ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1",
  231. id="NIST384p",
  232. ),
  233. pytest.param(
  234. NIST521p,
  235. "017eecc07ab4b329068fba65e56a1f8890aa935e57134ae0ffcce802735151f4ea"
  236. "c6564f6ee9974c5e6887a1fefee5743ae2241bfeb95d5ce31ddcb6f9edb4d6fc47",
  237. "00685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a949034085433"
  238. "4b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2046d"
  239. "01ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b739884a83"
  240. "bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302f676",
  241. "005fc70477c3e63bc3954bd0df3ea0d1f41ee21746ed95fc5e1fdf90930d5e1366"
  242. "72d72cc770742d1711c3c3a4c334a0ad9759436a4d3c5bf6e74b9578fac148c831",
  243. id="NIST521p",
  244. ),
  245. ],
  246. )
  247. def test_ecdh_NIST(curve, privatekey, pubkey, secret):
  248. ecdh = ECDH(curve=curve)
  249. ecdh.load_private_key_bytes(unhexlify(privatekey))
  250. ecdh.load_received_public_key_bytes(unhexlify(pubkey))
  251. sharedsecret = ecdh.generate_sharedsecret_bytes()
  252. assert sharedsecret == unhexlify(secret)
  253. pem_local_private_key = (
  254. "-----BEGIN EC PRIVATE KEY-----\n"
  255. "MF8CAQEEGF7IQgvW75JSqULpiQQ8op9WH6Uldw6xxaAKBggqhkjOPQMBAaE0AzIA\n"
  256. "BLiBd9CE7xf15FY5QIAoNg+fWbSk1yZOYtoGUdzkejWkxbRc9RWTQjqLVXucIJnz\n"
  257. "bA==\n"
  258. "-----END EC PRIVATE KEY-----\n"
  259. )
  260. der_local_private_key = (
  261. "305f02010104185ec8420bd6ef9252a942e989043ca29f561fa525770eb1c5a00a06082a864"
  262. "8ce3d030101a13403320004b88177d084ef17f5e45639408028360f9f59b4a4d7264e62da06"
  263. "51dce47a35a4c5b45cf51593423a8b557b9c2099f36c"
  264. )
  265. pem_remote_public_key = (
  266. "-----BEGIN PUBLIC KEY-----\n"
  267. "MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEuIF30ITvF/XkVjlAgCg2D59ZtKTX\n"
  268. "Jk5i2gZR3OR6NaTFtFz1FZNCOotVe5wgmfNs\n"
  269. "-----END PUBLIC KEY-----\n"
  270. )
  271. der_remote_public_key = (
  272. "3049301306072a8648ce3d020106082a8648ce3d03010103320004b88177d084ef17f5e4563"
  273. "9408028360f9f59b4a4d7264e62da0651dce47a35a4c5b45cf51593423a8b557b9c2099f36c"
  274. )
  275. gshared_secret = "8f457e34982478d1c34b9cd2d0c15911b72dd60d869e2cea"
  276. def test_ecdh_pem():
  277. ecdh = ECDH()
  278. ecdh.load_private_key_pem(pem_local_private_key)
  279. ecdh.load_received_public_key_pem(pem_remote_public_key)
  280. sharedsecret = ecdh.generate_sharedsecret_bytes()
  281. assert sharedsecret == unhexlify(gshared_secret)
  282. def test_ecdh_der():
  283. ecdh = ECDH()
  284. ecdh.load_private_key_der(unhexlify(der_local_private_key))
  285. ecdh.load_received_public_key_der(unhexlify(der_remote_public_key))
  286. sharedsecret = ecdh.generate_sharedsecret_bytes()
  287. assert sharedsecret == unhexlify(gshared_secret)
  288. # Exception classes used by run_openssl.
  289. class RunOpenSslError(Exception):
  290. pass
  291. def run_openssl(cmd):
  292. OPENSSL = "openssl"
  293. p = subprocess.Popen(
  294. [OPENSSL] + cmd.split(),
  295. stdout=subprocess.PIPE,
  296. stderr=subprocess.STDOUT,
  297. )
  298. stdout, ignored = p.communicate()
  299. if p.returncode != 0:
  300. raise RunOpenSslError(
  301. "cmd '%s %s' failed: rc=%s, stdout/err was %s"
  302. % (OPENSSL, cmd, p.returncode, stdout)
  303. )
  304. return stdout.decode()
  305. OPENSSL_SUPPORTED_CURVES = set(
  306. c.split(":")[0].strip()
  307. for c in run_openssl("ecparam -list_curves").split("\n")
  308. )
  309. @pytest.mark.slow
  310. @pytest.mark.parametrize(
  311. "vcurve",
  312. curves,
  313. ids=[curve.name for curve in curves],
  314. )
  315. def test_ecdh_with_openssl(vcurve):
  316. if isinstance(vcurve.curve, CurveEdTw):
  317. pytest.skip("Edwards curves are not supported for ECDH")
  318. assert vcurve.openssl_name
  319. if vcurve.openssl_name not in OPENSSL_SUPPORTED_CURVES:
  320. pytest.skip("system openssl does not support " + vcurve.openssl_name)
  321. try:
  322. hlp = run_openssl("pkeyutl -help")
  323. if hlp.find("-derive") == 0: # pragma: no cover
  324. pytest.skip("system openssl does not support `pkeyutl -derive`")
  325. except RunOpenSslError: # pragma: no cover
  326. pytest.skip("system openssl could not be executed")
  327. if os.path.isdir("t"): # pragma: no branch
  328. shutil.rmtree("t")
  329. os.mkdir("t")
  330. run_openssl(
  331. "ecparam -name %s -genkey -out t/privkey1.pem" % vcurve.openssl_name
  332. )
  333. run_openssl(
  334. "ecparam -name %s -genkey -out t/privkey2.pem" % vcurve.openssl_name
  335. )
  336. run_openssl("ec -in t/privkey1.pem -pubout -out t/pubkey1.pem")
  337. ecdh1 = ECDH(curve=vcurve)
  338. ecdh2 = ECDH(curve=vcurve)
  339. with open("t/privkey1.pem") as e:
  340. key = e.read()
  341. ecdh1.load_private_key_pem(key)
  342. with open("t/privkey2.pem") as e:
  343. key = e.read()
  344. ecdh2.load_private_key_pem(key)
  345. with open("t/pubkey1.pem") as e:
  346. key = e.read()
  347. vk1 = VerifyingKey.from_pem(key)
  348. assert vk1.to_string() == ecdh1.get_public_key().to_string()
  349. vk2 = ecdh2.get_public_key()
  350. with open("t/pubkey2.pem", "wb") as e:
  351. e.write(vk2.to_pem())
  352. ecdh1.load_received_public_key(vk2)
  353. ecdh2.load_received_public_key(vk1)
  354. secret1 = ecdh1.generate_sharedsecret_bytes()
  355. secret2 = ecdh2.generate_sharedsecret_bytes()
  356. assert secret1 == secret2
  357. run_openssl(
  358. "pkeyutl -derive -inkey t/privkey1.pem -peerkey t/pubkey2.pem -out t/secret1"
  359. )
  360. run_openssl(
  361. "pkeyutl -derive -inkey t/privkey2.pem -peerkey t/pubkey1.pem -out t/secret2"
  362. )
  363. with open("t/secret1", "rb") as e:
  364. ssl_secret1 = e.read()
  365. with open("t/secret1", "rb") as e:
  366. ssl_secret2 = e.read()
  367. assert len(ssl_secret1) == vk1.curve.verifying_key_length // 2
  368. assert len(secret1) == vk1.curve.verifying_key_length // 2
  369. assert ssl_secret1 == ssl_secret2
  370. assert secret1 == ssl_secret1