utils.py 29 KB

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