diff options
| author | J08nY | 2017-01-17 22:35:02 +0100 |
|---|---|---|
| committer | J08nY | 2017-01-17 22:35:02 +0100 |
| commit | b99a1484397cc1b64a4798fa4a73b0782d99f18e (patch) | |
| tree | 53e58d9ef7ce7f00e13e9c7271964454abfbdc25 /src | |
| parent | e113197a41fc1961a9649cb3a96a18d7a9eab58f (diff) | |
| download | ECTester-b99a1484397cc1b64a4798fa4a73b0782d99f18e.tar.gz ECTester-b99a1484397cc1b64a4798fa4a73b0782d99f18e.tar.zst ECTester-b99a1484397cc1b64a4798fa4a73b0782d99f18e.zip | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECTesterApplet.java | 107 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/CardMngr.java | 32 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/ECTester.java | 178 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/ParamReader.java | 5 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/Util.java | 35 |
5 files changed, 248 insertions, 109 deletions
diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index f304196..dd13fc3 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -1,4 +1,25 @@ /* + * Copyright (c) 2016-2017 Petr Svenda <petr@svenda.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* * PACKAGEID: 4C6162616B417070 * APPLETID: 4C6162616B4170706C6574 */ @@ -11,6 +32,8 @@ import javacard.security.KeyPair; import javacard.security.RandomData; /** + * Reader part of ECTester, a tool for testing Elliptic curve support on javacards. + * * @author Petr Svenda petr@svenda.com * @author Jan Jancar johny@neuromancer.sk */ @@ -125,10 +148,10 @@ public class ECTesterApplet extends Applet { } /** - * Allocate local and remote keypairs. + * Allocates local and remote keyPairs. * returns allocate SWs * - * @param apdu P1 = byte keypair (KEYPAIR_* | ...) + * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) * P2 = * DATA = short keyLength * byte keyClass @@ -137,32 +160,32 @@ public class ECTesterApplet extends Applet { apdu.setIncomingAndReceive(); byte[] apdubuf = apdu.getBuffer(); - byte keypair = apdubuf[ISO7816.OFFSET_P1]; + byte keyPair = apdubuf[ISO7816.OFFSET_P1]; short keyLength = Util.getShort(apdubuf, ISO7816.OFFSET_CDATA); byte keyClass = apdubuf[ISO7816.OFFSET_CDATA + 2]; - short len = allocate(keypair, keyLength, keyClass, apdubuf, (short) 0); + short len = allocate(keyPair, keyLength, keyClass, apdubuf, (short) 0); apdu.setOutgoingAndSend((short) 0, len); } /** - * @param keypair which keypair to use, local/remote (KEYPAIR_* | ...) + * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...) * @param keyLength key length to set * @param keyClass key class to allocate * @param buffer apdu buffer * @param offset offset into apdu buffer * @return length of data written to the buffer */ - private short allocate(byte keypair, short keyLength, byte keyClass, byte[] buffer, short offset) { + private short allocate(byte keyPair, short keyLength, byte keyClass, byte[] buffer, short offset) { short length = 0; - if ((keypair & KEYPAIR_LOCAL) != 0) { + if ((keyPair & KEYPAIR_LOCAL) != 0) { localKeypair = keyGenerator.allocatePair(keyClass, keyLength); Util.setShort(buffer, offset, keyGenerator.getSW()); length += 2; } - if ((keypair & KEYPAIR_REMOTE) != 0) { + if ((keyPair & KEYPAIR_REMOTE) != 0) { remoteKeypair = keyGenerator.allocatePair(keyClass, keyLength); Util.setShort(buffer, (short) (offset + length), keyGenerator.getSW()); length += 2; @@ -172,10 +195,10 @@ public class ECTesterApplet extends Applet { } /** - * Sets curve parameters on local and remote keypairs. + * Sets curve parameters on local and remote keyPairs. * returns setCurve SWs, set params if export * - * @param apdu P1 = byte keypair (KEYPAIR_* | ...) + * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) * P2 = byte export (EXPORT_* | KEYPAIR_*) * DATA = byte curve (EC_Consts.CURVE_*) * short params (EC_Consts.PARAMETER_* | ...) @@ -183,7 +206,7 @@ public class ECTesterApplet extends Applet { * byte corruptionType (EC_Consts.CORRUPTION_*) * <p> * if curveID = CURVE_EXTERNAL: - * [short param_length, byte[] param], + * [short paramLength, byte[] param], * for all params in params, * in order: field,a,b,g,r,k,w,s */ @@ -191,7 +214,7 @@ public class ECTesterApplet extends Applet { apdu.setIncomingAndReceive(); byte[] apdubuf = apdu.getBuffer(); - byte keypair = apdubuf[ISO7816.OFFSET_P1]; + byte keyPair = apdubuf[ISO7816.OFFSET_P1]; byte export = apdubuf[ISO7816.OFFSET_P2]; byte curve = apdubuf[ISO7816.OFFSET_CDATA]; short params = Util.getShort(apdubuf, (short) (ISO7816.OFFSET_CDATA + 1)); @@ -200,9 +223,9 @@ public class ECTesterApplet extends Applet { short len = 0; - if ((keypair & KEYPAIR_LOCAL) != 0) + if ((keyPair & KEYPAIR_LOCAL) != 0) len += set(localKeypair, curve, params, corruptedParams, corruptionType, apdubuf, (short) (ISO7816.OFFSET_CDATA + 6), (short) 0); - if ((keypair & KEYPAIR_REMOTE) != 0) + if ((keyPair & KEYPAIR_REMOTE) != 0) len += set(remoteKeypair, curve, params, corruptedParams, corruptionType, apdubuf, (short) (ISO7816.OFFSET_CDATA + 6), len); if ((export & KEYPAIR_LOCAL) != 0) len += export(localKeypair, export, params, apdubuf, len); @@ -213,7 +236,7 @@ public class ECTesterApplet extends Applet { } /** - * @param keypair KeyPair to set params on + * @param keyPair KeyPair to set params on * @param curve curve to set (EC_Consts.CURVE_*) * @param params parameters to set (EC_Consts.PARAMETER_* | ...) * @param corrupted parameters to corrupt (EC_Consts.PARAMETER_* | ...) @@ -223,7 +246,7 @@ public class ECTesterApplet extends Applet { * @param outOffset output offset in buffer * @return length of data written to the buffer */ - private short set(KeyPair keypair, byte curve, short params, short corrupted, byte corruption, byte[] buffer, short inOffset, short outOffset) { + private short set(KeyPair keyPair, byte curve, short params, short corrupted, byte corruption, byte[] buffer, short inOffset, short outOffset) { short sw = ISO7816.SW_NO_ERROR; switch (curve) { @@ -232,38 +255,38 @@ public class ECTesterApplet extends Applet { break; case EC_Consts.CURVE_external: //external - sw = keyGenerator.setExternalCurve(keypair, params, buffer, inOffset); + sw = keyGenerator.setExternalCurve(keyPair, params, buffer, inOffset); break; default: //custom - sw = keyGenerator.setCurve(keypair, curve, params, ramArray, (short) 0); + sw = keyGenerator.setCurve(keyPair, curve, params, ramArray, (short) 0); break; } if (sw == ISO7816.SW_NO_ERROR) - sw = keyGenerator.corruptCurve(keypair, corrupted, corruption, ramArray, (short) 0); + sw = keyGenerator.corruptCurve(keyPair, corrupted, corruption, ramArray, (short) 0); Util.setShort(buffer, outOffset, sw); return 2; } /** - * Generates the local and remote keypairs. + * Generates the local and remote keyPairs. * returns generate SWs, pubkey and privkey if export * - * @param apdu P1 = byte keypair (KEYPAIR_* | ...) + * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) * P2 = byte export (EXPORT_* | KEYPAIR_*) */ private void insGenerate(APDU apdu) { apdu.setIncomingAndReceive(); byte[] apdubuf = apdu.getBuffer(); - byte keypair = apdubuf[ISO7816.OFFSET_P1]; + byte keyPair = apdubuf[ISO7816.OFFSET_P1]; byte export = apdubuf[ISO7816.OFFSET_P2]; short len = 0; - if ((keypair & KEYPAIR_LOCAL) != 0) + if ((keyPair & KEYPAIR_LOCAL) != 0) len += generate(localKeypair, apdubuf, (short) 0); - if ((keypair & KEYPAIR_REMOTE) != 0) + if ((keyPair & KEYPAIR_REMOTE) != 0) len += generate(remoteKeypair, apdubuf, len); if ((export & KEYPAIR_LOCAL) != 0) len += export(localKeypair, export, (short) (EC_Consts.PARAMETER_W | EC_Consts.PARAMETER_S), apdubuf, len); @@ -274,44 +297,44 @@ public class ECTesterApplet extends Applet { } /** - * @param keypair KeyPair to generate + * @param keyPair KeyPair to generate * @param buffer buffer to write sw to * @param offset output offset in buffer * @return length of data written to the buffer */ - private short generate(KeyPair keypair, byte[] buffer, short offset) { - short sw = keyGenerator.generatePair(keypair); + private short generate(KeyPair keyPair, byte[] buffer, short offset) { + short sw = keyGenerator.generatePair(keyPair); Util.setShort(buffer, offset, sw); return 2; } /** - * @param keypair KeyPair to export from + * @param keyPair KeyPair to export from * @param export which key to export from (EXPORT_PUBLIC | EXPORT_PRIVATE) * @param params which params to export (EC_Consts.PARAMETER_* | ...) * @param buffer buffer to export params to * @param offset output offset in buffer * @return length of data written to the buffer */ - private short export(KeyPair keypair, byte export, short params, byte[] buffer, short offset) { + private short export(KeyPair keyPair, byte export, short params, byte[] buffer, short offset) { short length = 0; if ((export & EXPORT_PUBLIC) != 0) { //export params from public - length += keyGenerator.exportParameters(keypair, ECKeyGenerator.KEY_PUBLIC, params, buffer, offset); + length += keyGenerator.exportParameters(keyPair, ECKeyGenerator.KEY_PUBLIC, params, buffer, offset); } if ((export & EXPORT_PRIVATE) != 0) { //export params from private - length += keyGenerator.exportParameters(keypair, ECKeyGenerator.KEY_PRIVATE, params, buffer, (short) (offset + length)); + length += keyGenerator.exportParameters(keyPair, ECKeyGenerator.KEY_PRIVATE, params, buffer, (short) (offset + length)); } return length; } /** - * Does ECDH, between the pubkey specified in P1(local/remote) and the privkey specified in P2(local/remote). + * Performs ECDH, between the pubkey specified in P1(local/remote) and the privkey specified in P2(local/remote). * returns deriveSecret SW, if export != 0 => short secretlen, byte[] secret * * @param apdu P1 = byte pubkey (KEYPAIR_*) @@ -334,8 +357,8 @@ public class ECTesterApplet extends Applet { } /** - * @param pubkey keypair to use for public key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) - * @param privkey keypair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) + * @param pubkey keyPair to use for public key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) + * @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) * @param export whether to export ECDH secret * @param invalid whether to invalidate the pubkey before ECDH * @param buffer buffer to write sw to, and export ECDH secret if (export & EXPORT_ECDH) != 0 @@ -369,35 +392,35 @@ public class ECTesterApplet extends Applet { } /** - * Does and ECDSA signature and verification on data provided, using the keypair in P1(local/remote). + * Performs ECDSA signature and verification on data provided or random, using the keyPair in P1(local/remote). * returns ecdsa SW, if export != 0 => short signature_length, byte[] signature * - * @param apdu P1 = byte keypair (KEYPAIR_*) + * @param apdu P1 = byte keyPair (KEYPAIR_*) * P2 = byte export (EXPORT_SIG || 0) - * DATA = short data_length (00 = random data generated, !00 = data length) + * DATA = short dataLength (00 = random data generated, !00 = data length) * byte[] data */ private void insECDSA(APDU apdu) { apdu.setIncomingAndReceive(); byte[] apdubuf = apdu.getBuffer(); - byte keypair = apdubuf[ISO7816.OFFSET_P1]; + byte keyPair = apdubuf[ISO7816.OFFSET_P1]; byte export = apdubuf[ISO7816.OFFSET_P2]; - short len = ecdsa(keypair, export, apdubuf, ISO7816.OFFSET_CDATA, (short) 0); + short len = ecdsa(keyPair, export, apdubuf, ISO7816.OFFSET_CDATA, (short) 0); apdu.setOutgoingAndSend((short) 0, len); } /** - * @param keypair keypair to use for signing and verification (KEYPAIR_LOCAL || KEYPAIR_REMOTE) + * @param keyPair keyPair to use for signing and verification (KEYPAIR_LOCAL || KEYPAIR_REMOTE) * @param export whether to export ECDSA signature * @param buffer buffer to write sw to, and export ECDSA signature if (export & EXPORT_SIG) != 0 * @param inOffset input offset in buffer * @param outOffset output offset in buffer * @return length of data written to the buffer */ - private short ecdsa(byte keypair, byte export, byte[] buffer, short inOffset, short outOffset) { + private short ecdsa(byte keyPair, byte export, byte[] buffer, short inOffset, short outOffset) { short length = 0; short dataLength = Util.getShort(buffer, inOffset); @@ -409,7 +432,7 @@ public class ECTesterApplet extends Applet { Util.arrayCopyNonAtomic(buffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength); } - KeyPair sign = ((keypair & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair; + KeyPair sign = ((keyPair & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair; short signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0); Util.setShort(buffer, outOffset, keyTester.getSW()); diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index aab7da9..9cdd055 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -2,11 +2,11 @@ package cz.crcs.ectester.reader; import com.licel.jcardsim.io.CAD; import com.licel.jcardsim.io.JavaxSmartCardInterface; -import java.util.List; -import java.util.Scanner; import javacard.framework.AID; import javax.smartcardio.*; +import java.util.List; +import java.util.Scanner; /** * @author Petr Svenda petr@svenda.com @@ -16,16 +16,16 @@ public class CardMngr { private CardTerminal terminal = null; private CardChannel channel = null; private Card card = null; - + // Simulator related attributes private CAD cad = null; private JavaxSmartCardInterface simulator = null; private boolean simulate = false; - + 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}; + (byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x07, (byte) 0xa0, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x18, (byte) 0x43, (byte) 0x4d}; public static final byte OFFSET_CLA = 0x00; public static final byte OFFSET_INS = 0x01; @@ -42,7 +42,7 @@ public class CardMngr { this(false); } - public CardMngr(boolean simulate) { + public CardMngr(boolean simulate) { this.simulate = simulate; } @@ -70,14 +70,14 @@ public class CardMngr { //reset the card System.out.println(Util.bytesToHex(card.getATR().getBytes())); - + cardFound = true; } } return cardFound; } - + public boolean connectToCardSelect() throws CardException { if (simulate) return true; @@ -113,7 +113,7 @@ public class CardMngr { terminal = terminalList.get(answ); } } - + if (terminal != null) { card = terminal.connect("*"); System.out.println("card: " + card); @@ -190,15 +190,15 @@ public class CardMngr { apdu[OFFSET_LC] = (byte) 0x00; ResponseAPDU resp = send(apdu); - - System.out.println("Response: " + Integer.toHexString(resp.getSW())); - + + System.out.println("Response: " + Integer.toHexString(resp.getSW())); + if (resp.getSW() != 0x6D00) { // Note: 0x6D00 is SW_INS_NOT_SUPPORTED // something? } } } - + public static List<CardTerminal> getReaderList() { try { TerminalFactory factory = TerminalFactory.getDefault(); @@ -242,14 +242,14 @@ public class CardMngr { CommandAPDU commandAPDU = new CommandAPDU(apdu); return sendAPDU(commandAPDU); } - + public boolean prepareLocalSimulatorApplet(byte[] appletAIDArray, byte[] installData, Class appletClass) { System.setProperty("com.licel.jcardsim.terminal.type", "2"); cad = new CAD(System.getProperties()); simulator = (JavaxSmartCardInterface) cad.getCardInterface(); AID appletAID = new AID(appletAIDArray, (short) 0, (byte) appletAIDArray.length); - AID appletAIDRes = simulator.installApplet(appletAID, appletClass, installData, (short) 0, (byte) installData.length); + AID appletAIDRes = simulator.installApplet(appletAID, appletClass, installData, (short) 0, (byte) installData.length); return simulator.selectApplet(appletAID); } diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java index 6d1be42..1ee0015 100644 --- a/src/cz/crcs/ectester/reader/ECTester.java +++ b/src/cz/crcs/ectester/reader/ECTester.java @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2016-2017 Petr Svenda <petr@svenda.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package cz.crcs.ectester.reader; import cz.crcs.ectester.applet.ECTesterApplet; @@ -8,14 +29,17 @@ import org.apache.commons.cli.*; import javax.smartcardio.CardException; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; +import java.io.File; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; +import java.nio.file.Files; import java.util.ArrayList; import java.util.List; /** + * Reader part of ECTester, a tool for testing Elliptic curve support on javacards. + * * @author Petr Svenda petr@svenda.com * @author Jan Jancar johny@neuromancer.sk */ @@ -23,7 +47,6 @@ public class ECTester { private CardMngr cardManager = null; private DirtyLogger systemOutLogger = null; - private FileOutputStream outputFile = null; //Options private int optBits; @@ -56,7 +79,7 @@ public class ECTester { private static final byte[] ALLOCATE = { (byte) 0xB0, (byte) 0x5a, //INS ALLOCATE - (byte) 0x00, //P1 *byte keypair + (byte) 0x00, //P1 *byte keyPair (byte) 0x00, //P2 (byte) 0x03, //LC (byte) 0x00, //DATA *short keyLength @@ -67,7 +90,7 @@ public class ECTester { private static final byte[] SET = { (byte) 0xB0, (byte) 0x5B, //INS SET - (byte) 0x00, //P1 *byte keypair + (byte) 0x00, //P1 *byte keyPair (byte) 0x00, //P2 *byte export (byte) 0x06, //LC (byte) 0x00, //DATA *byte curve @@ -82,7 +105,7 @@ public class ECTester { private static final byte[] GENERATE = { (byte) 0xB0, (byte) 0x5C, //INS GENERATE - (byte) 0x00, //P1 *byte keypair + (byte) 0x00, //P1 *byte keyPair (byte) 0x00, //P2 *byte export (byte) 0x00 //LC }; @@ -90,7 +113,7 @@ public class ECTester { private static final byte[] ECDH = { (byte) 0xB0, (byte) 0x5D, //INS ECDH - (byte) 0x00, //P1 *byte keypair + (byte) 0x00, //P1 *byte keyPair (byte) 0x00, //P2 *byte export (byte) 0x01, //LC (byte) 0x00 //DATA *byte valid @@ -99,7 +122,7 @@ public class ECTester { private static final byte[] ECDSA = { (byte) 0xB0, (byte) 0x5E, //INS ECDSA - (byte) 0x00, //P1 *byte keypair + (byte) 0x00, //P1 *byte keyPair (byte) 0x00, //P2 *byte export (byte) 0x00, //LC //DATA [*short dataLength, byte[] data] @@ -177,6 +200,13 @@ public class ECTester { } } + /** + * Parses command-line options. + * + * @param args cli arguments + * @return parsed CommandLine object + * @throws ParseException if there are any problems encountered while parsing the command line tokens + */ private CommandLine parseArgs(String[] args) throws ParseException { /* * Actions: @@ -221,7 +251,7 @@ public class ECTester { 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("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("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build()); @@ -301,6 +331,19 @@ public class ECTester { } } else if (cli.hasOption("ecdsa")) { + if (optPrimeField == optBinaryField) { + System.err.print("Need to specify field with -fp or -f2m. (not both)"); + return false; + } + if (optAll) { + System.err.println("You have to specify curve bit-size with -b"); + return false; + } + if ((optPublic == null) != (optPrivate == null)) { + System.err.println("You have cannot only specify a part of a keypair."); + return false; + } + optECDSASign = cli.getOptionValue("ecdsa"); } @@ -316,9 +359,10 @@ public class ECTester { } /** - * Generates EC keypairs and outputs them to output file. - * @throws CardException - * @throws IOException + * Generates EC keyPairs and outputs them to output file. + * + * @throws CardException if APDU transmission fails + * @throws IOException if an IO error occurs when writing to key file. */ private void generate() throws CardException, IOException { byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; @@ -360,9 +404,10 @@ public class ECTester { } /** - * Tests + * Tests Elliptic curve support for a given curve/curves. */ private void test() { + //TODO if (optAll) { if (optPrimeField) { //iterate over prime curve sizes used: EC_Consts.FP_SIZES @@ -404,9 +449,10 @@ public class ECTester { } /** + * Performs ECDH key exchange. * - * @throws IOException - * @throws CardException + * @throws CardException if APDU transmission fails + * @throws IOException if an IO error occurs when writing to key file. */ private void ecdh() throws IOException, CardException { byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; @@ -425,24 +471,55 @@ public class ECTester { CommandAPDU ecdh = insECDH(ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_ECDH, (byte) 0); ResponseAPDU response = cardManager.send(ecdh); - //TODO output ecdh + //TODO print response SWs/error codes + //TODO output to file } /** + * Performs ECDSA signature, on random or provided data. + * + * @throws CardException if APDU transmission fails + * @throws IOException if an IO error occurs when writing to key file. */ - private void ecdsa() { - //TODO + private void ecdsa() throws CardException, IOException { + byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; + CommandAPDU[] curve = prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass); + cardManager.send(curve); + + if (optKey != null || (optPublic != null && optPrivate != null)) { + CommandAPDU set = prepareKey(ECTesterApplet.KEYPAIR_LOCAL); + cardManager.send(set); + } else { + CommandAPDU generate = insGenerate(ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_NONE); + cardManager.send(generate); + } + + //read file, if asked to sign + byte[] data = null; + if (optECDSASign != null) { + File in = new File(optECDSASign); + long len = in.length(); + if (len == 0) { + throw new FileNotFoundException("File " + optECDSASign + " not found."); + } + data = Files.readAllBytes(in.toPath()); + } + + CommandAPDU ecdsa = insECDSA(ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_SIG, data); + ResponseAPDU response = cardManager.send(ecdsa); + //TODO print response SWs/error codes + //TODO output to file } /** * Creates the INS_ALLOCATE instruction. * - * @param keyPair - * @param keyLength - * @param keyClass + * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...) + * @param keyLength key length to set + * @param keyClass key class to allocate * @return apdu to send */ - private CommandAPDU insAllocate(byte keyPair, short keyLength, byte keyClass) throws CardException { + private CommandAPDU insAllocate(byte keyPair, short keyLength, byte keyClass) { byte[] data = new byte[]{0, 0, keyClass}; Util.setShort(data, 0, keyLength); @@ -452,13 +529,13 @@ public class ECTester { /** * Creates the INS_SET instruction. * - * @param keyPair - * @param export - * @param curve - * @param params - * @param corrupted - * @param corruption - * @param external + * @param keyPair which keyPair to set params on, local/remote (KEYPAIR_* || ...) + * @param export whether to export set params from keyPair + * @param curve curve to set (EC_Consts.CURVE_*) + * @param params parameters to set (EC_Consts.PARAMETER_* | ...) + * @param corrupted parameters to corrupt (EC_Consts.PARAMETER_* | ...) + * @param corruption corruption type (EC_Consts.CORRUPTION_*) + * @param external external curve data, can be null * @return apdu to send */ private CommandAPDU insSet(byte keyPair, byte export, byte curve, short params, short corrupted, byte corruption, byte[] external) { @@ -478,8 +555,8 @@ public class ECTester { /** * Creates the INS_GENERATE instruction. * - * @param keyPair - * @param export + * @param keyPair which keyPair to generate, local/remote (KEYPAIR_* || ...) + * @param export whether to export generated keys from keyPair * @return apdu to send */ private CommandAPDU insGenerate(byte keyPair, byte export) { @@ -489,10 +566,10 @@ public class ECTester { /** * Creates the INS_ECDH instruction. * - * @param pubkey - * @param privkey - * @param export - * @param invalid + * @param pubkey keyPair to use for public key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) + * @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE) + * @param export whether to export ECDH secret + * @param invalid whether to invalidate the pubkey before ECDH * @return apdu to send */ private CommandAPDU insECDH(byte pubkey, byte privkey, byte export, byte invalid) { @@ -504,9 +581,9 @@ public class ECTester { /** * Creates the INS_ECDSA instruction. * - * @param keyPair - * @param export - * @param raw + * @param keyPair keyPair to use for signing and verification (KEYPAIR_LOCAL || KEYPAIR_REMOTE) + * @param export whether to export ECDSA signature + * @param raw data to sign, can be null, in which case random data is signed. * @return apdu to send */ private CommandAPDU insECDSA(byte keyPair, byte export, byte[] raw) { @@ -521,14 +598,13 @@ public class ECTester { } /** - * @param keyPair - * @param keyLength - * @param keyClass - * @return - * @throws CardException - * @throws FileNotFoundException + * @param keyPair which keyPair/s (local/remote) to set curve domain parameters on + * @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. + * @throws IOException if curve file cannot be found/opened */ - private CommandAPDU[] prepareCurve(byte keyPair, short keyLength, byte keyClass) throws CardException, IOException { + private CommandAPDU[] prepareCurve(byte keyPair, short keyLength, byte keyClass) throws IOException { List<CommandAPDU> commands = new ArrayList<>(); commands.add(insAllocate(keyPair, keyLength, keyClass)); @@ -548,11 +624,11 @@ public class ECTester { } /** - * @param keypair - * @return - * @throws IOException + * @param keyPair which keyPair/s to set the key params on + * @return a CommandAPDU setting params loaded on the keyPair/s + * @throws IOException if any of the key files cannot be found/opened */ - private CommandAPDU prepareKey(byte keypair) throws IOException { + private CommandAPDU prepareKey(byte keyPair) throws IOException { short params = EC_Consts.PARAMETERS_NONE; byte[] data = null; if (optKey != null) { @@ -570,9 +646,13 @@ public class ECTester { } if (data == null && params != EC_Consts.PARAMETERS_NONE) { + /* + TODO: this is not correct, in case (optPublic != null) and (optPrivate != null), + only one can actually load(return not null from ParamReader.flatten) and an exception will not be thrown + */ throw new IOException("Couldn't read the key file correctly."); } - return insSet(keypair, ECTesterApplet.EXPORT_NONE, EC_Consts.CURVE_external, params, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, data); + return insSet(keyPair, ECTesterApplet.EXPORT_NONE, EC_Consts.CURVE_external, params, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, data); } public static void main(String[] args) { diff --git a/src/cz/crcs/ectester/reader/ParamReader.java b/src/cz/crcs/ectester/reader/ParamReader.java index 5232326..ca14d2d 100644 --- a/src/cz/crcs/ectester/reader/ParamReader.java +++ b/src/cz/crcs/ectester/reader/ParamReader.java @@ -9,6 +9,7 @@ import java.util.Scanner; import java.util.regex.Pattern; /** + * * @author Jan Jancar johny@neuromancer.sk */ public class ParamReader { @@ -18,7 +19,7 @@ public class ParamReader { * Flattens params read from String[] data into a byte[] with their lengths prepended as short entries. * @param params (EC_Consts.PARAMETER_* | ...) * @param data data read by readString, readFile, readResource - * @return byte[] with params flattened + * @return byte[] with params flattened, or null */ public static byte[] flatten(short params, String[] data) { if (!validate(data)) { @@ -42,7 +43,7 @@ public class ParamReader { if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) { //read another param (the y coord) and put into X962 format. byte[] y = parse(data[i + 1]); - param = Util.concatenate(new byte[]{4}, param, y); + param = Util.concatenate(new byte[]{4}, param, y);//<- ugly but works! i++; } if (param.length == 0) diff --git a/src/cz/crcs/ectester/reader/Util.java b/src/cz/crcs/ectester/reader/Util.java index aa0dfd5..1464728 100644 --- a/src/cz/crcs/ectester/reader/Util.java +++ b/src/cz/crcs/ectester/reader/Util.java @@ -1,6 +1,12 @@ package cz.crcs.ectester.reader; +import cz.crcs.ectester.applet.ECTesterApplet; +import javacard.framework.ISO7816; +import javacard.security.CryptoException; + /** + * Utility class, some byte/hex manipulation, convenient byte[] methods. + * * @author Petr Svenda petr@svenda.com * @author Jan Jancar johny@neuromancer.sk */ @@ -79,4 +85,33 @@ public class Util { } return out; } + + public static String getPrintError(short code) { + if (code == ISO7816.SW_NO_ERROR) { + return "OK\t(0x9000)"; + } else { + String codeStr = "unknown"; + switch (code) { + case CryptoException.ILLEGAL_VALUE: + codeStr = "ILLEGAL_VALUE"; + break; + case CryptoException.UNINITIALIZED_KEY: + codeStr = "UNINITIALIZED_KEY"; + break; + case CryptoException.NO_SUCH_ALGORITHM: + codeStr = "NO_SUCH_ALG"; + break; + case CryptoException.INVALID_INIT: + codeStr = "INVALID_INIT"; + break; + case CryptoException.ILLEGAL_USE: + codeStr = "ILLEGAL_USE"; + break; + case ECTesterApplet.SW_SIG_VERIFY_FAIL: + codeStr = "SIG_VERIFY_FAIL"; + break; + } + return String.format("fail\t(%s,\t0x%4x)", codeStr, code); + } + } } |
