blob: 136b06076f20e13dd7be2fa44d35f5f6de5e3af7 [file] [log] [blame]
Alex Gaynor5951f462014-11-16 09:08:42 -08001# 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.
Alex Gaynorf312a5c2013-08-10 15:23:38 -04004
Alex Gaynorc37feed2014-03-08 08:32:56 -08005from __future__ import absolute_import, division, print_function
6
Alex Stapletonc387cf72014-04-13 13:58:02 +01007import binascii
Alex Gaynor36e651c2014-01-27 10:08:35 -08008import collections
Simo Sorce7600dee2015-09-22 21:56:20 -04009import math
Alex Stapletonc387cf72014-04-13 13:58:02 +010010import re
Alex Stapleton707b0082014-04-20 22:24:41 +010011from contextlib import contextmanager
Paul Kehrer90450f32014-03-19 12:37:17 -040012
Alex Stapletona39a3192014-03-14 20:03:12 +000013import pytest
14
Paul Kehrerafc1ccd2014-03-19 11:49:32 -040015import six
Alex Gaynor2b3f9422013-12-24 21:55:24 -080016
Alex Gaynor7a489db2014-03-22 15:09:34 -070017from cryptography.exceptions import UnsupportedAlgorithm
Alex Gaynor07c4dcc2014-04-05 11:22:07 -070018
Alex Stapletona39a3192014-03-14 20:03:12 +000019import cryptography_vectors
Matthew Iversen68e77c72014-03-13 08:54:43 +110020
Alex Gaynor2b3f9422013-12-24 21:55:24 -080021
Alex Gaynor36e651c2014-01-27 10:08:35 -080022HashVector = collections.namedtuple("HashVector", ["message", "digest"])
23KeyedHashVector = collections.namedtuple(
24 "KeyedHashVector", ["message", "digest", "key"]
25)
26
27
Paul Kehrer60fc8da2013-12-26 20:19:34 -060028def check_backend_support(item):
Paul Kehrer5a8fdf82013-12-26 20:13:45 -060029 supported = item.keywords.get("supported")
30 if supported and "backend" in item.funcargs:
Alex Gaynor50ebb482015-07-02 00:21:41 -040031 for mark in supported:
32 if not mark.kwargs["only_if"](item.funcargs["backend"]):
33 pytest.skip("{0} ({1})".format(
34 mark.kwargs["skip_message"], item.funcargs["backend"]
35 ))
Paul Kehrer5a8fdf82013-12-26 20:13:45 -060036 elif supported:
Paul Kehrerec495502013-12-27 15:51:40 -060037 raise ValueError("This mark is only available on methods that take a "
38 "backend")
Paul Kehrer5a8fdf82013-12-26 20:13:45 -060039
40
Alex Gaynor7a489db2014-03-22 15:09:34 -070041@contextmanager
Alex Stapleton5e4c8c32014-03-27 16:38:00 +000042def raises_unsupported_algorithm(reason):
Alex Gaynor7a489db2014-03-22 15:09:34 -070043 with pytest.raises(UnsupportedAlgorithm) as exc_info:
Alex Stapleton112963e2014-03-26 17:39:29 +000044 yield exc_info
Alex Stapleton5e4c8c32014-03-27 16:38:00 +000045
Alex Stapleton85a791f2014-03-27 16:55:41 +000046 assert exc_info.value._reason is reason
Alex Gaynor7a489db2014-03-22 15:09:34 -070047
48
Paul Kehrerfdae0702014-11-27 07:50:46 -100049def load_vectors_from_file(filename, loader, mode="r"):
50 with cryptography_vectors.open_vector_file(filename, mode) as vector_file:
Alex Stapletona39a3192014-03-14 20:03:12 +000051 return loader(vector_file)
Paul Kehrerf7f6a9f2013-11-11 20:43:52 -060052
53
Alex Gaynord3ce7032013-11-11 14:46:20 -080054def load_nist_vectors(vector_data):
Paul Kehrer749ac5b2013-11-18 18:12:41 -060055 test_data = None
56 data = []
Donald Stufft9e1a48b2013-08-09 00:32:30 -040057
58 for line in vector_data:
59 line = line.strip()
60
Paul Kehrer749ac5b2013-11-18 18:12:41 -060061 # Blank lines, comments, and section headers are ignored
Alex Gaynore0a879f2015-02-15 20:54:34 -080062 if not line or line.startswith("#") or (line.startswith("[") and
63 line.endswith("]")):
Alex Gaynor521c42d2013-11-11 14:25:59 -080064 continue
65
Paul Kehrera43b6692013-11-12 15:35:49 -060066 if line.strip() == "FAIL":
Paul Kehrer749ac5b2013-11-18 18:12:41 -060067 test_data["fail"] = True
Paul Kehrera43b6692013-11-12 15:35:49 -060068 continue
69
Donald Stufft9e1a48b2013-08-09 00:32:30 -040070 # Build our data using a simple Key = Value format
Paul Kehrera43b6692013-11-12 15:35:49 -060071 name, value = [c.strip() for c in line.split("=")]
Donald Stufft9e1a48b2013-08-09 00:32:30 -040072
Paul Kehrer1050ddf2014-01-27 21:04:03 -060073 # Some tests (PBKDF2) contain \0, which should be interpreted as a
74 # null character rather than literal.
75 value = value.replace("\\0", "\0")
76
Donald Stufft9e1a48b2013-08-09 00:32:30 -040077 # COUNT is a special token that indicates a new block of data
78 if name.upper() == "COUNT":
Paul Kehrer749ac5b2013-11-18 18:12:41 -060079 test_data = {}
80 data.append(test_data)
81 continue
Donald Stufft9e1a48b2013-08-09 00:32:30 -040082 # For all other tokens we simply want the name, value stored in
83 # the dictionary
84 else:
Paul Kehrer749ac5b2013-11-18 18:12:41 -060085 test_data[name.lower()] = value.encode("ascii")
Donald Stufft9e1a48b2013-08-09 00:32:30 -040086
Paul Kehrer749ac5b2013-11-18 18:12:41 -060087 return data
Donald Stufft9e1a48b2013-08-09 00:32:30 -040088
89
Paul Kehrer1951bf62013-09-15 12:05:43 -050090def load_cryptrec_vectors(vector_data):
Paul Kehrere5805982013-09-27 11:26:01 -050091 cryptrec_list = []
Paul Kehrer1951bf62013-09-15 12:05:43 -050092
93 for line in vector_data:
94 line = line.strip()
95
96 # Blank lines and comments are ignored
97 if not line or line.startswith("#"):
98 continue
99
100 if line.startswith("K"):
Paul Kehrere5805982013-09-27 11:26:01 -0500101 key = line.split(" : ")[1].replace(" ", "").encode("ascii")
Paul Kehrer1951bf62013-09-15 12:05:43 -0500102 elif line.startswith("P"):
Paul Kehrere5805982013-09-27 11:26:01 -0500103 pt = line.split(" : ")[1].replace(" ", "").encode("ascii")
Paul Kehrer1951bf62013-09-15 12:05:43 -0500104 elif line.startswith("C"):
Paul Kehrere5805982013-09-27 11:26:01 -0500105 ct = line.split(" : ")[1].replace(" ", "").encode("ascii")
106 # after a C is found the K+P+C tuple is complete
107 # there are many P+C pairs for each K
Alex Gaynor1fe70b12013-10-16 11:59:17 -0700108 cryptrec_list.append({
109 "key": key,
110 "plaintext": pt,
111 "ciphertext": ct
112 })
Donald Stufft3359d7e2013-10-19 19:33:06 -0400113 else:
114 raise ValueError("Invalid line in file '{}'".format(line))
Paul Kehrer1951bf62013-09-15 12:05:43 -0500115 return cryptrec_list
116
117
Paul Kehrer69e06522013-10-18 17:28:39 -0500118def load_hash_vectors(vector_data):
119 vectors = []
Paul Kehrer1bb8b712013-10-27 17:00:14 -0500120 key = None
121 msg = None
122 md = None
Paul Kehrer69e06522013-10-18 17:28:39 -0500123
124 for line in vector_data:
125 line = line.strip()
126
Paul Kehrer87cd0db2013-10-18 18:01:26 -0500127 if not line or line.startswith("#") or line.startswith("["):
Paul Kehrer69e06522013-10-18 17:28:39 -0500128 continue
129
130 if line.startswith("Len"):
131 length = int(line.split(" = ")[1])
Paul Kehrer0317b042013-10-28 17:34:27 -0500132 elif line.startswith("Key"):
Alex Gaynor36e651c2014-01-27 10:08:35 -0800133 # HMAC vectors contain a key attribute. Hash vectors do not.
Paul Kehrer0317b042013-10-28 17:34:27 -0500134 key = line.split(" = ")[1].encode("ascii")
Paul Kehrer69e06522013-10-18 17:28:39 -0500135 elif line.startswith("Msg"):
Alex Gaynor36e651c2014-01-27 10:08:35 -0800136 # In the NIST vectors they have chosen to represent an empty
137 # string as hex 00, which is of course not actually an empty
138 # string. So we parse the provided length and catch this edge case.
Paul Kehrer69e06522013-10-18 17:28:39 -0500139 msg = line.split(" = ")[1].encode("ascii") if length > 0 else b""
140 elif line.startswith("MD"):
141 md = line.split(" = ")[1]
Paul Kehrer0317b042013-10-28 17:34:27 -0500142 # after MD is found the Msg+MD (+ potential key) tuple is complete
Paul Kehrer00dd5092013-10-23 09:41:49 -0500143 if key is not None:
Alex Gaynor36e651c2014-01-27 10:08:35 -0800144 vectors.append(KeyedHashVector(msg, md, key))
Paul Kehrer1bb8b712013-10-27 17:00:14 -0500145 key = None
146 msg = None
147 md = None
Paul Kehrer00dd5092013-10-23 09:41:49 -0500148 else:
Alex Gaynor36e651c2014-01-27 10:08:35 -0800149 vectors.append(HashVector(msg, md))
Paul Kehrer1bb8b712013-10-27 17:00:14 -0500150 msg = None
151 md = None
Paul Kehrer69e06522013-10-18 17:28:39 -0500152 else:
153 raise ValueError("Unknown line in hash vector")
154 return vectors
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000155
156
157def load_pkcs1_vectors(vector_data):
158 """
159 Loads data out of RSA PKCS #1 vector files.
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000160 """
161 private_key_vector = None
162 public_key_vector = None
163 attr = None
164 key = None
Paul Kehrerefca2802014-02-17 20:55:13 -0600165 example_vector = None
166 examples = []
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000167 vectors = []
168 for line in vector_data:
Paul Kehrer7774a032014-02-17 22:56:55 -0600169 if (
170 line.startswith("# PSS Example") or
Paul Kehrer3fe91502014-03-29 12:08:39 -0500171 line.startswith("# OAEP Example") or
172 line.startswith("# PKCS#1 v1.5")
Paul Kehrer7774a032014-02-17 22:56:55 -0600173 ):
Paul Kehrerefca2802014-02-17 20:55:13 -0600174 if example_vector:
175 for key, value in six.iteritems(example_vector):
Paul Kehrer26811802014-02-19 16:32:11 -0600176 hex_str = "".join(value).replace(" ", "").encode("ascii")
Paul Kehrerefca2802014-02-17 20:55:13 -0600177 example_vector[key] = hex_str
178 examples.append(example_vector)
179
180 attr = None
181 example_vector = collections.defaultdict(list)
182
Paul Kehrer3fe91502014-03-29 12:08:39 -0500183 if line.startswith("# Message"):
Paul Kehrer7d9c3062014-02-18 08:27:39 -0600184 attr = "message"
Paul Kehrerefca2802014-02-17 20:55:13 -0600185 continue
186 elif line.startswith("# Salt"):
187 attr = "salt"
188 continue
Paul Kehrer3fe91502014-03-29 12:08:39 -0500189 elif line.startswith("# Seed"):
190 attr = "seed"
191 continue
Paul Kehrerefca2802014-02-17 20:55:13 -0600192 elif line.startswith("# Signature"):
193 attr = "signature"
194 continue
Paul Kehrer3fe91502014-03-29 12:08:39 -0500195 elif line.startswith("# Encryption"):
196 attr = "encryption"
197 continue
Paul Kehrerefca2802014-02-17 20:55:13 -0600198 elif (
199 example_vector and
200 line.startswith("# =============================================")
201 ):
202 for key, value in six.iteritems(example_vector):
Paul Kehrer26811802014-02-19 16:32:11 -0600203 hex_str = "".join(value).replace(" ", "").encode("ascii")
Paul Kehrerefca2802014-02-17 20:55:13 -0600204 example_vector[key] = hex_str
205 examples.append(example_vector)
206 example_vector = None
207 attr = None
208 elif example_vector and line.startswith("#"):
209 continue
210 else:
211 if attr is not None and example_vector is not None:
212 example_vector[attr].append(line.strip())
213 continue
214
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000215 if (
216 line.startswith("# Example") or
217 line.startswith("# =============================================")
218 ):
219 if key:
220 assert private_key_vector
221 assert public_key_vector
222
223 for key, value in six.iteritems(public_key_vector):
224 hex_str = "".join(value).replace(" ", "")
225 public_key_vector[key] = int(hex_str, 16)
226
227 for key, value in six.iteritems(private_key_vector):
228 hex_str = "".join(value).replace(" ", "")
229 private_key_vector[key] = int(hex_str, 16)
230
Paul Kehrerefca2802014-02-17 20:55:13 -0600231 private_key_vector["examples"] = examples
232 examples = []
233
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000234 assert (
235 private_key_vector['public_exponent'] ==
236 public_key_vector['public_exponent']
237 )
238
239 assert (
240 private_key_vector['modulus'] ==
241 public_key_vector['modulus']
242 )
243
244 vectors.append(
245 (private_key_vector, public_key_vector)
246 )
247
248 public_key_vector = collections.defaultdict(list)
249 private_key_vector = collections.defaultdict(list)
250 key = None
251 attr = None
252
253 if private_key_vector is None or public_key_vector is None:
254 continue
255
256 if line.startswith("# Private key"):
257 key = private_key_vector
258 elif line.startswith("# Public key"):
259 key = public_key_vector
260 elif line.startswith("# Modulus:"):
261 attr = "modulus"
262 elif line.startswith("# Public exponent:"):
263 attr = "public_exponent"
264 elif line.startswith("# Exponent:"):
265 if key is public_key_vector:
266 attr = "public_exponent"
267 else:
268 assert key is private_key_vector
269 attr = "private_exponent"
270 elif line.startswith("# Prime 1:"):
271 attr = "p"
272 elif line.startswith("# Prime 2:"):
273 attr = "q"
Paul Kehrer09328bb2014-02-12 23:57:27 -0600274 elif line.startswith("# Prime exponent 1:"):
275 attr = "dmp1"
276 elif line.startswith("# Prime exponent 2:"):
277 attr = "dmq1"
278 elif line.startswith("# Coefficient:"):
279 attr = "iqmp"
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000280 elif line.startswith("#"):
281 attr = None
282 else:
283 if key is not None and attr is not None:
284 key[attr].append(line.strip())
285 return vectors
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400286
287
288def load_rsa_nist_vectors(vector_data):
289 test_data = None
Paul Kehrer62707f12014-03-18 07:19:14 -0400290 p = None
Paul Kehrerafc25182014-03-18 07:51:56 -0400291 salt_length = None
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400292 data = []
293
294 for line in vector_data:
295 line = line.strip()
296
297 # Blank lines and section headers are ignored
298 if not line or line.startswith("["):
299 continue
300
301 if line.startswith("# Salt len:"):
302 salt_length = int(line.split(":")[1].strip())
303 continue
304 elif line.startswith("#"):
305 continue
306
307 # Build our data using a simple Key = Value format
308 name, value = [c.strip() for c in line.split("=")]
309
310 if name == "n":
311 n = int(value, 16)
Paul Kehrer62707f12014-03-18 07:19:14 -0400312 elif name == "e" and p is None:
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400313 e = int(value, 16)
Paul Kehrer62707f12014-03-18 07:19:14 -0400314 elif name == "p":
315 p = int(value, 16)
316 elif name == "q":
317 q = int(value, 16)
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400318 elif name == "SHAAlg":
Paul Kehrer62707f12014-03-18 07:19:14 -0400319 if p is None:
320 test_data = {
321 "modulus": n,
322 "public_exponent": e,
323 "salt_length": salt_length,
Paul Kehrere66f69a2014-03-18 07:57:26 -0400324 "algorithm": value,
Paul Kehrer62707f12014-03-18 07:19:14 -0400325 "fail": False
326 }
327 else:
328 test_data = {
329 "modulus": n,
330 "p": p,
331 "q": q,
Paul Kehrere66f69a2014-03-18 07:57:26 -0400332 "algorithm": value
Paul Kehrer62707f12014-03-18 07:19:14 -0400333 }
Paul Kehrerafc25182014-03-18 07:51:56 -0400334 if salt_length is not None:
335 test_data["salt_length"] = salt_length
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400336 data.append(test_data)
Paul Kehrer62707f12014-03-18 07:19:14 -0400337 elif name == "e" and p is not None:
338 test_data["public_exponent"] = int(value, 16)
339 elif name == "d":
340 test_data["private_exponent"] = int(value, 16)
341 elif name == "Result":
342 test_data["fail"] = value.startswith("F")
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400343 # For all other tokens we simply want the name, value stored in
344 # the dictionary
345 else:
346 test_data[name.lower()] = value.encode("ascii")
347
348 return data
Mohammed Attia987cc702014-03-12 16:07:21 +0200349
350
351def load_fips_dsa_key_pair_vectors(vector_data):
352 """
353 Loads data out of the FIPS DSA KeyPair vector files.
354 """
355 vectors = []
Mohammed Attia49b92592014-03-12 20:07:05 +0200356 # When reading_key_data is set to True it tells the loader to continue
357 # constructing dictionaries. We set reading_key_data to False during the
358 # blocks of the vectors of N=224 because we don't support it.
359 reading_key_data = True
Mohammed Attia987cc702014-03-12 16:07:21 +0200360 for line in vector_data:
361 line = line.strip()
362
363 if not line or line.startswith("#"):
364 continue
Mohammed Attia49b92592014-03-12 20:07:05 +0200365 elif line.startswith("[mod = L=1024"):
Mohammed Attia987cc702014-03-12 16:07:21 +0200366 continue
Mohammed Attia49b92592014-03-12 20:07:05 +0200367 elif line.startswith("[mod = L=2048, N=224"):
368 reading_key_data = False
Mohammed Attia987cc702014-03-12 16:07:21 +0200369 continue
Mohammed Attia49b92592014-03-12 20:07:05 +0200370 elif line.startswith("[mod = L=2048, N=256"):
371 reading_key_data = True
Mohammed Attia987cc702014-03-12 16:07:21 +0200372 continue
Mohammed Attia49b92592014-03-12 20:07:05 +0200373 elif line.startswith("[mod = L=3072"):
Mohammed Attia987cc702014-03-12 16:07:21 +0200374 continue
Alex Gaynor0fe7db62015-06-27 17:20:59 -0400375
376 if reading_key_data:
Mohammed Attia987cc702014-03-12 16:07:21 +0200377 if line.startswith("P"):
378 vectors.append({'p': int(line.split("=")[1], 16)})
Mohammed Attia22ccb872014-03-12 18:27:59 +0200379 elif line.startswith("Q"):
Mohammed Attia987cc702014-03-12 16:07:21 +0200380 vectors[-1]['q'] = int(line.split("=")[1], 16)
Mohammed Attia22ccb872014-03-12 18:27:59 +0200381 elif line.startswith("G"):
Mohammed Attia987cc702014-03-12 16:07:21 +0200382 vectors[-1]['g'] = int(line.split("=")[1], 16)
Mohammed Attia22ccb872014-03-12 18:27:59 +0200383 elif line.startswith("X") and 'x' not in vectors[-1]:
Mohammed Attia987cc702014-03-12 16:07:21 +0200384 vectors[-1]['x'] = int(line.split("=")[1], 16)
Mohammed Attia22ccb872014-03-12 18:27:59 +0200385 elif line.startswith("X") and 'x' in vectors[-1]:
Mohammed Attia987cc702014-03-12 16:07:21 +0200386 vectors.append({'p': vectors[-1]['p'],
387 'q': vectors[-1]['q'],
388 'g': vectors[-1]['g'],
389 'x': int(line.split("=")[1], 16)
390 })
Mohammed Attia22ccb872014-03-12 18:27:59 +0200391 elif line.startswith("Y"):
Mohammed Attia987cc702014-03-12 16:07:21 +0200392 vectors[-1]['y'] = int(line.split("=")[1], 16)
Mohammed Attia987cc702014-03-12 16:07:21 +0200393
394 return vectors
Alex Stapletoncf048602014-04-12 12:48:59 +0100395
396
Mohammed Attia3c9e1582014-04-22 14:24:44 +0200397def load_fips_dsa_sig_vectors(vector_data):
Mohammed Attia0fb5d852014-04-21 10:31:15 +0200398 """
399 Loads data out of the FIPS DSA SigVer vector files.
400 """
401 vectors = []
402 sha_regex = re.compile(
403 r"\[mod = L=...., N=..., SHA-(?P<sha>1|224|256|384|512)\]"
404 )
405 # When reading_key_data is set to True it tells the loader to continue
406 # constructing dictionaries. We set reading_key_data to False during the
407 # blocks of the vectors of N=224 because we don't support it.
408 reading_key_data = True
Mohammed Attia3c9e1582014-04-22 14:24:44 +0200409
Mohammed Attia0fb5d852014-04-21 10:31:15 +0200410 for line in vector_data:
411 line = line.strip()
412
413 if not line or line.startswith("#"):
414 continue
415
416 sha_match = sha_regex.match(line)
417 if sha_match:
418 digest_algorithm = "SHA-{0}".format(sha_match.group("sha"))
419
Paul Kehrer7ef2f8f2014-04-22 08:37:58 -0500420 if line.startswith("[mod = L=2048, N=224"):
Mohammed Attia0fb5d852014-04-21 10:31:15 +0200421 reading_key_data = False
422 continue
Paul Kehrer7ef2f8f2014-04-22 08:37:58 -0500423 elif line.startswith("[mod = L=2048, N=256"):
Mohammed Attia0fb5d852014-04-21 10:31:15 +0200424 reading_key_data = True
425 continue
426
427 if not reading_key_data or line.startswith("[mod"):
428 continue
429
430 name, value = [c.strip() for c in line.split("=")]
431
432 if name == "P":
433 vectors.append({'p': int(value, 16),
434 'digest_algorithm': digest_algorithm})
435 elif name == "Q":
436 vectors[-1]['q'] = int(value, 16)
437 elif name == "G":
438 vectors[-1]['g'] = int(value, 16)
439 elif name == "Msg" and 'msg' not in vectors[-1]:
440 hexmsg = value.strip().encode("ascii")
441 vectors[-1]['msg'] = binascii.unhexlify(hexmsg)
442 elif name == "Msg" and 'msg' in vectors[-1]:
443 hexmsg = value.strip().encode("ascii")
444 vectors.append({'p': vectors[-1]['p'],
445 'q': vectors[-1]['q'],
446 'g': vectors[-1]['g'],
447 'digest_algorithm':
448 vectors[-1]['digest_algorithm'],
449 'msg': binascii.unhexlify(hexmsg)})
450 elif name == "X":
451 vectors[-1]['x'] = int(value, 16)
452 elif name == "Y":
453 vectors[-1]['y'] = int(value, 16)
454 elif name == "R":
455 vectors[-1]['r'] = int(value, 16)
456 elif name == "S":
457 vectors[-1]['s'] = int(value, 16)
458 elif name == "Result":
459 vectors[-1]['result'] = value.split("(")[0].strip()
460
461 return vectors
462
463
Alex Stapleton44fe82d2014-04-19 09:44:26 +0100464# http://tools.ietf.org/html/rfc4492#appendix-A
Alex Stapletonc387cf72014-04-13 13:58:02 +0100465_ECDSA_CURVE_NAMES = {
466 "P-192": "secp192r1",
467 "P-224": "secp224r1",
Alex Stapleton39e300f2014-04-18 22:44:02 +0100468 "P-256": "secp256r1",
Alex Stapletonc387cf72014-04-13 13:58:02 +0100469 "P-384": "secp384r1",
470 "P-521": "secp521r1",
Alex Stapleton39e300f2014-04-18 22:44:02 +0100471
Alex Stapletonc387cf72014-04-13 13:58:02 +0100472 "K-163": "sect163k1",
473 "K-233": "sect233k1",
Alex Stapletonf6a1cf62015-05-03 12:16:19 +0100474 "K-256": "secp256k1",
Alex Stapleton39e300f2014-04-18 22:44:02 +0100475 "K-283": "sect283k1",
Alex Stapletonc387cf72014-04-13 13:58:02 +0100476 "K-409": "sect409k1",
477 "K-571": "sect571k1",
Alex Stapleton39e300f2014-04-18 22:44:02 +0100478
Alex Stapleton44fe82d2014-04-19 09:44:26 +0100479 "B-163": "sect163r2",
Alex Stapletonc387cf72014-04-13 13:58:02 +0100480 "B-233": "sect233r1",
481 "B-283": "sect283r1",
482 "B-409": "sect409r1",
483 "B-571": "sect571r1",
484}
485
486
Alex Stapletoncf048602014-04-12 12:48:59 +0100487def load_fips_ecdsa_key_pair_vectors(vector_data):
488 """
489 Loads data out of the FIPS ECDSA KeyPair vector files.
490 """
491 vectors = []
492 key_data = None
Alex Stapletoncf048602014-04-12 12:48:59 +0100493 for line in vector_data:
494 line = line.strip()
495
496 if not line or line.startswith("#"):
497 continue
498
Alex Stapletonc387cf72014-04-13 13:58:02 +0100499 if line[1:-1] in _ECDSA_CURVE_NAMES:
500 curve_name = _ECDSA_CURVE_NAMES[line[1:-1]]
Alex Stapletoncf048602014-04-12 12:48:59 +0100501
502 elif line.startswith("d = "):
503 if key_data is not None:
504 vectors.append(key_data)
505
506 key_data = {
507 "curve": curve_name,
508 "d": int(line.split("=")[1], 16)
509 }
510
511 elif key_data is not None:
512 if line.startswith("Qx = "):
513 key_data["x"] = int(line.split("=")[1], 16)
514 elif line.startswith("Qy = "):
515 key_data["y"] = int(line.split("=")[1], 16)
516
Paul Kehrerb60b8dd2015-08-01 19:47:22 +0100517 assert key_data is not None
518 vectors.append(key_data)
Alex Stapletoncf048602014-04-12 12:48:59 +0100519
520 return vectors
Alex Stapletonc387cf72014-04-13 13:58:02 +0100521
522
523def load_fips_ecdsa_signing_vectors(vector_data):
524 """
525 Loads data out of the FIPS ECDSA SigGen vector files.
526 """
527 vectors = []
528
529 curve_rx = re.compile(
530 r"\[(?P<curve>[PKB]-[0-9]{3}),SHA-(?P<sha>1|224|256|384|512)\]"
531 )
532
533 data = None
534 for line in vector_data:
535 line = line.strip()
536
Alex Stapletonc387cf72014-04-13 13:58:02 +0100537 curve_match = curve_rx.match(line)
538 if curve_match:
539 curve_name = _ECDSA_CURVE_NAMES[curve_match.group("curve")]
540 digest_name = "SHA-{0}".format(curve_match.group("sha"))
541
542 elif line.startswith("Msg = "):
543 if data is not None:
544 vectors.append(data)
545
546 hexmsg = line.split("=")[1].strip().encode("ascii")
547
548 data = {
549 "curve": curve_name,
550 "digest_algorithm": digest_name,
551 "message": binascii.unhexlify(hexmsg)
552 }
553
554 elif data is not None:
555 if line.startswith("Qx = "):
556 data["x"] = int(line.split("=")[1], 16)
557 elif line.startswith("Qy = "):
558 data["y"] = int(line.split("=")[1], 16)
559 elif line.startswith("R = "):
560 data["r"] = int(line.split("=")[1], 16)
561 elif line.startswith("S = "):
562 data["s"] = int(line.split("=")[1], 16)
563 elif line.startswith("d = "):
564 data["d"] = int(line.split("=")[1], 16)
Alex Stapleton6f729492014-04-19 09:01:25 +0100565 elif line.startswith("Result = "):
566 data["fail"] = line.split("=")[1].strip()[0] == "F"
Alex Stapletonc387cf72014-04-13 13:58:02 +0100567
Paul Kehrerb60b8dd2015-08-01 19:47:22 +0100568 assert data is not None
569 vectors.append(data)
Alex Stapletonc387cf72014-04-13 13:58:02 +0100570 return vectors
Alex Stapleton839c09d2014-08-10 12:18:02 +0100571
572
573def load_kasvs_dh_vectors(vector_data):
574 """
575 Loads data out of the KASVS key exchange vector data
576 """
577
578 result_rx = re.compile(r"([FP]) \(([0-9]+) -")
579
580 vectors = []
581 data = {
582 "fail_z": False,
583 "fail_agree": False
584 }
585
586 for line in vector_data:
587 line = line.strip()
588
589 if not line or line.startswith("#"):
590 continue
591
592 if line.startswith("P = "):
593 data["p"] = int(line.split("=")[1], 16)
594 elif line.startswith("Q = "):
595 data["q"] = int(line.split("=")[1], 16)
596 elif line.startswith("G = "):
597 data["g"] = int(line.split("=")[1], 16)
598 elif line.startswith("Z = "):
599 z_hex = line.split("=")[1].strip().encode("ascii")
600 data["z"] = binascii.unhexlify(z_hex)
601 elif line.startswith("XstatCAVS = "):
602 data["x1"] = int(line.split("=")[1], 16)
603 elif line.startswith("YstatCAVS = "):
604 data["y1"] = int(line.split("=")[1], 16)
605 elif line.startswith("XstatIUT = "):
606 data["x2"] = int(line.split("=")[1], 16)
607 elif line.startswith("YstatIUT = "):
608 data["y2"] = int(line.split("=")[1], 16)
609 elif line.startswith("Result = "):
610 result_str = line.split("=")[1].strip()
611 match = result_rx.match(result_str)
612
613 if match.group(1) == "F":
614 if int(match.group(2)) in (5, 10):
615 data["fail_z"] = True
616 else:
617 data["fail_agree"] = True
618
619 vectors.append(data)
620
621 data = {
622 "p": data["p"],
623 "q": data["q"],
624 "g": data["g"],
625 "fail_z": False,
626 "fail_agree": False
627 }
628
629 return vectors
Simo Sorce917addb2015-04-29 19:41:26 -0400630
631
632def load_kasvs_ecdh_vectors(vector_data):
633 """
634 Loads data out of the KASVS key exchange vector data
635 """
636
637 curve_name_map = {
638 "P-192": "secp192r1",
639 "P-224": "secp224r1",
640 "P-256": "secp256r1",
641 "P-384": "secp384r1",
642 "P-521": "secp521r1",
643 }
644
645 result_rx = re.compile(r"([FP]) \(([0-9]+) -")
646
647 tags = []
Alex Gaynorace036d2015-09-24 20:23:08 -0400648 sets = {}
Simo Sorce917addb2015-04-29 19:41:26 -0400649 vectors = []
650
651 # find info in header
652 for line in vector_data:
653 line = line.strip()
654
655 if line.startswith("#"):
656 parm = line.split("Parameter set(s) supported:")
657 if len(parm) == 2:
658 names = parm[1].strip().split()
659 for n in names:
660 tags.append("[%s]" % n)
661 break
662
663 # Sets Metadata
664 tag = None
665 curve = None
666 for line in vector_data:
667 line = line.strip()
668
669 if not line or line.startswith("#"):
670 continue
671
672 if line in tags:
673 tag = line
674 curve = None
675 elif line.startswith("[Curve selected:"):
676 curve = curve_name_map[line.split(':')[1].strip()[:-1]]
677
678 if tag is not None and curve is not None:
679 sets[tag.strip("[]")] = curve
680 tag = None
681 if len(tags) == len(sets):
682 break
683
684 # Data
685 data = {
Alex Gaynorace036d2015-09-24 20:23:08 -0400686 "CAVS": {},
687 "IUT": {},
Simo Sorce917addb2015-04-29 19:41:26 -0400688 }
689 tag = None
690 for line in vector_data:
691 line = line.strip()
692
693 if not line or line.startswith("#"):
694 continue
695
696 if line.startswith("["):
697 tag = line.split()[0][1:]
698 elif line.startswith("COUNT = "):
Simo Sorce6e3b1552015-10-13 14:45:21 -0400699 data["COUNT"] = int(line.split("=")[1])
Simo Sorce917addb2015-04-29 19:41:26 -0400700 elif line.startswith("dsCAVS = "):
701 data["CAVS"]["d"] = int(line.split("=")[1], 16)
702 elif line.startswith("QsCAVSx = "):
703 data["CAVS"]["x"] = int(line.split("=")[1], 16)
704 elif line.startswith("QsCAVSy = "):
705 data["CAVS"]["y"] = int(line.split("=")[1], 16)
706 elif line.startswith("dsIUT = "):
707 data["IUT"]["d"] = int(line.split("=")[1], 16)
708 elif line.startswith("QsIUTx = "):
709 data["IUT"]["x"] = int(line.split("=")[1], 16)
710 elif line.startswith("QsIUTy = "):
711 data["IUT"]["y"] = int(line.split("=")[1], 16)
Simo Sorce83e563e2015-05-06 10:56:31 -0400712 elif line.startswith("OI = "):
713 data["OI"] = int(line.split("=")[1], 16)
Simo Sorce917addb2015-04-29 19:41:26 -0400714 elif line.startswith("Z = "):
715 data["Z"] = int(line.split("=")[1], 16)
Simo Sorce83e563e2015-05-06 10:56:31 -0400716 elif line.startswith("DKM = "):
717 data["DKM"] = int(line.split("=")[1], 16)
Simo Sorce917addb2015-04-29 19:41:26 -0400718 elif line.startswith("Result = "):
719 result_str = line.split("=")[1].strip()
720 match = result_rx.match(result_str)
721
722 if match.group(1) == "F":
723 data["fail"] = True
724 else:
725 data["fail"] = False
726 data["errno"] = int(match.group(2))
727
728 data["curve"] = sets[tag]
729
730 vectors.append(data)
731
732 data = {
Alex Gaynorace036d2015-09-24 20:23:08 -0400733 "CAVS": {},
734 "IUT": {},
Simo Sorce917addb2015-04-29 19:41:26 -0400735 }
736
737 return vectors
Simo Sorce7600dee2015-09-22 21:56:20 -0400738
739
740def load_x963_vectors(vector_data):
741 """
742 Loads data out of the X9.63 vector data
743 """
744
745 vectors = []
746
747 # Sets Metadata
748 hashname = None
Alex Gaynorace036d2015-09-24 20:23:08 -0400749 vector = {}
Simo Sorce7600dee2015-09-22 21:56:20 -0400750 for line in vector_data:
751 line = line.strip()
752
753 if line.startswith("[SHA"):
754 hashname = line[1:-1]
755 shared_secret_len = 0
756 shared_info_len = 0
757 key_data_len = 0
758 elif line.startswith("[shared secret length"):
759 shared_secret_len = int(line[1:-1].split("=")[1].strip())
760 elif line.startswith("[SharedInfo length"):
761 shared_info_len = int(line[1:-1].split("=")[1].strip())
762 elif line.startswith("[key data length"):
763 key_data_len = int(line[1:-1].split("=")[1].strip())
764 elif line.startswith("COUNT"):
765 count = int(line.split("=")[1].strip())
766 vector["hash"] = hashname
767 vector["count"] = count
Alex Gaynorace036d2015-09-24 20:23:08 -0400768 vector["shared_secret_length"] = shared_secret_len
769 vector["sharedinfo_length"] = shared_info_len
770 vector["key_data_length"] = key_data_len
Simo Sorce7600dee2015-09-22 21:56:20 -0400771 elif line.startswith("Z"):
772 vector["Z"] = line.split("=")[1].strip()
773 assert math.ceil(shared_secret_len / 8) * 2 == len(vector["Z"])
774 elif line.startswith("SharedInfo"):
775 if shared_info_len != 0:
Alex Gaynorace036d2015-09-24 20:23:08 -0400776 vector["sharedinfo"] = line.split("=")[1].strip()
777 silen = len(vector["sharedinfo"])
Simo Sorce7600dee2015-09-22 21:56:20 -0400778 assert math.ceil(shared_info_len / 8) * 2 == silen
779 elif line.startswith("key_data"):
780 vector["key_data"] = line.split("=")[1].strip()
781 assert math.ceil(key_data_len / 8) * 2 == len(vector["key_data"])
782 vectors.append(vector)
Alex Gaynorace036d2015-09-24 20:23:08 -0400783 vector = {}
Simo Sorce7600dee2015-09-22 21:56:20 -0400784
785 return vectors
Jaredcd258d52016-04-13 14:03:52 -0700786
787
788def load_nist_kbkdf_vectors(vector_data):
789 """
790 Load NIST SP 800-108 KDF Vectors
791 """
792 vectors = []
793 test_data = None
794 tag = {}
795
796 for line in vector_data:
797 line = line.strip()
798
799 if not line or line.startswith("#"):
800 continue
801
802 if line.startswith("[") and line.endswith("]"):
803 tag_data = line[1:-1]
804 name, value = [c.strip() for c in tag_data.split("=")]
805 if value.endswith('_BITS'):
806 value = int(value.split('_')[0])
807 tag.update({name.lower(): value})
808 continue
809
810 tag.update({name.lower(): value.lower()})
811 elif line.startswith("COUNT="):
812 test_data = dict()
813 test_data.update(tag)
814 vectors.append(test_data)
815 elif line.startswith("L"):
816 name, value = [c.strip() for c in line.split("=")]
817 test_data[name.lower()] = int(value)
818 else:
819 name, value = [c.strip() for c in line.split("=")]
820 test_data[name.lower()] = value.encode("ascii")
821
822 return vectors