From 117b35545288df5b01173d36bde451b414d31d66 Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 6 Mar 2017 22:56:34 +0100 Subject: Added support for named curves (in jar). - Doesn't work well while simulating, some weird memory bug. Will investigate. - Has categories of curves, more will be added. --- src/cz/crcs/ectester/reader/ec/EC_Curve.java | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/cz/crcs/ectester/reader/ec/EC_Curve.java (limited to 'src/cz/crcs/ectester/reader/ec/EC_Curve.java') diff --git a/src/cz/crcs/ectester/reader/ec/EC_Curve.java b/src/cz/crcs/ectester/reader/ec/EC_Curve.java new file mode 100644 index 0000000..08a0b8a --- /dev/null +++ b/src/cz/crcs/ectester/reader/ec/EC_Curve.java @@ -0,0 +1,41 @@ +package cz.crcs.ectester.reader.ec; + +import cz.crcs.ectester.applet.EC_Consts; +import javacard.security.KeyPair; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class EC_Curve extends EC_Params { + + private short bits; + private byte field; + private String desc; + + /** + * + * @param bits + * @param field KeyPair.ALG_EC_FP or KeyPair.ALG_EC_F2M + */ + public EC_Curve(short bits, byte field) { + super(field == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M); + this.bits = bits; + } + + public EC_Curve(short bits, byte field, String desc) { + this(bits, field); + this.desc = desc; + } + + public short getBits() { + return bits; + } + + public byte getField() { + return field; + } + + public String getDesc() { + return desc; + } +} -- cgit v1.3.1 From ea77f29683c8721ae1581b76f3f6b83ee26720bc Mon Sep 17 00:00:00 2001 From: J08nY Date: Thu, 9 Mar 2017 00:46:35 +0100 Subject: Reader: fixed ECDH and ECDSA output, also named curve testing --- !uploader/ectester.cap | Bin 13789 -> 13790 bytes dist/ECTester.jar | Bin 104311 -> 211003 bytes src/cz/crcs/ectester/data/EC_Data.java | 25 +++++++++++++++++---- src/cz/crcs/ectester/reader/ECTester.java | 31 ++++++++++++++++++++------- src/cz/crcs/ectester/reader/Response.java | 2 +- src/cz/crcs/ectester/reader/ec/EC_Curve.java | 2 ++ 6 files changed, 47 insertions(+), 13 deletions(-) (limited to 'src/cz/crcs/ectester/reader/ec/EC_Curve.java') diff --git a/!uploader/ectester.cap b/!uploader/ectester.cap index 4dc1bca..c669495 100644 Binary files a/!uploader/ectester.cap and b/!uploader/ectester.cap differ diff --git a/dist/ECTester.jar b/dist/ECTester.jar index 8201bec..6ebc1c8 100644 Binary files a/dist/ECTester.jar and b/dist/ECTester.jar differ diff --git a/src/cz/crcs/ectester/data/EC_Data.java b/src/cz/crcs/ectester/data/EC_Data.java index a867fcf..0c4bda2 100644 --- a/src/cz/crcs/ectester/data/EC_Data.java +++ b/src/cz/crcs/ectester/data/EC_Data.java @@ -10,7 +10,9 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; @@ -29,12 +31,12 @@ import java.util.Map; */ public class EC_Data { - private DocumentBuilderFactory dbf; + private DocumentBuilder db; private Map categories; public EC_Data() { - dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { SchemaFactory scf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); @@ -43,6 +45,23 @@ public class EC_Data { dbf.setNamespaceAware(true); dbf.setIgnoringComments(true); dbf.setIgnoringElementContentWhitespace(true); + db = dbf.newDocumentBuilder(); + db.setErrorHandler(new ErrorHandler() { + @Override + public void warning(SAXParseException exception) throws SAXException { + System.err.println("EC_Data | Warning : " + exception); + } + + @Override + public void error(SAXParseException exception) throws SAXException { + System.err.println("EC_Data | Error : " + exception); + } + + @Override + public void fatalError(SAXParseException exception) throws SAXException { + System.err.println("EC_Data | Fatal : " + exception); + } + }); parse(); } catch (ParserConfigurationException | IOException | SAXException e) { @@ -51,7 +70,6 @@ public class EC_Data { } private void parse() throws SAXException, ParserConfigurationException, IOException { - DocumentBuilder db = dbf.newDocumentBuilder(); Document categoriesDoc = db.parse(this.getClass().getResourceAsStream("/cz/crcs/ectester/data/categories.xml")); categoriesDoc.normalize(); @@ -76,7 +94,6 @@ public class EC_Data { } private EC_Category parseCategory(String name, String dir, String desc) throws ParserConfigurationException, IOException, SAXException { - DocumentBuilder db = dbf.newDocumentBuilder(); Map objMap = new HashMap<>(); diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java index c4d29a5..86588df 100644 --- a/src/cz/crcs/ectester/reader/ECTester.java +++ b/src/cz/crcs/ectester/reader/ECTester.java @@ -602,6 +602,12 @@ public class ECTester { generate.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH)); } + FileWriter out = null; + if (optOutput != null) { + out = new FileWriter(optOutput); + out.write("index;time;secret\n"); + } + int retry = 0; int done = 0; while (done < optECDHCount) { @@ -621,13 +627,15 @@ public class ECTester { } } - if (optOutput != null) { - FileWriter out = new FileWriter(optOutput); - out.write(Util.bytesToHex(perform.getSecret(), false)); - out.close(); + if (out != null) { + out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSecret(), false))); } + ++done; } + + if (out != null) + out.close(); } /** @@ -662,6 +670,12 @@ public class ECTester { systemOutLogger.println(Response.toString(prepare)); + FileWriter out = null; + if (optOutput != null) { + out = new FileWriter(optOutput); + out.write("index;time;signature\n"); + } + int retry = 0; int done = 0; while (done < optECDSACount) { @@ -682,13 +696,14 @@ public class ECTester { } } - if (optOutput != null) { - FileWriter out = new FileWriter(optOutput); - out.write(Util.bytesToHex(perform.getSignature(), false)); - out.close(); + if (out != null) { + out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSignature(), false))); } + ++done; } + if (out != null) + out.close(); } /** diff --git a/src/cz/crcs/ectester/reader/Response.java b/src/cz/crcs/ectester/reader/Response.java index 28b6c17..e76d35c 100644 --- a/src/cz/crcs/ectester/reader/Response.java +++ b/src/cz/crcs/ectester/reader/Response.java @@ -129,7 +129,7 @@ public abstract class Response { } else { suffix = String.format("%s %s", Util.getPrintError(r.getSW1()), Util.getPrintError(r.getSW2())); } - out.append(String.format("%-55s: %5d ms : %s", message, r.time/1000000, suffix)); + out.append(String.format("%-55s:%5d ms : %s", message, r.time/1000000, suffix)); if (i < responses.size() - 1) { out.append("\n"); } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Curve.java b/src/cz/crcs/ectester/reader/ec/EC_Curve.java index 08a0b8a..273b1f4 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Curve.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Curve.java @@ -20,6 +20,8 @@ public class EC_Curve extends EC_Params { public EC_Curve(short bits, byte field) { super(field == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M); this.bits = bits; + + this.field = field; } public EC_Curve(short bits, byte field, String desc) { -- cgit v1.3.1 From 45d1bb40cbc4c71e5b94e78f3a541e8f9cd8d62f Mon Sep 17 00:00:00 2001 From: J08nY Date: Tue, 4 Apr 2017 23:25:20 +0200 Subject: Some docs, allow EC_* objects to print themselves. --- dist/ECTester.jar | Bin 290834 -> 155730 bytes src/cz/crcs/ectester/reader/Command.java | 29 ++++++++++++++++-------- src/cz/crcs/ectester/reader/ECTester.java | 27 +++++++++++++--------- src/cz/crcs/ectester/reader/Response.java | 2 +- src/cz/crcs/ectester/reader/ec/EC_Curve.java | 5 ++++ src/cz/crcs/ectester/reader/ec/EC_Data.java | 4 ++-- src/cz/crcs/ectester/reader/ec/EC_KAResult.java | 8 +++++++ src/cz/crcs/ectester/reader/ec/EC_Key.java | 9 ++++++++ src/cz/crcs/ectester/reader/ec/EC_Keypair.java | 5 ++++ 9 files changed, 65 insertions(+), 24 deletions(-) (limited to 'src/cz/crcs/ectester/reader/ec/EC_Curve.java') diff --git a/dist/ECTester.jar b/dist/ECTester.jar index a256495..5a8f64b 100644 Binary files a/dist/ECTester.jar and b/dist/ECTester.jar differ diff --git a/src/cz/crcs/ectester/reader/Command.java b/src/cz/crcs/ectester/reader/Command.java index 24418be..73f4987 100644 --- a/src/cz/crcs/ectester/reader/Command.java +++ b/src/cz/crcs/ectester/reader/Command.java @@ -44,7 +44,7 @@ public abstract class Command { /** * Creates the INS_ALLOCATE instruction. * - * @param cardManager + * @param cardManager cardManager to send APDU through * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...) * @param keyLength key length to set * @param keyClass key class to allocate @@ -76,7 +76,7 @@ public abstract class Command { private byte keyPair; /** - * @param cardManager + * @param cardManager cardManager to send APDU through * @param keyPair which keyPair clear, local/remote (KEYPAIR_* || ...) */ protected Clear(CardMngr cardManager, byte keyPair) { @@ -107,7 +107,7 @@ public abstract class Command { /** * Creates the INS_SET instruction. * - * @param cardManager + * @param cardManager cardManager to send APDU through * @param keyPair which keyPair to set params on, local/remote (KEYPAIR_* || ...) * @param curve curve to set (EC_Consts.CURVE_*) * @param params parameters to set (EC_Consts.PARAMETER_* | ...) @@ -149,9 +149,9 @@ public abstract class Command { private byte corruption; /** - * @param cardManager + * @param cardManager cardManager to send APDU through * @param keyPair which keyPair to corrupt, local/remote (KEYPAIR_* || ...) - * @param key + * @param key key to corrupt (EC_Consts.KEY_* | ...) * @param params parameters to corrupt (EC_Consts.PARAMETER_* | ...) * @param corruption corruption type (EC_Consts.CORRUPTION_*) */ @@ -187,7 +187,7 @@ public abstract class Command { /** * Creates the INS_GENERATE instruction. * - * @param cardManager + * @param cardManager cardManager to send APDU through * @param keyPair which keyPair to generate, local/remote (KEYPAIR_* || ...) */ protected Generate(CardMngr cardManager, byte keyPair) { @@ -217,7 +217,7 @@ public abstract class Command { /** * Creates the INS_EXPORT instruction. * - * @param cardManager + * @param cardManager cardManager to send APDU through * @param keyPair keyPair to export from (KEYPAIR_* | ...) * @param key key to export from (EC_Consts.KEY_* | ...) * @param params params to export (EC_Consts.PARAMETER_* | ...) @@ -256,12 +256,12 @@ public abstract class Command { /** * Creates the INS_ECDH instruction. * - * @param cardManager + * @param cardManager cardManager to send APDU through * @param pubkey keyPair to use for public key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) * @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) * @param export whether to export ECDH secret * @param corruption whether to invalidate the pubkey before ECDH (EC_Consts.CORRUPTION_* || ...) - * @param type + * @param type ECDH algorithm type (EC_Consts.KA_* | ...) */ protected ECDH(CardMngr cardManager, byte pubkey, byte privkey, byte export, byte corruption, byte type) { super(cardManager); @@ -293,7 +293,7 @@ public abstract class Command { /** * Creates the INS_ECDSA instruction. * - * @param cardManager + * @param cardManager cardManager to send APDU through * @param keyPair keyPair to use for signing and verification (KEYPAIR_LOCAL || KEYPAIR_REMOTE) * @param export whether to export ECDSA signature * @param raw data to sign, can be null, in which case random data is signed. @@ -328,6 +328,10 @@ public abstract class Command { */ public static class Cleanup extends Command { + /** + * + * @param cardManager cardManager to send APDU through + */ protected Cleanup(CardMngr cardManager) { super(cardManager); @@ -347,6 +351,11 @@ public abstract class Command { * */ public static class Support extends Command { + + /** + * + * @param cardManager cardManager to send APDU through + */ protected Support(CardMngr cardManager) { super(cardManager); diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java index 716d4ea..cb3d298 100644 --- a/src/cz/crcs/ectester/reader/ECTester.java +++ b/src/cz/crcs/ectester/reader/ECTester.java @@ -529,7 +529,10 @@ public class ECTester { //TODO } else { // print given object - //TODO + EC_Data object = dataStore.getObject(EC_Data.class, optListNamed); + if (object != null) { + System.out.println(object); + } } } @@ -628,8 +631,8 @@ public class ECTester { /** * Tests Elliptic curve support for a given curve/curves. * - * @throws IOException - * @throws CardException + * @throws CardException if APDU transmission fails + * @throws IOException if an IO error occurs when writing to key file. */ private void test() throws IOException, CardException { List commands = new LinkedList<>(); @@ -915,9 +918,9 @@ public class ECTester { private List prepareCurve(byte keyPair, short keyLength, byte keyClass) throws IOException { List commands = new ArrayList<>(); - short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; if (optCustomCurve) { // Set custom curve (one of the SECG curves embedded applet-side) + short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; commands.add(new Command.Set(cardManager, keyPair, EC_Consts.getCurve(keyLength, keyClass), domainParams, null)); } else if (optNamedCurve != null) { // Set a named curve. @@ -934,20 +937,20 @@ public class ECTester { if (external == null) { throw new IOException("Couldn't read named curve data."); } - commands.add(new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, domainParams, external)); + commands.add(new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, curve.getParams(), external)); } else if (optCurveFile != null) { // Set curve loaded from a file - EC_Params params = new EC_Params(domainParams); + EC_Curve curve = new EC_Curve(keyLength, keyClass); FileInputStream in = new FileInputStream(optCurveFile); - params.readCSV(in); + curve.readCSV(in); in.close(); - byte[] external = params.flatten(); + byte[] external = curve.flatten(); if (external == null) { throw new IOException("Couldn't read the curve file correctly."); } - commands.add(new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, domainParams, external)); + commands.add(new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, curve.getParams(), external)); } else { // Set default curve /* This command was generally causing problems for simulating on jcardsim. @@ -1036,8 +1039,9 @@ public class ECTester { } /** + * * @return - * @throws IOException + * @throws IOException if an IO error occurs when writing to key file. */ private List testCurve() throws IOException { List commands = new LinkedList<>(); @@ -1052,10 +1056,11 @@ public class ECTester { } /** + * * @param category * @param field * @return - * @throws IOException + * @throws IOException if an IO error occurs when writing to key file. */ private List testCurves(String category, byte field) throws IOException { List commands = new LinkedList<>(); diff --git a/src/cz/crcs/ectester/reader/Response.java b/src/cz/crcs/ectester/reader/Response.java index 4bb5b88..c3f2fe4 100644 --- a/src/cz/crcs/ectester/reader/Response.java +++ b/src/cz/crcs/ectester/reader/Response.java @@ -524,7 +524,7 @@ public abstract class Response { @Override public String toString() { - return String.format("Requested JCSystem object deletion"); + return "Requested JCSystem object deletion"; } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Curve.java b/src/cz/crcs/ectester/reader/ec/EC_Curve.java index 273b1f4..953884f 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Curve.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Curve.java @@ -40,4 +40,9 @@ public class EC_Curve extends EC_Params { public String getDesc() { return desc; } + + @Override + public String toString() { + return "Elliptic curve (" + String.valueOf(bits) + "b): " + desc; + } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Data.java b/src/cz/crcs/ectester/reader/ec/EC_Data.java index 2e1eb29..c55b99d 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Data.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Data.java @@ -21,12 +21,12 @@ public class EC_Data { EC_Data() { } - public EC_Data(int count) { + EC_Data(int count) { this.count = count; this.data = new byte[count][]; } - public EC_Data(byte[][] data) { + EC_Data(byte[][] data) { this.count = data.length; this.data = data; } diff --git a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java b/src/cz/crcs/ectester/reader/ec/EC_KAResult.java index e556f90..f1be49a 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java +++ b/src/cz/crcs/ectester/reader/ec/EC_KAResult.java @@ -1,5 +1,7 @@ package cz.crcs.ectester.reader.ec; +import cz.crcs.ectester.applet.EC_Consts; + /** * @author Jan Jancar johny@neuromancer.sk */ @@ -45,4 +47,10 @@ public class EC_KAResult extends EC_Data { return desc; } + @Override + public String toString() { + String agreement = ka == EC_Consts.KA_ECDH ? "ECDH" : "ECDHC"; + return agreement + " over " + curve + ", " + oneKey + " + " + otherKey + ": " + desc; + } + } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Key.java b/src/cz/crcs/ectester/reader/ec/EC_Key.java index b78aaee..983ffa8 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Key.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Key.java @@ -37,6 +37,11 @@ public class EC_Key extends EC_Params { public Public(String curve, String desc) { super(EC_Consts.PARAMETER_W, curve, desc); } + + @Override + public String toString() { + return "EC Public key, over " + getCurve() + ": " + getDesc(); + } } public static class Private extends EC_Key { @@ -49,5 +54,9 @@ public class EC_Key extends EC_Params { super(EC_Consts.PARAMETER_S, curve, desc); } + @Override + public String toString() { + return "EC Private key, over " + getCurve() + ": " + getDesc(); + } } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java b/src/cz/crcs/ectester/reader/ec/EC_Keypair.java index 0ee3801..af4038a 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Keypair.java @@ -27,4 +27,9 @@ public class EC_Keypair extends EC_Params { public String getDesc() { return desc; } + + @Override + public String toString() { + return "EC Keypair, over " + curve + ": " + desc; + } } -- cgit v1.3.1 From 914931cfea79c7947b180069b0e67cc208971869 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sat, 15 Apr 2017 01:27:24 +0200 Subject: Add invalid curves test(partly) and some parameters (brainpool) for it - curves.xml, keys.xml and results.xml's entries can now instead of file path to point to csv file, contain the csv data inline. - Moved EC_Category to reader package from data - Fixed printing of named objects - Added ECDH/C test for KA_BOTH which does ECDH and ECDHC on the applet side, compares the results and reports success/failure etc. --- dist/ECTester.jar | Bin 155730 -> 295880 bytes src/cz/crcs/ectester/applet/ECKeyTester.java | 29 +++++ src/cz/crcs/ectester/applet/ECTesterApplet.java | 23 +++- src/cz/crcs/ectester/data/EC_Category.java | 72 ------------ src/cz/crcs/ectester/data/EC_Store.java | 54 +++++++-- src/cz/crcs/ectester/data/categories.xml | 5 + .../crcs/ectester/data/invalid/brainpool/keys.xml | 108 +++++++++++++++++ src/cz/crcs/ectester/data/invalid/curves.xml | 4 - src/cz/crcs/ectester/data/invalid/keys.xml | 14 +++ src/cz/crcs/ectester/data/invalid/nist/keys.xml | 6 + src/cz/crcs/ectester/data/invalid/secg/keys.xml | 6 + src/cz/crcs/ectester/data/schema.xsd | 12 +- src/cz/crcs/ectester/reader/ECTester.java | 115 ++++++------------ src/cz/crcs/ectester/reader/Response.java | 2 +- src/cz/crcs/ectester/reader/ec/EC_Category.java | 128 +++++++++++++++++++++ src/cz/crcs/ectester/reader/ec/EC_Curve.java | 2 +- src/cz/crcs/ectester/reader/ec/EC_KAResult.java | 2 +- src/cz/crcs/ectester/reader/ec/EC_Key.java | 4 +- src/cz/crcs/ectester/reader/ec/EC_Keypair.java | 2 +- 19 files changed, 409 insertions(+), 179 deletions(-) delete mode 100644 src/cz/crcs/ectester/data/EC_Category.java create mode 100644 src/cz/crcs/ectester/data/invalid/brainpool/keys.xml delete mode 100644 src/cz/crcs/ectester/data/invalid/curves.xml create mode 100644 src/cz/crcs/ectester/data/invalid/keys.xml create mode 100644 src/cz/crcs/ectester/data/invalid/nist/keys.xml create mode 100644 src/cz/crcs/ectester/data/invalid/secg/keys.xml create mode 100644 src/cz/crcs/ectester/reader/ec/EC_Category.java (limited to 'src/cz/crcs/ectester/reader/ec/EC_Curve.java') diff --git a/dist/ECTester.jar b/dist/ECTester.jar index 5a8f64b..0126533 100644 Binary files a/dist/ECTester.jar and b/dist/ECTester.jar differ diff --git a/src/cz/crcs/ectester/applet/ECKeyTester.java b/src/cz/crcs/ectester/applet/ECKeyTester.java index e22094b..64f3024 100644 --- a/src/cz/crcs/ectester/applet/ECKeyTester.java +++ b/src/cz/crcs/ectester/applet/ECKeyTester.java @@ -3,6 +3,7 @@ package cz.crcs.ectester.applet; import javacard.framework.CardRuntimeException; import javacard.framework.ISO7816; +import javacard.framework.Util; import javacard.security.ECPrivateKey; import javacard.security.ECPublicKey; import javacard.security.KeyAgreement; @@ -104,6 +105,34 @@ public class ECKeyTester { return testKA(ecdhcKeyAgreement, privateKey, pubkeyBuffer, pubkeyOffset, length, outputBuffer, outputOffset); } + /** + * + * @param privateKey + * @param publicKey + * @param pubkeyBuffer + * @param pubkeyOffset + * @param outputBuffer + * @param outputOffset + * @param corruption + * @return + */ + public short testKA(ECPrivateKey privateKey, ECPublicKey publicKey, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, byte corruption) { + short ecdhLength = testECDH(privateKey, publicKey, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption); + if (sw != ISO7816.SW_NO_ERROR) { + return ecdhLength; + } + short ecdhcLength = testECDHC(privateKey, publicKey, pubkeyBuffer, pubkeyOffset, outputBuffer, (short) (outputOffset + ecdhLength), corruption); + short length = (short) (ecdhLength + ecdhcLength); + if (sw != ISO7816.SW_NO_ERROR) { + return length; + } + if (Util.arrayCompare(outputBuffer, outputOffset, outputBuffer, (short)(outputOffset + ecdhLength), ecdhLength) != 0) { + sw = ECTesterApplet.SW_DH_DHC_MISMATCH; + } + return length; + + } + /** * Uses {@code signKey} to sign data from {@code inputBuffer} at {@code inputOffset} with {@code inputOffset}. * Then checks for correct signature length. diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index f9fb5da..98f59c4 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -63,6 +63,7 @@ public class ECTesterApplet extends Applet { // STATUS WORDS public static final short SW_SIG_VERIFY_FAIL = (short) 0x0ee1; + public static final short SW_DH_DHC_MISMATCH = (short) 0x0ee2; private static final short ARRAY_LENGTH = (short) 0xff; @@ -556,7 +557,7 @@ public class ECTesterApplet extends Applet { secretLength = keyTester.testECDHC((ECPrivateKey) priv.getPrivate(), (ECPublicKey) pub.getPublic(), ramArray, (short) 0, ramArray2, (short) 0, corruption); break; case EC_Consts.KA_BOTH: - // TODO + secretLength = keyTester.testKA((ECPrivateKey) priv.getPrivate(), (ECPublicKey) pub.getPublic(), ramArray, (short) 0, ramArray2, (short) 0, corruption); break; default: ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); @@ -589,7 +590,7 @@ public class ECTesterApplet extends Applet { short dataLength = Util.getShort(buffer, inOffset); if (dataLength == 0) { //no data to sign //generate random - dataLength = 32; + dataLength = 64; randomData.generateData(ramArray, (short) 0, dataLength); } else { Util.arrayCopyNonAtomic(buffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength); @@ -636,9 +637,21 @@ public class ECTesterApplet extends Applet { */ private short support(byte[] buffer, short offset) { - Util.setShort(buffer, offset, ecdhSW); - Util.setShort(buffer, (short) (offset+2), ecdhcSW); - Util.setShort(buffer, (short) (offset+4), ecdsaSW); + if (keyTester.hasECDH()) { + Util.setShort(buffer, offset, ecdhSW); + } else { + Util.setShort(buffer, offset, ISO7816.SW_INS_NOT_SUPPORTED); + } + if (keyTester.hasECDHC()) { + Util.setShort(buffer, (short) (offset+2), ecdhcSW); + } else { + Util.setShort(buffer, (short) (offset+2), ISO7816.SW_INS_NOT_SUPPORTED); + } + if (keyTester.hasECDSA()) { + Util.setShort(buffer, (short) (offset+4), ecdsaSW); + } else { + Util.setShort(buffer, (short) (offset+4), ISO7816.SW_INS_NOT_SUPPORTED); + } return 6; } diff --git a/src/cz/crcs/ectester/data/EC_Category.java b/src/cz/crcs/ectester/data/EC_Category.java deleted file mode 100644 index 57d9ca3..0000000 --- a/src/cz/crcs/ectester/data/EC_Category.java +++ /dev/null @@ -1,72 +0,0 @@ -package cz.crcs.ectester.data; - -import cz.crcs.ectester.reader.ec.EC_Data; -import cz.crcs.ectester.reader.ec.EC_Params; - -import java.util.Collections; -import java.util.TreeMap; -import java.util.Map; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class EC_Category { - - private String name; - private String directory; - private String desc; - - private Map objects; - - - public EC_Category(String name, String directory) { - this.name = name; - this.directory = directory; - } - - public EC_Category(String name, String directory, String desc) { - this(name, directory); - this.desc = desc; - } - - public EC_Category(String name, String directory, String desc, Map objects) { - this(name, directory, desc); - this.objects = objects; - } - - public String getName() { - return name; - } - - public String getDirectory() { - return directory; - } - - public String getDesc() { - return desc; - } - - public Map getObjects() { - return Collections.unmodifiableMap(objects); - } - - public Map getObjects(Class cls) { - Map objs = new TreeMap<>(); - for (Map.Entry entry : objects.entrySet()) { - if (cls.isInstance(entry.getValue())) { - objs.put(entry.getKey(), cls.cast(entry.getValue())); - } - } - return Collections.unmodifiableMap(objs); - } - - public T getObject(Class cls, String id) { - EC_Data obj = objects.get(id); - if (cls.isInstance(obj)) { - return cls.cast(obj); - } else { - return null; - } - } - -} diff --git a/src/cz/crcs/ectester/data/EC_Store.java b/src/cz/crcs/ectester/data/EC_Store.java index abf0a9b..0571cd8 100644 --- a/src/cz/crcs/ectester/data/EC_Store.java +++ b/src/cz/crcs/ectester/data/EC_Store.java @@ -8,8 +8,10 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; +import org.xml.sax.ext.EntityResolver2; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; @@ -17,10 +19,10 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Collections; -import java.util.HashMap; import java.util.Map; import java.util.TreeMap; @@ -61,6 +63,25 @@ public class EC_Store { throw new SAXException(exception); } }); + db.setEntityResolver(new EntityResolver2() { + @Override + public InputSource getExternalSubset(String name, String baseURI) throws SAXException, IOException { + return null; + } + + @Override + public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) throws SAXException, IOException { + InputSource is = new InputSource(); + is.setSystemId(systemId); + is.setByteStream(getClass().getClass().getResourceAsStream("/cz/crcs/ectester/data/" + systemId)); + return is; + } + + @Override + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + return null; + } + }); parse(); } catch (ParserConfigurationException | SAXException e) { @@ -80,7 +101,7 @@ public class EC_Store { NodeList catList = categoriesDoc.getElementsByTagName("category"); - this.categories = new HashMap<>(catList.getLength()); + this.categories = new TreeMap<>(); for (int i = 0; i < catList.getLength(); ++i) { Node catNode = catList.item(i); if (catNode instanceof Element) { @@ -115,7 +136,6 @@ public class EC_Store { Node id = curveElem.getElementsByTagName("id").item(0); Node bits = curveElem.getElementsByTagName("bits").item(0); Node field = curveElem.getElementsByTagName("field").item(0); - Node file = curveElem.getElementsByTagName("file").item(0); NodeList descc = curveElem.getElementsByTagName("desc"); String descs = null; @@ -132,7 +152,9 @@ public class EC_Store { short bitsize = Short.parseShort(bits.getTextContent()); EC_Curve curve = new EC_Curve(bitsize, alg, descs); - if (!curve.readCSV(this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/" + file.getTextContent()))) { + + InputStream csv = parseDataElement(dir, curveElem); + if (!curve.readCSV(csv)) { throw new IOException("Invalid csv data."); } @@ -194,7 +216,6 @@ public class EC_Store { Node id = elem.getElementsByTagName("id").item(0); Node ka = elem.getElementsByTagName("ka").item(0); - Node file = elem.getElementsByTagName("file").item(0); Node curve = elem.getElementsByTagName("curve").item(0); Node onekey = elem.getElementsByTagName("onekey").item(0); Node otherkey = elem.getElementsByTagName("otherkey").item(0); @@ -213,7 +234,9 @@ public class EC_Store { } EC_KAResult kaResult = new EC_KAResult(kab, curve.getTextContent(), onekey.getTextContent(), otherkey.getTextContent(), descs); - if (!kaResult.readCSV(this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/" + file.getTextContent()))) { + + InputStream csv = parseDataElement(dir, elem); + if (!kaResult.readCSV(csv)) { throw new IOException("Invalid csv data."); } @@ -248,12 +271,29 @@ public class EC_Store { } else { throw new SAXException("?"); } - if (!result.readCSV(this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/" + file.getTextContent()))) { + + InputStream csv = parseDataElement(dir, elem); + if (!result.readCSV(csv)) { throw new IOException("Invalid CSV data."); } return result; } + private InputStream parseDataElement(String dir, Element elem) throws SAXException { + NodeList file = elem.getElementsByTagName("file"); + NodeList inline = elem.getElementsByTagName("inline"); + + InputStream csv; + if (file.getLength() == 1) { + csv = this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/" + file.item(0).getTextContent()); + } else if (inline.getLength() == 1) { + csv = new ByteArrayInputStream(inline.item(0).getTextContent().getBytes()); + } else { + throw new SAXException("?"); + } + return csv; + } + public Map getCategories() { return Collections.unmodifiableMap(categories); } diff --git a/src/cz/crcs/ectester/data/categories.xml b/src/cz/crcs/ectester/data/categories.xml index 100d962..29dcba0 100644 --- a/src/cz/crcs/ectester/data/categories.xml +++ b/src/cz/crcs/ectester/data/categories.xml @@ -31,6 +31,11 @@ wrong Wrong field curves. These should definitely give an error when used. Since the "prime" used for the field are not prime, and the field polynomials are also not irreducible. Simply put these parameters don't specify a valid elliptic curve. + + invalid + invalid + + test test diff --git a/src/cz/crcs/ectester/data/invalid/brainpool/keys.xml b/src/cz/crcs/ectester/data/invalid/brainpool/keys.xml new file mode 100644 index 0000000..985fab6 --- /dev/null +++ b/src/cz/crcs/ectester/data/invalid/brainpool/keys.xml @@ -0,0 +1,108 @@ + + + 160r1-1 + 0xc4d7ddb433381eeb0c62b502b4059e616caf6fcf,0x0 + brainpool/brainpoolP160r1 + invalid order = 2 + + + +160r1-2 +0x55303e73394b0da59a85f48ad0ba78deee2df5d8,0x2874a5d9c08777c1151c87cd6d0577842ea68e13 +brainpool/brainpoolP160r1 +invalid order = 3 + + + +160r1-3 +0x4381828db3ae0c10a51074929b60700f87b0337b,0x2a2a76a4af0a96106ba6fe9d2496f1908edd2a23 +brainpool/brainpoolP160r1 +invalid order = 5 + + + +160r1-4 +0x68f115185e91815d9259714e7a7154300b8db314,0x3784f206684eb6c8c252ea4fe5453ff37b93eaf9 +brainpool/brainpoolP160r1 +invalid order = 7 + + + +160r1-5 +0xcc521e5a0366ee48cc37e757b994afee2452015e,0x93e0e6c648b0f0b2e354425025041345beb35b3c +brainpool/brainpoolP160r1 +invalid order = 11 + + + +160r1-6 +0x2b4d92bf08d99b87767e40f46ba4ad3dc21e2302,0x72f3e483e7b2c562fba12bad2402a411af02a15c +brainpool/brainpoolP160r1 +invalid order = 13 + + + +160r1-7 +0x1397bfed0edd4c38019af46c6864d106bc1c7241,0xa78a13e065701c31796231ceeb2200b4459c92ad +brainpool/brainpoolP160r1 +invalid order = 17 + + + +160r1-8 +0x448604062905058037d0776f0111e25d44b1abe3,0x1337a58bb32dd2c34355b47dedce2014b53cb832 +brainpool/brainpoolP160r1 +invalid order = 19 + + + +160r1-9 +0x64d734b3bf25c6546b963b43ece33fdc9347e66b,0xc311a5ed6b51380cada8c5c6658b633c4e40169e +brainpool/brainpoolP160r1 +invalid order = 23 + + + +160r1-10 +0x77c06cb540d349ebe61218241deb813c591f0509,0xd7eb002458fa0c38ae3528c9b3ec5e1117a84ff8 +brainpool/brainpoolP160r1 +invalid order = 29 + + + +160r1-11 +0xbefde0dd07cb3ef5d189b15fd129ec564d194cf3,0x55106a2379e3eef9010f4d11239ea0d83039cb66 +brainpool/brainpoolP160r1 +invalid order = 31 + + + +160r1-12 +0xe54d642cd1c68d018db437fb624b3595a5a9588c,0xae6165d75eec8e22072a0d7b800eae804e9b4136 +brainpool/brainpoolP160r1 +invalid order = 37 + + + +160r1-13 +0x60d871f4fde332d00e183381d0e3cbbc586dcb80,0x10a9f5e2a238ab38a743f52645dbbff2b250a34a +brainpool/brainpoolP160r1 +invalid order = 41 + + + +160r1-14 +0x7e2901c9f5610e4230aa7a53e8553426073458e4,0x3ac1810d4beb3244d62343ea40a23324b67b442 +brainpool/brainpoolP160r1 +invalid order = 43 + + + +160r1-15 +0x6b4d7bd164a2fb9fbb835a5ad5ee70adecf0cb37,0x22096241d3ec1f1ec072e10a04a731380fdedab5 +brainpool/brainpoolP160r1 +invalid order = 47 + + + + diff --git a/src/cz/crcs/ectester/data/invalid/curves.xml b/src/cz/crcs/ectester/data/invalid/curves.xml deleted file mode 100644 index e87269f..0000000 --- a/src/cz/crcs/ectester/data/invalid/curves.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/invalid/keys.xml b/src/cz/crcs/ectester/data/invalid/keys.xml new file mode 100644 index 0000000..9048518 --- /dev/null +++ b/src/cz/crcs/ectester/data/invalid/keys.xml @@ -0,0 +1,14 @@ + + + + + ]> + + &brainpool; + &nist; + &secg; + \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/invalid/nist/keys.xml b/src/cz/crcs/ectester/data/invalid/nist/keys.xml new file mode 100644 index 0000000..5427845 --- /dev/null +++ b/src/cz/crcs/ectester/data/invalid/nist/keys.xml @@ -0,0 +1,6 @@ + + 160r1-1 + 0xc4d7ddb433381eeb0c62b502b4059e616caf6fcf,0x0 + brainpool/brainpoolP160r1 + order = 2 + diff --git a/src/cz/crcs/ectester/data/invalid/secg/keys.xml b/src/cz/crcs/ectester/data/invalid/secg/keys.xml new file mode 100644 index 0000000..5427845 --- /dev/null +++ b/src/cz/crcs/ectester/data/invalid/secg/keys.xml @@ -0,0 +1,6 @@ + + 160r1-1 + 0xc4d7ddb433381eeb0c62b502b4059e616caf6fcf,0x0 + brainpool/brainpoolP160r1 + order = 2 + diff --git a/src/cz/crcs/ectester/data/schema.xsd b/src/cz/crcs/ectester/data/schema.xsd index 8f9427d..33b9acd 100644 --- a/src/cz/crcs/ectester/data/schema.xsd +++ b/src/cz/crcs/ectester/data/schema.xsd @@ -1,5 +1,5 @@ - @@ -11,12 +11,16 @@ + + + + - + @@ -34,7 +38,7 @@ - + @@ -65,7 +69,7 @@ - + diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java index cb3d298..6965d14 100644 --- a/src/cz/crcs/ectester/reader/ECTester.java +++ b/src/cz/crcs/ectester/reader/ECTester.java @@ -23,7 +23,6 @@ package cz.crcs.ectester.reader; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.data.EC_Category; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.ec.*; import javacard.security.KeyPair; @@ -468,70 +467,18 @@ public class ECTester { if (optListNamed == null) { // print all categories, briefly for (EC_Category cat : categories.values()) { - System.out.println("\t- " + cat.getName() + ": " + (cat.getDesc() == null ? "" : cat.getDesc())); - - Map curves = cat.getObjects(EC_Curve.class); - int size = curves.size(); - if (size > 0) { - System.out.print("\t\tCurves: "); - for (Map.Entry curve : curves.entrySet()) { - System.out.print(curve.getKey()); - size--; - if (size > 0) - System.out.print(", "); - } - System.out.println(); - } - - Map keys = cat.getObjects(EC_Key.class); - size = keys.size(); - if (size > 0) { - System.out.print("\t\tKeys: "); - for (Map.Entry key : keys.entrySet()) { - System.out.print(key.getKey()); - size--; - if (size > 0) - System.out.print(", "); - } - System.out.println(); - } - - Map keypairs = cat.getObjects(EC_Keypair.class); - size = keypairs.size(); - if (size > 0) { - System.out.print("\t\tKeypairs: "); - for (Map.Entry key : keypairs.entrySet()) { - System.out.print(key.getKey()); - size--; - if (size > 0) - System.out.print(", "); - } - System.out.println(); - } - - Map results = cat.getObjects(EC_KAResult.class); - size = results.size(); - if (size > 0) { - System.out.print("\t\tResults: "); - for (Map.Entry result : results.entrySet()) { - System.out.print(result.getKey()); - size--; - if (size > 0) - System.out.print(", "); - } - System.out.println(); - } - - System.out.println(); + System.out.println(cat); } } else if (categories.containsKey(optListNamed)) { // print given category - //TODO + System.out.println(categories.get(optListNamed)); } else { // print given object EC_Data object = dataStore.getObject(EC_Data.class, optListNamed); if (object != null) { System.out.println(object); + } else { + System.err.println("Named object " + optListNamed + " not found!"); } } } @@ -562,9 +509,9 @@ public class ECTester { // Cofactor generally isn't set on the default curve parameters on cards, // since its not necessary for ECDH, only ECDHC which not many cards implement // TODO: check if its assumend to be == 1? - short domain_all = optPrimeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; - short domain = (short) (domain_all ^ EC_Consts.PARAMETER_K); - Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain_all).send(); + short domainAll = optPrimeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; + short domain = (short) (domainAll ^ EC_Consts.PARAMETER_K); + Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domainAll).send(); if (!export.successful()) { export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send(); } @@ -722,12 +669,13 @@ public class ECTester { // These tests are dangerous, prompt before them. 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):"); + System.out.print("Do you want to proceed? (y/n): "); Scanner in = new Scanner(System.in); String confirmation = in.nextLine(); if (!Arrays.asList("yes", "y", "Y").contains(confirmation)) { return; } + in.close(); if (optTestSuite.equals("wrong")) { /* Just do the default tests on the wrong curves. @@ -750,20 +698,35 @@ public class ECTester { 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_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.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL)); + 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 (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."); + /* Set original curves (secg/nist/brainpool). Generate local. + * Try ECDH with invalid public keys of increasing (or decreasing) order. + */ + Map pubkeys = dataStore.getObjects(EC_Key.Public.class, "invalid"); + for (EC_Key.Public key : pubkeys.values()) { + EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve()); + if (optNamedCurve != null && !(key.getCurve().startsWith(optNamedCurve) || key.getCurve().equals(optNamedCurve))) { + continue; + } + if (curve.getBits() != optBits && !optAll) { + continue; + } + commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField())); + commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten())); + commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL)); + 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_BOTH)); + //commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDHC)); + commands.add(new Command.Cleanup(cardManager)); + + } } } @@ -771,14 +734,6 @@ public class ECTester { List test = Command.sendAll(commands); systemOutLogger.println(Response.toString(test, optTestSuite)); - for (Response response : test) { - if (response instanceof Response.ECDH) { - Response.ECDH ecdh = (Response.ECDH) response; - if (ecdh.hasSecret()) { - System.out.println(Util.bytesToHex(ecdh.getSecret(), false)); - } - } - } } /** @@ -1039,9 +994,8 @@ public class ECTester { } /** - * * @return - * @throws IOException if an IO error occurs when writing to key file. + * @throws IOException if an IO error occurs when writing to key file. */ private List testCurve() throws IOException { List commands = new LinkedList<>(); @@ -1056,11 +1010,10 @@ public class ECTester { } /** - * * @param category * @param field * @return - * @throws IOException if an IO error occurs when writing to key file. + * @throws IOException if an IO error occurs when writing to key file. */ private List testCurves(String category, byte field) throws IOException { List commands = new LinkedList<>(); diff --git a/src/cz/crcs/ectester/reader/Response.java b/src/cz/crcs/ectester/reader/Response.java index c3f2fe4..ee27260 100644 --- a/src/cz/crcs/ectester/reader/Response.java +++ b/src/cz/crcs/ectester/reader/Response.java @@ -137,7 +137,7 @@ public abstract class Response { if (prefix != null) out.append(prefix); - out.append(String.format("%-58s:%4d ms : %s", message, r.time / 1000000, suffix)); + out.append(String.format("%-62s:%4d ms : %s", message, r.time / 1000000, suffix)); if (i < responses.size() - 1) { out.append("\n"); } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Category.java b/src/cz/crcs/ectester/reader/ec/EC_Category.java new file mode 100644 index 0000000..a0c8755 --- /dev/null +++ b/src/cz/crcs/ectester/reader/ec/EC_Category.java @@ -0,0 +1,128 @@ +package cz.crcs.ectester.reader.ec; + +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class EC_Category { + + private String name; + private String directory; + private String desc; + + private Map objects; + + + public EC_Category(String name, String directory) { + this.name = name; + this.directory = directory; + } + + public EC_Category(String name, String directory, String desc) { + this(name, directory); + this.desc = desc; + } + + public EC_Category(String name, String directory, String desc, Map objects) { + this(name, directory, desc); + this.objects = objects; + } + + public String getName() { + return name; + } + + public String getDirectory() { + return directory; + } + + public String getDesc() { + return desc; + } + + public Map getObjects() { + return Collections.unmodifiableMap(objects); + } + + public Map getObjects(Class cls) { + Map objs = new TreeMap<>(); + for (Map.Entry entry : objects.entrySet()) { + if (cls.isInstance(entry.getValue())) { + objs.put(entry.getKey(), cls.cast(entry.getValue())); + } + } + return Collections.unmodifiableMap(objs); + } + + public T getObject(Class cls, String id) { + EC_Data obj = objects.get(id); + if (cls.isInstance(obj)) { + return cls.cast(obj); + } else { + return null; + } + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + out.append("\t- ").append(name).append((desc == null || desc.equals("")) ? "" : ": " + desc); + out.append(System.lineSeparator()); + + Map curves = getObjects(EC_Curve.class); + int size = curves.size(); + if (size > 0) { + out.append("\t\tCurves: "); + for (Map.Entry curve : curves.entrySet()) { + out.append(curve.getKey()); + size--; + if (size > 0) + out.append(", "); + } + out.append(System.lineSeparator()); + } + + Map keys = getObjects(EC_Key.class); + size = keys.size(); + if (size > 0) { + out.append("\t\tKeys: "); + for (Map.Entry key : keys.entrySet()) { + out.append(key.getKey()); + size--; + if (size > 0) + out.append(", "); + } + out.append(System.lineSeparator()); + } + + Map keypairs = getObjects(EC_Keypair.class); + size = keypairs.size(); + if (size > 0) { + out.append("\t\tKeypairs: "); + for (Map.Entry key : keypairs.entrySet()) { + out.append(key.getKey()); + size--; + if (size > 0) + out.append(", "); + } + out.append(System.lineSeparator()); + } + + Map results = getObjects(EC_KAResult.class); + size = results.size(); + if (size > 0) { + out.append("\t\tResults: "); + for (Map.Entry result : results.entrySet()) { + out.append(result.getKey()); + size--; + if (size > 0) + out.append(", "); + } + out.append(System.lineSeparator()); + } + return out.toString(); + } +} diff --git a/src/cz/crcs/ectester/reader/ec/EC_Curve.java b/src/cz/crcs/ectester/reader/ec/EC_Curve.java index 953884f..9b783ec 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Curve.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Curve.java @@ -43,6 +43,6 @@ public class EC_Curve extends EC_Params { @Override public String toString() { - return "Elliptic curve (" + String.valueOf(bits) + "b): " + desc; + return "Elliptic curve (" + String.valueOf(bits) + "b)" + (desc == null ? "" : ": " + desc); } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java b/src/cz/crcs/ectester/reader/ec/EC_KAResult.java index f1be49a..1385f12 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java +++ b/src/cz/crcs/ectester/reader/ec/EC_KAResult.java @@ -50,7 +50,7 @@ public class EC_KAResult extends EC_Data { @Override public String toString() { String agreement = ka == EC_Consts.KA_ECDH ? "ECDH" : "ECDHC"; - return agreement + " over " + curve + ", " + oneKey + " + " + otherKey + ": " + desc; + return agreement + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc); } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Key.java b/src/cz/crcs/ectester/reader/ec/EC_Key.java index 983ffa8..ad846b8 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Key.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Key.java @@ -40,7 +40,7 @@ public class EC_Key extends EC_Params { @Override public String toString() { - return "EC Public key, over " + getCurve() + ": " + getDesc(); + return "EC Public key, over " + getCurve() + (getDesc() == null ? "" : ": " + getDesc()); } } @@ -56,7 +56,7 @@ public class EC_Key extends EC_Params { @Override public String toString() { - return "EC Private key, over " + getCurve() + ": " + getDesc(); + return "EC Private key, over " + getCurve() + (getDesc() == null ? "" : ": " + getDesc()); } } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java b/src/cz/crcs/ectester/reader/ec/EC_Keypair.java index af4038a..bf87e9e 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Keypair.java @@ -30,6 +30,6 @@ public class EC_Keypair extends EC_Params { @Override public String toString() { - return "EC Keypair, over " + curve + ": " + desc; + return "EC Keypair, over " + curve + (desc == null ? "" : ": " + desc); } } -- cgit v1.3.1 From a7eef06134bef0861e43261640d61153ebb2a6e5 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 19 Apr 2017 01:10:17 +0200 Subject: Refactor testing, add Config class, make EC_Data read bytes - The ECTester.Config class now stores and reads all CLI options - Testing with the -t / --test option was partially refactored into: - Test: Encapsulates one Command and Response pair with expected result, a real result and a callback to dynamically assign result - TestSuite: Encapsulates a bunch of tests, represents a whole category of tests either that can be run on any curve or only on some. --- !uploader/ectester.cap | Bin 14053 -> 14353 bytes dist/ECTester.jar | Bin 295880 -> 322457 bytes src/cz/crcs/ectester/applet/ECKeyGenerator.java | 32 +- src/cz/crcs/ectester/applet/ECKeyTester.java | 49 +- src/cz/crcs/ectester/applet/ECTesterApplet.java | 7 +- src/cz/crcs/ectester/applet/ECUtil.java | 17 + src/cz/crcs/ectester/data/EC_Store.java | 8 +- src/cz/crcs/ectester/reader/ECTester.java | 666 +++++++++++------------- src/cz/crcs/ectester/reader/Response.java | 106 ++-- src/cz/crcs/ectester/reader/Test.java | 81 +++ src/cz/crcs/ectester/reader/TestSuite.java | 167 ++++++ src/cz/crcs/ectester/reader/Util.java | 82 ++- src/cz/crcs/ectester/reader/ec/EC_Curve.java | 10 +- src/cz/crcs/ectester/reader/ec/EC_Data.java | 40 +- src/cz/crcs/ectester/reader/ec/EC_KAResult.java | 13 +- src/cz/crcs/ectester/reader/ec/EC_Key.java | 10 + src/cz/crcs/ectester/reader/ec/EC_Keypair.java | 1 - src/cz/crcs/ectester/reader/ec/EC_Params.java | 28 +- 18 files changed, 854 insertions(+), 463 deletions(-) create mode 100644 src/cz/crcs/ectester/applet/ECUtil.java create mode 100644 src/cz/crcs/ectester/reader/Test.java create mode 100644 src/cz/crcs/ectester/reader/TestSuite.java (limited to 'src/cz/crcs/ectester/reader/ec/EC_Curve.java') diff --git a/!uploader/ectester.cap b/!uploader/ectester.cap index 96d0c82..1e7235d 100644 Binary files a/!uploader/ectester.cap and b/!uploader/ectester.cap differ diff --git a/dist/ECTester.jar b/dist/ECTester.jar index 0126533..58f44b9 100644 Binary files a/dist/ECTester.jar and b/dist/ECTester.jar differ diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java index b412370..a36bd0c 100644 --- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java +++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java @@ -39,8 +39,8 @@ public class ECKeyGenerator { } public short clearPair(KeyPair keypair, byte key) { - sw = ISO7816.SW_NO_ERROR; try { + sw = ECUtil.nullCheck(keypair); if ((key & EC_Consts.KEY_PUBLIC) != 0) keypair.getPublic().clearKey(); if ((key & EC_Consts.KEY_PRIVATE) != 0) keypair.getPrivate().clearKey(); } catch (CardRuntimeException ce) { @@ -54,8 +54,8 @@ public class ECKeyGenerator { * @return */ public short generatePair(KeyPair keypair) { - sw = ISO7816.SW_NO_ERROR; try { + sw = ECUtil.nullCheck(keypair); keypair.genKeyPair(); } catch (CardRuntimeException ce) { sw = ce.getReason(); @@ -155,11 +155,12 @@ public class ECKeyGenerator { * @return */ public short setParameter(KeyPair keypair, byte key, short param, byte[] data, short offset, short length) { - sw = ISO7816.SW_NO_ERROR; - ECPublicKey ecPublicKey = (ECPublicKey) keypair.getPublic(); - ECPrivateKey ecPrivateKey = (ECPrivateKey) keypair.getPrivate(); - try { + sw = ECUtil.nullCheck(keypair); + + ECPublicKey ecPublicKey = (ECPublicKey) keypair.getPublic(); + ECPrivateKey ecPrivateKey = (ECPrivateKey) keypair.getPrivate(); + switch (param) { case EC_Consts.PARAMETER_FP: if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldFP(data, offset, length); @@ -174,8 +175,11 @@ public class ECKeyGenerator { short i1 = Util.makeShort(data[(short) (offset + 2)], data[(short) (offset + 3)]); short i2 = Util.makeShort(data[(short) (offset + 4)], data[(short) (offset + 5)]); short i3 = Util.makeShort(data[(short) (offset + 6)], data[(short) (offset + 7)]); - if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3); - if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3); +// if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3); +// if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3); + // TODO fix this + if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i3, i2, i1); + if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i3, i2, i1); } else { sw = ISO7816.SW_UNKNOWN; } @@ -275,12 +279,12 @@ public class ECKeyGenerator { * @return length of data written */ public short exportParameter(KeyPair keypair, byte key, short param, byte[] outputBuffer, short outputOffset) { - sw = ISO7816.SW_NO_ERROR; - ECPublicKey ecPublicKey = (ECPublicKey) keypair.getPublic(); - ECPrivateKey ecPrivateKey = (ECPrivateKey) keypair.getPrivate(); - short length = 0; try { + sw = ECUtil.nullCheck(keypair); + ECPublicKey ecPublicKey = (ECPublicKey) keypair.getPublic(); + ECPrivateKey ecPrivateKey = (ECPrivateKey) keypair.getPrivate(); + switch (param) { case EC_Consts.PARAMETER_FP: if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getField(outputBuffer, outputOffset); @@ -385,8 +389,10 @@ public class ECKeyGenerator { * @return sw */ public short copyCurve(KeyPair from, KeyPair to, short params, byte[] buffer, short offset) { - sw = ISO7816.SW_NO_ERROR; try { + sw = ECUtil.nullCheck(from); + sw = ECUtil.nullCheck(to); + short param = EC_Consts.PARAMETER_FP; while (param <= EC_Consts.PARAMETER_K) { short masked = (short) (param & params); diff --git a/src/cz/crcs/ectester/applet/ECKeyTester.java b/src/cz/crcs/ectester/applet/ECKeyTester.java index 64f3024..c4b58e0 100644 --- a/src/cz/crcs/ectester/applet/ECKeyTester.java +++ b/src/cz/crcs/ectester/applet/ECKeyTester.java @@ -4,10 +4,7 @@ package cz.crcs.ectester.applet; import javacard.framework.CardRuntimeException; import javacard.framework.ISO7816; import javacard.framework.Util; -import javacard.security.ECPrivateKey; -import javacard.security.ECPublicKey; -import javacard.security.KeyAgreement; -import javacard.security.Signature; +import javacard.security.*; /** * Class capable of testing ECDH/C and ECDSA. @@ -53,11 +50,15 @@ public class ECKeyTester { return sw; } - private short testKA(KeyAgreement ka, ECPrivateKey privateKey, byte[] pubkeyBuffer, short pubkeyOffset, short pubkeyLength, byte[] outputBuffer, short outputOffset) { - sw = ISO7816.SW_NO_ERROR; + private short testKA(KeyAgreement ka, KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, byte corruption) { short length = 0; try { - ka.init(privateKey); + sw = ECUtil.nullCheck(privatePair); + sw = ECUtil.nullCheck(publicPair); + + ka.init(privatePair.getPrivate()); + short pubkeyLength = ((ECPublicKey) publicPair.getPublic()).getW(pubkeyBuffer, pubkeyOffset); + pubkeyLength = EC_Consts.corruptParameter(corruption, pubkeyBuffer, pubkeyOffset, pubkeyLength); length = ka.generateSecret(pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset); } catch (CardRuntimeException ce) { sw = ce.getReason(); @@ -66,12 +67,12 @@ public class ECKeyTester { } /** - * Tests ECDH secret generation with given {@code privateKey} and {@code publicKey}. + * Tests ECDH secret generation with keys from given {@code privatePair} and {@code publicPair}. * Uses {@code pubkeyBuffer} at {@code pubkeyOffset} for computations. * Output should equal with ECDHC output. * - * @param privateKey - * @param publicKey + * @param privatePair + * @param publicPair * @param pubkeyBuffer * @param pubkeyOffset * @param outputBuffer @@ -79,19 +80,17 @@ public class ECKeyTester { * @param corruption * @return derived secret length **/ - public short testECDH(ECPrivateKey privateKey, ECPublicKey publicKey, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, byte corruption) { - short length = publicKey.getW(pubkeyBuffer, pubkeyOffset); - length = EC_Consts.corruptParameter(corruption, pubkeyBuffer, pubkeyOffset, length); - return testKA(ecdhKeyAgreement, privateKey, pubkeyBuffer, pubkeyOffset, length, outputBuffer, outputOffset); + public short testECDH(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, byte corruption) { + return testKA(ecdhKeyAgreement, privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption); } /** - * Tests ECDHC secret generation with given {@code privateKey} and {@code publicKey}. + * Tests ECDHC secret generation with keys from given {@code privatePair} and {@code publicPair}. * Uses {@code pubkeyBuffer} at {@code pubkeyOffset} for computations. * Output should equal to ECDH output. * - * @param privateKey - * @param publicKey + * @param privatePair + * @param publicPair * @param pubkeyBuffer * @param pubkeyOffset * @param outputBuffer @@ -99,16 +98,14 @@ public class ECKeyTester { * @param corruption * @return derived secret length */ - public short testECDHC(ECPrivateKey privateKey, ECPublicKey publicKey, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, byte corruption) { - short length = publicKey.getW(pubkeyBuffer, pubkeyOffset); - length = EC_Consts.corruptParameter(corruption, pubkeyBuffer, pubkeyOffset, length); - return testKA(ecdhcKeyAgreement, privateKey, pubkeyBuffer, pubkeyOffset, length, outputBuffer, outputOffset); + public short testECDHC(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, byte corruption) { + return testKA(ecdhcKeyAgreement, privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption); } /** * - * @param privateKey - * @param publicKey + * @param privatePair + * @param publicPair * @param pubkeyBuffer * @param pubkeyOffset * @param outputBuffer @@ -116,12 +113,12 @@ public class ECKeyTester { * @param corruption * @return */ - public short testKA(ECPrivateKey privateKey, ECPublicKey publicKey, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, byte corruption) { - short ecdhLength = testECDH(privateKey, publicKey, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption); + public short testECDH_ECDHC(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, byte corruption) { + short ecdhLength = testECDH(privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption); if (sw != ISO7816.SW_NO_ERROR) { return ecdhLength; } - short ecdhcLength = testECDHC(privateKey, publicKey, pubkeyBuffer, pubkeyOffset, outputBuffer, (short) (outputOffset + ecdhLength), corruption); + short ecdhcLength = testECDHC(privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, (short) (outputOffset + ecdhLength), corruption); short length = (short) (ecdhLength + ecdhcLength); if (sw != ISO7816.SW_NO_ERROR) { return length; diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index 98f59c4..f802233 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -64,6 +64,7 @@ public class ECTesterApplet extends Applet { // STATUS WORDS public static final short SW_SIG_VERIFY_FAIL = (short) 0x0ee1; public static final short SW_DH_DHC_MISMATCH = (short) 0x0ee2; + public static final short SW_KEYPAIR_NULL = (short) 0x0ee3; private static final short ARRAY_LENGTH = (short) 0xff; @@ -551,13 +552,13 @@ public class ECTesterApplet extends Applet { short secretLength = 0; switch (type) { case EC_Consts.KA_ECDH: - secretLength = keyTester.testECDH((ECPrivateKey) priv.getPrivate(), (ECPublicKey) pub.getPublic(), ramArray, (short) 0, ramArray2, (short) 0, corruption); + secretLength = keyTester.testECDH(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption); break; case EC_Consts.KA_ECDHC: - secretLength = keyTester.testECDHC((ECPrivateKey) priv.getPrivate(), (ECPublicKey) pub.getPublic(), ramArray, (short) 0, ramArray2, (short) 0, corruption); + secretLength = keyTester.testECDHC(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption); break; case EC_Consts.KA_BOTH: - secretLength = keyTester.testKA((ECPrivateKey) priv.getPrivate(), (ECPublicKey) pub.getPublic(), ramArray, (short) 0, ramArray2, (short) 0, corruption); + secretLength = keyTester.testECDH_ECDHC(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption); break; default: ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); diff --git a/src/cz/crcs/ectester/applet/ECUtil.java b/src/cz/crcs/ectester/applet/ECUtil.java new file mode 100644 index 0000000..e7e4a8a --- /dev/null +++ b/src/cz/crcs/ectester/applet/ECUtil.java @@ -0,0 +1,17 @@ +package cz.crcs.ectester.applet; + +import javacard.framework.ISO7816; +import javacard.framework.ISOException; +import javacard.security.KeyPair; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class ECUtil { + + static short nullCheck(KeyPair keyPair) { + if (keyPair == null) + ISOException.throwIt(ECTesterApplet.SW_KEYPAIR_NULL); + return ISO7816.SW_NO_ERROR; + } +} diff --git a/src/cz/crcs/ectester/data/EC_Store.java b/src/cz/crcs/ectester/data/EC_Store.java index 0571cd8..ccd3586 100644 --- a/src/cz/crcs/ectester/data/EC_Store.java +++ b/src/cz/crcs/ectester/data/EC_Store.java @@ -151,12 +151,13 @@ public class EC_Store { } short bitsize = Short.parseShort(bits.getTextContent()); - EC_Curve curve = new EC_Curve(bitsize, alg, descs); + EC_Curve curve = new EC_Curve(id.getTextContent(), bitsize, alg, descs); InputStream csv = parseDataElement(dir, curveElem); if (!curve.readCSV(csv)) { throw new IOException("Invalid csv data."); } + csv.close(); objMap.put(id.getTextContent(), curve); } else { @@ -233,12 +234,13 @@ public class EC_Store { kab = EC_Consts.KA_ECDHC; } - EC_KAResult kaResult = new EC_KAResult(kab, curve.getTextContent(), onekey.getTextContent(), otherkey.getTextContent(), descs); + EC_KAResult kaResult = new EC_KAResult(id.getTextContent(), kab, curve.getTextContent(), onekey.getTextContent(), otherkey.getTextContent(), descs); InputStream csv = parseDataElement(dir, elem); if (!kaResult.readCSV(csv)) { throw new IOException("Invalid csv data."); } + csv.close(); objMap.put(id.getTextContent(), kaResult); } else { @@ -276,6 +278,8 @@ public class EC_Store { if (!result.readCSV(csv)) { throw new IOException("Invalid CSV data."); } + csv.close(); + return result; } diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java index 6965d14..8afda17 100644 --- a/src/cz/crcs/ectester/reader/ECTester.java +++ b/src/cz/crcs/ectester/reader/ECTester.java @@ -44,47 +44,7 @@ public class ECTester { private CardMngr cardManager; private DirtyLogger systemOutLogger; private EC_Store dataStore; - - //Options - private int optBits; - private boolean optAll; - private boolean optPrimeField = false; - private boolean optBinaryField = false; - - private String optNamedCurve = null; - private String optCurveFile = null; - private boolean optCustomCurve = false; - - private boolean optAnyPublic = false; - private String optNamedPublic = null; - private String optPublic = null; - - private boolean optAnyPrivate = false; - private String optNamedPrivate = null; - private String optPrivate = null; - - private boolean optAnyKey = false; - private String optNamedKey = null; - private String optKey = null; - - private boolean optAnyKeypart = false; - - private String optLog = null; - - private boolean optVerbose = false; - private String optInput = null; - private String optOutput = null; - private boolean optFresh = false; - private boolean optSimulate = false; - - //Action-related options - private String optListNamed; - private String optTestSuite; - private int optGenerateAmount; - private int optECDHCount; - private byte optECDHKA; - private int optECDSACount; - + private Config cfg; private Options opts = new Options(); private static final String CLI_HEADER = "\nECTester, a javacard Elliptic Curve Cryptograhy support tester/utility.\n\n"; @@ -104,8 +64,10 @@ public class ECTester { help(); return; } + cfg = new Config(); + //if not, read other options first, into attributes, then do action - if (!readOptions(cli)) { + if (!cfg.readOptions(cli)) { return; } @@ -117,10 +79,10 @@ public class ECTester { } //init CardManager - cardManager = new CardMngr(optVerbose, optSimulate); + cardManager = new CardMngr(cfg.verbose, cfg.simulate); //connect or simulate connection - if (optSimulate) { + if (cfg.simulate) { if (!cardManager.prepareLocalSimulatorApplet(AID, INSTALL_DATA, ECTesterApplet.class)) { System.err.println("Failed to establish a simulator."); System.exit(1); @@ -133,7 +95,7 @@ public class ECTester { cardManager.send(SELECT_ECTESTERAPPLET); } - systemOutLogger = new DirtyLogger(optLog, true); + systemOutLogger = new DirtyLogger(cfg.log, true); //do action if (cli.hasOption("export")) { @@ -208,7 +170,7 @@ public class ECTester { * -dh / --ecdh [count] * -dhc / --ecdhc [count] * -dsa / --ecdsa [count] - * -ln / --list-named + * -ln / --list-named [obj] * * Options: * -b / --bit-size // -a / --all @@ -291,194 +253,26 @@ public class ECTester { return parser.parse(opts, args); } - /** - * Reads and validates options, also sets defaults. - * - * @param cli cli object, with parsed args - * @return whether the options are valid. - */ - private boolean readOptions(CommandLine cli) { - optBits = Integer.parseInt(cli.getOptionValue("bit-size", "0")); - optAll = cli.hasOption("all"); - optPrimeField = cli.hasOption("fp"); - optBinaryField = cli.hasOption("f2m"); - - optNamedCurve = cli.getOptionValue("named-curve"); - optCustomCurve = cli.hasOption("custom"); - optCurveFile = cli.getOptionValue("curve"); - - optNamedPublic = cli.getOptionValue("named-public"); - optPublic = cli.getOptionValue("public"); - optAnyPublic = (optPublic != null) || (optNamedPublic != null); - - optNamedPrivate = cli.getOptionValue("named-private"); - optPrivate = cli.getOptionValue("private"); - optAnyPrivate = (optPrivate != null) || (optNamedPrivate != null); - - optNamedKey = cli.getOptionValue("named-key"); - optKey = cli.getOptionValue("key"); - optAnyKey = (optKey != null) || (optNamedKey != null); - optAnyKeypart = optAnyKey || optAnyPublic || optAnyPrivate; - - if (cli.hasOption("log")) { - optLog = cli.getOptionValue("log", String.format("ECTESTER_log_%d.log", System.currentTimeMillis() / 1000)); - } - - optVerbose = cli.hasOption("verbose"); - optInput = cli.getOptionValue("input"); - optOutput = cli.getOptionValue("output"); - optFresh = cli.hasOption("fresh"); - optSimulate = cli.hasOption("simulate"); - - if (cli.hasOption("list-named")) { - optListNamed = cli.getOptionValue("list-named"); - return true; - } - - if ((optKey != null || optNamedKey != null) && (optPublic != null || optPrivate != null || optNamedPublic != null || optNamedPrivate != null)) { - System.err.print("Can only specify the whole key with --key/--named-key or pubkey and privkey with --public/--named-public and --private/--named-private."); - return false; - } - if (optBits < 0) { - System.err.println("Bit-size must not be negative."); - return false; - } - if (optBits == 0 && !optAll) { - System.err.println("You must specify either bit-size with -b or all bit-sizes with -a."); - return false; - } - - if (optKey != null && optNamedKey != null || optPublic != null && optNamedPublic != null || optPrivate != null && optNamedPrivate != null) { - System.err.println("You cannot specify both a named key and a key file."); - return false; - } - - if (cli.hasOption("export")) { - if (optPrimeField == optBinaryField) { - System.err.print("Need to specify field with -fp or -f2m. (not both)"); - return false; - } - if (optAnyKeypart) { - System.err.println("Keys should not be specified when exporting curve params."); - return false; - } - if (optNamedCurve != null || optCustomCurve || optCurveFile != null) { - System.err.println("Specifying a curve for curve export makes no sense."); - return false; - } - if (optOutput == null) { - System.err.println("You have to specify an output file for curve parameter export."); - return false; - } - if (optAll) { - System.err.println("You have to specify curve bit-size with -b"); - return false; - } - - } else if (cli.hasOption("generate")) { - if (optPrimeField == optBinaryField) { - System.err.print("Need to specify field with -fp or -f2m. (not both)"); - return false; - } - if (optAnyKeypart) { - System.err.println("Keys should not be specified when generating keys."); - return false; - } - if (optOutput == null) { - System.err.println("You have to specify an output file for the key generation process."); - return false; - } - if (optAll) { - System.err.println("You have to specify curve bit-size with -b"); - return false; - } - - optGenerateAmount = Integer.parseInt(cli.getOptionValue("generate", "0")); - if (optGenerateAmount < 0) { - System.err.println("Amount of keys generated cant be negative."); - return false; - } - } else if (cli.hasOption("test")) { - if (!optBinaryField && !optPrimeField) { - optBinaryField = true; - optPrimeField = true; - } - - optTestSuite = cli.getOptionValue("test", "default").toLowerCase(); - String[] tests = new String[]{"default", "nonprime", "invalid", "test-vectors", "wrong"}; - List testsList = Arrays.asList(tests); - if (!testsList.contains(optTestSuite)) { - System.err.println("Unknown test case. Should be one of: " + Arrays.toString(tests)); - return false; - } - - } else if (cli.hasOption("ecdh") || cli.hasOption("ecdhc")) { - if (optPrimeField == optBinaryField) { - System.err.print("Need to specify field with -fp or -f2m. (not both)"); - return false; - } - if (optAll) { - System.err.println("You have to specify curve bit-size with -b"); - return false; - } - - if (cli.hasOption("ecdh")) { - optECDHCount = Integer.parseInt(cli.getOptionValue("ecdh", "1")); - optECDHKA = EC_Consts.KA_ECDH; - } else if (cli.hasOption("ecdhc")) { - optECDHCount = Integer.parseInt(cli.getOptionValue("ecdhc", "1")); - optECDHKA = EC_Consts.KA_ECDHC; - } - if (optECDHCount <= 0) { - System.err.println("ECDH count cannot be <= 0."); - return false; - } - - } else if (cli.hasOption("ecdsa")) { - if (optPrimeField == optBinaryField) { - System.err.print("Need to specify field with -fp or -f2m. (but not both)"); - return false; - } - if (optAll) { - System.err.println("You have to specify curve bit-size with -b"); - return false; - } - - if ((optAnyPublic) != (optAnyPrivate) && !optAnyKey) { - System.err.println("You cannot only specify a part of a keypair."); - return false; - } - - optECDSACount = Integer.parseInt(cli.getOptionValue("ecdsa", "1")); - if (optECDSACount <= 0) { - System.err.println("ECDSA count cannot be <= 0."); - return false; - } - } - - return true; - } - /** * List categories and named curves. */ private void list() { Map categories = dataStore.getCategories(); - if (optListNamed == null) { + if (cfg.listNamed == null) { // print all categories, briefly for (EC_Category cat : categories.values()) { System.out.println(cat); } - } else if (categories.containsKey(optListNamed)) { + } else if (categories.containsKey(cfg.listNamed)) { // print given category - System.out.println(categories.get(optListNamed)); + System.out.println(categories.get(cfg.listNamed)); } else { // print given object - EC_Data object = dataStore.getObject(EC_Data.class, optListNamed); + EC_Data object = dataStore.getObject(EC_Data.class, cfg.listNamed); if (object != null) { System.out.println(object); } else { - System.err.println("Named object " + optListNamed + " not found!"); + System.err.println("Named object " + cfg.listNamed + " not found!"); } } } @@ -499,17 +293,17 @@ public class ECTester { * @throws IOException if an IO error occurs when writing to key file. */ private void export() throws CardException, IOException { - byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; + byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; List sent = new LinkedList<>(); - sent.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass).send()); + sent.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send()); sent.add(new Command.Clear(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send()); sent.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send()); // Cofactor generally isn't set on the default curve parameters on cards, // since its not necessary for ECDH, only ECDHC which not many cards implement // TODO: check if its assumend to be == 1? - short domainAll = optPrimeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; + short domainAll = cfg.primeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; short domain = (short) (domainAll ^ EC_Consts.PARAMETER_K); Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domainAll).send(); if (!export.successful()) { @@ -521,7 +315,7 @@ public class ECTester { EC_Params exported = new EC_Params(domain, export.getParams()); - FileOutputStream out = new FileOutputStream(optOutput); + FileOutputStream out = new FileOutputStream(cfg.output); exported.writeCSV(out); out.close(); } @@ -533,18 +327,18 @@ public class ECTester { * @throws IOException if an IO error occurs when writing to key file. */ private void generate() throws CardException, IOException { - byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; + byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; - new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass).send(); - List curve = prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass); + new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send(); + List curve = prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass); - FileWriter keysFile = new FileWriter(optOutput); + FileWriter keysFile = new FileWriter(cfg.output); keysFile.write("index;time;pubW;privS\n"); int generated = 0; int retry = 0; - while (generated < optGenerateAmount || optGenerateAmount == 0) { - if (optFresh || generated == 0) { + while (generated < cfg.generateAmount || cfg.generateAmount == 0) { + if (cfg.fresh || generated == 0) { Command.sendAll(curve); } @@ -583,19 +377,20 @@ public class ECTester { */ private void test() throws IOException, CardException { List commands = new LinkedList<>(); + TestSuite suite = null; - if (optTestSuite.equals("default")) { + if (cfg.testSuite.equals("default")) { commands.add(new Command.Support(cardManager)); - if (optNamedCurve != null) { - if (optPrimeField) { - commands.addAll(testCurves(optNamedCurve, KeyPair.ALG_EC_FP)); + if (cfg.namedCurve != null) { + if (cfg.primeField) { + commands.addAll(testCurves(cfg.namedCurve, KeyPair.ALG_EC_FP)); } - if (optBinaryField) { - commands.addAll(testCurves(optNamedCurve, KeyPair.ALG_EC_F2M)); + if (cfg.binaryField) { + commands.addAll(testCurves(cfg.namedCurve, KeyPair.ALG_EC_F2M)); } } else { - if (optAll) { - if (optPrimeField) { + if (cfg.all) { + if (cfg.primeField) { //iterate over prime curve sizes used: EC_Consts.FP_SIZES for (short keyLength : EC_Consts.FP_SIZES) { commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP)); @@ -604,7 +399,7 @@ public class ECTester { commands.add(new Command.Cleanup(cardManager)); } } - if (optBinaryField) { + if (cfg.binaryField) { //iterate over binary curve sizes used: EC_Consts.F2M_SIZES for (short keyLength : EC_Consts.F2M_SIZES) { commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M)); @@ -614,60 +409,31 @@ public class ECTester { } } } else { - if (optPrimeField) { - commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_FP)); - commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_FP)); + if (cfg.primeField) { + commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, KeyPair.ALG_EC_FP)); + commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, KeyPair.ALG_EC_FP)); commands.addAll(testCurve()); commands.add(new Command.Cleanup(cardManager)); } - if (optBinaryField) { - commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_F2M)); - commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_F2M)); + if (cfg.binaryField) { + commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, KeyPair.ALG_EC_F2M)); + commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, KeyPair.ALG_EC_F2M)); commands.addAll(testCurve()); commands.add(new Command.Cleanup(cardManager)); } } } - } else if (optTestSuite.equals("test-vectors")) { + } else if (cfg.testSuite.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. * */ - Map 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()); - } - EC_Params otherkey = dataStore.getObject(EC_Keypair.class, result.getOtherKey()); - if (otherkey == null) { - otherkey = dataStore.getObject(EC_Key.Public.class, result.getOtherKey()); - } - if (onekey == null || otherkey == null) { - throw new IOException("Test vector keys not located"); - } - - commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField())); - commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten())); - commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH)); - commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S))); - commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W))); - commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getKA())); - //TODO add compare with result.getParam(0); - commands.add(new Command.Cleanup(cardManager)); - } + suite = new TestSuite.TestVectors(dataStore, cfg); } else { // These tests are dangerous, prompt before them. - System.out.println("The test you selected (" + optTestSuite + ") is potentially dangerous."); + System.out.println("The test you selected (" + cfg.testSuite + ") 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): "); Scanner in = new Scanner(System.in); @@ -677,62 +443,40 @@ public class ECTester { } in.close(); - if (optTestSuite.equals("wrong")) { + if (cfg.testSuite.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(optTestSuite, KeyPair.ALG_EC_FP)); + if (cfg.primeField) { + commands.addAll(testCurves(cfg.testSuite, KeyPair.ALG_EC_FP)); } - if (optBinaryField) { - commands.addAll(testCurves(optTestSuite, KeyPair.ALG_EC_F2M)); + if (cfg.binaryField) { + commands.addAll(testCurves(cfg.testSuite, KeyPair.ALG_EC_F2M)); } - } else if (optTestSuite.equals("nonprime")) { + } else if (cfg.testSuite.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 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.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten())); - commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL)); - 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 (optTestSuite.equals("invalid")) { + suite = new TestSuite.NonPrime(dataStore, cfg); + } else if (cfg.testSuite.equals("invalid")) { /* Set original curves (secg/nist/brainpool). Generate local. * Try ECDH with invalid public keys of increasing (or decreasing) order. */ - Map pubkeys = dataStore.getObjects(EC_Key.Public.class, "invalid"); - for (EC_Key.Public key : pubkeys.values()) { - EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve()); - if (optNamedCurve != null && !(key.getCurve().startsWith(optNamedCurve) || key.getCurve().equals(optNamedCurve))) { - continue; - } - if (curve.getBits() != optBits && !optAll) { - continue; - } - commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField())); - commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten())); - commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL)); - 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_BOTH)); - //commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDHC)); - commands.add(new Command.Cleanup(cardManager)); - - } + suite = new TestSuite.Invalid(dataStore, cfg); } } List test = Command.sendAll(commands); - systemOutLogger.println(Response.toString(test, optTestSuite)); + if (suite != null) { + List tests = suite.run(cardManager); + for (Test t : tests) { + System.out.println(t); + } + } + systemOutLogger.println(Response.toString(test, cfg.testSuite)); } @@ -743,34 +487,34 @@ public class ECTester { * @throws IOException if an IO error occurs when writing to key file. */ private void ecdh() throws IOException, CardException { - byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; + byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; List prepare = new LinkedList<>(); - prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass).send()); - prepare.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass))); + prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass).send()); + prepare.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass))); systemOutLogger.println(Response.toString(prepare)); - byte pubkey = (optAnyPublic || optAnyKey) ? ECTesterApplet.KEYPAIR_REMOTE : ECTesterApplet.KEYPAIR_LOCAL; - byte privkey = (optAnyPrivate || optAnyKey) ? ECTesterApplet.KEYPAIR_REMOTE : ECTesterApplet.KEYPAIR_LOCAL; + byte pubkey = (cfg.anyPublicKey || cfg.anyKey) ? ECTesterApplet.KEYPAIR_REMOTE : ECTesterApplet.KEYPAIR_LOCAL; + byte privkey = (cfg.anyPrivateKey || cfg.anyKey) ? ECTesterApplet.KEYPAIR_REMOTE : ECTesterApplet.KEYPAIR_LOCAL; List generate = new LinkedList<>(); generate.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH)); - if (optAnyPublic || optAnyPrivate || optAnyKey) { + if (cfg.anyPublicKey || cfg.anyPrivateKey || cfg.anyKey) { generate.add(prepareKey(ECTesterApplet.KEYPAIR_REMOTE)); } FileWriter out = null; - if (optOutput != null) { - out = new FileWriter(optOutput); + if (cfg.output != null) { + out = new FileWriter(cfg.output); out.write("index;time;secret\n"); } int retry = 0; int done = 0; - while (done < optECDHCount) { + while (done < cfg.ECDHCount) { List ecdh = Command.sendAll(generate); - Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, optECDHKA).send(); + Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, cfg.ECDHKA).send(); ecdh.add(perform); systemOutLogger.println(Response.toString(ecdh)); @@ -804,38 +548,38 @@ public class ECTester { private void ecdsa() throws CardException, IOException { //read file, if asked to sign byte[] data = null; - if (optInput != null) { - File in = new File(optInput); + if (cfg.input != null) { + File in = new File(cfg.input); long len = in.length(); if (len == 0) { - throw new FileNotFoundException(optInput); + throw new FileNotFoundException(cfg.input); } data = Files.readAllBytes(in.toPath()); } Command generate; - if (optAnyKeypart) { + if (cfg.anyKeypart) { generate = prepareKey(ECTesterApplet.KEYPAIR_LOCAL); } else { generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL); } - byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; + byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; List prepare = new LinkedList<>(); - prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass).send()); - prepare.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass))); + prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send()); + prepare.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass))); systemOutLogger.println(Response.toString(prepare)); FileWriter out = null; - if (optOutput != null) { - out = new FileWriter(optOutput); + if (cfg.output != null) { + out = new FileWriter(cfg.output); out.write("index;time;signature\n"); } int retry = 0; int done = 0; - while (done < optECDSACount) { + while (done < cfg.ECDSACount) { List ecdsa = new LinkedList<>(); ecdsa.add(generate.send()); @@ -873,14 +617,14 @@ public class ECTester { private List prepareCurve(byte keyPair, short keyLength, byte keyClass) throws IOException { List commands = new ArrayList<>(); - if (optCustomCurve) { + if (cfg.customCurve) { // Set custom curve (one of the SECG curves embedded applet-side) short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; commands.add(new Command.Set(cardManager, keyPair, EC_Consts.getCurve(keyLength, keyClass), domainParams, null)); - } else if (optNamedCurve != null) { + } else if (cfg.namedCurve != null) { // Set a named curve. - // parse optNamedCurve -> cat / id | cat | id - EC_Curve curve = dataStore.getObject(EC_Curve.class, optNamedCurve); + // parse cfg.namedCurve -> cat / id | cat | id + EC_Curve curve = dataStore.getObject(EC_Curve.class, cfg.namedCurve); if (curve == null) { throw new IOException("Curve could no be found."); } @@ -893,11 +637,11 @@ public class ECTester { throw new IOException("Couldn't read named curve data."); } commands.add(new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, curve.getParams(), external)); - } else if (optCurveFile != null) { + } else if (cfg.curveFile != null) { // Set curve loaded from a file - EC_Curve curve = new EC_Curve(keyLength, keyClass); + EC_Curve curve = new EC_Curve(null, keyLength, keyClass); - FileInputStream in = new FileInputStream(optCurveFile); + FileInputStream in = new FileInputStream(cfg.curveFile); curve.readCSV(in); in.close(); @@ -927,17 +671,17 @@ public class ECTester { short params = EC_Consts.PARAMETERS_NONE; byte[] data = null; - if (optKey != null || optNamedKey != null) { + if (cfg.key != null || cfg.namedKey != null) { params |= EC_Consts.PARAMETERS_KEYPAIR; EC_Params keypair; - if (optKey != null) { + if (cfg.key != null) { keypair = new EC_Params(EC_Consts.PARAMETERS_KEYPAIR); - FileInputStream in = new FileInputStream(optKey); + FileInputStream in = new FileInputStream(cfg.key); keypair.readCSV(in); in.close(); } else { - keypair = dataStore.getObject(EC_Keypair.class, optNamedKey); + keypair = dataStore.getObject(EC_Keypair.class, cfg.namedKey); } data = keypair.flatten(); @@ -946,19 +690,19 @@ public class ECTester { } } - if (optPublic != null || optNamedPublic != null) { + if (cfg.publicKey != null || cfg.namedPublicKey != null) { params |= EC_Consts.PARAMETER_W; EC_Params pub; - if (optPublic != null) { + if (cfg.publicKey != null) { pub = new EC_Params(EC_Consts.PARAMETER_W); - FileInputStream in = new FileInputStream(optPublic); + FileInputStream in = new FileInputStream(cfg.publicKey); pub.readCSV(in); in.close(); } else { - pub = dataStore.getObject(EC_Key.Public.class, optNamedPublic); + pub = dataStore.getObject(EC_Key.Public.class, cfg.namedPublicKey); if (pub == null) { - pub = dataStore.getObject(EC_Keypair.class, optNamedPublic); + pub = dataStore.getObject(EC_Keypair.class, cfg.namedPublicKey); } } @@ -968,19 +712,19 @@ public class ECTester { } data = pubkey; } - if (optPrivate != null || optNamedPrivate != null) { + if (cfg.privateKey != null || cfg.namedPrivateKey != null) { params |= EC_Consts.PARAMETER_S; EC_Params priv; - if (optPrivate != null) { + if (cfg.privateKey != null) { priv = new EC_Params(EC_Consts.PARAMETER_S); - FileInputStream in = new FileInputStream(optPrivate); + FileInputStream in = new FileInputStream(cfg.privateKey); priv.readCSV(in); in.close(); } else { - priv = dataStore.getObject(EC_Key.Public.class, optNamedPrivate); + priv = dataStore.getObject(EC_Key.Public.class, cfg.namedPrivateKey); if (priv == null) { - priv = dataStore.getObject(EC_Keypair.class, optNamedPrivate); + priv = dataStore.getObject(EC_Keypair.class, cfg.namedPrivateKey); } } @@ -1022,7 +766,7 @@ public class ECTester { return commands; for (Map.Entry entry : curves.entrySet()) { EC_Curve curve = entry.getValue(); - if (curve.getField() == field && (curve.getBits() == optBits || optAll)) { + if (curve.getField() == field && (curve.getBits() == cfg.bits || cfg.all)) { commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), field)); commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten())); commands.addAll(testCurve()); @@ -1037,4 +781,214 @@ public class ECTester { ECTester app = new ECTester(); app.run(args); } + + public static class Config { + + //Options + public int bits; + public boolean all; + public boolean primeField = false; + public boolean binaryField = false; + + public String namedCurve; + public String curveFile; + public boolean customCurve = false; + + public boolean anyPublicKey = false; + public String namedPublicKey; + public String publicKey; + + public boolean anyPrivateKey = false; + public String namedPrivateKey; + public String privateKey; + + public boolean anyKey = false; + public String namedKey; + public String key; + + public boolean anyKeypart = false; + + public String log; + + public boolean verbose = false; + public String input; + public String output; + public boolean fresh = false; + public boolean simulate = false; + + //Action-related ions + public String listNamed; + public String testSuite; + public int generateAmount; + public int ECDHCount; + public byte ECDHKA; + public int ECDSACount; + + /** + * Reads and validates options, also sets defaults. + * + * @param cli cli object, with parsed args + * @return whether the options are valid. + */ + public boolean readOptions(CommandLine cli) { + bits = Integer.parseInt(cli.getOptionValue("bit-size", "0")); + all = cli.hasOption("all"); + primeField = cli.hasOption("fp"); + binaryField = cli.hasOption("f2m"); + + namedCurve = cli.getOptionValue("named-curve"); + customCurve = cli.hasOption("custom"); + curveFile = cli.getOptionValue("curve"); + + namedPublicKey = cli.getOptionValue("named-public"); + publicKey = cli.getOptionValue("public"); + anyPublicKey = (publicKey != null) || (namedPublicKey != null); + + namedPrivateKey = cli.getOptionValue("named-private"); + privateKey = cli.getOptionValue("private"); + anyPrivateKey = (privateKey != null) || (namedPrivateKey != null); + + namedKey = cli.getOptionValue("named-key"); + key = cli.getOptionValue("key"); + anyKey = (key != null) || (namedKey != null); + anyKeypart = anyKey || anyPublicKey || anyPrivateKey; + + if (cli.hasOption("log")) { + log = cli.getOptionValue("log", String.format("ECTESTER_log_%d.log", System.currentTimeMillis() / 1000)); + } + + verbose = cli.hasOption("verbose"); + input = cli.getOptionValue("input"); + output = cli.getOptionValue("output"); + fresh = cli.hasOption("fresh"); + simulate = cli.hasOption("simulate"); + + if (cli.hasOption("list-named")) { + listNamed = cli.getOptionValue("list-named"); + return true; + } + + if ((key != null || namedKey != null) && (anyPublicKey || anyPrivateKey)) { + System.err.print("Can only specify the whole key with --key/--named-key or pubkey and privkey with --public/--named-public and --private/--named-private."); + return false; + } + if (bits < 0) { + System.err.println("Bit-size must not be negative."); + return false; + } + if (bits == 0 && !all) { + System.err.println("You must specify either bit-size with -b or all bit-sizes with -a."); + return false; + } + + if (key != null && namedKey != null || publicKey != null && namedPublicKey != null || privateKey != null && namedPrivateKey != null) { + System.err.println("You cannot specify both a named key and a key file."); + return false; + } + + if (cli.hasOption("export")) { + if (primeField == binaryField) { + System.err.print("Need to specify field with -fp or -f2m. (not both)"); + return false; + } + if (anyKeypart) { + System.err.println("Keys should not be specified when exporting curve params."); + return false; + } + if (namedCurve != null || customCurve || curveFile != null) { + System.err.println("Specifying a curve for curve export makes no sense."); + return false; + } + if (output == null) { + System.err.println("You have to specify an output file for curve parameter export."); + return false; + } + if (all) { + System.err.println("You have to specify curve bit-size with -b"); + return false; + } + + } else if (cli.hasOption("generate")) { + if (primeField == binaryField) { + System.err.print("Need to specify field with -fp or -f2m. (not both)"); + return false; + } + if (anyKeypart) { + System.err.println("Keys should not be specified when generating keys."); + return false; + } + if (output == null) { + System.err.println("You have to specify an output file for the key generation process."); + return false; + } + if (all) { + System.err.println("You have to specify curve bit-size with -b"); + return false; + } + + generateAmount = Integer.parseInt(cli.getOptionValue("generate", "0")); + if (generateAmount < 0) { + System.err.println("Amount of keys generated cant be negative."); + return false; + } + } else if (cli.hasOption("test")) { + if (!binaryField && primeField) { + binaryField = true; + primeField = true; + } + + testSuite = cli.getOptionValue("test", "default").toLowerCase(); + String[] tests = new String[]{"default", "nonprime", "invalid", "test-vectors", "wrong"}; + List testsList = Arrays.asList(tests); + if (!testsList.contains(testSuite)) { + System.err.println("Unknown test case. Should be one of: " + Arrays.toString(tests)); + return false; + } + + } else if (cli.hasOption("ecdh") || cli.hasOption("ecdhc")) { + if (primeField == binaryField) { + System.err.print("Need to specify field with -fp or -f2m. (not both)"); + return false; + } + if (all) { + System.err.println("You have to specify curve bit-size with -b"); + return false; + } + + if (cli.hasOption("ecdh")) { + ECDHCount = Integer.parseInt(cli.getOptionValue("ecdh", "1")); + ECDHKA = EC_Consts.KA_ECDH; + } else if (cli.hasOption("ecdhc")) { + ECDHCount = Integer.parseInt(cli.getOptionValue("ecdhc", "1")); + ECDHKA = EC_Consts.KA_ECDHC; + } + if (ECDHCount <= 0) { + System.err.println("ECDH count cannot be <= 0."); + return false; + } + + } else if (cli.hasOption("ecdsa")) { + if (primeField == binaryField) { + System.err.print("Need to specify field with -fp or -f2m. (but not both)"); + return false; + } + if (all) { + System.err.println("You have to specify curve bit-size with -b"); + return false; + } + + if ((anyPublicKey) != (anyPrivateKey) && !anyKey) { + System.err.println("You cannot only specify a part of a keypair."); + return false; + } + + ECDSACount = Integer.parseInt(cli.getOptionValue("ecdsa", "1")); + if (ECDSACount <= 0) { + System.err.println("ECDSA count cannot be <= 0."); + return false; + } + } + return true; + } + } } diff --git a/src/cz/crcs/ectester/reader/Response.java b/src/cz/crcs/ectester/reader/Response.java index ee27260..e5b8c1c 100644 --- a/src/cz/crcs/ectester/reader/Response.java +++ b/src/cz/crcs/ectester/reader/Response.java @@ -2,6 +2,7 @@ package cz.crcs.ectester.reader; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.reader.ec.EC_Curve; import javacard.framework.ISO7816; import javacard.security.KeyPair; @@ -12,11 +13,13 @@ import java.util.List; * @author Jan Jancar johny@neuromancer.sk */ public abstract class Response { + private ResponseAPDU resp; private long time; private short[] sws; private int numSW = 0; private byte[][] params; + //TODO replace params with EC_Data? private boolean success = true; protected Response(ResponseAPDU response, long time) { @@ -40,9 +43,14 @@ public abstract class Response { if (sw != ISO7816.SW_NO_ERROR) { success = false; } + } else { + success = false; } } + if ((short) resp.getSW() != ISO7816.SW_NO_ERROR) + success = false; + //try to parse numParams.. params = new byte[numParams][]; for (int i = 0; i < numParams; i++) { @@ -70,16 +78,8 @@ public abstract class Response { return time; } - public int getNaturalSW() { - return resp.getSW(); - } - - public short getSW1() { - return sws[0]; - } - - public short getSW2() { - return sws[1]; + public short getNaturalSW() { + return (short) resp.getSW(); } public short getSW(int index) { @@ -90,15 +90,15 @@ public abstract class Response { return numSW; } - protected boolean hasParam(int index) { + public boolean hasParam(int index) { return params.length >= index + 1 && params[index] != null; } - protected int getParamLength(int index) { + public int getParamLength(int index) { return params[index].length; } - protected byte[] getParam(int index) { + public byte[] getParam(int index) { return params[index]; } @@ -117,27 +117,32 @@ public abstract class Response { @Override public abstract String toString(); + public String toString(String inner) { + StringBuilder suffix = new StringBuilder(); + for (int j = 0; j < getNumSW(); ++j) { + suffix.append(" ").append(Util.getSWString(getSW(j))); + } + return String.format("%-62s:%4d ms : %s", inner, time / 1000000, suffix); + } + public static String toString(List responses) { return toString(responses, null); } - public static String toString(List responses, String prefix) { + public static String toString(List 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 = ""; - for (int j = 0; j < r.getNumSW(); ++j) { - suffix += " " + Util.getSWString(r.getSW(j)); - } - if (prefix != null) out.append(prefix); - out.append(String.format("%-62s:%4d ms : %s", message, r.time / 1000000, suffix)); + String message = r.toString(); + String full = r.toString(message); + + out.append(full); if (i < responses.size() - 1) { out.append("\n"); } @@ -149,6 +154,7 @@ public abstract class Response { * */ public static class Allocate extends Response { + private byte keyPair; private short keyLength; private byte keyClass; @@ -174,11 +180,15 @@ public abstract class Response { } else { key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; } - return String.format("Allocated %s %db %s", key, keyLength, field); + return super.toString(String.format("Allocated %s %db %s", key, keyLength, field)); } } + /** + * + */ public static class Clear extends Response { + private byte keyPair; protected Clear(ResponseAPDU response, long time, byte keyPair) { @@ -199,7 +209,7 @@ public abstract class Response { } else { key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; } - return String.format("Cleared %s", key); + return super.toString(String.format("Cleared %s", key)); } } @@ -207,6 +217,7 @@ public abstract class Response { * */ public static class Set extends Response { + private byte keyPair; private byte curve; private short parameters; @@ -238,13 +249,24 @@ public abstract class Response { name = "custom"; break; } + String what = ""; + if (parameters == EC_Consts.PARAMETERS_DOMAIN_F2M || parameters == EC_Consts.PARAMETERS_DOMAIN_FP) { + what = "curve"; + } else if (parameters == EC_Consts.PARAMETER_W) { + what = "pubkey"; + } else if (parameters == EC_Consts.PARAMETER_S) { + what = "privkey"; + } else if (parameters == EC_Consts.PARAMETERS_KEYPAIR) { + what = "keypair"; + } + String pair; if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { pair = "both keypairs"; } else { pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; } - return String.format("Set %s curve parameters on %s", name, pair); + return super.toString(String.format("Set %s %s parameters on %s", name, what, pair)); } } @@ -253,6 +275,7 @@ public abstract class Response { * */ public static class Corrupt extends Response { + private byte keyPair; private byte key; private short params; @@ -282,7 +305,7 @@ public abstract class Response { } else { pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; } - return String.format("Corrupted params of %s, %s", pair, corrupt); + return super.toString(String.format("Corrupted params of %s, %s", pair, corrupt)); } } @@ -290,6 +313,7 @@ public abstract class Response { * */ public static class Generate extends Response { + private byte keyPair; protected Generate(ResponseAPDU response, long time, byte keyPair) { @@ -310,7 +334,7 @@ public abstract class Response { } else { key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; } - return String.format("Generated %s", key); + return super.toString(String.format("Generated %s", key)); } } @@ -319,6 +343,7 @@ public abstract class Response { * */ public static class Export extends Response { + private byte keyPair; private byte key; private short parameters; @@ -419,7 +444,7 @@ public abstract class Response { } else { pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; } - return String.format("Exported params from %s of %s", source, pair); + return super.toString(String.format("Exported params from %s of %s", source, pair)); } } @@ -427,6 +452,7 @@ public abstract class Response { * */ public static class ECDH extends Response { + private byte pubkey; private byte privkey; private byte export; @@ -452,18 +478,13 @@ public abstract class Response { return getParam(0); } + public int secretLength() { + return getParamLength(0); + } + @Override public String toString() { - String algo = ""; - if ((type & EC_Consts.KA_ECDH) != 0) { - algo += "ECDH"; - } - if (type == EC_Consts.KA_BOTH) { - algo += "+"; - } - if ((type & EC_Consts.KA_ECDHC) != 0) { - algo += "ECDHC"; - } + String algo = Util.getKA(type); String pub = pubkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; @@ -474,7 +495,7 @@ public abstract class Response { } else { validity = Util.getCorruption(corruption); } - return String.format("%s of %s pubkey and %s privkey(%s point)", algo, pub, priv, validity); + return super.toString(String.format("%s of %s pubkey and %s privkey(%s point)", algo, pub, priv, validity)); } } @@ -482,6 +503,7 @@ public abstract class Response { * */ public static class ECDSA extends Response { + private byte keyPair; private byte export; private byte[] raw; @@ -507,7 +529,7 @@ public abstract class Response { public String toString() { String key = keyPair == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; String data = raw == null ? "random" : "provided"; - return String.format("ECDSA with %s keypair(%s data)", key, data); + return super.toString(String.format("ECDSA with %s keypair(%s data)", key, data)); } } @@ -524,7 +546,7 @@ public abstract class Response { @Override public String toString() { - return "Requested JCSystem object deletion"; + return super.toString("Requested JCSystem object deletion"); } } @@ -537,12 +559,12 @@ public abstract class Response { protected Support(ResponseAPDU response, long time) { super(response, time); - parse(3,0); + parse(3, 0); } @Override public String toString() { - return "Support of ECDH, ECDHC, ECDSA"; + return super.toString("Support of ECDH, ECDHC, ECDSA"); } } } diff --git a/src/cz/crcs/ectester/reader/Test.java b/src/cz/crcs/ectester/reader/Test.java new file mode 100644 index 0000000..78efef5 --- /dev/null +++ b/src/cz/crcs/ectester/reader/Test.java @@ -0,0 +1,81 @@ +package cz.crcs.ectester.reader; + +import javax.smartcardio.CardException; +import java.util.function.BiFunction; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class Test { + private boolean hasRun = false; + private BiFunction callback; + private Result result; + private Result expected; + private Command command; + private Response response; + + public Test(Command command, Result expected) { + this.command = command; + this.expected = expected; + } + + public Test(Command command, Result expected, BiFunction callback) { + this(command, expected); + this.callback = callback; + } + + public Command getCommand() { + return command; + } + + public Response getResponse() { + if (!hasRun) { + return null; + } + return response; + } + + public Result getResult() { + if (!hasRun) { + return null; + } + return result; + } + + public Result getExpected() { + return expected; + } + + public boolean ok() { + return result == expected || expected == Result.ANY; + } + + public void run() throws CardException { + response = command.send(); + if (callback != null) { + result = callback.apply(command, response); + } else { + if (response.successful()) { + result = Result.SUCCESS; + } else { + result = Result.FAILURE; + } + } + hasRun = true; + } + + @Override + public String toString() { + if (hasRun) { + return (ok() ? "OK " : "NOK") + " " + response.toString(); + } else { + return ""; + } + } + + public enum Result { + SUCCESS, + FAILURE, + ANY + } +} diff --git a/src/cz/crcs/ectester/reader/TestSuite.java b/src/cz/crcs/ectester/reader/TestSuite.java new file mode 100644 index 0000000..892e853 --- /dev/null +++ b/src/cz/crcs/ectester/reader/TestSuite.java @@ -0,0 +1,167 @@ +package cz.crcs.ectester.reader; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.reader.ec.*; + +import javax.smartcardio.CardException; +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class TestSuite { + + EC_Store dataStore; + ECTester.Config cfg; + String name; + boolean hasRun; + List tests = new LinkedList<>(); + + public TestSuite(EC_Store dataStore, ECTester.Config cfg, String name) { + this.dataStore = dataStore; + this.cfg = cfg; + this.name = name; + } + + public List run(CardMngr cardManager) throws IOException, CardException { + for (Test t : tests) { + t.run(); + System.out.println(t); + } + hasRun = true; + return tests; + } + + public List getTests() { + return Collections.unmodifiableList(tests); + } + + public boolean hasRun() { + return hasRun; + } + + public String getName() { + return name; + } + + public static class Default extends TestSuite { + + public Default(EC_Store dataStore, ECTester.Config cfg) { + super(dataStore, cfg, "default"); + } + + @Override + public List run(CardMngr cardManager) { + return null; + } + } + + public static class TestVectors extends TestSuite { + public TestVectors(EC_Store dataStore, ECTester.Config cfg) { + super(dataStore, cfg, "test"); + } + + @Override + public List run(CardMngr cardManager) throws IOException, CardException { + + Map results = dataStore.getObjects(EC_KAResult.class, "test"); + for (EC_KAResult result : results.values()) { + EC_Curve curve = dataStore.getObject(EC_Curve.class, result.getCurve()); + if (cfg.namedCurve != null && !(result.getCurve().startsWith(cfg.namedCurve) || result.getCurve().equals(cfg.namedCurve))) { + continue; + } + if (curve.getBits() != cfg.bits && !cfg.all) { + continue; + } + EC_Params onekey = dataStore.getObject(EC_Keypair.class, result.getOneKey()); + if (onekey == null) { + onekey = dataStore.getObject(EC_Key.Private.class, result.getOneKey()); + } + EC_Params otherkey = dataStore.getObject(EC_Keypair.class, result.getOtherKey()); + if (otherkey == null) { + otherkey = dataStore.getObject(EC_Key.Public.class, result.getOtherKey()); + } + if (onekey == null || otherkey == null) { + throw new IOException("Test vector keys couldn't be located."); + } + + tests.add(new Test(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Test.Result.SUCCESS)); + tests.add(new Test(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Test.Result.SUCCESS)); + //tests.add(new Test(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), Test.Result.SUCCESS)); + tests.add(new Test(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), Test.Result.SUCCESS)); + tests.add(new Test(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), Test.Result.SUCCESS)); + tests.add(new Test(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getKA()), Test.Result.SUCCESS, (command, response) -> { + Response.ECDH dh = (Response.ECDH) response; + if (!dh.successful() || !dh.hasSecret()) + return Test.Result.FAILURE; + if (!Util.compareBytes(dh.getSecret(), 0, result.getParam(0), 0, dh.secretLength())) { + return Test.Result.FAILURE; + } + return Test.Result.SUCCESS; + })); + tests.add(new Test(new Command.Cleanup(cardManager), Test.Result.ANY)); + + } + return super.run(cardManager); + } + } + + public static class NonPrime extends TestSuite { + + + public NonPrime(EC_Store dataStore, ECTester.Config cfg) { + super(dataStore, cfg, "nonprime"); + } + + @Override + public List run(CardMngr cardManager) throws IOException, CardException { + Map 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() == cfg.bits || cfg.all)) { + tests.add(new Test(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Test.Result.SUCCESS)); + tests.add(new Test(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Test.Result.ANY)); + tests.add(new Test(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), Test.Result.ANY)); + tests.add(new Test(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, key.getParams(), key.flatten()), Test.Result.ANY)); + tests.add(new Test(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH), Test.Result.FAILURE)); + tests.add(new Test(new Command.Cleanup(cardManager), Test.Result.ANY)); + } + } + return super.run(cardManager); + } + } + + public static class Invalid extends TestSuite { + + public Invalid(EC_Store dataStore, ECTester.Config cfg) { + super(dataStore, cfg, "invalid"); + } + + @Override + public List run(CardMngr cardManager) throws IOException, CardException { + Map pubkeys = dataStore.getObjects(EC_Key.Public.class, "invalid"); + for (EC_Key.Public key : pubkeys.values()) { + EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve()); + if (cfg.namedCurve != null && !(key.getCurve().startsWith(cfg.namedCurve) || key.getCurve().equals(cfg.namedCurve))) { + continue; + } + if (curve.getBits() != cfg.bits && !cfg.all) { + continue; + } + tests.add(new Test(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Test.Result.SUCCESS)); + tests.add(new Test(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Test.Result.SUCCESS)); + tests.add(new Test(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), Test.Result.SUCCESS)); + tests.add(new Test(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, key.getParams(), key.flatten()), Test.Result.ANY)); + tests.add(new Test(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_BOTH), Test.Result.FAILURE)); + tests.add(new Test(new Command.Cleanup(cardManager), Test.Result.ANY)); + } + return super.run(cardManager); + } + } +} diff --git a/src/cz/crcs/ectester/reader/Util.java b/src/cz/crcs/ectester/reader/Util.java index 41a7821..3a6a8ae 100644 --- a/src/cz/crcs/ectester/reader/Util.java +++ b/src/cz/crcs/ectester/reader/Util.java @@ -22,6 +22,25 @@ public class Util { array[offset] = (byte) ((value >> 8) & 0xFF); } + public static boolean compareBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) { + for (int i = 0; i < length; ++i) { + byte a = one[i + oneOffset]; + byte b = other[i + otherOffset]; + if (a != b) { + return false; + } + } + return true; + } + + public static boolean allValue(byte[] array, byte value) { + for (byte a : array) { + if (a != value) + return false; + } + return true; + } + public static byte[] hexToBytes(String hex) { return hexToBytes(hex, true); } @@ -103,6 +122,47 @@ public class Util { return out; } + public static String getSWSource(short sw) { + switch (sw) { + case ISO7816.SW_NO_ERROR: + case ISO7816.SW_APPLET_SELECT_FAILED: + case ISO7816.SW_BYTES_REMAINING_00: + case ISO7816.SW_CLA_NOT_SUPPORTED: + case ISO7816.SW_COMMAND_NOT_ALLOWED: + case ISO7816.SW_CONDITIONS_NOT_SATISFIED: + case ISO7816.SW_CORRECT_LENGTH_00: + case ISO7816.SW_DATA_INVALID: + case ISO7816.SW_FILE_FULL: + case ISO7816.SW_FILE_INVALID: + case ISO7816.SW_FILE_NOT_FOUND: + case ISO7816.SW_FUNC_NOT_SUPPORTED: + case ISO7816.SW_INCORRECT_P1P2: + case ISO7816.SW_INS_NOT_SUPPORTED: + case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED: + case ISO7816.SW_RECORD_NOT_FOUND: + case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED: + case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED: + case ISO7816.SW_UNKNOWN: + case ISO7816.SW_WARNING_STATE_UNCHANGED: + case ISO7816.SW_WRONG_DATA: + case ISO7816.SW_WRONG_LENGTH: + case ISO7816.SW_WRONG_P1P2: + return "ISO"; + case CryptoException.ILLEGAL_VALUE: + case CryptoException.UNINITIALIZED_KEY: + case CryptoException.NO_SUCH_ALGORITHM: + case CryptoException.INVALID_INIT: + case CryptoException.ILLEGAL_USE: + return "CryptoException"; + case ECTesterApplet.SW_SIG_VERIFY_FAIL: + case ECTesterApplet.SW_DH_DHC_MISMATCH: + case ECTesterApplet.SW_KEYPAIR_NULL: + return "ECTesterApplet"; + default: + return "?"; + } + } + public static String getSWString(short sw) { if (sw == ISO7816.SW_NO_ERROR) { return "OK\t(0x9000)"; @@ -193,6 +253,12 @@ public class Util { case ECTesterApplet.SW_SIG_VERIFY_FAIL: str = "SIG_VERIFY_FAIL"; break; + case ECTesterApplet.SW_DH_DHC_MISMATCH: + str = "DH_DHC_MISMATCH"; + break; + case ECTesterApplet.SW_KEYPAIR_NULL: + str = "KEYPAIR_NULL"; + break; default: str = "unknown"; break; @@ -229,9 +295,23 @@ public class Util { corrupt = "INFINITY"; break; default: - corrupt = "UNKNOWN"; + corrupt = "unknown"; break; } return corrupt; } + + public static String getKA(byte ka) { + String algo = ""; + if ((ka & EC_Consts.KA_ECDH) != 0) { + algo += "ECDH"; + } + if (ka == EC_Consts.KA_BOTH) { + algo += "+"; + } + if ((ka & EC_Consts.KA_ECDHC) != 0) { + algo += "ECDHC"; + } + return algo; + } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Curve.java b/src/cz/crcs/ectester/reader/ec/EC_Curve.java index 9b783ec..7d056a5 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Curve.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Curve.java @@ -7,25 +7,27 @@ import javacard.security.KeyPair; * @author Jan Jancar johny@neuromancer.sk */ public class EC_Curve extends EC_Params { - private short bits; private byte field; private String desc; /** - * * @param bits * @param field KeyPair.ALG_EC_FP or KeyPair.ALG_EC_F2M */ public EC_Curve(short bits, byte field) { super(field == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M); this.bits = bits; - this.field = field; } - public EC_Curve(short bits, byte field, String desc) { + public EC_Curve(String id, short bits, byte field) { this(bits, field); + this.id = id; + } + + public EC_Curve(String id, short bits, byte field, String desc) { + this(id, bits, field); this.desc = desc; } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Data.java b/src/cz/crcs/ectester/reader/ec/EC_Data.java index c55b99d..49b5316 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Data.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Data.java @@ -13,11 +13,12 @@ import java.util.regex.Pattern; * @author Jan Jancar johny@neuromancer.sk */ public class EC_Data { - private static final Pattern hex = Pattern.compile("(0x|0X)?[a-fA-F\\d]+"); - + String id; int count; byte[][] data; + private static final Pattern HEX = Pattern.compile("(0x|0X)?[a-fA-F\\d]+"); + EC_Data() { } @@ -31,6 +32,20 @@ public class EC_Data { this.data = data; } + EC_Data(String id, int count) { + this(count); + this.id = id; + } + + EC_Data(String id, byte[][] data) { + this(data); + this.id = id; + } + + public String getId() { + return id; + } + public int getCount() { return count; } @@ -117,16 +132,29 @@ public class EC_Data { return false; } for (String param : data) { - if (!hex.matcher(param).matches()) { + if (!HEX.matcher(param).matches()) { return false; } } return readHex(data.toArray(new String[data.size()])); } - public boolean readBytes(byte[] data) { - //TODO - return false; + public boolean readBytes(byte[] bytes) { + int offset = 0; + for (int i = 0; i < count; i++) { + if (bytes.length - offset < 2) { + return false; + } + short paramLength = Util.getShort(bytes, offset); + offset += 2; + if (bytes.length < offset + paramLength) { + return false; + } + data[i] = new byte[paramLength]; + System.arraycopy(bytes, offset, data[i], 0, paramLength); + offset += paramLength; + } + return true; } public void writeCSV(OutputStream out) throws IOException { diff --git a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java b/src/cz/crcs/ectester/reader/ec/EC_KAResult.java index 1385f12..9e92fd9 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java +++ b/src/cz/crcs/ectester/reader/ec/EC_KAResult.java @@ -1,6 +1,6 @@ package cz.crcs.ectester.reader.ec; -import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.reader.Util; /** * @author Jan Jancar johny@neuromancer.sk @@ -22,8 +22,13 @@ public class EC_KAResult extends EC_Data { this.otherKey = otherKey; } - public EC_KAResult(byte ka, String curve, String oneKey, String otherKey, String desc) { + public EC_KAResult(String id, byte ka, String curve, String oneKey, String otherKey) { this(ka, curve, oneKey, otherKey); + this.id = id; + } + + public EC_KAResult(String id, byte ka, String curve, String oneKey, String otherKey, String desc) { + this(id, ka, curve, oneKey, otherKey); this.desc = desc; } @@ -49,8 +54,8 @@ public class EC_KAResult extends EC_Data { @Override public String toString() { - String agreement = ka == EC_Consts.KA_ECDH ? "ECDH" : "ECDHC"; - return agreement + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc); + String algo = Util.getKA(ka); + return algo + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc); } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Key.java b/src/cz/crcs/ectester/reader/ec/EC_Key.java index ad846b8..85fd652 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Key.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Key.java @@ -20,6 +20,16 @@ public class EC_Key extends EC_Params { this.desc = desc; } + private EC_Key(String id, short mask, String curve) { + this(mask, curve); + this.id = id; + } + + private EC_Key(String id, short mask, String curve, String desc) { + this(mask, curve, desc); + this.id = id; + } + public String getCurve() { return curve; } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java b/src/cz/crcs/ectester/reader/ec/EC_Keypair.java index bf87e9e..4da7218 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Keypair.java @@ -6,7 +6,6 @@ import cz.crcs.ectester.applet.EC_Consts; * @author Jan Jancar johny@neuromancer.sk */ public class EC_Keypair extends EC_Params { - private String curve; private String desc; diff --git a/src/cz/crcs/ectester/reader/ec/EC_Params.java b/src/cz/crcs/ectester/reader/ec/EC_Params.java index 00747b1..cee9c16 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Params.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Params.java @@ -4,6 +4,7 @@ import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.reader.Util; import java.io.ByteArrayOutputStream; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -25,6 +26,16 @@ public class EC_Params extends EC_Data { this.data = data; } + public EC_Params(String id, short params) { + this(params); + this.id = id; + } + + public EC_Params(String id, short params, byte[][] data) { + this(params, data); + this.id = id; + } + public short getParams() { return params; } @@ -67,8 +78,14 @@ public class EC_Params extends EC_Data { byte[] param = data[i]; if (masked == EC_Consts.PARAMETER_F2M) { //add m, e_1, e_2, e_3 - param = Util.concatenate(param, data[i + 1], data[i + 2], data[i + 3]); - if (param.length != 8) + param = Util.concatenate(param, data[i + 1]); + if (!Util.allValue(data[i + 2], (byte) 0)) { + param = Util.concatenate(param, data[i + 2]); + } + if (!Util.allValue(data[i + 3], (byte) 0)) { + param = Util.concatenate(param, data[i + 3]); + } + if (!(param.length == 4 || param.length == 8)) throw new RuntimeException("PARAMETER_F2M length is not 8.(should be)"); } if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) { @@ -112,9 +129,6 @@ public class EC_Params extends EC_Data { if (masked == EC_Consts.PARAMETER_F2M) { //split into m, e1, e2, e3 - if (param.length != 8) { - throw new RuntimeException("PARAMETER_F2M length is not 8.(should be)"); - } for (int i = 0; i < 4; ++i) { out.add(String.format("%04x", Util.getShort(param, i * 2))); } @@ -136,4 +150,8 @@ public class EC_Params extends EC_Data { return out.toArray(new String[out.size()]); } + @Override + public String toString() { + return String.join(",", expand()); + } } -- cgit v1.3.1 From 5e46fb3406b99b9d7f1e1be000a3e87abca6ad8a Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 19 Apr 2017 20:01:53 +0200 Subject: Add id to EC_Params subclasses toString, fix EC_Params.expand --- src/cz/crcs/ectester/reader/ec/EC_Curve.java | 2 +- src/cz/crcs/ectester/reader/ec/EC_Data.java | 13 ++++++------- src/cz/crcs/ectester/reader/ec/EC_KAResult.java | 2 +- src/cz/crcs/ectester/reader/ec/EC_Key.java | 2 +- src/cz/crcs/ectester/reader/ec/EC_Keypair.java | 2 +- src/cz/crcs/ectester/reader/ec/EC_Params.java | 24 +++++++----------------- 6 files changed, 17 insertions(+), 28 deletions(-) (limited to 'src/cz/crcs/ectester/reader/ec/EC_Curve.java') diff --git a/src/cz/crcs/ectester/reader/ec/EC_Curve.java b/src/cz/crcs/ectester/reader/ec/EC_Curve.java index 7d056a5..45080fb 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Curve.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Curve.java @@ -45,6 +45,6 @@ public class EC_Curve extends EC_Params { @Override public String toString() { - return "Elliptic curve (" + String.valueOf(bits) + "b)" + (desc == null ? "" : ": " + desc); + return "<" + getId() + "> " + (field == KeyPair.ALG_EC_FP ? "Prime" : "Binary") + " field Elliptic curve (" + String.valueOf(bits) + "b)" + (desc == null ? "" : ": " + desc); } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Data.java b/src/cz/crcs/ectester/reader/ec/EC_Data.java index 49b5316..5197665 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Data.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Data.java @@ -158,14 +158,13 @@ public class EC_Data { } public void writeCSV(OutputStream out) throws IOException { - String[] hex = expand(); Writer w = new OutputStreamWriter(out); - for (int i = 0; i < hex.length; ++i) { - w.write(hex[i]); - if (i < hex.length - 1) { - w.write(","); - } - } + w.write(String.join(",", expand())); w.flush(); } + + @Override + public String toString() { + return String.join(",", expand()); + } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java b/src/cz/crcs/ectester/reader/ec/EC_KAResult.java index 9e92fd9..28115f7 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java +++ b/src/cz/crcs/ectester/reader/ec/EC_KAResult.java @@ -55,7 +55,7 @@ public class EC_KAResult extends EC_Data { @Override public String toString() { String algo = Util.getKA(ka); - return algo + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc); + return "<" + getId() + "> " + algo + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc); } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Key.java b/src/cz/crcs/ectester/reader/ec/EC_Key.java index 85fd652..cecd228 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Key.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Key.java @@ -66,7 +66,7 @@ public class EC_Key extends EC_Params { @Override public String toString() { - return "EC Private key, over " + getCurve() + (getDesc() == null ? "" : ": " + getDesc()); + return "<" + getId() + "> EC Private key, over " + getCurve() + (getDesc() == null ? "" : ": " + getDesc()); } } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java b/src/cz/crcs/ectester/reader/ec/EC_Keypair.java index 4da7218..924906e 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Keypair.java @@ -29,6 +29,6 @@ public class EC_Keypair extends EC_Params { @Override public String toString() { - return "EC Keypair, over " + curve + (desc == null ? "" : ": " + desc); + return "<" + getId() + "> EC Keypair, over " + curve + (desc == null ? "" : ": " + desc); } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Params.java b/src/cz/crcs/ectester/reader/ec/EC_Params.java index cee9c16..7192b61 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Params.java +++ b/src/cz/crcs/ectester/reader/ec/EC_Params.java @@ -126,32 +126,22 @@ public class EC_Params extends EC_Data { short masked = (short) (params & paramMask); if (masked != 0) { byte[] param = data[index]; - if (masked == EC_Consts.PARAMETER_F2M) { - //split into m, e1, e2, e3 for (int i = 0; i < 4; ++i) { - out.add(String.format("%04x", Util.getShort(param, i * 2))); + out.add(Util.bytesToHex(data[index + i], false)); } - + index += 4; } else if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) { - //split from X962 format into X and Y - //disregard the first 04 and then split into half(uncompress) - int half = (param.length - 1) / 2; - out.add(Util.bytesToHex(param, 1, half, false)); - out.add(Util.bytesToHex(param, half + 1, half, false)); + out.add(Util.bytesToHex(param, false)); + out.add(Util.bytesToHex(data[index + 1], false)); + index += 2; } else { - //read raw - out.add(Util.bytesToHex(data[index], false)); + out.add(Util.bytesToHex(param, false)); + index++; } - index++; } paramMask = (short) (paramMask << 1); } return out.toArray(new String[out.size()]); } - - @Override - public String toString() { - return String.join(",", expand()); - } } -- cgit v1.3.1