aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/reader/ECTester.java
diff options
context:
space:
mode:
authorJ08nY2017-03-06 22:56:34 +0100
committerJ08nY2017-03-06 22:56:34 +0100
commit117b35545288df5b01173d36bde451b414d31d66 (patch)
treeadd0ecbc48e95a398662bef9e41670df1c61243e /src/cz/crcs/ectester/reader/ECTester.java
parent66bd8469e56cbe7c6bed823b376229a02ecdd37d (diff)
downloadECTester-117b35545288df5b01173d36bde451b414d31d66.tar.gz
ECTester-117b35545288df5b01173d36bde451b414d31d66.tar.zst
ECTester-117b35545288df5b01173d36bde451b414d31d66.zip
Added support for named curves (in jar).
- Doesn't work well while simulating, some weird memory bug. Will investigate. - Has categories of curves, more will be added.
Diffstat (limited to 'src/cz/crcs/ectester/reader/ECTester.java')
-rw-r--r--src/cz/crcs/ectester/reader/ECTester.java219
1 files changed, 169 insertions, 50 deletions
diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java
index f55e943..6ccbbbe 100644
--- a/src/cz/crcs/ectester/reader/ECTester.java
+++ b/src/cz/crcs/ectester/reader/ECTester.java
@@ -23,18 +23,22 @@ package cz.crcs.ectester.reader;
import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.data.EC_Category;
+import cz.crcs.ectester.data.EC_Data;
+import cz.crcs.ectester.reader.ec.EC_Curve;
+import cz.crcs.ectester.reader.ec.EC_Key;
+import cz.crcs.ectester.reader.ec.EC_Keypair;
+import cz.crcs.ectester.reader.ec.EC_Params;
import javacard.security.KeyPair;
import org.apache.commons.cli.*;
import javax.smartcardio.CardException;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.IOException;
+import java.io.*;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
/**
* Reader part of ECTester, a tool for testing Elliptic curve support on javacards.
@@ -46,6 +50,7 @@ public class ECTester {
private CardMngr cardManager = null;
private DirtyLogger systemOutLogger = null;
+ private EC_Data dataDB = null;
//Options
private int optBits;
@@ -86,7 +91,6 @@ public class ECTester {
private void run(String[] args) {
try {
-
CommandLine cli = parseArgs(args);
//if help, print and quit
@@ -94,22 +98,35 @@ public class ECTester {
help();
return;
}
+
+ dataDB = new EC_Data();
+ //if list, print and quit
+ if (cli.hasOption("list-named")) {
+ Map<String, EC_Category> categories = dataDB.getCategories();
+ for (EC_Category cat : categories.values()) {
+ System.out.println("\t- " + cat.getName() + ": " + (cat.getDesc() == null ? "" : cat.getDesc()));
+ }
+ return;
+ }
+
//if not, read other options first, into attributes, then do action
if (!readOptions(cli)) {
return;
}
+
+ //init CardManager
cardManager = new CardMngr(optSimulate);
//connect or simulate connection
if (optSimulate) {
if (!cardManager.prepareLocalSimulatorApplet(AID, INSTALL_DATA, ECTesterApplet.class)) {
System.err.println("Failed to establish a simulator.");
- return;
+ System.exit(1);
}
} else {
if (!cardManager.connectToCardSelect()) {
System.err.println("Failed to connect to card.");
- return;
+ System.exit(1);
}
cardManager.send(SELECT_ECTESTERAPPLET);
}
@@ -171,6 +188,7 @@ public class ECTester {
* -t / --test
* -dh / --ecdh
* -dsa / --ecdsa [data_file]
+ * --list-named
*
* Options:
* -b / --bit-size [b] // -a / --all
@@ -179,19 +197,26 @@ public class ECTester {
* -f2m / --binary-field
*
* -u / --custom
- * -n / --named [cat/id|id|cat]
+ * -n / --named [cat/id]
* -c / --curve [curve_file] field,a,b,gx,gy,r,k
*
* -pub / --public [pubkey_file] wx,wy
+ * -npub / --named-public [cat/id]
+ *
* -priv / --private [privkey_file] s
+ * -npriv / --named-private [cat/id]
+ *
* -k / --key [key_file] wx,wy,s
+ * -nk / --named-key [cat/id]
*
* -o / --output [output_file]
+ * -f / --fresh
* -s / --simulate
*/
OptionGroup actions = new OptionGroup();
actions.setRequired(true);
actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build());
+ actions.addOption(Option.builder().longOpt("list-named").desc("Print the list of supported named curves and keys.").build());
actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build());
actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build());
actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support.").build());
@@ -205,7 +230,7 @@ public class ECTester {
opts.addOptionGroup(size);
OptionGroup curve = new OptionGroup();
- curve.addOption(Option.builder("n").longOpt("named").desc("Use a named curve.").hasArg().argName("[cat/id|id|cat]").build());
+ curve.addOption(Option.builder("n").longOpt("named").desc("Use a named curve.").hasArg().argName("cat/id").build());
curve.addOption(Option.builder("c").longOpt("curve").desc("Use curve from file [curve_file] (field,a,b,gx,gy,r,k).").hasArg().argName("curve_file").build());
curve.addOption(Option.builder("u").longOpt("custom").desc("Use a custom curve(applet-side embedded, SECG curves).").build());
opts.addOptionGroup(curve);
@@ -214,12 +239,12 @@ public class ECTester {
opts.addOption(Option.builder("f2m").longOpt("binary-field").desc("Use binary field curve.").build());
OptionGroup pub = new OptionGroup();
- pub.addOption(Option.builder("npub").longOpt("named-public").desc("Use public key from KeyDB: [cat/id|cat|id]").hasArg().argName("[cat/id|id|cat]").build());
+ pub.addOption(Option.builder("npub").longOpt("named-public").desc("Use public key from KeyDB: [cat/id]").hasArg().argName("cat/id").build());
pub.addOption(Option.builder("pub").longOpt("public").desc("Use public key from file [pubkey_file] (wx,wy).").hasArg().argName("pubkey_file").build());
opts.addOptionGroup(pub);
OptionGroup priv = new OptionGroup();
- priv.addOption(Option.builder("npriv").longOpt("named-private").desc("Use private key from KeyDB: [cat/id|id|cat]").hasArg().argName("[cat/id|id|cat]").build());
+ priv.addOption(Option.builder("npriv").longOpt("named-private").desc("Use private key from KeyDB: [cat/id]").hasArg().argName("cat/id").build());
priv.addOption(Option.builder("priv").longOpt("private").desc("Use private key from file [privkey_file] (s).").hasArg().argName("privkey_file").build());
opts.addOptionGroup(priv);
@@ -282,6 +307,10 @@ public class ECTester {
return false;
}
+ if (optKey != null && optNamedKey != null || optPublic != null && optNamedPublic != null || optPrivate != null && optNamedPrivate != null) {
+ System.err.println("You cannot specify both a named key and a key file.");
+ return false;
+ }
if (cli.hasOption("export")) {
if (optPrimeField == optBinaryField) {
@@ -292,6 +321,10 @@ public class ECTester {
System.err.println("Keys should not be specified when exporting curve params.");
return false;
}
+ if (optNamedCurve != null || optCustomCurve || optCurveFile != null) {
+ System.err.println("Specifying a curve for curve export makes no sense.");
+ return false;
+ }
if (optOutput == null) {
System.err.println("You have to specify an output file for curve parameter export.");
return false;
@@ -381,19 +414,30 @@ public class ECTester {
*/
private void export() throws CardException, IOException {
byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- //skip cofactor in domain export, since it doesnt need to be initialized for the key to be initialized.
- //and generally isn't initialized on cards with default domain params(TODO, check, is it assumed to be ==1?)
- short domain = (short) ((optPrimeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M) ^ EC_Consts.PARAMETER_K);
- List<Response> sent = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ List<Response> sent = new LinkedList<>();
+ sent.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass).send());
sent.add(new Command.Clear(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
sent.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
- Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send();
+
+ // Cofactor generally isn't set on the default curve parameters on cards,
+ // since its not necessary for ECDH, only ECDHC which not many cards implement
+ // TODO: check if its assumend to be == 1?
+ short domain_all = optPrimeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
+ short domain = (short) (domain_all ^ EC_Consts.PARAMETER_K);
+ Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain_all).send();
+ if (!export.successful()) {
+ export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send();
+ }
sent.add(export);
systemOutLogger.println(Response.toString(sent));
- ECParams.writeFile(optOutput, ECParams.expand(export.getParams(), domain));
+ EC_Params exported = new EC_Params(domain, export.getParams());
+
+ FileOutputStream out = new FileOutputStream(optOutput);
+ exported.writeCSV(out);
+ out.close();
}
/**
@@ -405,7 +449,7 @@ public class ECTester {
private void generate() throws CardException, IOException {
byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass).send();
List<Command> curve = prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass);
FileWriter keysFile = new FileWriter(optOutput);
@@ -454,24 +498,58 @@ public class ECTester {
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) {
- commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_FP));
+ if (optNamedCurve != null) {
+ Map<String, EC_Curve> curves = dataDB.getObjects(EC_Curve.class, optNamedCurve);
+ if (optPrimeField) {
+ for (Map.Entry<String, EC_Curve> entry : curves.entrySet()) {
+ EC_Curve curve = entry.getValue();
+ if (curve.getField() == KeyPair.ALG_EC_FP) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), KeyPair.ALG_EC_FP));
+ byte[] external = curve.flatten();
+ commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, external));
+ commands.addAll(testCurve(curve.getBits(), KeyPair.ALG_EC_FP));
+ }
+ }
}
- }
- if (optBinaryField) {
- //iterate over binary curve sizes used: EC_Consts.F2M_SIZES
- for (short keyLength : EC_Consts.F2M_SIZES) {
- commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_F2M));
+ if (optBinaryField) {
+ for (Map.Entry<String, EC_Curve> entry : curves.entrySet()) {
+ EC_Curve curve = entry.getValue();
+ if (curve.getField() == KeyPair.ALG_EC_F2M) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), KeyPair.ALG_EC_F2M));
+ byte[] external = curve.flatten();
+ commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, external));
+ commands.addAll(testCurve(curve.getBits(), KeyPair.ALG_EC_F2M));
+ }
+ }
+ }
+ } else {
+ if (optPrimeField) {
+ //iterate over prime curve sizes used: EC_Consts.FP_SIZES
+ for (short keyLength : EC_Consts.FP_SIZES) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP));
+ commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP));
+ 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) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M));
+ commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M));
+ commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_F2M));
+ }
}
}
} else {
if (optPrimeField) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_FP));
+ commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_FP));
commands.addAll(testCurve((short) optBits, KeyPair.ALG_EC_FP));
}
if (optBinaryField) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_F2M));
+ commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_F2M));
commands.addAll(testCurve((short) optBits, KeyPair.ALG_EC_F2M));
}
}
@@ -487,7 +565,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(prepareKeyPair(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass));
+ List<Response> ecdh = new LinkedList<>();
+ ecdh.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass).send());
ecdh.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass)));
if (optPublic != null || optPrivate != null || optKey != null) {
@@ -520,7 +599,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(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ List<Response> ecdsa = new LinkedList<>();
+ ecdsa.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass).send());
ecdsa.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass)));
Response keys;
@@ -558,18 +638,6 @@ public class ECTester {
}
/**
- * @param keyPair which keyPair/s (local/remote) to allocate
- * @param keyLength key length to allocate
- * @param keyClass key class to allocate
- * @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
@@ -586,9 +654,28 @@ public class ECTester {
} else if (optNamedCurve != null) {
// Set a named curve.
// parse optNamedCurve -> cat / id | cat | id
+ EC_Curve curve = dataDB.getObject(EC_Curve.class, optNamedCurve);
+ if (curve == null) {
+ throw new IOException("Curve could no be found.");
+ }
+ if (curve.getBits() != keyLength) {
+ throw new IOException("Curve bits mismatch: " + curve.getBits() + " vs " + keyLength + " entered.");
+ }
+
+ byte[] external = curve.flatten();
+ if (external == null) {
+ throw new IOException("Couldn't read named curve data.");
+ }
+ commands.add(new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, domainParams, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, external));
} else if (optCurveFile != null) {
// Set curve loaded from a file
- byte[] external = ECParams.flatten(domainParams, ECParams.readFile(optCurveFile));
+ EC_Params params = new EC_Params(domainParams);
+
+ FileInputStream in = new FileInputStream(optCurveFile);
+ params.readCSV(in);
+ in.close();
+
+ byte[] external = params.flatten();
if (external == null) {
throw new IOException("Couldn't read the curve file correctly.");
}
@@ -609,25 +696,59 @@ public class ECTester {
private Command prepareKey(byte keyPair) throws IOException {
short params = EC_Consts.PARAMETERS_NONE;
byte[] data = null;
- if (optKey != null) {
+
+ if (optKey != null || optNamedKey != null) {
params |= EC_Consts.PARAMETERS_KEYPAIR;
- data = ECParams.flatten(EC_Consts.PARAMETERS_KEYPAIR, ECParams.readFile(optKey));
+ EC_Params keypair;
+ if (optKey != null) {
+ keypair = new EC_Params(EC_Consts.PARAMETERS_KEYPAIR);
+
+ FileInputStream in = new FileInputStream(optKey);
+ keypair.readCSV(in);
+ in.close();
+ } else {
+ keypair = dataDB.getObject(EC_Keypair.class, optNamedKey);
+ }
+
+ data = keypair.flatten();
if (data == null) {
throw new IOException("Couldn't read the key file correctly.");
}
}
- if (optPublic != null) {
+ if (optPublic != null || optNamedPublic != null) {
params |= EC_Consts.PARAMETER_W;
- byte[] pubkey = ECParams.flatten(EC_Consts.PARAMETER_W, ECParams.readFile(optPublic));
+ EC_Params pub;
+ if (optPublic != null) {
+ pub = new EC_Params(EC_Consts.PARAMETER_W);
+
+ FileInputStream in = new FileInputStream(optPublic);
+ pub.readCSV(in);
+ in.close();
+ } else {
+ pub = dataDB.getObject(EC_Key.Public.class, optNamedPublic);
+ }
+
+ byte[] pubkey = pub.flatten();
if (pubkey == null) {
throw new IOException("Couldn't read the key file correctly.");
}
data = pubkey;
}
- if (optPrivate != null) {
+ if (optPrivate != null || optNamedPrivate != null) {
params |= EC_Consts.PARAMETER_S;
- byte[] privkey = ECParams.flatten(EC_Consts.PARAMETER_S, ECParams.readFile(optPrivate));
+ EC_Params priv;
+ if (optPublic != null) {
+ priv = new EC_Params(EC_Consts.PARAMETER_S);
+
+ FileInputStream in = new FileInputStream(optPrivate);
+ priv.readCSV(in);
+ in.close();
+ } else {
+ priv = dataDB.getObject(EC_Key.Public.class, optNamedPrivate);
+ }
+
+ byte[] privkey = priv.flatten();
if (privkey == null) {
throw new IOException("Couldn't read the key file correctly.");
}
@@ -644,8 +765,6 @@ public class ECTester {
*/
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));
commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, (byte) 0));
commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, (byte) 1));