aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/reader
diff options
context:
space:
mode:
authorJ08nY2017-03-30 01:51:46 +0200
committerJ08nY2017-03-30 01:51:46 +0200
commit565d312568da433f213b3d7ea67861b7784b2115 (patch)
tree7e3af1d28512e77b073105d5dc40c6e869633a3d /src/cz/crcs/ectester/reader
parent83c963ae78407e7a14ac71096f81254364d1e605 (diff)
downloadECTester-565d312568da433f213b3d7ea67861b7784b2115.tar.gz
ECTester-565d312568da433f213b3d7ea67861b7784b2115.tar.zst
ECTester-565d312568da433f213b3d7ea67861b7784b2115.zip
Added more documentation, anomalous curves, support command.
- Added CURVES.md, FORMAT.md and TESTS.md that talk a bit about what ECTester actually does/support. - Added anomalous curves (where |F_p| = #|E(F_p)|), meaning these curves have a trace of one and ECDLP over them reduces to easy DLP over multiplicative F*_p. These concrete curves are from Atsuko Miyaji's paper: Elliptic curves over F_p Suitable for Cryptosystems. - Added Support command that queries the results of KeyAgreement and Signature allocations. - Renamed smallpub curves to nonprime curves. - Fixed nonprime curves test suite.
Diffstat (limited to 'src/cz/crcs/ectester/reader')
-rw-r--r--src/cz/crcs/ectester/reader/Command.java33
-rw-r--r--src/cz/crcs/ectester/reader/ECTester.java58
-rw-r--r--src/cz/crcs/ectester/reader/Response.java64
3 files changed, 101 insertions, 54 deletions
diff --git a/src/cz/crcs/ectester/reader/Command.java b/src/cz/crcs/ectester/reader/Command.java
index 92d9da1..24418be 100644
--- a/src/cz/crcs/ectester/reader/Command.java
+++ b/src/cz/crcs/ectester/reader/Command.java
@@ -49,7 +49,7 @@ public abstract class Command {
* @param keyLength key length to set
* @param keyClass key class to allocate
*/
- public Allocate(CardMngr cardManager, byte keyPair, short keyLength, byte keyClass) {
+ protected Allocate(CardMngr cardManager, byte keyPair, short keyLength, byte keyClass) {
super(cardManager);
this.keyPair = keyPair;
this.keyLength = keyLength;
@@ -79,7 +79,7 @@ public abstract class Command {
* @param cardManager
* @param keyPair which keyPair clear, local/remote (KEYPAIR_* || ...)
*/
- public Clear(CardMngr cardManager, byte keyPair) {
+ protected Clear(CardMngr cardManager, byte keyPair) {
super(cardManager);
this.keyPair = keyPair;
@@ -113,7 +113,7 @@ public abstract class Command {
* @param params parameters to set (EC_Consts.PARAMETER_* | ...)
* @param external external curve data, can be null
*/
- public Set(CardMngr cardManager, byte keyPair, byte curve, short params, byte[] external) {
+ protected Set(CardMngr cardManager, byte keyPair, byte curve, short params, byte[] external) {
super(cardManager);
this.keyPair = keyPair;
this.curve = curve;
@@ -190,7 +190,7 @@ public abstract class Command {
* @param cardManager
* @param keyPair which keyPair to generate, local/remote (KEYPAIR_* || ...)
*/
- public Generate(CardMngr cardManager, byte keyPair) {
+ protected Generate(CardMngr cardManager, byte keyPair) {
super(cardManager);
this.keyPair = keyPair;
@@ -222,7 +222,7 @@ public abstract class Command {
* @param key key to export from (EC_Consts.KEY_* | ...)
* @param params params to export (EC_Consts.PARAMETER_* | ...)
*/
- public Export(CardMngr cardManager, byte keyPair, byte key, short params) {
+ protected Export(CardMngr cardManager, byte keyPair, byte key, short params) {
super(cardManager);
this.keyPair = keyPair;
this.key = key;
@@ -263,7 +263,7 @@ public abstract class Command {
* @param corruption whether to invalidate the pubkey before ECDH (EC_Consts.CORRUPTION_* || ...)
* @param type
*/
- public ECDH(CardMngr cardManager, byte pubkey, byte privkey, byte export, byte corruption, byte type) {
+ protected ECDH(CardMngr cardManager, byte pubkey, byte privkey, byte export, byte corruption, byte type) {
super(cardManager);
this.pubkey = pubkey;
this.privkey = privkey;
@@ -298,7 +298,7 @@ public abstract class Command {
* @param export whether to export ECDSA signature
* @param raw data to sign, can be null, in which case random data is signed.
*/
- public ECDSA(CardMngr cardManager, byte keyPair, byte export, byte[] raw) {
+ protected ECDSA(CardMngr cardManager, byte keyPair, byte export, byte[] raw) {
super(cardManager);
this.keyPair = keyPair;
this.export = export;
@@ -342,5 +342,24 @@ public abstract class Command {
return new Response.Cleanup(response, elapsed);
}
}
+
+ /**
+ *
+ */
+ public static class Support extends Command {
+ protected Support(CardMngr cardManager) {
+ super(cardManager);
+
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SUPPORT, 0, 0);
+ }
+
+ @Override
+ public Response.Support send() throws CardException {
+ long elapsed = -System.nanoTime();
+ ResponseAPDU response = cardManager.send(cmd);
+ elapsed += System.nanoTime();
+ return new Response.Support(response, elapsed);
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java
index 9926d3e..716d4ea 100644
--- a/src/cz/crcs/ectester/reader/ECTester.java
+++ b/src/cz/crcs/ectester/reader/ECTester.java
@@ -80,7 +80,7 @@ public class ECTester {
//Action-related options
private String optListNamed;
- private String optTestCase;
+ private String optTestSuite;
private int optGenerateAmount;
private int optECDHCount;
private byte optECDHKA;
@@ -205,7 +205,7 @@ public class ECTester {
* -h / --help
* -e / --export
* -g / --generate [amount]
- * -t / --test [test_case]
+ * -t / --test [test_suite]
* -dh / --ecdh [count]
* -dhc / --ecdhc [count]
* -dsa / --ecdsa [count]
@@ -245,7 +245,7 @@ public class ECTester {
actions.addOption(Option.builder("ln").longOpt("list-named").desc("Print the list of supported named curves and keys.").hasArg().argName("what").optionalArg(true).build());
actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build());
actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build());
- actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. <test_case>:\n- default:\n- invalid:\n- wrong:\n- nonprime:\n- smallpub:\n- test-vectors:").hasArg().argName("test_case").optionalArg(true).build());
+ actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- wrong:\n- nonprime:\n- smallpub:\n- test-vectors:").hasArg().argName("test_suite").optionalArg(true).build());
actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do ECDH, [count] times.").hasArg().argName("count").optionalArg(true).build());
actions.addOption(Option.builder("dhc").longOpt("ecdhc").desc("Do ECDHC, [count] times.").hasArg().argName("count").optionalArg(true).build());
actions.addOption(Option.builder("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build());
@@ -304,7 +304,7 @@ public class ECTester {
optPrimeField = cli.hasOption("fp");
optBinaryField = cli.hasOption("f2m");
- optNamedCurve = cli.getOptionValue("named");
+ optNamedCurve = cli.getOptionValue("named-curve");
optCustomCurve = cli.hasOption("custom");
optCurveFile = cli.getOptionValue("curve");
@@ -405,10 +405,10 @@ public class ECTester {
optPrimeField = true;
}
- optTestCase = cli.getOptionValue("test", "default").toLowerCase();
- String[] tests = new String[]{"default", "nonprime", "invalid", "smallpub", "test-vectors", "wrong"};
+ optTestSuite = cli.getOptionValue("test", "default").toLowerCase();
+ String[] tests = new String[]{"default", "nonprime", "invalid", "test-vectors", "wrong"};
List<String> testsList = Arrays.asList(tests);
- if (!testsList.contains(optTestCase)) {
+ if (!testsList.contains(optTestSuite)) {
System.err.println("Unknown test case. Should be one of: " + Arrays.toString(tests));
return false;
}
@@ -527,6 +527,9 @@ public class ECTester {
} else if (categories.containsKey(optListNamed)) {
// print given category
//TODO
+ } else {
+ // print given object
+ //TODO
}
}
@@ -631,7 +634,8 @@ public class ECTester {
private void test() throws IOException, CardException {
List<Command> commands = new LinkedList<>();
- if (optTestCase.equals("default")) {
+ if (optTestSuite.equals("default")) {
+ commands.add(new Command.Support(cardManager));
if (optNamedCurve != null) {
if (optPrimeField) {
commands.addAll(testCurves(optNamedCurve, KeyPair.ALG_EC_FP));
@@ -675,7 +679,7 @@ public class ECTester {
}
}
}
- } else if (optTestCase.equals("test-vectors")) {
+ } else if (optTestSuite.equals("test-vectors")) {
/* Set original curves (secg/nist/brainpool). Set keypairs from test vectors.
* Do ECDH both ways, export and verify that the result is correct.
*
@@ -683,6 +687,12 @@ public class ECTester {
Map<String, EC_KAResult> results = dataStore.getObjects(EC_KAResult.class, "test");
for (EC_KAResult result : results.values()) {
EC_Curve curve = dataStore.getObject(EC_Curve.class, result.getCurve());
+ if (optNamedCurve != null && !(result.getCurve().startsWith(optNamedCurve) || result.getCurve().equals(optNamedCurve))) {
+ continue;
+ }
+ if (curve.getBits() != optBits && !optAll) {
+ continue;
+ }
EC_Params onekey = dataStore.getObject(EC_Keypair.class, result.getOneKey());
if (onekey == null) {
onekey = dataStore.getObject(EC_Key.Private.class, result.getOneKey());
@@ -707,53 +717,56 @@ public class ECTester {
} else {
// These tests are dangerous, prompt before them.
- System.out.println("The test you selected (" + optTestCase + ") is potentially dangerous.");
+ System.out.println("The test you selected (" + optTestSuite + ") is potentially dangerous.");
System.out.println("Some of these tests have caused temporary DoS of some cards.");
System.out.print("Do you want to proceed? (y/n):");
- String confirmation = System.console().readLine();
+ Scanner in = new Scanner(System.in);
+ String confirmation = in.nextLine();
if (!Arrays.asList("yes", "y", "Y").contains(confirmation)) {
return;
}
- if (optTestCase.equals("wrong") || optTestCase.equals("nonprime")) {
- /* Just do the default tests on the wrong and non-prime curves.
+ if (optTestSuite.equals("wrong")) {
+ /* Just do the default tests on the wrong curves.
* These should generally fail, the curves aren't safe.
*/
if (optPrimeField) {
- commands.addAll(testCurves(optTestCase, KeyPair.ALG_EC_FP));
+ commands.addAll(testCurves(optTestSuite, KeyPair.ALG_EC_FP));
}
if (optBinaryField) {
- commands.addAll(testCurves(optTestCase, KeyPair.ALG_EC_F2M));
+ commands.addAll(testCurves(optTestSuite, KeyPair.ALG_EC_F2M));
}
- } else if (optTestCase.equals("smallpub")) {
- /* Do the default tests with the public keys set to provided smallpub keys.
+ } else if (optTestSuite.equals("nonprime")) {
+ /* Do the default tests with the public keys set to provided nonprime keys.
* These should fail, the curves aren't safe so that if the computation with
* a small order public key succeeds the private key modulo the public key order
* is revealed.
*/
- Map<String, EC_Key> keys = dataStore.getObjects(EC_Key.class, "smallpub");
+ Map<String, EC_Key> keys = dataStore.getObjects(EC_Key.class, "nonprime");
for (EC_Key key : keys.values()) {
EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve());
if ((curve.getBits() == optBits || optAll)) {
commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()));
commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL));
- commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()));
+ commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()));
+ commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, key.getParams(), key.flatten()));
commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH));
commands.add(new Command.Cleanup(cardManager));
}
}
- } else if (optTestCase.equals("invalid")) {
+ } else if (optTestSuite.equals("invalid")) {
/* Set original curves (secg/nist/brainpool). Generate local.
* Try ECDH with invalid public keys of increasing (or decreasing) order.
*
*/
//TODO
+ System.err.println("Currently not yet implemented.");
}
}
List<Response> test = Command.sendAll(commands);
- systemOutLogger.println(Response.toString(test));
+ systemOutLogger.println(Response.toString(test, optTestSuite));
for (Response response : test) {
if (response instanceof Response.ECDH) {
@@ -1053,8 +1066,7 @@ public class ECTester {
EC_Curve curve = entry.getValue();
if (curve.getField() == field && (curve.getBits() == optBits || optAll)) {
commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), field));
- byte[] external = curve.flatten();
- commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), external));
+ commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()));
commands.addAll(testCurve());
commands.add(new Command.Cleanup(cardManager));
}
diff --git a/src/cz/crcs/ectester/reader/Response.java b/src/cz/crcs/ectester/reader/Response.java
index 92d1b9f..4bb5b88 100644
--- a/src/cz/crcs/ectester/reader/Response.java
+++ b/src/cz/crcs/ectester/reader/Response.java
@@ -14,8 +14,7 @@ import java.util.List;
public abstract class Response {
private ResponseAPDU resp;
private long time;
- private short sw1 = 0;
- private short sw2 = 0;
+ private short[] sws;
private int numSW = 0;
private byte[][] params;
private boolean success = true;
@@ -27,23 +26,20 @@ public abstract class Response {
protected void parse(int numSW, int numParams) {
this.numSW = numSW;
+ this.sws = new short[numSW];
byte[] data = resp.getData();
int offset = 0;
//parse SWs in response
- if (--numSW >= 0 && getLength() >= 2) {
- sw1 = Util.getShort(data, offset);
- offset += 2;
- if (sw1 != ISO7816.SW_NO_ERROR) {
- success = false;
- }
- }
- if (--numSW >= 0 && getLength() >= 4) {
- sw2 = Util.getShort(data, offset);
- offset += 2;
- if (sw2 != ISO7816.SW_NO_ERROR) {
- success = false;
+ for (int i = 0; i < numSW; ++i) {
+ if (getLength() >= (offset + 2)) {
+ short sw = Util.getShort(data, offset);
+ offset += 2;
+ sws[i] = sw;
+ if (sw != ISO7816.SW_NO_ERROR) {
+ success = false;
+ }
}
}
@@ -79,11 +75,15 @@ public abstract class Response {
}
public short getSW1() {
- return sw1;
+ return sws[0];
}
public short getSW2() {
- return sw2;
+ return sws[1];
+ }
+
+ public short getSW(int index) {
+ return sws[index];
}
public int getNumSW() {
@@ -122,16 +122,16 @@ public abstract class Response {
}
public static String toString(List<Response> responses, String prefix) {
+ if (prefix != null)
+ prefix += " | ";
StringBuilder out = new StringBuilder();
for (int i = 0; i < responses.size(); ++i) {
Response r = responses.get(i);
String message = r.toString();
- String suffix;
- if (r.getNumSW() == 1) {
- suffix = String.format("%s", Util.getSWString(r.getSW1()));
- } else {
- suffix = String.format("%s %s", Util.getSWString(r.getSW1()), Util.getSWString(r.getSW2()));
+ String suffix = "";
+ for (int j = 0; j < r.getNumSW(); ++j) {
+ suffix += " " + Util.getSWString(r.getSW(j));
}
if (prefix != null)
@@ -153,7 +153,7 @@ public abstract class Response {
private short keyLength;
private byte keyClass;
- public Allocate(ResponseAPDU response, long time, byte keyPair, short keyLength, byte keyClass) {
+ protected Allocate(ResponseAPDU response, long time, byte keyPair, short keyLength, byte keyClass) {
super(response, time);
this.keyPair = keyPair;
this.keyLength = keyLength;
@@ -181,7 +181,7 @@ public abstract class Response {
public static class Clear extends Response {
private byte keyPair;
- public Clear(ResponseAPDU response, long time, byte keyPair) {
+ protected Clear(ResponseAPDU response, long time, byte keyPair) {
super(response, time);
this.keyPair = keyPair;
@@ -323,7 +323,7 @@ public abstract class Response {
private byte key;
private short parameters;
- public Export(ResponseAPDU response, long time, byte keyPair, byte key, short parameters) {
+ protected Export(ResponseAPDU response, long time, byte keyPair, byte key, short parameters) {
super(response, time);
this.keyPair = keyPair;
this.key = key;
@@ -527,6 +527,22 @@ public abstract class Response {
return String.format("Requested JCSystem object deletion");
}
+ }
+
+ /**
+ *
+ */
+ public static class Support extends Response {
+
+ protected Support(ResponseAPDU response, long time) {
+ super(response, time);
+ parse(3,0);
+ }
+
+ @Override
+ public String toString() {
+ return "Support of ECDH, ECDHC, ECDSA";
+ }
}
}