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 ++++++++++++++++ 7 files changed, 463 insertions(+), 402 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/common') 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; + } +} -- cgit v1.2.3-70-g09d2