From fc32d6c7500aea671cdccfc2ccf26af812d20908 Mon Sep 17 00:00:00 2001 From: J08nY Date: Fri, 10 Nov 2017 19:35:17 +0100 Subject: Cleanup and a new gitignore. --- .gitignore | 5 +++++ LICENSE | 2 +- src/cz/crcs/ectester/applet/ECTesterApplet.java | 24 +++++++++++++----------- src/cz/crcs/ectester/reader/Util.java | 14 +++++--------- 4 files changed, 24 insertions(+), 21 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fe6a5d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/dist/lib/ +/dist/ECTester.jar +/dist/ECTester-dist.jar +/dist/ectester.sh +/dist/ectester.bat \ No newline at end of file diff --git a/LICENSE b/LICENSE index a8fc851..21ecc94 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016 +Copyright (c) 2016-2017 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index ecf97f2..deb3aae 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -57,8 +57,8 @@ public class ECTesterApplet extends Applet implements ExtendedLength { public static final byte INS_CLEANUP = (byte) 0x73; public static final byte INS_SUPPORT = (byte) 0x74; public static final byte INS_ALLOCATE_KA = (byte) 0x75; - - + + // PARAMETERS for P1 and P2 public static final byte KEYPAIR_LOCAL = (byte) 0x01; public static final byte KEYPAIR_REMOTE = (byte) 0x02; @@ -72,10 +72,10 @@ public class ECTesterApplet extends Applet implements ExtendedLength { public static final short SW_KEYPAIR_NULL = (short) 0x0ee3; public static final short SW_KA_NULL = (short) 0x0ee4; public static final short SW_SIGNATURE_NULL = (short) 0x0ee5; - public static final short SW_OBJECT_NULL = (short) 0x0ee6; + public static final short SW_OBJECT_NULL = (short) 0x0ee6; public static final short SW_KA_UNSUPPORTED = (short) 0x0ee7; - + // Class javacard.security.KeyAgreement // javacard.security.KeyAgreement Fields: public static final byte KeyAgreement_ALG_EC_SVDP_DH = 1; @@ -86,7 +86,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength { public static final byte KeyAgreement_ALG_EC_SVDP_DHC_PLAIN = 4; public static final byte KeyAgreement_ALG_EC_PACE_GM = 5; public static final byte KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY = 6; - public static final byte KeyAgreement_ALG_DH_PLAIN = 7; + public static final byte KeyAgreement_ALG_DH_PLAIN = 7; private static final short ARRAY_LENGTH = (short) 0xff; @@ -163,7 +163,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength { short length = 0; switch (ins) { - case INS_ALLOCATE_KA: + case INS_ALLOCATE_KA: length = insAllocateKA(apdu); break; case INS_ALLOCATE: @@ -208,7 +208,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength { apdu.setOutgoingAndSend((short) 0, length); } else ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); } - + /** * Allocates KeyAgreement object. returns allocate SW * @@ -235,18 +235,18 @@ public class ECTesterApplet extends Applet implements ExtendedLength { sw = SW_KA_UNSUPPORTED; break; } -*/ +*/ // Allocate given type into both DH and DHC objects short sw = keyTester.allocateECDH(kaType); short offset = 0; Util.setShort(apdu.getBuffer(), offset, sw); offset += 2; - + //sw = keyTester.allocateECDHC(kaType); Util.setShort(apdu.getBuffer(), offset, sw); offset += 2; return offset; - } + } /** * Allocates local and remote keyPairs. * returns allocate SWs @@ -422,13 +422,15 @@ public class ECTesterApplet extends Applet implements ExtendedLength { } /** + * Performs ECDH, directly between the privkey specified in P1(local/remote) and the raw data * * @param apdu P1 = byte privkey (KEYPAIR_*) - * @return P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) + * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) * DATA = short corruption (EC_Consts.CORRUPTION_* | ...) * byte type (EC_Consts.KA_* | ...) * short length * byte[] pubkey + * @return length of response */ private short insECDH_direct(APDU apdu) { byte privkey = apduArray[ISO7816.OFFSET_P1]; diff --git a/src/cz/crcs/ectester/reader/Util.java b/src/cz/crcs/ectester/reader/Util.java index 4e1154b..001f58c 100644 --- a/src/cz/crcs/ectester/reader/Util.java +++ b/src/cz/crcs/ectester/reader/Util.java @@ -1,16 +1,12 @@ package cz.crcs.ectester.reader; import cz.crcs.ectester.applet.ECTesterApplet; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_PACE_GM; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_PLAIN; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY; import cz.crcs.ectester.applet.EC_Consts; import javacard.framework.ISO7816; import javacard.security.CryptoException; +import static cz.crcs.ectester.applet.ECTesterApplet.*; + /** * Utility class, some byte/hex manipulation, convenient byte[] methods. * @@ -349,9 +345,9 @@ public class Util { } return algo; } - + public static String getKATypeString(byte kaType) { - String kaTypeString = "unknown"; + String kaTypeString; switch (kaType) { case KeyAgreement_ALG_EC_SVDP_DH: kaTypeString = "ALG_EC_SVDP_DH"; @@ -373,7 +369,7 @@ public class Util { break; default: kaTypeString = "unknown"; - } + } return kaTypeString; } } -- cgit v1.2.3-70-g09d2 From 59a043192903918a68e8d9df629c09221a13c641 Mon Sep 17 00:00:00 2001 From: J08nY Date: Fri, 10 Nov 2017 21:17:54 +0100 Subject: Split the ec package into common package, rename reader part of the project. --- build.xml | 22 - manifest.mf | 2 +- nbproject/project.properties | 2 +- src/cz/crcs/ectester/common/ec/EC_Category.java | 142 ++++ src/cz/crcs/ectester/common/ec/EC_Curve.java | 52 ++ src/cz/crcs/ectester/common/ec/EC_Data.java | 200 +++++ src/cz/crcs/ectester/common/ec/EC_KAResult.java | 63 ++ src/cz/crcs/ectester/common/ec/EC_Key.java | 83 ++ src/cz/crcs/ectester/common/ec/EC_Keypair.java | 41 + src/cz/crcs/ectester/common/ec/EC_Params.java | 151 ++++ src/cz/crcs/ectester/data/EC_Store.java | 2 +- src/cz/crcs/ectester/reader/ECTester.java | 856 --------------------- src/cz/crcs/ectester/reader/ECTesterReader.java | 856 +++++++++++++++++++++ src/cz/crcs/ectester/reader/command/Command.java | 14 +- src/cz/crcs/ectester/reader/ec/EC_Category.java | 142 ---- src/cz/crcs/ectester/reader/ec/EC_Curve.java | 52 -- src/cz/crcs/ectester/reader/ec/EC_Data.java | 200 ----- src/cz/crcs/ectester/reader/ec/EC_KAResult.java | 63 -- src/cz/crcs/ectester/reader/ec/EC_Key.java | 83 -- src/cz/crcs/ectester/reader/ec/EC_Keypair.java | 41 - src/cz/crcs/ectester/reader/ec/EC_Params.java | 151 ---- src/cz/crcs/ectester/reader/response/Response.java | 1 - .../ectester/reader/test/CompositeCurvesSuite.java | 8 +- src/cz/crcs/ectester/reader/test/DefaultSuite.java | 4 +- .../ectester/reader/test/InvalidCurvesSuite.java | 8 +- src/cz/crcs/ectester/reader/test/TestSuite.java | 8 +- .../crcs/ectester/reader/test/TestVectorSuite.java | 6 +- .../ectester/reader/test/WrongCurvesSuite.java | 4 +- 28 files changed, 1617 insertions(+), 1640 deletions(-) create mode 100644 src/cz/crcs/ectester/common/ec/EC_Category.java create mode 100644 src/cz/crcs/ectester/common/ec/EC_Curve.java create mode 100644 src/cz/crcs/ectester/common/ec/EC_Data.java create mode 100644 src/cz/crcs/ectester/common/ec/EC_KAResult.java create mode 100644 src/cz/crcs/ectester/common/ec/EC_Key.java create mode 100644 src/cz/crcs/ectester/common/ec/EC_Keypair.java create mode 100644 src/cz/crcs/ectester/common/ec/EC_Params.java delete mode 100644 src/cz/crcs/ectester/reader/ECTester.java create mode 100644 src/cz/crcs/ectester/reader/ECTesterReader.java delete mode 100644 src/cz/crcs/ectester/reader/ec/EC_Category.java delete mode 100644 src/cz/crcs/ectester/reader/ec/EC_Curve.java delete mode 100644 src/cz/crcs/ectester/reader/ec/EC_Data.java delete mode 100644 src/cz/crcs/ectester/reader/ec/EC_KAResult.java delete mode 100644 src/cz/crcs/ectester/reader/ec/EC_Key.java delete mode 100644 src/cz/crcs/ectester/reader/ec/EC_Keypair.java delete mode 100644 src/cz/crcs/ectester/reader/ec/EC_Params.java diff --git a/build.xml b/build.xml index 3d778f3..f89b743 100644 --- a/build.xml +++ b/build.xml @@ -69,28 +69,6 @@ properties which you can use, check the target you are overriding in the nbproject/build-impl.xml file. - --> - diff --git a/manifest.mf b/manifest.mf index 2cb1a50..cbfea93 100644 --- a/manifest.mf +++ b/manifest.mf @@ -1,4 +1,4 @@ Manifest-Version: 1.0 Class-Path: lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.3.1.jar lib/snakeyaml-1.19.jar -Main-Class: cz.crcs.ectester.reader.ECTester +Main-Class: cz.crcs.ectester.reader.ECTesterReader diff --git a/nbproject/project.properties b/nbproject/project.properties index 152dc9c..8c65b4e 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -59,7 +59,7 @@ javadoc.splitindex=true javadoc.use=true javadoc.version=false javadoc.windowtitle= -main.class=cz.crcs.ectester.reader.ECTester +main.class=cz.crcs.ectester.reader.ECTesterReader manifest.file=manifest.mf meta.inf.dir=${src.dir}/META-INF mkdist.disabled=false diff --git a/src/cz/crcs/ectester/common/ec/EC_Category.java b/src/cz/crcs/ectester/common/ec/EC_Category.java new file mode 100644 index 0000000..32a788d --- /dev/null +++ b/src/cz/crcs/ectester/common/ec/EC_Category.java @@ -0,0 +1,142 @@ +package cz.crcs.ectester.common.ec; + +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.TreeMap; + +/** + * A category of EC_Data objects, has a name, description and represents a directory in + * the cz.crcs.ectester.data package. + * @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(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof EC_Category && Objects.equals(this.name, ((EC_Category) obj).name); + } + + @Override + public int hashCode() { + return this.name.hashCode() ^ this.directory.hashCode(); + } + +} diff --git a/src/cz/crcs/ectester/common/ec/EC_Curve.java b/src/cz/crcs/ectester/common/ec/EC_Curve.java new file mode 100644 index 0000000..19cfe2d --- /dev/null +++ b/src/cz/crcs/ectester/common/ec/EC_Curve.java @@ -0,0 +1,52 @@ +package cz.crcs.ectester.common.ec; + +import cz.crcs.ectester.applet.EC_Consts; +import javacard.security.KeyPair; + +/** + * An Elliptic curve, contains parameters Fp/F2M, A, B, G, R, (K)?. + * + * @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(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; + } + + public short getBits() { + return bits; + } + + public byte getField() { + return field; + } + + public String getDesc() { + return desc; + } + + @Override + public String toString() { + 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/common/ec/EC_Data.java b/src/cz/crcs/ectester/common/ec/EC_Data.java new file mode 100644 index 0000000..da97208 --- /dev/null +++ b/src/cz/crcs/ectester/common/ec/EC_Data.java @@ -0,0 +1,200 @@ +package cz.crcs.ectester.common.ec; + +import cz.crcs.ectester.reader.Util; + +import java.io.*; +import java.util.*; +import java.util.regex.Pattern; + +/** + * A list of byte arrays for holding EC data. + * + * The data can be read from a byte array via readBytes(), from a CSV via readCSV(). + * The data can be exported to a byte array via flatten() or to a string array via expand(). + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class EC_Data { + String id; + int count; + byte[][] data; + + private static final Pattern HEX = Pattern.compile("(0x|0X)?[a-fA-F\\d]+"); + + EC_Data() { + } + + EC_Data(int count) { + this.count = count; + this.data = new byte[count][]; + } + + EC_Data(byte[][] data) { + this.count = data.length; + 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; + } + + public byte[][] getData() { + return data; + } + + public boolean hasData() { + return data != null; + } + + public byte[] getParam(int index) { + return data[index]; + } + + public byte[] flatten() { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (byte[] param : data) { + byte[] length = new byte[2]; + Util.setShort(length, 0, (short) param.length); + + out.write(length, 0, 2); + out.write(param, 0, param.length); + } + + return out.toByteArray(); + } + + public String[] expand() { + List out = new ArrayList<>(count); + for (byte[] param : data) { + out.add(Util.bytesToHex(param, false)); + } + + return out.toArray(new String[out.size()]); + } + + private static byte[] pad(byte[] data) { + if (data.length == 1) { + return new byte[]{(byte) 0, data[0]}; + } else if (data.length == 0 || data.length > 2) { + return data; + } + return null; + } + + private static byte[] parse(String param) { + byte[] data; + if (param.startsWith("0x") || param.startsWith("0X")) { + data = Util.hexToBytes(param.substring(2)); + } else { + data = Util.hexToBytes(param); + } + if (data == null) + return new byte[0]; + if (data.length < 2) + return pad(data); + return data; + } + + private boolean readHex(String[] hex) { + if (hex.length != count) { + return false; + } + + for (int i = 0; i < count; ++i) { + this.data[i] = parse(hex[i]); + } + return true; + } + + public boolean readCSV(InputStream in) { + Scanner s = new Scanner(in); + + s.useDelimiter(",|;"); + List data = new LinkedList<>(); + while (s.hasNext()) { + String field = s.next(); + data.add(field.replaceAll("\\s+", "")); + } + + if (data.isEmpty()) { + return false; + } + for (String param : data) { + if (!HEX.matcher(param).matches()) { + return false; + } + } + return readHex(data.toArray(new String[data.size()])); + } + + 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 { + Writer w = new OutputStreamWriter(out); + w.write(String.join(",", expand())); + w.flush(); + } + + @Override + public String toString() { + return String.join(",", expand()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof EC_Data) { + EC_Data other = (EC_Data) obj; + if (this.id != null || other.id != null) { + return Objects.equals(this.id, other.id); + } + + if (this.count != other.count) + return false; + for (int i = 0; i < this.count; ++i) { + if (!Arrays.equals(this.data[i], other.data[i])) { + return false; + } + } + return true; + } else { + return false; + } + } + + @Override + public int hashCode() { + if (this.id != null) { + return this.id.hashCode(); + } + return Arrays.deepHashCode(this.data); + } +} diff --git a/src/cz/crcs/ectester/common/ec/EC_KAResult.java b/src/cz/crcs/ectester/common/ec/EC_KAResult.java new file mode 100644 index 0000000..b215d0e --- /dev/null +++ b/src/cz/crcs/ectester/common/ec/EC_KAResult.java @@ -0,0 +1,63 @@ +package cz.crcs.ectester.common.ec; + +import cz.crcs.ectester.reader.Util; + +/** + * A result of EC based Key agreement operation. + * + * @author Jan Jancar johny@neuromancer.sk + */ +public class EC_KAResult extends EC_Data { + + private byte ka; + private String curve; + private String oneKey; + private String otherKey; + + private String desc; + + public EC_KAResult(byte ka, String curve, String oneKey, String otherKey) { + super(1); + this.ka = ka; + this.curve = curve; + this.oneKey = oneKey; + this.otherKey = otherKey; + } + + 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; + } + + public byte getKA() { + return ka; + } + + public String getCurve() { + return curve; + } + + public String getOneKey() { + return oneKey; + } + + public String getOtherKey() { + return otherKey; + } + + public String getDesc() { + return desc; + } + + @Override + public String toString() { + String algo = Util.getKA(ka); + return "<" + getId() + "> " + algo + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc); + } + +} diff --git a/src/cz/crcs/ectester/common/ec/EC_Key.java b/src/cz/crcs/ectester/common/ec/EC_Key.java new file mode 100644 index 0000000..a34b0e7 --- /dev/null +++ b/src/cz/crcs/ectester/common/ec/EC_Key.java @@ -0,0 +1,83 @@ +package cz.crcs.ectester.common.ec; + +import cz.crcs.ectester.applet.EC_Consts; + +/** + * An abstract-like EC key. Concrete implementations create a public and private keys. + * + * @author Jan Jancar johny@neuromancer.sk + */ +public class EC_Key extends EC_Params { + + private String curve; + private String desc; + + private EC_Key(short mask, String curve) { + super(mask); + this.curve = curve; + } + + private EC_Key(short mask, String curve, String desc) { + this(mask, curve); + this.desc = desc; + } + + private EC_Key(String id, short mask, String curve, String desc) { + this(mask, curve, desc); + this.id = id; + } + + public String getCurve() { + return curve; + } + + public String getDesc() { + return desc; + } + + /** + * An EC public key, contains the W parameter. + */ + public static class Public extends EC_Key { + + public Public(String curve) { + super(EC_Consts.PARAMETER_W, curve); + } + + public Public(String curve, String desc) { + super(EC_Consts.PARAMETER_W, curve, desc); + } + + public Public(String id, String curve, String desc) { + super(id, EC_Consts.PARAMETER_W, curve, desc); + } + + @Override + public String toString() { + return "<" + getId() + "> EC Public key, over " + getCurve() + (getDesc() == null ? "" : ": " + getDesc()); + } + } + + /** + * An EC private key, contains the S parameter. + */ + public static class Private extends EC_Key { + + public Private(String curve) { + super(EC_Consts.PARAMETER_S, curve); + } + + public Private(String curve, String desc) { + super(EC_Consts.PARAMETER_S, curve, desc); + } + + public Private(String id, String curve, String desc) { + super(id, EC_Consts.PARAMETER_S, curve, desc); + } + + @Override + public String toString() { + return "<" + getId() + "> EC Private key, over " + getCurve() + (getDesc() == null ? "" : ": " + getDesc()); + } + } +} diff --git a/src/cz/crcs/ectester/common/ec/EC_Keypair.java b/src/cz/crcs/ectester/common/ec/EC_Keypair.java new file mode 100644 index 0000000..53632cd --- /dev/null +++ b/src/cz/crcs/ectester/common/ec/EC_Keypair.java @@ -0,0 +1,41 @@ +package cz.crcs.ectester.common.ec; + +import cz.crcs.ectester.applet.EC_Consts; + +/** + * An EC keypair, contains both the W and S parameters. + * + * @author Jan Jancar johny@neuromancer.sk + */ +public class EC_Keypair extends EC_Params { + private String curve; + private String desc; + + public EC_Keypair(String curve) { + super(EC_Consts.PARAMETERS_KEYPAIR); + this.curve = curve; + } + + public EC_Keypair(String curve, String desc) { + this(curve); + this.desc = desc; + } + + public EC_Keypair(String id, String curve, String desc) { + this(curve, desc); + this.id = id; + } + + public String getCurve() { + return curve; + } + + public String getDesc() { + return desc; + } + + @Override + public String toString() { + return "<" + getId() + "> EC Keypair, over " + curve + (desc == null ? "" : ": " + desc); + } +} diff --git a/src/cz/crcs/ectester/common/ec/EC_Params.java b/src/cz/crcs/ectester/common/ec/EC_Params.java new file mode 100644 index 0000000..5b8295e --- /dev/null +++ b/src/cz/crcs/ectester/common/ec/EC_Params.java @@ -0,0 +1,151 @@ +package cz.crcs.ectester.common.ec; + +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.reader.Util; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * A list of EC parameters, can contain a subset of the Fp/F2M, A, B, G, R, K, W, S parameters. + * + * The set of parameters is uniquely identified by a short bit string. + * The parameters can be exported to a byte array via flatten() or to a comma delimited + * string via expand(). + * @author Jan Jancar johny@neuromancer.sk + */ +public class EC_Params extends EC_Data { + private short params; + + public EC_Params(short params) { + this.params = params; + this.count = numParams(); + this.data = new byte[this.count][]; + } + + public EC_Params(short params, byte[][] data) { + this.params = params; + this.count = data.length; + 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; + } + + public boolean hasParam(short param) { + return (params & param) != 0; + } + + public int numParams() { + short paramMask = EC_Consts.PARAMETER_FP; + int num = 0; + while (paramMask <= EC_Consts.PARAMETER_S) { + if ((paramMask & params) != 0) { + if (paramMask == EC_Consts.PARAMETER_F2M) { + num += 3; + } + if (paramMask == EC_Consts.PARAMETER_W || paramMask == EC_Consts.PARAMETER_G) { + num += 1; + } + ++num; + } + paramMask = (short) (paramMask << 1); + } + return num; + } + + @Override + public byte[] flatten() { + return flatten(params); + } + + public byte[] flatten(short params) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + short paramMask = EC_Consts.PARAMETER_FP; + int i = 0; + while (paramMask <= EC_Consts.PARAMETER_S) { + short masked = (short) (this.params & params & paramMask); + short shallow = (short) (this.params & paramMask); + if (masked != 0) { + 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]); + 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) { + //read another param (the y coord) and put into X962 format. + byte[] y = data[i + 1]; + param = Util.concatenate(new byte[]{4}, param, y); //<- ugly but works! + } + if (param.length == 0) + throw new RuntimeException("Empty parameter read?"); + + //write length + byte[] length = new byte[2]; + Util.setShort(length, 0, (short) param.length); + out.write(length, 0, 2); + //write data + out.write(param, 0, param.length); + } + if (shallow == EC_Consts.PARAMETER_F2M) { + i += 4; + } else if (shallow == EC_Consts.PARAMETER_G || shallow == EC_Consts.PARAMETER_W) { + i += 2; + } else if (shallow != 0) { + i++; + } + paramMask = (short) (paramMask << 1); + } + + return (out.size() == 0) ? null : out.toByteArray(); + } + + @Override + public String[] expand() { + List out = new ArrayList<>(); + + short paramMask = EC_Consts.PARAMETER_FP; + int index = 0; + while (paramMask <= EC_Consts.PARAMETER_S) { + short masked = (short) (params & paramMask); + if (masked != 0) { + byte[] param = data[index]; + if (masked == EC_Consts.PARAMETER_F2M) { + for (int i = 0; i < 4; ++i) { + out.add(Util.bytesToHex(data[index + i], false)); + } + index += 4; + } else if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) { + out.add(Util.bytesToHex(param, false)); + out.add(Util.bytesToHex(data[index + 1], false)); + index += 2; + } else { + out.add(Util.bytesToHex(param, false)); + index++; + } + } + paramMask = (short) (paramMask << 1); + } + return out.toArray(new String[out.size()]); + } +} diff --git a/src/cz/crcs/ectester/data/EC_Store.java b/src/cz/crcs/ectester/data/EC_Store.java index 9b1f5bb..3103c1d 100644 --- a/src/cz/crcs/ectester/data/EC_Store.java +++ b/src/cz/crcs/ectester/data/EC_Store.java @@ -1,7 +1,7 @@ package cz.crcs.ectester.data; import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.reader.ec.*; +import cz.crcs.ectester.common.ec.*; import javacard.security.KeyPair; import org.w3c.dom.Document; import org.w3c.dom.Element; diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java deleted file mode 100644 index 550e070..0000000 --- a/src/cz/crcs/ectester/reader/ECTester.java +++ /dev/null @@ -1,856 +0,0 @@ -/* - * Copyright (c) 2016-2017 Petr Svenda - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -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.command.Command; -import cz.crcs.ectester.reader.ec.EC_Category; -import cz.crcs.ectester.reader.ec.EC_Data; -import cz.crcs.ectester.reader.ec.EC_Params; -import cz.crcs.ectester.reader.output.*; -import cz.crcs.ectester.reader.response.Response; -import cz.crcs.ectester.reader.test.*; -import javacard.security.KeyPair; -import org.apache.commons.cli.*; - -import javax.smartcardio.CardException; -import javax.xml.parsers.ParserConfigurationException; -import java.io.*; -import java.nio.file.Files; -import java.util.*; - -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH; - -/** - * Reader part of ECTester, a tool for testing Elliptic curve support on javacards. - * - * @author Petr Svenda petr@svenda.com - * @author Jan Jancar johny@neuromancer.sk - * @version v0.1.0 - */ -public class ECTester { - - private CardMngr cardManager; - private OutputLogger logger; - private TestWriter testWriter; - private ResponseWriter respWriter; - private EC_Store dataStore; - private Config cfg; - - private Options opts = new Options(); - private static final String VERSION = "v0.1.0"; - private static final String DESCRIPTION = "ECTester " + VERSION + ", a javacard Elliptic Curve Cryptograhy support tester/utility."; - private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda "; - private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; - private static final String CLI_FOOTER = "\n" + LICENSE; - - private static final byte[] SELECT_ECTESTERAPPLET = {(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x0a, - (byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x31}; - private static final byte[] AID = {(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x31}; - private static final byte[] INSTALL_DATA = new byte[10]; - - private void run(String[] args) { - try { - CommandLine cli = parseArgs(args); - - //if help, print and quit - if (cli.hasOption("help")) { - help(); - return; - } else if (cli.hasOption("version")) { - System.out.println(DESCRIPTION); - System.out.println(LICENSE); - return; - } - cfg = new Config(); - - //if not, read other options first, into attributes, then do action - if (!cfg.readOptions(cli)) { - return; - } - - dataStore = new EC_Store(); - //if list, print and quit - if (cli.hasOption("list-named")) { - list(); - return; - } - - //init CardManager - cardManager = new CardMngr(cfg.verbose, cfg.simulate); - - //connect or simulate connection - if (cfg.simulate) { - if (!cardManager.prepareLocalSimulatorApplet(AID, INSTALL_DATA, ECTesterApplet.class)) { - System.err.println("Failed to establish a simulator."); - System.exit(1); - } - } else { - if (!cardManager.connectToCardSelect()) { - System.err.println("Failed to connect to card."); - System.exit(1); - } - cardManager.send(SELECT_ECTESTERAPPLET); - } - - // Setup logger, testWriter and respWriter - logger = new OutputLogger(true, cfg.log); - if (cfg.format == null) { - testWriter = new TextTestWriter(logger.getPrintStream()); - } else { - switch (cfg.format) { - case "text": - testWriter = new TextTestWriter(logger.getPrintStream()); - break; - case "xml": - testWriter = new XMLTestWriter(logger.getOutputStream()); - break; - case "yaml": - case "yml": - testWriter = new YAMLTestWriter(logger.getPrintStream()); - break; - } - } - respWriter = new ResponseWriter(logger.getPrintStream()); - - //do action - if (cli.hasOption("export")) { - export(); - } else if (cli.hasOption("generate")) { - generate(); - } else if (cli.hasOption("test")) { - test(); - } else if (cli.hasOption("ecdh") || cli.hasOption("ecdhc")) { - ecdh(); - } else if (cli.hasOption("ecdsa")) { - ecdsa(); - } - - //disconnect - cardManager.disconnectFromCard(); - logger.close(); - - } catch (MissingOptionException moex) { - System.err.println("Missing required options, one of:"); - for (Object opt : moex.getMissingOptions().toArray()) { - if (opt instanceof OptionGroup) { - for (Option o : ((OptionGroup) opt).getOptions()) { - System.err.print("-" + o.getOpt()); - - if (o.hasLongOpt()) { - System.err.print("\t/ --" + o.getLongOpt() + " "); - } - - if (o.hasArg()) { - if (o.hasOptionalArg()) { - System.err.print("[" + o.getArgName() + "] "); - } else { - System.err.print("<" + o.getArgName() + "> "); - } - } - - if (o.getDescription() != null) { - System.err.print("\t\t\t" + o.getDescription()); - } - System.err.println(); - } - } else if (opt instanceof String) { - System.err.println(opt); - } - } - } catch (MissingArgumentException maex) { - System.err.println("Option, " + maex.getOption().getOpt() + " requires an argument: " + maex.getOption().getArgName()); - } catch (NumberFormatException nfex) { - System.err.println("Not a number. " + nfex.getMessage()); - } catch (FileNotFoundException fnfe) { - System.err.println("File " + fnfe.getMessage() + " not found."); - } catch (ParseException | IOException ex) { - System.err.println(ex.getMessage()); - } catch (CardException ex) { - if (logger != null) - logger.println(ex.getMessage()); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } finally { - if (logger != null) - logger.flush(); - } - } - - /** - * Parses command-line options. - * - * @param args cli arguments - * @return parsed CommandLine object - * @throws ParseException if there are any problems encountered while parsing the command line tokens - */ - private CommandLine parseArgs(String[] args) throws ParseException { - /* - * Actions: - * -V / --version - * -h / --help - * -e / --export - * -g / --generate [amount] - * -t / --test [test_suite] - * -dh / --ecdh [count] - * -dhc / --ecdhc [count] - * -dsa / --ecdsa [count] - * -ln / --list-named [obj] - * - * Options: - * -b / --bit-size // -a / --all - * - * -fp / --prime-field - * -f2m / --binary-field - * - * -u / --custom - * -nc / --named-curve - * -c / --curve field,a,b,gx,gy,r,k - * - * -pub / --public wx,wy - * -npub / --named-public - * - * -priv / --private s - * -npriv / --named-private - * - * -k / --key wx,wy,s - * -nk / --named-key - * - * -v / --verbose - * - * -i / --input - * -o / --output - * --format - * -l / --log [log_file] - * - * -f / --fresh - * -s / --simulate - * -y / --yes - * -ka/ --ka-type - */ - OptionGroup actions = new OptionGroup(); - actions.setRequired(true); - actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); - actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); - actions.addOption(Option.builder("ln").longOpt("list-named").desc("Print the list of supported named curves and keys.").hasArg().argName("what").optionalArg(true).build()); - actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build()); - actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build()); - actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- wrong:\n- composite:\n- test-vectors:").hasArg().argName("test_suite").optionalArg(true).build()); - actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do ECDH, [count] times.").hasArg().argName("count").optionalArg(true).build()); - actions.addOption(Option.builder("dhc").longOpt("ecdhc").desc("Do ECDHC, [count] times.").hasArg().argName("count").optionalArg(true).build()); - actions.addOption(Option.builder("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build()); - - opts.addOptionGroup(actions); - - OptionGroup size = new OptionGroup(); - size.addOption(Option.builder("b").longOpt("bit-size").desc("Set curve size.").hasArg().argName("bits").build()); - size.addOption(Option.builder("a").longOpt("all").desc("Test all curve sizes.").build()); - opts.addOptionGroup(size); - - opts.addOption(Option.builder("fp").longOpt("prime-field").desc("Use a prime field.").build()); - opts.addOption(Option.builder("f2m").longOpt("binary-field").desc("Use a binary field.").build()); - - OptionGroup curve = new OptionGroup(); - curve.addOption(Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: ").hasArg().argName("cat/id").build()); - curve.addOption(Option.builder("c").longOpt("curve").desc("Use curve from file (field,a,b,gx,gy,r,k).").hasArg().argName("curve_file").build()); - curve.addOption(Option.builder("u").longOpt("custom").desc("Use a custom curve (applet-side embedded, SECG curves).").build()); - opts.addOptionGroup(curve); - - OptionGroup pub = new OptionGroup(); - pub.addOption(Option.builder("npub").longOpt("named-public").desc("Use public key from KeyDB: ").hasArg().argName("cat/id").build()); - pub.addOption(Option.builder("pub").longOpt("public").desc("Use public key from file (wx,wy).").hasArg().argName("pubkey_file").build()); - opts.addOptionGroup(pub); - - OptionGroup priv = new OptionGroup(); - priv.addOption(Option.builder("npriv").longOpt("named-private").desc("Use private key from KeyDB: ").hasArg().argName("cat/id").build()); - priv.addOption(Option.builder("priv").longOpt("private").desc("Use private key from file (s).").hasArg().argName("privkey_file").build()); - opts.addOptionGroup(priv); - - OptionGroup key = new OptionGroup(); - key.addOption(Option.builder("nk").longOpt("named-key").desc("Use keyPair from KeyDB: ").hasArg().argName("cat/id").build()); - key.addOption(Option.builder("k").longOpt("key").desc("Use keyPair from fileĀ  (wx,wy,s).").hasArg().argName("key_file").build()); - opts.addOptionGroup(key); - - opts.addOption(Option.builder("i").longOpt("input").desc("Input from fileĀ , for ECDSA signing.").hasArg().argName("input_file").build()); - opts.addOption(Option.builder("o").longOpt("output").desc("Output into file .").hasArg().argName("output_file").build()); - opts.addOption(Option.builder("l").longOpt("log").desc("Log output into file [log_file].").hasArg().argName("log_file").optionalArg(true).build()); - opts.addOption(Option.builder("v").longOpt("verbose").desc("Turn on verbose logging.").build()); - opts.addOption(Option.builder().longOpt("format").desc("Output format to use. One of: text,yml,xml.").hasArg().argName("format").build()); - - opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build()); - opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build()); - opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build()); - - opts.addOption(Option.builder("ka").longOpt("ka-type").desc("Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants.").hasArg().argName("type").optionalArg(true).build()); - - CommandLineParser parser = new DefaultParser(); - return parser.parse(opts, args); - } - - /** - * Prints help. - */ - private void help() { - HelpFormatter help = new HelpFormatter(); - help.setOptionComparator(null); - help.printHelp("ECTester.jar", CLI_HEADER, opts, CLI_FOOTER, true); - } - - /** - * List categories and named curves. - */ - private void list() { - Map categories = dataStore.getCategories(); - if (cfg.listNamed == null) { - // print all categories, briefly - for (EC_Category cat : categories.values()) { - System.out.println(cat); - } - } else if (categories.containsKey(cfg.listNamed)) { - // print given category - System.out.println(categories.get(cfg.listNamed)); - } else { - // print given object - EC_Data object = dataStore.getObject(EC_Data.class, cfg.listNamed); - if (object != null) { - System.out.println(object); - } else { - System.err.println("Named object " + cfg.listNamed + " not found!"); - } - } - } - - /** - * Exports default card/simulation EC domain parameters to output file. - * - * @throws CardException if APDU transmission fails - * @throws IOException if an IO error occurs when writing to key file. - */ - private void export() throws CardException, IOException { - 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) 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 = 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()) { - export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send(); - } - sent.add(export); - - for (Response r : sent) { - respWriter.outputResponse(r); - } - - EC_Params exported = new EC_Params(domain, export.getParams()); - - FileOutputStream out = new FileOutputStream(cfg.output); - exported.writeCSV(out); - out.close(); - } - - /** - * Generates EC keyPairs and outputs them to output file. - * - * @throws CardException if APDU transmission fails - * @throws IOException if an IO error occurs when writing to key file. - */ - private void generate() throws CardException, IOException { - byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; - - new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send(); - Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass); - - FileWriter keysFile = new FileWriter(cfg.output); - keysFile.write("index;time;pubW;privS\n"); - - int generated = 0; - int retry = 0; - while (generated < cfg.generateAmount || cfg.generateAmount == 0) { - if ((cfg.fresh || generated == 0) && curve != null) { - Response fresh = curve.send(); - respWriter.outputResponse(fresh); - } - - Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL); - Response.Generate response = generate.send(); - long elapsed = response.getDuration(); - - Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send(); - - if (!response.successful() || !export.successful()) { - if (retry < 10) { - retry++; - continue; - } else { - System.err.println("Keys could not be generated."); - break; - } - } - respWriter.outputResponse(response); - - String pub = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false); - String priv = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false); - String line = String.format("%d;%d;%s;%s\n", generated, elapsed / 1000000, pub, priv); - keysFile.write(line); - keysFile.flush(); - generated++; - } - Response cleanup = new Command.Cleanup(cardManager).send(); - respWriter.outputResponse(cleanup); - - keysFile.close(); - } - - /** - * Tests Elliptic curve support for a given curve/curves. - * - * @throws CardException if APDU transmission fails - * @throws IOException if an IO error occurs when writing to key file. - */ - private void test() throws IOException, CardException { - TestSuite suite; - - switch (cfg.testSuite) { - case "default": - suite = new DefaultSuite(dataStore, cfg); - break; - case "test-vectors": - suite = new TestVectorSuite(dataStore, cfg); - break; - default: - // These tests are dangerous, prompt before them. - 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."); - if (!cfg.yes) { - System.out.print("Do you want to proceed? (y/n): "); - Scanner in = new Scanner(System.in); - String confirmation = in.nextLine().toLowerCase(); - if (!Arrays.asList("yes", "y").contains(confirmation)) { - return; - } - in.close(); - } - - - switch (cfg.testSuite) { - case "wrong": - suite = new WrongCurvesSuite(dataStore, cfg); - break; - case "composite": - suite = new CompositeCurvesSuite(dataStore, cfg); - break; - case "invalid": - suite = new InvalidCurvesSuite(dataStore, cfg); - break; - default: - System.err.println("Unknown test suite."); - return; - } - break; - } - - TestRunner runner = new TestRunner(suite, testWriter); - suite.setup(cardManager); - runner.run(); - } - - /** - * Performs ECDH key exchange. - * - * @throws CardException if APDU transmission fails - * @throws IOException if an IO error occurs when writing to key file. - */ - private void ecdh() throws IOException, CardException { - byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; - List prepare = new LinkedList<>(); - prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.kaType).send()); // Prepare KeyAgreement or required type - prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass).send()); - Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass); - if (curve != null) - prepare.add(curve.send()); - - for (Response r : prepare) { - respWriter.outputResponse(r); - } - - 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 (cfg.anyPublicKey || cfg.anyPrivateKey || cfg.anyKey) { - generate.add(Command.prepareKey(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_REMOTE)); - } - - FileWriter out = null; - if (cfg.output != null) { - out = new FileWriter(cfg.output); - out.write("index;time;secret\n"); - } - - int retry = 0; - int done = 0; - 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, cfg.ECDHKA).send(); - ecdh.add(perform); - for (Response r : ecdh) { - respWriter.outputResponse(r); - } - - if (!perform.successful() || !perform.hasSecret()) { - if (retry < 10) { - ++retry; - continue; - } else { - System.err.println("Couldn't obtain ECDH secret from card response."); - break; - } - } - - if (out != null) { - out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSecret(), false))); - } - - ++done; - } - Response cleanup = new Command.Cleanup(cardManager).send(); - respWriter.outputResponse(cleanup); - - if (out != null) - out.close(); - } - - /** - * Performs ECDSA signature, on random or provided data. - * - * @throws CardException if APDU transmission fails - * @throws IOException if an IO error occurs when writing to key file. - */ - private void ecdsa() throws CardException, IOException { - //read file, if asked to sign - byte[] data = null; - if (cfg.input != null) { - File in = new File(cfg.input); - long len = in.length(); - if (len == 0) { - throw new FileNotFoundException(cfg.input); - } - data = Files.readAllBytes(in.toPath()); - } - - Command generate; - if (cfg.anyKeypart) { - generate = Command.prepareKey(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL); - } else { - generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL); - } - - 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) cfg.bits, keyClass).send()); - Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass); - if (curve != null) - prepare.add(curve.send()); - - for (Response r : prepare) { - respWriter.outputResponse(r); - } - - FileWriter out = null; - if (cfg.output != null) { - out = new FileWriter(cfg.output); - out.write("index;time;signature\n"); - } - - int retry = 0; - int done = 0; - while (done < cfg.ECDSACount) { - List ecdsa = new LinkedList<>(); - ecdsa.add(generate.send()); - - Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, data).send(); - ecdsa.add(perform); - for (Response r : ecdsa) { - respWriter.outputResponse(r); - } - - if (!perform.successful() || !perform.hasSignature()) { - if (retry < 10) { - ++retry; - continue; - } else { - System.err.println("Couldn't obtain ECDSA signature from card response."); - break; - } - } - - if (out != null) { - out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSignature(), false))); - } - - ++done; - } - Response cleanup = new Command.Cleanup(cardManager).send(); - respWriter.outputResponse(cleanup); - - if (out != null) - out.close(); - } - - public static void main(String[] args) { - 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 byte kaType = KeyAgreement_ALG_EC_SVDP_DH; - - 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; - public boolean yes = false; - public String format; - - //Action-related options - 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. - */ - boolean readOptions(CommandLine cli) { - bits = Integer.parseInt(cli.getOptionValue("bit-size", "0")); - all = cli.hasOption("all"); - primeField = cli.hasOption("fp"); - binaryField = cli.hasOption("f2m"); - kaType = Byte.parseByte(cli.getOptionValue("ka-type", "1")); - - 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"); - yes = cli.hasOption("yes"); - - if (cli.hasOption("list-named")) { - listNamed = cli.getOptionValue("list-named"); - return true; - } - - format = cli.getOptionValue("format", "text"); - String formats[] = new String[]{"text", "xml", "yaml", "yml"}; - if (!Arrays.asList(formats).contains(format)) { - System.err.println("Wrong output format " + format + ". Should be one of " + Arrays.toString(formats)); - return false; - } - - 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", "composite", "invalid", "test-vectors", "wrong"}; - if (!Arrays.asList(tests).contains(testSuite)) { - System.err.println("Unknown test suite " + testSuite + ". 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/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java new file mode 100644 index 0000000..4eadfd3 --- /dev/null +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -0,0 +1,856 @@ +/* + * Copyright (c) 2016-2017 Petr Svenda + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +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.command.Command; +import cz.crcs.ectester.common.ec.EC_Category; +import cz.crcs.ectester.common.ec.EC_Data; +import cz.crcs.ectester.common.ec.EC_Params; +import cz.crcs.ectester.reader.output.*; +import cz.crcs.ectester.reader.response.Response; +import cz.crcs.ectester.reader.test.*; +import javacard.security.KeyPair; +import org.apache.commons.cli.*; + +import javax.smartcardio.CardException; +import javax.xml.parsers.ParserConfigurationException; +import java.io.*; +import java.nio.file.Files; +import java.util.*; + +import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH; + +/** + * Reader part of ECTester, a tool for testing Elliptic curve support on javacards. + * + * @author Petr Svenda petr@svenda.com + * @author Jan Jancar johny@neuromancer.sk + * @version v0.1.0 + */ +public class ECTesterReader { + + private CardMngr cardManager; + private OutputLogger logger; + private TestWriter testWriter; + private ResponseWriter respWriter; + private EC_Store dataStore; + private Config cfg; + + private Options opts = new Options(); + private static final String VERSION = "v0.1.0"; + private static final String DESCRIPTION = "ECTesterReader " + VERSION + ", a javacard Elliptic Curve Cryptograhy support tester/utility."; + private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda "; + private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; + private static final String CLI_FOOTER = "\n" + LICENSE; + + private static final byte[] SELECT_ECTESTERAPPLET = {(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x0a, + (byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x31}; + private static final byte[] AID = {(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x31}; + private static final byte[] INSTALL_DATA = new byte[10]; + + private void run(String[] args) { + try { + CommandLine cli = parseArgs(args); + + //if help, print and quit + if (cli.hasOption("help")) { + help(); + return; + } else if (cli.hasOption("version")) { + System.out.println(DESCRIPTION); + System.out.println(LICENSE); + return; + } + cfg = new Config(); + + //if not, read other options first, into attributes, then do action + if (!cfg.readOptions(cli)) { + return; + } + + dataStore = new EC_Store(); + //if list, print and quit + if (cli.hasOption("list-named")) { + list(); + return; + } + + //init CardManager + cardManager = new CardMngr(cfg.verbose, cfg.simulate); + + //connect or simulate connection + if (cfg.simulate) { + if (!cardManager.prepareLocalSimulatorApplet(AID, INSTALL_DATA, ECTesterApplet.class)) { + System.err.println("Failed to establish a simulator."); + System.exit(1); + } + } else { + if (!cardManager.connectToCardSelect()) { + System.err.println("Failed to connect to card."); + System.exit(1); + } + cardManager.send(SELECT_ECTESTERAPPLET); + } + + // Setup logger, testWriter and respWriter + logger = new OutputLogger(true, cfg.log); + if (cfg.format == null) { + testWriter = new TextTestWriter(logger.getPrintStream()); + } else { + switch (cfg.format) { + case "text": + testWriter = new TextTestWriter(logger.getPrintStream()); + break; + case "xml": + testWriter = new XMLTestWriter(logger.getOutputStream()); + break; + case "yaml": + case "yml": + testWriter = new YAMLTestWriter(logger.getPrintStream()); + break; + } + } + respWriter = new ResponseWriter(logger.getPrintStream()); + + //do action + if (cli.hasOption("export")) { + export(); + } else if (cli.hasOption("generate")) { + generate(); + } else if (cli.hasOption("test")) { + test(); + } else if (cli.hasOption("ecdh") || cli.hasOption("ecdhc")) { + ecdh(); + } else if (cli.hasOption("ecdsa")) { + ecdsa(); + } + + //disconnect + cardManager.disconnectFromCard(); + logger.close(); + + } catch (MissingOptionException moex) { + System.err.println("Missing required options, one of:"); + for (Object opt : moex.getMissingOptions().toArray()) { + if (opt instanceof OptionGroup) { + for (Option o : ((OptionGroup) opt).getOptions()) { + System.err.print("-" + o.getOpt()); + + if (o.hasLongOpt()) { + System.err.print("\t/ --" + o.getLongOpt() + " "); + } + + if (o.hasArg()) { + if (o.hasOptionalArg()) { + System.err.print("[" + o.getArgName() + "] "); + } else { + System.err.print("<" + o.getArgName() + "> "); + } + } + + if (o.getDescription() != null) { + System.err.print("\t\t\t" + o.getDescription()); + } + System.err.println(); + } + } else if (opt instanceof String) { + System.err.println(opt); + } + } + } catch (MissingArgumentException maex) { + System.err.println("Option, " + maex.getOption().getOpt() + " requires an argument: " + maex.getOption().getArgName()); + } catch (NumberFormatException nfex) { + System.err.println("Not a number. " + nfex.getMessage()); + } catch (FileNotFoundException fnfe) { + System.err.println("File " + fnfe.getMessage() + " not found."); + } catch (ParseException | IOException ex) { + System.err.println(ex.getMessage()); + } catch (CardException ex) { + if (logger != null) + logger.println(ex.getMessage()); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } finally { + if (logger != null) + logger.flush(); + } + } + + /** + * Parses command-line options. + * + * @param args cli arguments + * @return parsed CommandLine object + * @throws ParseException if there are any problems encountered while parsing the command line tokens + */ + private CommandLine parseArgs(String[] args) throws ParseException { + /* + * Actions: + * -V / --version + * -h / --help + * -e / --export + * -g / --generate [amount] + * -t / --test [test_suite] + * -dh / --ecdh [count] + * -dhc / --ecdhc [count] + * -dsa / --ecdsa [count] + * -ln / --list-named [obj] + * + * Options: + * -b / --bit-size // -a / --all + * + * -fp / --prime-field + * -f2m / --binary-field + * + * -u / --custom + * -nc / --named-curve + * -c / --curve field,a,b,gx,gy,r,k + * + * -pub / --public wx,wy + * -npub / --named-public + * + * -priv / --private s + * -npriv / --named-private + * + * -k / --key wx,wy,s + * -nk / --named-key + * + * -v / --verbose + * + * -i / --input + * -o / --output + * --format + * -l / --log [log_file] + * + * -f / --fresh + * -s / --simulate + * -y / --yes + * -ka/ --ka-type + */ + OptionGroup actions = new OptionGroup(); + actions.setRequired(true); + actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); + actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); + actions.addOption(Option.builder("ln").longOpt("list-named").desc("Print the list of supported named curves and keys.").hasArg().argName("what").optionalArg(true).build()); + actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build()); + actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build()); + actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- wrong:\n- composite:\n- test-vectors:").hasArg().argName("test_suite").optionalArg(true).build()); + actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do ECDH, [count] times.").hasArg().argName("count").optionalArg(true).build()); + actions.addOption(Option.builder("dhc").longOpt("ecdhc").desc("Do ECDHC, [count] times.").hasArg().argName("count").optionalArg(true).build()); + actions.addOption(Option.builder("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build()); + + opts.addOptionGroup(actions); + + OptionGroup size = new OptionGroup(); + size.addOption(Option.builder("b").longOpt("bit-size").desc("Set curve size.").hasArg().argName("bits").build()); + size.addOption(Option.builder("a").longOpt("all").desc("Test all curve sizes.").build()); + opts.addOptionGroup(size); + + opts.addOption(Option.builder("fp").longOpt("prime-field").desc("Use a prime field.").build()); + opts.addOption(Option.builder("f2m").longOpt("binary-field").desc("Use a binary field.").build()); + + OptionGroup curve = new OptionGroup(); + curve.addOption(Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: ").hasArg().argName("cat/id").build()); + curve.addOption(Option.builder("c").longOpt("curve").desc("Use curve from file (field,a,b,gx,gy,r,k).").hasArg().argName("curve_file").build()); + curve.addOption(Option.builder("u").longOpt("custom").desc("Use a custom curve (applet-side embedded, SECG curves).").build()); + opts.addOptionGroup(curve); + + OptionGroup pub = new OptionGroup(); + pub.addOption(Option.builder("npub").longOpt("named-public").desc("Use public key from KeyDB: ").hasArg().argName("cat/id").build()); + pub.addOption(Option.builder("pub").longOpt("public").desc("Use public key from file (wx,wy).").hasArg().argName("pubkey_file").build()); + opts.addOptionGroup(pub); + + OptionGroup priv = new OptionGroup(); + priv.addOption(Option.builder("npriv").longOpt("named-private").desc("Use private key from KeyDB: ").hasArg().argName("cat/id").build()); + priv.addOption(Option.builder("priv").longOpt("private").desc("Use private key from file (s).").hasArg().argName("privkey_file").build()); + opts.addOptionGroup(priv); + + OptionGroup key = new OptionGroup(); + key.addOption(Option.builder("nk").longOpt("named-key").desc("Use keyPair from KeyDB: ").hasArg().argName("cat/id").build()); + key.addOption(Option.builder("k").longOpt("key").desc("Use keyPair from fileĀ  (wx,wy,s).").hasArg().argName("key_file").build()); + opts.addOptionGroup(key); + + opts.addOption(Option.builder("i").longOpt("input").desc("Input from fileĀ , for ECDSA signing.").hasArg().argName("input_file").build()); + opts.addOption(Option.builder("o").longOpt("output").desc("Output into file .").hasArg().argName("output_file").build()); + opts.addOption(Option.builder("l").longOpt("log").desc("Log output into file [log_file].").hasArg().argName("log_file").optionalArg(true).build()); + opts.addOption(Option.builder("v").longOpt("verbose").desc("Turn on verbose logging.").build()); + opts.addOption(Option.builder().longOpt("format").desc("Output format to use. One of: text,yml,xml.").hasArg().argName("format").build()); + + opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build()); + opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build()); + opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build()); + + opts.addOption(Option.builder("ka").longOpt("ka-type").desc("Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants.").hasArg().argName("type").optionalArg(true).build()); + + CommandLineParser parser = new DefaultParser(); + return parser.parse(opts, args); + } + + /** + * Prints help. + */ + private void help() { + HelpFormatter help = new HelpFormatter(); + help.setOptionComparator(null); + help.printHelp("ECTesterReader.jar", CLI_HEADER, opts, CLI_FOOTER, true); + } + + /** + * List categories and named curves. + */ + private void list() { + Map categories = dataStore.getCategories(); + if (cfg.listNamed == null) { + // print all categories, briefly + for (EC_Category cat : categories.values()) { + System.out.println(cat); + } + } else if (categories.containsKey(cfg.listNamed)) { + // print given category + System.out.println(categories.get(cfg.listNamed)); + } else { + // print given object + EC_Data object = dataStore.getObject(EC_Data.class, cfg.listNamed); + if (object != null) { + System.out.println(object); + } else { + System.err.println("Named object " + cfg.listNamed + " not found!"); + } + } + } + + /** + * Exports default card/simulation EC domain parameters to output file. + * + * @throws CardException if APDU transmission fails + * @throws IOException if an IO error occurs when writing to key file. + */ + private void export() throws CardException, IOException { + 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) 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 = 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()) { + export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send(); + } + sent.add(export); + + for (Response r : sent) { + respWriter.outputResponse(r); + } + + EC_Params exported = new EC_Params(domain, export.getParams()); + + FileOutputStream out = new FileOutputStream(cfg.output); + exported.writeCSV(out); + out.close(); + } + + /** + * Generates EC keyPairs and outputs them to output file. + * + * @throws CardException if APDU transmission fails + * @throws IOException if an IO error occurs when writing to key file. + */ + private void generate() throws CardException, IOException { + byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; + + new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send(); + Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass); + + FileWriter keysFile = new FileWriter(cfg.output); + keysFile.write("index;time;pubW;privS\n"); + + int generated = 0; + int retry = 0; + while (generated < cfg.generateAmount || cfg.generateAmount == 0) { + if ((cfg.fresh || generated == 0) && curve != null) { + Response fresh = curve.send(); + respWriter.outputResponse(fresh); + } + + Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL); + Response.Generate response = generate.send(); + long elapsed = response.getDuration(); + + Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send(); + + if (!response.successful() || !export.successful()) { + if (retry < 10) { + retry++; + continue; + } else { + System.err.println("Keys could not be generated."); + break; + } + } + respWriter.outputResponse(response); + + String pub = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false); + String priv = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false); + String line = String.format("%d;%d;%s;%s\n", generated, elapsed / 1000000, pub, priv); + keysFile.write(line); + keysFile.flush(); + generated++; + } + Response cleanup = new Command.Cleanup(cardManager).send(); + respWriter.outputResponse(cleanup); + + keysFile.close(); + } + + /** + * Tests Elliptic curve support for a given curve/curves. + * + * @throws CardException if APDU transmission fails + * @throws IOException if an IO error occurs when writing to key file. + */ + private void test() throws IOException, CardException { + TestSuite suite; + + switch (cfg.testSuite) { + case "default": + suite = new DefaultSuite(dataStore, cfg); + break; + case "test-vectors": + suite = new TestVectorSuite(dataStore, cfg); + break; + default: + // These tests are dangerous, prompt before them. + 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."); + if (!cfg.yes) { + System.out.print("Do you want to proceed? (y/n): "); + Scanner in = new Scanner(System.in); + String confirmation = in.nextLine().toLowerCase(); + if (!Arrays.asList("yes", "y").contains(confirmation)) { + return; + } + in.close(); + } + + + switch (cfg.testSuite) { + case "wrong": + suite = new WrongCurvesSuite(dataStore, cfg); + break; + case "composite": + suite = new CompositeCurvesSuite(dataStore, cfg); + break; + case "invalid": + suite = new InvalidCurvesSuite(dataStore, cfg); + break; + default: + System.err.println("Unknown test suite."); + return; + } + break; + } + + TestRunner runner = new TestRunner(suite, testWriter); + suite.setup(cardManager); + runner.run(); + } + + /** + * Performs ECDH key exchange. + * + * @throws CardException if APDU transmission fails + * @throws IOException if an IO error occurs when writing to key file. + */ + private void ecdh() throws IOException, CardException { + byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; + List prepare = new LinkedList<>(); + prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.kaType).send()); // Prepare KeyAgreement or required type + prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass).send()); + Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass); + if (curve != null) + prepare.add(curve.send()); + + for (Response r : prepare) { + respWriter.outputResponse(r); + } + + 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 (cfg.anyPublicKey || cfg.anyPrivateKey || cfg.anyKey) { + generate.add(Command.prepareKey(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_REMOTE)); + } + + FileWriter out = null; + if (cfg.output != null) { + out = new FileWriter(cfg.output); + out.write("index;time;secret\n"); + } + + int retry = 0; + int done = 0; + 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, cfg.ECDHKA).send(); + ecdh.add(perform); + for (Response r : ecdh) { + respWriter.outputResponse(r); + } + + if (!perform.successful() || !perform.hasSecret()) { + if (retry < 10) { + ++retry; + continue; + } else { + System.err.println("Couldn't obtain ECDH secret from card response."); + break; + } + } + + if (out != null) { + out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSecret(), false))); + } + + ++done; + } + Response cleanup = new Command.Cleanup(cardManager).send(); + respWriter.outputResponse(cleanup); + + if (out != null) + out.close(); + } + + /** + * Performs ECDSA signature, on random or provided data. + * + * @throws CardException if APDU transmission fails + * @throws IOException if an IO error occurs when writing to key file. + */ + private void ecdsa() throws CardException, IOException { + //read file, if asked to sign + byte[] data = null; + if (cfg.input != null) { + File in = new File(cfg.input); + long len = in.length(); + if (len == 0) { + throw new FileNotFoundException(cfg.input); + } + data = Files.readAllBytes(in.toPath()); + } + + Command generate; + if (cfg.anyKeypart) { + generate = Command.prepareKey(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL); + } else { + generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL); + } + + 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) cfg.bits, keyClass).send()); + Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass); + if (curve != null) + prepare.add(curve.send()); + + for (Response r : prepare) { + respWriter.outputResponse(r); + } + + FileWriter out = null; + if (cfg.output != null) { + out = new FileWriter(cfg.output); + out.write("index;time;signature\n"); + } + + int retry = 0; + int done = 0; + while (done < cfg.ECDSACount) { + List ecdsa = new LinkedList<>(); + ecdsa.add(generate.send()); + + Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, data).send(); + ecdsa.add(perform); + for (Response r : ecdsa) { + respWriter.outputResponse(r); + } + + if (!perform.successful() || !perform.hasSignature()) { + if (retry < 10) { + ++retry; + continue; + } else { + System.err.println("Couldn't obtain ECDSA signature from card response."); + break; + } + } + + if (out != null) { + out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSignature(), false))); + } + + ++done; + } + Response cleanup = new Command.Cleanup(cardManager).send(); + respWriter.outputResponse(cleanup); + + if (out != null) + out.close(); + } + + public static void main(String[] args) { + ECTesterReader app = new ECTesterReader(); + app.run(args); + } + + public static class Config { + + //Options + public int bits; + public boolean all; + public boolean primeField = false; + public boolean binaryField = false; + public byte kaType = KeyAgreement_ALG_EC_SVDP_DH; + + 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; + public boolean yes = false; + public String format; + + //Action-related options + 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. + */ + boolean readOptions(CommandLine cli) { + bits = Integer.parseInt(cli.getOptionValue("bit-size", "0")); + all = cli.hasOption("all"); + primeField = cli.hasOption("fp"); + binaryField = cli.hasOption("f2m"); + kaType = Byte.parseByte(cli.getOptionValue("ka-type", "1")); + + 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"); + yes = cli.hasOption("yes"); + + if (cli.hasOption("list-named")) { + listNamed = cli.getOptionValue("list-named"); + return true; + } + + format = cli.getOptionValue("format", "text"); + String formats[] = new String[]{"text", "xml", "yaml", "yml"}; + if (!Arrays.asList(formats).contains(format)) { + System.err.println("Wrong output format " + format + ". Should be one of " + Arrays.toString(formats)); + return false; + } + + 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", "composite", "invalid", "test-vectors", "wrong"}; + if (!Arrays.asList(tests).contains(testSuite)) { + System.err.println("Unknown test suite " + testSuite + ". 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/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index 3c11456..3668fbb 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -4,13 +4,13 @@ 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.CardMngr; -import cz.crcs.ectester.reader.ECTester; +import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.reader.Util; -import cz.crcs.ectester.reader.ec.EC_Curve; -import cz.crcs.ectester.reader.ec.EC_Key; -import cz.crcs.ectester.reader.ec.EC_Keypair; -import cz.crcs.ectester.reader.ec.EC_Params; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Key; +import cz.crcs.ectester.common.ec.EC_Keypair; +import cz.crcs.ectester.common.ec.EC_Params; import javacard.security.KeyPair; import javax.smartcardio.CardException; @@ -54,7 +54,7 @@ public abstract class Command { * @return a Command to send in order to prepare the curve on the keypairs. * @throws IOException if curve file cannot be found/opened */ - public static Command prepareCurve(CardMngr cardManager, EC_Store dataStore, ECTester.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException { + public static Command prepareCurve(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException { if (cfg.customCurve) { // Set custom curve (one of the SECG curves embedded applet-side) @@ -109,7 +109,7 @@ public abstract class Command { * @return a CommandAPDU setting params loaded on the keyPair/s * @throws IOException if any of the key files cannot be found/opened */ - public static Command prepareKey(CardMngr cardManager, EC_Store dataStore, ECTester.Config cfg, byte keyPair) throws IOException { + public static Command prepareKey(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair) throws IOException { short params = EC_Consts.PARAMETERS_NONE; byte[] data = null; diff --git a/src/cz/crcs/ectester/reader/ec/EC_Category.java b/src/cz/crcs/ectester/reader/ec/EC_Category.java deleted file mode 100644 index 41cbad8..0000000 --- a/src/cz/crcs/ectester/reader/ec/EC_Category.java +++ /dev/null @@ -1,142 +0,0 @@ -package cz.crcs.ectester.reader.ec; - -import java.util.Collections; -import java.util.Map; -import java.util.Objects; -import java.util.TreeMap; - -/** - * A category of EC_Data objects, has a name, description and represents a directory in - * the cz.crcs.ectester.data package. - * @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(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof EC_Category && Objects.equals(this.name, ((EC_Category) obj).name); - } - - @Override - public int hashCode() { - return this.name.hashCode() ^ this.directory.hashCode(); - } - -} diff --git a/src/cz/crcs/ectester/reader/ec/EC_Curve.java b/src/cz/crcs/ectester/reader/ec/EC_Curve.java deleted file mode 100644 index cb4a2df..0000000 --- a/src/cz/crcs/ectester/reader/ec/EC_Curve.java +++ /dev/null @@ -1,52 +0,0 @@ -package cz.crcs.ectester.reader.ec; - -import cz.crcs.ectester.applet.EC_Consts; -import javacard.security.KeyPair; - -/** - * An Elliptic curve, contains parameters Fp/F2M, A, B, G, R, (K)?. - * - * @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(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; - } - - public short getBits() { - return bits; - } - - public byte getField() { - return field; - } - - public String getDesc() { - return desc; - } - - @Override - public String toString() { - 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 deleted file mode 100644 index 0ceddef..0000000 --- a/src/cz/crcs/ectester/reader/ec/EC_Data.java +++ /dev/null @@ -1,200 +0,0 @@ -package cz.crcs.ectester.reader.ec; - -import cz.crcs.ectester.reader.Util; - -import java.io.*; -import java.util.*; -import java.util.regex.Pattern; - -/** - * A list of byte arrays for holding EC data. - * - * The data can be read from a byte array via readBytes(), from a CSV via readCSV(). - * The data can be exported to a byte array via flatten() or to a string array via expand(). - * @author Jan Jancar johny@neuromancer.sk - */ -public abstract class EC_Data { - String id; - int count; - byte[][] data; - - private static final Pattern HEX = Pattern.compile("(0x|0X)?[a-fA-F\\d]+"); - - EC_Data() { - } - - EC_Data(int count) { - this.count = count; - this.data = new byte[count][]; - } - - EC_Data(byte[][] data) { - this.count = data.length; - 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; - } - - public byte[][] getData() { - return data; - } - - public boolean hasData() { - return data != null; - } - - public byte[] getParam(int index) { - return data[index]; - } - - public byte[] flatten() { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - for (byte[] param : data) { - byte[] length = new byte[2]; - Util.setShort(length, 0, (short) param.length); - - out.write(length, 0, 2); - out.write(param, 0, param.length); - } - - return out.toByteArray(); - } - - public String[] expand() { - List out = new ArrayList<>(count); - for (byte[] param : data) { - out.add(Util.bytesToHex(param, false)); - } - - return out.toArray(new String[out.size()]); - } - - private static byte[] pad(byte[] data) { - if (data.length == 1) { - return new byte[]{(byte) 0, data[0]}; - } else if (data.length == 0 || data.length > 2) { - return data; - } - return null; - } - - private static byte[] parse(String param) { - byte[] data; - if (param.startsWith("0x") || param.startsWith("0X")) { - data = Util.hexToBytes(param.substring(2)); - } else { - data = Util.hexToBytes(param); - } - if (data == null) - return new byte[0]; - if (data.length < 2) - return pad(data); - return data; - } - - private boolean readHex(String[] hex) { - if (hex.length != count) { - return false; - } - - for (int i = 0; i < count; ++i) { - this.data[i] = parse(hex[i]); - } - return true; - } - - public boolean readCSV(InputStream in) { - Scanner s = new Scanner(in); - - s.useDelimiter(",|;"); - List data = new LinkedList<>(); - while (s.hasNext()) { - String field = s.next(); - data.add(field.replaceAll("\\s+", "")); - } - - if (data.isEmpty()) { - return false; - } - for (String param : data) { - if (!HEX.matcher(param).matches()) { - return false; - } - } - return readHex(data.toArray(new String[data.size()])); - } - - 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 { - Writer w = new OutputStreamWriter(out); - w.write(String.join(",", expand())); - w.flush(); - } - - @Override - public String toString() { - return String.join(",", expand()); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof EC_Data) { - EC_Data other = (EC_Data) obj; - if (this.id != null || other.id != null) { - return Objects.equals(this.id, other.id); - } - - if (this.count != other.count) - return false; - for (int i = 0; i < this.count; ++i) { - if (!Arrays.equals(this.data[i], other.data[i])) { - return false; - } - } - return true; - } else { - return false; - } - } - - @Override - public int hashCode() { - if (this.id != null) { - return this.id.hashCode(); - } - return Arrays.deepHashCode(this.data); - } -} diff --git a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java b/src/cz/crcs/ectester/reader/ec/EC_KAResult.java deleted file mode 100644 index 4a67bbe..0000000 --- a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java +++ /dev/null @@ -1,63 +0,0 @@ -package cz.crcs.ectester.reader.ec; - -import cz.crcs.ectester.reader.Util; - -/** - * A result of EC based Key agreement operation. - * - * @author Jan Jancar johny@neuromancer.sk - */ -public class EC_KAResult extends EC_Data { - - private byte ka; - private String curve; - private String oneKey; - private String otherKey; - - private String desc; - - public EC_KAResult(byte ka, String curve, String oneKey, String otherKey) { - super(1); - this.ka = ka; - this.curve = curve; - this.oneKey = oneKey; - this.otherKey = otherKey; - } - - 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; - } - - public byte getKA() { - return ka; - } - - public String getCurve() { - return curve; - } - - public String getOneKey() { - return oneKey; - } - - public String getOtherKey() { - return otherKey; - } - - public String getDesc() { - return desc; - } - - @Override - public String toString() { - String algo = Util.getKA(ka); - 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 deleted file mode 100644 index 5077d5b..0000000 --- a/src/cz/crcs/ectester/reader/ec/EC_Key.java +++ /dev/null @@ -1,83 +0,0 @@ -package cz.crcs.ectester.reader.ec; - -import cz.crcs.ectester.applet.EC_Consts; - -/** - * An abstract-like EC key. Concrete implementations create a public and private keys. - * - * @author Jan Jancar johny@neuromancer.sk - */ -public class EC_Key extends EC_Params { - - private String curve; - private String desc; - - private EC_Key(short mask, String curve) { - super(mask); - this.curve = curve; - } - - private EC_Key(short mask, String curve, String desc) { - this(mask, curve); - this.desc = desc; - } - - private EC_Key(String id, short mask, String curve, String desc) { - this(mask, curve, desc); - this.id = id; - } - - public String getCurve() { - return curve; - } - - public String getDesc() { - return desc; - } - - /** - * An EC public key, contains the W parameter. - */ - public static class Public extends EC_Key { - - public Public(String curve) { - super(EC_Consts.PARAMETER_W, curve); - } - - public Public(String curve, String desc) { - super(EC_Consts.PARAMETER_W, curve, desc); - } - - public Public(String id, String curve, String desc) { - super(id, EC_Consts.PARAMETER_W, curve, desc); - } - - @Override - public String toString() { - return "<" + getId() + "> EC Public key, over " + getCurve() + (getDesc() == null ? "" : ": " + getDesc()); - } - } - - /** - * An EC private key, contains the S parameter. - */ - public static class Private extends EC_Key { - - public Private(String curve) { - super(EC_Consts.PARAMETER_S, curve); - } - - public Private(String curve, String desc) { - super(EC_Consts.PARAMETER_S, curve, desc); - } - - public Private(String id, String curve, String desc) { - super(id, EC_Consts.PARAMETER_S, curve, desc); - } - - @Override - public String toString() { - 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 deleted file mode 100644 index 2643346..0000000 --- a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java +++ /dev/null @@ -1,41 +0,0 @@ -package cz.crcs.ectester.reader.ec; - -import cz.crcs.ectester.applet.EC_Consts; - -/** - * An EC keypair, contains both the W and S parameters. - * - * @author Jan Jancar johny@neuromancer.sk - */ -public class EC_Keypair extends EC_Params { - private String curve; - private String desc; - - public EC_Keypair(String curve) { - super(EC_Consts.PARAMETERS_KEYPAIR); - this.curve = curve; - } - - public EC_Keypair(String curve, String desc) { - this(curve); - this.desc = desc; - } - - public EC_Keypair(String id, String curve, String desc) { - this(curve, desc); - this.id = id; - } - - public String getCurve() { - return curve; - } - - public String getDesc() { - return desc; - } - - @Override - public String toString() { - 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 deleted file mode 100644 index 6fb164b..0000000 --- a/src/cz/crcs/ectester/reader/ec/EC_Params.java +++ /dev/null @@ -1,151 +0,0 @@ -package cz.crcs.ectester.reader.ec; - -import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.reader.Util; - -import java.io.ByteArrayOutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * A list of EC parameters, can contain a subset of the Fp/F2M, A, B, G, R, K, W, S parameters. - * - * The set of parameters is uniquely identified by a short bit string. - * The parameters can be exported to a byte array via flatten() or to a comma delimited - * string via expand(). - * @author Jan Jancar johny@neuromancer.sk - */ -public class EC_Params extends EC_Data { - private short params; - - public EC_Params(short params) { - this.params = params; - this.count = numParams(); - this.data = new byte[this.count][]; - } - - public EC_Params(short params, byte[][] data) { - this.params = params; - this.count = data.length; - 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; - } - - public boolean hasParam(short param) { - return (params & param) != 0; - } - - public int numParams() { - short paramMask = EC_Consts.PARAMETER_FP; - int num = 0; - while (paramMask <= EC_Consts.PARAMETER_S) { - if ((paramMask & params) != 0) { - if (paramMask == EC_Consts.PARAMETER_F2M) { - num += 3; - } - if (paramMask == EC_Consts.PARAMETER_W || paramMask == EC_Consts.PARAMETER_G) { - num += 1; - } - ++num; - } - paramMask = (short) (paramMask << 1); - } - return num; - } - - @Override - public byte[] flatten() { - return flatten(params); - } - - public byte[] flatten(short params) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - short paramMask = EC_Consts.PARAMETER_FP; - int i = 0; - while (paramMask <= EC_Consts.PARAMETER_S) { - short masked = (short) (this.params & params & paramMask); - short shallow = (short) (this.params & paramMask); - if (masked != 0) { - 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]); - 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) { - //read another param (the y coord) and put into X962 format. - byte[] y = data[i + 1]; - param = Util.concatenate(new byte[]{4}, param, y); //<- ugly but works! - } - if (param.length == 0) - throw new RuntimeException("Empty parameter read?"); - - //write length - byte[] length = new byte[2]; - Util.setShort(length, 0, (short) param.length); - out.write(length, 0, 2); - //write data - out.write(param, 0, param.length); - } - if (shallow == EC_Consts.PARAMETER_F2M) { - i += 4; - } else if (shallow == EC_Consts.PARAMETER_G || shallow == EC_Consts.PARAMETER_W) { - i += 2; - } else if (shallow != 0) { - i++; - } - paramMask = (short) (paramMask << 1); - } - - return (out.size() == 0) ? null : out.toByteArray(); - } - - @Override - public String[] expand() { - List out = new ArrayList<>(); - - short paramMask = EC_Consts.PARAMETER_FP; - int index = 0; - while (paramMask <= EC_Consts.PARAMETER_S) { - short masked = (short) (params & paramMask); - if (masked != 0) { - byte[] param = data[index]; - if (masked == EC_Consts.PARAMETER_F2M) { - for (int i = 0; i < 4; ++i) { - out.add(Util.bytesToHex(data[index + i], false)); - } - index += 4; - } else if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) { - out.add(Util.bytesToHex(param, false)); - out.add(Util.bytesToHex(data[index + 1], false)); - index += 2; - } else { - out.add(Util.bytesToHex(param, false)); - index++; - } - } - paramMask = (short) (paramMask << 1); - } - return out.toArray(new String[out.size()]); - } -} diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index 4abfd14..b816a97 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -3,7 +3,6 @@ package cz.crcs.ectester.reader.response; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.reader.Util; -import cz.crcs.ectester.reader.ec.EC_Data; import javacard.framework.ISO7816; import javacard.security.KeyPair; diff --git a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java index 8e7ca31..9c8393d 100644 --- a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java @@ -4,10 +4,10 @@ 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.CardMngr; -import cz.crcs.ectester.reader.ECTester; +import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.ec.EC_Curve; -import cz.crcs.ectester.reader.ec.EC_Key; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Key; import javacard.security.KeyPair; import java.util.Map; @@ -19,7 +19,7 @@ import static cz.crcs.ectester.reader.test.Result.ExpectedValue; */ public class CompositeCurvesSuite extends TestSuite { - public CompositeCurvesSuite(EC_Store dataStore, ECTester.Config cfg) { + public CompositeCurvesSuite(EC_Store dataStore, ECTesterReader.Config cfg) { super(dataStore, cfg, "composite", "The composite suite tests ECDH over curves with composite order. This should generally fail, as using such a curve is unsafe."); } diff --git a/src/cz/crcs/ectester/reader/test/DefaultSuite.java b/src/cz/crcs/ectester/reader/test/DefaultSuite.java index 736b7c5..b487a6e 100644 --- a/src/cz/crcs/ectester/reader/test/DefaultSuite.java +++ b/src/cz/crcs/ectester/reader/test/DefaultSuite.java @@ -4,7 +4,7 @@ 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.CardMngr; -import cz.crcs.ectester.reader.ECTester; +import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.command.Command; import javacard.security.KeyPair; @@ -17,7 +17,7 @@ import static cz.crcs.ectester.reader.test.Result.ExpectedValue; */ public class DefaultSuite extends TestSuite { - public DefaultSuite(EC_Store dataStore, ECTester.Config cfg) { + public DefaultSuite(EC_Store dataStore, ECTesterReader.Config cfg) { super(dataStore, cfg, "default", "The default test suite tests basic support of ECDH and ECDSA."); } diff --git a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java b/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java index f61b695..3dcabb3 100644 --- a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java @@ -4,10 +4,10 @@ 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.CardMngr; -import cz.crcs.ectester.reader.ECTester; +import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.ec.EC_Curve; -import cz.crcs.ectester.reader.ec.EC_Key; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Key; import javacard.security.KeyPair; import java.io.IOException; @@ -23,7 +23,7 @@ import static cz.crcs.ectester.reader.test.Result.ExpectedValue; */ public class InvalidCurvesSuite extends TestSuite { - public InvalidCurvesSuite(EC_Store dataStore, ECTester.Config cfg) { + public InvalidCurvesSuite(EC_Store dataStore, ECTesterReader.Config cfg) { super(dataStore, cfg, "invalid", "The invalid curve suite tests whether the card rejects points outside of the curve during ECDH."); } diff --git a/src/cz/crcs/ectester/reader/test/TestSuite.java b/src/cz/crcs/ectester/reader/test/TestSuite.java index f13317c..3b6af5a 100644 --- a/src/cz/crcs/ectester/reader/test/TestSuite.java +++ b/src/cz/crcs/ectester/reader/test/TestSuite.java @@ -4,9 +4,9 @@ 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.CardMngr; -import cz.crcs.ectester.reader.ECTester; +import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Curve; import java.io.IOException; import java.util.Collections; @@ -23,12 +23,12 @@ import static cz.crcs.ectester.reader.test.Result.Value; */ public abstract class TestSuite { EC_Store dataStore; - ECTester.Config cfg; + ECTesterReader.Config cfg; String name; String description; List tests = new LinkedList<>(); - TestSuite(EC_Store dataStore, ECTester.Config cfg, String name, String description) { + TestSuite(EC_Store dataStore, ECTesterReader.Config cfg, String name, String description) { this.dataStore = dataStore; this.cfg = cfg; this.name = name; diff --git a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java index ff46feb..6a3121b 100644 --- a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java +++ b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java @@ -4,10 +4,10 @@ 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.CardMngr; -import cz.crcs.ectester.reader.ECTester; +import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.Util; import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.ec.*; +import cz.crcs.ectester.common.ec.*; import cz.crcs.ectester.reader.response.Response; import javacard.security.KeyPair; @@ -24,7 +24,7 @@ import static cz.crcs.ectester.reader.test.Result.Value; */ public class TestVectorSuite extends TestSuite { - public TestVectorSuite(EC_Store dataStore, ECTester.Config cfg) { + public TestVectorSuite(EC_Store dataStore, ECTesterReader.Config cfg) { super(dataStore, cfg, "test", "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness."); } diff --git a/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java index e9389b4..09f10d3 100644 --- a/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java @@ -2,7 +2,7 @@ package cz.crcs.ectester.reader.test; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; -import cz.crcs.ectester.reader.ECTester; +import cz.crcs.ectester.reader.ECTesterReader; import javacard.security.KeyPair; import java.io.IOException; @@ -14,7 +14,7 @@ import static cz.crcs.ectester.reader.test.Result.ExpectedValue; */ public class WrongCurvesSuite extends TestSuite { - public WrongCurvesSuite(EC_Store dataStore, ECTester.Config cfg) { + public WrongCurvesSuite(EC_Store dataStore, ECTesterReader.Config cfg) { super(dataStore, cfg, "wrong", "The wrong curve suite tests whether the card rejects domain parameters which are not curves."); } -- cgit v1.2.3-70-g09d2 From 84a3a55be957900e0417a5afa77b65bfa6d19270 Mon Sep 17 00:00:00 2001 From: J08nY Date: Fri, 10 Nov 2017 22:18:07 +0100 Subject: Split test package into common. --- src/cz/crcs/ectester/common/test/CompoundTest.java | 108 ++++++++++ src/cz/crcs/ectester/common/test/Result.java | 96 +++++++++ src/cz/crcs/ectester/common/test/Test.java | 50 +++++ .../crcs/ectester/common/test/TestException.java | 11 ++ src/cz/crcs/ectester/common/test/Testable.java | 13 ++ src/cz/crcs/ectester/reader/ECTesterReader.java | 9 +- src/cz/crcs/ectester/reader/output/TestWriter.java | 2 +- .../ectester/reader/output/TextTestWriter.java | 10 +- .../crcs/ectester/reader/output/XMLTestWriter.java | 12 +- .../ectester/reader/output/YAMLTestWriter.java | 12 +- .../ectester/reader/test/CompositeCurvesSuite.java | 12 +- src/cz/crcs/ectester/reader/test/DefaultSuite.java | 10 +- .../ectester/reader/test/InvalidCurvesSuite.java | 16 +- src/cz/crcs/ectester/reader/test/Result.java | 94 --------- src/cz/crcs/ectester/reader/test/SimpleTest.java | 71 +++++++ src/cz/crcs/ectester/reader/test/Test.java | 217 --------------------- src/cz/crcs/ectester/reader/test/TestRunner.java | 6 +- src/cz/crcs/ectester/reader/test/TestSuite.java | 33 ++-- .../crcs/ectester/reader/test/TestVectorSuite.java | 21 +- .../ectester/reader/test/WrongCurvesSuite.java | 2 +- 20 files changed, 429 insertions(+), 376 deletions(-) create mode 100644 src/cz/crcs/ectester/common/test/CompoundTest.java create mode 100644 src/cz/crcs/ectester/common/test/Result.java create mode 100644 src/cz/crcs/ectester/common/test/Test.java create mode 100644 src/cz/crcs/ectester/common/test/TestException.java create mode 100644 src/cz/crcs/ectester/common/test/Testable.java delete mode 100644 src/cz/crcs/ectester/reader/test/Result.java create mode 100644 src/cz/crcs/ectester/reader/test/SimpleTest.java delete mode 100644 src/cz/crcs/ectester/reader/test/Test.java diff --git a/src/cz/crcs/ectester/common/test/CompoundTest.java b/src/cz/crcs/ectester/common/test/CompoundTest.java new file mode 100644 index 0000000..bcf4a0e --- /dev/null +++ b/src/cz/crcs/ectester/common/test/CompoundTest.java @@ -0,0 +1,108 @@ +package cz.crcs.ectester.common.test; + +import java.util.function.Function; + +/** + * A compound test that runs many Tests and has a Result dependent on all/some of their Results. + * + * @author Jan JancarĀ johny@neuromancer.sk + */ +public class CompoundTest extends Test { + private Function callback; + private Test[] tests; + private String description; + + private CompoundTest(Function callback, Test... tests) { + this.callback = callback; + this.tests = tests; + } + + private CompoundTest(Function callback, String descripiton, Test... tests) { + this(callback, tests); + this.description = descripiton; + } + + public static CompoundTest function(Function callback, Test... tests) { + return new CompoundTest(callback, tests); + } + + public static CompoundTest function(Function callback, String description, Test... tests) { + return new CompoundTest(callback, description, tests); + } + + public static CompoundTest all(Result.ExpectedValue what, Test... all) { + return new CompoundTest((tests) -> { + for (Test test : tests) { + if (!Result.Value.fromExpected(what, test.ok()).ok()) { + return new Result(Result.Value.FAILURE, "At least one of the sub-tests did not have the expected result."); + } + } + return new Result(Result.Value.SUCCESS, "All sub-tests had the expected result."); + }, all); + } + + public static CompoundTest all(Result.ExpectedValue what, String description, Test... all) { + CompoundTest result = CompoundTest.all(what, all); + result.setDescription(description); + return result; + } + + public static CompoundTest any(Result.ExpectedValue what, Test... any) { + return new CompoundTest((tests) -> { + for (Test test : tests) { + if (Result.Value.fromExpected(what, test.ok()).ok()) { + return new Result(Result.Value.SUCCESS, "At least one of the sub-tests did have the expected result."); + } + } + return new Result(Result.Value.FAILURE, "None of the sub-tests had the expected result."); + }, any); + } + + public static CompoundTest any(Result.ExpectedValue what, String description, Test... any) { + CompoundTest result = CompoundTest.any(what, any); + result.setDescription(description); + return result; + } + + public static CompoundTest mask(Result.ExpectedValue[] results, Test... masked) { + return new CompoundTest((tests) -> { + for (int i = 0; i < results.length; ++i) { + if (!Result.Value.fromExpected(results[i], tests[i].ok()).ok()) { + return new Result(Result.Value.FAILURE, "At least one of the sub-tests did not match the result mask."); + } + } + return new Result(Result.Value.SUCCESS, "All sub-tests matched the expected mask."); + }, masked); + } + + public static CompoundTest mask(Result.ExpectedValue[] results, String description, Test... masked) { + CompoundTest result = CompoundTest.mask(results, masked); + result.setDescription(description); + return result; + } + + public Test[] getTests() { + return tests; + } + + @Override + public void run() throws TestException { + if (hasRun) + return; + + for (Test test : tests) { + test.run(); + } + result = callback.apply(tests); + this.hasRun = true; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String getDescription() { + return description; + } +} diff --git a/src/cz/crcs/ectester/common/test/Result.java b/src/cz/crcs/ectester/common/test/Result.java new file mode 100644 index 0000000..523a9d7 --- /dev/null +++ b/src/cz/crcs/ectester/common/test/Result.java @@ -0,0 +1,96 @@ +package cz.crcs.ectester.common.test; + +/** + * A Result of a Test. Has a Value and an optional String cause. + * + * @author Jan JancarĀ johny@neuromancer.sk + */ +public class Result { + + private Value value; + private String cause; + + public Result(Value value) { + this.value = value; + } + + public Result(Value value, String cause) { + this(value); + this.cause = cause; + } + + public Value getValue() { + return value; + } + + public String getCause() { + return cause; + } + + public boolean ok() { + return value.ok(); + } + + public boolean compareTo(Result other) { + if (other == null) { + return false; + } + return value == other.value; + } + + public boolean compareTo(Value other) { + if (other == null) { + return false; + } + return value == other; + } + + /** + * + */ + public enum Value { + SUCCESS(true), + FAILURE(false), + UXSUCCESS(false), + XFAILURE(true), + ERROR(false); + + private boolean ok; + + Value(boolean ok) { + this.ok = ok; + } + + public static Value fromExpected(ExpectedValue expected, boolean successful) { + switch (expected) { + case SUCCESS: + return successful ? SUCCESS : FAILURE; + case FAILURE: + return successful ? UXSUCCESS : XFAILURE; + case ANY: + return SUCCESS; + } + return SUCCESS; + } + + public static Value fromExpected(ExpectedValue expected, boolean successful, boolean error) { + if (error) { + return ERROR; + } + return fromExpected(expected, successful); + } + + public boolean ok() { + return ok; + } + } + + /** + * + */ + public enum ExpectedValue { + SUCCESS, + FAILURE, + ANY + } +} diff --git a/src/cz/crcs/ectester/common/test/Test.java b/src/cz/crcs/ectester/common/test/Test.java new file mode 100644 index 0000000..8c025b8 --- /dev/null +++ b/src/cz/crcs/ectester/common/test/Test.java @@ -0,0 +1,50 @@ +package cz.crcs.ectester.common.test; + +import static cz.crcs.ectester.common.test.Result.Value; + +/** + * An abstract test that can be run and has a Result. + * + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class Test { + protected boolean hasRun = false; + protected Result result; + + public Result getResult() { + if (!hasRun) { + return null; + } + return result; + } + + public Value getResultValue() { + if (!hasRun) { + return null; + } + return result.getValue(); + } + + public String getResultCause() { + if (!hasRun) { + return null; + } + return result.getCause(); + } + + public boolean ok() { + if (!hasRun) { + return true; + } + return result.ok(); + } + + public abstract String getDescription(); + + public boolean hasRun() { + return hasRun; + } + + public abstract void run() throws TestException; + +} diff --git a/src/cz/crcs/ectester/common/test/TestException.java b/src/cz/crcs/ectester/common/test/TestException.java new file mode 100644 index 0000000..01d195c --- /dev/null +++ b/src/cz/crcs/ectester/common/test/TestException.java @@ -0,0 +1,11 @@ +package cz.crcs.ectester.common.test; + +/** + * + * @author Jan JancarĀ johny@neuromancer.sk + */ +public class TestException extends Exception { + public TestException(Throwable e) { + super(e); + } +} diff --git a/src/cz/crcs/ectester/common/test/Testable.java b/src/cz/crcs/ectester/common/test/Testable.java new file mode 100644 index 0000000..e033b0a --- /dev/null +++ b/src/cz/crcs/ectester/common/test/Testable.java @@ -0,0 +1,13 @@ +package cz.crcs.ectester.common.test; + +/** + * + * @author Jan JancarĀ johny@neuromancer.sk + */ +public interface Testable { + + boolean hasRun(); + void run() throws TestException; + boolean ok(); + boolean error(); +} diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 4eadfd3..786ab05 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -23,11 +23,12 @@ 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.command.Command; import cz.crcs.ectester.common.ec.EC_Category; import cz.crcs.ectester.common.ec.EC_Data; import cz.crcs.ectester.common.ec.EC_Params; +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.output.*; import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.reader.test.*; @@ -187,7 +188,7 @@ public class ECTesterReader { System.err.println("File " + fnfe.getMessage() + " not found."); } catch (ParseException | IOException ex) { System.err.println(ex.getMessage()); - } catch (CardException ex) { + } catch (CardException | TestException ex) { if (logger != null) logger.println(ex.getMessage()); } catch (ParserConfigurationException e) { @@ -436,7 +437,7 @@ public class ECTesterReader { * @throws CardException if APDU transmission fails * @throws IOException if an IO error occurs when writing to key file. */ - private void test() throws IOException, CardException { + private void test() throws IOException, TestException { TestSuite suite; switch (cfg.testSuite) { diff --git a/src/cz/crcs/ectester/reader/output/TestWriter.java b/src/cz/crcs/ectester/reader/output/TestWriter.java index 74c76fb..d79252d 100644 --- a/src/cz/crcs/ectester/reader/output/TestWriter.java +++ b/src/cz/crcs/ectester/reader/output/TestWriter.java @@ -1,6 +1,6 @@ package cz.crcs.ectester.reader.output; -import cz.crcs.ectester.reader.test.Test; +import cz.crcs.ectester.common.test.Test; import cz.crcs.ectester.reader.test.TestSuite; /** diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java index bcebcd5..07b2a2f 100644 --- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java @@ -1,6 +1,8 @@ package cz.crcs.ectester.reader.output; -import cz.crcs.ectester.reader.test.Test; +import cz.crcs.ectester.common.test.CompoundTest; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.reader.test.SimpleTest; import cz.crcs.ectester.reader.test.TestSuite; import java.io.PrintStream; @@ -31,8 +33,8 @@ public class TextTestWriter implements TestWriter { } StringBuilder out = new StringBuilder(); - if (t instanceof Test.Simple) { - Test.Simple test = (Test.Simple) t; + if (t instanceof SimpleTest) { + SimpleTest test = (SimpleTest) t; out.append(test.ok() ? "OK " : "NOK "); out.append("━ "); int width = BASE_WIDTH - (offset + out.length()); @@ -43,7 +45,7 @@ public class TextTestWriter implements TestWriter { out.append(" ā”ƒ "); out.append(respWriter.responseSuffix(test.getResponse())); } else { - Test.Compound test = (Test.Compound) t; + CompoundTest test = (CompoundTest) t; out.append(test.ok() ? "OK " : "NOK "); out.append("┳ "); int width = BASE_WIDTH - (offset + out.length()); diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java index beb758c..f35e467 100644 --- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java @@ -1,9 +1,11 @@ package cz.crcs.ectester.reader.output; +import cz.crcs.ectester.common.test.CompoundTest; import cz.crcs.ectester.reader.Util; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; -import cz.crcs.ectester.reader.test.Test; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.reader.test.SimpleTest; import cz.crcs.ectester.reader.test.TestSuite; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -89,13 +91,13 @@ public class XMLTestWriter implements TestWriter { private Element testElement(Test t) { Element testElem = doc.createElement("test"); - if (t instanceof Test.Simple) { - Test.Simple test = (Test.Simple) t; + if (t instanceof SimpleTest) { + SimpleTest test = (SimpleTest) t; testElem.setAttribute("type", "simple"); testElem.appendChild(commandElement(test.getCommand())); testElem.appendChild(responseElement(test.getResponse())); - } else if (t instanceof Test.Compound) { - Test.Compound test = (Test.Compound) t; + } else if (t instanceof CompoundTest) { + CompoundTest test = (CompoundTest) t; testElem.setAttribute("type", "compound"); for (Test innerTest : test.getTests()) { testElem.appendChild(testElement(innerTest)); diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java index 3b2b72d..15c0522 100644 --- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java @@ -1,9 +1,11 @@ package cz.crcs.ectester.reader.output; +import cz.crcs.ectester.common.test.CompoundTest; import cz.crcs.ectester.reader.Util; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; -import cz.crcs.ectester.reader.test.Test; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.reader.test.SimpleTest; import cz.crcs.ectester.reader.test.TestSuite; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; @@ -64,13 +66,13 @@ public class YAMLTestWriter implements TestWriter { private Map testObject(Test t) { Map testObj = new HashMap<>(); - if (t instanceof Test.Simple) { - Test.Simple test = (Test.Simple) t; + if (t instanceof SimpleTest) { + SimpleTest test = (SimpleTest) t; testObj.put("type", "simple"); testObj.put("command", commandObject(test.getCommand())); testObj.put("response", responseObject(test.getResponse())); - } else if (t instanceof Test.Compound) { - Test.Compound test = (Test.Compound) t; + } else if (t instanceof CompoundTest) { + CompoundTest test = (CompoundTest) t; testObj.put("type", "compound"); List> tests = new LinkedList<>(); for (Test innerTest : test.getTests()) { diff --git a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java index 9c8393d..2e711a2 100644 --- a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java @@ -12,7 +12,7 @@ import javacard.security.KeyPair; import java.util.Map; -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; +import static cz.crcs.ectester.common.test.Result.ExpectedValue; /** * @author Jan Jancar johny@neuromancer.sk @@ -41,12 +41,12 @@ public class CompositeCurvesSuite extends TestSuite { continue; } if ((curve.getBits() == cfg.bits || cfg.all)) { - tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); - tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY)); - tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY)); + tests.add(new SimpleTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + tests.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY)); + tests.add(new SimpleTest(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY)); Command ecdhCommand = new Command.ECDH_direct(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH, key.flatten()); - tests.add(new Test.Simple(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key.")); - tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY)); + tests.add(new SimpleTest(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key.")); + tests.add(new SimpleTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); } } } diff --git a/src/cz/crcs/ectester/reader/test/DefaultSuite.java b/src/cz/crcs/ectester/reader/test/DefaultSuite.java index b487a6e..fb8fdab 100644 --- a/src/cz/crcs/ectester/reader/test/DefaultSuite.java +++ b/src/cz/crcs/ectester/reader/test/DefaultSuite.java @@ -10,7 +10,7 @@ import javacard.security.KeyPair; import java.io.IOException; -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; +import static cz.crcs.ectester.common.test.Result.ExpectedValue; /** * @author Jan Jancar johny@neuromancer.sk @@ -23,7 +23,7 @@ public class DefaultSuite extends TestSuite { @Override public void setup(CardMngr cardManager) throws IOException { - tests.add(new Test.Simple(new Command.Support(cardManager), ExpectedValue.ANY)); + tests.add(new SimpleTest(new Command.Support(cardManager), ExpectedValue.ANY)); if (cfg.namedCurve != null) { String desc = "Default tests over the " + cfg.namedCurve + " curve category."; if (cfg.primeField) { @@ -59,11 +59,11 @@ public class DefaultSuite extends TestSuite { } private void defaultTests(CardMngr cardManager, short keyLength, byte keyType) throws IOException { - tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType), ExpectedValue.SUCCESS)); + tests.add(new SimpleTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType), ExpectedValue.SUCCESS)); Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType); if (curve != null) - tests.add(new Test.Simple(curve, ExpectedValue.SUCCESS)); + tests.add(new SimpleTest(curve, ExpectedValue.SUCCESS)); tests.add(defaultCurveTests(cardManager, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, "Default tests.")); - tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY)); + tests.add(new SimpleTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); } } diff --git a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java b/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java index 3dcabb3..1f71ad5 100644 --- a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java @@ -2,6 +2,8 @@ package cz.crcs.ectester.reader.test; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.test.CompoundTest; +import cz.crcs.ectester.common.test.Test; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; @@ -16,7 +18,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; +import static cz.crcs.ectester.common.test.Result.ExpectedValue; /** * @author Jan Jancar johny@neuromancer.sk @@ -53,16 +55,16 @@ public class InvalidCurvesSuite extends TestSuite { EC_Curve curve = e.getKey(); List keys = e.getValue(); - tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); - tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); - tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS)); + tests.add(new SimpleTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + tests.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); + tests.add(new SimpleTest(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS)); List ecdhTests = new LinkedList<>(); for (EC_Key.Public pub : keys) { Command ecdhCommand = new Command.ECDH_direct(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ANY, pub.flatten()); - ecdhTests.add(new Test.Simple(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve." , "Card incorrectly accepted point on invalid curve.")); + ecdhTests.add(new SimpleTest(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve." , "Card incorrectly accepted point on invalid curve.")); } - tests.add(Test.Compound.all(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), ecdhTests.toArray(new Test[0]))); - tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY)); + tests.add(CompoundTest.all(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), ecdhTests.toArray(new Test[0]))); + tests.add(new SimpleTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); } } } diff --git a/src/cz/crcs/ectester/reader/test/Result.java b/src/cz/crcs/ectester/reader/test/Result.java deleted file mode 100644 index 82f0f32..0000000 --- a/src/cz/crcs/ectester/reader/test/Result.java +++ /dev/null @@ -1,94 +0,0 @@ -package cz.crcs.ectester.reader.test; - -/** - * @author Jan JancarĀ johny@neuromancer.sk - */ -public class Result { - - private Value value; - private String cause; - - public Result(Value value) { - this.value = value; - } - - public Result(Value value, String cause) { - this(value); - this.cause = cause; - } - - public Value getValue() { - return value; - } - - public String getCause() { - return cause; - } - - public boolean ok() { - return value.ok(); - } - - public boolean compareTo(Result other) { - if (other == null) { - return false; - } - return value == other.value; - } - - public boolean compareTo(Value other) { - if (other == null) { - return false; - } - return value == other; - } - - /** - * - */ - public enum Value { - SUCCESS(true), - FAILURE(false), - UXSUCCESS(false), - XFAILURE(true), - ERROR(false); - - private boolean ok; - - Value(boolean ok) { - this.ok = ok; - } - - public static Value fromExpected(ExpectedValue expected, boolean successful) { - switch (expected) { - case SUCCESS: - return successful ? SUCCESS : FAILURE; - case FAILURE: - return successful ? UXSUCCESS : XFAILURE; - case ANY: - return SUCCESS; - } - return SUCCESS; - } - - public static Value fromExpected(ExpectedValue expected, boolean successful, boolean error) { - if (error) { - return ERROR; - } - return fromExpected(expected, successful); - } - - public boolean ok() { - return ok; - } - } - - /** - * - */ - public enum ExpectedValue { - SUCCESS, - FAILURE, - ANY - } -} diff --git a/src/cz/crcs/ectester/reader/test/SimpleTest.java b/src/cz/crcs/ectester/reader/test/SimpleTest.java new file mode 100644 index 0000000..067f43e --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/SimpleTest.java @@ -0,0 +1,71 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.reader.command.Command; +import cz.crcs.ectester.reader.response.Response; + +import javax.smartcardio.CardException; +import java.util.function.BiFunction; + +/** + * A simple test that runs one Command to get and evaluate one Response + * to get a Result and compare it with the expected one. + */ +public class SimpleTest extends Test { + private BiFunction callback; + private Command command; + private Response response; + + public SimpleTest(Command command, BiFunction callback) { + this.command = command; + this.callback = callback; + } + + public SimpleTest(Command command, Result.ExpectedValue expected, String ok, String nok) { + this(command, (cmd, resp) -> { + Result.Value resultValue = Result.Value.fromExpected(expected, resp.successful(), resp.error()); + return new Result(resultValue, resultValue.ok() ? ok : nok); + }); + } + + public SimpleTest(Command command, Result.ExpectedValue expected) { + this(command, expected, null, null); + } + + public Command getCommand() { + return command; + } + + public Response getResponse() { + return response; + } + + @Override + public void run() throws TestException { + if (hasRun) + return; + + try { + response = command.send(); + } catch (CardException e) { + throw new TestException(e); + } + if (callback != null) { + result = callback.apply(command, response); + } else { + if (response.successful()) { + result = new Result(Result.Value.SUCCESS); + } else { + result = new Result(Result.Value.FAILURE); + } + } + hasRun = true; + } + + @Override + public String getDescription() { + return response.getDescription(); + } +} diff --git a/src/cz/crcs/ectester/reader/test/Test.java b/src/cz/crcs/ectester/reader/test/Test.java deleted file mode 100644 index 022ad56..0000000 --- a/src/cz/crcs/ectester/reader/test/Test.java +++ /dev/null @@ -1,217 +0,0 @@ -package cz.crcs.ectester.reader.test; - -import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.response.Response; - -import javax.smartcardio.CardException; -import java.util.function.BiFunction; -import java.util.function.Function; - -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; -import static cz.crcs.ectester.reader.test.Result.Value; - -/** - * An abstract test that can be run and has a Result. - * - * @author Jan Jancar johny@neuromancer.sk - */ -public abstract class Test { - boolean hasRun = false; - Result result; - - public Result getResult() { - if (!hasRun) { - return null; - } - return result; - } - - public Value getResultValue() { - if (!hasRun) { - return null; - } - return result.getValue(); - } - - public String getResultCause() { - if (!hasRun) { - return null; - } - return result.getCause(); - } - - public boolean ok() { - if (!hasRun) { - return true; - } - return result.ok(); - } - - public abstract String getDescription(); - - public boolean hasRun() { - return hasRun; - } - - public abstract void run() throws CardException; - - /** - * A simple test that runs one Command to get and evaluate one Response - * to get a Result and compare it with the expected one. - */ - public static class Simple extends Test { - private BiFunction callback; - private Command command; - private Response response; - - public Simple(Command command, BiFunction callback) { - this.command = command; - this.callback = callback; - } - - public Simple(Command command, ExpectedValue expected, String ok, String nok) { - this(command, (cmd, resp) -> { - Value resultValue = Value.fromExpected(expected, resp.successful(), resp.error()); - return new Result(resultValue, resultValue.ok() ? ok : nok); - }); - } - - public Simple(Command command, ExpectedValue expected) { - this(command, expected, null, null); - } - - public Command getCommand() { - return command; - } - - public Response getResponse() { - return response; - } - - @Override - public void run() throws CardException { - if (hasRun) - return; - - response = command.send(); - if (callback != null) { - result = callback.apply(command, response); - } else { - if (response.successful()) { - result = new Result(Value.SUCCESS); - } else { - result = new Result(Value.FAILURE); - } - } - hasRun = true; - } - - @Override - public String getDescription() { - return response.getDescription(); - } - } - - /** - * A compound test that runs many Tests and has a Result dependent on all/some of their Results. - */ - public static class Compound extends Test { - private Function callback; - private Test[] tests; - private String description; - - private Compound(Function callback, Test... tests) { - this.callback = callback; - this.tests = tests; - } - - private Compound(Function callback, String descripiton, Test... tests) { - this(callback, tests); - this.description = descripiton; - } - - public static Compound function(Function callback, Test... tests) { - return new Compound(callback, tests); - } - - public static Compound function(Function callback, String description, Test... tests) { - return new Compound(callback, description, tests); - } - - public static Compound all(ExpectedValue what, Test... all) { - return new Compound((tests) -> { - for (Test test : tests) { - if (!Value.fromExpected(what, test.ok()).ok()) { - return new Result(Value.FAILURE, "At least one of the sub-tests did not have the expected result."); - } - } - return new Result(Value.SUCCESS, "All sub-tests had the expected result."); - }, all); - } - - public static Compound all(ExpectedValue what, String description, Test... all) { - Compound result = Compound.all(what, all); - result.setDescription(description); - return result; - } - - public static Compound any(ExpectedValue what, Test... any) { - return new Compound((tests) -> { - for (Test test : tests) { - if (Value.fromExpected(what, test.ok()).ok()) { - return new Result(Value.SUCCESS, "At least one of the sub-tests did have the expected result."); - } - } - return new Result(Value.FAILURE, "None of the sub-tests had the expected result."); - }, any); - } - - public static Compound any(ExpectedValue what, String description, Test... any) { - Compound result = Compound.any(what, any); - result.setDescription(description); - return result; - } - - public static Compound mask(ExpectedValue[] results, Test... masked) { - return new Compound((tests) -> { - for (int i = 0; i < results.length; ++i) { - if (!Value.fromExpected(results[i], tests[i].ok()).ok()) { - return new Result(Value.FAILURE, "At least one of the sub-tests did not match the result mask."); - } - } - return new Result(Value.SUCCESS, "All sub-tests matched the expected mask."); - }, masked); - } - - public static Compound mask(ExpectedValue[] results, String description, Test... masked) { - Compound result = Compound.mask(results, masked); - result.setDescription(description); - return result; - } - - public Test[] getTests() { - return tests; - } - - @Override - public void run() throws CardException { - if (hasRun) - return; - - for (Test test : tests) { - test.run(); - } - result = callback.apply(tests); - this.hasRun = true; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public String getDescription() { - return description; - } - } -} diff --git a/src/cz/crcs/ectester/reader/test/TestRunner.java b/src/cz/crcs/ectester/reader/test/TestRunner.java index baab6a8..dcc78db 100644 --- a/src/cz/crcs/ectester/reader/test/TestRunner.java +++ b/src/cz/crcs/ectester/reader/test/TestRunner.java @@ -1,9 +1,9 @@ package cz.crcs.ectester.reader.test; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestException; import cz.crcs.ectester.reader.output.TestWriter; -import javax.smartcardio.CardException; - /** * @author Jan Jancar johny@neuromancer.sk */ @@ -16,7 +16,7 @@ public class TestRunner { this.writer = writer; } - public void run() throws CardException { + public void run() throws TestException { writer.begin(suite); for (Test t : suite.getTests()) { if (!t.hasRun()) { diff --git a/src/cz/crcs/ectester/reader/test/TestSuite.java b/src/cz/crcs/ectester/reader/test/TestSuite.java index 3b6af5a..dc8167b 100644 --- a/src/cz/crcs/ectester/reader/test/TestSuite.java +++ b/src/cz/crcs/ectester/reader/test/TestSuite.java @@ -2,11 +2,14 @@ package cz.crcs.ectester.reader.test; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.test.CompoundTest; +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.Test; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.common.ec.EC_Curve; import java.io.IOException; import java.util.Collections; @@ -15,8 +18,8 @@ import java.util.List; import java.util.Map; import java.util.function.Function; -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; -import static cz.crcs.ectester.reader.test.Result.Value; +import static cz.crcs.ectester.common.test.Result.ExpectedValue; +import static cz.crcs.ectester.common.test.Result.Value; /** * @author Jan Jancar johny@neuromancer.sk @@ -61,16 +64,16 @@ public abstract class TestSuite { Test defaultCurveTests(CardMngr cardManager, ExpectedValue generateExpected, ExpectedValue ecdhExpected, ExpectedValue ecdhCompressExpected, ExpectedValue ecdsaExpected, String description) { List tests = new LinkedList<>(); - tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), generateExpected)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH), ecdhExpected)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_COMPRESS, EC_Consts.KA_ECDH), ecdhExpected)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ONE, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ZERO, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_MAX, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_FULLRANDOM, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new Test.Simple(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, null), ecdsaExpected)); + tests.add(new SimpleTest(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), generateExpected)); + tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH), ecdhExpected)); + tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_COMPRESS, EC_Consts.KA_ECDH), ecdhExpected)); + tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ONE, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); + tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ZERO, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); + tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_MAX, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); + tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_FULLRANDOM, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); + tests.add(new SimpleTest(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, null), ecdsaExpected)); - return Test.Compound.function((testArray) -> { + return CompoundTest.function((testArray) -> { Function shouldHave = (expected) -> { switch (expected) { case SUCCESS: @@ -123,10 +126,10 @@ public abstract class TestSuite { for (Map.Entry entry : curves.entrySet()) { EC_Curve curve = entry.getValue(); if (curve.getField() == field && (curve.getBits() == cfg.bits || cfg.all)) { - tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), field), ExpectedValue.SUCCESS)); - tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), setExpected)); + tests.add(new SimpleTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), field), ExpectedValue.SUCCESS)); + tests.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), setExpected)); tests.add(defaultCurveTests(cardManager, generateExpected, ecdhExpected, ecdhCompressedExpected, ecdsaExpected, description)); - tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY)); + tests.add(new SimpleTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); } } diff --git a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java index 6a3121b..742661d 100644 --- a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java +++ b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java @@ -2,6 +2,9 @@ package cz.crcs.ectester.reader.test; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.test.CompoundTest; +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.Test; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; @@ -16,8 +19,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; -import static cz.crcs.ectester.reader.test.Result.Value; +import static cz.crcs.ectester.common.test.Result.ExpectedValue; +import static cz.crcs.ectester.common.test.Result.Value; /** * @author Jan Jancar johny@neuromancer.sk @@ -58,12 +61,12 @@ public class TestVectorSuite extends TestSuite { } List testVector = new LinkedList<>(); - testVector.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); - testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); + testVector.add(new SimpleTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + testVector.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); //tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS)); - testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS)); - testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS)); - testVector.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getKA()), (command, response) -> { + testVector.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS)); + testVector.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS)); + testVector.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getKA()), (command, response) -> { Response.ECDH dh = (Response.ECDH) response; if (!dh.successful()) return new Result(Value.FAILURE, "ECDH was unsuccessful."); @@ -75,8 +78,8 @@ public class TestVectorSuite extends TestSuite { } return new Result(Value.SUCCESS); })); - tests.add(Test.Compound.all(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0]))); - tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY)); + tests.add(CompoundTest.all(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0]))); + tests.add(new SimpleTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); } } diff --git a/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java index 09f10d3..76da718 100644 --- a/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java @@ -7,7 +7,7 @@ import javacard.security.KeyPair; import java.io.IOException; -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; +import static cz.crcs.ectester.common.test.Result.ExpectedValue; /** * @author Jan Jancar johny@neuromancer.sk -- cgit v1.2.3-70-g09d2 From a2f5316ad96b6e78844c371f8dd5483095cf4af3 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 12 Nov 2017 12:38:04 +0100 Subject: Introduce ECTesterStandalone. --- .../crcs/ectester/common/output/OutputLogger.java | 62 ++++++++++++++++++++++ src/cz/crcs/ectester/common/test/Result.java | 4 +- src/cz/crcs/ectester/common/test/Test.java | 2 +- src/cz/crcs/ectester/common/test/Testable.java | 4 +- src/cz/crcs/ectester/reader/ECTesterReader.java | 1 + .../crcs/ectester/reader/output/OutputLogger.java | 60 --------------------- .../ectester/standalone/ECTesterStandalone.java | 13 +++++ 7 files changed, 82 insertions(+), 64 deletions(-) create mode 100644 src/cz/crcs/ectester/common/output/OutputLogger.java delete mode 100644 src/cz/crcs/ectester/reader/output/OutputLogger.java create mode 100644 src/cz/crcs/ectester/standalone/ECTesterStandalone.java diff --git a/src/cz/crcs/ectester/common/output/OutputLogger.java b/src/cz/crcs/ectester/common/output/OutputLogger.java new file mode 100644 index 0000000..b876c5b --- /dev/null +++ b/src/cz/crcs/ectester/common/output/OutputLogger.java @@ -0,0 +1,62 @@ +package cz.crcs.ectester.common.output; + +import cz.crcs.ectester.reader.output.TeeOutputStream; + +import java.io.*; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Petr Svenda petr@svenda.com + * @author Jan Jancar johny@neuromancer.sk + */ +public class OutputLogger { + private OutputStream out; + private PrintStream print; + + public OutputLogger(boolean systemOut, String... filePaths) throws IOException { + List streams = new LinkedList<>(); + for (String filePath : filePaths) { + if (filePath != null) { + streams.add(new FileOutputStream(filePath)); + } + } + if (systemOut) { + streams.add(System.out); + } + this.out = new TeeOutputStream(streams.toArray(new OutputStream[0])); + this.print = new PrintStream(this.out); + } + + public OutputLogger(String filePath) throws IOException { + this(true, filePath); + } + + public OutputStream getOutputStream() { + return this.out; + } + + public PrintStream getPrintStream() { + return this.print; + } + + public void println() { + print.println(); + } + + public void println(String logLine) { + print.println(logLine); + } + + public void print(String logLine) { + print.print(logLine); + } + + public void flush() { + print.flush(); + } + + public void close() { + print.close(); + } +} diff --git a/src/cz/crcs/ectester/common/test/Result.java b/src/cz/crcs/ectester/common/test/Result.java index 523a9d7..11fcb4d 100644 --- a/src/cz/crcs/ectester/common/test/Result.java +++ b/src/cz/crcs/ectester/common/test/Result.java @@ -46,7 +46,7 @@ public class Result { } /** - * + * A result value of a Test. */ public enum Value { SUCCESS(true), @@ -86,7 +86,7 @@ public class Result { } /** - * + * A possible expected value result of a Test. */ public enum ExpectedValue { SUCCESS, diff --git a/src/cz/crcs/ectester/common/test/Test.java b/src/cz/crcs/ectester/common/test/Test.java index 8c025b8..5973d0f 100644 --- a/src/cz/crcs/ectester/common/test/Test.java +++ b/src/cz/crcs/ectester/common/test/Test.java @@ -7,7 +7,7 @@ import static cz.crcs.ectester.common.test.Result.Value; * * @author Jan Jancar johny@neuromancer.sk */ -public abstract class Test { +public abstract class Test implements Testable { protected boolean hasRun = false; protected Result result; diff --git a/src/cz/crcs/ectester/common/test/Testable.java b/src/cz/crcs/ectester/common/test/Testable.java index e033b0a..d05d31e 100644 --- a/src/cz/crcs/ectester/common/test/Testable.java +++ b/src/cz/crcs/ectester/common/test/Testable.java @@ -1,13 +1,15 @@ package cz.crcs.ectester.common.test; /** - * * @author Jan JancarĀ johny@neuromancer.sk */ public interface Testable { boolean hasRun(); + void run() throws TestException; + boolean ok(); + boolean error(); } diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 786ab05..99b2f83 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -26,6 +26,7 @@ import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.common.ec.EC_Category; import cz.crcs.ectester.common.ec.EC_Data; import cz.crcs.ectester.common.ec.EC_Params; +import cz.crcs.ectester.common.output.OutputLogger; import cz.crcs.ectester.common.test.TestException; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.command.Command; diff --git a/src/cz/crcs/ectester/reader/output/OutputLogger.java b/src/cz/crcs/ectester/reader/output/OutputLogger.java deleted file mode 100644 index bf47a1f..0000000 --- a/src/cz/crcs/ectester/reader/output/OutputLogger.java +++ /dev/null @@ -1,60 +0,0 @@ -package cz.crcs.ectester.reader.output; - -import java.io.*; -import java.util.LinkedList; -import java.util.List; - -/** - * @author Petr Svenda petr@svenda.com - * @author Jan Jancar johny@neuromancer.sk - */ -public class OutputLogger { - private OutputStream out; - private PrintStream print; - - public OutputLogger(boolean systemOut, String... filePaths) throws IOException { - List streams = new LinkedList<>(); - for (String filePath : filePaths) { - if (filePath != null) { - streams.add(new FileOutputStream(filePath)); - } - } - if (systemOut) { - streams.add(System.out); - } - this.out = new TeeOutputStream(streams.toArray(new OutputStream[0])); - this.print = new PrintStream(this.out); - } - - public OutputLogger(String filePath) throws IOException { - this(true, filePath); - } - - public OutputStream getOutputStream() { - return this.out; - } - - public PrintStream getPrintStream() { - return this.print; - } - - public void println() { - print.println(); - } - - public void println(String logLine) { - print.println(logLine); - } - - public void print(String logLine) { - print.print(logLine); - } - - public void flush() { - print.flush(); - } - - public void close() { - print.close(); - } -} diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java new file mode 100644 index 0000000..cae4bb9 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -0,0 +1,13 @@ +package cz.crcs.ectester.standalone; + +public class ECTesterStandalone { + + private void run(String[] args) { + + } + + public static void main(String[] args) { + ECTesterStandalone app = new ECTesterStandalone(); + app.run(args); + } +} -- cgit v1.2.3-70-g09d2 From a45fa0d3cde29728a252c2ca5b7ed4f3e6c87849 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 12 Nov 2017 13:49:54 +0100 Subject: Separate build files for standalone and reader apps. --- .gitignore | 10 +- .travis.yml | 11 +- README.md | 5 +- build-applet.xml | 31 + build-reader.xml | 82 ++ build-standalone.xml | 78 ++ build.xml | 108 -- dist/README.TXT | 34 +- jcbuild.xml | 31 - manifest.mf | 4 - nbproject/build-impl.xml | 1413 -------------------- nbproject/copylibstask.jar | Bin 22335 -> 11902 bytes nbproject/dist-build.xml | 34 + nbproject/project.properties | 79 -- nbproject/project.xml | 15 - nbproject/reader/build-impl.xml | 1413 ++++++++++++++++++++ nbproject/reader/manifest.mf | 4 + nbproject/reader/project.properties | 79 ++ nbproject/reader/project.xml | 15 + nbproject/standalone/build-impl.xml | 1413 ++++++++++++++++++++ nbproject/standalone/manifest.mf | 4 + nbproject/standalone/project.properties | 79 ++ nbproject/standalone/project.xml | 15 + src/cz/crcs/ectester/common/Util.java | 375 ++++++ src/cz/crcs/ectester/common/ec/EC_Data.java | 2 +- src/cz/crcs/ectester/common/ec/EC_KAResult.java | 2 +- src/cz/crcs/ectester/common/ec/EC_Params.java | 2 +- .../crcs/ectester/common/output/OutputLogger.java | 2 - .../ectester/common/output/TeeOutputStream.java | 36 + src/cz/crcs/ectester/common/test/Test.java | 7 + src/cz/crcs/ectester/reader/CardMngr.java | 1 + src/cz/crcs/ectester/reader/ECTesterReader.java | 1 + src/cz/crcs/ectester/reader/Util.java | 375 ------ src/cz/crcs/ectester/reader/command/Command.java | 2 +- .../ectester/reader/output/ResponseWriter.java | 2 +- .../ectester/reader/output/TeeOutputStream.java | 36 - .../crcs/ectester/reader/output/XMLTestWriter.java | 2 +- .../ectester/reader/output/YAMLTestWriter.java | 2 +- src/cz/crcs/ectester/reader/response/Response.java | 2 +- .../crcs/ectester/reader/test/TestVectorSuite.java | 2 +- src/cz/crcs/ectester/scripts/ectester-reader.bat | 34 + src/cz/crcs/ectester/scripts/ectester-reader.sh | 48 + src/cz/crcs/ectester/scripts/ectester.bat | 34 - src/cz/crcs/ectester/scripts/ectester.sh | 48 - 44 files changed, 3783 insertions(+), 2189 deletions(-) create mode 100644 build-applet.xml create mode 100644 build-reader.xml create mode 100644 build-standalone.xml delete mode 100644 build.xml delete mode 100644 jcbuild.xml delete mode 100644 manifest.mf delete mode 100644 nbproject/build-impl.xml create mode 100644 nbproject/dist-build.xml delete mode 100644 nbproject/project.properties delete mode 100644 nbproject/project.xml create mode 100644 nbproject/reader/build-impl.xml create mode 100644 nbproject/reader/manifest.mf create mode 100644 nbproject/reader/project.properties create mode 100644 nbproject/reader/project.xml create mode 100644 nbproject/standalone/build-impl.xml create mode 100644 nbproject/standalone/manifest.mf create mode 100644 nbproject/standalone/project.properties create mode 100644 nbproject/standalone/project.xml create mode 100644 src/cz/crcs/ectester/common/Util.java create mode 100644 src/cz/crcs/ectester/common/output/TeeOutputStream.java delete mode 100644 src/cz/crcs/ectester/reader/Util.java delete mode 100644 src/cz/crcs/ectester/reader/output/TeeOutputStream.java create mode 100644 src/cz/crcs/ectester/scripts/ectester-reader.bat create mode 100755 src/cz/crcs/ectester/scripts/ectester-reader.sh delete mode 100644 src/cz/crcs/ectester/scripts/ectester.bat delete mode 100755 src/cz/crcs/ectester/scripts/ectester.sh diff --git a/.gitignore b/.gitignore index fe6a5d3..4724134 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ /dist/lib/ -/dist/ECTester.jar -/dist/ECTester-dist.jar -/dist/ectester.sh -/dist/ectester.bat \ No newline at end of file +/dist/ECTesterReader.jar +/dist/ECTesterReader-dist.jar +/dist/ectester-reader.sh +/dist/ectester-reader.bat +/dist/ECTesterStandalone.jar +/dist/ECTesterStandalone-dist.jar \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 3959c4d..d599dfb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,16 +2,19 @@ language: java jdk: - oraclejdk8 script: -- ant -f jcbuild.xml build -- ant -f build.xml package +- ant -f build-applet.xml build +- ant -f build-reader.xml package +- ant -f build-standalone.xml package deploy: provider: releases api_key: secure: q2aJvu32K+nfbMR60nFCEkn+jYCKprlCRlIoPjuRz1HySX233Ccwpx1CAdNzEjY6FDFcoReKAg6r5vdPjJ4FRPAQ23TxffIYZPkykL5K/pUZJbM5xkazJY0Fp8i6Vyl0JfeanVib1PTyOSugplhCttFk5nb9JUFV36Tre66XntOl5y80Trn94F5aTlRjfW26UH65W7Aa6WZ0N4OX/ZsX+vEOJPAu+RLfOq9oBOx/loB8ntYM/e/6bEwJp6EedRQLDsiS4NavP3svH+GXsPLs5p3soyRXYsvvGKVnVjcjZURxDDdxv5YuCWUUfl9PbNB+Mqmx/HQxl50BKoKFqwap1+TnlbuTAiWaXeh3zdXuGB+TPg8KE8h6ueDneHd3Lpivgq79IvPWIH+N4b3Pa952+rD+JKBZ807efB+97OtWrkQL7/sLZESQUdIszE724HHOiArKpNajIX+kN6NJdul5xFCiQQHG+O7iDFQBavCGM9fk63mZRyGPxZQzS06BV2vIIHg0yx3igN+OKKMFCH+P3hYR1zL6o65OlgbL1ifTZ18GDvmVRNdi53/fxQ2n/mQmI4tQpn4ZB7Ddoxx4GlpjFjzdKk/P9nKwng0M9wrp8row/vb5S+1aPwSxp9/4ASP9dkvLcNjTkWhmGPrWe+82Y9JPK47uesx0YeaVI2C7IR0= file: - - "dist/ECTester-dist.jar" - - "dist/ECTester.jar" + - "dist/ECTesterReader-dist.jar" + - "dist/ECTesterReader.jar" - "!uploader/ectester.cap" + - "dist/ECTesterStandalone-dist.jar" + - "dist/ECTesterStandalone.jar" skip_cleanup: true on: tags: true diff --git a/README.md b/README.md index 5096bd3..0ec59b7 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ Tests support and behavior of smartcards with JavaCard platform with focus on El ECTester uses ant. ```bash -ant package # To build the reader tool (jar). -ant -f jcbuild.xml build # To build the applet (cap). +ant -f build-reader.xml package # To build the reader tool (jar). +ant -f build-standalone.xml package # To build the standalone tool (jar). +ant -f build-applet.xml build # To build the applet (cap). ``` ## Usage diff --git a/build-applet.xml b/build-applet.xml new file mode 100644 index 0000000..793060c --- /dev/null +++ b/build-applet.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build-reader.xml b/build-reader.xml new file mode 100644 index 0000000..ec62f6f --- /dev/null +++ b/build-reader.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + Builds, tests, and runs the project ECTesterReader. + + + + + + + + + + + + diff --git a/build-standalone.xml b/build-standalone.xml new file mode 100644 index 0000000..0ba7f93 --- /dev/null +++ b/build-standalone.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + Builds, tests, and runs the project ECTesterStandalone. + + + + + + + + diff --git a/build.xml b/build.xml deleted file mode 100644 index f89b743..0000000 --- a/build.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - Builds, tests, and runs the project ECTester. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dist/README.TXT b/dist/README.TXT index 5d6fa17..64c76a6 100644 --- a/dist/README.TXT +++ b/dist/README.TXT @@ -2,31 +2,15 @@ BUILD OUTPUT DESCRIPTION ======================== -When you build an Java application project that has a main class, the IDE -automatically copies all of the JAR -files on the projects classpath to your projects dist/lib folder. The IDE -also adds each of the JAR files to the Class-Path element in the application -JAR files manifest file (MANIFEST.MF). +After building (with package target) this directory should contain the files: -To run the project from the command line, go to the dist folder and -type the following: +- ECTesterReader.jar +- ECTesterReader-dist.jar +- ECTesterStandalone.jar +- ECTesterStandalone-dist.jar +- ectester-reader.sh +- ectester-reader.bat -java -jar "ECTester.jar" +The *-dist.jar variants of JAR files are self-contained executable JAR files with +all the dependencies inside them. -To distribute this project, zip up the dist folder (including the lib folder) -and distribute the ZIP file. - -Notes: - -* If two JAR files on the project classpath have the same name, only the first -JAR file is copied to the lib folder. -* Only JAR files are copied to the lib folder. -If the classpath contains other types of files or folders, these files (folders) -are not copied. -* If a library on the projects classpath also has a Class-Path element -specified in the manifest,the content of the Class-Path element has to be on -the projects runtime path. -* To set a main class in a standard Java project, right-click the project node -in the Projects window and choose Properties. Then click Run and enter the -class name in the Main Class field. Alternatively, you can manually type the -class name in the manifest Main-Class element. diff --git a/jcbuild.xml b/jcbuild.xml deleted file mode 100644 index 793060c..0000000 --- a/jcbuild.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/manifest.mf b/manifest.mf deleted file mode 100644 index cbfea93..0000000 --- a/manifest.mf +++ /dev/null @@ -1,4 +0,0 @@ -Manifest-Version: 1.0 -Class-Path: lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.3.1.jar lib/snakeyaml-1.19.jar -Main-Class: cz.crcs.ectester.reader.ECTesterReader - diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml deleted file mode 100644 index 3b01c7f..0000000 --- a/nbproject/build-impl.xml +++ /dev/null @@ -1,1413 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set src.dir - Must set test.src.dir - Must set build.dir - Must set dist.dir - Must set build.classes.dir - Must set dist.javadoc.dir - Must set build.test.classes.dir - Must set build.test.results.dir - Must set build.classes.excludes - Must set dist.jar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No tests executed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set JVM to use for profiling in profiler.info.jvm - Must set profiler agent JVM arguments in profiler.info.jvmargs.agent - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select some files in the IDE or set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - To run this application from the command line without Ant, try: - - java -jar "${dist.jar.resolved}" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set run.class - - - - Must select one file in the IDE or set run.class - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set debug.class - - - - - Must select one file in the IDE or set debug.class - - - - - Must set fix.includes - - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - Must select one file in the IDE or set profile.class - This target only works when run from inside the NetBeans IDE. - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set run.class - - - - - - Must select some files in the IDE or set test.includes - - - - - Must select one file in the IDE or set run.class - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select some files in the IDE or set javac.includes - - - - - - - - - - - - - - - - - - - - Some tests failed; see details above. - - - - - - - - - Must select some files in the IDE or set test.includes - - - - Some tests failed; see details above. - - - - Must select some files in the IDE or set test.class - Must select some method in the IDE or set test.method - - - - Some tests failed; see details above. - - - - - Must select one file in the IDE or set test.class - - - - Must select one file in the IDE or set test.class - Must select some method in the IDE or set test.method - - - - - - - - - - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/nbproject/copylibstask.jar b/nbproject/copylibstask.jar index ad1d2ac..45fdbe1 100644 Binary files a/nbproject/copylibstask.jar and b/nbproject/copylibstask.jar differ diff --git a/nbproject/dist-build.xml b/nbproject/dist-build.xml new file mode 100644 index 0000000..b980e2d --- /dev/null +++ b/nbproject/dist-build.xml @@ -0,0 +1,34 @@ + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nbproject/project.properties b/nbproject/project.properties deleted file mode 100644 index 8c65b4e..0000000 --- a/nbproject/project.properties +++ /dev/null @@ -1,79 +0,0 @@ -annotation.processing.enabled=true -annotation.processing.enabled.in.editor=false -annotation.processing.processors.list= -annotation.processing.run.all.processors=true -annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output -application.title=ECTester -application.vendor=xsvenda -build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form -# This directory is removed when the project is cleaned: -build.dir=build -build.generated.dir=${build.dir}/generated -build.generated.sources.dir=${build.dir}/generated-sources -# Only compile against the classpath explicitly listed here: -build.sysclasspath=ignore -build.test.classes.dir=${build.dir}/test/classes -build.test.results.dir=${build.dir}/test/results -# Uncomment to specify the preferred debugger connection transport: -#debug.transport=dt_socket -debug.classpath=\ - ${run.classpath} -debug.test.classpath=\ - ${run.test.classpath} -# Files in build.classes.dir which should be excluded from distribution jar -dist.archive.excludes= -# This directory is removed when the project is cleaned: -dist.dir=dist -dist.jar=${dist.dir}/ECTester.jar -dist.javadoc.dir=${dist.dir}/javadoc -libs.CopyLibs.classpath=nbproject/copylibstask.jar -endorsed.classpath= -excludes= -includes=** -jar.compress=false -javac.classpath=\ - lib/jcardsim-3.0.4-SNAPSHOT.jar:\ - lib/commons-cli-1.3.1.jar:\ - lib/snakeyaml-1.19.jar -# Space-separated list of extra javac options -javac.compilerargs= -javac.deprecation=false -javac.processorpath=\ - ${javac.classpath} -javac.source=1.8 -javac.target=1.8 -javac.test.classpath=\ - ${javac.classpath}:\ - ${build.classes.dir} -javac.test.processorpath=\ - ${javac.test.classpath} -javadoc.additionalparam= -javadoc.author=false -javadoc.encoding=${source.encoding} -javadoc.noindex=false -javadoc.nonavbar=false -javadoc.notree=false -javadoc.private=false -javadoc.splitindex=true -javadoc.use=true -javadoc.version=false -javadoc.windowtitle= -main.class=cz.crcs.ectester.reader.ECTesterReader -manifest.file=manifest.mf -meta.inf.dir=${src.dir}/META-INF -mkdist.disabled=false -platform.active=default_platform -run.classpath=\ - ${javac.classpath}:\ - ${build.classes.dir} -# Space-separated list of JVM arguments used when running the project. -# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. -# To set system properties for unit tests define test-sys-prop.name=value: -run.jvmargs= -run.test.classpath=\ - ${javac.test.classpath}:\ - ${build.test.classes.dir} -source.encoding=UTF-8 -src.dir=src -test.src.dir=test diff --git a/nbproject/project.xml b/nbproject/project.xml deleted file mode 100644 index 6e5a48e..0000000 --- a/nbproject/project.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - org.netbeans.modules.java.j2seproject - - - ECTester - - - - - - - - - diff --git a/nbproject/reader/build-impl.xml b/nbproject/reader/build-impl.xml new file mode 100644 index 0000000..f7c43a2 --- /dev/null +++ b/nbproject/reader/build-impl.xml @@ -0,0 +1,1413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/reader/manifest.mf b/nbproject/reader/manifest.mf new file mode 100644 index 0000000..cbfea93 --- /dev/null +++ b/nbproject/reader/manifest.mf @@ -0,0 +1,4 @@ +Manifest-Version: 1.0 +Class-Path: lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.3.1.jar lib/snakeyaml-1.19.jar +Main-Class: cz.crcs.ectester.reader.ECTesterReader + diff --git a/nbproject/reader/project.properties b/nbproject/reader/project.properties new file mode 100644 index 0000000..6cd1760 --- /dev/null +++ b/nbproject/reader/project.properties @@ -0,0 +1,79 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=ECTesterReader +application.vendor=xsvenda +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# Files in build.classes.dir which should be excluded from distribution jar +dist.archive.excludes= +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/ECTesterReader.jar +dist.javadoc.dir=${dist.dir}/javadoc +libs.CopyLibs.classpath=nbproject/copylibstask.jar +endorsed.classpath= +excludes= +includes=**/applet/**,**/common/**,**/data/**,**/reader/** +jar.compress=false +javac.classpath=\ + lib/jcardsim-3.0.4-SNAPSHOT.jar:\ + lib/commons-cli-1.3.1.jar:\ + lib/snakeyaml-1.19.jar +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.8 +javac.target=1.8 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=cz.crcs.ectester.reader.ECTesterReader +manifest.file=nbproject/reader/manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=false +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project. +# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. +# To set system properties for unit tests define test-sys-prop.name=value: +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/nbproject/reader/project.xml b/nbproject/reader/project.xml new file mode 100644 index 0000000..aebe217 --- /dev/null +++ b/nbproject/reader/project.xml @@ -0,0 +1,15 @@ + + + org.netbeans.modules.java.j2seproject + + + ECTesterReader + + + + + + + + + diff --git a/nbproject/standalone/build-impl.xml b/nbproject/standalone/build-impl.xml new file mode 100644 index 0000000..a1f91c2 --- /dev/null +++ b/nbproject/standalone/build-impl.xml @@ -0,0 +1,1413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/standalone/manifest.mf b/nbproject/standalone/manifest.mf new file mode 100644 index 0000000..316e308 --- /dev/null +++ b/nbproject/standalone/manifest.mf @@ -0,0 +1,4 @@ +Manifest-Version: 1.0 +Class-Path: lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.3.1.jar lib/snakeyaml-1.19.jar +Main-Class: cz.crcs.ectester.standalone.ECTesterStandalone + diff --git a/nbproject/standalone/project.properties b/nbproject/standalone/project.properties new file mode 100644 index 0000000..1952f1d --- /dev/null +++ b/nbproject/standalone/project.properties @@ -0,0 +1,79 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=ECTesterStandalone +application.vendor=xsvenda +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# Files in build.classes.dir which should be excluded from distribution jar +dist.archive.excludes= +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/ECTesterStandalone.jar +dist.javadoc.dir=${dist.dir}/javadoc +libs.CopyLibs.classpath=nbproject/copylibstask.jar +endorsed.classpath= +excludes= +includes=**/common/**,**/standalone/**,**/data/**,**/applet/* +jar.compress=false +javac.classpath=\ + lib/jcardsim-3.0.4-SNAPSHOT.jar:\ + lib/commons-cli-1.3.1.jar:\ + lib/snakeyaml-1.19.jar +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.8 +javac.target=1.8 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=cz.crcs.ectester.standalone.ECTesterStandalone +manifest.file=nbproject/standalone/manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=false +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project. +# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. +# To set system properties for unit tests define test-sys-prop.name=value: +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/nbproject/standalone/project.xml b/nbproject/standalone/project.xml new file mode 100644 index 0000000..2f2fb3f --- /dev/null +++ b/nbproject/standalone/project.xml @@ -0,0 +1,15 @@ + + + org.netbeans.modules.java.j2seproject + + + ECTesterStandalone + + + + + + + + + diff --git a/src/cz/crcs/ectester/common/Util.java b/src/cz/crcs/ectester/common/Util.java new file mode 100644 index 0000000..0136493 --- /dev/null +++ b/src/cz/crcs/ectester/common/Util.java @@ -0,0 +1,375 @@ +package cz.crcs.ectester.common; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import javacard.framework.ISO7816; +import javacard.security.CryptoException; + +import static cz.crcs.ectester.applet.ECTesterApplet.*; + +/** + * Utility class, some byte/hex manipulation, convenient byte[] methods. + * + * @author Petr Svenda petr@svenda.com + * @author Jan Jancar johny@neuromancer.sk + */ +public class Util { + + public static short getShort(byte[] array, int offset) { + return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF)); + } + + public static void setShort(byte[] array, int offset, short value) { + array[offset + 1] = (byte) (value & 0xFF); + array[offset] = (byte) ((value >> 8) & 0xFF); + } + + public static int diffBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) { + for (int i = 0; i < length; ++i) { + byte a = one[i + oneOffset]; + byte b = other[i + otherOffset]; + if (a != b) { + return i; + } + } + return length; + } + + public static boolean compareBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) { + return diffBytes(one, oneOffset, other, otherOffset, length) == length; + } + + 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); + } + + public static byte[] hexToBytes(String hex, boolean bigEndian) { + hex = hex.replace(" ", ""); + int len = hex.length(); + StringBuilder sb = new StringBuilder(); + + if (len % 2 == 1) { + sb.append("0"); + ++len; + } + + if (bigEndian) { + sb.append(hex); + } else { + for (int i = 0; i < len / 2; ++i) { + if (sb.length() >= 2) { + sb.insert(sb.length() - 2, hex.substring(2 * i, 2 * i + 2)); + } else { + sb.append(hex.substring(2 * i, 2 * i + 2)); + } + + } + } + + String data = sb.toString(); + byte[] result = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + result[i / 2] = (byte) ((Character.digit(data.charAt(i), 16) << 4) + + (Character.digit(data.charAt(i + 1), 16))); + } + return result; + } + + public static String byteToHex(byte data) { + return String.format("%02x", data); + } + + public static String bytesToHex(byte[] data) { + return bytesToHex(data, true); + } + + public static String bytesToHex(byte[] data, boolean addSpace) { + return bytesToHex(data, 0, data.length, addSpace); + } + + public static String bytesToHex(byte[] data, int offset, int len) { + return bytesToHex(data, offset, len, true); + } + + public static String bytesToHex(byte[] data, int offset, int len, boolean addSpace) { + StringBuilder buf = new StringBuilder(); + for (int i = offset; i < (offset + len); i++) { + buf.append(byteToHex(data[i])); + if (addSpace && i != (offset + len - 1)) { + buf.append(" "); + } + } + return (buf.toString()); + } + + public static byte[] concatenate(byte[]... arrays) { + int len = 0; + for (byte[] array : arrays) { + if (array == null) + continue; + len += array.length; + } + byte[] out = new byte[len]; + int offset = 0; + for (byte[] array : arrays) { + if (array == null || array.length == 0) + continue; + System.arraycopy(array, 0, out, offset, array.length); + offset += array.length; + } + 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: + case ECTesterApplet.SW_KA_NULL: + case ECTesterApplet.SW_SIGNATURE_NULL: + case ECTesterApplet.SW_OBJECT_NULL: + return "ECTesterApplet"; + default: + return "?"; + } + } + + public static String getSW(short sw) { + String str; + switch (sw) { + case ISO7816.SW_APPLET_SELECT_FAILED: + str = "APPLET_SELECT_FAILED"; + break; + case ISO7816.SW_BYTES_REMAINING_00: + str = "BYTES_REMAINING"; + break; + case ISO7816.SW_CLA_NOT_SUPPORTED: + str = "CLA_NOT_SUPPORTED"; + break; + case ISO7816.SW_COMMAND_NOT_ALLOWED: + str = "COMMAND_NOT_ALLOWED"; + break; + case ISO7816.SW_CONDITIONS_NOT_SATISFIED: + str = "CONDITIONS_NOT_SATISFIED"; + break; + case ISO7816.SW_CORRECT_LENGTH_00: + str = "CORRECT_LENGTH"; + break; + case ISO7816.SW_DATA_INVALID: + str = "DATA_INVALID"; + break; + case ISO7816.SW_FILE_FULL: + str = "FILE_FULL"; + break; + case ISO7816.SW_FILE_INVALID: + str = "FILE_INVALID"; + break; + case ISO7816.SW_FILE_NOT_FOUND: + str = "FILE_NOT_FOUND"; + break; + case ISO7816.SW_FUNC_NOT_SUPPORTED: + str = "FUNC_NOT_SUPPORTED"; + break; + case ISO7816.SW_INCORRECT_P1P2: + str = "INCORRECT_P1P2"; + break; + case ISO7816.SW_INS_NOT_SUPPORTED: + str = "INS_NOT_SUPPORTED"; + break; + case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED: + str = "LOGICAL_CHANNEL_NOT_SUPPORTED"; + break; + case ISO7816.SW_RECORD_NOT_FOUND: + str = "RECORD_NOT_FOUND"; + break; + case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED: + str = "SECURE_MESSAGING_NOT_SUPPORTED"; + break; + case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED: + str = "SECURITY_STATUS_NOT_SATISFIED"; + break; + case ISO7816.SW_UNKNOWN: + str = "UNKNOWN"; + break; + case ISO7816.SW_WARNING_STATE_UNCHANGED: + str = "WARNING_STATE_UNCHANGED"; + break; + case ISO7816.SW_WRONG_DATA: + str = "WRONG_DATA"; + break; + case ISO7816.SW_WRONG_LENGTH: + str = "WRONG_LENGTH"; + break; + case ISO7816.SW_WRONG_P1P2: + str = "WRONG_P1P2"; + break; + case CryptoException.ILLEGAL_VALUE: + str = "ILLEGAL_VALUE"; + break; + case CryptoException.UNINITIALIZED_KEY: + str = "UNINITIALIZED_KEY"; + break; + case CryptoException.NO_SUCH_ALGORITHM: + str = "NO_SUCH_ALG"; + break; + case CryptoException.INVALID_INIT: + str = "INVALID_INIT"; + break; + case CryptoException.ILLEGAL_USE: + str = "ILLEGAL_USE"; + break; + 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; + case ECTesterApplet.SW_KA_NULL: + str = "KA_NULL"; + break; + case ECTesterApplet.SW_SIGNATURE_NULL: + str = "SIGNATURE_NULL"; + break; + case ECTesterApplet.SW_OBJECT_NULL: + str = "OBJECT_NULL"; + break; + default: + str = "unknown"; + break; + } + return str; + } + + public static String getSWString(short sw) { + if (sw == ISO7816.SW_NO_ERROR) { + return "OK (0x9000)"; + } else { + String str = getSW(sw); + return String.format("fail (%s, 0x%04x)", str, sw); + } + } + + public static String getCorruption(short corruptionType) { + String corrupt; + switch (corruptionType) { + case EC_Consts.CORRUPTION_NONE: + corrupt = "NONE"; + break; + case EC_Consts.CORRUPTION_FIXED: + corrupt = "FIXED"; + break; + case EC_Consts.CORRUPTION_ONE: + corrupt = "ONE"; + break; + case EC_Consts.CORRUPTION_ZERO: + corrupt = "ZERO"; + break; + case EC_Consts.CORRUPTION_ONEBYTERANDOM: + corrupt = "ONE_BYTE_RANDOM"; + break; + case EC_Consts.CORRUPTION_FULLRANDOM: + corrupt = "FULL_RANDOM"; + break; + case EC_Consts.CORRUPTION_INCREMENT: + corrupt = "INCREMENT"; + break; + case EC_Consts.CORRUPTION_INFINITY: + corrupt = "INFINITY"; + break; + case EC_Consts.CORRUPTION_COMPRESS: + corrupt = "COMPRESSED"; + break; + case EC_Consts.CORRUPTION_MAX: + corrupt = "MAX"; + break; + default: + corrupt = "unknown"; + break; + } + return corrupt; + } + + public static String getKA(byte ka) { + String algo = ""; + if ((ka & EC_Consts.KA_ECDH) != 0 || ka == EC_Consts.KA_ANY) { + algo += "ECDH"; + } + if (ka == EC_Consts.KA_BOTH) { + algo += "+"; + } else if (ka == EC_Consts.KA_ANY) { + algo += "/"; + } + if ((ka & EC_Consts.KA_ECDHC) != 0 || ka == EC_Consts.KA_ANY) { + algo += "ECDHC"; + } + return algo; + } + + public static String getKATypeString(byte kaType) { + String kaTypeString; + switch (kaType) { + case KeyAgreement_ALG_EC_SVDP_DH: + kaTypeString = "ALG_EC_SVDP_DH"; + break; + case KeyAgreement_ALG_EC_SVDP_DH_PLAIN: + kaTypeString = "ALG_EC_SVDP_DH_PLAIN"; + break; + case KeyAgreement_ALG_EC_PACE_GM: + kaTypeString = "ALG_EC_PACE_GM"; + break; + case KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY: + kaTypeString = "ALG_EC_SVDP_DH_PLAIN_XY"; + break; + case KeyAgreement_ALG_EC_SVDP_DHC: + kaTypeString = "ALG_EC_SVDP_DHC"; + break; + case KeyAgreement_ALG_EC_SVDP_DHC_PLAIN: + kaTypeString = "ALG_EC_SVDP_DHC_PLAIN"; + break; + default: + kaTypeString = "unknown"; + } + return kaTypeString; + } +} diff --git a/src/cz/crcs/ectester/common/ec/EC_Data.java b/src/cz/crcs/ectester/common/ec/EC_Data.java index da97208..d308261 100644 --- a/src/cz/crcs/ectester/common/ec/EC_Data.java +++ b/src/cz/crcs/ectester/common/ec/EC_Data.java @@ -1,6 +1,6 @@ package cz.crcs.ectester.common.ec; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.Util; import java.io.*; import java.util.*; diff --git a/src/cz/crcs/ectester/common/ec/EC_KAResult.java b/src/cz/crcs/ectester/common/ec/EC_KAResult.java index b215d0e..3b74c57 100644 --- a/src/cz/crcs/ectester/common/ec/EC_KAResult.java +++ b/src/cz/crcs/ectester/common/ec/EC_KAResult.java @@ -1,6 +1,6 @@ package cz.crcs.ectester.common.ec; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.Util; /** * A result of EC based Key agreement operation. diff --git a/src/cz/crcs/ectester/common/ec/EC_Params.java b/src/cz/crcs/ectester/common/ec/EC_Params.java index 5b8295e..d50ebb0 100644 --- a/src/cz/crcs/ectester/common/ec/EC_Params.java +++ b/src/cz/crcs/ectester/common/ec/EC_Params.java @@ -1,7 +1,7 @@ package cz.crcs.ectester.common.ec; import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.Util; import java.io.ByteArrayOutputStream; import java.util.ArrayList; diff --git a/src/cz/crcs/ectester/common/output/OutputLogger.java b/src/cz/crcs/ectester/common/output/OutputLogger.java index b876c5b..09b8f73 100644 --- a/src/cz/crcs/ectester/common/output/OutputLogger.java +++ b/src/cz/crcs/ectester/common/output/OutputLogger.java @@ -1,7 +1,5 @@ package cz.crcs.ectester.common.output; -import cz.crcs.ectester.reader.output.TeeOutputStream; - import java.io.*; import java.util.LinkedList; import java.util.List; diff --git a/src/cz/crcs/ectester/common/output/TeeOutputStream.java b/src/cz/crcs/ectester/common/output/TeeOutputStream.java new file mode 100644 index 0000000..2401fce --- /dev/null +++ b/src/cz/crcs/ectester/common/output/TeeOutputStream.java @@ -0,0 +1,36 @@ +package cz.crcs.ectester.common.output; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class TeeOutputStream extends OutputStream { + private OutputStream[] outputs; + + public TeeOutputStream(OutputStream... outputs) { + this.outputs = outputs; + } + + @Override + public void write(int b) throws IOException { + for (OutputStream out : outputs) { + out.write(b); + } + } + + @Override + public void flush() throws IOException { + for (OutputStream out : outputs) { + out.flush(); + } + } + + @Override + public void close() throws IOException { + for (OutputStream out : outputs) { + out.close(); + } + } +} diff --git a/src/cz/crcs/ectester/common/test/Test.java b/src/cz/crcs/ectester/common/test/Test.java index 5973d0f..750a410 100644 --- a/src/cz/crcs/ectester/common/test/Test.java +++ b/src/cz/crcs/ectester/common/test/Test.java @@ -39,6 +39,13 @@ public abstract class Test implements Testable { return result.ok(); } + public boolean error() { + if (!hasRun) { + return false; + } + return result.compareTo(Value.ERROR); + } + public abstract String getDescription(); public boolean hasRun() { diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index e11bcb3..ad5b368 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -2,6 +2,7 @@ package cz.crcs.ectester.reader; import com.licel.jcardsim.io.CAD; import com.licel.jcardsim.io.JavaxSmartCardInterface; +import cz.crcs.ectester.common.Util; import javacard.framework.AID; import javax.smartcardio.*; diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 99b2f83..e13a683 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -23,6 +23,7 @@ package cz.crcs.ectester.reader; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.Util; import cz.crcs.ectester.common.ec.EC_Category; import cz.crcs.ectester.common.ec.EC_Data; import cz.crcs.ectester.common.ec.EC_Params; diff --git a/src/cz/crcs/ectester/reader/Util.java b/src/cz/crcs/ectester/reader/Util.java deleted file mode 100644 index 001f58c..0000000 --- a/src/cz/crcs/ectester/reader/Util.java +++ /dev/null @@ -1,375 +0,0 @@ -package cz.crcs.ectester.reader; - -import cz.crcs.ectester.applet.ECTesterApplet; -import cz.crcs.ectester.applet.EC_Consts; -import javacard.framework.ISO7816; -import javacard.security.CryptoException; - -import static cz.crcs.ectester.applet.ECTesterApplet.*; - -/** - * Utility class, some byte/hex manipulation, convenient byte[] methods. - * - * @author Petr Svenda petr@svenda.com - * @author Jan Jancar johny@neuromancer.sk - */ -public class Util { - - public static short getShort(byte[] array, int offset) { - return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF)); - } - - public static void setShort(byte[] array, int offset, short value) { - array[offset + 1] = (byte) (value & 0xFF); - array[offset] = (byte) ((value >> 8) & 0xFF); - } - - public static int diffBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) { - for (int i = 0; i < length; ++i) { - byte a = one[i + oneOffset]; - byte b = other[i + otherOffset]; - if (a != b) { - return i; - } - } - return length; - } - - public static boolean compareBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) { - return diffBytes(one, oneOffset, other, otherOffset, length) == length; - } - - 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); - } - - public static byte[] hexToBytes(String hex, boolean bigEndian) { - hex = hex.replace(" ", ""); - int len = hex.length(); - StringBuilder sb = new StringBuilder(); - - if (len % 2 == 1) { - sb.append("0"); - ++len; - } - - if (bigEndian) { - sb.append(hex); - } else { - for (int i = 0; i < len / 2; ++i) { - if (sb.length() >= 2) { - sb.insert(sb.length() - 2, hex.substring(2 * i, 2 * i + 2)); - } else { - sb.append(hex.substring(2 * i, 2 * i + 2)); - } - - } - } - - String data = sb.toString(); - byte[] result = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - result[i / 2] = (byte) ((Character.digit(data.charAt(i), 16) << 4) - + (Character.digit(data.charAt(i + 1), 16))); - } - return result; - } - - public static String byteToHex(byte data) { - return String.format("%02x", data); - } - - public static String bytesToHex(byte[] data) { - return bytesToHex(data, true); - } - - public static String bytesToHex(byte[] data, boolean addSpace) { - return bytesToHex(data, 0, data.length, addSpace); - } - - public static String bytesToHex(byte[] data, int offset, int len) { - return bytesToHex(data, offset, len, true); - } - - public static String bytesToHex(byte[] data, int offset, int len, boolean addSpace) { - StringBuilder buf = new StringBuilder(); - for (int i = offset; i < (offset + len); i++) { - buf.append(byteToHex(data[i])); - if (addSpace && i != (offset + len - 1)) { - buf.append(" "); - } - } - return (buf.toString()); - } - - public static byte[] concatenate(byte[]... arrays) { - int len = 0; - for (byte[] array : arrays) { - if (array == null) - continue; - len += array.length; - } - byte[] out = new byte[len]; - int offset = 0; - for (byte[] array : arrays) { - if (array == null || array.length == 0) - continue; - System.arraycopy(array, 0, out, offset, array.length); - offset += array.length; - } - 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: - case ECTesterApplet.SW_KA_NULL: - case ECTesterApplet.SW_SIGNATURE_NULL: - case ECTesterApplet.SW_OBJECT_NULL: - return "ECTesterApplet"; - default: - return "?"; - } - } - - public static String getSW(short sw) { - String str; - switch (sw) { - case ISO7816.SW_APPLET_SELECT_FAILED: - str = "APPLET_SELECT_FAILED"; - break; - case ISO7816.SW_BYTES_REMAINING_00: - str = "BYTES_REMAINING"; - break; - case ISO7816.SW_CLA_NOT_SUPPORTED: - str = "CLA_NOT_SUPPORTED"; - break; - case ISO7816.SW_COMMAND_NOT_ALLOWED: - str = "COMMAND_NOT_ALLOWED"; - break; - case ISO7816.SW_CONDITIONS_NOT_SATISFIED: - str = "CONDITIONS_NOT_SATISFIED"; - break; - case ISO7816.SW_CORRECT_LENGTH_00: - str = "CORRECT_LENGTH"; - break; - case ISO7816.SW_DATA_INVALID: - str = "DATA_INVALID"; - break; - case ISO7816.SW_FILE_FULL: - str = "FILE_FULL"; - break; - case ISO7816.SW_FILE_INVALID: - str = "FILE_INVALID"; - break; - case ISO7816.SW_FILE_NOT_FOUND: - str = "FILE_NOT_FOUND"; - break; - case ISO7816.SW_FUNC_NOT_SUPPORTED: - str = "FUNC_NOT_SUPPORTED"; - break; - case ISO7816.SW_INCORRECT_P1P2: - str = "INCORRECT_P1P2"; - break; - case ISO7816.SW_INS_NOT_SUPPORTED: - str = "INS_NOT_SUPPORTED"; - break; - case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED: - str = "LOGICAL_CHANNEL_NOT_SUPPORTED"; - break; - case ISO7816.SW_RECORD_NOT_FOUND: - str = "RECORD_NOT_FOUND"; - break; - case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED: - str = "SECURE_MESSAGING_NOT_SUPPORTED"; - break; - case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED: - str = "SECURITY_STATUS_NOT_SATISFIED"; - break; - case ISO7816.SW_UNKNOWN: - str = "UNKNOWN"; - break; - case ISO7816.SW_WARNING_STATE_UNCHANGED: - str = "WARNING_STATE_UNCHANGED"; - break; - case ISO7816.SW_WRONG_DATA: - str = "WRONG_DATA"; - break; - case ISO7816.SW_WRONG_LENGTH: - str = "WRONG_LENGTH"; - break; - case ISO7816.SW_WRONG_P1P2: - str = "WRONG_P1P2"; - break; - case CryptoException.ILLEGAL_VALUE: - str = "ILLEGAL_VALUE"; - break; - case CryptoException.UNINITIALIZED_KEY: - str = "UNINITIALIZED_KEY"; - break; - case CryptoException.NO_SUCH_ALGORITHM: - str = "NO_SUCH_ALG"; - break; - case CryptoException.INVALID_INIT: - str = "INVALID_INIT"; - break; - case CryptoException.ILLEGAL_USE: - str = "ILLEGAL_USE"; - break; - 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; - case ECTesterApplet.SW_KA_NULL: - str = "KA_NULL"; - break; - case ECTesterApplet.SW_SIGNATURE_NULL: - str = "SIGNATURE_NULL"; - break; - case ECTesterApplet.SW_OBJECT_NULL: - str = "OBJECT_NULL"; - break; - default: - str = "unknown"; - break; - } - return str; - } - - public static String getSWString(short sw) { - if (sw == ISO7816.SW_NO_ERROR) { - return "OK (0x9000)"; - } else { - String str = getSW(sw); - return String.format("fail (%s, 0x%04x)", str, sw); - } - } - - public static String getCorruption(short corruptionType) { - String corrupt; - switch (corruptionType) { - case EC_Consts.CORRUPTION_NONE: - corrupt = "NONE"; - break; - case EC_Consts.CORRUPTION_FIXED: - corrupt = "FIXED"; - break; - case EC_Consts.CORRUPTION_ONE: - corrupt = "ONE"; - break; - case EC_Consts.CORRUPTION_ZERO: - corrupt = "ZERO"; - break; - case EC_Consts.CORRUPTION_ONEBYTERANDOM: - corrupt = "ONE_BYTE_RANDOM"; - break; - case EC_Consts.CORRUPTION_FULLRANDOM: - corrupt = "FULL_RANDOM"; - break; - case EC_Consts.CORRUPTION_INCREMENT: - corrupt = "INCREMENT"; - break; - case EC_Consts.CORRUPTION_INFINITY: - corrupt = "INFINITY"; - break; - case EC_Consts.CORRUPTION_COMPRESS: - corrupt = "COMPRESSED"; - break; - case EC_Consts.CORRUPTION_MAX: - corrupt = "MAX"; - break; - default: - corrupt = "unknown"; - break; - } - return corrupt; - } - - public static String getKA(byte ka) { - String algo = ""; - if ((ka & EC_Consts.KA_ECDH) != 0 || ka == EC_Consts.KA_ANY) { - algo += "ECDH"; - } - if (ka == EC_Consts.KA_BOTH) { - algo += "+"; - } else if (ka == EC_Consts.KA_ANY) { - algo += "/"; - } - if ((ka & EC_Consts.KA_ECDHC) != 0 || ka == EC_Consts.KA_ANY) { - algo += "ECDHC"; - } - return algo; - } - - public static String getKATypeString(byte kaType) { - String kaTypeString; - switch (kaType) { - case KeyAgreement_ALG_EC_SVDP_DH: - kaTypeString = "ALG_EC_SVDP_DH"; - break; - case KeyAgreement_ALG_EC_SVDP_DH_PLAIN: - kaTypeString = "ALG_EC_SVDP_DH_PLAIN"; - break; - case KeyAgreement_ALG_EC_PACE_GM: - kaTypeString = "ALG_EC_PACE_GM"; - break; - case KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY: - kaTypeString = "ALG_EC_SVDP_DH_PLAIN_XY"; - break; - case KeyAgreement_ALG_EC_SVDP_DHC: - kaTypeString = "ALG_EC_SVDP_DHC"; - break; - case KeyAgreement_ALG_EC_SVDP_DHC_PLAIN: - kaTypeString = "ALG_EC_SVDP_DHC_PLAIN"; - break; - default: - kaTypeString = "unknown"; - } - return kaTypeString; - } -} diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index 3668fbb..9d23322 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -6,7 +6,7 @@ import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.response.Response; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.Util; import cz.crcs.ectester.common.ec.EC_Curve; import cz.crcs.ectester.common.ec.EC_Key; import cz.crcs.ectester.common.ec.EC_Keypair; diff --git a/src/cz/crcs/ectester/reader/output/ResponseWriter.java b/src/cz/crcs/ectester/reader/output/ResponseWriter.java index c357233..0f5b6e8 100644 --- a/src/cz/crcs/ectester/reader/output/ResponseWriter.java +++ b/src/cz/crcs/ectester/reader/output/ResponseWriter.java @@ -1,6 +1,6 @@ package cz.crcs.ectester.reader.output; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.Util; import cz.crcs.ectester.reader.response.Response; import java.io.PrintStream; diff --git a/src/cz/crcs/ectester/reader/output/TeeOutputStream.java b/src/cz/crcs/ectester/reader/output/TeeOutputStream.java deleted file mode 100644 index 2a1af99..0000000 --- a/src/cz/crcs/ectester/reader/output/TeeOutputStream.java +++ /dev/null @@ -1,36 +0,0 @@ -package cz.crcs.ectester.reader.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class TeeOutputStream extends OutputStream { - private OutputStream[] outputs; - - public TeeOutputStream(OutputStream... outputs) { - this.outputs = outputs; - } - - @Override - public void write(int b) throws IOException { - for (OutputStream out : outputs) { - out.write(b); - } - } - - @Override - public void flush() throws IOException { - for (OutputStream out : outputs) { - out.flush(); - } - } - - @Override - public void close() throws IOException { - for (OutputStream out : outputs) { - out.close(); - } - } -} diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java index f35e467..24a308c 100644 --- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java @@ -1,7 +1,7 @@ package cz.crcs.ectester.reader.output; import cz.crcs.ectester.common.test.CompoundTest; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.Util; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.common.test.Test; diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java index 15c0522..c637a13 100644 --- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java @@ -1,7 +1,7 @@ package cz.crcs.ectester.reader.output; import cz.crcs.ectester.common.test.CompoundTest; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.Util; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.common.test.Test; diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index b816a97..4158ac3 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -2,7 +2,7 @@ package cz.crcs.ectester.reader.response; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.Util; import javacard.framework.ISO7816; import javacard.security.KeyPair; diff --git a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java index 742661d..668056b 100644 --- a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java +++ b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java @@ -8,7 +8,7 @@ import cz.crcs.ectester.common.test.Test; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.Util; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.common.ec.*; import cz.crcs.ectester.reader.response.Response; diff --git a/src/cz/crcs/ectester/scripts/ectester-reader.bat b/src/cz/crcs/ectester/scripts/ectester-reader.bat new file mode 100644 index 0000000..876fda7 --- /dev/null +++ b/src/cz/crcs/ectester/scripts/ectester-reader.bat @@ -0,0 +1,34 @@ +@ECHO OFF +SETLOCAL enabledelayedexpansion + +SET n=0 +:loop +IF NOT "%1"=="" ( + IF "%1"=="--dangerous" ( + SET dangerous=1 + ) ELSE ( + SET positional[!n!]=%1 + SET /A n+=1 + ) + SHIFT + GOTO :loop +) + +IF NOT "%n%"=="1" ( + ECHO "One argument expected:" + ECHO " ./ectester-reader.bat [--dangerous] CARD_NAME" +) + +SET card=!positional[%%0]! + +SET tests="default test-vectors" +java -jar ECTesterReader.jar -t default -a --format yaml -l %card%.default +java -jar ECTesterReader.jar -t test-vectors -a --format yaml -l %card%.test-vectors +IF "%dangerous%"=="1" ( + SET tests=%tests% "invalid wrong composite" + java -jar ECTesterReader.jar -t invalid -a --format yaml -l %card%.invalid + java -jar ECTesterReader.jar -t wrong -a --format yaml -l %card%.wrong + java -jar ECTesterReader.jar -t composite -a --format yaml -l %card%.composite +) + +zip %card%.zip %tests% diff --git a/src/cz/crcs/ectester/scripts/ectester-reader.sh b/src/cz/crcs/ectester/scripts/ectester-reader.sh new file mode 100755 index 0000000..e6458c9 --- /dev/null +++ b/src/cz/crcs/ectester/scripts/ectester-reader.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +dangerous="0" + +positional=() +while [[ $# -gt 0 ]] +do + +key="$1" +case $key in + --dangerous) + dangerous=1 + shift + ;; + *) + positional+=("$1") + shift + ;; +esac +done +set -- "${positional[@]}" + +if [[ $# -lt 1 ]]; then + echo "At least one argument expected:" >&2 + echo " ./ectester-reader.sh [--dangerous] CARD_NAME [ECTester args]" >&2 + exit 1 +fi + +card="$1" +shift + +declare -a tests=("default" "test-vectors") +if [[ "$dangerous" == "1" ]]; then + tests+=("invalid" "wrong" "composite") +fi + +declare -a files=() +for i in $(seq 0 $((${#tests[@]} - 1))); do + test="${tests[$i]}" + java -jar ECTester.jar -t ${test} -a --format yaml -l ${card}.${test} $@ + files+=(${card}.$test) +done + +if command -v tar 2>&1 >/dev/null; then + tar -czvf ${card}.tar.gz ${files[*]} +elif command -v zip 2>&1 >/dev/null; then + zip ${card}.zip ${files[*]} +fi diff --git a/src/cz/crcs/ectester/scripts/ectester.bat b/src/cz/crcs/ectester/scripts/ectester.bat deleted file mode 100644 index e20b855..0000000 --- a/src/cz/crcs/ectester/scripts/ectester.bat +++ /dev/null @@ -1,34 +0,0 @@ -@ECHO OFF -SETLOCAL enabledelayedexpansion - -SET n=0 -:loop -IF NOT "%1"=="" ( - IF "%1"=="--dangerous" ( - SET dangerous=1 - ) ELSE ( - SET positional[!n!]=%1 - SET /A n+=1 - ) - SHIFT - GOTO :loop -) - -IF NOT "%n%"=="1" ( - ECHO "One argument expected:" - ECHO " ./ectester.bar [--dangerous] CARD_NAME" -) - -SET card=!positional[%%0]! - -SET tests="default test-vectors" -java -jar ECTester.jar -t default -a --format yaml -l %card%.default -java -jar ECTester.jar -t test-vectors -a --format yaml -l %card%.test-vectors -IF "%dangerous%"=="1" ( - SET tests=%tests% "invalid wrong composite" - java -jar ECTester.jar -t invalid -a --format yaml -l %card%.invalid - java -jar ECTester.jar -t wrong -a --format yaml -l %card%.wrong - java -jar ECTester.jar -t composite -a --format yaml -l %card%.composite -) - -zip %card%.zip %tests% diff --git a/src/cz/crcs/ectester/scripts/ectester.sh b/src/cz/crcs/ectester/scripts/ectester.sh deleted file mode 100755 index 8040096..0000000 --- a/src/cz/crcs/ectester/scripts/ectester.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -dangerous="0" - -positional=() -while [[ $# -gt 0 ]] -do - -key="$1" -case $key in - --dangerous) - dangerous=1 - shift - ;; - *) - positional+=("$1") - shift - ;; -esac -done -set -- "${positional[@]}" - -if [[ $# -lt 1 ]]; then - echo "At least one argument expected:" >&2 - echo " ./ectester.sh [--dangerous] CARD_NAME [ECTester args]" >&2 - exit 1 -fi - -card="$1" -shift - -declare -a tests=("default" "test-vectors") -if [[ "$dangerous" == "1" ]]; then - tests+=("invalid" "wrong" "composite") -fi - -declare -a files=() -for i in $(seq 0 $((${#tests[@]} - 1))); do - test="${tests[$i]}" - java -jar ECTester.jar -t ${test} -a --format yaml -l ${card}.${test} $@ - files+=(${card}.$test) -done - -if command -v tar 2>&1 >/dev/null; then - tar -czvf ${card}.tar.gz ${files[*]} -elif command -v zip 2>&1 >/dev/null; then - zip ${card}.zip ${files[*]} -fi -- cgit v1.2.3-70-g09d2 From e97e68677d0141af52e0c5be291d147cbe58c5b1 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 12 Nov 2017 17:18:28 +0100 Subject: Add ANSI curves. --- src/cz/crcs/ectester/data/categories.xml | 5 +++ src/cz/crcs/ectester/data/x962/curves.xml | 48 +++++++++++++++++++++++++++ src/cz/crcs/ectester/data/x962/prime192v1.csv | 1 + src/cz/crcs/ectester/data/x962/prime192v2.csv | 1 + src/cz/crcs/ectester/data/x962/prime192v3.csv | 1 + src/cz/crcs/ectester/data/x962/prime239v1.csv | 1 + src/cz/crcs/ectester/data/x962/prime239v2.csv | 1 + src/cz/crcs/ectester/data/x962/prime239v3.csv | 1 + src/cz/crcs/ectester/data/x962/prime256v1.csv | 1 + 9 files changed, 60 insertions(+) create mode 100644 src/cz/crcs/ectester/data/x962/curves.xml create mode 100644 src/cz/crcs/ectester/data/x962/prime192v1.csv create mode 100644 src/cz/crcs/ectester/data/x962/prime192v2.csv create mode 100644 src/cz/crcs/ectester/data/x962/prime192v3.csv create mode 100644 src/cz/crcs/ectester/data/x962/prime239v1.csv create mode 100644 src/cz/crcs/ectester/data/x962/prime239v2.csv create mode 100644 src/cz/crcs/ectester/data/x962/prime239v3.csv create mode 100644 src/cz/crcs/ectester/data/x962/prime256v1.csv diff --git a/src/cz/crcs/ectester/data/categories.xml b/src/cz/crcs/ectester/data/categories.xml index 750fa8c..d7f0f7e 100644 --- a/src/cz/crcs/ectester/data/categories.xml +++ b/src/cz/crcs/ectester/data/categories.xml @@ -51,4 +51,9 @@ test Test vectors + + x962 + x962 + ANSI X9.62 example curves. + \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/curves.xml b/src/cz/crcs/ectester/data/x962/curves.xml new file mode 100644 index 0000000..eee64ad --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/curves.xml @@ -0,0 +1,48 @@ + + + + prime192v1 + 192 + prime + prime192v1.csv + + + prime192v2 + 192 + prime + prime192v2.csv + + + prime192v3 + 192 + prime + prime192v3.csv + + + + prime239v1 + 239 + prime + prime239v1.csv + + + prime239v2 + 239 + prime + prime239v2.csv + + + prime239v3 + 239 + prime + prime239v3.csv + + + + prime256v1 + 256 + prime + prime256v1.csv + + \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime192v1.csv b/src/cz/crcs/ectester/data/x962/prime192v1.csv new file mode 100644 index 0000000..07f9154 --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime192v1.csv @@ -0,0 +1 @@ +0xfffffffffffffffffffffffffffffffeffffffffffffffff,0xfffffffffffffffffffffffffffffffefffffffffffffffc,0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1,0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012,0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811,0xffffffffffffffffffffffff99def836146bc9b1b4d22831,0x1 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime192v2.csv b/src/cz/crcs/ectester/data/x962/prime192v2.csv new file mode 100644 index 0000000..ee6f1a2 --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime192v2.csv @@ -0,0 +1 @@ +0xfffffffffffffffffffffffffffffffeffffffffffffffff,0xfffffffffffffffffffffffffffffffefffffffffffffffc,0xcc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953,0xeea2bae7e1497842f2de7769cfe9c989c072ad696f48034a,0x6574d11d69b6ec7a672bb82a083df2f2b0847de970b2de15,0xfffffffffffffffffffffffe5fb1a724dc80418648d8dd31,0x1 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime192v3.csv b/src/cz/crcs/ectester/data/x962/prime192v3.csv new file mode 100644 index 0000000..f80fd5b --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime192v3.csv @@ -0,0 +1 @@ +0xfffffffffffffffffffffffffffffffeffffffffffffffff,0xfffffffffffffffffffffffffffffffefffffffffffffffc,0x22123dc2395a05caa7423daeccc94760a7d462256bd56916,0x7d29778100c65a1da1783716588dce2b8b4aee8e228f1896,0x38a90f22637337334b49dcb66a6dc8f9978aca7648a943b0,0xffffffffffffffffffffffff7a62d031c83f4294f640ec13,0x1 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime239v1.csv b/src/cz/crcs/ectester/data/x962/prime239v1.csv new file mode 100644 index 0000000..c9d704b --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime239v1.csv @@ -0,0 +1 @@ +0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,0x6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a,0x0ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf,0x7debe8e4e90a5dae6e4054ca530ba04654b36818ce226b39fccb7b02f1ae,0x7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b,0x1 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime239v2.csv b/src/cz/crcs/ectester/data/x962/prime239v2.csv new file mode 100644 index 0000000..100e60b --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime239v2.csv @@ -0,0 +1 @@ +0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,0x617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c,0x38af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7,0x5b0125e4dbea0ec7206da0fc01d9b081329fb555de6ef460237dff8be4ba,0x7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063,0x1 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime239v3.csv b/src/cz/crcs/ectester/data/x962/prime239v3.csv new file mode 100644 index 0000000..ce8b38a --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime239v3.csv @@ -0,0 +1 @@ +0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,0x255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e,0x6768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a,0x1607e6898f390c06bc1d552bad226f3b6fcfe48b6e818499af18e3ed6cf3,0x7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551,0x1 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime256v1.csv b/src/cz/crcs/ectester/data/x962/prime256v1.csv new file mode 100644 index 0000000..c5a2440 --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime256v1.csv @@ -0,0 +1 @@ +0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff,0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc,0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b,0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551,0x1 \ No newline at end of file -- cgit v1.2.3-70-g09d2 From e329190e496ecf847cfd7afa886ac08cacb2fc92 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 12 Nov 2017 17:23:04 +0100 Subject: Add BouncyCastle library. Sketch out ECTesterStandalone. --- docs/LIBS.md | 16 ++++ lib/bcprov-jdk15on-1.58.jar | Bin 0 -> 3955990 bytes nbproject/standalone/manifest.mf | 2 +- nbproject/standalone/project.properties | 1 + src/cz/crcs/ectester/common/ec/EC_Data.java | 8 +- src/cz/crcs/ectester/common/ec/EC_Params.java | 43 +++++++++++ src/cz/crcs/ectester/reader/ECTesterReader.java | 2 +- .../crcs/ectester/reader/test/TestVectorSuite.java | 4 +- .../ectester/standalone/ECTesterStandalone.java | 86 +++++++++++++++++++++ .../ectester/standalone/libs/BouncyCastleLib.java | 21 +++++ 10 files changed, 175 insertions(+), 8 deletions(-) create mode 100644 docs/LIBS.md create mode 100644 lib/bcprov-jdk15on-1.58.jar create mode 100644 src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java diff --git a/docs/LIBS.md b/docs/LIBS.md new file mode 100644 index 0000000..97a80ec --- /dev/null +++ b/docs/LIBS.md @@ -0,0 +1,16 @@ +# Libraries + +Libraries with at least some ECC support: + + - [BouncyCastle](https://bouncycastle.org/java.html) + - [Botan](https://botan.randombit.net/) + - [Crypto++](https://cryptopp.com/) + - [libgcrypt](https://www.gnupg.org/related_software/libgcrypt/) + - [libtomcrypt](http://www.libtom.net/LibTomCrypt/) + - [mbedTLS](https://tls.mbed.org/) + - [Nettle](http://www.lysator.liu.se/~nisse/nettle/) + - [OpenSSL](https://www.openssl.org/) + - [OpenSSL (FIPS mode)](https://www.openssl.org/docs/fipsnotes.html) + - [Sun EC](https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SunEC) + - [Microsoft CNG](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376210(v=vs.85).aspx) + - [Microsoft .NET crypto](https://docs.microsoft.com/en-us/dotnet/standard/security/cryptography-model) \ No newline at end of file diff --git a/lib/bcprov-jdk15on-1.58.jar b/lib/bcprov-jdk15on-1.58.jar new file mode 100644 index 0000000..dae02cb Binary files /dev/null and b/lib/bcprov-jdk15on-1.58.jar differ diff --git a/nbproject/standalone/manifest.mf b/nbproject/standalone/manifest.mf index 316e308..02f1e3e 100644 --- a/nbproject/standalone/manifest.mf +++ b/nbproject/standalone/manifest.mf @@ -1,4 +1,4 @@ Manifest-Version: 1.0 -Class-Path: lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.3.1.jar lib/snakeyaml-1.19.jar +Class-Path: lib/bcprov-jdk15on-1.58.jar lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.3.1.jar lib/snakeyaml-1.19.jar Main-Class: cz.crcs.ectester.standalone.ECTesterStandalone diff --git a/nbproject/standalone/project.properties b/nbproject/standalone/project.properties index 1952f1d..367ec51 100644 --- a/nbproject/standalone/project.properties +++ b/nbproject/standalone/project.properties @@ -33,6 +33,7 @@ excludes= includes=**/common/**,**/standalone/**,**/data/**,**/applet/* jar.compress=false javac.classpath=\ + lib/bcprov-jdk15on-1.58.jar:\ lib/jcardsim-3.0.4-SNAPSHOT.jar:\ lib/commons-cli-1.3.1.jar:\ lib/snakeyaml-1.19.jar diff --git a/src/cz/crcs/ectester/common/ec/EC_Data.java b/src/cz/crcs/ectester/common/ec/EC_Data.java index d308261..acd282a 100644 --- a/src/cz/crcs/ectester/common/ec/EC_Data.java +++ b/src/cz/crcs/ectester/common/ec/EC_Data.java @@ -55,12 +55,12 @@ public abstract class EC_Data { return data; } - public boolean hasData() { - return data != null; + public byte[] getData(int index) { + return data[index]; } - public byte[] getParam(int index) { - return data[index]; + public boolean hasData() { + return data != null; } public byte[] flatten() { diff --git a/src/cz/crcs/ectester/common/ec/EC_Params.java b/src/cz/crcs/ectester/common/ec/EC_Params.java index d50ebb0..3fada93 100644 --- a/src/cz/crcs/ectester/common/ec/EC_Params.java +++ b/src/cz/crcs/ectester/common/ec/EC_Params.java @@ -44,6 +44,49 @@ public class EC_Params extends EC_Data { return params; } + public byte[][] getParam(short param) { + if (!hasParam(param)) { + return null; + } + if (Integer.bitCount(param) != 1) { + return null; + } + short paramMask = EC_Consts.PARAMETER_FP; + byte[][] result = null; + int i = 0; + while (paramMask <= EC_Consts.PARAMETER_S) { + short masked = (short) (this.params & param & paramMask); + short shallow = (short) (this.params & paramMask); + if (masked != 0) { + if (masked == EC_Consts.PARAMETER_F2M) { + result = new byte[4][]; + result[0] = data[i].clone(); + result[1] = data[i+1].clone(); + result[2] = data[i+2].clone(); + result[3] = data[i+3].clone(); + break; + } + if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) { + result = new byte[2][]; + result[0] = data[i].clone(); + result[1] = data[i+1].clone(); + break; + } + result = new byte[1][]; + result[0] = data[i].clone(); + } + if (shallow == EC_Consts.PARAMETER_F2M) { + i += 4; + } else if (shallow == EC_Consts.PARAMETER_G || shallow == EC_Consts.PARAMETER_W) { + i += 2; + } else if (shallow != 0) { + i++; + } + paramMask = (short) (paramMask << 1); + } + return result; + } + public boolean hasParam(short param) { return (params & param) != 0; } diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index e13a683..0bbe8f7 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -63,7 +63,7 @@ public class ECTesterReader { private Options opts = new Options(); private static final String VERSION = "v0.1.0"; - private static final String DESCRIPTION = "ECTesterReader " + VERSION + ", a javacard Elliptic Curve Cryptograhy support tester/utility."; + private static final String DESCRIPTION = "ECTesterReader " + VERSION + ", a javacard Elliptic Curve Cryptography support tester/utility."; private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda "; private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; private static final String CLI_FOOTER = "\n" + LICENSE; diff --git a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java index 668056b..3f11a79 100644 --- a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java +++ b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java @@ -72,8 +72,8 @@ public class TestVectorSuite extends TestSuite { return new Result(Value.FAILURE, "ECDH was unsuccessful."); if (!dh.hasSecret()) return new Result(Value.FAILURE, "ECDH response did not contain the derived secret."); - if (!Util.compareBytes(dh.getSecret(), 0, result.getParam(0), 0, dh.secretLength())) { - int firstDiff = Util.diffBytes(dh.getSecret(), 0, result.getParam(0), 0, dh.secretLength()); + if (!Util.compareBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength())) { + int firstDiff = Util.diffBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength()); return new Result(Value.FAILURE, "ECDH derived secret does not match the test, first difference was at byte " + String.valueOf(firstDiff) + "."); } return new Result(Value.SUCCESS); diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index cae4bb9..d2cbce1 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -1,8 +1,90 @@ package cz.crcs.ectester.standalone; +import cz.crcs.ectester.common.Util; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.data.EC_Store; +import org.apache.commons.cli.*; + +import java.io.IOException; + +/** + * Standalone part of ECTester, a tool for testing Elliptic curve implementations in software libraries. + * + * @author Jan Jancar johny@neuromancer.sk + * @version v0.1.0 + */ public class ECTesterStandalone { + private EC_Store dataStore; + private Config cfg; + + private Options opts = new Options(); + private static final String VERSION = "v0.1.0"; + private static final String DESCRIPTION = "ECTesterStandalone " + VERSION + ", an Elliptic Curve Cryptography support tester/utility."; + private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda "; + private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; + private static final String CLI_FOOTER = "\n" + LICENSE; + private void run(String[] args) { + try { + CommandLine cli = parseArgs(args); + + if (cli.hasOption("help")) { + help(); + return; + } else if (cli.hasOption("version")) { + version(); + return; + } + + cfg = new Config(); + dataStore = new EC_Store(); + + if (cli.hasOption("generate")) { + generate(); + } + + } catch (ParseException | IOException ex) { + System.err.println(ex.getMessage()); + } + } + + private CommandLine parseArgs(String[] args) throws ParseException { + OptionGroup actions = new OptionGroup(); + actions.setRequired(true); + actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); + actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); + actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build()); + opts.addOptionGroup(actions); + + CommandLineParser parser = new DefaultParser(); + return parser.parse(opts, args); + } + + /** + * Prints help. + */ + private void help() { + HelpFormatter help = new HelpFormatter(); + help.setOptionComparator(null); + help.printHelp("ECTesterStandalone.jar", CLI_HEADER, opts, CLI_FOOTER, true); + } + + /** + * Prints version info. + */ + private void version() { + System.out.println(DESCRIPTION); + System.out.println(LICENSE); + } + + /** + * + */ + private void generate() { + EC_Curve curve = dataStore.getObject(EC_Curve.class, "secg/secp192r1"); + byte[] fp = curve.getParam(EC_Consts.PARAMETER_FP)[0]; } @@ -10,4 +92,8 @@ public class ECTesterStandalone { ECTesterStandalone app = new ECTesterStandalone(); app.run(args); } + + public static class Config { + + } } diff --git a/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java b/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java new file mode 100644 index 0000000..78da737 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java @@ -0,0 +1,21 @@ +package cz.crcs.ectester.standalone.libs; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import java.security.Security; + +public class BouncyCastleLib { + + public BouncyCastleLib() { + + } + + public boolean setUp() { + try { + Security.addProvider(new BouncyCastleProvider()); + } catch (NullPointerException | SecurityException ignored) { + return false; + } + return true; + } + +} -- cgit v1.2.3-70-g09d2 From 9e615b101398bd4c8e2678bf86337e2756a8ee7a Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 12 Nov 2017 23:39:35 +0100 Subject: Implement collecting of supported KeyAgreement and Signature objects. --- .../ectester/standalone/ECTesterStandalone.java | 26 ++++++- src/cz/crcs/ectester/standalone/consts/Ident.java | 41 +++++++++++ .../standalone/consts/KeyAgreementIdent.java | 53 ++++++++++++++ .../ectester/standalone/consts/SignatureIdent.java | 77 ++++++++++++++++++++ .../ectester/standalone/libs/BouncyCastleLib.java | 19 ++--- .../crcs/ectester/standalone/libs/CECLibrary.java | 31 ++++++++ .../crcs/ectester/standalone/libs/ECLibrary.java | 21 ++++++ .../ectester/standalone/libs/JavaECLibrary.java | 85 ++++++++++++++++++++++ src/cz/crcs/ectester/standalone/libs/SunECLib.java | 14 ++++ 9 files changed, 353 insertions(+), 14 deletions(-) create mode 100644 src/cz/crcs/ectester/standalone/consts/Ident.java create mode 100644 src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java create mode 100644 src/cz/crcs/ectester/standalone/consts/SignatureIdent.java create mode 100644 src/cz/crcs/ectester/standalone/libs/CECLibrary.java create mode 100644 src/cz/crcs/ectester/standalone/libs/ECLibrary.java create mode 100644 src/cz/crcs/ectester/standalone/libs/JavaECLibrary.java create mode 100644 src/cz/crcs/ectester/standalone/libs/SunECLib.java diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index d2cbce1..47b7121 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -1,12 +1,15 @@ package cz.crcs.ectester.standalone; -import cz.crcs.ectester.common.Util; import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.common.ec.EC_Curve; import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.standalone.libs.BouncyCastleLib; +import cz.crcs.ectester.standalone.libs.ECLibrary; +import cz.crcs.ectester.standalone.libs.SunECLib; import org.apache.commons.cli.*; import java.io.IOException; +import java.util.Arrays; /** * Standalone part of ECTester, a tool for testing Elliptic curve implementations in software libraries. @@ -16,6 +19,7 @@ import java.io.IOException; */ public class ECTesterStandalone { + private ECLibrary[] libs = new ECLibrary[]{new SunECLib(), new BouncyCastleLib()}; private EC_Store dataStore; private Config cfg; @@ -40,9 +44,17 @@ public class ECTesterStandalone { cfg = new Config(); dataStore = new EC_Store(); + for (ECLibrary lib : libs) { + lib.initialize(); + lib.getECKAs(); + lib.getECSigs(); + } + System.out.println(Arrays.toString(libs)); if (cli.hasOption("generate")) { generate(); + } else if (cli.hasOption("libs")) { + listLibraries(); } } catch (ParseException | IOException ex) { @@ -56,6 +68,7 @@ public class ECTesterStandalone { actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build()); + actions.addOption(Option.builder("ls").longOpt("libs").desc("List supported libraries.").build()); opts.addOptionGroup(actions); CommandLineParser parser = new DefaultParser(); @@ -88,6 +101,17 @@ public class ECTesterStandalone { } + /** + * + */ + private void listLibraries() { + for (ECLibrary lib : libs) { + if (lib.isInitialized()) { + System.out.println(lib.name()); + } + } + } + public static void main(String[] args) { ECTesterStandalone app = new ECTesterStandalone(); app.run(args); diff --git a/src/cz/crcs/ectester/standalone/consts/Ident.java b/src/cz/crcs/ectester/standalone/consts/Ident.java new file mode 100644 index 0000000..3228c37 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/consts/Ident.java @@ -0,0 +1,41 @@ +package cz.crcs.ectester.standalone.consts; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; + +public abstract class Ident { + private Set idents; + + public Ident(String... names) { + this.idents = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + this.idents.addAll(Arrays.asList(names)); + } + + public Set getIdents() { + return Collections.unmodifiableSet(idents); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Ident)) { + return false; + } + Ident other = (Ident) obj; + return idents.equals(other.getIdents()); + } + + @Override + public int hashCode() { + return idents.hashCode() + 37; + } + + @Override + public String toString() { + return "(" + String.join("|", idents) + ")"; + } +} diff --git a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java new file mode 100644 index 0000000..9dc9797 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java @@ -0,0 +1,53 @@ +package cz.crcs.ectester.standalone.consts; + +import java.util.LinkedList; +import java.util.List; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyAgreementIdent extends Ident { + private static final List ALL = new LinkedList<>(); + + static { + //https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html + // Basic ECDH and ECDHC (plain/raw) + ALL.add(new KeyAgreementIdent("ECDH")); + ALL.add(new KeyAgreementIdent("ECDHC", "ECCDH")); + // ECDH and ECDHC with SHA as KDF, OIDs from RFC 3278 + ALL.add(new KeyAgreementIdent("ECDHwithSHA1KDF", "1.3.133.16.840.63.0.2")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA1KDF", "1.3.133.16.840.63.0.3")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA224KDF", "1.3.132.1.11.0")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA224KDF", "1.3.132.1.14.0")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA256KDF", "1.3.132.1.11.1")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA256KDF", "1.3.132.1.14.1")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA384KDF", "1.3.132.1.11.2")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA384KDF", "1.3.132.1.14.2")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA512KDF", "1.3.132.1.11.3")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA512KDF", "1.3.132.1.14.3")); + // ECMQV + ALL.add(new KeyAgreementIdent("ECMQV")); + ALL.add(new KeyAgreementIdent("ECMQVwithSHA1CKDF", "1.3.133.16.840.63.0.16")); + ALL.add(new KeyAgreementIdent("ECMQVwithSHA224CKDF", "1.3.132.1.15.0")); + ALL.add(new KeyAgreementIdent("ECMQVwithSHA256CKDF", "1.3.132.1.15.1")); + ALL.add(new KeyAgreementIdent("ECMQVwithSHA384CKDF", "1.3.132.1.15.2")); + ALL.add(new KeyAgreementIdent("ECMQVwithSHA512CKDF", "1.3.132.1.15.3")); + // ECVKO + ALL.add(new KeyAgreementIdent("ECVKO", "ECGOST3410", "1.2.643.2.2.19", "GOST-3410-2001", "1.2.643.2.2.96")); + ALL.add(new KeyAgreementIdent("ECVKO256", "ECGOST3410-2012-256", "1.2.643.7.1.1.6.1", "1.2.643.7.1.1.1.1")); + ALL.add(new KeyAgreementIdent("ECVKO512", "ECGOST3410-2012-512", "1.2.643.7.1.1.6.2", "1.2.643.7.1.1.1.2")); + } + + public static KeyAgreementIdent get(String ident) { + for (KeyAgreementIdent ka : ALL) { + if (ka.getIdents().contains(ident)) { + return ka; + } + } + return null; + } + + private KeyAgreementIdent(String... names) { + super(names); + } +} diff --git a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java new file mode 100644 index 0000000..b41e9e4 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java @@ -0,0 +1,77 @@ +package cz.crcs.ectester.standalone.consts; + +import java.util.LinkedList; +import java.util.List; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SignatureIdent extends Ident { + private static final List ALL = new LinkedList<>(); + + static { + //https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html + // ECDSA + ALL.add(new SignatureIdent("ECDSA", "SHA1withECDSA", "ECDSAwithSHA1", "1.2.840.10045.4.1", "1.3.36.3.3.2.1")); + ALL.add(new SignatureIdent("NONEwithECDSA")); + ALL.add(new SignatureIdent("SHA224withECDSA", "SHA224/ECDSA", "1.2.840.10045.4.3.1")); + ALL.add(new SignatureIdent("SHA256withECDSA", "SHA256/ECDSA", "1.2.840.10045.4.3.2")); + ALL.add(new SignatureIdent("SHA384withECDSA", "SHA384/ECDSA", "1.2.840.10045.4.3.3")); + ALL.add(new SignatureIdent("SHA512withECDSA", "SHA512/ECDSA", "1.2.840.10045.4.3.4")); + ALL.add(new SignatureIdent("SHA3-224withECDSA", "SHA3-224/ECDSA", "2.16.840.1.101.3.4.3.9")); + ALL.add(new SignatureIdent("SHA3-256withECDSA", "SHA3-256/ECDSA", "2.16.840.1.101.3.4.3.10")); + ALL.add(new SignatureIdent("SHA3-384withECDSA", "SHA3-384/ECDSA", "2.16.840.1.101.3.4.3.11")); + ALL.add(new SignatureIdent("SHA3-512withECDSA", "SHA3-512/ECDSA", "2.16.840.1.101.3.4.3.12")); + ALL.add(new SignatureIdent("RIPEMD160withECDSA", "RIPEMD160/ECDSA", "1.3.36.3.3.2.2")); + // ECNR + ALL.add(new SignatureIdent("SHA1withECNR")); + ALL.add(new SignatureIdent("SHA224withECNR")); + ALL.add(new SignatureIdent("SHA256withECNR")); + ALL.add(new SignatureIdent("SHA512withECNR")); + // CVC-ECDSA + ALL.add(new SignatureIdent("SHA1withCVC-ECDSA", "SHA1/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.1")); + ALL.add(new SignatureIdent("SHA224withCVC-ECDSA", "SHA224/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.2")); + ALL.add(new SignatureIdent("SHA256withCVC-ECDSA", "SHA256/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.3")); + ALL.add(new SignatureIdent("SHA384withCVC-ECDSA", "SHA384/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.4")); + ALL.add(new SignatureIdent("SHA512withCVC-ECDSA", "SHA512/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.5")); + // PLAIN-ECDSA + ALL.add(new SignatureIdent("SHA1withPLAIN-ECDSA", "SHA1/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.1")); + ALL.add(new SignatureIdent("SHA224withPLAIN-ECDSA", "SHA224/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.2")); + ALL.add(new SignatureIdent("SHA256withPLAIN-ECDSA", "SHA256/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.3")); + ALL.add(new SignatureIdent("SHA384withPLAIN-ECDSA", "SHA384/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.4")); + ALL.add(new SignatureIdent("SHA512withPLAIN-ECDSA", "SHA512/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.5")); + ALL.add(new SignatureIdent("RIPEMD160withPLAIN-ECDSA", "RIPEMD160/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.6")); + // ECGOST + ALL.add(new SignatureIdent("ECGOST3410", "ECGOST-3410", "GOST-3410-2001")); + ALL.add(new SignatureIdent("GOST3411withECGOST3410", "GOST3411/ECGOST3410", "1.2.643.2.2.3")); + ALL.add(new SignatureIdent("ECGOST3410-2012-256", "GOST-3410-2012-256")); + ALL.add(new SignatureIdent("GOST3411-2012-256withECGOST3410-2012-256", "GOST3411-2012-256/ECGOST3410-2012-2560", "1.2.643.7.1.1.3.2")); + ALL.add(new SignatureIdent("ECGOST3410-2012-512", "GOST-3410-2012-512")); + ALL.add(new SignatureIdent("GOST3411-2012-512withECGOST3410-2012-512", "GOST3411-2012-512/ECGOST3410-2012-5120", "1.2.643.7.1.1.3.3")); + ALL.add(new SignatureIdent("SM3withSM2")); + // ECDDSA + ALL.add(new SignatureIdent("ECDDSA", "DETECDSA", "ECDETDSA")); + ALL.add(new SignatureIdent("SHA1withECDDSA", "SHA1withDETECDSA")); + ALL.add(new SignatureIdent("SHA224withECDDSA", "SHA224withDETECDSA")); + ALL.add(new SignatureIdent("SHA256withECDDSA", "SHA256withDETECDSA")); + ALL.add(new SignatureIdent("SHA384withECDDSA", "SHA384withDETECDSA")); + ALL.add(new SignatureIdent("SHA512withECDDSA", "SHA512withDETECDSA")); + ALL.add(new SignatureIdent("SHA3-224withECDDSA", "SHA3-224withDETECDSA")); + ALL.add(new SignatureIdent("SHA3-256withECDDSA", "SHA3-256withDETECDSA")); + ALL.add(new SignatureIdent("SHA3-384withECDDSA", "SHA3-384withDETECDSA")); + ALL.add(new SignatureIdent("SHA3-512withECDDSA", "SHA3-512withDETECDSA")); + } + + public static SignatureIdent get(String ident) { + for (SignatureIdent sig : ALL) { + if (sig.getIdents().contains(ident)) { + return sig; + } + } + return null; + } + + private SignatureIdent(String... names) { + super(names); + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java b/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java index 78da737..73cd197 100644 --- a/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java +++ b/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java @@ -1,21 +1,14 @@ package cz.crcs.ectester.standalone.libs; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import java.security.Security; +import org.bouncycastle.jce.provider.BouncyCastleProvider; -public class BouncyCastleLib { +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class BouncyCastleLib extends JavaECLibrary { public BouncyCastleLib() { - - } - - public boolean setUp() { - try { - Security.addProvider(new BouncyCastleProvider()); - } catch (NullPointerException | SecurityException ignored) { - return false; - } - return true; + super(new BouncyCastleProvider()); } } diff --git a/src/cz/crcs/ectester/standalone/libs/CECLibrary.java b/src/cz/crcs/ectester/standalone/libs/CECLibrary.java new file mode 100644 index 0000000..82a4555 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/CECLibrary.java @@ -0,0 +1,31 @@ +package cz.crcs.ectester.standalone.libs; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class CECLibrary implements ECLibrary { + + private String resourcePath; + private String libname; + + public CECLibrary(String resourcePath, String libname) { + this.resourcePath = resourcePath; + this.libname = libname; + } + + @Override + public boolean initialize() { + // load the library here. + return false; + } + + @Override + public String name() { + return libname; + } + + @Override + public String toString() { + return name(); + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/ECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ECLibrary.java new file mode 100644 index 0000000..b2792bd --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/ECLibrary.java @@ -0,0 +1,21 @@ +package cz.crcs.ectester.standalone.libs; + +import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.SignatureIdent; + +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public interface ECLibrary { + boolean initialize(); + + boolean isInitialized(); + + Set getECKAs(); + + Set getECSigs(); + + String name(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/JavaECLibrary.java b/src/cz/crcs/ectester/standalone/libs/JavaECLibrary.java new file mode 100644 index 0000000..f8848da --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/JavaECLibrary.java @@ -0,0 +1,85 @@ +package cz.crcs.ectester.standalone.libs; + +import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.SignatureIdent; + +import java.security.Provider; +import java.security.Security; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class JavaECLibrary implements ECLibrary { + private Provider provider; + private boolean initialized; + + public JavaECLibrary(Provider provider) { + this.provider = provider; + this.initialized = false; + } + + @Override + public boolean initialize() { + try { + int result = Security.addProvider(provider); + if (result == -1) { + provider = Security.getProvider(provider.getName()); + } + initialized = true; + } catch (NullPointerException | SecurityException ignored) { + initialized = false; + } + return initialized; + } + + @Override + public boolean isInitialized() { + return initialized; + } + + @Override + public Set getECKAs() { + Set results = new HashSet<>(); + for (Provider.Service service : provider.getServices()) { + if (service.getType().equals("KeyAgreement")) { + KeyAgreementIdent id = KeyAgreementIdent.get(service.getAlgorithm()); + if (id != null) { + results.add(id); + } + } + } + System.out.println(results); + return results; + } + + @Override + public Set getECSigs() { + Set results = new HashSet<>(); + for (Provider.Service service : provider.getServices()) { + if (service.getType().equals("Signature")) { + SignatureIdent id = SignatureIdent.get(service.getAlgorithm()); + if (id != null) { + results.add(id); + } + } + } + System.out.println(results); + return results; + } + + @Override + public String name() { + return provider.getInfo(); + } + + public Provider getProvider() { + return provider; + } + + @Override + public String toString() { + return name(); + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/SunECLib.java b/src/cz/crcs/ectester/standalone/libs/SunECLib.java new file mode 100644 index 0000000..408908e --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/SunECLib.java @@ -0,0 +1,14 @@ +package cz.crcs.ectester.standalone.libs; + +import sun.security.ec.SunEC; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SunECLib extends JavaECLibrary { + + public SunECLib() { + super(new SunEC()); + } + +} -- cgit v1.2.3-70-g09d2 From cccf2c9c382fa63c68a6c3821d587bc2caa72b05 Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 13 Nov 2017 18:03:00 +0100 Subject: Add KeyAgreement/KeyGeneration/Signature tests. Implement KeyAgreementTest. --- src/cz/crcs/ectester/common/test/TestCallback.java | 11 +++ .../ectester/reader/output/TextTestWriter.java | 6 +- .../crcs/ectester/reader/output/XMLTestWriter.java | 6 +- .../ectester/reader/output/YAMLTestWriter.java | 6 +- src/cz/crcs/ectester/reader/test/CommandTest.java | 71 +++++++++++++++++++ .../ectester/reader/test/CompositeCurvesSuite.java | 10 +-- src/cz/crcs/ectester/reader/test/DefaultSuite.java | 8 +-- .../ectester/reader/test/InvalidCurvesSuite.java | 10 +-- src/cz/crcs/ectester/reader/test/SimpleTest.java | 71 ------------------- src/cz/crcs/ectester/reader/test/TestSuite.java | 22 +++--- .../crcs/ectester/reader/test/TestVectorSuite.java | 12 ++-- src/cz/crcs/ectester/standalone/consts/Ident.java | 13 +++- .../standalone/consts/KeyAgreementIdent.java | 11 ++- .../ectester/standalone/consts/SignatureIdent.java | 11 ++- .../ectester/standalone/test/KeyAgreementTest.java | 55 +++++++++++++++ .../standalone/test/KeyAgreementTestable.java | 80 ++++++++++++++++++++++ .../standalone/test/KeyGenerationTest.java | 19 +++++ .../ectester/standalone/test/SignatureTest.java | 19 +++++ 18 files changed, 323 insertions(+), 118 deletions(-) create mode 100644 src/cz/crcs/ectester/common/test/TestCallback.java create mode 100644 src/cz/crcs/ectester/reader/test/CommandTest.java delete mode 100644 src/cz/crcs/ectester/reader/test/SimpleTest.java create mode 100644 src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java create mode 100644 src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java create mode 100644 src/cz/crcs/ectester/standalone/test/KeyGenerationTest.java create mode 100644 src/cz/crcs/ectester/standalone/test/SignatureTest.java diff --git a/src/cz/crcs/ectester/common/test/TestCallback.java b/src/cz/crcs/ectester/common/test/TestCallback.java new file mode 100644 index 0000000..488e2f2 --- /dev/null +++ b/src/cz/crcs/ectester/common/test/TestCallback.java @@ -0,0 +1,11 @@ +package cz.crcs.ectester.common.test; + +import java.util.function.Function; + +/** + * + * @param + */ +public abstract class TestCallback implements Function { + +} diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java index 07b2a2f..dc285b5 100644 --- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java @@ -2,7 +2,7 @@ package cz.crcs.ectester.reader.output; import cz.crcs.ectester.common.test.CompoundTest; import cz.crcs.ectester.common.test.Test; -import cz.crcs.ectester.reader.test.SimpleTest; +import cz.crcs.ectester.reader.test.CommandTest; import cz.crcs.ectester.reader.test.TestSuite; import java.io.PrintStream; @@ -33,8 +33,8 @@ public class TextTestWriter implements TestWriter { } StringBuilder out = new StringBuilder(); - if (t instanceof SimpleTest) { - SimpleTest test = (SimpleTest) t; + if (t instanceof CommandTest) { + CommandTest test = (CommandTest) t; out.append(test.ok() ? "OK " : "NOK "); out.append("━ "); int width = BASE_WIDTH - (offset + out.length()); diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java index 24a308c..0a5155b 100644 --- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java @@ -5,7 +5,7 @@ import cz.crcs.ectester.common.Util; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.common.test.Test; -import cz.crcs.ectester.reader.test.SimpleTest; +import cz.crcs.ectester.reader.test.CommandTest; import cz.crcs.ectester.reader.test.TestSuite; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -91,8 +91,8 @@ public class XMLTestWriter implements TestWriter { private Element testElement(Test t) { Element testElem = doc.createElement("test"); - if (t instanceof SimpleTest) { - SimpleTest test = (SimpleTest) t; + if (t instanceof CommandTest) { + CommandTest test = (CommandTest) t; testElem.setAttribute("type", "simple"); testElem.appendChild(commandElement(test.getCommand())); testElem.appendChild(responseElement(test.getResponse())); diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java index c637a13..84f1eac 100644 --- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java @@ -5,7 +5,7 @@ import cz.crcs.ectester.common.Util; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.common.test.Test; -import cz.crcs.ectester.reader.test.SimpleTest; +import cz.crcs.ectester.reader.test.CommandTest; import cz.crcs.ectester.reader.test.TestSuite; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; @@ -66,8 +66,8 @@ public class YAMLTestWriter implements TestWriter { private Map testObject(Test t) { Map testObj = new HashMap<>(); - if (t instanceof SimpleTest) { - SimpleTest test = (SimpleTest) t; + if (t instanceof CommandTest) { + CommandTest test = (CommandTest) t; testObj.put("type", "simple"); testObj.put("command", commandObject(test.getCommand())); testObj.put("response", responseObject(test.getResponse())); diff --git a/src/cz/crcs/ectester/reader/test/CommandTest.java b/src/cz/crcs/ectester/reader/test/CommandTest.java new file mode 100644 index 0000000..b7728b6 --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CommandTest.java @@ -0,0 +1,71 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.reader.command.Command; +import cz.crcs.ectester.reader.response.Response; + +import javax.smartcardio.CardException; +import java.util.function.BiFunction; + +/** + * A simple test that runs one Command to get and evaluate one Response + * to get a Result and compare it with the expected one. + */ +public class CommandTest extends Test { + private BiFunction callback; + private Command command; + private Response response; + + public CommandTest(Command command, BiFunction callback) { + this.command = command; + this.callback = callback; + } + + public CommandTest(Command command, Result.ExpectedValue expected, String ok, String nok) { + this(command, (cmd, resp) -> { + Result.Value resultValue = Result.Value.fromExpected(expected, resp.successful(), resp.error()); + return new Result(resultValue, resultValue.ok() ? ok : nok); + }); + } + + public CommandTest(Command command, Result.ExpectedValue expected) { + this(command, expected, null, null); + } + + public Command getCommand() { + return command; + } + + public Response getResponse() { + return response; + } + + @Override + public void run() throws TestException { + if (hasRun) + return; + + try { + response = command.send(); + } catch (CardException e) { + throw new TestException(e); + } + if (callback != null) { + result = callback.apply(command, response); + } else { + if (response.successful()) { + result = new Result(Result.Value.SUCCESS); + } else { + result = new Result(Result.Value.FAILURE); + } + } + hasRun = true; + } + + @Override + public String getDescription() { + return response.getDescription(); + } +} diff --git a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java index 2e711a2..77df7d6 100644 --- a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java @@ -41,12 +41,12 @@ public class CompositeCurvesSuite extends TestSuite { continue; } if ((curve.getBits() == cfg.bits || cfg.all)) { - tests.add(new SimpleTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); - tests.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY)); - tests.add(new SimpleTest(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY)); + tests.add(new CommandTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + tests.add(new CommandTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY)); + tests.add(new CommandTest(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY)); Command ecdhCommand = new Command.ECDH_direct(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH, key.flatten()); - tests.add(new SimpleTest(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key.")); - tests.add(new SimpleTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); + tests.add(new CommandTest(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key.")); + tests.add(new CommandTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); } } } diff --git a/src/cz/crcs/ectester/reader/test/DefaultSuite.java b/src/cz/crcs/ectester/reader/test/DefaultSuite.java index fb8fdab..0e25312 100644 --- a/src/cz/crcs/ectester/reader/test/DefaultSuite.java +++ b/src/cz/crcs/ectester/reader/test/DefaultSuite.java @@ -23,7 +23,7 @@ public class DefaultSuite extends TestSuite { @Override public void setup(CardMngr cardManager) throws IOException { - tests.add(new SimpleTest(new Command.Support(cardManager), ExpectedValue.ANY)); + tests.add(new CommandTest(new Command.Support(cardManager), ExpectedValue.ANY)); if (cfg.namedCurve != null) { String desc = "Default tests over the " + cfg.namedCurve + " curve category."; if (cfg.primeField) { @@ -59,11 +59,11 @@ public class DefaultSuite extends TestSuite { } private void defaultTests(CardMngr cardManager, short keyLength, byte keyType) throws IOException { - tests.add(new SimpleTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType), ExpectedValue.SUCCESS)); + tests.add(new CommandTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType), ExpectedValue.SUCCESS)); Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType); if (curve != null) - tests.add(new SimpleTest(curve, ExpectedValue.SUCCESS)); + tests.add(new CommandTest(curve, ExpectedValue.SUCCESS)); tests.add(defaultCurveTests(cardManager, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, "Default tests.")); - tests.add(new SimpleTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); + tests.add(new CommandTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); } } diff --git a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java b/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java index 1f71ad5..e4afb5d 100644 --- a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java @@ -55,16 +55,16 @@ public class InvalidCurvesSuite extends TestSuite { EC_Curve curve = e.getKey(); List keys = e.getValue(); - tests.add(new SimpleTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); - tests.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); - tests.add(new SimpleTest(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS)); + tests.add(new CommandTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + tests.add(new CommandTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); + tests.add(new CommandTest(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS)); List ecdhTests = new LinkedList<>(); for (EC_Key.Public pub : keys) { Command ecdhCommand = new Command.ECDH_direct(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ANY, pub.flatten()); - ecdhTests.add(new SimpleTest(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve." , "Card incorrectly accepted point on invalid curve.")); + ecdhTests.add(new CommandTest(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve." , "Card incorrectly accepted point on invalid curve.")); } tests.add(CompoundTest.all(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), ecdhTests.toArray(new Test[0]))); - tests.add(new SimpleTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); + tests.add(new CommandTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); } } } diff --git a/src/cz/crcs/ectester/reader/test/SimpleTest.java b/src/cz/crcs/ectester/reader/test/SimpleTest.java deleted file mode 100644 index 067f43e..0000000 --- a/src/cz/crcs/ectester/reader/test/SimpleTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package cz.crcs.ectester.reader.test; - -import cz.crcs.ectester.common.test.Result; -import cz.crcs.ectester.common.test.Test; -import cz.crcs.ectester.common.test.TestException; -import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.response.Response; - -import javax.smartcardio.CardException; -import java.util.function.BiFunction; - -/** - * A simple test that runs one Command to get and evaluate one Response - * to get a Result and compare it with the expected one. - */ -public class SimpleTest extends Test { - private BiFunction callback; - private Command command; - private Response response; - - public SimpleTest(Command command, BiFunction callback) { - this.command = command; - this.callback = callback; - } - - public SimpleTest(Command command, Result.ExpectedValue expected, String ok, String nok) { - this(command, (cmd, resp) -> { - Result.Value resultValue = Result.Value.fromExpected(expected, resp.successful(), resp.error()); - return new Result(resultValue, resultValue.ok() ? ok : nok); - }); - } - - public SimpleTest(Command command, Result.ExpectedValue expected) { - this(command, expected, null, null); - } - - public Command getCommand() { - return command; - } - - public Response getResponse() { - return response; - } - - @Override - public void run() throws TestException { - if (hasRun) - return; - - try { - response = command.send(); - } catch (CardException e) { - throw new TestException(e); - } - if (callback != null) { - result = callback.apply(command, response); - } else { - if (response.successful()) { - result = new Result(Result.Value.SUCCESS); - } else { - result = new Result(Result.Value.FAILURE); - } - } - hasRun = true; - } - - @Override - public String getDescription() { - return response.getDescription(); - } -} diff --git a/src/cz/crcs/ectester/reader/test/TestSuite.java b/src/cz/crcs/ectester/reader/test/TestSuite.java index dc8167b..034f579 100644 --- a/src/cz/crcs/ectester/reader/test/TestSuite.java +++ b/src/cz/crcs/ectester/reader/test/TestSuite.java @@ -64,14 +64,14 @@ public abstract class TestSuite { Test defaultCurveTests(CardMngr cardManager, ExpectedValue generateExpected, ExpectedValue ecdhExpected, ExpectedValue ecdhCompressExpected, ExpectedValue ecdsaExpected, String description) { List tests = new LinkedList<>(); - tests.add(new SimpleTest(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), generateExpected)); - tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH), ecdhExpected)); - tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_COMPRESS, EC_Consts.KA_ECDH), ecdhExpected)); - tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ONE, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ZERO, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_MAX, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_FULLRANDOM, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new SimpleTest(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, null), ecdsaExpected)); + tests.add(new CommandTest(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), generateExpected)); + tests.add(new CommandTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH), ecdhExpected)); + tests.add(new CommandTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_COMPRESS, EC_Consts.KA_ECDH), ecdhExpected)); + tests.add(new CommandTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ONE, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); + tests.add(new CommandTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ZERO, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); + tests.add(new CommandTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_MAX, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); + tests.add(new CommandTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_FULLRANDOM, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); + tests.add(new CommandTest(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, null), ecdsaExpected)); return CompoundTest.function((testArray) -> { Function shouldHave = (expected) -> { @@ -126,10 +126,10 @@ public abstract class TestSuite { for (Map.Entry entry : curves.entrySet()) { EC_Curve curve = entry.getValue(); if (curve.getField() == field && (curve.getBits() == cfg.bits || cfg.all)) { - tests.add(new SimpleTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), field), ExpectedValue.SUCCESS)); - tests.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), setExpected)); + tests.add(new CommandTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), field), ExpectedValue.SUCCESS)); + tests.add(new CommandTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), setExpected)); tests.add(defaultCurveTests(cardManager, generateExpected, ecdhExpected, ecdhCompressedExpected, ecdsaExpected, description)); - tests.add(new SimpleTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); + tests.add(new CommandTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); } } diff --git a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java index 3f11a79..77653d1 100644 --- a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java +++ b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java @@ -61,12 +61,12 @@ public class TestVectorSuite extends TestSuite { } List testVector = new LinkedList<>(); - testVector.add(new SimpleTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); - testVector.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); + testVector.add(new CommandTest(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + testVector.add(new CommandTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); //tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS)); - testVector.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS)); - testVector.add(new SimpleTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS)); - testVector.add(new SimpleTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getKA()), (command, response) -> { + testVector.add(new CommandTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS)); + testVector.add(new CommandTest(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS)); + testVector.add(new CommandTest(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getKA()), (command, response) -> { Response.ECDH dh = (Response.ECDH) response; if (!dh.successful()) return new Result(Value.FAILURE, "ECDH was unsuccessful."); @@ -79,7 +79,7 @@ public class TestVectorSuite extends TestSuite { return new Result(Value.SUCCESS); })); tests.add(CompoundTest.all(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0]))); - tests.add(new SimpleTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); + tests.add(new CommandTest(new Command.Cleanup(cardManager), ExpectedValue.ANY)); } } diff --git a/src/cz/crcs/ectester/standalone/consts/Ident.java b/src/cz/crcs/ectester/standalone/consts/Ident.java index 3228c37..eaea0e3 100644 --- a/src/cz/crcs/ectester/standalone/consts/Ident.java +++ b/src/cz/crcs/ectester/standalone/consts/Ident.java @@ -6,11 +6,18 @@ import java.util.Set; import java.util.TreeSet; public abstract class Ident { - private Set idents; + Set idents; + String name; - public Ident(String... names) { + public Ident(String name, String... aliases) { + this.name = name; this.idents = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); - this.idents.addAll(Arrays.asList(names)); + this.idents.add(name); + this.idents.addAll(Arrays.asList(aliases)); + } + + public String getName() { + return name; } public Set getIdents() { diff --git a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java index 9dc9797..22b03a4 100644 --- a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java +++ b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java @@ -1,5 +1,8 @@ package cz.crcs.ectester.standalone.consts; +import javax.crypto.KeyAgreement; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; import java.util.LinkedList; import java.util.List; @@ -47,7 +50,11 @@ public class KeyAgreementIdent extends Ident { return null; } - private KeyAgreementIdent(String... names) { - super(names); + private KeyAgreementIdent(String name, String... aliases) { + super(name, aliases); + } + + public KeyAgreement getInstance(Provider provider) throws NoSuchAlgorithmException { + return KeyAgreement.getInstance(name, provider); } } diff --git a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java index b41e9e4..dc554e2 100644 --- a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java +++ b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java @@ -1,5 +1,8 @@ package cz.crcs.ectester.standalone.consts; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Signature; import java.util.LinkedList; import java.util.List; @@ -71,7 +74,11 @@ public class SignatureIdent extends Ident { return null; } - private SignatureIdent(String... names) { - super(names); + private SignatureIdent(String name, String... aliases) { + super(name, aliases); + } + + public Signature getInstance(Provider provider) throws NoSuchAlgorithmException { + return Signature.getInstance(name, provider); } } diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java new file mode 100644 index 0000000..9c761fa --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java @@ -0,0 +1,55 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestCallback; +import cz.crcs.ectester.common.test.TestException; + +import java.util.Arrays; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyAgreementTest extends Test { + private KeyAgreementTestable ka; + private TestCallback callback; + + private KeyAgreementTest(KeyAgreementTestable ka, TestCallback callback) { + this.ka = ka; + this.callback = callback; + } + + public static KeyAgreementTest match(KeyAgreementTestable ka, byte[] expectedSecret) { + return new KeyAgreementTest(ka, new TestCallback() { + @Override + public Result apply(KeyAgreementTestable ka) { + if (Arrays.equals(ka.getSecret(), expectedSecret)) { + return new Result(Result.Value.SUCCESS); + } else { + return new Result(Result.Value.FAILURE); + } + } + }); + } + + public static KeyAgreementTest expect(KeyAgreementTestable ka, Result.ExpectedValue expected) { + return new KeyAgreementTest(ka, new TestCallback() { + @Override + public Result apply(KeyAgreementTestable keyAgreementTestable) { + return new Result(Result.Value.fromExpected(expected, keyAgreementTestable.ok(), keyAgreementTestable.error())); + } + }); + } + + @Override + public String getDescription() { + return null; + } + + @Override + public void run() throws TestException { + ka.run(); + result = callback.apply(ka); + hasRun = true; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java new file mode 100644 index 0000000..51c295c --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java @@ -0,0 +1,80 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.common.test.Testable; + +import javax.crypto.KeyAgreement; +import java.security.InvalidKeyException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyAgreementTestable implements Testable { + private KeyAgreement ka; + private ECPrivateKey privateKey; + private ECPublicKey publicKey; + private byte[] secret; + private boolean hasRun; + private boolean error; + private boolean ok; + + public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey) { + this.ka = ka; + this.privateKey = privateKey; + this.publicKey = publicKey; + } + + public byte[] getSecret() { + if (!hasRun) { + return null; + } + return secret; + } + + @Override + public boolean hasRun() { + return hasRun; + } + + @Override + public void run() throws TestException { + try { + ka.init(privateKey); + } catch (InvalidKeyException ikex) { + throw new TestException(ikex); + } + + try { + ka.doPhase(publicKey, true); + } catch (InvalidKeyException ikex) { + throw new TestException(ikex); + } catch (IllegalStateException isex) { + error = true; + ok = false; + hasRun = true; + return; + } + + try { + secret = ka.generateSecret(); + } catch (IllegalStateException isex) { + error = true; + ok = false; + hasRun = true; + return; + } + ok = true; + } + + @Override + public boolean ok() { + return ok; + } + + @Override + public boolean error() { + return error; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/KeyGenerationTest.java b/src/cz/crcs/ectester/standalone/test/KeyGenerationTest.java new file mode 100644 index 0000000..7a96ba1 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/KeyGenerationTest.java @@ -0,0 +1,19 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestException; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyGenerationTest extends Test { + @Override + public String getDescription() { + return null; + } + + @Override + public void run() throws TestException { + + } +} diff --git a/src/cz/crcs/ectester/standalone/test/SignatureTest.java b/src/cz/crcs/ectester/standalone/test/SignatureTest.java new file mode 100644 index 0000000..2102db0 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/SignatureTest.java @@ -0,0 +1,19 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestException; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SignatureTest extends Test { + @Override + public String getDescription() { + return null; + } + + @Override + public void run() throws TestException { + + } +} -- cgit v1.2.3-70-g09d2 From 35bdac1fff6e98485d5fbef870d6438fdbbd00c3 Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 13 Nov 2017 22:49:41 +0100 Subject: Implement basic lib tests. --- .../ectester/standalone/test/KeyAgreementTest.java | 4 + .../standalone/test/KeyAgreementTestable.java | 5 +- .../standalone/test/KeyGenerationTest.java | 27 +++++- .../standalone/test/KeyGenerationTestable.java | 67 ++++++++++++++ .../ectester/standalone/test/SignatureTest.java | 13 ++- .../standalone/test/SignatureTestable.java | 102 +++++++++++++++++++++ 6 files changed, 213 insertions(+), 5 deletions(-) create mode 100644 src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java create mode 100644 src/cz/crcs/ectester/standalone/test/SignatureTestable.java diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java index 9c761fa..a24346e 100644 --- a/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java +++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java @@ -41,6 +41,10 @@ public class KeyAgreementTest extends Test { }); } + public static KeyAgreementTest function(KeyAgreementTestable ka, TestCallback callback) { + return new KeyAgreementTest(ka, callback); + } + @Override public String getDescription() { return null; diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java index 51c295c..ef363c3 100644 --- a/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java +++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java @@ -17,7 +17,7 @@ public class KeyAgreementTestable implements Testable { private ECPublicKey publicKey; private byte[] secret; private boolean hasRun; - private boolean error; + private boolean error = false; private boolean ok; public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey) { @@ -51,7 +51,6 @@ public class KeyAgreementTestable implements Testable { } catch (InvalidKeyException ikex) { throw new TestException(ikex); } catch (IllegalStateException isex) { - error = true; ok = false; hasRun = true; return; @@ -60,12 +59,12 @@ public class KeyAgreementTestable implements Testable { try { secret = ka.generateSecret(); } catch (IllegalStateException isex) { - error = true; ok = false; hasRun = true; return; } ok = true; + hasRun = true; } @Override diff --git a/src/cz/crcs/ectester/standalone/test/KeyGenerationTest.java b/src/cz/crcs/ectester/standalone/test/KeyGenerationTest.java index 7a96ba1..0ec4741 100644 --- a/src/cz/crcs/ectester/standalone/test/KeyGenerationTest.java +++ b/src/cz/crcs/ectester/standalone/test/KeyGenerationTest.java @@ -1,12 +1,35 @@ package cz.crcs.ectester.standalone.test; +import cz.crcs.ectester.common.test.Result; import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestCallback; import cz.crcs.ectester.common.test.TestException; /** * @author Jan Jancar johny@neuromancer.sk */ public class KeyGenerationTest extends Test { + private KeyGenerationTestable kg; + private TestCallback callback; + + private KeyGenerationTest(KeyGenerationTestable kg, TestCallback callback) { + this.kg = kg; + this.callback = callback; + } + + public static KeyGenerationTest expect(KeyGenerationTestable kg, Result.ExpectedValue expected) { + return new KeyGenerationTest(kg, new TestCallback() { + @Override + public Result apply(KeyGenerationTestable keyGenerationTestable) { + return new Result(Result.Value.fromExpected(expected, keyGenerationTestable.ok(), keyGenerationTestable.error())); + } + }); + } + + public static KeyGenerationTest function(KeyGenerationTestable ka, TestCallback callback) { + return new KeyGenerationTest(ka, callback); + } + @Override public String getDescription() { return null; @@ -14,6 +37,8 @@ public class KeyGenerationTest extends Test { @Override public void run() throws TestException { - + kg.run(); + result = callback.apply(kg); + hasRun = true; } } diff --git a/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java b/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java new file mode 100644 index 0000000..10d02cb --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java @@ -0,0 +1,67 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.common.test.Testable; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.spec.AlgorithmParameterSpec; + +public class KeyGenerationTestable implements Testable { + + private KeyPair kp; + private KeyPairGenerator kpg; + private int keysize; + private AlgorithmParameterSpec spec; + private boolean hasRun; + private boolean error = false; + private boolean ok; + + public KeyGenerationTestable(KeyPairGenerator kpg, int keysize) { + this.kpg = kpg; + this.keysize = keysize; + } + + public KeyGenerationTestable(KeyPairGenerator kpg, AlgorithmParameterSpec spec) { + this.kpg = kpg; + this.spec = spec; + } + + public KeyPair getKeyPair() { + return kp; + } + + @Override + public boolean hasRun() { + return hasRun; + } + + @Override + public void run() throws TestException { + try { + if (spec != null) { + kpg.initialize(spec); + } else { + kpg.initialize(keysize); + } + } catch (InvalidAlgorithmParameterException e) { + hasRun = true; + ok = false; + return; + } + kp = kpg.genKeyPair(); + hasRun = true; + ok = true; + } + + @Override + public boolean ok() { + return ok; + } + + @Override + public boolean error() { + return error; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/SignatureTest.java b/src/cz/crcs/ectester/standalone/test/SignatureTest.java index 2102db0..828b84f 100644 --- a/src/cz/crcs/ectester/standalone/test/SignatureTest.java +++ b/src/cz/crcs/ectester/standalone/test/SignatureTest.java @@ -1,12 +1,21 @@ package cz.crcs.ectester.standalone.test; import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestCallback; import cz.crcs.ectester.common.test.TestException; /** * @author Jan Jancar johny@neuromancer.sk */ public class SignatureTest extends Test { + private SignatureTestable sig; + private TestCallback callback; + + private SignatureTest(SignatureTestable sig, TestCallback callback) { + this.sig = sig; + this.callback = callback; + } + @Override public String getDescription() { return null; @@ -14,6 +23,8 @@ public class SignatureTest extends Test { @Override public void run() throws TestException { - + sig.run(); + result = callback.apply(sig); + hasRun = true; } } diff --git a/src/cz/crcs/ectester/standalone/test/SignatureTestable.java b/src/cz/crcs/ectester/standalone/test/SignatureTestable.java new file mode 100644 index 0000000..5f58b4a --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/SignatureTestable.java @@ -0,0 +1,102 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.common.test.Testable; + +import java.security.InvalidKeyException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; + +public class SignatureTestable implements Testable { + + private Signature sig; + private ECPrivateKey signKey; + private ECPublicKey verifyKey; + private byte[] data; + private byte[] signature; + private boolean verified; + + private boolean hasRun; + private boolean error; + private boolean ok; + + public SignatureTestable(Signature sig, ECPrivateKey signKey, ECPublicKey verifyKey, byte[] data) { + this.sig = sig; + this.signKey = signKey; + this.verifyKey = verifyKey; + this.data = data; + } + + public byte[] getSignature() { + return signature; + } + + public boolean getVerified() { + return verified; + } + + @Override + public boolean hasRun() { + return hasRun; + } + + @Override + public void run() throws TestException { + try { + sig.initSign(signKey); + } catch (InvalidKeyException e) { + throw new TestException(e); + } + + try { + sig.update(data); + } catch (SignatureException e) { + ok = false; + hasRun = true; + return; + } + + try { + signature = sig.sign(); + } catch (SignatureException e) { + ok = false; + hasRun = true; + return; + } + + try { + sig.initVerify(verifyKey); + } catch (InvalidKeyException e) { + throw new TestException(e); + } + + try { + sig.update(data); + } catch (SignatureException e) { + ok = false; + hasRun = true; + return; + } + + try { + verified = sig.verify(signature); + } catch (SignatureException e) { + ok = false; + hasRun = true; + } + ok = true; + hasRun = true; + } + + @Override + public boolean ok() { + return ok; + } + + @Override + public boolean error() { + return error; + } +} -- cgit v1.2.3-70-g09d2 From 80e14c7d3f9eeec34f0236bfb8c595033142756a Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 13 Nov 2017 23:18:35 +0100 Subject: Add KeyPairGenerator idents. --- .../ectester/standalone/ECTesterStandalone.java | 25 +++++++++++++-- .../standalone/consts/KeyPairGeneratorIdent.java | 36 ++++++++++++++++++++++ .../crcs/ectester/standalone/libs/ECLibrary.java | 3 ++ .../ectester/standalone/libs/JavaECLibrary.java | 35 +++++++++++---------- 4 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 47b7121..016d095 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -3,12 +3,17 @@ package cz.crcs.ectester.standalone; import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.common.ec.EC_Curve; import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; import cz.crcs.ectester.standalone.libs.BouncyCastleLib; import cz.crcs.ectester.standalone.libs.ECLibrary; +import cz.crcs.ectester.standalone.libs.JavaECLibrary; import cz.crcs.ectester.standalone.libs.SunECLib; import org.apache.commons.cli.*; import java.io.IOException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; import java.util.Arrays; /** @@ -45,9 +50,23 @@ public class ECTesterStandalone { cfg = new Config(); dataStore = new EC_Store(); for (ECLibrary lib : libs) { - lib.initialize(); - lib.getECKAs(); - lib.getECSigs(); + if (lib instanceof JavaECLibrary) { + JavaECLibrary jlib = (JavaECLibrary) lib; + lib.initialize(); + lib.getECKAs(); + lib.getECSigs(); + for (KeyPairGeneratorIdent ident : lib.getKPGs()) { + try { + KeyPairGenerator kpg = ident.getInstance(jlib.getProvider()); + kpg.initialize(192); + KeyPair kp = kpg.genKeyPair(); + System.out.println(kp); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + } + } System.out.println(Arrays.toString(libs)); diff --git a/src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java b/src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java new file mode 100644 index 0000000..f806282 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java @@ -0,0 +1,36 @@ +package cz.crcs.ectester.standalone.consts; + +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.util.LinkedList; +import java.util.List; + +public class KeyPairGeneratorIdent extends Ident { + private static final List ALL = new LinkedList<>(); + + static { + ALL.add(new KeyPairGeneratorIdent("EC")); + ALL.add(new KeyPairGeneratorIdent("ECDH")); + ALL.add(new KeyPairGeneratorIdent("ECDSA")); + ALL.add(new KeyPairGeneratorIdent("ECDHC")); + ALL.add(new KeyPairGeneratorIdent("ECMQV")); + } + + public static KeyPairGeneratorIdent get(String ident) { + for (KeyPairGeneratorIdent kg : ALL) { + if (kg.getIdents().contains(ident)) { + return kg; + } + } + return null; + } + + public KeyPairGeneratorIdent(String name, String... aliases) { + super(name, aliases); + } + + public KeyPairGenerator getInstance(Provider provider) throws NoSuchAlgorithmException { + return KeyPairGenerator.getInstance(name, provider); + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/ECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ECLibrary.java index b2792bd..7e26dbe 100644 --- a/src/cz/crcs/ectester/standalone/libs/ECLibrary.java +++ b/src/cz/crcs/ectester/standalone/libs/ECLibrary.java @@ -1,6 +1,7 @@ package cz.crcs.ectester.standalone.libs; import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; import cz.crcs.ectester.standalone.consts.SignatureIdent; import java.util.Set; @@ -17,5 +18,7 @@ public interface ECLibrary { Set getECSigs(); + Set getKPGs(); + String name(); } diff --git a/src/cz/crcs/ectester/standalone/libs/JavaECLibrary.java b/src/cz/crcs/ectester/standalone/libs/JavaECLibrary.java index f8848da..5689b2b 100644 --- a/src/cz/crcs/ectester/standalone/libs/JavaECLibrary.java +++ b/src/cz/crcs/ectester/standalone/libs/JavaECLibrary.java @@ -1,12 +1,15 @@ package cz.crcs.ectester.standalone.libs; +import cz.crcs.ectester.standalone.consts.Ident; import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; import cz.crcs.ectester.standalone.consts.SignatureIdent; import java.security.Provider; import java.security.Security; import java.util.HashSet; import java.util.Set; +import java.util.function.Function; /** * @author Jan Jancar johny@neuromancer.sk @@ -39,34 +42,32 @@ public abstract class JavaECLibrary implements ECLibrary { return initialized; } - @Override - public Set getECKAs() { - Set results = new HashSet<>(); + private Set getIdents(String type, Function getter) { + Set results = new HashSet<>(); for (Provider.Service service : provider.getServices()) { - if (service.getType().equals("KeyAgreement")) { - KeyAgreementIdent id = KeyAgreementIdent.get(service.getAlgorithm()); + if (service.getType().equals(type)) { + T id = getter.apply(service.getAlgorithm()); if (id != null) { results.add(id); } } } - System.out.println(results); return results; } + @Override + public Set getECKAs() { + return getIdents("KeyAgreement", KeyAgreementIdent::get); + } + @Override public Set getECSigs() { - Set results = new HashSet<>(); - for (Provider.Service service : provider.getServices()) { - if (service.getType().equals("Signature")) { - SignatureIdent id = SignatureIdent.get(service.getAlgorithm()); - if (id != null) { - results.add(id); - } - } - } - System.out.println(results); - return results; + return getIdents("Signature", SignatureIdent::get); + } + + @Override + public Set getKPGs() { + return getIdents("KeyPairGenerator", KeyPairGeneratorIdent::get); } @Override -- cgit v1.2.3-70-g09d2 From 82a0399051d3bc059deb6923512092b31971d352 Mon Sep 17 00:00:00 2001 From: J08nY Date: Tue, 14 Nov 2017 03:04:10 +0100 Subject: Extract common CLI methods to CLITools. --- src/cz/crcs/ectester/common/CLITools.java | 56 ++++++++++++++++++++++ src/cz/crcs/ectester/reader/ECTesterReader.java | 41 ++-------------- .../ectester/standalone/ECTesterStandalone.java | 38 +++++++-------- .../standalone/test/KeyGenerationTestable.java | 6 +-- 4 files changed, 80 insertions(+), 61 deletions(-) create mode 100644 src/cz/crcs/ectester/common/CLITools.java diff --git a/src/cz/crcs/ectester/common/CLITools.java b/src/cz/crcs/ectester/common/CLITools.java new file mode 100644 index 0000000..57cea64 --- /dev/null +++ b/src/cz/crcs/ectester/common/CLITools.java @@ -0,0 +1,56 @@ +package cz.crcs.ectester.common; + +import cz.crcs.ectester.common.ec.EC_Category; +import cz.crcs.ectester.common.ec.EC_Data; +import cz.crcs.ectester.data.EC_Store; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; + +import java.util.Map; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CLITools { + + /** + * Print help. + */ + public static void help(String prog, String header, Options options, String footer, boolean usage) { + HelpFormatter help = new HelpFormatter(); + help.setOptionComparator(null); + help.printHelp(prog, header, options, footer, usage); + } + + /** + * Print version info. + */ + public static void version(String description, String license) { + System.out.println(description); + System.out.println(license); + } + + /** + * List categories and named curves. + */ + public static void listNamed(EC_Store dataStore, String named) { + Map categories = dataStore.getCategories(); + if (named == null) { + // print all categories, briefly + for (EC_Category cat : categories.values()) { + System.out.println(cat); + } + } else if (categories.containsKey(named)) { + // print given category + System.out.println(categories.get(named)); + } else { + // print given object + EC_Data object = dataStore.getObject(EC_Data.class, named); + if (object != null) { + System.out.println(object); + } else { + System.err.println("Named object " + named + " not found!"); + } + } + } +} diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 0bbe8f7..c51430d 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -23,6 +23,7 @@ package cz.crcs.ectester.reader; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.CLITools; import cz.crcs.ectester.common.Util; import cz.crcs.ectester.common.ec.EC_Category; import cz.crcs.ectester.common.ec.EC_Data; @@ -79,11 +80,10 @@ public class ECTesterReader { //if help, print and quit if (cli.hasOption("help")) { - help(); + CLITools.help("ECTesterReader.jar", CLI_HEADER, opts, CLI_FOOTER, true); return; } else if (cli.hasOption("version")) { - System.out.println(DESCRIPTION); - System.out.println(LICENSE); + CLITools.version(DESCRIPTION, LICENSE); return; } cfg = new Config(); @@ -96,7 +96,7 @@ public class ECTesterReader { dataStore = new EC_Store(); //if list, print and quit if (cli.hasOption("list-named")) { - list(); + CLITools.listNamed(dataStore, cli.getOptionValue("list-named")); return; } @@ -311,39 +311,6 @@ public class ECTesterReader { return parser.parse(opts, args); } - /** - * Prints help. - */ - private void help() { - HelpFormatter help = new HelpFormatter(); - help.setOptionComparator(null); - help.printHelp("ECTesterReader.jar", CLI_HEADER, opts, CLI_FOOTER, true); - } - - /** - * List categories and named curves. - */ - private void list() { - Map categories = dataStore.getCategories(); - if (cfg.listNamed == null) { - // print all categories, briefly - for (EC_Category cat : categories.values()) { - System.out.println(cat); - } - } else if (categories.containsKey(cfg.listNamed)) { - // print given category - System.out.println(categories.get(cfg.listNamed)); - } else { - // print given object - EC_Data object = dataStore.getObject(EC_Data.class, cfg.listNamed); - if (object != null) { - System.out.println(object); - } else { - System.err.println("Named object " + cfg.listNamed + " not found!"); - } - } - } - /** * Exports default card/simulation EC domain parameters to output file. * diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 016d095..e8998ff 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -1,6 +1,7 @@ package cz.crcs.ectester.standalone; import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.CLITools; import cz.crcs.ectester.common.ec.EC_Curve; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; @@ -40,15 +41,21 @@ public class ECTesterStandalone { CommandLine cli = parseArgs(args); if (cli.hasOption("help")) { - help(); + CLITools.help("ECTesterStandalone.jar", CLI_HEADER, opts, CLI_FOOTER, true); return; } else if (cli.hasOption("version")) { - version(); + CLITools.version(DESCRIPTION, LICENSE); return; } cfg = new Config(); dataStore = new EC_Store(); + + if (cli.hasOption("list-named")) { + CLITools.listNamed(dataStore, cli.getOptionValue("list-named")); + return; + } + for (ECLibrary lib : libs) { if (lib instanceof JavaECLibrary) { JavaECLibrary jlib = (JavaECLibrary) lib; @@ -72,7 +79,7 @@ public class ECTesterStandalone { if (cli.hasOption("generate")) { generate(); - } else if (cli.hasOption("libs")) { + } else if (cli.hasOption("list-libs")) { listLibraries(); } @@ -86,31 +93,20 @@ public class ECTesterStandalone { actions.setRequired(true); actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); + actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build()); actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build()); - actions.addOption(Option.builder("ls").longOpt("libs").desc("List supported libraries.").build()); + actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- wrong:\n- composite:\n- test-vectors:").hasArg().argName("test_suite").optionalArg(true).build()); + actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do ECDH, [count] times.").hasArg().argName("count").optionalArg(true).build()); + actions.addOption(Option.builder("dhc").longOpt("ecdhc").desc("Do ECDHC, [count] times.").hasArg().argName("count").optionalArg(true).build()); + actions.addOption(Option.builder("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build()); + actions.addOption(Option.builder("ln").longOpt("list-named").desc("Print the list of supported named curves and keys.").hasArg().argName("what").optionalArg(true).build()); + actions.addOption(Option.builder("ls").longOpt("list-libs").desc("List supported libraries.").build()); opts.addOptionGroup(actions); CommandLineParser parser = new DefaultParser(); return parser.parse(opts, args); } - /** - * Prints help. - */ - private void help() { - HelpFormatter help = new HelpFormatter(); - help.setOptionComparator(null); - help.printHelp("ECTesterStandalone.jar", CLI_HEADER, opts, CLI_FOOTER, true); - } - - /** - * Prints version info. - */ - private void version() { - System.out.println(DESCRIPTION); - System.out.println(LICENSE); - } - /** * */ diff --git a/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java b/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java index 10d02cb..8ad425b 100644 --- a/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java +++ b/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java @@ -6,14 +6,14 @@ import cz.crcs.ectester.common.test.Testable; import java.security.InvalidAlgorithmParameterException; import java.security.KeyPair; import java.security.KeyPairGenerator; -import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECParameterSpec; public class KeyGenerationTestable implements Testable { private KeyPair kp; private KeyPairGenerator kpg; private int keysize; - private AlgorithmParameterSpec spec; + private ECParameterSpec spec; private boolean hasRun; private boolean error = false; private boolean ok; @@ -23,7 +23,7 @@ public class KeyGenerationTestable implements Testable { this.keysize = keysize; } - public KeyGenerationTestable(KeyPairGenerator kpg, AlgorithmParameterSpec spec) { + public KeyGenerationTestable(KeyPairGenerator kpg, ECParameterSpec spec) { this.kpg = kpg; this.spec = spec; } -- cgit v1.2.3-70-g09d2 From 7758239163e6c81f985fa4e33ad1c0cb57627f0e Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 15 Nov 2017 01:00:13 +0100 Subject: Add Tree-like CLI parsing utilities. --- src/cz/crcs/ectester/common/CLITools.java | 56 --------- src/cz/crcs/ectester/common/cli/CLITools.java | 90 ++++++++++++++ src/cz/crcs/ectester/common/cli/ParserOptions.java | 25 ++++ .../crcs/ectester/common/cli/TreeCommandLine.java | 134 +++++++++++++++++++++ src/cz/crcs/ectester/common/cli/TreeParser.java | 75 ++++++++++++ src/cz/crcs/ectester/reader/ECTesterReader.java | 4 +- .../ectester/standalone/ECTesterStandalone.java | 5 +- 7 files changed, 327 insertions(+), 62 deletions(-) delete mode 100644 src/cz/crcs/ectester/common/CLITools.java create mode 100644 src/cz/crcs/ectester/common/cli/CLITools.java create mode 100644 src/cz/crcs/ectester/common/cli/ParserOptions.java create mode 100644 src/cz/crcs/ectester/common/cli/TreeCommandLine.java create mode 100644 src/cz/crcs/ectester/common/cli/TreeParser.java diff --git a/src/cz/crcs/ectester/common/CLITools.java b/src/cz/crcs/ectester/common/CLITools.java deleted file mode 100644 index 57cea64..0000000 --- a/src/cz/crcs/ectester/common/CLITools.java +++ /dev/null @@ -1,56 +0,0 @@ -package cz.crcs.ectester.common; - -import cz.crcs.ectester.common.ec.EC_Category; -import cz.crcs.ectester.common.ec.EC_Data; -import cz.crcs.ectester.data.EC_Store; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Options; - -import java.util.Map; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class CLITools { - - /** - * Print help. - */ - public static void help(String prog, String header, Options options, String footer, boolean usage) { - HelpFormatter help = new HelpFormatter(); - help.setOptionComparator(null); - help.printHelp(prog, header, options, footer, usage); - } - - /** - * Print version info. - */ - public static void version(String description, String license) { - System.out.println(description); - System.out.println(license); - } - - /** - * List categories and named curves. - */ - public static void listNamed(EC_Store dataStore, String named) { - Map categories = dataStore.getCategories(); - if (named == null) { - // print all categories, briefly - for (EC_Category cat : categories.values()) { - System.out.println(cat); - } - } else if (categories.containsKey(named)) { - // print given category - System.out.println(categories.get(named)); - } else { - // print given object - EC_Data object = dataStore.getObject(EC_Data.class, named); - if (object != null) { - System.out.println(object); - } else { - System.err.println("Named object " + named + " not found!"); - } - } - } -} diff --git a/src/cz/crcs/ectester/common/cli/CLITools.java b/src/cz/crcs/ectester/common/cli/CLITools.java new file mode 100644 index 0000000..8f34f62 --- /dev/null +++ b/src/cz/crcs/ectester/common/cli/CLITools.java @@ -0,0 +1,90 @@ +package cz.crcs.ectester.common.cli; + +import cz.crcs.ectester.common.ec.EC_Category; +import cz.crcs.ectester.common.ec.EC_Data; +import cz.crcs.ectester.data.EC_Store; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Map; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CLITools { + + /** + * Print help. + */ + public static void help(String prog, String header, Options options, String footer, boolean usage) { + HelpFormatter help = new HelpFormatter(); + help.setOptionComparator(null); + help.printHelp(prog, header, options, footer, usage); + } + + private static void help(HelpFormatter help, PrintWriter pw, CommandLineParser cli, int depth) { + if (cli instanceof TreeParser) { + TreeParser tp = (TreeParser) cli; + tp.getParsers().forEach((key, value) -> { + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + String.valueOf(depth) + "s" + key + ":", " ")); + help.printOptions(pw, HelpFormatter.DEFAULT_WIDTH, value.getOptions(), HelpFormatter.DEFAULT_LEFT_PAD + depth, HelpFormatter.DEFAULT_DESC_PAD); + pw.println(); + CLITools.help(help, pw, value.getParser(), depth + 1); + }); + } + } + + /** + * Print tree help. + */ + public static void help(String prog, String header, Options baseOpts, TreeParser baseParser, String footer, boolean usage) { + HelpFormatter help = new HelpFormatter(); + help.setOptionComparator(null); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + if (usage) { + help.printUsage(pw, HelpFormatter.DEFAULT_WIDTH, prog, baseOpts); + } + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, header); + help.printOptions(pw, HelpFormatter.DEFAULT_WIDTH, baseOpts, HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD); + pw.println(); + help(help, pw, baseParser, 1); + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, footer); + System.out.println(sw.toString()); + } + + /** + * Print version info. + */ + public static void version(String description, String license) { + System.out.println(description); + System.out.println(license); + } + + /** + * List categories and named curves. + */ + public static void listNamed(EC_Store dataStore, String named) { + Map categories = dataStore.getCategories(); + if (named == null) { + // print all categories, briefly + for (EC_Category cat : categories.values()) { + System.out.println(cat); + } + } else if (categories.containsKey(named)) { + // print given category + System.out.println(categories.get(named)); + } else { + // print given object + EC_Data object = dataStore.getObject(EC_Data.class, named); + if (object != null) { + System.out.println(object); + } else { + System.err.println("Named object " + named + " not found!"); + } + } + } +} diff --git a/src/cz/crcs/ectester/common/cli/ParserOptions.java b/src/cz/crcs/ectester/common/cli/ParserOptions.java new file mode 100644 index 0000000..4216ce3 --- /dev/null +++ b/src/cz/crcs/ectester/common/cli/ParserOptions.java @@ -0,0 +1,25 @@ +package cz.crcs.ectester.common.cli; + +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.Options; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class ParserOptions { + private CommandLineParser parser; + private Options options; + + public ParserOptions(CommandLineParser parser, Options options) { + this.parser = parser; + this.options = options; + } + + public CommandLineParser getParser() { + return parser; + } + + public Options getOptions() { + return options; + } +} diff --git a/src/cz/crcs/ectester/common/cli/TreeCommandLine.java b/src/cz/crcs/ectester/common/cli/TreeCommandLine.java new file mode 100644 index 0000000..ef6079e --- /dev/null +++ b/src/cz/crcs/ectester/common/cli/TreeCommandLine.java @@ -0,0 +1,134 @@ +package cz.crcs.ectester.common.cli; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.ParseException; + +import java.util.Iterator; +import java.util.Properties; +import java.util.function.BiFunction; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class TreeCommandLine extends CommandLine { + private String name = ""; + private TreeCommandLine next; + private CommandLine cli; + + public TreeCommandLine(CommandLine cli, TreeCommandLine next) { + this.cli = cli; + this.next = next; + } + + public TreeCommandLine(String name, CommandLine cli, TreeCommandLine next) { + this(cli, next); + this.name = name; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String getNextName() { + if (next != null) { + return next.getName(); + } + return null; + } + + public TreeCommandLine getNext() { + return next; + } + + public CommandLine getThis() { + return cli; + } + + private T getOption(String opt, BiFunction getter, T defaultValue) { + if (opt.contains(".")) { + String[] parts = opt.split(".", 2); + if (next != null && parts[0].equals(next.getName())) { + return getter.apply(next, parts[1]); + } + return defaultValue; + } + return getter.apply(cli, opt); + } + + @Override + public boolean hasOption(String opt) { + return getOption(opt, CommandLine::hasOption, false); + } + + @Override + public boolean hasOption(char opt) { + return cli.hasOption(opt); + } + + @Override + public Object getParsedOptionValue(String opt) throws ParseException { + if (opt.contains(".")) { + String[] parts = opt.split(".", 2); + if (next != null && parts[0].equals(next.getName())) { + return next.getParsedOptionValue(parts[1]); + } + return null; + } + return cli.getParsedOptionValue(opt); + } + + @Override + public Object getOptionObject(char opt) { + return cli.getOptionObject(opt); + } + + @Override + public String getOptionValue(String opt) { + return getOption(opt, CommandLine::getOptionValue, null); + } + + @Override + public String getOptionValue(char opt) { + return cli.getOptionValue(opt); + } + + @Override + public String[] getOptionValues(String opt) { + return getOption(opt, CommandLine::getOptionValues, null); + } + + @Override + public String[] getOptionValues(char opt) { + return cli.getOptionValues(opt); + } + + @Override + public String getOptionValue(String opt, String defaultValue) { + return getOption(opt, CommandLine::getOptionValue, defaultValue); + } + + @Override + public String getOptionValue(char opt, String defaultValue) { + return cli.getOptionValue(opt, defaultValue); + } + + @Override + public Properties getOptionProperties(String opt) { + return getOption(opt, CommandLine::getOptionProperties, new Properties()); + } + + @Override + public Iterator