aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cz/crcs/ectester/common/util/CardUtil.java17
-rw-r--r--src/cz/crcs/ectester/common/util/ECUtil.java41
-rw-r--r--src/cz/crcs/ectester/reader/ECTesterReader.java22
-rw-r--r--src/cz/crcs/ectester/reader/command/Command.java68
4 files changed, 108 insertions, 40 deletions
diff --git a/src/cz/crcs/ectester/common/util/CardUtil.java b/src/cz/crcs/ectester/common/util/CardUtil.java
index 7483c32..a761949 100644
--- a/src/cz/crcs/ectester/common/util/CardUtil.java
+++ b/src/cz/crcs/ectester/common/util/CardUtil.java
@@ -31,6 +31,23 @@ public class CardUtil {
}
}
+ public static String getSigHashAlgo(byte sigType) {
+ switch (sigType) {
+ case EC_Consts.Signature_ALG_ECDSA_SHA:
+ return "SHA-1";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_224:
+ return "SHA-224";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_256:
+ return "SHA-256";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_384:
+ return "SHA-384";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_512:
+ return "SHA-512";
+ default:
+ return null;
+ }
+ }
+
public static byte getKA(String name) {
switch (name) {
case "DH":
diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java
index 1706ca0..0260e95 100644
--- a/src/cz/crcs/ectester/common/util/ECUtil.java
+++ b/src/cz/crcs/ectester/common/util/ECUtil.java
@@ -3,9 +3,16 @@ package cz.crcs.ectester.common.util;
import cz.crcs.ectester.applet.EC_Consts;
import cz.crcs.ectester.common.ec.*;
import cz.crcs.ectester.data.EC_Store;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1StreamParser;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERSequenceParser;
+import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.*;
@@ -196,7 +203,7 @@ public class ECUtil {
public static ECPublicKey toPublicKey(EC_Key.Public pubkey) {
EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, pubkey.getCurve());
if (curve == null) {
- throw new IllegalArgumentException("pubkey curve nor found: " + pubkey.getCurve());
+ throw new IllegalArgumentException("pubkey curve not found: " + pubkey.getCurve());
}
return new RawECPublicKey(toPoint(pubkey), curve.toSpec());
}
@@ -204,7 +211,7 @@ public class ECUtil {
public static ECPrivateKey toPrivateKey(EC_Key.Private privkey) {
EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, privkey.getCurve());
if (curve == null) {
- throw new IllegalArgumentException("privkey curve nor found: " + privkey.getCurve());
+ throw new IllegalArgumentException("privkey curve not found: " + privkey.getCurve());
}
return new RawECPrivateKey(toScalar(privkey), curve.toSpec());
}
@@ -212,7 +219,7 @@ public class ECUtil {
public static KeyPair toKeyPair(EC_Keypair kp) {
EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, kp.getCurve());
if (curve == null) {
- throw new IllegalArgumentException("keypair curve nor found: " + kp.getCurve());
+ throw new IllegalArgumentException("keypair curve not found: " + kp.getCurve());
}
ECPublicKey pubkey = new RawECPublicKey(toPoint(kp), curve.toSpec());
ECPrivateKey privkey = new RawECPrivateKey(toScalar(kp), curve.toSpec());
@@ -222,4 +229,32 @@ public class ECUtil {
public static byte[] toDERSignature(byte[] r, byte[] s) {
return ByteUtil.concatenate(new byte[]{0x30, (byte) (r.length + s.length + 4), 0x02, (byte) r.length}, r, new byte[]{0x02, (byte) s.length}, s);
}
+
+ public static BigInteger[] fromDERSignature(byte[] signature) throws IOException {
+ ASN1StreamParser parser = new ASN1StreamParser(signature);
+ DERSequence sequence = (DERSequence) ((DERSequenceParser) parser.readObject()).getLoadedObject();
+ ASN1Integer r = (ASN1Integer) sequence.getObjectAt(0);
+ ASN1Integer s = (ASN1Integer) sequence.getObjectAt(1);
+ return new BigInteger[]{r.getPositiveValue(), s.getPositiveValue()};
+ }
+
+ public static BigInteger recoverSignatureNonce(byte[] signature, byte[] data, BigInteger privkey, ECParameterSpec params, String hashType) {
+ try {
+ int bitSize = params.getOrder().bitLength();
+ MessageDigest md = MessageDigest.getInstance(hashType);
+ byte[] hash = md.digest(data);
+ BigInteger hashInt = new BigInteger(1, hash);
+ hashInt = hashInt.and(BigInteger.ONE.shiftLeft(bitSize + 1).subtract(BigInteger.ONE));
+
+ BigInteger[] sigPair = fromDERSignature(signature);
+ BigInteger r = sigPair[0];
+ BigInteger s = sigPair[1];
+
+ BigInteger rd = privkey.multiply(r).mod(params.getOrder());
+ BigInteger hrd = hashInt.add(rd).mod(params.getOrder());
+ return s.modInverse(params.getOrder()).multiply(hrd).mod(params.getOrder());
+ } catch (NoSuchAlgorithmException | IOException nsae) {
+ return null;
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java
index c442ec1..fe44709 100644
--- a/src/cz/crcs/ectester/reader/ECTesterReader.java
+++ b/src/cz/crcs/ectester/reader/ECTesterReader.java
@@ -26,10 +26,12 @@ import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.applet.EC_Consts;
import cz.crcs.ectester.common.cli.CLITools;
import cz.crcs.ectester.common.cli.Colors;
+import cz.crcs.ectester.common.ec.EC_Curve;
import cz.crcs.ectester.common.output.OutputLogger;
import cz.crcs.ectester.common.output.TestWriter;
import cz.crcs.ectester.common.util.ByteUtil;
import cz.crcs.ectester.common.util.CardUtil;
+import cz.crcs.ectester.common.util.ECUtil;
import cz.crcs.ectester.common.util.FileUtil;
import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.reader.command.Command;
@@ -40,16 +42,22 @@ import cz.crcs.ectester.reader.test.*;
import javacard.framework.ISO7816;
import javacard.security.KeyPair;
import org.apache.commons.cli.*;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1StreamParser;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERSequenceParser;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.smartcardio.CardException;
import javax.smartcardio.ResponseAPDU;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
+import java.math.BigInteger;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.security.Security;
+import java.security.spec.ECParameterSpec;
import java.util.*;
import java.util.jar.Manifest;
@@ -670,7 +678,7 @@ public class ECTesterReader {
OutputStreamWriter out = FileUtil.openFiles(cfg.outputs);
if (out != null) {
- out.write("index;signTime;verifyTime;data;pubW;privS;signature;valid\n");
+ out.write("index;signTime;verifyTime;data;pubW;privS;signature;nonce;valid\n");
}
Command.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR);
@@ -719,7 +727,17 @@ public class ECTesterReader {
String pub = ByteUtil.bytesToHex(exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
String priv = ByteUtil.bytesToHex(exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
String dataString = (cfg.input != null) ? "" : ByteUtil.bytesToHex(data, false);
- out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%d\n", done, sign.getDuration() / 1000000, verify.getDuration() / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), verify.successful() ? 1 : 0));
+ BigInteger privkey = new BigInteger(1, exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S));
+ EC_Curve actualCurve = Command.findCurve(EC_Store.getInstance(), cfg, cfg.bits, keyClass);
+ String k = "";
+ if (actualCurve != null) {
+ ECParameterSpec params = actualCurve.toSpec();
+ BigInteger kValue = ECUtil.recoverSignatureNonce(signature, data, privkey, params, CardUtil.getSigHashAlgo(cfg.ECDSAType));
+ if (kValue != null) {
+ k = ByteUtil.bytesToHex(kValue.toByteArray(), false);
+ }
+ }
+ out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, sign.getDuration() / 1000000, verify.getDuration() / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k,verify.successful() ? 1 : 0));
}
++done;
diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java
index 1b1ec33..a92017e 100644
--- a/src/cz/crcs/ectester/reader/command/Command.java
+++ b/src/cz/crcs/ectester/reader/command/Command.java
@@ -54,23 +54,11 @@ public abstract class Command implements Cloneable {
return (Command) super.clone();
}
-
- /**
- * @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 Command to send in order to prepare the curve on the keypairs.
- * @throws IOException if curve file cannot be found/opened
- */
- public static Command prepareCurve(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException {
-
+ public static EC_Curve findCurve(EC_Store dataStore, ECTesterReader.Config cfg, short keyLength, byte keyClass) throws IOException {
if (cfg.customCurve) {
- // Set custom curve (one of the SECG curves embedded applet-side)
- short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
- return new Command.Set(cardManager, keyPair, EC_Consts.getCurve(keyLength, keyClass), domainParams, null);
+ byte curveId = EC_Consts.getCurve(keyLength, keyClass);
+ return dataStore.getObject(EC_Curve.class, "secg", CardUtil.getCurveName(curveId));
} else if (cfg.namedCurve != null) {
- // Set a named curve.
- // parse cfg.namedCurve -> cat / id | cat | id
EC_Curve curve = dataStore.getObject(EC_Curve.class, cfg.namedCurve);
if (curve == null) {
throw new IOException("Curve could no be found.");
@@ -81,34 +69,44 @@ public abstract class Command implements Cloneable {
if (curve.getField() != keyClass) {
throw new IOException("Curve field mismatch.");
}
-
- byte[] external = curve.flatten();
- if (external == null) {
- throw new IOException("Couldn't read named curve data.");
- }
- return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, curve.getParams(), external);
+ return curve;
} else if (cfg.curveFile != null) {
- // Set curve loaded from a file
EC_Curve curve = new EC_Curve(null, keyLength, keyClass);
FileInputStream in = new FileInputStream(cfg.curveFile);
curve.readCSV(in);
in.close();
+ return curve;
+ } else {
+ return null;
+ }
+ }
- byte[] external = curve.flatten();
- if (external == null) {
- throw new IOException("Couldn't read the curve file correctly.");
+
+ /**
+ * @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 Command to send in order to prepare the curve on the keypairs.
+ * @throws IOException if curve file cannot be found/opened
+ */
+ public static Command prepareCurve(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException {
+ if (cfg.customCurve) {
+ // Set custom curve (one of the SECG curves embedded applet-side)
+ short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
+ return new Command.Set(cardManager, keyPair, EC_Consts.getCurve(keyLength, keyClass), domainParams, null);
+ }
+
+ EC_Curve curve = findCurve(dataStore, cfg, keyLength, keyClass);
+ if ((curve == null || curve.flatten() == null) && (cfg.namedCurve != null || cfg.curveFile != null)) {
+ if (cfg.namedCurve != null) {
+ throw new IOException("Couldn't read named curve data.");
}
- return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, curve.getParams(), external);
- } else {
- // Set default curve
- /* This command was generally causing problems for simulating on jcardsim.
- * Since there, .clearKey() resets all the keys values, even the domain.
- * This might break some other stuff.. But should not.
- */
- //commands.add(new Command.Clear(cardManager, keyPair));
+ throw new IOException("Couldn't read the curve file correctly.");
+ } else if (curve == null) {
return null;
}
+ return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, curve.getParams(), curve.flatten());
}
@@ -896,8 +894,8 @@ public abstract class Command implements Cloneable {
*/
public static class SetDryRunMode extends Command {
private byte dryRunMode;
+
/**
- *
* @param cardManager
* @param dryRunMode
*/
@@ -918,7 +916,7 @@ public abstract class Command implements Cloneable {
@Override
public String getDescription() {
- return (dryRunMode == ECTesterApplet.MODE_NORMAL ? "Disable" : "Enable") + " dry run mode";
+ return (dryRunMode == ECTesterApplet.MODE_NORMAL ? "Disable" : "Enable") + " dry run mode";
}
}
}