From 18bfe2cdac09ff9faed5c92971a7e63d56570ac2 Mon Sep 17 00:00:00 2001
From: J08nY
Date: Sun, 4 Feb 2018 18:03:54 +0100
Subject: Add more tests to the Wrong test suite.
- Now tests also for:
- Fp:
- p = 0
- p = 1
- p = q^2; q prime
- p = q * s; q and s primes
- F2m:
- e1 = e2 = e3 = 0
- m < e1 < e2 < e3
---
src/cz/crcs/ectester/common/util/ByteUtil.java | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
(limited to 'src/cz/crcs/ectester/common/util/ByteUtil.java')
diff --git a/src/cz/crcs/ectester/common/util/ByteUtil.java b/src/cz/crcs/ectester/common/util/ByteUtil.java
index 90c6eaa..ad9f1bf 100644
--- a/src/cz/crcs/ectester/common/util/ByteUtil.java
+++ b/src/cz/crcs/ectester/common/util/ByteUtil.java
@@ -39,6 +39,23 @@ public class ByteUtil {
return true;
}
+ public static byte[] shortToBytes(short value) {
+ byte[] result = new byte[2];
+ setShort(result, 0, value);
+ return result;
+ }
+
+ public static byte[] shortToBytes(short[] shorts) {
+ if (shorts == null) {
+ return null;
+ }
+ byte[] result = new byte[shorts.length * 2];
+ for (int i = 0; i < shorts.length; ++i) {
+ setShort(result, 2 * i, shorts[i]);
+ }
+ return result;
+ }
+
public static byte[] hexToBytes(String hex) {
return hexToBytes(hex, true);
}
--
cgit v1.2.3-70-g09d2
From 30210ec562a49d1b397a19d8c64ed0e0fd80cc0e Mon Sep 17 00:00:00 2001
From: J08nY
Date: Sat, 3 Mar 2018 19:13:04 +0100
Subject: Add some docs and fix ECTesterReader --bit-size option.
---
src/cz/crcs/ectester/applet/ECTesterApplet.java | 1 -
.../ectester/common/output/BaseTextTestWriter.java | 15 +++++++++++
src/cz/crcs/ectester/common/output/TestWriter.java | 8 +++++-
src/cz/crcs/ectester/common/test/TestSuite.java | 2 +-
src/cz/crcs/ectester/common/util/ByteUtil.java | 30 ++++++++++++++++++++++
src/cz/crcs/ectester/reader/ECTesterReader.java | 8 +++---
6 files changed, 57 insertions(+), 7 deletions(-)
(limited to 'src/cz/crcs/ectester/common/util/ByteUtil.java')
diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java
index 9689a51..5c87105 100644
--- a/src/cz/crcs/ectester/applet/ECTesterApplet.java
+++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java
@@ -582,7 +582,6 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PUBLIC, params, outBuffer, outOffset);
sw = keyGenerator.getSW();
}
- //TODO unify this, now that param key == the passed on param.
if ((key & EC_Consts.KEY_PRIVATE) != 0 && sw == ISO7816.SW_NO_ERROR) {
//export params from private
length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PRIVATE, params, outBuffer, (short) (outOffset + length));
diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
index f29d28e..4315201 100644
--- a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
+++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
@@ -5,6 +5,11 @@ import cz.crcs.ectester.common.test.*;
import java.io.PrintStream;
/**
+ * An absctract basis of a TextTestWriter, which outputs in a human readable format, into console.
+ * Requires the implementation of:
+ * String testableString(Testable t)
+ * String deviceString(TestSuite t)
+ *
* @author Jan Jancar johny@neuromancer.sk
*/
public abstract class BaseTextTestWriter implements TestWriter {
@@ -23,8 +28,18 @@ public abstract class BaseTextTestWriter implements TestWriter {
output.print(deviceString(suite));
}
+ /**
+ *
+ * @param t
+ * @return
+ */
protected abstract String testableString(Testable t);
+ /**
+ *
+ * @param suite
+ * @return
+ */
protected abstract String deviceString(TestSuite suite);
private String testString(Test t, String prefix) {
diff --git a/src/cz/crcs/ectester/common/output/TestWriter.java b/src/cz/crcs/ectester/common/output/TestWriter.java
index 5fa7f67..7de23a5 100644
--- a/src/cz/crcs/ectester/common/output/TestWriter.java
+++ b/src/cz/crcs/ectester/common/output/TestWriter.java
@@ -8,7 +8,13 @@ import cz.crcs.ectester.common.test.TestSuite;
*/
public interface TestWriter {
/**
- * @param suite
+ * Begin writing the TestSuite suite.
+ * This should reset all the internal state of the writer
+ * and prepare it to output tests from suite.
+ * It may also write any header part of the output of the
+ * writer but doesn't have to.
+ *
+ * @param suite The TestSuite to start writing.
*/
void begin(TestSuite suite);
diff --git a/src/cz/crcs/ectester/common/test/TestSuite.java b/src/cz/crcs/ectester/common/test/TestSuite.java
index ca1b199..7883633 100644
--- a/src/cz/crcs/ectester/common/test/TestSuite.java
+++ b/src/cz/crcs/ectester/common/test/TestSuite.java
@@ -18,7 +18,7 @@ public abstract class TestSuite {
}
/**
- *
+ * Run the TestSuite.
*/
public void run() {
writer.begin(this);
diff --git a/src/cz/crcs/ectester/common/util/ByteUtil.java b/src/cz/crcs/ectester/common/util/ByteUtil.java
index ad9f1bf..0de8dc7 100644
--- a/src/cz/crcs/ectester/common/util/ByteUtil.java
+++ b/src/cz/crcs/ectester/common/util/ByteUtil.java
@@ -7,15 +7,27 @@ package cz.crcs.ectester.common.util;
* @author Jan Jancar johny@neuromancer.sk
*/
public class ByteUtil {
+
+ /**
+ * Gen a short from a byte array at offset, big-endian.
+ * @return the short value
+ */
public static short getShort(byte[] array, int offset) {
return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF));
}
+ /**
+ * Set a short in a byte array at offset, big-endian.
+ */
public static void setShort(byte[] array, int offset, short value) {
array[offset + 1] = (byte) (value & 0xFF);
array[offset] = (byte) ((value >> 8) & 0xFF);
}
+ /**
+ * Compare two byte arrays upto length and get first difference.
+ * @return the position of the first difference in the two byte arrays, or length if they are equal.
+ */
public static int diffBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) {
for (int i = 0; i < length; ++i) {
byte a = one[i + oneOffset];
@@ -27,10 +39,17 @@ public class ByteUtil {
return length;
}
+ /**
+ * Compare two byte arrays, upto length.
+ * @return whether the arrays are equal upto length
+ */
public static boolean compareBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) {
return diffBytes(one, oneOffset, other, otherOffset, length) == length;
}
+ /**
+ * Test if the byte array has all values equal to value.
+ */
public static boolean allValue(byte[] array, byte value) {
for (byte a : array) {
if (a != value)
@@ -56,10 +75,21 @@ public class ByteUtil {
return result;
}
+ /**
+ * Parse a hex string into a byte array, big-endian.
+ * @param hex The String to parse.
+ * @return the byte array from the hex string.
+ */
public static byte[] hexToBytes(String hex) {
return hexToBytes(hex, true);
}
+ /**
+ * Parse a hex string into a byte-array, specify endianity.
+ * @param hex The String to parse.
+ * @param bigEndian Whether to parse as big-endian.
+ * @return the byte array from the hex string.
+ */
public static byte[] hexToBytes(String hex, boolean bigEndian) {
hex = hex.replace(" ", "");
int len = hex.length();
diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java
index ef2d235..9c80bd2 100644
--- a/src/cz/crcs/ectester/reader/ECTesterReader.java
+++ b/src/cz/crcs/ectester/reader/ECTesterReader.java
@@ -726,7 +726,7 @@ public class ECTesterReader {
System.err.println("You have to specify an output file for curve parameter export.");
return false;
}
- if (all) {
+ if (all || bits == 0) {
System.err.println("You have to specify curve bit-size with -b");
return false;
}
@@ -743,7 +743,7 @@ public class ECTesterReader {
System.err.println("You have to specify an output file for the key generation process.");
return false;
}
- if (all) {
+ if (all || bits == 0) {
System.err.println("You have to specify curve bit-size with -b");
return false;
}
@@ -770,7 +770,7 @@ public class ECTesterReader {
System.err.print("Need to specify field with -fp or -f2m. (not both)");
return false;
}
- if (all) {
+ if (all || bits == 0) {
System.err.println("You have to specify curve bit-size with -b");
return false;
}
@@ -787,7 +787,7 @@ public class ECTesterReader {
System.err.print("Need to specify field with -fp or -f2m. (but not both)");
return false;
}
- if (all) {
+ if (all || bits == 0) {
System.err.println("You have to specify curve bit-size with -b");
return false;
}
--
cgit v1.2.3-70-g09d2
From 87c4accbecc2f37a42c96e2bbc3c90618bfa2fdc Mon Sep 17 00:00:00 2001
From: J08nY
Date: Wed, 2 May 2018 20:08:49 +0200
Subject: Add compression test suite.
---
.gitignore | 3 +
src/cz/crcs/ectester/applet/EC_Consts.java | 11 +-
src/cz/crcs/ectester/common/ec/EC_Curve.java | 8 +-
src/cz/crcs/ectester/common/test/TestSuite.java | 4 +-
src/cz/crcs/ectester/common/util/ByteUtil.java | 4 +
src/cz/crcs/ectester/common/util/CardUtil.java | 2 +
src/cz/crcs/ectester/reader/ECTesterReader.java | 7 +-
.../ectester/reader/test/CardCofactorSuite.java | 73 +++++++++++++
.../reader/test/CardCofactorTestSuite.java | 73 -------------
.../ectester/reader/test/CardCompressionSuite.java | 119 +++++++++++++++++++++
.../ectester/reader/test/CardDefaultSuite.java | 18 +++-
.../crcs/ectester/reader/test/PerformanceTest.java | 23 +++-
12 files changed, 255 insertions(+), 90 deletions(-)
create mode 100644 src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
delete mode 100644 src/cz/crcs/ectester/reader/test/CardCofactorTestSuite.java
create mode 100644 src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
(limited to 'src/cz/crcs/ectester/common/util/ByteUtil.java')
diff --git a/.gitignore b/.gitignore
index f03ac1b..aecbbec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,11 +11,14 @@
# Test runs in /dist
/dist/*.default
/dist/*.test-vectors
+/dist/*.compression
/dist/*.cofactor
/dist/*.composite
/dist/*.wrong
/dist/*.invalid
/dist/*.twist
+/dist/*.degenerate
+/dist/*.xml
# Built binaries in /src.
/src/**/*.a
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 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 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/CardCofactorSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
new file mode 100644
index 0000000..aca3371
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
@@ -0,0 +1,73 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import static cz.crcs.ectester.common.test.Result.ExpectedValue;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+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.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ Map pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "cofactor");
+ List>> curveList = EC_Store.mapToCurve(pubkeys.values());
+ for (Map.Entry> e : curveList) {
+ EC_Curve curve = e.getKey();
+ List keys = e.getValue();
+
+ Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS);
+ Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS);
+ Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS);
+
+ Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId(), allocate, set, generate);
+
+ List ecdhTests = new LinkedList<>();
+ for (EC_Key.Public pub : keys) {
+ Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
+ ecdhTests.add(CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on non-generator subgroup.", "Card incorrectly accepted point on non-generator subgroup."));
+ }
+ Test ecdh = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH with public points on non-generator subgroup", ecdhTests.toArray(new Test[0]));
+
+ Random r = new Random();
+ byte[] raw = new byte[128];
+ byte[] sig = new byte[40];
+ r.nextBytes(raw);
+ r.nextBytes(sig);
+
+ List ecdsaTests = new LinkedList<>();
+ for (EC_Key.Public pub : keys) {
+ Command setCommand = new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten());
+ Test setTest = CommandTest.expect(setCommand, ExpectedValue.ANY);
+ Command ecdsaCommand = new Command.ECDSA_verify(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.Signature_ALG_ECDSA_SHA, raw, sig);
+ Test ecdsaTest = CommandTest.expect(ecdsaCommand, ExpectedValue.FAILURE);
+ ecdsaTests.add(CompoundTest.all(ExpectedValue.SUCCESS, "Verify random ECDSA signature by " + pub.getId(), setTest, ecdsaTest));
+ }
+ Test ecdsa = CompoundTest.all(ExpectedValue.SUCCESS, "Verify random ECDSA signature by public points on non-generator subgroup.", ecdsaTests.toArray(new Test[0]));
+
+ Test tests = CompoundTest.all(ExpectedValue.SUCCESS, ecdh, ecdsa);
+
+ doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId(), prepare, tests));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardCofactorTestSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorTestSuite.java
deleted file mode 100644
index 8cf59e2..0000000
--- a/src/cz/crcs/ectester/reader/test/CardCofactorTestSuite.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Key;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-
-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) {
- 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.");
- }
-
- @Override
- protected void runTests() throws Exception {
- Map pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "cofactor");
- List>> curveList = EC_Store.mapToCurve(pubkeys.values());
- for (Map.Entry> e : curveList) {
- EC_Curve curve = e.getKey();
- List keys = e.getValue();
-
- Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS);
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS);
-
- Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId(), allocate, set, generate);
-
- List ecdhTests = new LinkedList<>();
- for (EC_Key.Public pub : keys) {
- Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
- ecdhTests.add(CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on non-generator subgroup.", "Card incorrectly accepted point on non-generator subgroup."));
- }
- Test ecdh = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH with public points on non-generator subgroup", ecdhTests.toArray(new Test[0]));
-
- Random r = new Random();
- byte[] raw = new byte[128];
- byte[] sig = new byte[40];
- r.nextBytes(raw);
- r.nextBytes(sig);
-
- List ecdsaTests = new LinkedList<>();
- for (EC_Key.Public pub : keys) {
- Command setCommand = new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten());
- Test setTest = CommandTest.expect(setCommand, ExpectedValue.ANY);
- Command ecdsaCommand = new Command.ECDSA_verify(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.Signature_ALG_ECDSA_SHA, raw, sig);
- Test ecdsaTest = CommandTest.expect(ecdsaCommand, ExpectedValue.FAILURE);
- ecdsaTests.add(CompoundTest.all(ExpectedValue.SUCCESS, "Verify random ECDSA signature by " + pub.getId(), setTest, ecdsaTest));
- }
- Test ecdsa = CompoundTest.all(ExpectedValue.SUCCESS, "Verify random ECDSA signature by public points on non-generator subgroup.", ecdsaTests.toArray(new Test[0]));
-
- Test tests = CompoundTest.all(ExpectedValue.SUCCESS, ecdh, ecdsa);
-
- doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId(), prepare, tests));
- new Command.Cleanup(this.card).send();
- }
- }
-}
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 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 kaTests = new LinkedList<>();
+ for (byte kaType : EC_Consts.KA_TYPES) {
+ List 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 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 {
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() {
@Override
public Result apply(CommandTestable testable) {
@@ -26,23 +29,31 @@ public class PerformanceTest extends SimpleTest {
}
});
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 {
return testable.getCommand();
}
+ public Response[] getResponses() {
+ return responses;
+ }
+
public long[] getTimes() {
return times;
}
--
cgit v1.2.3-70-g09d2