aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cz/crcs/ectester/applet/ECTesterApplet.java107
-rw-r--r--src/cz/crcs/ectester/reader/CardMngr.java32
-rw-r--r--src/cz/crcs/ectester/reader/ECTester.java178
-rw-r--r--src/cz/crcs/ectester/reader/ParamReader.java5
-rw-r--r--src/cz/crcs/ectester/reader/Util.java35
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);
+ }
+ }
}