utils.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. from __future__ import absolute_import, division, print_function
  5. import binascii
  6. import collections
  7. import math
  8. import re
  9. from contextlib import contextmanager
  10. import pytest
  11. import six
  12. from cryptography.exceptions import UnsupportedAlgorithm
  13. import cryptography_vectors
  14. HashVector = collections.namedtuple("HashVector", ["message", "digest"])
  15. KeyedHashVector = collections.namedtuple(
  16. "KeyedHashVector", ["message", "digest", "key"]
  17. )
  18. def select_backends(names, backend_list):
  19. if names is None:
  20. return backend_list
  21. split_names = [x.strip() for x in names.split(',')]
  22. selected_backends = []
  23. for backend in backend_list:
  24. if backend.name in split_names:
  25. selected_backends.append(backend)
  26. if len(selected_backends) > 0:
  27. return selected_backends
  28. else:
  29. raise ValueError(
  30. "No backend selected. Tried to select: {0}".format(split_names)
  31. )
  32. def skip_if_empty(backend_list, required_interfaces):
  33. if not backend_list:
  34. pytest.skip(
  35. "No backends provided supply the interface: {0}".format(
  36. ", ".join(iface.__name__ for iface in required_interfaces)
  37. )
  38. )
  39. def check_backend_support(item):
  40. supported = item.keywords.get("supported")
  41. if supported and "backend" in item.funcargs:
  42. for mark in supported:
  43. if not mark.kwargs["only_if"](item.funcargs["backend"]):
  44. pytest.skip("{0} ({1})".format(
  45. mark.kwargs["skip_message"], item.funcargs["backend"]
  46. ))
  47. elif supported:
  48. raise ValueError("This mark is only available on methods that take a "
  49. "backend")
  50. @contextmanager
  51. def raises_unsupported_algorithm(reason):
  52. with pytest.raises(UnsupportedAlgorithm) as exc_info:
  53. yield exc_info
  54. assert exc_info.value._reason is reason
  55. def load_vectors_from_file(filename, loader, mode="r"):
  56. with cryptography_vectors.open_vector_file(filename, mode) as vector_file:
  57. return loader(vector_file)
  58. def load_nist_vectors(vector_data):
  59. test_data = None
  60. data = []
  61. for line in vector_data:
  62. line = line.strip()
  63. # Blank lines, comments, and section headers are ignored
  64. if not line or line.startswith("#") or (line.startswith("[") and
  65. line.endswith("]")):
  66. continue
  67. if line.strip() == "FAIL":
  68. test_data["fail"] = True
  69. continue
  70. # Build our data using a simple Key = Value format
  71. name, value = [c.strip() for c in line.split("=")]
  72. # Some tests (PBKDF2) contain \0, which should be interpreted as a
  73. # null character rather than literal.
  74. value = value.replace("\\0", "\0")
  75. # COUNT is a special token that indicates a new block of data
  76. if name.upper() == "COUNT":
  77. test_data = {}
  78. data.append(test_data)
  79. continue
  80. # For all other tokens we simply want the name, value stored in
  81. # the dictionary
  82. else:
  83. test_data[name.lower()] = value.encode("ascii")
  84. return data
  85. def load_cryptrec_vectors(vector_data):
  86. cryptrec_list = []
  87. for line in vector_data:
  88. line = line.strip()
  89. # Blank lines and comments are ignored
  90. if not line or line.startswith("#"):
  91. continue
  92. if line.startswith("K"):
  93. key = line.split(" : ")[1].replace(" ", "").encode("ascii")
  94. elif line.startswith("P"):
  95. pt = line.split(" : ")[1].replace(" ", "").encode("ascii")
  96. elif line.startswith("C"):
  97. ct = line.split(" : ")[1].replace(" ", "").encode("ascii")
  98. # after a C is found the K+P+C tuple is complete
  99. # there are many P+C pairs for each K
  100. cryptrec_list.append({
  101. "key": key,
  102. "plaintext": pt,
  103. "ciphertext": ct
  104. })
  105. else:
  106. raise ValueError("Invalid line in file '{}'".format(line))
  107. return cryptrec_list
  108. def load_hash_vectors(vector_data):
  109. vectors = []
  110. key = None
  111. msg = None
  112. md = None
  113. for line in vector_data:
  114. line = line.strip()
  115. if not line or line.startswith("#") or line.startswith("["):
  116. continue
  117. if line.startswith("Len"):
  118. length = int(line.split(" = ")[1])
  119. elif line.startswith("Key"):
  120. # HMAC vectors contain a key attribute. Hash vectors do not.
  121. key = line.split(" = ")[1].encode("ascii")
  122. elif line.startswith("Msg"):
  123. # In the NIST vectors they have chosen to represent an empty
  124. # string as hex 00, which is of course not actually an empty
  125. # string. So we parse the provided length and catch this edge case.
  126. msg = line.split(" = ")[1].encode("ascii") if length > 0 else b""
  127. elif line.startswith("MD"):
  128. md = line.split(" = ")[1]
  129. # after MD is found the Msg+MD (+ potential key) tuple is complete
  130. if key is not None:
  131. vectors.append(KeyedHashVector(msg, md, key))
  132. key = None
  133. msg = None
  134. md = None
  135. else:
  136. vectors.append(HashVector(msg, md))
  137. msg = None
  138. md = None
  139. else:
  140. raise ValueError("Unknown line in hash vector")
  141. return vectors
  142. def load_pkcs1_vectors(vector_data):
  143. """
  144. Loads data out of RSA PKCS #1 vector files.
  145. """
  146. private_key_vector = None
  147. public_key_vector = None
  148. attr = None
  149. key = None
  150. example_vector = None
  151. examples = []
  152. vectors = []
  153. for line in vector_data:
  154. if (
  155. line.startswith("# PSS Example") or
  156. line.startswith("# OAEP Example") or
  157. line.startswith("# PKCS#1 v1.5")
  158. ):
  159. if example_vector:
  160. for key, value in six.iteritems(example_vector):
  161. hex_str = "".join(value).replace(" ", "").encode("ascii")
  162. example_vector[key] = hex_str
  163. examples.append(example_vector)
  164. attr = None
  165. example_vector = collections.defaultdict(list)
  166. if line.startswith("# Message"):
  167. attr = "message"
  168. continue
  169. elif line.startswith("# Salt"):
  170. attr = "salt"
  171. continue
  172. elif line.startswith("# Seed"):
  173. attr = "seed"
  174. continue
  175. elif line.startswith("# Signature"):
  176. attr = "signature"
  177. continue
  178. elif line.startswith("# Encryption"):
  179. attr = "encryption"
  180. continue
  181. elif (
  182. example_vector and
  183. line.startswith("# =============================================")
  184. ):
  185. for key, value in six.iteritems(example_vector):
  186. hex_str = "".join(value).replace(" ", "").encode("ascii")
  187. example_vector[key] = hex_str
  188. examples.append(example_vector)
  189. example_vector = None
  190. attr = None
  191. elif example_vector and line.startswith("#"):
  192. continue
  193. else:
  194. if attr is not None and example_vector is not None:
  195. example_vector[attr].append(line.strip())
  196. continue
  197. if (
  198. line.startswith("# Example") or
  199. line.startswith("# =============================================")
  200. ):
  201. if key:
  202. assert private_key_vector
  203. assert public_key_vector
  204. for key, value in six.iteritems(public_key_vector):
  205. hex_str = "".join(value).replace(" ", "")
  206. public_key_vector[key] = int(hex_str, 16)
  207. for key, value in six.iteritems(private_key_vector):
  208. hex_str = "".join(value).replace(" ", "")
  209. private_key_vector[key] = int(hex_str, 16)
  210. private_key_vector["examples"] = examples
  211. examples = []
  212. assert (
  213. private_key_vector['public_exponent'] ==
  214. public_key_vector['public_exponent']
  215. )
  216. assert (
  217. private_key_vector['modulus'] ==
  218. public_key_vector['modulus']
  219. )
  220. vectors.append(
  221. (private_key_vector, public_key_vector)
  222. )
  223. public_key_vector = collections.defaultdict(list)
  224. private_key_vector = collections.defaultdict(list)
  225. key = None
  226. attr = None
  227. if private_key_vector is None or public_key_vector is None:
  228. continue
  229. if line.startswith("# Private key"):
  230. key = private_key_vector
  231. elif line.startswith("# Public key"):
  232. key = public_key_vector
  233. elif line.startswith("# Modulus:"):
  234. attr = "modulus"
  235. elif line.startswith("# Public exponent:"):
  236. attr = "public_exponent"
  237. elif line.startswith("# Exponent:"):
  238. if key is public_key_vector:
  239. attr = "public_exponent"
  240. else:
  241. assert key is private_key_vector
  242. attr = "private_exponent"
  243. elif line.startswith("# Prime 1:"):
  244. attr = "p"
  245. elif line.startswith("# Prime 2:"):
  246. attr = "q"
  247. elif line.startswith("# Prime exponent 1:"):
  248. attr = "dmp1"
  249. elif line.startswith("# Prime exponent 2:"):
  250. attr = "dmq1"
  251. elif line.startswith("# Coefficient:"):
  252. attr = "iqmp"
  253. elif line.startswith("#"):
  254. attr = None
  255. else:
  256. if key is not None and attr is not None:
  257. key[attr].append(line.strip())
  258. return vectors
  259. def load_rsa_nist_vectors(vector_data):
  260. test_data = None
  261. p = None
  262. salt_length = None
  263. data = []
  264. for line in vector_data:
  265. line = line.strip()
  266. # Blank lines and section headers are ignored
  267. if not line or line.startswith("["):
  268. continue
  269. if line.startswith("# Salt len:"):
  270. salt_length = int(line.split(":")[1].strip())
  271. continue
  272. elif line.startswith("#"):
  273. continue
  274. # Build our data using a simple Key = Value format
  275. name, value = [c.strip() for c in line.split("=")]
  276. if name == "n":
  277. n = int(value, 16)
  278. elif name == "e" and p is None:
  279. e = int(value, 16)
  280. elif name == "p":
  281. p = int(value, 16)
  282. elif name == "q":
  283. q = int(value, 16)
  284. elif name == "SHAAlg":
  285. if p is None:
  286. test_data = {
  287. "modulus": n,
  288. "public_exponent": e,
  289. "salt_length": salt_length,
  290. "algorithm": value,
  291. "fail": False
  292. }
  293. else:
  294. test_data = {
  295. "modulus": n,
  296. "p": p,
  297. "q": q,
  298. "algorithm": value
  299. }
  300. if salt_length is not None:
  301. test_data["salt_length"] = salt_length
  302. data.append(test_data)
  303. elif name == "e" and p is not None:
  304. test_data["public_exponent"] = int(value, 16)
  305. elif name == "d":
  306. test_data["private_exponent"] = int(value, 16)
  307. elif name == "Result":
  308. test_data["fail"] = value.startswith("F")
  309. # For all other tokens we simply want the name, value stored in
  310. # the dictionary
  311. else:
  312. test_data[name.lower()] = value.encode("ascii")
  313. return data
  314. def load_fips_dsa_key_pair_vectors(vector_data):
  315. """
  316. Loads data out of the FIPS DSA KeyPair vector files.
  317. """
  318. vectors = []
  319. # When reading_key_data is set to True it tells the loader to continue
  320. # constructing dictionaries. We set reading_key_data to False during the
  321. # blocks of the vectors of N=224 because we don't support it.
  322. reading_key_data = True
  323. for line in vector_data:
  324. line = line.strip()
  325. if not line or line.startswith("#"):
  326. continue
  327. elif line.startswith("[mod = L=1024"):
  328. continue
  329. elif line.startswith("[mod = L=2048, N=224"):
  330. reading_key_data = False
  331. continue
  332. elif line.startswith("[mod = L=2048, N=256"):
  333. reading_key_data = True
  334. continue
  335. elif line.startswith("[mod = L=3072"):
  336. continue
  337. if reading_key_data:
  338. if line.startswith("P"):
  339. vectors.append({'p': int(line.split("=")[1], 16)})
  340. elif line.startswith("Q"):
  341. vectors[-1]['q'] = int(line.split("=")[1], 16)
  342. elif line.startswith("G"):
  343. vectors[-1]['g'] = int(line.split("=")[1], 16)
  344. elif line.startswith("X") and 'x' not in vectors[-1]:
  345. vectors[-1]['x'] = int(line.split("=")[1], 16)
  346. elif line.startswith("X") and 'x' in vectors[-1]:
  347. vectors.append({'p': vectors[-1]['p'],
  348. 'q': vectors[-1]['q'],
  349. 'g': vectors[-1]['g'],
  350. 'x': int(line.split("=")[1], 16)
  351. })
  352. elif line.startswith("Y"):
  353. vectors[-1]['y'] = int(line.split("=")[1], 16)
  354. return vectors
  355. def load_fips_dsa_sig_vectors(vector_data):
  356. """
  357. Loads data out of the FIPS DSA SigVer vector files.
  358. """
  359. vectors = []
  360. sha_regex = re.compile(
  361. r"\[mod = L=...., N=..., SHA-(?P<sha>1|224|256|384|512)\]"
  362. )
  363. # When reading_key_data is set to True it tells the loader to continue
  364. # constructing dictionaries. We set reading_key_data to False during the
  365. # blocks of the vectors of N=224 because we don't support it.
  366. reading_key_data = True
  367. for line in vector_data:
  368. line = line.strip()
  369. if not line or line.startswith("#"):
  370. continue
  371. sha_match = sha_regex.match(line)
  372. if sha_match:
  373. digest_algorithm = "SHA-{0}".format(sha_match.group("sha"))
  374. if line.startswith("[mod = L=2048, N=224"):
  375. reading_key_data = False
  376. continue
  377. elif line.startswith("[mod = L=2048, N=256"):
  378. reading_key_data = True
  379. continue
  380. if not reading_key_data or line.startswith("[mod"):
  381. continue
  382. name, value = [c.strip() for c in line.split("=")]
  383. if name == "P":
  384. vectors.append({'p': int(value, 16),
  385. 'digest_algorithm': digest_algorithm})
  386. elif name == "Q":
  387. vectors[-1]['q'] = int(value, 16)
  388. elif name == "G":
  389. vectors[-1]['g'] = int(value, 16)
  390. elif name == "Msg" and 'msg' not in vectors[-1]:
  391. hexmsg = value.strip().encode("ascii")
  392. vectors[-1]['msg'] = binascii.unhexlify(hexmsg)
  393. elif name == "Msg" and 'msg' in vectors[-1]:
  394. hexmsg = value.strip().encode("ascii")
  395. vectors.append({'p': vectors[-1]['p'],
  396. 'q': vectors[-1]['q'],
  397. 'g': vectors[-1]['g'],
  398. 'digest_algorithm':
  399. vectors[-1]['digest_algorithm'],
  400. 'msg': binascii.unhexlify(hexmsg)})
  401. elif name == "X":
  402. vectors[-1]['x'] = int(value, 16)
  403. elif name == "Y":
  404. vectors[-1]['y'] = int(value, 16)
  405. elif name == "R":
  406. vectors[-1]['r'] = int(value, 16)
  407. elif name == "S":
  408. vectors[-1]['s'] = int(value, 16)
  409. elif name == "Result":
  410. vectors[-1]['result'] = value.split("(")[0].strip()
  411. return vectors
  412. # http://tools.ietf.org/html/rfc4492#appendix-A
  413. _ECDSA_CURVE_NAMES = {
  414. "P-192": "secp192r1",
  415. "P-224": "secp224r1",
  416. "P-256": "secp256r1",
  417. "P-384": "secp384r1",
  418. "P-521": "secp521r1",
  419. "K-163": "sect163k1",
  420. "K-233": "sect233k1",
  421. "K-256": "secp256k1",
  422. "K-283": "sect283k1",
  423. "K-409": "sect409k1",
  424. "K-571": "sect571k1",
  425. "B-163": "sect163r2",
  426. "B-233": "sect233r1",
  427. "B-283": "sect283r1",
  428. "B-409": "sect409r1",
  429. "B-571": "sect571r1",
  430. }
  431. def load_fips_ecdsa_key_pair_vectors(vector_data):
  432. """
  433. Loads data out of the FIPS ECDSA KeyPair vector files.
  434. """
  435. vectors = []
  436. key_data = None
  437. for line in vector_data:
  438. line = line.strip()
  439. if not line or line.startswith("#"):
  440. continue
  441. if line[1:-1] in _ECDSA_CURVE_NAMES:
  442. curve_name = _ECDSA_CURVE_NAMES[line[1:-1]]
  443. elif line.startswith("d = "):
  444. if key_data is not None:
  445. vectors.append(key_data)
  446. key_data = {
  447. "curve": curve_name,
  448. "d": int(line.split("=")[1], 16)
  449. }
  450. elif key_data is not None:
  451. if line.startswith("Qx = "):
  452. key_data["x"] = int(line.split("=")[1], 16)
  453. elif line.startswith("Qy = "):
  454. key_data["y"] = int(line.split("=")[1], 16)
  455. assert key_data is not None
  456. vectors.append(key_data)
  457. return vectors
  458. def load_fips_ecdsa_signing_vectors(vector_data):
  459. """
  460. Loads data out of the FIPS ECDSA SigGen vector files.
  461. """
  462. vectors = []
  463. curve_rx = re.compile(
  464. r"\[(?P<curve>[PKB]-[0-9]{3}),SHA-(?P<sha>1|224|256|384|512)\]"
  465. )
  466. data = None
  467. for line in vector_data:
  468. line = line.strip()
  469. curve_match = curve_rx.match(line)
  470. if curve_match:
  471. curve_name = _ECDSA_CURVE_NAMES[curve_match.group("curve")]
  472. digest_name = "SHA-{0}".format(curve_match.group("sha"))
  473. elif line.startswith("Msg = "):
  474. if data is not None:
  475. vectors.append(data)
  476. hexmsg = line.split("=")[1].strip().encode("ascii")
  477. data = {
  478. "curve": curve_name,
  479. "digest_algorithm": digest_name,
  480. "message": binascii.unhexlify(hexmsg)
  481. }
  482. elif data is not None:
  483. if line.startswith("Qx = "):
  484. data["x"] = int(line.split("=")[1], 16)
  485. elif line.startswith("Qy = "):
  486. data["y"] = int(line.split("=")[1], 16)
  487. elif line.startswith("R = "):
  488. data["r"] = int(line.split("=")[1], 16)
  489. elif line.startswith("S = "):
  490. data["s"] = int(line.split("=")[1], 16)
  491. elif line.startswith("d = "):
  492. data["d"] = int(line.split("=")[1], 16)
  493. elif line.startswith("Result = "):
  494. data["fail"] = line.split("=")[1].strip()[0] == "F"
  495. assert data is not None
  496. vectors.append(data)
  497. return vectors
  498. def load_kasvs_dh_vectors(vector_data):
  499. """
  500. Loads data out of the KASVS key exchange vector data
  501. """
  502. result_rx = re.compile(r"([FP]) \(([0-9]+) -")
  503. vectors = []
  504. data = {
  505. "fail_z": False,
  506. "fail_agree": False
  507. }
  508. for line in vector_data:
  509. line = line.strip()
  510. if not line or line.startswith("#"):
  511. continue
  512. if line.startswith("P = "):
  513. data["p"] = int(line.split("=")[1], 16)
  514. elif line.startswith("Q = "):
  515. data["q"] = int(line.split("=")[1], 16)
  516. elif line.startswith("G = "):
  517. data["g"] = int(line.split("=")[1], 16)
  518. elif line.startswith("Z = "):
  519. z_hex = line.split("=")[1].strip().encode("ascii")
  520. data["z"] = binascii.unhexlify(z_hex)
  521. elif line.startswith("XstatCAVS = "):
  522. data["x1"] = int(line.split("=")[1], 16)
  523. elif line.startswith("YstatCAVS = "):
  524. data["y1"] = int(line.split("=")[1], 16)
  525. elif line.startswith("XstatIUT = "):
  526. data["x2"] = int(line.split("=")[1], 16)
  527. elif line.startswith("YstatIUT = "):
  528. data["y2"] = int(line.split("=")[1], 16)
  529. elif line.startswith("Result = "):
  530. result_str = line.split("=")[1].strip()
  531. match = result_rx.match(result_str)
  532. if match.group(1) == "F":
  533. if int(match.group(2)) in (5, 10):
  534. data["fail_z"] = True
  535. else:
  536. data["fail_agree"] = True
  537. vectors.append(data)
  538. data = {
  539. "p": data["p"],
  540. "q": data["q"],
  541. "g": data["g"],
  542. "fail_z": False,
  543. "fail_agree": False
  544. }
  545. return vectors
  546. def load_kasvs_ecdh_vectors(vector_data):
  547. """
  548. Loads data out of the KASVS key exchange vector data
  549. """
  550. curve_name_map = {
  551. "P-192": "secp192r1",
  552. "P-224": "secp224r1",
  553. "P-256": "secp256r1",
  554. "P-384": "secp384r1",
  555. "P-521": "secp521r1",
  556. }
  557. result_rx = re.compile(r"([FP]) \(([0-9]+) -")
  558. tags = []
  559. sets = {}
  560. vectors = []
  561. # find info in header
  562. for line in vector_data:
  563. line = line.strip()
  564. if line.startswith("#"):
  565. parm = line.split("Parameter set(s) supported:")
  566. if len(parm) == 2:
  567. names = parm[1].strip().split()
  568. for n in names:
  569. tags.append("[%s]" % n)
  570. break
  571. # Sets Metadata
  572. tag = None
  573. curve = None
  574. for line in vector_data:
  575. line = line.strip()
  576. if not line or line.startswith("#"):
  577. continue
  578. if line in tags:
  579. tag = line
  580. curve = None
  581. elif line.startswith("[Curve selected:"):
  582. curve = curve_name_map[line.split(':')[1].strip()[:-1]]
  583. if tag is not None and curve is not None:
  584. sets[tag.strip("[]")] = curve
  585. tag = None
  586. if len(tags) == len(sets):
  587. break
  588. # Data
  589. data = {
  590. "CAVS": {},
  591. "IUT": {},
  592. }
  593. tag = None
  594. for line in vector_data:
  595. line = line.strip()
  596. if not line or line.startswith("#"):
  597. continue
  598. if line.startswith("["):
  599. tag = line.split()[0][1:]
  600. elif line.startswith("COUNT = "):
  601. data["COUNT"] = int(line.split("=")[1])
  602. elif line.startswith("dsCAVS = "):
  603. data["CAVS"]["d"] = int(line.split("=")[1], 16)
  604. elif line.startswith("QsCAVSx = "):
  605. data["CAVS"]["x"] = int(line.split("=")[1], 16)
  606. elif line.startswith("QsCAVSy = "):
  607. data["CAVS"]["y"] = int(line.split("=")[1], 16)
  608. elif line.startswith("dsIUT = "):
  609. data["IUT"]["d"] = int(line.split("=")[1], 16)
  610. elif line.startswith("QsIUTx = "):
  611. data["IUT"]["x"] = int(line.split("=")[1], 16)
  612. elif line.startswith("QsIUTy = "):
  613. data["IUT"]["y"] = int(line.split("=")[1], 16)
  614. elif line.startswith("OI = "):
  615. data["OI"] = int(line.split("=")[1], 16)
  616. elif line.startswith("Z = "):
  617. data["Z"] = int(line.split("=")[1], 16)
  618. elif line.startswith("DKM = "):
  619. data["DKM"] = int(line.split("=")[1], 16)
  620. elif line.startswith("Result = "):
  621. result_str = line.split("=")[1].strip()
  622. match = result_rx.match(result_str)
  623. if match.group(1) == "F":
  624. data["fail"] = True
  625. else:
  626. data["fail"] = False
  627. data["errno"] = int(match.group(2))
  628. data["curve"] = sets[tag]
  629. vectors.append(data)
  630. data = {
  631. "CAVS": {},
  632. "IUT": {},
  633. }
  634. return vectors
  635. def load_x963_vectors(vector_data):
  636. """
  637. Loads data out of the X9.63 vector data
  638. """
  639. vectors = []
  640. # Sets Metadata
  641. hashname = None
  642. vector = {}
  643. for line in vector_data:
  644. line = line.strip()
  645. if line.startswith("[SHA"):
  646. hashname = line[1:-1]
  647. shared_secret_len = 0
  648. shared_info_len = 0
  649. key_data_len = 0
  650. elif line.startswith("[shared secret length"):
  651. shared_secret_len = int(line[1:-1].split("=")[1].strip())
  652. elif line.startswith("[SharedInfo length"):
  653. shared_info_len = int(line[1:-1].split("=")[1].strip())
  654. elif line.startswith("[key data length"):
  655. key_data_len = int(line[1:-1].split("=")[1].strip())
  656. elif line.startswith("COUNT"):
  657. count = int(line.split("=")[1].strip())
  658. vector["hash"] = hashname
  659. vector["count"] = count
  660. vector["shared_secret_length"] = shared_secret_len
  661. vector["sharedinfo_length"] = shared_info_len
  662. vector["key_data_length"] = key_data_len
  663. elif line.startswith("Z"):
  664. vector["Z"] = line.split("=")[1].strip()
  665. assert math.ceil(shared_secret_len / 8) * 2 == len(vector["Z"])
  666. elif line.startswith("SharedInfo"):
  667. if shared_info_len != 0:
  668. vector["sharedinfo"] = line.split("=")[1].strip()
  669. silen = len(vector["sharedinfo"])
  670. assert math.ceil(shared_info_len / 8) * 2 == silen
  671. elif line.startswith("key_data"):
  672. vector["key_data"] = line.split("=")[1].strip()
  673. assert math.ceil(key_data_len / 8) * 2 == len(vector["key_data"])
  674. vectors.append(vector)
  675. vector = {}
  676. return vectors