aboutsummaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
authorJ08nY2020-06-13 01:59:22 +0200
committerJ08nY2020-06-13 01:59:22 +0200
commit4e17dfdb12707c814add7851c81eda4edb3dacde (patch)
tree1f59c7adad2cc58e3a53d995b029c5a76f591411 /test
parent23b3638a496637c1810fb5a2bd610b63b1a72521 (diff)
downloadpyecsca-4e17dfdb12707c814add7851c81eda4edb3dacde.tar.gz
pyecsca-4e17dfdb12707c814add7851c81eda4edb3dacde.tar.zst
pyecsca-4e17dfdb12707c814add7851c81eda4edb3dacde.zip
Add docs and tests to the ECTester target.
Diffstat (limited to 'test')
-rw-r--r--test/ec/test_curve.py13
-rw-r--r--test/ec/test_mod.py18
-rw-r--r--test/sca/test_target.py288
3 files changed, 315 insertions, 4 deletions
diff --git a/test/ec/test_curve.py b/test/ec/test_curve.py
index 91d9f16..1b22279 100644
--- a/test/ec/test_curve.py
+++ b/test/ec/test_curve.py
@@ -1,5 +1,7 @@
+from binascii import unhexlify
from unittest import TestCase
+from pyecsca.ec.coordinates import AffineCoordinateModel
from pyecsca.ec.curve import EllipticCurve
from pyecsca.ec.params import get_params
from pyecsca.ec.mod import Mod
@@ -76,3 +78,14 @@ class CurveTests(TestCase):
self.assertEqual(self.secp128r1.curve, self.secp128r1.curve)
self.assertNotEqual(self.secp128r1.curve, self.curve25519.curve)
self.assertNotEqual(self.secp128r1.curve, None)
+
+ def test_decode(self):
+ affine_curve = self.secp128r1.curve.to_affine()
+ affine_point = self.secp128r1.generator.to_affine()
+ decoded = affine_curve.decode_point(bytes(affine_point))
+ self.assertEqual(decoded, affine_point)
+
+ affine_compressed_bytes = unhexlify("03161ff7528b899b2d0c28607ca52c5b86")
+ decoded_compressed = affine_curve.decode_point(affine_compressed_bytes)
+ self.assertEqual(decoded_compressed, affine_point)
+
diff --git a/test/ec/test_mod.py b/test/ec/test_mod.py
index 59b716e..59c8e24 100644
--- a/test/ec/test_mod.py
+++ b/test/ec/test_mod.py
@@ -1,6 +1,6 @@
from unittest import TestCase
-from pyecsca.ec.mod import Mod, gcd, extgcd, Undefined
+from pyecsca.ec.mod import Mod, gcd, extgcd, Undefined, miller_rabin
class ModTests(TestCase):
@@ -10,6 +10,22 @@ class ModTests(TestCase):
self.assertEqual(extgcd(15, 0), (1, 0, 15))
self.assertEqual(extgcd(15, 20), (-1, 1, 5))
+ def test_miller_rabin(self):
+ self.assertTrue(miller_rabin(2))
+ self.assertTrue(miller_rabin(3))
+ self.assertTrue(miller_rabin(5))
+ self.assertFalse(miller_rabin(8))
+ self.assertTrue(miller_rabin(0xe807561107ccf8fa82af74fd492543a918ca2e9c13750233a9))
+ self.assertFalse(miller_rabin(0x6f6889deb08da211927370810f026eb4c17b17755f72ea005))
+
+ def test_is_residue(self):
+ self.assertTrue(Mod(4, 11).is_residue())
+ self.assertFalse(Mod(11, 31).is_residue())
+
+ def test_sqrt(self):
+ p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
+ self.assertIn(Mod(0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc, p).sqrt(), (0x9add512515b70d9ec471151c1dec46625cd18b37bde7ca7fb2c8b31d7033599d, 0x6522aed9ea48f2623b8eeae3e213b99da32e74c9421835804d374ce28fcca662))
+
def test_wrong_mod(self):
a = Mod(5, 7)
b = Mod(4, 11)
diff --git a/test/sca/test_target.py b/test/sca/test_target.py
index 25d506a..5519502 100644
--- a/test/sca/test_target.py
+++ b/test/sca/test_target.py
@@ -1,12 +1,30 @@
-from unittest import TestCase
+from copy import copy
from os.path import realpath, dirname, join
+from typing import Optional
+from unittest import TestCase, SkipTest
+from pyecsca.ec.key_agreement import ECDH_SHA1
+from pyecsca.ec.key_generation import KeyGeneration
+from pyecsca.ec.mod import Mod
+from pyecsca.ec.mult import LTRMultiplier
+from pyecsca.ec.params import DomainParameters, get_params
+from pyecsca.ec.point import Point
+from pyecsca.ec.signature import SignatureResult, ECDSA_SHA1
+from pyecsca.sca.target import BinaryTarget, SimpleSerialTarget, SimpleSerialMessage, has_pyscard
+from pyecsca.sca.target.ectester import (KeyAgreementEnum, SignatureEnum, KeypairEnum, KeyBuildEnum,
+ KeyClassEnum, CurveEnum, ParameterEnum, RunModeEnum,
+ KeyEnum, TransformationEnum)
+
+if has_pyscard:
+ from pyecsca.sca.target.ectester import ECTesterTarget
+else:
+ ECTesterTarget = None
-from pyecsca.sca.target import BinaryTarget, SimpleSerialTarget, SimpleSerialMessage
class TestTarget(SimpleSerialTarget, BinaryTarget):
pass
+
class BinaryTargetTests(TestCase):
def test_basic_target(self):
@@ -17,4 +35,268 @@ class BinaryTargetTests(TestCase):
self.assertIn("r", resp)
self.assertIn("z", resp)
self.assertEqual(resp["r"].data, "01020304")
- target.disconnect() \ No newline at end of file
+ target.disconnect()
+
+
+class ECTesterTargetTests(TestCase):
+ reader: Optional[str] = None
+ target: Optional[ECTesterTarget] = None
+ secp256r1: DomainParameters
+ secp256r1_projective: DomainParameters
+
+ @classmethod
+ def setUpClass(cls):
+ if not has_pyscard:
+ return
+ from smartcard.System import readers
+ rs = readers()
+ if not rs:
+ return
+ cls.reader = rs[0]
+ cls.secp256r1 = get_params("secg", "secp256r1", "affine")
+ cls.secp256r1_projective = get_params("secg", "secp256r1", "projective")
+
+ def setUp(self):
+ if not ECTesterTargetTests.reader:
+ raise SkipTest("No smartcard readers.")
+ self.target = ECTesterTarget(ECTesterTargetTests.reader)
+ self.target.connect()
+ if not self.target.select_applet():
+ self.target.disconnect()
+ raise SkipTest("No applet in reader: {}".format(ECTesterTargetTests.reader))
+
+ def tearDown(self):
+ self.target.cleanup()
+ self.target.disconnect()
+
+ def test_allocate(self):
+ ka_resp = self.target.allocate_ka(KeyAgreementEnum.ALG_EC_SVDP_DH)
+ self.assertTrue(ka_resp.success)
+ sig_resp = self.target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
+ self.assertTrue(sig_resp.success)
+ key_resp = self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.assertTrue(key_resp.success)
+
+ def test_set(self):
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ set_resp = self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1,
+ ParameterEnum.DOMAIN_FP)
+ self.assertTrue(set_resp.success)
+
+ def test_set_explicit(self):
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ values = ECTesterTarget.encode_parameters(ParameterEnum.DOMAIN_FP, self.secp256r1)
+ set_resp = self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.external,
+ ParameterEnum.DOMAIN_FP, values)
+ self.assertTrue(set_resp.success)
+
+ def test_generate(self):
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP)
+ generate_resp = self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ self.assertTrue(generate_resp.success)
+
+ def test_clear(self):
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ clear_resp = self.target.clear(KeypairEnum.KEYPAIR_LOCAL)
+ self.assertTrue(clear_resp.success)
+
+ def test_cleanup(self):
+ cleanup_resp = self.target.cleanup()
+ self.assertTrue(cleanup_resp.success)
+
+ def test_info(self):
+ info_resp = self.target.info()
+ self.assertTrue(info_resp.success)
+
+ def test_dry_run(self):
+ dry_run_resp = self.target.run_mode(RunModeEnum.MODE_DRY_RUN)
+ self.assertTrue(dry_run_resp.success)
+ allocate_resp = self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.assertTrue(allocate_resp.success)
+ dry_run_resp = self.target.run_mode(RunModeEnum.MODE_NORMAL)
+ self.assertTrue(dry_run_resp.success)
+
+ def test_export(self):
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP)
+ self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ export_public_resp = self.target.export(KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC,
+ ParameterEnum.W)
+ self.assertTrue(export_public_resp.success)
+ pubkey_bytes = export_public_resp.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W)
+ pubkey = self.secp256r1.curve.decode_point(pubkey_bytes)
+ export_privkey_resp = self.target.export(KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE,
+ ParameterEnum.S)
+ self.assertTrue(export_privkey_resp.success)
+ privkey = int.from_bytes(
+ export_privkey_resp.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S), "big")
+ self.assertEqual(pubkey,
+ self.secp256r1.curve.affine_multiply(self.secp256r1.generator, privkey))
+
+ def test_export_curve(self):
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP)
+ export_resp = self.target.export(KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC,
+ ParameterEnum.DOMAIN_FP)
+ self.assertTrue(export_resp.success)
+
+ def test_transform(self):
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP)
+ self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ export_privkey_resp1 = self.target.export(KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE,
+ ParameterEnum.S)
+ privkey = int.from_bytes(
+ export_privkey_resp1.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S), "big")
+ transform_resp = self.target.transform(KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE,
+ ParameterEnum.S, TransformationEnum.INCREMENT)
+ self.assertTrue(transform_resp.success)
+ export_privkey_resp2 = self.target.export(KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE,
+ ParameterEnum.S)
+ privkey_new = int.from_bytes(
+ export_privkey_resp2.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S), "big")
+ self.assertEqual(privkey + 1, privkey_new)
+
+ def test_ecdh(self):
+ self.target.allocate_ka(KeyAgreementEnum.ALG_EC_SVDP_DH)
+ self.target.allocate(KeypairEnum.KEYPAIR_BOTH, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.target.set(KeypairEnum.KEYPAIR_BOTH, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP)
+ self.target.generate(KeypairEnum.KEYPAIR_BOTH)
+ ecdh_resp = self.target.ecdh(KeypairEnum.KEYPAIR_LOCAL, KeypairEnum.KEYPAIR_REMOTE, True,
+ TransformationEnum.NONE, KeyAgreementEnum.ALG_EC_SVDP_DH)
+ self.assertTrue(ecdh_resp.success)
+ export_public_resp = self.target.export(KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC,
+ ParameterEnum.W)
+ pubkey_bytes = export_public_resp.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W)
+ pubkey = self.secp256r1.curve.decode_point(pubkey_bytes)
+ export_privkey_resp = self.target.export(KeypairEnum.KEYPAIR_REMOTE, KeyEnum.PRIVATE,
+ ParameterEnum.S)
+ privkey = Mod(int.from_bytes(
+ export_privkey_resp.get_param(KeypairEnum.KEYPAIR_REMOTE, ParameterEnum.S), "big"),
+ self.secp256r1.curve.prime)
+ pubkey_projective = Point.from_affine(self.secp256r1_projective.curve.coordinate_model,
+ pubkey)
+ mult = LTRMultiplier(
+ self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ self.secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"])
+ ecdh = ECDH_SHA1(mult, self.secp256r1_projective, pubkey_projective, privkey)
+ expected = ecdh.perform()
+ self.assertEqual(ecdh_resp.secret, expected)
+
+ def test_ecdh_raw(self):
+ self.target.allocate_ka(KeyAgreementEnum.ALG_EC_SVDP_DH)
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP)
+ self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ mult = LTRMultiplier(
+ self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ self.secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"])
+ keygen = KeyGeneration(copy(mult), self.secp256r1_projective)
+ priv, pubkey_projective = keygen.generate()
+
+ ecdh_resp = self.target.ecdh_direct(KeypairEnum.KEYPAIR_LOCAL, True,
+ TransformationEnum.NONE,
+ KeyAgreementEnum.ALG_EC_SVDP_DH,
+ bytes(pubkey_projective.to_affine()))
+ self.assertTrue(ecdh_resp.success)
+ export_privkey_resp = self.target.export(KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE,
+ ParameterEnum.S)
+ privkey = Mod(int.from_bytes(
+ export_privkey_resp.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S), "big"),
+ self.secp256r1.curve.prime)
+
+ ecdh = ECDH_SHA1(copy(mult), self.secp256r1_projective, pubkey_projective, privkey)
+ expected = ecdh.perform()
+ self.assertEqual(ecdh_resp.secret, expected)
+
+ def test_ecdsa(self):
+ self.target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP)
+ self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ data = "Some text over here.".encode()
+ ecdsa_resp = self.target.ecdsa(KeypairEnum.KEYPAIR_LOCAL, True, SignatureEnum.ALG_ECDSA_SHA,
+ data)
+ self.assertTrue(ecdsa_resp.success)
+ export_public_resp = self.target.export(KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC,
+ ParameterEnum.W)
+ pubkey_bytes = export_public_resp.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W)
+ pubkey = self.secp256r1.curve.decode_point(pubkey_bytes)
+ pubkey_projective = Point.from_affine(self.secp256r1_projective.curve.coordinate_model,
+ pubkey)
+
+ sig = SignatureResult.from_DER(ecdsa_resp.signature)
+ mult = LTRMultiplier(
+ self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ self.secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"])
+ ecdsa = ECDSA_SHA1(copy(mult), self.secp256r1_projective,
+ self.secp256r1_projective.curve.coordinate_model.formulas[
+ "add-2016-rcb"],
+ pubkey_projective)
+ self.assertTrue(ecdsa.verify_data(sig, data))
+
+ def test_ecdsa_sign(self):
+ self.target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP)
+ self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ data = "Some text over here.".encode()
+ ecdsa_resp = self.target.ecdsa_sign(KeypairEnum.KEYPAIR_LOCAL, True,
+ SignatureEnum.ALG_ECDSA_SHA, data)
+ self.assertTrue(ecdsa_resp.success)
+ export_public_resp = self.target.export(KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC,
+ ParameterEnum.W)
+ pubkey_bytes = export_public_resp.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W)
+ pubkey = self.secp256r1.curve.decode_point(pubkey_bytes)
+ pubkey_projective = Point.from_affine(self.secp256r1_projective.curve.coordinate_model,
+ pubkey)
+
+ sig = SignatureResult.from_DER(ecdsa_resp.signature)
+ mult = LTRMultiplier(
+ self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ self.secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"])
+ ecdsa = ECDSA_SHA1(copy(mult), self.secp256r1_projective,
+ self.secp256r1_projective.curve.coordinate_model.formulas[
+ "add-2016-rcb"],
+ pubkey_projective)
+ self.assertTrue(ecdsa.verify_data(sig, data))
+
+ def test_ecdsa_verify(self):
+ self.target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
+ self.target.allocate(KeypairEnum.KEYPAIR_LOCAL, KeyBuildEnum.BUILD_KEYPAIR, 256,
+ KeyClassEnum.ALG_EC_FP)
+ self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP)
+ mult = LTRMultiplier(
+ self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ self.secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"])
+ keygen = KeyGeneration(copy(mult), self.secp256r1_projective)
+ priv, pubkey_projective = keygen.generate()
+ self.target.set(KeypairEnum.KEYPAIR_LOCAL, CurveEnum.external, ParameterEnum.W,
+ ECTesterTarget.encode_parameters(ParameterEnum.W,
+ pubkey_projective.to_affine()))
+ ecdsa = ECDSA_SHA1(copy(mult), self.secp256r1_projective,
+ self.secp256r1_projective.curve.coordinate_model.formulas[
+ "add-2016-rcb"],
+ pubkey_projective,
+ priv)
+ data = "Some text over here.".encode()
+ sig = ecdsa.sign_data(data)
+
+ ecdsa_resp = self.target.ecdsa_verify(KeypairEnum.KEYPAIR_LOCAL,
+ SignatureEnum.ALG_ECDSA_SHA, sig.to_DER(), data)
+ self.assertTrue(ecdsa_resp.success)