aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2018-02-04 18:03:54 +0100
committerJ08nY2018-02-04 18:03:54 +0100
commit18bfe2cdac09ff9faed5c92971a7e63d56570ac2 (patch)
treef356373dafd95a04c72de9e222280db2796b7ab1
parentd940ed695fc36d2782d27c50e398fc185cf6fed3 (diff)
downloadECTester-18bfe2cdac09ff9faed5c92971a7e63d56570ac2.tar.gz
ECTester-18bfe2cdac09ff9faed5c92971a7e63d56570ac2.tar.zst
ECTester-18bfe2cdac09ff9faed5c92971a7e63d56570ac2.zip
-rw-r--r--src/cz/crcs/ectester/applet/ECKeyGenerator.java4
-rw-r--r--src/cz/crcs/ectester/applet/ECTesterApplet.java6
-rw-r--r--src/cz/crcs/ectester/common/test/CompoundTest.java2
-rw-r--r--src/cz/crcs/ectester/common/test/TestSuite.java12
-rw-r--r--src/cz/crcs/ectester/common/util/ByteUtil.java17
-rw-r--r--src/cz/crcs/ectester/data/wrong/curves.xml13
-rw-r--r--src/cz/crcs/ectester/reader/command/Command.java8
-rw-r--r--src/cz/crcs/ectester/reader/response/Response.java4
-rw-r--r--src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java96
9 files changed, 149 insertions, 13 deletions
diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
index b026cfe..244bdba 100644
--- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java
+++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
@@ -145,7 +145,7 @@ public class ECKeyGenerator {
* @param offset
* @return
*/
- public short corruptCurve(KeyPair keypair, short corruptParams, byte corruption, byte[] buffer, short offset) {
+ public short corruptCurve(KeyPair keypair, short corruptParams, short corruption, byte[] buffer, short offset) {
return corruptCurve(keypair, EC_Consts.KEY_BOTH, corruptParams, corruption, buffer, offset);
}
@@ -158,7 +158,7 @@ public class ECKeyGenerator {
* @param offset
* @return
*/
- public short corruptCurve(KeyPair keypair, byte key, short corruptParams, byte corruption, byte[] buffer, short offset) {
+ public short corruptCurve(KeyPair keypair, byte key, short corruptParams, short corruption, byte[] buffer, short offset) {
sw = ISO7816.SW_NO_ERROR;
if (corruptParams == EC_Consts.PARAMETERS_NONE) {
return sw;
diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java
index 20e3f05..210b3e7 100644
--- a/src/cz/crcs/ectester/applet/ECTesterApplet.java
+++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java
@@ -310,7 +310,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
* @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
* P2 = byte key (EC_Consts.KEY_* | ...)
* DATA = short params (EC_Consts.PARAMETER_* | ...)
- * byte corruption (EC_Consts.CORRUPTION_* || ...)
+ * short corruption (EC_Consts.CORRUPTION_* || ...)
* @return length of response
*/
private short insCorrupt(APDU apdu) {
@@ -318,7 +318,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
byte key = apduArray[ISO7816.OFFSET_P2];
short cdata = apdu.getOffsetCdata();
short params = Util.getShort(apduArray, cdata);
- byte corruption = apduArray[(short) (cdata + 2)];
+ short corruption = Util.getShort(apduArray, (short) (cdata + 2));
short len = 0;
if ((keyPair & KEYPAIR_LOCAL) != 0) {
@@ -544,7 +544,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
* @param outOffset output offset in buffer
* @return length of data written to the buffer
*/
- private short corrupt(KeyPair keyPair, byte key, short params, byte corruption, byte[] outBuffer, short outOffset) {
+ private short corrupt(KeyPair keyPair, byte key, short params, short corruption, byte[] outBuffer, short outOffset) {
short sw = keyGenerator.corruptCurve(keyPair, key, params, corruption, ramArray, (short) 0);
Util.setShort(outBuffer, outOffset, sw);
return 2;
diff --git a/src/cz/crcs/ectester/common/test/CompoundTest.java b/src/cz/crcs/ectester/common/test/CompoundTest.java
index 10ecf9c..69122b0 100644
--- a/src/cz/crcs/ectester/common/test/CompoundTest.java
+++ b/src/cz/crcs/ectester/common/test/CompoundTest.java
@@ -12,7 +12,7 @@ import java.util.function.Function;
public class CompoundTest extends Test {
private Function<Test[], Result> callback;
private Test[] tests;
- private String description;
+ private String description = "";
private CompoundTest(Function<Test[], Result> callback, Test... tests) {
this.callback = callback;
diff --git a/src/cz/crcs/ectester/common/test/TestSuite.java b/src/cz/crcs/ectester/common/test/TestSuite.java
index f4f30ee..5bcee85 100644
--- a/src/cz/crcs/ectester/common/test/TestSuite.java
+++ b/src/cz/crcs/ectester/common/test/TestSuite.java
@@ -32,11 +32,23 @@ public abstract class TestSuite {
writer.end();
}
+ /**
+ * Run the given test and return it back.
+ * @param t The test to run.
+ * @return The test that was run.
+ * @throws TestException
+ */
protected Test runTest(Test t) throws TestException {
t.run();
return t;
}
+ /**
+ * Run the given test, output it and return it back.
+ * @param t The test to run.
+ * @return The test that was run.
+ * @throws TestException
+ */
protected Test doTest(Test t) throws TestException {
t.run();
writer.outputTest(t);
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);
}
diff --git a/src/cz/crcs/ectester/data/wrong/curves.xml b/src/cz/crcs/ectester/data/wrong/curves.xml
index 396dc4e..2a51474 100644
--- a/src/cz/crcs/ectester/data/wrong/curves.xml
+++ b/src/cz/crcs/ectester/data/wrong/curves.xml
@@ -6,77 +6,90 @@
<bits>128</bits>
<field>prime</field>
<file>wrongp128.csv</file>
+ <desc>The field is not prime.</desc>
</curve>
<curve>
<id>wrongp160</id>
<bits>160</bits>
<field>prime</field>
<file>wrongp160.csv</file>
+ <desc>The field is not prime.</desc>
</curve>
<curve>
<id>wrongp192</id>
<bits>192</bits>
<field>prime</field>
<file>wrongp192.csv</file>
+ <desc>The field is not prime.</desc>
</curve>
<curve>
<id>wrongp224</id>
<bits>224</bits>
<field>prime</field>
<file>wrongp224.csv</file>
+ <desc>The field is not prime.</desc>
</curve>
<curve>
<id>wrongp256</id>
<bits>256</bits>
<field>prime</field>
<file>wrongp256.csv</file>
+ <desc>The field is not prime.</desc>
</curve>
<curve>
<id>wrongp384</id>
<bits>384</bits>
<field>prime</field>
<file>wrongp384.csv</file>
+ <desc>The field is not prime.</desc>
</curve>
<curve>
<id>wrongp521</id>
<bits>521</bits>
<field>prime</field>
<file>wrongp521.csv</file>
+ <desc>The field is not prime.</desc>
</curve>
<curve>
<id>wrongt163</id>
<bits>163</bits>
<field>binary</field>
<file>wrongt163.csv</file>
+ <desc>The field polynomial is not irreducible in F_2^163[x].</desc>
</curve>
<curve>
<id>wrongt233</id>
<bits>233</bits>
<field>binary</field>
<file>wrongt233.csv</file>
+ <desc>The field polynomial is not irreducible in F_2^233[x].</desc>
</curve>
<curve>
<id>wrongt239</id>
<bits>239</bits>
<field>binary</field>
<file>wrongt239.csv</file>
+ <desc>The field polynomial is not irreducible in F_2^239[x].</desc>
</curve>
<curve>
<id>wrongt283</id>
<bits>283</bits>
<field>binary</field>
<file>wrongt283.csv</file>
+ <desc>The field polynomial is not irreducible in F_2^283[x].</desc>
</curve>
<curve>
<id>wrongt409</id>
<bits>409</bits>
<field>binary</field>
<file>wrongt409.csv</file>
+ <desc>The field polynomial is not irreducible in F_2^409[x].</desc>
</curve>
<curve>
<id>wrongt571</id>
<bits>571</bits>
<field>binary</field>
<file>wrongt571.csv</file>
+ <desc>The field polynomial is not irreducible in F_2^571[x].</desc>
</curve>
</curves> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java
index 5a6906c..eefbc27 100644
--- a/src/cz/crcs/ectester/reader/command/Command.java
+++ b/src/cz/crcs/ectester/reader/command/Command.java
@@ -374,7 +374,7 @@ public abstract class Command {
private byte keyPair;
private byte key;
private short params;
- private byte corruption;
+ private short corruption;
/**
* @param cardManager cardManager to send APDU through
@@ -383,16 +383,16 @@ public abstract class Command {
* @param params parameters to corrupt (EC_Consts.PARAMETER_* | ...)
* @param corruption corruption type (EC_Consts.CORRUPTION_*)
*/
- public Corrupt(CardMngr cardManager, byte keyPair, byte key, short params, byte corruption) {
+ public Corrupt(CardMngr cardManager, byte keyPair, byte key, short params, short corruption) {
super(cardManager);
this.keyPair = keyPair;
this.key = key;
this.params = params;
this.corruption = corruption;
- byte[] data = new byte[3];
+ byte[] data = new byte[4];
ByteUtil.setShort(data, 0, params);
- data[2] = corruption;
+ ByteUtil.setShort(data, 2, corruption);
this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CORRUPT, keyPair, key, data);
}
diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java
index cbed3b2..1ae59de 100644
--- a/src/cz/crcs/ectester/reader/response/Response.java
+++ b/src/cz/crcs/ectester/reader/response/Response.java
@@ -292,9 +292,9 @@ public abstract class Response {
private byte keyPair;
private byte key;
private short params;
- private byte corruption;
+ private short corruption;
- public Corrupt(ResponseAPDU response, long time, byte keyPair, byte key, short params, byte corruption) {
+ public Corrupt(ResponseAPDU response, long time, byte keyPair, byte key, short params, short corruption) {
super(response, time);
this.keyPair = keyPair;
this.key = key;
diff --git a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java
index cac8fab..1de0723 100644
--- a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java
@@ -3,17 +3,24 @@ 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_Params;
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.test.TestException;
+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.data.EC_Store;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
import cz.crcs.ectester.reader.command.Command;
import javacard.security.KeyPair;
+import java.math.BigInteger;
import java.util.Map;
+import java.util.Random;
/**
* @author Jan Jancar johny@neuromancer.sk
@@ -44,7 +51,7 @@ public class CardWrongCurvesSuite extends CardTestSuite {
}
Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS));
Test generate = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS));
- doTest(CompoundTest.any(Result.ExpectedValue.FAILURE, "Set wrong curve and generate keypairs, should fail." ,set, generate));
+ doTest(CompoundTest.any(Result.ExpectedValue.FAILURE, "Set wrong curve and generate keypairs, should fail.", set, generate));
for (byte kaType : EC_Consts.KA_TYPES) {
Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), Result.ExpectedValue.SUCCESS));
@@ -54,5 +61,92 @@ public class CardWrongCurvesSuite extends CardTestSuite {
}
}
}
+ /*
+ * Do some interesting tests with corrupting the custom curves.
+ * For prime field:
+ * - p = 0
+ * - p = 1
+ * - p is a square of a prime
+ * - p is a composite q * s with q, s primes
+ * - TODO: p divides discriminant
+ */
+ Random r = new Random();
+ for (short keyLength : EC_Consts.FP_SIZES) {
+ byte curve = EC_Consts.getCurve(keyLength, KeyPair.ALG_EC_FP);
+ Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP), Result.ExpectedValue.SUCCESS));
+ if (!key.ok()) {
+ continue;
+ }
+ Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curve, EC_Consts.PARAMETERS_DOMAIN_FP, null), Result.ExpectedValue.SUCCESS));
+ Test setup = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set));
+
+ Test prime0 = ecdhTest(new Command.Corrupt(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_FP, EC_Consts.CORRUPTION_ZERO), "Set p = 0.", "ECDH with p = 0.");
+ Test prime1 = ecdhTest(new Command.Corrupt(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_FP, EC_Consts.CORRUPTION_ONE), "Set p = 1.", "ECDH with p = 1.");
+
+ short keyHalf = (short) (keyLength / 2);
+ BigInteger prime = new BigInteger(keyHalf, r);
+ BigInteger primePow = prime.pow(2);
+ byte[] primePowBytes = ECUtil.toByteArray(primePow, keyLength);
+ EC_Params primePowData = new EC_Params(EC_Consts.PARAMETER_FP, new byte[][]{primePowBytes});
+ Test primePower = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, primePowData.getParams(), primePowData.flatten()), "Set p = square of a prime.", "ECDH with p = q^2.");
+
+ BigInteger q = new BigInteger(keyHalf, r);
+ BigInteger s = new BigInteger(keyHalf, r);
+ BigInteger compositeValue = q.multiply(s);
+ byte[] compositeBytes = ECUtil.toByteArray(compositeValue, keyLength);
+ EC_Params compositeData = new EC_Params(EC_Consts.PARAMETER_FP, new byte[][]{compositeBytes});
+ Test composite = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, compositeData.getParams(), compositeData.flatten()), "Set p = product of two primes.", "ECDH with p = q * s.");
+
+ Test wrong = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted prime parameter.", prime0, prime1, primePower, composite));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_FP), setup, wrong));
+ }
+
+ /*
+ * For binary field:
+ * - e1, e2 or e3 is larger than m.
+ * - e1 = e2 = e3 = 0
+ */
+ for (short keyLength : EC_Consts.F2M_SIZES) {
+ byte curve = EC_Consts.getCurve(keyLength, KeyPair.ALG_EC_F2M);
+ Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M), Result.ExpectedValue.SUCCESS));
+ if (!key.ok()) {
+ continue;
+ }
+ Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curve, EC_Consts.PARAMETERS_DOMAIN_F2M, null), Result.ExpectedValue.SUCCESS));
+ Test setup = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set));
+
+ Test coeff0 = ecdhTest(new Command.Corrupt(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_F2M, EC_Consts.CORRUPTION_ZERO), "Set e1 = e2 = e3 = 0.", "ECDH with wrong field polynomial: x^" + keyLength);
+
+ short e1 = (short) (2 * keyLength);
+ short e2 = (short) (3 * keyLength);
+ short e3 = (short) (4 * keyLength);
+ byte[][] coeffBytes = new byte[][]{
+ ByteUtil.shortToBytes(keyLength),
+ ByteUtil.shortToBytes(e1),
+ ByteUtil.shortToBytes(e2),
+ ByteUtil.shortToBytes(e3)};
+ EC_Params coeffParams = new EC_Params(EC_Consts.PARAMETER_F2M, coeffBytes);
+ Test coeffLarger = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, coeffParams.getParams(), coeffParams.flatten()), "Set e1=" + e1 + ", e2=" + e2 + ", e3=" + e3, "ECDH with wrong field poly, powers larger than " + keyLength);
+
+ Test wrong = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted field polynomial parameter.", coeff0, coeffLarger));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_F2M), setup, wrong));
+ }
+
+ /*
+ * TODO: tests for both Fp and F2m:
+ * - generator not on curve,
+ * - generator not on proper subgroup of curve(as specified by order/cofactor),
+ * - wrong order,
+ * - wrong cofactor.
+ */
+ }
+
+ private Test ecdhTest(Command setupCmd, String prepareDesc, String fullDesc) throws TestException {
+ Test setup = runTest(CommandTest.expect(setupCmd, Result.ExpectedValue.FAILURE));
+ Test generate = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.FAILURE));
+ Test preparePhase = runTest(CompoundTest.any(Result.ExpectedValue.SUCCESS, prepareDesc, setup, generate));
+ Test allocateECDH = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.SUCCESS));
+ Test ecdh = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE));
+ return runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, fullDesc, preparePhase, allocateECDH, ecdh));
}
}