aboutsummaryrefslogtreecommitdiff
path: root/test/sca
diff options
context:
space:
mode:
authorJ08nY2020-06-13 01:59:22 +0200
committerJ08nY2020-06-13 01:59:22 +0200
commit4e17dfdb12707c814add7851c81eda4edb3dacde (patch)
tree1f59c7adad2cc58e3a53d995b029c5a76f591411 /test/sca
parent23b3638a496637c1810fb5a2bd610b63b1a72521 (diff)
downloadpyecsca-4e17dfdb12707c814add7851c81eda4edb3dacde.tar.gz
pyecsca-4e17dfdb12707c814add7851c81eda4edb3dacde.tar.zst
pyecsca-4e17dfdb12707c814add7851c81eda4edb3dacde.zip
Diffstat (limited to 'test/sca')
-rw-r--r--test/sca/test_target.py288
1 files changed, 285 insertions, 3 deletions
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)