diff options
| author | J08nY | 2017-01-27 21:34:39 +0100 |
|---|---|---|
| committer | J08nY | 2017-01-27 21:34:39 +0100 |
| commit | c3e48df92858bad5e74e9cec69c16397b6b12481 (patch) | |
| tree | 470994330c84a56207c3b65eab1232f6e3d0f7df /src | |
| parent | 636306e09a84ac785d2711117640efe914ae020f (diff) | |
| download | ECTester-c3e48df92858bad5e74e9cec69c16397b6b12481.tar.gz ECTester-c3e48df92858bad5e74e9cec69c16397b6b12481.tar.zst ECTester-c3e48df92858bad5e74e9cec69c16397b6b12481.zip | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECKeyGenerator.java | 41 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECTesterApplet.java | 38 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/CardMngr.java | 2 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/Command.java | 27 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/ECTester.java | 121 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/Response.java | 131 |
6 files changed, 260 insertions, 100 deletions
diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java index 417944c..427577b 100644 --- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java +++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java @@ -44,6 +44,19 @@ public class ECKeyGenerator { return ecKeyPair; } + public short clearPair(KeyPair keypair, byte key) { + sw = ISO7816.SW_NO_ERROR; + try { + if ((key & KEY_PUBLIC) != 0) keypair.getPublic().clearKey(); + if ((key & KEY_PRIVATE) != 0) keypair.getPrivate().clearKey(); + } catch (CryptoException ce) { + sw = ce.getReason(); + } catch (Exception e) { + sw = ISO7816.SW_UNKNOWN; + } + return sw; + } + /** * @param keypair * @return @@ -73,8 +86,8 @@ public class ECKeyGenerator { sw = ISO7816.SW_NO_ERROR; if (params == EC_Consts.PARAMETERS_NONE) { - return sw; - } + return sw; + } short length; if (alg == KeyPair.ALG_EC_FP && (params & EC_Consts.PARAMETER_FP) != 0) { @@ -123,9 +136,9 @@ public class ECKeyGenerator { */ public short corruptCurve(KeyPair keypair, byte key, short corruptParams, byte corruption, byte[] buffer, short offset) { sw = ISO7816.SW_NO_ERROR; - if (corruptParams == EC_Consts.PARAMETERS_NONE) { - return sw; - } + if (corruptParams == EC_Consts.PARAMETERS_NONE) { + return sw; + } //go through param bit by bit, and invalidate all selected params short paramMask = EC_Consts.PARAMETER_FP; @@ -252,7 +265,7 @@ public class ECKeyGenerator { public short setExternalCurve(KeyPair keypair, byte key, short params, byte[] inBuffer, short inOffset) { sw = ISO7816.SW_NO_ERROR; if (params == EC_Consts.PARAMETERS_NONE) { - return sw; + return sw; } short paramMask = EC_Consts.PARAMETER_FP; @@ -273,9 +286,9 @@ public class ECKeyGenerator { /** * Exports a selected parameter from a given keyPairs key. * - * @param keypair keypair to export from - * @param key key to export from (KEY_PUBLIC | KEY_PRIVATE) - * @param param parameter to export (EC_Consts.PARAMETER_* || ...) + * @param keypair keypair to export from + * @param key key to export from (KEY_PUBLIC | KEY_PRIVATE) + * @param param parameter to export (EC_Consts.PARAMETER_* || ...) * @param outputBuffer buffer to write to * @param outputOffset offset to start writing in buffer * @return length of data written @@ -346,9 +359,9 @@ public class ECKeyGenerator { */ public short exportParameters(KeyPair keypair, byte key, short params, byte[] buffer, short offset) { sw = ISO7816.SW_NO_ERROR; - if (params == EC_Consts.PARAMETERS_NONE) { - return sw; - } + if (params == EC_Consts.PARAMETERS_NONE) { + return sw; + } short length = 0; short paramMask = EC_Consts.PARAMETER_FP; @@ -372,8 +385,8 @@ public class ECKeyGenerator { /** * Copies this KeyPairs curve parameters to another ECKeyGenerator. * - * @param from keyPair to copy from - * @param to keyPair to copy to + * @param from keyPair to copy from + * @param to keyPair to copy to * @param buffer buffer to use for copying * @param offset offset to use in buffer * @return sw diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index dfdd0f0..cb2c43f 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -44,10 +44,11 @@ public class ECTesterApplet extends Applet { //INSTRUCTIONS public static final byte INS_ALLOCATE = (byte) 0x5a; - public static final byte INS_SET = (byte) 0x5b; - public static final byte INS_GENERATE = (byte) 0x5c; - public static final byte INS_ECDH = (byte) 0x5d; - public static final byte INS_ECDSA = (byte) 0x5e; + public static final byte INS_CLEAR = (byte) 0x5b; + public static final byte INS_SET = (byte) 0x5c; + public static final byte INS_GENERATE = (byte) 0x5d; + public static final byte INS_ECDH = (byte) 0x5e; + public static final byte INS_ECDSA = (byte) 0x5f; //PARAMETERS for P1 and P2 public static final byte KEYPAIR_LOCAL = (byte) 0x01; @@ -127,6 +128,9 @@ public class ECTesterApplet extends Applet { case INS_ALLOCATE: insAllocate(apdu); break; + case INS_CLEAR: + insClear(apdu); + break; case INS_SET: insSet(apdu); break; @@ -170,6 +174,25 @@ public class ECTesterApplet extends Applet { } /** + * + * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) + * P2 = + */ + private void insClear(APDU apdu) { + apdu.setIncomingAndReceive(); + byte[] apdubuf = apdu.getBuffer(); + byte keyPair = apdubuf[ISO7816.OFFSET_P1]; + + short len = 0; + if ((keyPair & KEYPAIR_LOCAL) != 0) + len += clear(localKeypair, apdubuf, (short) 0); + if ((keyPair & KEYPAIR_REMOTE) != 0) + len += clear(remoteKeypair, apdubuf, len); + + apdu.setOutgoingAndSend((short) 0, len); + } + + /** * Sets curve parameters on local and remote keyPairs. * returns setCurve SWs, set params if export * @@ -306,6 +329,13 @@ public class ECTesterApplet extends Applet { return length; } + private short clear(KeyPair keyPair, byte[] buffer, short offset) { + short sw = keyGenerator.clearPair(keyPair, ECKeyGenerator.KEY_BOTH); + Util.setShort(buffer, offset, sw); + + return 2; + } + /** * @param keyPair KeyPair to set params on * @param curve curve to set (EC_Consts.CURVE_*) diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index d95b7e5..6875d2e 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -23,7 +23,7 @@ public class CardMngr { private boolean simulate = false; - private final byte selectCM[] = { + private final byte[] selectCM = { (byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x07, (byte) 0xa0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x18, (byte) 0x43, (byte) 0x4d}; diff --git a/src/cz/crcs/ectester/reader/Command.java b/src/cz/crcs/ectester/reader/Command.java index c5fd465..31cde4d 100644 --- a/src/cz/crcs/ectester/reader/Command.java +++ b/src/cz/crcs/ectester/reader/Command.java @@ -23,11 +23,6 @@ public abstract class Command { return cmd; } - /** - * - * @return - * @throws CardException - */ public abstract Response send() throws CardException; public static List<Response> sendAll(List<Command> commands) throws CardException { @@ -77,6 +72,28 @@ public abstract class Command { /** * */ + public static class Clear extends Command { + private byte keyPair; + + public Clear(CardMngr cardManager, byte keyPair) { + super(cardManager); + this.keyPair = keyPair; + + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEAR, keyPair, 0x00); + } + + @Override + public Response.Clear send() throws CardException { + long elapsed = -System.nanoTime(); + ResponseAPDU response = cardManager.send(cmd); + elapsed += System.nanoTime(); + return new Response.Clear(response, elapsed, keyPair); + } + } + + /** + * + */ public static class Set extends Command { private byte keyPair; private byte export; diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java index e5a2b70..4cb63f7 100644 --- a/src/cz/crcs/ectester/reader/ECTester.java +++ b/src/cz/crcs/ectester/reader/ECTester.java @@ -33,6 +33,7 @@ import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; /** @@ -58,6 +59,7 @@ public class ECTester { private String optKey = null; private String optLog = null; private String optOutput = null; + private boolean optFresh = false; private boolean optSimulate = false; private int optGenerateAmount; @@ -244,11 +246,15 @@ public class ECTester { opts.addOption(Option.builder("fp").longOpt("prime-field").desc("Use prime field curve.").build()); opts.addOption(Option.builder("f2m").longOpt("binary-field").desc("Use binary field curve.").build()); + opts.addOption(Option.builder("pub").longOpt("public").desc("Use public key from file [pubkey_file] (wx,wy).").hasArg().argName("pubkey_file").build()); opts.addOption(Option.builder("priv").longOpt("private").desc("Use private key from file [privkey_file] (s).").hasArg().argName("privkey_file").build()); opts.addOption(Option.builder("k").longOpt("key").desc("Use keyPair from fileĀ [key_file] (wx,wy,s).").hasArg().argName("key_file").build()); + opts.addOption(Option.builder("o").longOpt("output").desc("Output into file [output_file].").hasArg().argName("output_file").build()); opts.addOption(Option.builder("l").longOpt("log").desc("Log output into file [log_file].").hasArg().argName("log_file").optionalArg(true).build()); + + opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys(set domain parameters before every generation).").build()); opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build()); CommandLineParser parser = new DefaultParser(); @@ -275,6 +281,7 @@ public class ECTester { optLog = cli.getOptionValue("log", String.format("ECTESTER_log_%d.log", System.currentTimeMillis() / 1000)); } optOutput = cli.getOptionValue("output"); + optFresh = cli.hasOption("fresh"); optSimulate = cli.hasOption("simulate"); if (optKey != null && (optPublic != null || optPrivate != null)) { @@ -365,7 +372,8 @@ public class ECTester { */ private void generate() throws CardException, IOException { byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; - List<Response> prepare = Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass)); + List<Response> prepare = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass)); + prepare.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass))); FileWriter keysFile = new FileWriter(optOutput); keysFile.write("index;time;pubW;privS\n"); @@ -373,6 +381,10 @@ public class ECTester { int generated = 0; int retry = 0; while (generated < optGenerateAmount || optGenerateAmount == 0) { + if (optFresh) { + Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass)); + } + Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (byte) (ECTesterApplet.EXPORT_BOTH | ECTesterApplet.KEYPAIR_LOCAL)); Response.Generate response = generate.send(); long elapsed = response.getDuration(); @@ -400,47 +412,36 @@ public class ECTester { /** * Tests Elliptic curve support for a given curve/curves. + * + * @throws IOException + * @throws CardException */ - private void test() { - //TODO + private void test() throws IOException, CardException { + List<Command> commands = new LinkedList<>(); if (optAll) { if (optPrimeField) { //iterate over prime curve sizes used: EC_Consts.FP_SIZES for (short keyLength : EC_Consts.FP_SIZES) { - //prepareCurve(KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP); - //insGenerate(KEYPAIR_BOTH, EXPORT_NONE); - //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 00); - //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 01); - //insECDSA(KEYPAIR_LOCAL, EXPORT_NONE, null); + commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_FP)); } } if (optBinaryField) { //iterate over binary curve sizes used: EC_Consts.F2M_SIZES for (short keyLength : EC_Consts.F2M_SIZES) { - //prepareCurve(KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M); - //insGenerate(KEYPAIR_BOTH, EXPORT_NONE); - //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 00); - //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 01); - //insECDSA(KEYPAIR_LOCAL, EXPORT_NONE, null); + commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_F2M)); } } } else { if (optPrimeField) { - //test with prepareCurve(KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_FP) - //insGenerate(KEYPAIR_BOTH, EXPORT_NONE); - //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 00); - //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 01); - //insECDSA(KEYPAIR_LOCAL, EXPORT_NONE, null); + commands.addAll(testCurve((short) optBits, KeyPair.ALG_EC_FP)); } if (optBinaryField) { - //test with prepareCurve(KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_F2M) - //insGenerate(KEYPAIR_BOTH, EXPORT_NONE); - //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 00); - //insECDH(KEYPAIR_LOCAL, KEYPAIR_REMOTE, EXPORT_NONE, 01); - //insECDSA(KEYPAIR_LOCAL, EXPORT_NONE, null); + commands.addAll(testCurve((short) optBits, KeyPair.ALG_EC_F2M)); } } + List<Response> test = Command.sendAll(commands); + systemOutLogger.println(Response.toString(test)); } /** @@ -451,7 +452,8 @@ public class ECTester { */ private void ecdh() throws IOException, CardException { byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; - List<Response> ecdh = Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass)); + List<Response> ecdh = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass)); + ecdh.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass))); if (optPublic != null || optPrivate != null || optKey != null) { Response local = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_NONE).send(); @@ -465,10 +467,17 @@ public class ECTester { Response.ECDH perform = new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_ECDH, (byte) 0).send(); ecdh.add(perform); - for (Response r : ecdh) { - systemOutLogger.println(r.toString()); + systemOutLogger.println(Response.toString(ecdh)); + + if (!perform.hasSecret()) { + System.err.println("Couldn't obtain ECDH secret from card response."); + } else { + if (optOutput != null) { + FileWriter out = new FileWriter(optOutput); + out.write(Util.bytesToHex(perform.getSecret(), false)); + out.close(); + } } - //TODO check perform.hasSecret(), write perform.getSecret to file if -o } /** @@ -479,7 +488,8 @@ public class ECTester { */ private void ecdsa() throws CardException, IOException { byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; - List<Response> ecdsa = Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass)); + List<Response> ecdsa = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass)); + ecdsa.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass))); Response keys; if (optKey != null || (optPublic != null && optPrivate != null)) { @@ -502,33 +512,55 @@ public class ECTester { Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_SIG, data).send(); ecdsa.add(perform); - for (Response r : ecdsa) { - systemOutLogger.println(r.toString()); + systemOutLogger.println(Response.toString(ecdsa)); + + if (!perform.hasSignature()) { + System.err.println("Couldn't obtain ECDSA signature from card response."); + } else { + if (optOutput != null) { + FileWriter out = new FileWriter(optOutput); + out.write(Util.bytesToHex(perform.getSignature(), false)); + out.close(); + } } - //TODO output to file } /** - * @param keyPair which keyPair/s (local/remote) to set curve domain parameters on + * @param keyPair which keyPair/s (local/remote) to allocate * @param keyLength key length to allocate * @param keyClass key class to allocate - * @return an array of CommandAPDUs to send in order to prepare the keypair/s. + * @return a list of Commands to send in order to prepare the keyPair. + */ + private List<Command> prepareKeyPair(byte keyPair, short keyLength, byte keyClass) { + List<Command> commands = new ArrayList<>(); + commands.add(new Command.Allocate(cardManager, keyPair, keyLength, keyClass)); + return commands; + } + + /** + * @param keyPair which keyPair/s (local/remote) to set curve domain parameters on + * @param keyLength key length to choose + * @param keyClass key class to choose + * @return a list of Commands to send in order to prepare the curve on the keypairs. * @throws IOException if curve file cannot be found/opened */ private List<Command> prepareCurve(byte keyPair, short keyLength, byte keyClass) throws IOException { List<Command> commands = new ArrayList<>(); - commands.add(new Command.Allocate(cardManager, keyPair, keyLength, keyClass)); short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; if (optNamed) { + // Set named curve (one of the SECG curves embedded applet-side) commands.add(new Command.Set(cardManager, keyPair, ECTesterApplet.EXPORT_NONE, EC_Consts.getCurve(keyLength, keyClass), domainParams, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, null)); - } - if (optCurve != null) { + } else if (optCurve != null) { + // Set curve loaded from a file byte[] external = ParamReader.flatten(domainParams, ParamReader.readFile(optCurve)); if (external == null) { throw new IOException("Couldn't read the curve file correctly."); } commands.add(new Command.Set(cardManager, keyPair, ECTesterApplet.EXPORT_NONE, EC_Consts.CURVE_external, domainParams, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, external)); + } else { + // Set default curve + commands.add(new Command.Clear(cardManager, keyPair)); } return commands; @@ -566,6 +598,23 @@ public class ECTester { return new Command.Set(cardManager, keyPair, ECTesterApplet.EXPORT_NONE, EC_Consts.CURVE_external, params, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, data); } + /** + * @param keyLength + * @param keyClass + * @return + * @throws IOException + */ + private List<Command> testCurve(short keyLength, byte keyClass) throws IOException { + List<Command> commands = new LinkedList<>(); + commands.addAll(prepareKeyPair(ECTesterApplet.KEYPAIR_BOTH, keyLength, keyClass)); + commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, keyLength, keyClass)); + commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH, ECTesterApplet.EXPORT_NONE)); + commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_NONE, (byte) 0)); + commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_NONE, (byte) 1)); + commands.add(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_NONE, null)); + return commands; + } + public static void main(String[] args) { ECTester app = new ECTester(); app.run(args); diff --git a/src/cz/crcs/ectester/reader/Response.java b/src/cz/crcs/ectester/reader/Response.java index 8f9ab9b..05cd92a 100644 --- a/src/cz/crcs/ectester/reader/Response.java +++ b/src/cz/crcs/ectester/reader/Response.java @@ -6,17 +6,19 @@ 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 { - protected ResponseAPDU resp; - protected long time; - protected short sw1 = 0; - protected short sw2 = 0; - protected byte[][] params; - protected boolean success = true; + private ResponseAPDU resp; + private long time; + private short sw1 = 0; + private short sw2 = 0; + private int numSW = 0; + private byte[][] params; + private boolean success = true; protected Response(ResponseAPDU response, long time) { this.resp = response; @@ -24,6 +26,8 @@ public abstract class Response { } protected void parse(int numSW, int numParams) { + this.numSW = numSW; + byte[] data = resp.getData(); int offset = 0; @@ -31,14 +35,16 @@ public abstract class Response { if (--numSW >= 0 && getLength() >= 2) { sw1 = Util.getShort(data, offset); offset += 2; - if (sw1 != ISO7816.SW_NO_ERROR) + if (sw1 != ISO7816.SW_NO_ERROR) { success = false; + } } if (--numSW >= 0 && getLength() >= 4) { sw2 = Util.getShort(data, offset); offset += 2; - if (sw2 != ISO7816.SW_NO_ERROR) + if (sw2 != ISO7816.SW_NO_ERROR) { success = false; + } } //try to parse numParams.. @@ -60,18 +66,6 @@ public abstract class Response { } } - protected boolean hasParam(int index) { - return params.length >= index + 1 && params[index] != null; - } - - protected int getParamLength(int index) { - return params[index].length; - } - - protected byte[] getParam(int index) { - return params[index]; - } - public ResponseAPDU getAPDU() { return resp; } @@ -92,6 +86,22 @@ public abstract class Response { return sw2; } + public int getNumSW() { + return numSW; + } + + protected boolean hasParam(int index) { + return params.length >= index + 1 && params[index] != null; + } + + protected int getParamLength(int index) { + return params[index].length; + } + + protected byte[] getParam(int index) { + return params[index]; + } + public int getLength() { return resp.getNr(); } @@ -104,6 +114,21 @@ public abstract class Response { public abstract String toString(); + public static String toString(List<Response> responses) { + StringBuilder out = new StringBuilder(); + for (Response r : responses) { + String message = r.toString(); + String suffix; + if (r.getNumSW() == 1) { + suffix = String.format("%s", Util.getPrintError(r.getSW1())); + } else { + suffix = String.format("%s %s", Util.getPrintError(r.getSW1()), Util.getPrintError(r.getSW2())); + } + out.append(String.format("%-55s: %s\n", message, suffix)); + } + return out.toString(); + } + /** * */ @@ -133,8 +158,32 @@ public abstract class Response { } else { key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; } - //TODO general response.toString alignment + 2 SWs - return String.format("Allocated %s %db %s: %#x", key, keyLength, field, getSW1()); + return 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 String.format("Cleared %s", key); } } @@ -145,15 +194,15 @@ public abstract class Response { private byte keyPair; private byte export; private byte curve; - private short params; + private short parameters; private short corrupted; - protected Set(ResponseAPDU response, long time, byte keyPair, byte export, byte curve, short params, short corrupted) { + protected Set(ResponseAPDU response, long time, byte keyPair, byte export, byte curve, short parameters, short corrupted) { super(response, time); this.keyPair = keyPair; this.export = export; this.curve = curve; - this.params = params; + this.parameters = parameters; this.corrupted = corrupted; int pairs = 0; @@ -168,14 +217,14 @@ public abstract class Response { int paramCount = 0; short mask = EC_Consts.PARAMETER_FP; while (mask <= EC_Consts.PARAMETER_K) { - if ((mask & params) != 0) { + if ((mask & parameters) != 0) { paramCount++; } mask = (short) (mask << 1); } int other = 0; - if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0 && (params & EC_Consts.PARAMETER_W) != 0) other++; - if ((export & ECTesterApplet.EXPORT_PRIVATE) != 0 && (params & EC_Consts.PARAMETER_S) != 0) other++; + if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0 && (parameters & EC_Consts.PARAMETER_W) != 0) other++; + if ((export & ECTesterApplet.EXPORT_PRIVATE) != 0 && (parameters & EC_Consts.PARAMETER_S) != 0) other++; parse(pairs, exported * keys * paramCount + exported * other); } @@ -189,7 +238,7 @@ public abstract class Response { if (key == keyPair && param == mask) { return index; } - if ((params & mask) != 0 && (key & export) != 0) { + if ((parameters & mask) != 0 && (key & export) != 0) { if (mask == EC_Consts.PARAMETER_W) { if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0) index++; @@ -209,7 +258,11 @@ public abstract class Response { } public boolean hasParameter(byte keyPair, short param) { - return !((export & keyPair) == 0 || (params & param) == 0) && getIndex(keyPair, param) != -1; + if ((export & keyPair) == 0 || (parameters & param) == 0) { + return false; + } + int index = getIndex(keyPair, param); + return index != -1 && hasParam(index); } public byte[] getParameter(byte keyPair, short param) { @@ -236,8 +289,7 @@ public abstract class Response { } else { key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; } - //TODO general response.toString alignment + 2 SWs - return String.format("Set %s curve parameters on %s: %#x", name, key, getSW1()); + return String.format("Set %s curve parameters on %s", name, key); } } @@ -301,13 +353,15 @@ public abstract class Response { public boolean hasPublic(byte keyPair) { if ((export & ECTesterApplet.EXPORT_PUBLIC) == 0 || (export & keyPair) == 0) return false; - return getIndex((byte) (keyPair | ECTesterApplet.EXPORT_PUBLIC)) != -1; + int index = getIndex((byte) (keyPair | ECTesterApplet.EXPORT_PUBLIC)); + return index != -1 && hasParam(index); } public boolean hasPrivate(byte keyPair) { if ((export & ECTesterApplet.EXPORT_PRIVATE) == 0 || (export & keyPair) == 0) return false; - return getIndex((byte) (keyPair | ECTesterApplet.EXPORT_PRIVATE)) != -1; + int index = getIndex((byte) (keyPair | ECTesterApplet.EXPORT_PRIVATE)); + return index != -1 && hasParam(index); } public byte[] getPublic(byte keyPair) { @@ -330,8 +384,7 @@ public abstract class Response { } else { key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; } - //TODO general response.toString alignment + 2 SWs - return String.format("Generated %s: %#x", key, getSW1()); + return String.format("Generated %s", key); } } @@ -368,8 +421,7 @@ public abstract class Response { String pub = pubkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; String validity = invalid != 0 ? "invalid" : "valid"; - //TODO general response.toString alignment + 2SWs - return String.format("ECDH of %s pubkey and %s privkey(%s point): %#x", pub, priv, validity, getSW1()); + return String.format("ECDH of %s pubkey and %s privkey(%s point)", pub, priv, validity); } } @@ -402,8 +454,7 @@ public abstract class Response { public String toString() { String key = keyPair == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; String data = raw == null ? "random" : "provided"; - //TODO general response.toString alignment + 2 SWs - return String.format("ECDSA with %s keypair(%s data): %#x", key, data, getSW1()); + return String.format("ECDSA with %s keypair(%s data)", key, data); } } |
