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. --- src/cz/crcs/ectester/reader/CardMngr.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/cz/crcs/ectester/reader/CardMngr.java') 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.*; -- cgit v1.2.3-70-g09d2 From 83943c809c56c1856038b21fd91f50cc709310aa Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 26 Nov 2017 23:27:07 +0100 Subject: Split Util class into a package. --- src/cz/crcs/ectester/common/Util.java | 375 --------------------- src/cz/crcs/ectester/common/ec/EC_Curve.java | 54 ++- src/cz/crcs/ectester/common/ec/EC_Data.java | 31 +- src/cz/crcs/ectester/common/ec/EC_KAResult.java | 4 +- src/cz/crcs/ectester/common/ec/EC_Params.java | 24 +- src/cz/crcs/ectester/common/util/ByteUtil.java | 122 +++++++ src/cz/crcs/ectester/common/util/CardUtil.java | 255 ++++++++++++++ src/cz/crcs/ectester/reader/CardMngr.java | 16 +- src/cz/crcs/ectester/reader/ECTesterReader.java | 10 +- src/cz/crcs/ectester/reader/command/Command.java | 18 +- .../ectester/reader/output/ResponseWriter.java | 6 +- .../crcs/ectester/reader/output/XMLTestWriter.java | 6 +- .../ectester/reader/output/YAMLTestWriter.java | 6 +- src/cz/crcs/ectester/reader/response/Response.java | 15 +- .../crcs/ectester/reader/test/TestVectorSuite.java | 6 +- .../ectester/standalone/ECTesterStandalone.java | 21 +- .../standalone/test/KeyGenerationTestable.java | 10 +- 17 files changed, 528 insertions(+), 451 deletions(-) delete mode 100644 src/cz/crcs/ectester/common/Util.java create mode 100644 src/cz/crcs/ectester/common/util/ByteUtil.java create mode 100644 src/cz/crcs/ectester/common/util/CardUtil.java (limited to 'src/cz/crcs/ectester/reader/CardMngr.java') diff --git a/src/cz/crcs/ectester/common/Util.java b/src/cz/crcs/ectester/common/Util.java deleted file mode 100644 index 0136493..0000000 --- a/src/cz/crcs/ectester/common/Util.java +++ /dev/null @@ -1,375 +0,0 @@ -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_Curve.java b/src/cz/crcs/ectester/common/ec/EC_Curve.java index 478ce7d..19228dc 100644 --- a/src/cz/crcs/ectester/common/ec/EC_Curve.java +++ b/src/cz/crcs/ectester/common/ec/EC_Curve.java @@ -1,7 +1,7 @@ package cz.crcs.ectester.common.ec; import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.common.Util; +import cz.crcs.ectester.common.util.ByteUtil; import javacard.security.KeyPair; import java.math.BigInteger; @@ -60,10 +60,10 @@ public class EC_Curve extends EC_Params { field = new ECFieldFp(new BigInteger(1, getData(0))); } else { byte[][] fieldData = getParam(EC_Consts.PARAMETER_F2M); - int m = Util.getShort(fieldData[0], 0); - int e1 = Util.getShort(fieldData[1], 0); - int e2 = Util.getShort(fieldData[2], 0); - int e3 = Util.getShort(fieldData[3], 0); + int m = ByteUtil.getShort(fieldData[0], 0); + int e1 = ByteUtil.getShort(fieldData[1], 0); + int e2 = ByteUtil.getShort(fieldData[2], 0); + int e3 = ByteUtil.getShort(fieldData[3], 0); int[] powers = new int[]{e1, e2, e3}; field = new ECFieldF2m(m, powers); } @@ -80,8 +80,50 @@ public class EC_Curve extends EC_Params { BigInteger n = new BigInteger(1, getParam(EC_Consts.PARAMETER_R)[0]); - int h = Util.getShort(getParam(EC_Consts.PARAMETER_K)[0], 0); + int h = ByteUtil.getShort(getParam(EC_Consts.PARAMETER_K)[0], 0); return new ECParameterSpec(curve, generator, n, h); } + + public static EC_Curve fromSpec(ECParameterSpec spec) { + EllipticCurve curve = spec.getCurve(); + ECField field = curve.getField(); + + short bits = (short) field.getFieldSize(); + byte[][] params; + int paramIndex = 0; + byte fieldType; + if (field instanceof ECFieldFp) { + ECFieldFp primeField = (ECFieldFp) field; + params = new byte[5][]; + params[paramIndex++] = primeField.getP().toByteArray(); + fieldType = KeyPair.ALG_EC_FP; + } else if (field instanceof ECFieldF2m) { + ECFieldF2m binaryField = (ECFieldF2m) field; + params = new byte[8][]; + params[paramIndex] = new byte[2]; + ByteUtil.setShort(params[paramIndex++], 0, (short) binaryField.getM()); + int[] powers = binaryField.getMidTermsOfReductionPolynomial(); + for (int i = 0; i < 3; ++i) { + params[paramIndex] = new byte[2]; + ByteUtil.setShort(params[paramIndex++], 0, (short) powers[i]); + } + fieldType = KeyPair.ALG_EC_F2M; + } else { + throw new IllegalArgumentException("ECParameterSpec with an unknnown field."); + } + + ECPoint generator = spec.getGenerator(); + + params[paramIndex++] = generator.getAffineX().toByteArray(); + params[paramIndex++] = generator.getAffineY().toByteArray(); + + params[paramIndex++] = spec.getOrder().toByteArray(); + params[paramIndex] = new byte[2]; + ByteUtil.setShort(params[paramIndex], 0, (short) spec.getCofactor()); + + EC_Curve result = new EC_Curve(bits, fieldType); + result.readByteArray(params); + return result; + } } diff --git a/src/cz/crcs/ectester/common/ec/EC_Data.java b/src/cz/crcs/ectester/common/ec/EC_Data.java index acd282a..c048ef7 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.common.Util; +import cz.crcs.ectester.common.util.ByteUtil; import java.io.*; import java.util.*; @@ -8,9 +8,10 @@ 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 { @@ -67,7 +68,7 @@ public abstract class EC_Data { ByteArrayOutputStream out = new ByteArrayOutputStream(); for (byte[] param : data) { byte[] length = new byte[2]; - Util.setShort(length, 0, (short) param.length); + ByteUtil.setShort(length, 0, (short) param.length); out.write(length, 0, 2); out.write(param, 0, param.length); @@ -79,7 +80,7 @@ public abstract class EC_Data { public String[] expand() { List out = new ArrayList<>(count); for (byte[] param : data) { - out.add(Util.bytesToHex(param, false)); + out.add(ByteUtil.bytesToHex(param, false)); } return out.toArray(new String[out.size()]); @@ -97,9 +98,9 @@ public abstract class EC_Data { private static byte[] parse(String param) { byte[] data; if (param.startsWith("0x") || param.startsWith("0X")) { - data = Util.hexToBytes(param.substring(2)); + data = ByteUtil.hexToBytes(param.substring(2)); } else { - data = Util.hexToBytes(param); + data = ByteUtil.hexToBytes(param); } if (data == null) return new byte[0]; @@ -141,12 +142,16 @@ public abstract class EC_Data { } public boolean readBytes(byte[] bytes) { + if (bytes == null) { + return false; + } + int offset = 0; for (int i = 0; i < count; i++) { if (bytes.length - offset < 2) { return false; } - short paramLength = Util.getShort(bytes, offset); + short paramLength = ByteUtil.getShort(bytes, offset); offset += 2; if (bytes.length < offset + paramLength) { return false; @@ -158,6 +163,18 @@ public abstract class EC_Data { return true; } + public boolean readByteArray(byte[][] bytes) { + if (bytes == null || count != bytes.length) { + return false; + } + + for (int i = 0; i < count; ++i) { + data[i] = new byte[bytes[i].length]; + System.arraycopy(bytes[i], 0, data[i], 0, bytes[i].length); + } + return true; + } + public void writeCSV(OutputStream out) throws IOException { Writer w = new OutputStreamWriter(out); w.write(String.join(",", expand())); diff --git a/src/cz/crcs/ectester/common/ec/EC_KAResult.java b/src/cz/crcs/ectester/common/ec/EC_KAResult.java index 3b74c57..a7b3cd5 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.common.Util; +import cz.crcs.ectester.common.util.CardUtil; /** * A result of EC based Key agreement operation. @@ -56,7 +56,7 @@ public class EC_KAResult extends EC_Data { @Override public String toString() { - String algo = Util.getKA(ka); + String algo = CardUtil.getKA(ka); return "<" + getId() + "> " + algo + " result over " + curve + ", " + oneKey + " + " + otherKey + (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 index 3fada93..1c066e7 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.common.Util; +import cz.crcs.ectester.common.util.ByteUtil; import java.io.ByteArrayOutputStream; import java.util.ArrayList; @@ -125,12 +125,12 @@ public class EC_Params extends EC_Data { byte[] param = data[i]; if (masked == EC_Consts.PARAMETER_F2M) { //add m, e_1, e_2, e_3 - param = Util.concatenate(param, data[i + 1]); - if (!Util.allValue(data[i + 2], (byte) 0)) { - param = Util.concatenate(param, data[i + 2]); + param = ByteUtil.concatenate(param, data[i + 1]); + if (!ByteUtil.allValue(data[i + 2], (byte) 0)) { + param = ByteUtil.concatenate(param, data[i + 2]); } - if (!Util.allValue(data[i + 3], (byte) 0)) { - param = Util.concatenate(param, data[i + 3]); + if (!ByteUtil.allValue(data[i + 3], (byte) 0)) { + param = ByteUtil.concatenate(param, data[i + 3]); } if (!(param.length == 4 || param.length == 8)) throw new RuntimeException("PARAMETER_F2M length is not 8.(should be)"); @@ -138,14 +138,14 @@ public class EC_Params extends EC_Data { 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! + param = ByteUtil.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); + ByteUtil.setShort(length, 0, (short) param.length); out.write(length, 0, 2); //write data out.write(param, 0, param.length); @@ -175,15 +175,15 @@ public class EC_Params extends EC_Data { 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)); + out.add(ByteUtil.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)); + out.add(ByteUtil.bytesToHex(param, false)); + out.add(ByteUtil.bytesToHex(data[index + 1], false)); index += 2; } else { - out.add(Util.bytesToHex(param, false)); + out.add(ByteUtil.bytesToHex(param, false)); index++; } } diff --git a/src/cz/crcs/ectester/common/util/ByteUtil.java b/src/cz/crcs/ectester/common/util/ByteUtil.java new file mode 100644 index 0000000..939e487 --- /dev/null +++ b/src/cz/crcs/ectester/common/util/ByteUtil.java @@ -0,0 +1,122 @@ +package cz.crcs.ectester.common.util; + +/** + * Utility class, some byte/hex manipulation, convenient byte[] methods. + * + * @author Petr Svenda petr@svenda.com + * @author Jan Jancar johny@neuromancer.sk + */ +public class ByteUtil { + 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; + } +} diff --git a/src/cz/crcs/ectester/common/util/CardUtil.java b/src/cz/crcs/ectester/common/util/CardUtil.java new file mode 100644 index 0000000..a94c773 --- /dev/null +++ b/src/cz/crcs/ectester/common/util/CardUtil.java @@ -0,0 +1,255 @@ +package cz.crcs.ectester.common.util; + +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.*; + +public class CardUtil { + 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/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index ad5b368..cea46bc 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -2,7 +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 cz.crcs.ectester.common.util.ByteUtil; import javacard.framework.AID; import javax.smartcardio.*; @@ -80,7 +80,7 @@ public class CardMngr { //reset the card if (verbose) - System.out.println(Util.bytesToHex(card.getATR().getBytes())); + System.out.println(ByteUtil.bytesToHex(card.getATR().getBytes())); cardFound = true; } @@ -109,7 +109,7 @@ public class CardMngr { try { card = terminal.connect("*"); ATR atr = card.getATR(); - System.out.println(terminalIndex + " : " + terminal.getName() + " - " + Util.bytesToHex(atr.getBytes())); + System.out.println(terminalIndex + " : " + terminal.getName() + " - " + ByteUtil.bytesToHex(atr.getBytes())); terminalIndex++; } catch (CardException ex) { ex.printStackTrace(System.out); @@ -227,7 +227,7 @@ public class CardMngr { System.out.println(">>>>"); System.out.println(apdu); - System.out.println(Util.bytesToHex(apdu.getBytes())); + System.out.println(ByteUtil.bytesToHex(apdu.getBytes())); } long elapsed = -System.nanoTime(); @@ -238,7 +238,7 @@ public class CardMngr { if (verbose) { System.out.println(responseAPDU); - System.out.println(Util.bytesToHex(responseAPDU.getBytes())); + System.out.println(ByteUtil.bytesToHex(responseAPDU.getBytes())); } if (responseAPDU.getSW1() == (byte) 0x61) { @@ -248,7 +248,7 @@ public class CardMngr { responseAPDU = channel.transmit(apduToSend); if (verbose) - System.out.println(Util.bytesToHex(responseAPDU.getBytes())); + System.out.println(ByteUtil.bytesToHex(responseAPDU.getBytes())); } if (verbose) { @@ -277,7 +277,7 @@ public class CardMngr { if (verbose) { System.out.println(">>>>"); System.out.println(apdu); - System.out.println(Util.bytesToHex(apdu.getBytes())); + System.out.println(ByteUtil.bytesToHex(apdu.getBytes())); } ResponseAPDU response = simulator.transmitCommand(apdu); @@ -285,7 +285,7 @@ public class CardMngr { if (verbose) { System.out.println(response); - System.out.println(Util.bytesToHex(responseBytes)); + System.out.println(ByteUtil.bytesToHex(responseBytes)); System.out.println("<<<<"); } diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 2c57107..d32d9d8 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -24,10 +24,10 @@ package cz.crcs.ectester.reader; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.common.cli.CLITools; -import cz.crcs.ectester.common.Util; 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.common.util.ByteUtil; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.output.*; @@ -385,8 +385,8 @@ public class ECTesterReader { } 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 pub = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false); + String priv = ByteUtil.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(); @@ -507,7 +507,7 @@ public class ECTesterReader { } if (out != null) { - out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSecret(), false))); + out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(perform.getSecret(), false))); } ++done; @@ -584,7 +584,7 @@ public class ECTesterReader { } if (out != null) { - out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSignature(), false))); + out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(perform.getSignature(), false))); } ++done; diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index 9d23322..b60db53 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -2,11 +2,11 @@ package cz.crcs.ectester.reader.command; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.util.ByteUtil; 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.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; @@ -174,7 +174,7 @@ public abstract class Command { if (privkey == null) { throw new IOException("Couldn't read the private key file correctly."); } - data = Util.concatenate(data, privkey); + data = ByteUtil.concatenate(data, privkey); } return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, params, data); } @@ -203,7 +203,7 @@ public abstract class Command { this.keyClass = keyClass; byte[] data = new byte[]{0, 0, keyClass}; - Util.setShort(data, 0, keyLength); + ByteUtil.setShort(data, 0, keyLength); this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE, keyPair, 0x00, data); } @@ -296,7 +296,7 @@ public abstract class Command { int len = external != null ? 2 + external.length : 2; byte[] data = new byte[len]; - Util.setShort(data, 0, params); + ByteUtil.setShort(data, 0, params); if (external != null) { System.arraycopy(external, 0, data, 2, external.length); } @@ -337,7 +337,7 @@ public abstract class Command { this.corruption = corruption; byte[] data = new byte[3]; - Util.setShort(data, 0, params); + ByteUtil.setShort(data, 0, params); data[2] = corruption; this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CORRUPT, keyPair, key, data); @@ -403,7 +403,7 @@ public abstract class Command { this.params = params; byte[] data = new byte[2]; - Util.setShort(data, 0, params); + ByteUtil.setShort(data, 0, params); this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_EXPORT, keyPair, key, data); } @@ -446,7 +446,7 @@ public abstract class Command { this.type = type; byte[] data = new byte[]{export, 0,0, type}; - Util.setShort(data, 1, corruption); + ByteUtil.setShort(data, 1, corruption); this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDH, pubkey, privkey, data); } @@ -489,7 +489,7 @@ public abstract class Command { this.pubkey = pubkey; byte[] data = new byte[3 + pubkey.length]; - Util.setShort(data, 0, corruption); + ByteUtil.setShort(data, 0, corruption); data[2] = type; System.arraycopy(pubkey, 0, data, 3, pubkey.length); @@ -526,7 +526,7 @@ public abstract class Command { int len = raw != null ? raw.length : 0; byte[] data = new byte[2 + len]; - Util.setShort(data, 0, (short) len); + ByteUtil.setShort(data, 0, (short) len); if (raw != null) { System.arraycopy(raw, 0, data, 2, len); } diff --git a/src/cz/crcs/ectester/reader/output/ResponseWriter.java b/src/cz/crcs/ectester/reader/output/ResponseWriter.java index 0f5b6e8..1dbfdfa 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.common.Util; +import cz.crcs.ectester.common.util.CardUtil; import cz.crcs.ectester.reader.response.Response; import java.io.PrintStream; @@ -20,11 +20,11 @@ public class ResponseWriter { for (int j = 0; j < r.getNumSW(); ++j) { short sw = r.getSW(j); if (sw != 0) { - suffix.append(" ").append(Util.getSWString(sw)); + suffix.append(" ").append(CardUtil.getSWString(sw)); } } if (suffix.length() == 0) { - suffix.append(" [").append(Util.getSW(r.getNaturalSW())).append("]"); + suffix.append(" [").append(CardUtil.getSW(r.getNaturalSW())).append("]"); } return String.format("%4d ms ┃ %s", r.getDuration() / 1000000, suffix); } diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java index 0a5155b..ebc93ac 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.common.Util; +import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.common.test.Test; @@ -51,7 +51,7 @@ public class XMLTestWriter implements TestWriter { Element commandElem = doc.createElement("command"); Element apdu = doc.createElement("apdu"); - apdu.setTextContent(Util.bytesToHex(c.getAPDU().getBytes())); + apdu.setTextContent(ByteUtil.bytesToHex(c.getAPDU().getBytes())); commandElem.appendChild(apdu); return commandElem; @@ -62,7 +62,7 @@ public class XMLTestWriter implements TestWriter { responseElem.setAttribute("successful", r.successful() ? "true" : "false"); Element apdu = doc.createElement("apdu"); - apdu.setTextContent(Util.bytesToHex(r.getAPDU().getBytes())); + apdu.setTextContent(ByteUtil.bytesToHex(r.getAPDU().getBytes())); responseElem.appendChild(apdu); Element naturalSW = doc.createElement("natural-sw"); diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java index 84f1eac..d8350ac 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.common.Util; +import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.common.test.Test; @@ -44,14 +44,14 @@ public class YAMLTestWriter implements TestWriter { private Map commandObject(Command c) { Map commandObj = new HashMap<>(); - commandObj.put("apdu", Util.bytesToHex(c.getAPDU().getBytes())); + commandObj.put("apdu", ByteUtil.bytesToHex(c.getAPDU().getBytes())); return commandObj; } private Map responseObject(Response r) { Map responseObj = new HashMap<>(); responseObj.put("successful", r.successful()); - responseObj.put("apdu", Util.bytesToHex(r.getAPDU().getBytes())); + responseObj.put("apdu", ByteUtil.bytesToHex(r.getAPDU().getBytes())); responseObj.put("natural_sw", Short.toUnsignedInt(r.getNaturalSW())); List sws = new LinkedList<>(); for (int i = 0; i < r.getNumSW(); ++i) { diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index 4158ac3..d8edf9e 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -2,7 +2,8 @@ package cz.crcs.ectester.reader.response; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.common.Util; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.common.util.CardUtil; import javacard.framework.ISO7816; import javacard.security.KeyPair; @@ -36,7 +37,7 @@ public abstract class Response { //parse SWs in response for (int i = 0; i < numSW; ++i) { if (getLength() >= (offset + 2)) { - short sw = Util.getShort(data, offset); + short sw = ByteUtil.getShort(data, offset); offset += 2; sws[i] = sw; if (sw != ISO7816.SW_NO_ERROR) { @@ -62,7 +63,7 @@ public abstract class Response { error = true; break; } - short paramLength = Util.getShort(data, offset); + short paramLength = ByteUtil.getShort(data, offset); offset += 2; if (data.length < offset + paramLength) { error = true; @@ -140,7 +141,7 @@ public abstract class Response { @Override public String getDescription() { - return String.format("Allocated KeyAgreement(%s) object", Util.getKATypeString(this.kaType)); + return String.format("Allocated KeyAgreement(%s) object", CardUtil.getKATypeString(this.kaType)); } } @@ -289,7 +290,7 @@ public abstract class Response { @Override public String getDescription() { - String corrupt = Util.getCorruption(corruption); + String corrupt = CardUtil.getCorruption(corruption); String pair; if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { @@ -476,7 +477,7 @@ public abstract class Response { @Override public String getDescription() { - String algo = Util.getKA(type); + String algo = CardUtil.getKA(type); String pub = pubkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; @@ -485,7 +486,7 @@ public abstract class Response { if (corruption == EC_Consts.CORRUPTION_NONE) { validity = "unchanged"; } else { - validity = Util.getCorruption(corruption); + validity = CardUtil.getCorruption(corruption); } return String.format("%s of %s pubkey and %s privkey(%s point)", algo, pub, priv, validity); } diff --git a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java index 77653d1..98172f3 100644 --- a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java +++ b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java @@ -5,10 +5,10 @@ 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.common.util.ByteUtil; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; -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; @@ -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.getData(0), 0, dh.secretLength())) { - int firstDiff = Util.diffBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength()); + if (!ByteUtil.compareBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength())) { + int firstDiff = ByteUtil.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 049626e..9f100d0 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -2,6 +2,7 @@ package cz.crcs.ectester.standalone; import cz.crcs.ectester.common.cli.*; import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; @@ -21,6 +22,7 @@ import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; import java.security.spec.ECParameterSpec; import java.util.*; import java.util.stream.Collectors; @@ -49,12 +51,12 @@ public class ECTesterStandalone { try { cli = parseArgs(args); - if (cli.hasOption("help") || cli.getNext() == null) { - CLITools.help("ECTesterStandalone.jar", CLI_HEADER, opts, optParser, CLI_FOOTER, true); - return; - } else if (cli.hasOption("version")) { + if (cli.hasOption("version")) { CLITools.version(DESCRIPTION, LICENSE); return; + } else if (cli.hasOption("help") || cli.getNext() == null) { + CLITools.help("ECTesterStandalone.jar", CLI_HEADER, opts, optParser, CLI_FOOTER, true); + return; } @@ -209,12 +211,19 @@ public class ECTesterStandalone { } kpg.initialize(curve.toSpec()); } + System.out.println("index;time;pubW;privS"); int amount = Integer.parseInt(cli.getOptionValue("generate.amount", "1")); for (int i = 0; i < amount; ++i) { + long elapsed = -System.nanoTime(); KeyPair kp = kpg.genKeyPair(); + elapsed += System.nanoTime(); + ECPublicKey publicKey = (ECPublicKey) kp.getPublic(); ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate(); - System.out.println(privateKey); + + String pub = ByteUtil.bytesToHex(publicKey.getEncoded(), false); + String priv = ByteUtil.bytesToHex(privateKey.getEncoded(), false); + System.out.println(String.format("%d;%d;%s;%s", i, elapsed / 1000000, pub, priv)); } } } @@ -253,6 +262,8 @@ public class ECTesterStandalone { ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate(); ECParameterSpec params = privateKey.getParams(); System.out.println(params); + EC_Curve curve = EC_Curve.fromSpec(params); + System.out.println(curve); } } } diff --git a/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java b/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java index 8ad425b..381ce70 100644 --- a/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java +++ b/src/cz/crcs/ectester/standalone/test/KeyGenerationTestable.java @@ -12,12 +12,16 @@ public class KeyGenerationTestable implements Testable { private KeyPair kp; private KeyPairGenerator kpg; - private int keysize; - private ECParameterSpec spec; + private int keysize = 0; + private ECParameterSpec spec = null; private boolean hasRun; private boolean error = false; private boolean ok; + public KeyGenerationTestable(KeyPairGenerator kpg) { + this.kpg = kpg; + } + public KeyGenerationTestable(KeyPairGenerator kpg, int keysize) { this.kpg = kpg; this.keysize = keysize; @@ -42,7 +46,7 @@ public class KeyGenerationTestable implements Testable { try { if (spec != null) { kpg.initialize(spec); - } else { + } else if (keysize != 0) { kpg.initialize(keysize); } } catch (InvalidAlgorithmParameterException e) { -- cgit v1.2.3-70-g09d2 From 6b77638b9c82607b76a0a13a36b3c28418d772ba Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 14 Jan 2018 12:48:20 +0100 Subject: Add CPLC fetch and parsing. --- src/cz/crcs/ectester/reader/CardMngr.java | 157 ++++++++++++++++++++++-------- 1 file changed, 117 insertions(+), 40 deletions(-) (limited to 'src/cz/crcs/ectester/reader/CardMngr.java') diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index cea46bc..a959f2a 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -4,10 +4,10 @@ import com.licel.jcardsim.io.CAD; import com.licel.jcardsim.io.JavaxSmartCardInterface; import cz.crcs.ectester.common.util.ByteUtil; import javacard.framework.AID; +import javacard.framework.ISO7816; import javax.smartcardio.*; -import java.util.List; -import java.util.Scanner; +import java.util.*; /** * @author Petr Svenda petr@svenda.com @@ -165,50 +165,127 @@ public class CardMngr { } } - public byte[] getCPLCData() throws Exception { - byte[] data; - - // TODO: Modify to obtain CPLC data - byte apdu[] = new byte[HEADER_LENGTH]; - apdu[OFFSET_CLA] = (byte) 0x00; - apdu[OFFSET_INS] = (byte) 0x00; - apdu[OFFSET_P1] = (byte) 0x00; - apdu[OFFSET_P2] = (byte) 0x00; - apdu[OFFSET_LC] = (byte) 0x00; - - ResponseAPDU resp = send(apdu); - if (resp.getSW() != 0x9000) { // 0x9000 is "OK" - System.err.println("Fail to obtain card's response data"); - data = null; - } else { - byte temp[] = resp.getBytes(); - data = new byte[temp.length - 2]; - System.arraycopy(temp, 0, data, 0, temp.length - 2); - // Last two bytes are status word (also obtainable by resp.getSW()) - // Take a look at ISO7816_status_words.txt for common codes + // Functions for CPLC taken and modified from https://github.com/martinpaljak/GlobalPlatformPro + private static final byte CLA_GP = (byte) 0x80; + private static final byte ISO7816_INS_GET_DATA = (byte) 0xCA; + private static final byte[] FETCH_GP_CPLC_APDU = {CLA_GP, ISO7816_INS_GET_DATA, (byte) 0x9F, (byte) 0x7F, (byte) 0x00}; + private static final byte[] FETCH_ISO_CPLC_APDU = {ISO7816.CLA_ISO7816, ISO7816_INS_GET_DATA, (byte) 0x9F, (byte) 0x7F, (byte) 0x00}; + private static final byte[] FETCH_GP_CARDDATA_APDU = {CLA_GP, ISO7816_INS_GET_DATA, (byte) 0x00, (byte) 0x66, (byte) 0x00}; + + public byte[] fetchCPLC() throws CardException { + // Try CPLC via GP + ResponseAPDU resp = sendAPDU(FETCH_GP_CPLC_APDU); + // If GP CLA fails, try with ISO + if (resp.getSW() == (ISO7816.SW_CLA_NOT_SUPPORTED & 0xffff)) { + resp = sendAPDU(FETCH_ISO_CPLC_APDU); } - - return data; + if (resp.getSW() == (ISO7816.SW_NO_ERROR & 0xffff)) { + return resp.getData(); + } + return null; } - public void probeCardCommands() throws Exception { - // TODO: modify to probe for instruction - for (int i = 0; i <= 0; i++) { - byte apdu[] = new byte[HEADER_LENGTH]; - apdu[OFFSET_CLA] = (byte) 0x00; - apdu[OFFSET_INS] = (byte) 0x00; - apdu[OFFSET_P1] = (byte) 0x00; - apdu[OFFSET_P2] = (byte) 0x00; - apdu[OFFSET_LC] = (byte) 0x00; + public static final class CPLC { + public enum Field { + ICFabricator, + ICType, + OperatingSystemID, + OperatingSystemReleaseDate, + OperatingSystemReleaseLevel, + ICFabricationDate, + ICSerialNumber, + ICBatchIdentifier, + ICModuleFabricator, + ICModulePackagingDate, + ICCManufacturer, + ICEmbeddingDate, + ICPrePersonalizer, + ICPrePersonalizationEquipmentDate, + ICPrePersonalizationEquipmentID, + ICPersonalizer, + ICPersonalizationDate, + ICPersonalizationEquipmentID + } - ResponseAPDU resp = send(apdu); + private Map values = new HashMap<>(); - if (verbose) - System.out.println("Response: " + Integer.toHexString(resp.getSW())); - - if (resp.getSW() != 0x6D00) { // Note: 0x6D00 is SW_INS_NOT_SUPPORTED - // something? + public CPLC(byte[] data) { + if (data == null || data.length < 3 || data[2] != 0x2A) { + throw new IllegalArgumentException("CPLC must be 0x2A bytes long"); } + //offset = TLVUtils.skipTag(data, offset, (short)0x9F7F); + short offset = 3; + values.put(Field.ICFabricator, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICType, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.OperatingSystemID, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.OperatingSystemReleaseDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.OperatingSystemReleaseLevel, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICFabricationDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICSerialNumber, Arrays.copyOfRange(data, offset, offset + 4)); + offset += 4; + values.put(Field.ICBatchIdentifier, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICModuleFabricator, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICModulePackagingDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICCManufacturer, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICEmbeddingDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICPrePersonalizer, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICPrePersonalizationEquipmentDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICPrePersonalizationEquipmentID, Arrays.copyOfRange(data, offset, offset + 4)); + offset += 4; + values.put(Field.ICPersonalizer, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICPersonalizationDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICPersonalizationEquipmentID, Arrays.copyOfRange(data, offset, offset + 4)); + offset += 4; + } + + public Map values() { + return values; + } + } + + public CPLC getCPLC() throws CardException { + byte[] data = fetchCPLC(); + return new CPLC(data); + } + + public String mapCPLCField(CPLC.Field field, byte[] value) { + switch (field) { + case ICFabricator: + String id = ByteUtil.bytesToHex(value, false); + String fabricatorName = "unknown"; + if (id.equals("3060")) { + fabricatorName = "Renesas"; + } + if (id.equals("4090")) { + fabricatorName = "Infineon"; + } + if (id.equals("4180")) { + fabricatorName = "Atmel"; + } + if (id.equals("4250")) { + fabricatorName = "Samsung"; + } + if (id.equals("4790")) { + fabricatorName = "NXP"; + } + return id + " (" + fabricatorName + ")"; + default: + return ByteUtil.bytesToHex(value, false); } } -- cgit v1.2.3-70-g09d2 From aeb322e1da26dcfc83762d9bc8df83667a22282a Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 14 Jan 2018 15:26:30 +0100 Subject: Export CPLC data and card ATR in test suite outputs. --- .../ectester/common/output/BaseTextTestWriter.java | 3 ++ .../ectester/common/output/BaseXMLTestWriter.java | 3 ++ .../ectester/common/output/BaseYAMLTestWriter.java | 3 ++ src/cz/crcs/ectester/reader/CardMngr.java | 21 +++++++++--- .../ectester/reader/output/TextTestWriter.java | 29 +++++++++++++++++ .../crcs/ectester/reader/output/XMLTestWriter.java | 38 ++++++++++++++++++++++ .../ectester/reader/output/YAMLTestWriter.java | 33 +++++++++++++++++++ .../crcs/ectester/reader/test/CardTestSuite.java | 4 +++ .../ectester/standalone/output/TextTestWriter.java | 8 +++++ .../ectester/standalone/output/XMLTestWriter.java | 7 ++++ .../ectester/standalone/output/YAMLTestWriter.java | 7 ++++ 11 files changed, 151 insertions(+), 5 deletions(-) (limited to 'src/cz/crcs/ectester/reader/CardMngr.java') diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java index 6ace3a0..29eb671 100644 --- a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java @@ -20,10 +20,13 @@ public abstract class BaseTextTestWriter implements TestWriter { public void begin(TestSuite suite) { output.println("═══ Running test suite: " + suite.getName() + " ═══"); output.println("═══ " + suite.getDescription()); + output.print(deviceString(suite)); } protected abstract String testableString(Testable t); + protected abstract String deviceString(TestSuite suite); + private String testString(Test t, String prefix) { if (!t.hasRun()) { return null; diff --git a/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java index 9d3c8f3..f3e9411 100644 --- a/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java @@ -39,10 +39,13 @@ public abstract class BaseXMLTestWriter implements TestWriter { root = rootElem; doc.appendChild(root); + root.appendChild(deviceElement(suite)); } protected abstract Element testableElement(Testable t); + protected abstract Element deviceElement(TestSuite suite); + private Element testElement(Test t) { Element testElem; if (t instanceof CompoundTest) { diff --git a/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java index af76927..0769e83 100644 --- a/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java @@ -33,11 +33,14 @@ public abstract class BaseYAMLTestWriter implements TestWriter { testSuite.put("desc", suite.getDescription()); testRun.put("suite", testSuite); + testRun.put("device", deviceObject(suite)); testRun.put("tests", tests); } abstract protected Map testableObject(Testable t); + abstract protected Map deviceObject(TestSuite suite); + private Map testObject(Test t) { Map testObj; if (t instanceof CompoundTest) { diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index a959f2a..1e42c52 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -174,10 +174,10 @@ public class CardMngr { public byte[] fetchCPLC() throws CardException { // Try CPLC via GP - ResponseAPDU resp = sendAPDU(FETCH_GP_CPLC_APDU); + ResponseAPDU resp = send(FETCH_GP_CPLC_APDU); // If GP CLA fails, try with ISO if (resp.getSW() == (ISO7816.SW_CLA_NOT_SUPPORTED & 0xffff)) { - resp = sendAPDU(FETCH_ISO_CPLC_APDU); + resp = send(FETCH_ISO_CPLC_APDU); } if (resp.getSW() == (ISO7816.SW_NO_ERROR & 0xffff)) { return resp.getData(); @@ -207,10 +207,13 @@ public class CardMngr { ICPersonalizationEquipmentID } - private Map values = new HashMap<>(); + private Map values = new TreeMap<>(); public CPLC(byte[] data) { - if (data == null || data.length < 3 || data[2] != 0x2A) { + if (data == null) { + return; + } + if (data.length < 3 || data[2] != 0x2A) { throw new IllegalArgumentException("CPLC must be 0x2A bytes long"); } //offset = TLVUtils.skipTag(data, offset, (short)0x9F7F); @@ -263,7 +266,7 @@ public class CardMngr { return new CPLC(data); } - public String mapCPLCField(CPLC.Field field, byte[] value) { + public static String mapCPLCField(CPLC.Field field, byte[] value) { switch (field) { case ICFabricator: String id = ByteUtil.bytesToHex(value, false); @@ -289,6 +292,14 @@ public class CardMngr { } } + public ATR getATR() { + if (simulate) { + return new ATR(simulator.getATR()); + } else { + return card.getATR(); + } + } + public static List getReaderList() { try { TerminalFactory factory = TerminalFactory.getDefault(); diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java index dedf561..eb52937 100644 --- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java @@ -1,10 +1,16 @@ package cz.crcs.ectester.reader.output; import cz.crcs.ectester.common.output.BaseTextTestWriter; +import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.test.CardTestSuite; import cz.crcs.ectester.reader.test.CommandTestable; +import javax.smartcardio.CardException; import java.io.PrintStream; +import java.util.Map; /** * @author Jan Jancar johny@neuromancer.sk @@ -25,4 +31,27 @@ public class TextTestWriter extends BaseTextTestWriter { } return ""; } + + @Override + protected String deviceString(TestSuite suite) { + if (suite instanceof CardTestSuite) { + CardTestSuite cardSuite = (CardTestSuite) suite; + StringBuilder sb = new StringBuilder(); + sb.append("═══ Card ATR: ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator()); + try { + CardMngr.CPLC cplc = cardSuite.getCard().getCPLC(); + if (!cplc.values().isEmpty()) { + sb.append("═══ Card CPLC data:").append(System.lineSeparator()); + for (Map.Entry entry : cplc.values().entrySet()) { + CardMngr.CPLC.Field field = entry.getKey(); + byte[] value = entry.getValue(); + sb.append("═══ ").append(field.name()).append(": ").append(CardMngr.mapCPLCField(field, value)); + } + } + } catch (CardException ignored) { + } + return sb.toString(); + } + return ""; + } } diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java index d88a64e..356593e 100644 --- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java @@ -1,15 +1,20 @@ package cz.crcs.ectester.reader.output; import cz.crcs.ectester.common.output.BaseXMLTestWriter; +import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; +import cz.crcs.ectester.reader.test.CardTestSuite; import cz.crcs.ectester.reader.test.CommandTestable; import org.w3c.dom.Element; +import javax.smartcardio.CardException; import javax.xml.parsers.ParserConfigurationException; import java.io.OutputStream; +import java.util.Map; /** * @author Jan Jancar johny@neuromancer.sk @@ -72,4 +77,37 @@ public class XMLTestWriter extends BaseXMLTestWriter { } return null; } + + private Element cplcElement(CardMngr card) { + Element result = doc.createElement("cplc"); + try { + CardMngr.CPLC cplc = card.getCPLC(); + if (!cplc.values().isEmpty()) { + for (Map.Entry entry : cplc.values().entrySet()) { + CardMngr.CPLC.Field field = entry.getKey(); + byte[] value = entry.getValue(); + Element keyVal = doc.createElement(field.name()); + keyVal.setTextContent(ByteUtil.bytesToHex(value, false)); + result.appendChild(keyVal); + } + } + } catch (CardException ignored) { + } + return result; + } + + @Override + protected Element deviceElement(TestSuite suite) { + if (suite instanceof CardTestSuite) { + CardTestSuite cardSuite = (CardTestSuite) suite; + Element result = doc.createElement("device"); + result.setAttribute("type", "card"); + result.appendChild(cplcElement(cardSuite.getCard())); + + Element atr = doc.createElement("ATR"); + atr.setTextContent(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)); + result.appendChild(atr); + } + return null; + } } \ No newline at end of file diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java index 49a20f1..199f2c0 100644 --- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java @@ -1,12 +1,16 @@ package cz.crcs.ectester.reader.output; import cz.crcs.ectester.common.output.BaseYAMLTestWriter; +import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; +import cz.crcs.ectester.reader.test.CardTestSuite; import cz.crcs.ectester.reader.test.CommandTestable; +import javax.smartcardio.CardException; import java.io.PrintStream; import java.util.HashMap; import java.util.LinkedList; @@ -54,4 +58,33 @@ public class YAMLTestWriter extends BaseYAMLTestWriter { } return null; } + + private Map cplcObject(CardMngr card) { + Map result = new HashMap<>(); + try { + CardMngr.CPLC cplc = card.getCPLC(); + if (!cplc.values().isEmpty()) { + for (Map.Entry entry : cplc.values().entrySet()) { + CardMngr.CPLC.Field field = entry.getKey(); + byte[] value = entry.getValue(); + result.put(field.name(), ByteUtil.bytesToHex(value, false)); + } + } + } catch (CardException ignored) { + } + return result; + } + + @Override + protected Map deviceObject(TestSuite suite) { + if (suite instanceof CardTestSuite) { + CardTestSuite cardSuite = (CardTestSuite) suite; + Map result = new HashMap<>(); + result.put("type", "card"); + result.put("cplc", cplcObject(cardSuite.getCard())); + result.put("ATR", ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)); + return result; + } + return null; + } } diff --git a/src/cz/crcs/ectester/reader/test/CardTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTestSuite.java index e12a588..b451265 100644 --- a/src/cz/crcs/ectester/reader/test/CardTestSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardTestSuite.java @@ -116,4 +116,8 @@ public abstract class CardTestSuite extends TestSuite { return null; } + + public CardMngr getCard() { + return card; + } } diff --git a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java index ddb1029..972af18 100644 --- a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java @@ -1,6 +1,7 @@ package cz.crcs.ectester.standalone.output; import cz.crcs.ectester.common.output.BaseTextTestWriter; +import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import java.io.PrintStream; @@ -15,6 +16,13 @@ public class TextTestWriter extends BaseTextTestWriter { @Override protected String testableString(Testable t) { + //TODO + return ""; + } + + @Override + protected String deviceString(TestSuite suite) { + //TODO return ""; } } \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java b/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java index 9606646..d2b16d8 100644 --- a/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java @@ -1,6 +1,7 @@ package cz.crcs.ectester.standalone.output; import cz.crcs.ectester.common.output.BaseXMLTestWriter; +import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.standalone.test.KeyAgreementTestable; @@ -109,4 +110,10 @@ public class XMLTestWriter extends BaseXMLTestWriter { } return result; } + + @Override + protected Element deviceElement(TestSuite suite) { + //TODO + return null; + } } diff --git a/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java b/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java index 2133a8e..dfc6813 100644 --- a/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java @@ -1,6 +1,7 @@ package cz.crcs.ectester.standalone.output; import cz.crcs.ectester.common.output.BaseYAMLTestWriter; +import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.standalone.test.KeyAgreementTestable; @@ -88,4 +89,10 @@ public class YAMLTestWriter extends BaseYAMLTestWriter { } return result; } + + @Override + protected Map deviceObject(TestSuite suite) { + //TODO + return null; + } } -- cgit v1.2.3-70-g09d2