diff options
| author | J08nY | 2018-05-02 20:08:49 +0200 |
|---|---|---|
| committer | J08nY | 2018-05-02 20:08:49 +0200 |
| commit | 87c4accbecc2f37a42c96e2bbc3c90618bfa2fdc (patch) | |
| tree | f24d78af5e7a14e1a322a2b3978b0204bb0e5ec3 /src | |
| parent | 92c28a15e018e55b8f195993414f769ecf96a663 (diff) | |
| download | ECTester-87c4accbecc2f37a42c96e2bbc3c90618bfa2fdc.tar.gz ECTester-87c4accbecc2f37a42c96e2bbc3c90618bfa2fdc.tar.zst ECTester-87c4accbecc2f37a42c96e2bbc3c90618bfa2fdc.zip | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/cz/crcs/ectester/applet/EC_Consts.java | 11 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/common/ec/EC_Curve.java | 8 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/common/test/TestSuite.java | 4 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/common/util/ByteUtil.java | 4 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/common/util/CardUtil.java | 2 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/ECTesterReader.java | 7 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/test/CardCofactorSuite.java (renamed from src/cz/crcs/ectester/reader/test/CardCofactorTestSuite.java) | 4 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/test/CardCompressionSuite.java | 119 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/test/CardDefaultSuite.java | 18 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/test/PerformanceTest.java | 23 |
10 files changed, 181 insertions, 19 deletions
diff --git a/src/cz/crcs/ectester/applet/EC_Consts.java b/src/cz/crcs/ectester/applet/EC_Consts.java index 88a8bd6..c24283a 100644 --- a/src/cz/crcs/ectester/applet/EC_Consts.java +++ b/src/cz/crcs/ectester/applet/EC_Consts.java @@ -994,6 +994,7 @@ public class EC_Consts { public static final short TRANSFORMATION_INCREMENT = (short) 0x40; public static final short TRANSFORMATION_INFINITY = (short) 0x80; public static final short TRANSFORMATION_COMPRESS = (short) 0x0100; + public static final short TRANSFORMATION_COMPRESS_HYBRID = (short) 0x0200; // toX962 FORM types public static final byte X962_UNCOMPRESSED = (byte) 0x00; @@ -1386,6 +1387,7 @@ public class EC_Consts { Util.arrayFillNonAtomic(buffer, offset, length, (byte) 0); length = 1; break; + case TRANSFORMATION_COMPRESS_HYBRID: case TRANSFORMATION_COMPRESS: if ((short) (length % 2) != 1) { // an uncompressed point should have odd length (since 1 byte type, + 2 * coords) @@ -1400,9 +1402,12 @@ public class EC_Consts { buffer[offset] = 2; } - length = (short) (half + 1); + if (transformationPart == TRANSFORMATION_COMPRESS) { + length = (short) (half + 1); + } else { + buffer[offset] += 4; + } break; - //TODO: test hybrid form with not corresponding yBit (in first byte value) and y_value in the second half of the param default: ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); } @@ -1427,7 +1432,7 @@ public class EC_Consts { break; case X962_HYBRID: outputBuffer[offset] = 4; - case X962_COMPRESSED: + case X962_COMPRESSED: /* fallthrough */ byte yLSB = yBuffer[(short) (yOffset + yLength)]; byte yBit = (byte) (yLSB & 0x01); diff --git a/src/cz/crcs/ectester/common/ec/EC_Curve.java b/src/cz/crcs/ectester/common/ec/EC_Curve.java index 173fd29..8338a93 100644 --- a/src/cz/crcs/ectester/common/ec/EC_Curve.java +++ b/src/cz/crcs/ectester/common/ec/EC_Curve.java @@ -54,7 +54,7 @@ public class EC_Curve extends EC_Params { return "<" + getId() + "> " + (field == KeyPair.ALG_EC_FP ? "Prime" : "Binary") + " field Elliptic curve (" + String.valueOf(bits) + "b)" + (desc == null ? "" : ": " + desc); } - public ECParameterSpec toSpec() { + public EllipticCurve toCurve() { ECField field; if (this.field == KeyPair.ALG_EC_FP) { field = new ECFieldFp(new BigInteger(1, getData(0))); @@ -71,7 +71,11 @@ public class EC_Curve extends EC_Params { BigInteger a = new BigInteger(1, getParam(EC_Consts.PARAMETER_A)[0]); BigInteger b = new BigInteger(1, getParam(EC_Consts.PARAMETER_B)[0]); - EllipticCurve curve = new EllipticCurve(field, a, b); + return new EllipticCurve(field, a, b); + } + + public ECParameterSpec toSpec() { + EllipticCurve curve = toCurve(); byte[][] G = getParam(EC_Consts.PARAMETER_G); BigInteger gx = new BigInteger(1, G[0]); diff --git a/src/cz/crcs/ectester/common/test/TestSuite.java b/src/cz/crcs/ectester/common/test/TestSuite.java index 3b3cd4b..9e08891 100644 --- a/src/cz/crcs/ectester/common/test/TestSuite.java +++ b/src/cz/crcs/ectester/common/test/TestSuite.java @@ -40,7 +40,7 @@ public abstract class TestSuite { * @return The test that was run. * @throws TestException */ - protected Test runTest(Test t) { + protected <T extends Test> T runTest(T t) { running = t; t.run(); running = null; @@ -54,7 +54,7 @@ public abstract class TestSuite { * @return The test that was run. * @throws TestException */ - protected Test doTest(Test t) { + protected <T extends Test> T doTest(T t) { runTest(t); writer.outputTest(t); return t; diff --git a/src/cz/crcs/ectester/common/util/ByteUtil.java b/src/cz/crcs/ectester/common/util/ByteUtil.java index 0de8dc7..daacabb 100644 --- a/src/cz/crcs/ectester/common/util/ByteUtil.java +++ b/src/cz/crcs/ectester/common/util/ByteUtil.java @@ -172,4 +172,8 @@ public class ByteUtil { } return out; } + + public static byte[] prependLength(byte[] data) { + return concatenate(ByteUtil.shortToBytes((short) data.length), data); + } } diff --git a/src/cz/crcs/ectester/common/util/CardUtil.java b/src/cz/crcs/ectester/common/util/CardUtil.java index 2501e47..85a4a35 100644 --- a/src/cz/crcs/ectester/common/util/CardUtil.java +++ b/src/cz/crcs/ectester/common/util/CardUtil.java @@ -197,6 +197,8 @@ public class CardUtil { return "INFINITY"; case EC_Consts.TRANSFORMATION_COMPRESS: return "COMPRESSED"; + case EC_Consts.TRANSFORMATION_COMPRESS_HYBRID: + return "HYBRID"; case EC_Consts.TRANSFORMATION_MAX: return "MAX"; default: diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 0a3031b..6098cd4 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -406,6 +406,9 @@ public class ECTesterReader { case "test-vectors": suite = new CardTestVectorSuite(writer, cfg, cardManager); break; + case "compression": + suite = new CardCompressionSuite(writer, cfg, cardManager); + break; default: // These run are dangerous, prompt before them. System.out.println("The test you selected (" + cfg.testSuite + ") is potentially dangerous."); @@ -436,7 +439,7 @@ public class ECTesterReader { suite = new CardTwistTestSuite(writer, cfg, cardManager); break; case "cofactor": - suite = new CardCofactorTestSuite(writer, cfg, cardManager); + suite = new CardCofactorSuite(writer, cfg, cardManager); break; default: System.err.println("Unknown test suite."); @@ -767,7 +770,7 @@ public class ECTesterReader { } testSuite = cli.getOptionValue("test", "default").toLowerCase(); - String[] tests = new String[]{"default", "composite", "invalid", "degenerate", "test-vectors", "wrong", "twist", "cofactor"}; + String[] tests = new String[]{"default", "composite", "compression", "invalid", "degenerate", "test-vectors", "wrong", "twist", "cofactor"}; if (!Arrays.asList(tests).contains(testSuite)) { System.err.println("Unknown test suite " + testSuite + ". Should be one of: " + Arrays.toString(tests)); return false; diff --git a/src/cz/crcs/ectester/reader/test/CardCofactorTestSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java index 8cf59e2..aca3371 100644 --- a/src/cz/crcs/ectester/reader/test/CardCofactorTestSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java @@ -22,8 +22,8 @@ import static cz.crcs.ectester.common.test.Result.ExpectedValue; /** * @author Jan Jancar johny@neuromancer.sk */ -public class CardCofactorTestSuite extends CardTestSuite { - public CardCofactorTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { +public class CardCofactorSuite extends CardTestSuite { + public CardCofactorSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { super(writer, cfg, cardManager, "cofactor", "The cofactor test suite tests whether the card correctly rejects points on the curve but not in the subgroup generated by the generator during ECDH."); } diff --git a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java new file mode 100644 index 0000000..7300653 --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java @@ -0,0 +1,119 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.CompoundTest; +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.common.util.CardUtil; +import cz.crcs.ectester.common.util.ECUtil; +import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.ECTesterReader; +import cz.crcs.ectester.reader.command.Command; +import cz.crcs.ectester.reader.response.Response; +import javacard.security.KeyPair; + +import java.security.spec.ECPoint; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CardCompressionSuite extends CardTestSuite { + public CardCompressionSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { + super(writer, cfg, cardManager, "compression", ""); + } + + @Override + protected void runTests() throws Exception { + //iterate over default curve sizes + // for Fp + // - allocate, set custom curve, generate keypairs, -> export generated. + // - test ecdh with local and remote simply(no compression) + // - test local privkey, remote pubkey (compressed) + // - test local privkey, remote pubkey (hybrid) + // - test local privkey, remote pubkey (hybrid with wrong y) + // - test local privkey, remote pubkey (point at infinity) + if (cfg.primeField) { + runCompression(KeyPair.ALG_EC_FP); + } + // for F2m + // - allocate, set custom curve, generate keypairs, -> export generated. + // - test ecdh with local and remote simply(no compression) + // - test local privkey, remote pubkey (compressed) + // - test local privkey, remote pubkey (hybrid) + // - test local privkey, remote pubkey (hybrid with wrong y) + // - test local privkey, remote pubkey (point at infinity) + if (cfg.binaryField) { + runCompression(KeyPair.ALG_EC_F2M); + } + } + + private void runCompression(byte field) throws Exception { + short[] keySizes = field == KeyPair.ALG_EC_FP ? EC_Consts.FP_SIZES : EC_Consts.F2M_SIZES; + short domain = field == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; + + for (short keyLength : keySizes) { + String spec = keyLength + "b " + CardUtil.getKeyTypeString(field); + + Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, field), Result.ExpectedValue.SUCCESS)); + if (!allocateFirst.ok()) { + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + spec + ".", allocateFirst)); + continue; + } + + List<Test> compressionTests = new LinkedList<>(); + compressionTests.add(allocateFirst); + Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.getCurve(keyLength, field), domain, null), Result.ExpectedValue.SUCCESS)); + Test genCustom = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS)); + compressionTests.add(setCustom); + compressionTests.add(genCustom); + + Response.Export key = new Command.Export(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W).send(); + byte[] pubkey = key.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC); + ECPoint pub; + try { + pub = ECUtil.fromX962(pubkey, null); + } catch (IllegalArgumentException iae) { + // TODO: use external SECG curves so we have them here. + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "", compressionTests.toArray(new Test[0]))); + continue; + } + + List<Test> kaTests = new LinkedList<>(); + for (byte kaType : EC_Consts.KA_TYPES) { + List<Test> thisTests = new LinkedList<>(); + Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), Result.ExpectedValue.SUCCESS)); + if (allocate.ok()) { + Test ka = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType), Result.ExpectedValue.SUCCESS)); + + thisTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement setup and basic test.", allocate, ka)); + if (ka.ok()) { + // tests of the good stuff + Test kaCompressed = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS, kaType), Result.ExpectedValue.SUCCESS); + Test kaHybrid = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS_HYBRID, kaType), Result.ExpectedValue.SUCCESS); + thisTests.add(CompoundTest.any(Result.ExpectedValue.SUCCESS, "Tests of compressed and hybrid form.", kaCompressed, kaHybrid)); + + // tests the bad stuff here + byte[] pubHybrid = ECUtil.toX962Hybrid(pub, keyLength); + pubHybrid[pubHybrid.length - 1] ^= 1; + byte[] pubHybridEncoded = ByteUtil.prependLength(pubHybrid); + Test kaBadHybrid = CommandTest.expect(new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType, pubHybridEncoded), Result.ExpectedValue.FAILURE); + + byte[] pubInfinityEncoded = {0x01, 0x00}; + Test kaBadInfinity = CommandTest.expect(new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType, pubInfinityEncoded), Result.ExpectedValue.FAILURE); + thisTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of corrupted hybrid form and infinity.", kaBadHybrid, kaBadInfinity)); + } + kaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement tests of " + CardUtil.getKATypeString(kaType) + ".", thisTests.toArray(new Test[0]))); + } + } + compressionTests.addAll(kaTests); + + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Compression test of " + spec + ".", compressionTests.toArray(new Test[0]))); + new Command.Cleanup(this.card).send(); + } + } +} diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java index 611f5ec..4480962 100644 --- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java @@ -14,9 +14,11 @@ import javacard.security.KeyPair; import java.util.LinkedList; import java.util.List; +import java.util.Random; import java.util.function.Function; import static cz.crcs.ectester.common.test.Result.ExpectedValue; +import static cz.crcs.ectester.common.test.Result.Value; /** * @author Jan Jancar johny@neuromancer.sk @@ -70,9 +72,9 @@ public class CardDefaultSuite extends CardTestSuite { String kaDesc = "Test of the " + CardUtil.getKATypeString(kaType) + " KeyAgreement."; Function<Test[], Result> kaCallback = (tests) -> { if (tests[1].ok() || tests[2].ok()) { - return new Result(Result.Value.SUCCESS, "Some ECDH is supported."); + return new Result(Value.SUCCESS, "Some ECDH is supported."); } else { - return new Result(Result.Value.FAILURE, "ECDH failed."); + return new Result(Value.FAILURE, "ECDH failed."); } }; @@ -102,10 +104,18 @@ public class CardDefaultSuite extends CardTestSuite { String signDesc = "Test of the " + CardUtil.getSigTypeString(sigType) + " signature."; + Random rand = new Random(); + byte[] sigData = new byte[64]; + rand.nextBytes(sigData); + Test compound; if (expect.ok()) { - Test perfTest = runTest(PerformanceTest.repeat(ecdsa, 10)); - compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect, perfTest)); + Command ecdsaSign = new Command.ECDSA_sign(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, ECTesterApplet.EXPORT_TRUE, sigData); + PerformanceTest signTest = runTest(PerformanceTest.repeat("Sign", ecdsaSign, 10)); + byte[] signature = signTest.getResponses()[0].getParam(0); + Command ecdsaVerify = new Command.ECDSA_verify(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, sigData, signature); + PerformanceTest verifyTest = runTest(PerformanceTest.repeat("Verify", ecdsaVerify, 10)); + compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect, signTest, verifyTest)); } else { compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect)); } diff --git a/src/cz/crcs/ectester/reader/test/PerformanceTest.java b/src/cz/crcs/ectester/reader/test/PerformanceTest.java index 2e5f376..9abaadc 100644 --- a/src/cz/crcs/ectester/reader/test/PerformanceTest.java +++ b/src/cz/crcs/ectester/reader/test/PerformanceTest.java @@ -5,6 +5,7 @@ import cz.crcs.ectester.common.test.SimpleTest; import cz.crcs.ectester.common.test.TestCallback; import cz.crcs.ectester.common.test.TestException; import cz.crcs.ectester.reader.command.Command; +import cz.crcs.ectester.reader.response.Response; import java.util.Arrays; @@ -13,12 +14,14 @@ import java.util.Arrays; */ public class PerformanceTest extends SimpleTest<CommandTestable> { private long[] times; + private Response[] responses; private long mean; private long median; private long mode; private int count; + private String desc; - private PerformanceTest(CommandTestable testable, int count) { + private PerformanceTest(CommandTestable testable, int count, String desc) { super(testable, new TestCallback<CommandTestable>() { @Override public Result apply(CommandTestable testable) { @@ -26,23 +29,31 @@ public class PerformanceTest extends SimpleTest<CommandTestable> { } }); this.count = count; + this.desc = desc; } public static PerformanceTest repeat(Command cmd, int count) { - return new PerformanceTest(new CommandTestable(cmd), count); + return new PerformanceTest(new CommandTestable(cmd), count, null); + } + + public static PerformanceTest repeat(String desc, Command cmd, int count) { + return new PerformanceTest(new CommandTestable(cmd), count, desc); } @Override public String getDescription() { - return String.format("Mean = %d ns, Median = %d ns, Mode = %d ns", mean, median, mode); + String rest = String.format("Mean = %d ns, Median = %d ns, Mode = %d ns", mean, median, mode); + return (desc == null ? rest : desc + " (" + rest + ")"); } @Override protected void runSelf() { times = new long[count]; + responses = new Response[count]; for (int i = 0; i < count; ++i) { testable.run(); - times[i] = testable.getResponse().getDuration(); + responses[i] = testable.getResponse(); + times[i] = responses[i].getDuration(); testable.reset(); } @@ -81,6 +92,10 @@ public class PerformanceTest extends SimpleTest<CommandTestable> { return testable.getCommand(); } + public Response[] getResponses() { + return responses; + } + public long[] getTimes() { return times; } |
