diff options
| author | J08nY | 2017-10-13 21:42:49 +0200 |
|---|---|---|
| committer | J08nY | 2017-10-13 21:42:49 +0200 |
| commit | e78bd5d010bd6ced2b71d83b88748f9cc8d98d5e (patch) | |
| tree | 4b08c9788158a1ef87d226c7b1d5b691d91a0aed /src/cz/crcs/ectester/reader/response | |
| parent | d5a549b382db10c34eea35e571b1ba8056eaa5da (diff) | |
| download | ECTester-e78bd5d010bd6ced2b71d83b88748f9cc8d98d5e.tar.gz ECTester-e78bd5d010bd6ced2b71d83b88748f9cc8d98d5e.tar.zst ECTester-e78bd5d010bd6ced2b71d83b88748f9cc8d98d5e.zip | |
Reorganize reader packages.
Diffstat (limited to 'src/cz/crcs/ectester/reader/response')
| -rw-r--r-- | src/cz/crcs/ectester/reader/response/Response.java | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java new file mode 100644 index 0000000..59b24fc --- /dev/null +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -0,0 +1,591 @@ +package cz.crcs.ectester.reader.response; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.reader.Util; +import javacard.framework.ISO7816; +import javacard.security.KeyPair; + +import javax.smartcardio.ResponseAPDU; +import java.util.List; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class Response { + + private ResponseAPDU resp; + private long time; + private short[] sws; + private int numSW = 0; + private byte[][] params; + //TODO replace params with EC_Data? + private boolean success = true; + + public Response(ResponseAPDU response, long time) { + this.resp = response; + this.time = time; + } + + public void parse(int numSW, int numParams) { + this.numSW = numSW; + this.sws = new short[numSW]; + + byte[] data = resp.getData(); + int offset = 0; + + //parse SWs in response + for (int i = 0; i < numSW; ++i) { + if (getLength() >= (offset + 2)) { + short sw = Util.getShort(data, offset); + offset += 2; + sws[i] = sw; + if (sw != ISO7816.SW_NO_ERROR) { + success = false; + } + } else { + success = false; + } + } + + if ((short) resp.getSW() != ISO7816.SW_NO_ERROR) + success = false; + + //try to parse numParams.. + params = new byte[numParams][]; + for (int i = 0; i < numParams; i++) { + if (data.length - offset < 2) { + success = false; + break; + } + short paramLength = Util.getShort(data, offset); + offset += 2; + if (data.length < offset + paramLength) { + success = false; + break; + } + params[i] = new byte[paramLength]; + System.arraycopy(data, offset, params[i], 0, paramLength); + offset += paramLength; + } + } + + public ResponseAPDU getAPDU() { + return resp; + } + + public long getDuration() { + return time; + } + + public short getNaturalSW() { + return (short) resp.getSW(); + } + + public short getSW(int index) { + return sws[index]; + } + + public int getNumSW() { + return numSW; + } + + public boolean hasParam(int index) { + return params.length >= index + 1 && params[index] != null; + } + + public int getParamLength(int index) { + return params[index].length; + } + + public byte[] getParam(int index) { + return params[index]; + } + + public byte[][] getParams() { + return params; + } + + public int getLength() { + return resp.getNr(); + } + + public boolean successful() { + return this.success; + } + + @Override + public abstract String toString(); + + public String toString(String inner) { + StringBuilder suffix = new StringBuilder(); + for (int j = 0; j < getNumSW(); ++j) { + short sw = getSW(j); + if (sw != 0) { + suffix.append(" ").append(Util.getSWString(sw)); + } + } + if (suffix.length() == 0) { + suffix.append(" [").append(Util.getSW(getNaturalSW())).append("]"); + } + return String.format("%-62s:%4d ms : %s", inner, time / 1000000, suffix); + } + + public static String toString(List<Response> responses) { + return toString(responses, null); + } + + public static String toString(List<Response> responses, String prefix) { + if (prefix != null) + prefix += " | "; + StringBuilder out = new StringBuilder(); + for (int i = 0; i < responses.size(); ++i) { + Response r = responses.get(i); + + if (prefix != null) + out.append(prefix); + + String message = r.toString(); + out.append(message); + if (i < responses.size() - 1) { + out.append("\n"); + } + } + return out.toString(); + } + + + /** + * + */ + public static class AllocateKeyAgreement extends Response { + byte kaType; + public AllocateKeyAgreement(ResponseAPDU response, long time, byte kaType) { + super(response, time); + this.kaType = kaType; + + parse(2, 0); + } + + @Override + public String toString() { + return super.toString(String.format("Allocate KeyAgreement(%s) object", Util.getKATypeString(this.kaType))); + } + + } + + public static class Allocate extends Response { + + private byte keyPair; + private short keyLength; + private byte keyClass; + + public Allocate(ResponseAPDU response, long time, byte keyPair, short keyLength, byte keyClass) { + super(response, time); + this.keyPair = keyPair; + this.keyLength = keyLength; + this.keyClass = keyClass; + + int pairs = 0; + if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++; + if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++; + parse(pairs, 0); + } + + @Override + public String toString() { + String field = keyClass == KeyPair.ALG_EC_FP ? "ALG_EC_FP" : "ALG_EC_F2M"; + String key; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + key = "both keypairs"; + } else { + key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return super.toString(String.format("Allocated %s %db %s", key, keyLength, field)); + } + } + + /** + * + */ + public static class Clear extends Response { + + private byte keyPair; + + public Clear(ResponseAPDU response, long time, byte keyPair) { + super(response, time); + this.keyPair = keyPair; + + int pairs = 0; + if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++; + if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++; + parse(pairs, 0); + } + + @Override + public String toString() { + String key; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + key = "both keypairs"; + } else { + key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return super.toString(String.format("Cleared %s", key)); + } + } + + /** + * + */ + public static class Set extends Response { + + private byte keyPair; + private byte curve; + private short parameters; + + public Set(ResponseAPDU response, long time, byte keyPair, byte curve, short parameters) { + super(response, time); + this.keyPair = keyPair; + this.curve = curve; + this.parameters = parameters; + + int pairs = 0; + if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++; + if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++; + + parse(pairs, 0); + } + + @Override + public String toString() { + String name; + switch (curve) { + case EC_Consts.CURVE_default: + name = "default"; + break; + case EC_Consts.CURVE_external: + name = "external"; + break; + default: + name = "custom"; + break; + } + String what = ""; + if (parameters == EC_Consts.PARAMETERS_DOMAIN_F2M || parameters == EC_Consts.PARAMETERS_DOMAIN_FP) { + what = "curve"; + } else if (parameters == EC_Consts.PARAMETER_W) { + what = "pubkey"; + } else if (parameters == EC_Consts.PARAMETER_S) { + what = "privkey"; + } else if (parameters == EC_Consts.PARAMETERS_KEYPAIR) { + what = "keypair"; + } + + String pair; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + pair = "both keypairs"; + } else { + pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return super.toString(String.format("Set %s %s parameters on %s", name, what, pair)); + } + + } + + /** + * + */ + public static class Corrupt extends Response { + + private byte keyPair; + private byte key; + private short params; + private byte corruption; + + public Corrupt(ResponseAPDU response, long time, byte keyPair, byte key, short params, byte corruption) { + super(response, time); + this.keyPair = keyPair; + this.key = key; + this.params = params; + this.corruption = corruption; + + int pairs = 0; + if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++; + if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++; + + parse(pairs, 0); + } + + @Override + public String toString() { + String corrupt = Util.getCorruption(corruption); + + String pair; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + pair = "both keypairs"; + } else { + pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return super.toString(String.format("Corrupted params of %s, %s", pair, corrupt)); + } + } + + /** + * + */ + public static class Generate extends Response { + + private byte keyPair; + + public Generate(ResponseAPDU response, long time, byte keyPair) { + super(response, time); + this.keyPair = keyPair; + + int generated = 0; + if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) generated++; + if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) generated++; + parse(generated, 0); + } + + @Override + public String toString() { + String key; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + key = "both keypairs"; + } else { + key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return super.toString(String.format("Generated %s", key)); + } + + } + + /** + * + */ + public static class Export extends Response { + + private byte keyPair; + private byte key; + private short parameters; + + public Export(ResponseAPDU response, long time, byte keyPair, byte key, short parameters) { + super(response, time); + this.keyPair = keyPair; + this.key = key; + this.parameters = parameters; + + int exported = 0; + if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) exported++; + if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) exported++; + int keys = 0; + if ((key & EC_Consts.KEY_PUBLIC) != 0) keys++; + if ((key & EC_Consts.KEY_PRIVATE) != 0) keys++; + int paramCount = 0; + short mask = EC_Consts.PARAMETER_FP; + while (mask <= EC_Consts.PARAMETER_K) { + if ((mask & parameters) != 0) { + paramCount++; + } + mask = (short) (mask << 1); + } + int other = 0; + if ((key & EC_Consts.KEY_PUBLIC) != 0 && (parameters & EC_Consts.PARAMETER_W) != 0) other++; + if ((key & EC_Consts.KEY_PRIVATE) != 0 && (parameters & EC_Consts.PARAMETER_S) != 0) other++; + + parse(exported, exported * keys * paramCount + exported * other); + } + + private int getIndex(byte keyPair, short param) { + byte pair = ECTesterApplet.KEYPAIR_LOCAL; + int index = 0; + while (pair <= ECTesterApplet.KEYPAIR_REMOTE) { + short mask = EC_Consts.PARAMETER_FP; + while (mask <= EC_Consts.PARAMETER_S) { + if (pair == keyPair && param == mask) { + return index; + } + if ((parameters & mask) != 0 && (pair & keyPair) != 0) { + if (mask == EC_Consts.PARAMETER_W) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) + index++; + } else if (mask == EC_Consts.PARAMETER_S) { + if ((key & EC_Consts.KEY_PRIVATE) != 0) + index++; + } else { + index++; + } + } + mask = (short) (mask << 1); + } + + pair = (byte) (pair << 1); + } + return -1; + } + + public boolean hasParameters(byte keyPair, short params) { + if ((keyPair & this.keyPair) == 0 || (params ^ parameters) != 0) { + return false; + } + short param = EC_Consts.PARAMETER_FP; + while (param <= EC_Consts.PARAMETER_S) { + short masked = (short) (param & params); + if (masked != 0 && !hasParameter(keyPair, masked)) { + return false; + } + param = (short) (param << 1); + } + return true; + } + + public boolean hasParameter(byte keyPair, short param) { + if ((keyPair & this.keyPair) == 0 || (parameters & param) == 0) { + return false; + } + int index = getIndex(keyPair, param); + return index != -1 && hasParam(index); + } + + public byte[] getParameter(byte keyPair, short param) { + return getParam(getIndex(keyPair, param)); + } + + @Override + public String toString() { + String source; + if (key == EC_Consts.KEY_BOTH) { + source = "both keys"; + } else { + source = ((key == EC_Consts.KEY_PUBLIC) ? "public" : "private") + " key"; + } + String pair; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + pair = "both keypairs"; + } else { + pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return super.toString(String.format("Exported params from %s of %s", source, pair)); + } + } + + /** + * + */ + public static class ECDH extends Response { + + private byte pubkey; + private byte privkey; + private byte export; + private short corruption; + private byte type; + + public ECDH(ResponseAPDU response, long time, byte pubkey, byte privkey, byte export, short corruption, byte type) { + super(response, time); + this.pubkey = pubkey; + this.privkey = privkey; + this.export = export; + this.corruption = corruption; + this.type = type; + + parse(1, (export == ECTesterApplet.EXPORT_TRUE) ? 1 : 0); + } + + public boolean hasSecret() { + return hasParam(0); + } + + public byte[] getSecret() { + return getParam(0); + } + + public int secretLength() { + return getParamLength(0); + } + + @Override + public String toString() { + String algo = Util.getKA(type); + + String pub = pubkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; + String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; + + String validity; + if (corruption == EC_Consts.CORRUPTION_NONE) { + validity = "unchanged"; + } else { + validity = Util.getCorruption(corruption); + } + return super.toString(String.format("%s of %s pubkey and %s privkey(%s point)", algo, pub, priv, validity)); + } + } + + /** + * + */ + public static class ECDSA extends Response { + + private byte keyPair; + private byte export; + private byte[] raw; + + public ECDSA(ResponseAPDU response, long time, byte keyPair, byte export, byte[] raw) { + super(response, time); + this.keyPair = keyPair; + this.export = export; + this.raw = raw; + + parse(1, (export == ECTesterApplet.EXPORT_TRUE) ? 1 : 0); + } + + public boolean hasSignature() { + return hasParam(0); + } + + public byte[] getSignature() { + return getParam(0); + } + + @Override + public String toString() { + String key = keyPair == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; + String data = raw == null ? "random" : "provided"; + return super.toString(String.format("ECDSA with %s keypair(%s data)", key, data)); + } + } + + /** + * + */ + public static class Cleanup extends Response { + + public Cleanup(ResponseAPDU response, long time) { + super(response, time); + + parse(1, 0); + } + + @Override + public String toString() { + return super.toString("Requested JCSystem object deletion"); + } + + } + + /** + * + */ + public static class Support extends Response { + + public Support(ResponseAPDU response, long time) { + super(response, time); + + parse(3, 0); + } + + @Override + public String toString() { + return super.toString("Support of ECDH, ECDHC, ECDSA"); + } + } +} |
