diff options
Diffstat (limited to 'tests/test-ecdsa.py')
-rw-r--r-- | tests/test-ecdsa.py | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/tests/test-ecdsa.py b/tests/test-ecdsa.py new file mode 100644 index 0000000..1ecfef9 --- /dev/null +++ b/tests/test-ecdsa.py @@ -0,0 +1,156 @@ +# Test vectors from "Suite B Implementer's Guide to FIPS 186-3". +# +# e is given in decimal, all other values are hex, because that's how +# these were given in the paper + +p256_d = 0x70a12c2db16845ed56ff68cfc21a472b3f04d7d6851bf6349f2d7d5b3452b38a +p256_Qx = 0x8101ece47464a6ead70cf69a6e2bd3d88691a3262d22cba4f7635eaff26680a8 +p256_Qy = 0xd8a12ba61d599235f67d9cb4d58f1783d3ca43e78f0a5abaa624079936c0c3a9 +p256_k = 0x580ec00d856434334cef3f71ecaed4965b12ae37fa47055b1965c7b134ee45d0 +p256_kinv = 0x6a664fa115356d33f16331b54c4e7ce967965386c7dcbf2904604d0c132b4a74 +p256_Rx = 0x7214bc9647160bbd39ff2f80533f5dc6ddd70ddf86bb815661e805d5d4e6f27c +p256_Ry = 0x8b81e3e977597110c7cf2633435b2294b72642987defd3d4007e1cfc5df84541 +p256_r = p256_Rx +p256_M = 0x54686973206973206f6e6c7920612074657374206d6573736167652e204974206973203438206279746573206c6f6e67 +p256_H = 0x7c3e883ddc8bd688f96eac5e9324222c8f30f9d6bb59e9c5f020bd39ba2b8377 +p256_e = 56197278047627432394583341962843287937266210957576322469816113796290471232375 +p256_s = 0x7d1ff961980f961bdaa3233b6209f4013317d3e3f9e1493592dbeaa1af2bc367 +p256_w = 0xd69be75f67ee5394cabb6c286f3610cf62d722cba9eea70faee770a6b2ed72dc +p256_u1 = 0xbb252401d6fb322bb747184cf2ac52bf8d54b95a1515062a2f6141f2e2092ed8 +p256_u2 = 0xaae7d1c7f2c232dfc641948af3dba141d4de8634e571cf84c486301b510cfc04 +p256_v = 0x7214bc9647160bbd39ff2f80533f5dc6ddd70ddf86bb815661e805d5d4e6f27c + +p384_d = 0xc838b85253ef8dc7394fa5808a5183981c7deef5a69ba8f4f2117ffea39cfcd90e95f6cbc854abacab701d50c1f3cf24 +p384_Qx = 0x1fbac8eebd0cbf35640b39efe0808dd774debff20a2a329e91713baf7d7f3c3e81546d883730bee7e48678f857b02ca0 +p384_Qy = 0xeb213103bd68ce343365a8a4c3d4555fa385f5330203bdd76ffad1f3affb95751c132007e1b240353cb0a4cf1693bdf9 +p384_k = 0xdc6b44036989a196e39d1cdac000812f4bdd8b2db41bb33af51372585ebd1db63f0ce8275aa1fd45e2d2a735f8749359 +p384_kinv = 0x7436f03088e65c37ba8e7b33887fbc87757514d611f7d1fbdf6d2104a297ad318cdbf7404e4ba37e599666df37b8d8be +p384_Rx = 0xa0c27ec893092dea1e1bd2ccfed3cf945c8134ed0c9f81311a0f4a05942db8dbed8dd59f267471d5462aa14fe72de856 +p384_Ry = 0x855649409815bb91424eaca5fd76c97375d575d1422ec53d343bd33b847fdf0c11569685b528ab25493015428d7cf72b +p384_r = p384_Rx +p384_M = 0x54686973206973206f6e6c7920612074657374206d6573736167652e204974206973203438206279746573206c6f6e67 +p384_H = 0xb9210c9d7e20897ab86597266a9d5077e8db1b06f7220ed6ee75bd8b45db37891f8ba5550304004159f4453dc5b3f5a1 +p384_e = 28493976155450475404302482243066463769180620629462008675793884393889401828800663731864240088367206094074919580333473 +p384_s = 0x20ab3f45b74f10b6e11f96a2c8eb694d206b9dda86d3c7e331c26b22c987b7537726577667adadf168ebbe803794a402 +p384_w = 0x1798845cd0a6cea5327c501a71a4baf2f7be882cfbc303750a7c861af8fe8225467a257f5bf91a4aaa5a79a8637d218a +p384_u1 = 0x6ce25649d42d223e020c11140fe772326612bb11b686d35ee98ed4550e0635d9dd3a2afbca0cf2c4baedcd23313b189e +p384_u2 = 0xf3b240751d5d8ed394a4b5bf8e2a4c0e1e21aa51f2620a08b8c55a2bc334c9689923162648f06e5f4659fc526d9c1fd6 +p384_v = 0xa0c27ec893092dea1e1bd2ccfed3cf945c8134ed0c9f81311a0f4a05942db8dbed8dd59f267471d5462aa14fe72de856 + +from textwrap import TextWrapper +from os.path import basename +from sys import argv +from pyasn1.type.univ import Sequence, Choice, Integer, OctetString, ObjectIdentifier, BitString +from pyasn1.type.namedtype import NamedTypes, NamedType, OptionalNamedType +from pyasn1.type.namedval import NamedValues +from pyasn1.type.tag import Tag, tagClassContext, tagFormatSimple +from pyasn1.type.constraint import SingleValueConstraint +from pyasn1.codec.der.encoder import encode as DER_Encode +from pyasn1.codec.der.decoder import decode as DER_Decode + +wrapper = TextWrapper(width = 78, initial_indent = " " * 2, subsequent_indent = " " * 2) + +def long_to_bytes(l): + # + # This is just plain nasty. + # + s = "%x" % l + return ("0" + s if len(s) & 1 else s).decode("hex") + +def bytes_to_bits(b): + # + # This, on the other hand, is not just plain nasty, this is fancy nasty. + # This is nasty with raisins in it. + # + bits = bin(long(b.encode("hex"), 16))[2:] + if len(bits) % 8: + bits = ("0" * (8 - len(bits) % 8)) + bits + return tuple(int(i) for i in bits) + +### + +class ECDSA_Sig_Value(Sequence): + componentType = NamedTypes( + NamedType("r", Integer()), + NamedType("s", Integer())) + +def encode_sig(r, s): + sig = ECDSA_Sig_Value() + sig["r"] = r + sig["s"] = s + return DER_Encode(sig) + +p256_sig = encode_sig(p256_r, p256_s) +p384_sig = encode_sig(p384_r, p384_s) + +### + +class ECPrivateKey(Sequence): + componentType = NamedTypes( + NamedType("version", Integer(namedValues = NamedValues(("ecPrivkeyVer1", 1)) + ).subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(1))), + NamedType("privateKey", OctetString()), + OptionalNamedType("parameters", ObjectIdentifier().subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 0))), + OptionalNamedType("publicKey", BitString().subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 1)))) + +def encode_key(d, Qx, Qy, oid): + private_key = long_to_bytes(d) + public_key = bytes_to_bits(chr(0x04) + long_to_bytes(Qx) + long_to_bytes(Qy)) + parameters = oid + key = ECPrivateKey() + key["version"] = 1 + key["privateKey"] = private_key + key["parameters"] = parameters + key["publicKey"] = public_key + return DER_Encode(key) + +p256_key = encode_key(p256_d, p256_Qx, p256_Qy, "1.2.840.10045.3.1.7") +p384_key = encode_key(p384_d, p384_Qx, p384_Qy, "1.3.132.0.34") + +### + +print "/*" +print " * ECDSA test data." +print " * File automatically generated by", basename(argv[0]) +print " */" + +curves = ("p256", "p384") +vars = set() + +for name in dir(): + head, sep, tail = name.partition("_") + if head in curves: + vars.add(tail) + +vars = sorted(vars) + +for curve in curves: + for var in vars: + name = curve + "_" + var + value = globals().get(name, None) + if isinstance(value, (int, long)): + value = long_to_bytes(value) + if value is not None: + print + print "static const uint8_t %s[] = { /* %d bytes */" % (name, len(value)) + print wrapper.fill(", ".join("0x%02x" % ord(v) for v in value)) + print "};" + +print +print "typedef struct {" +print " hal_ecdsa_curve_t curve;" +for var in vars: + print " const uint8_t *%8s; size_t %8s_len;" % (var, var) +print "} ecdsa_tc_t;" +print +print "static const ecdsa_tc_t ecdsa_tc[] = {" +for curve in curves: + print " { HAL_ECDSA_CURVE_%s," % curve.upper() + for var in vars: + name = curve + "_" + var + if name in globals(): + print " %-14s sizeof(%s)," % (name + ",", name) + else: + print " %-14s 0," % "NULL," + print " }," +print "};" |