aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJ08nY2019-02-22 10:29:28 +0100
committerJ08nY2019-02-22 10:29:28 +0100
commitb6daaef0a884bd154a848bdb73919b3b82d0df98 (patch)
tree7a4034a9862324b0988050cfe9f13c66d633daec /src
parent687a09baf6fd858d393b8f284cfe7236b52d7457 (diff)
parentfea5c7b1cbd539b105b42c4bde65d0b9b6f0b8fc (diff)
downloadECTester-b6daaef0a884bd154a848bdb73919b3b82d0df98.tar.gz
ECTester-b6daaef0a884bd154a848bdb73919b3b82d0df98.tar.zst
ECTester-b6daaef0a884bd154a848bdb73919b3b82d0df98.zip
Diffstat (limited to 'src')
-rw-r--r--src/cz/crcs/ectester/applet/AppletBase.java37
-rw-r--r--src/cz/crcs/ectester/applet/ECKeyGenerator.java154
-rw-r--r--src/cz/crcs/ectester/applet/ECKeyTester.java63
-rw-r--r--src/cz/crcs/ectester/common/ec/EC_Category.java2
-rw-r--r--src/cz/crcs/ectester/common/output/BaseTextTestWriter.java6
-rw-r--r--src/cz/crcs/ectester/common/util/CardUtil.java17
-rw-r--r--src/cz/crcs/ectester/common/util/ECUtil.java74
-rw-r--r--src/cz/crcs/ectester/data/cofactor/cofactor128p56467.csv1
-rw-r--r--src/cz/crcs/ectester/data/cofactor/cofactor128p65521.csv1
-rw-r--r--src/cz/crcs/ectester/data/cofactor/cofactor128p65535.csv1
-rw-r--r--src/cz/crcs/ectester/data/cofactor/cofactor192p2.csv1
-rw-r--r--src/cz/crcs/ectester/data/cofactor/cofactor192p4.csv1
-rw-r--r--src/cz/crcs/ectester/data/cofactor/cofactor192p8.csv1
-rw-r--r--src/cz/crcs/ectester/data/cofactor/curves.xml30
-rw-r--r--src/cz/crcs/ectester/data/cofactor/keys.xml19
-rw-r--r--src/cz/crcs/ectester/data/degenerate/cofactor.xml123
-rw-r--r--src/cz/crcs/ectester/data/degenerate/keys.xml2
-rw-r--r--src/cz/crcs/ectester/data/invalid/secg/secp128r1.xml6
-rw-r--r--src/cz/crcs/ectester/data/misc/results.xml4
-rw-r--r--src/cz/crcs/ectester/data/twist/cofactor/cofactor128p4.xml44
-rw-r--r--src/cz/crcs/ectester/data/twist/cofactor/cofactor160p4.xml74
-rw-r--r--src/cz/crcs/ectester/data/twist/keys.xml6
-rw-r--r--src/cz/crcs/ectester/data/wycheproof/keys.xml86
-rw-r--r--src/cz/crcs/ectester/reader/CardMngr.java11
-rw-r--r--src/cz/crcs/ectester/reader/ECTesterReader.java185
-rw-r--r--src/cz/crcs/ectester/reader/command/Command.java122
-rw-r--r--src/cz/crcs/ectester/reader/output/TextTestWriter.java1
-rw-r--r--src/cz/crcs/ectester/reader/output/XMLTestWriter.java2
-rw-r--r--src/cz/crcs/ectester/reader/response/Response.java22
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCofactorSuite.java5
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCompositeSuite.java14
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCompressionSuite.java4
-rw-r--r--src/cz/crcs/ectester/reader/test/CardDefaultSuite.java9
-rw-r--r--src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java19
-rw-r--r--src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java67
-rw-r--r--src/cz/crcs/ectester/reader/test/CardInvalidSuite.java14
-rw-r--r--src/cz/crcs/ectester/reader/test/CardMiscSuite.java2
-rw-r--r--src/cz/crcs/ectester/reader/test/CardSignatureSuite.java2
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTestSuite.java22
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java86
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTwistSuite.java16
-rw-r--r--src/cz/crcs/ectester/reader/test/CommandTest.java2
-rw-r--r--src/cz/crcs/ectester/reader/test/PerformanceTest.java42
-rw-r--r--src/cz/crcs/ectester/standalone/ECTesterStandalone.java94
-rw-r--r--src/cz/crcs/ectester/standalone/consts/SignatureIdent.java1
45 files changed, 1205 insertions, 290 deletions
diff --git a/src/cz/crcs/ectester/applet/AppletBase.java b/src/cz/crcs/ectester/applet/AppletBase.java
index 48e7785..c77294e 100644
--- a/src/cz/crcs/ectester/applet/AppletBase.java
+++ b/src/cz/crcs/ectester/applet/AppletBase.java
@@ -24,6 +24,7 @@ public abstract class AppletBase extends Applet {
public static final byte INS_ALLOCATE_KA = (byte) 0x76;
public static final byte INS_ALLOCATE_SIG = (byte) 0x77;
public static final byte INS_GET_INFO = (byte) 0x78;
+ public static final byte INS_SET_DRY_RUN_MODE = (byte) 0x79;
// PARAMETERS for P1 and P2
public static final byte KEYPAIR_LOCAL = (byte) 0x01;
@@ -31,6 +32,8 @@ public abstract class AppletBase extends Applet {
public static final byte KEYPAIR_BOTH = KEYPAIR_LOCAL | KEYPAIR_REMOTE;
public static final byte EXPORT_TRUE = (byte) 0xff;
public static final byte EXPORT_FALSE = (byte) 0x00;
+ public static final byte MODE_NORMAL = (byte) 0xaa;
+ public static final byte MODE_DRY_RUN = (byte) 0xbb;
// STATUS WORDS
public static final short SW_SIG_VERIFY_FAIL = (short) 0x0ee1;
@@ -159,6 +162,9 @@ public abstract class AppletBase extends Applet {
case INS_GET_INFO:
length = insGetInfo(apdu);
break;
+ case INS_SET_DRY_RUN_MODE:
+ length = insSetDryRunMode(apdu);
+ break;
default:
// The INS code is not supported by the dispatcher
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
@@ -545,6 +551,26 @@ public abstract class AppletBase extends Applet {
}
/**
+ * Set the dry run mode of the applet.
+ *
+ * @param apdu P1 = byte mode (MODE_* || ...)
+ * @return length of response
+ */
+ private short insSetDryRunMode(APDU apdu) {
+ byte[] apdubuf = apdu.getBuffer();
+ byte mode = apduArray[ISO7816.OFFSET_P1];
+
+ short len = 0;
+ if (mode == MODE_NORMAL) {
+ len = setDryRunMode(apdubuf, false, (short) 0);
+ }
+ if (mode == MODE_DRY_RUN) {
+ len = setDryRunMode(apdubuf, true, (short) 0);
+ }
+ return len;
+ }
+
+ /**
* @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...)
* @param keyLength key length to set
* @param keyClass key class to allocate
@@ -883,4 +909,15 @@ public abstract class AppletBase extends Applet {
length += 2;
return length;
}
+
+ private short setDryRunMode(byte[] buffer, boolean mode, short offset) {
+ if (keyTester != null) {
+ keyTester.setDryRun(mode);
+ }
+ if (keyGenerator != null) {
+ keyGenerator.setDryRun(mode);
+ }
+ Util.setShort(buffer, offset, ISO7816.SW_NO_ERROR);
+ return 2;
+ }
}
diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
index 4326752..30910ca 100644
--- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java
+++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
@@ -14,6 +14,7 @@ import javacard.security.KeyPair;
public class ECKeyGenerator {
private short sw = ISO7816.SW_NO_ERROR;
+ private boolean dryRun = false;
/**
* @param keyClass
@@ -24,12 +25,14 @@ public class ECKeyGenerator {
sw = ISO7816.SW_NO_ERROR;
KeyPair ecKeyPair = null;
try {
- ecKeyPair = new KeyPair(keyClass, keyLength);
+ if (!dryRun) {
+ ecKeyPair = new KeyPair(keyClass, keyLength);
- if (ecKeyPair.getPublic() == null || ecKeyPair.getPrivate() == null) {
- try {
- ecKeyPair.genKeyPair();
- } catch (Exception ignored) {
+ if (ecKeyPair.getPublic() == null || ecKeyPair.getPrivate() == null) {
+ try {
+ ecKeyPair.genKeyPair();
+ } catch (Exception ignored) {
+ }
}
}
} catch (CardRuntimeException ce) {
@@ -46,8 +49,10 @@ public class ECKeyGenerator {
public short clearPair(KeyPair keypair, byte key) {
try {
sw = AppletUtil.keypairCheck(keypair);
- if ((key & EC_Consts.KEY_PUBLIC) != 0) keypair.getPublic().clearKey();
- if ((key & EC_Consts.KEY_PRIVATE) != 0) keypair.getPrivate().clearKey();
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) keypair.getPublic().clearKey();
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) keypair.getPrivate().clearKey();
+ }
} catch (CardRuntimeException ce) {
sw = ce.getReason();
}
@@ -61,7 +66,9 @@ public class ECKeyGenerator {
public short generatePair(KeyPair keypair) {
try {
sw = AppletUtil.keypairCheck(keypair);
- keypair.genKeyPair();
+ if (!dryRun) {
+ keypair.genKeyPair();
+ }
} catch (CardRuntimeException ce) {
sw = ce.getReason();
}
@@ -187,25 +194,35 @@ public class ECKeyGenerator {
try {
sw = AppletUtil.keypairCheck(keypair);
- ECPublicKey ecPublicKey = (ECPublicKey) keypair.getPublic();
- ECPrivateKey ecPrivateKey = (ECPrivateKey) keypair.getPrivate();
+ ECPublicKey ecPublicKey = null;
+ ECPrivateKey ecPrivateKey = null;
+ if (!dryRun) {
+ ecPublicKey = (ECPublicKey) keypair.getPublic();
+ ecPrivateKey = (ECPrivateKey) keypair.getPrivate();
+ }
switch (param) {
case EC_Consts.PARAMETER_FP:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldFP(data, offset, length);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldFP(data, offset, length);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldFP(data, offset, length);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldFP(data, offset, length);
+ }
break;
case EC_Consts.PARAMETER_F2M:
if (length == 4) {
short i = Util.getShort(data, (short) (offset + 2));
- if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i);
+ }
} else if (length == 8) {
short i1 = Util.getShort(data, (short) (offset + 2));
short i2 = Util.getShort(data, (short) (offset + 4));
short i3 = Util.getShort(data, (short) (offset + 6));
- if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3);
+ }
// if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i3, i2, i1);
// if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i3, i2, i1);
} else {
@@ -213,20 +230,28 @@ public class ECKeyGenerator {
}
break;
case EC_Consts.PARAMETER_A:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setA(data, offset, length);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setA(data, offset, length);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setA(data, offset, length);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setA(data, offset, length);
+ }
break;
case EC_Consts.PARAMETER_B:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setB(data, offset, length);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setB(data, offset, length);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setB(data, offset, length);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setB(data, offset, length);
+ }
break;
case EC_Consts.PARAMETER_G:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setG(data, offset, length);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setG(data, offset, length);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setG(data, offset, length);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setG(data, offset, length);
+ }
break;
case EC_Consts.PARAMETER_R:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setR(data, offset, length);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setR(data, offset, length);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setR(data, offset, length);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setR(data, offset, length);
+ }
break;
case EC_Consts.PARAMETER_K:
short k = 0;
@@ -238,14 +263,20 @@ public class ECKeyGenerator {
} else if (length == 1) {
k = data[offset];
}
- if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setK(k);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setK(k);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setK(k);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setK(k);
+ }
break;
case EC_Consts.PARAMETER_S:
- if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setS(data, offset, length);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setS(data, offset, length);
+ }
break;
case EC_Consts.PARAMETER_W:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setW(data, offset, length);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setW(data, offset, length);
+ }
break;
default:
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
@@ -310,54 +341,75 @@ public class ECKeyGenerator {
short length = 0;
try {
sw = AppletUtil.keypairCheck(keypair);
- ECPublicKey ecPublicKey = (ECPublicKey) keypair.getPublic();
- ECPrivateKey ecPrivateKey = (ECPrivateKey) keypair.getPrivate();
+
+ ECPublicKey ecPublicKey = null;
+ ECPrivateKey ecPrivateKey = null;
+ if (!dryRun) {
+ ecPublicKey = (ECPublicKey) keypair.getPublic();
+ ecPrivateKey = (ECPrivateKey) keypair.getPrivate();
+ }
switch (param) {
case EC_Consts.PARAMETER_FP:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getField(outputBuffer, outputOffset);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getField(outputBuffer, outputOffset);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0)
+ length = ecPublicKey.getField(outputBuffer, outputOffset);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0)
+ length = ecPrivateKey.getField(outputBuffer, outputOffset);
+ }
break;
case EC_Consts.PARAMETER_F2M:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0 && !dryRun) {
Util.setShort(outputBuffer, outputOffset, ecPublicKey.getSize());
length = 2;
length += ecPublicKey.getField(outputBuffer, (short) (outputOffset + 2));
}
- if ((key & EC_Consts.KEY_PRIVATE) != 0) {
+ if ((key & EC_Consts.KEY_PRIVATE) != 0 && !dryRun) {
Util.setShort(outputBuffer, outputOffset, ecPrivateKey.getSize());
length = 2;
length += ecPrivateKey.getField(outputBuffer, (short) (outputOffset + 2));
}
break;
case EC_Consts.PARAMETER_A:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getA(outputBuffer, outputOffset);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getA(outputBuffer, outputOffset);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getA(outputBuffer, outputOffset);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getA(outputBuffer, outputOffset);
+ }
break;
case EC_Consts.PARAMETER_B:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getB(outputBuffer, outputOffset);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getB(outputBuffer, outputOffset);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getB(outputBuffer, outputOffset);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getB(outputBuffer, outputOffset);
+ }
break;
case EC_Consts.PARAMETER_G:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getG(outputBuffer, outputOffset);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getG(outputBuffer, outputOffset);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getG(outputBuffer, outputOffset);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getG(outputBuffer, outputOffset);
+ }
break;
case EC_Consts.PARAMETER_R:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getR(outputBuffer, outputOffset);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getR(outputBuffer, outputOffset);
+ if (!dryRun) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getR(outputBuffer, outputOffset);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getR(outputBuffer, outputOffset);
+ }
break;
case EC_Consts.PARAMETER_K:
- length = 2;
- if ((key & EC_Consts.KEY_PUBLIC) != 0)
- Util.setShort(outputBuffer, outputOffset, ecPublicKey.getK());
- if ((key & EC_Consts.KEY_PRIVATE) != 0)
- Util.setShort(outputBuffer, outputOffset, ecPrivateKey.getK());
+ if (!dryRun) {
+ length = 2;
+ if ((key & EC_Consts.KEY_PUBLIC) != 0)
+ Util.setShort(outputBuffer, outputOffset, ecPublicKey.getK());
+ if ((key & EC_Consts.KEY_PRIVATE) != 0)
+ Util.setShort(outputBuffer, outputOffset, ecPrivateKey.getK());
+ }
break;
case EC_Consts.PARAMETER_W:
- if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getW(outputBuffer, outputOffset);
+ if ((key & EC_Consts.KEY_PUBLIC) != 0 && !dryRun)
+ length = ecPublicKey.getW(outputBuffer, outputOffset);
break;
case EC_Consts.PARAMETER_S:
- if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getS(outputBuffer, outputOffset);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0 && !dryRun)
+ length = ecPrivateKey.getS(outputBuffer, outputOffset);
break;
default:
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
@@ -439,4 +491,8 @@ public class ECKeyGenerator {
public short getSW() {
return sw;
}
+
+ public void setDryRun(boolean dryRun) {
+ this.dryRun = dryRun;
+ }
}
diff --git a/src/cz/crcs/ectester/applet/ECKeyTester.java b/src/cz/crcs/ectester/applet/ECKeyTester.java
index 0e46971..89590d0 100644
--- a/src/cz/crcs/ectester/applet/ECKeyTester.java
+++ b/src/cz/crcs/ectester/applet/ECKeyTester.java
@@ -18,12 +18,15 @@ public class ECKeyTester {
private short sigType = 0;
private short sw = ISO7816.SW_NO_ERROR;
+ private boolean dryRun = false;
public short allocateKA(byte algorithm) {
sw = ISO7816.SW_NO_ERROR;
try {
- ecKeyAgreement = KeyAgreement.getInstance(algorithm, false);
- kaType = algorithm;
+ if (!dryRun) {
+ ecKeyAgreement = KeyAgreement.getInstance(algorithm, false);
+ kaType = algorithm;
+ }
} catch (CardRuntimeException ce) {
sw = ce.getReason();
}
@@ -33,8 +36,10 @@ public class ECKeyTester {
public short allocateSig(byte algorithm) {
sw = ISO7816.SW_NO_ERROR;
try {
- ecdsaSignature = Signature.getInstance(algorithm, false);
- sigType = algorithm;
+ if (!dryRun) {
+ ecdsaSignature = Signature.getInstance(algorithm, false);
+ sigType = algorithm;
+ }
} catch (CardRuntimeException ce) {
sw = ce.getReason();
}
@@ -61,11 +66,13 @@ public class ECKeyTester {
sw = AppletUtil.kaCheck(ecKeyAgreement);
sw = AppletUtil.keypairCheck(privatePair);
sw = AppletUtil.keypairCheck(publicPair);
- short pubkeyLength = ((ECPublicKey) publicPair.getPublic()).getW(pubkeyBuffer, pubkeyOffset);
- ecKeyAgreement.init(privatePair.getPrivate());
+ if (!dryRun) {
+ short pubkeyLength = ((ECPublicKey) publicPair.getPublic()).getW(pubkeyBuffer, pubkeyOffset);
+ ecKeyAgreement.init(privatePair.getPrivate());
- pubkeyLength = EC_Consts.transformParameter(transformation, pubkeyBuffer, pubkeyOffset, pubkeyLength);
- length = ecKeyAgreement.generateSecret(pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset);
+ pubkeyLength = EC_Consts.transformParameter(transformation, pubkeyBuffer, pubkeyOffset, pubkeyLength);
+ length = ecKeyAgreement.generateSecret(pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset);
+ }
} catch (CardRuntimeException ce) {
sw = ce.getReason();
}
@@ -88,9 +95,11 @@ public class ECKeyTester {
sw = AppletUtil.kaCheck(ecKeyAgreement);
sw = AppletUtil.keypairCheck(privatePair);
- ecKeyAgreement.init(privatePair.getPrivate());
- pubkeyLength = EC_Consts.transformParameter(transformation, pubkey, pubkeyOffset, pubkeyLength);
- length = ecKeyAgreement.generateSecret(pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset);
+ if (!dryRun) {
+ ecKeyAgreement.init(privatePair.getPrivate());
+ pubkeyLength = EC_Consts.transformParameter(transformation, pubkey, pubkeyOffset, pubkeyLength);
+ length = ecKeyAgreement.generateSecret(pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset);
+ }
} catch (CardRuntimeException ce) {
sw = ce.getReason();
}
@@ -116,13 +125,14 @@ public class ECKeyTester {
try {
sw = AppletUtil.signCheck(ecdsaSignature);
- ecdsaSignature.init(signKey, Signature.MODE_SIGN);
- length = ecdsaSignature.sign(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset);
+ if (!dryRun) {
+ ecdsaSignature.init(signKey, Signature.MODE_SIGN);
+ length = ecdsaSignature.sign(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset);
- ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY);
- boolean correct = ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, length);
- if (!correct) {
- sw = AppletBase.SW_SIG_VERIFY_FAIL;
+ ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY);
+ if (!ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, length)) {
+ sw = AppletBase.SW_SIG_VERIFY_FAIL;
+ }
}
} catch (CardRuntimeException ce) {
sw = ce.getReason();
@@ -144,8 +154,10 @@ public class ECKeyTester {
try {
sw = AppletUtil.signCheck(ecdsaSignature);
- ecdsaSignature.init(signKey, Signature.MODE_SIGN);
- length = ecdsaSignature.sign(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset);
+ if (!dryRun) {
+ ecdsaSignature.init(signKey, Signature.MODE_SIGN);
+ length = ecdsaSignature.sign(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset);
+ }
} catch (CardRuntimeException ce) {
sw = ce.getReason();
}
@@ -167,10 +179,11 @@ public class ECKeyTester {
try {
sw = AppletUtil.signCheck(ecdsaSignature);
- ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY);
- boolean correct = ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, sigLength);
- if (!correct) {
- sw = AppletBase.SW_SIG_VERIFY_FAIL;
+ if (!dryRun) {
+ ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY);
+ if (!ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, sigLength)) {
+ sw = AppletBase.SW_SIG_VERIFY_FAIL;
+ }
}
} catch (CardRuntimeException ce) {
sw = ce.getReason();
@@ -205,4 +218,8 @@ public class ECKeyTester {
public short getSW() {
return sw;
}
+
+ public void setDryRun(boolean dryRun) {
+ this.dryRun = dryRun;
+ }
}
diff --git a/src/cz/crcs/ectester/common/ec/EC_Category.java b/src/cz/crcs/ectester/common/ec/EC_Category.java
index 05c910c..1eb818f 100644
--- a/src/cz/crcs/ectester/common/ec/EC_Category.java
+++ b/src/cz/crcs/ectester/common/ec/EC_Category.java
@@ -92,7 +92,7 @@ public class EC_Category {
}
String[] headers = new String[]{"Public keys", "Private keys", "KeyPairs", "Results(KA)", "Results(SIG)"};
- Class[] classes = new Class[]{EC_Key.Public.class, EC_Key.Private.class, EC_Keypair.class, EC_KAResult.class, EC_SigResult.class};
+ Class<EC_Data>[] classes = new Class[]{EC_Key.Public.class, EC_Key.Private.class, EC_Keypair.class, EC_KAResult.class, EC_SigResult.class};
for (int i = 0; i < headers.length; ++i) {
Map<String, EC_Data> data = getObjects(classes[i]);
size = data.size();
diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
index 85b32a4..8ad50c7 100644
--- a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
+++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
@@ -56,7 +56,7 @@ public abstract class BaseTextTestWriter implements TestWriter {
String line = "";
if (prefix.equals("")) {
- char charLine[] = new char[BASE_WIDTH + 24];
+ char[] charLine = new char[BASE_WIDTH + 24];
new String(new char[BASE_WIDTH + 24]).replace("\0", "━").getChars(0, charLine.length - 1, charLine, 0);
charLine[0] = '■';
charLine[4] = '┳';
@@ -70,7 +70,7 @@ public abstract class BaseTextTestWriter implements TestWriter {
out.append(t.ok() ? Colors.ok(" OK ") : Colors.error("NOK "));
out.append(compound ? (prefix.equals("") ? "╋ " : "┳ ") : "━ ");
int width = BASE_WIDTH - (prefix.length() + 6);
- String widthSpec = "%-" + String.valueOf(width) + "s";
+ String widthSpec = "%-" + width + "s";
String desc = ((prefix.equals("")) ? "(" + index + ") " : "") + t.getDescription();
out.append(String.format(widthSpec, desc));
out.append(" ┃ ");
@@ -87,7 +87,7 @@ public abstract class BaseTextTestWriter implements TestWriter {
if (compound) {
CompoundTest test = (CompoundTest) t;
- out.append(String.valueOf(result.getCause()));
+ out.append(result.getCause());
out.append(System.lineSeparator());
Test[] tests = test.getStartedTests();
for (int i = 0; i < tests.length; ++i) {
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..511f93f 100644
--- a/src/cz/crcs/ectester/common/util/ECUtil.java
+++ b/src/cz/crcs/ectester/common/util/ECUtil.java
@@ -3,9 +3,18 @@ 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 org.bouncycastle.crypto.digests.SHA1Digest;
+import java.io.IOException;
import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
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.*;
@@ -183,6 +192,27 @@ public class ECUtil {
}
}
+ public static byte[] semiRandomKey(EC_Curve curve) {
+ int bytes = (curve.getBits() + 7) / 8;
+ byte[] result = new byte[bytes];
+ SHA1Digest digest = new SHA1Digest();
+ byte[] curveName = curve.getId().getBytes(StandardCharsets.US_ASCII);
+ digest.update(curveName, 0, curveName.length);
+ int written = 0;
+ while (written < bytes) {
+ byte[] dig = new byte[digest.getDigestSize()];
+ digest.doFinal(dig, 0);
+ int toWrite = digest.getDigestSize() > bytes - written ? bytes - written : digest.getDigestSize();
+ System.arraycopy(dig, 0, result, written, toWrite);
+ written += toWrite;
+ digest.update(dig, 0, dig.length);
+ }
+ BigInteger priv = new BigInteger(1, result);
+ BigInteger order = new BigInteger(1, curve.getParam(EC_Consts.PARAMETER_R)[0]);
+ priv = priv.mod(order);
+ return toByteArray(priv, curve.getBits());
+ }
+
private static ECPoint toPoint(EC_Params params) {
return new ECPoint(
new BigInteger(1, params.getParam(EC_Consts.PARAMETER_W)[0]),
@@ -194,25 +224,34 @@ public class ECUtil {
}
public static ECPublicKey toPublicKey(EC_Key.Public pubkey) {
+ if (pubkey == null) {
+ return null;
+ }
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());
}
public static ECPrivateKey toPrivateKey(EC_Key.Private privkey) {
+ if (privkey == null) {
+ return null;
+ }
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());
}
public static KeyPair toKeyPair(EC_Keypair kp) {
+ if (kp == null) {
+ return null;
+ }
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 +261,33 @@ 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) {
+ nsae.printStackTrace();
+ return null;
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor128p56467.csv b/src/cz/crcs/ectester/data/cofactor/cofactor128p56467.csv
new file mode 100644
index 0000000..193f6a7
--- /dev/null
+++ b/src/cz/crcs/ectester/data/cofactor/cofactor128p56467.csv
@@ -0,0 +1 @@
+0xe8e100a50b479105f40c312de4bc7127,0x854c8cdc7389dbb3da8a949ce4598ebe,0x4e592cbd1471bba6dec1106cfa99f969,0x7a6c7f7f8305853831d7c99dd23b03aa,0xa3ad04379cb4789bd64e7d99a7874e0b,0x00010e47ea4c399c7ddb49c9915c3b5d,0xdc93 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor128p65521.csv b/src/cz/crcs/ectester/data/cofactor/cofactor128p65521.csv
new file mode 100644
index 0000000..80a1eb3
--- /dev/null
+++ b/src/cz/crcs/ectester/data/cofactor/cofactor128p65521.csv
@@ -0,0 +1 @@
+0xdc068a34e30288e08b495798af63ebc7,0xdc068a34e3027b1ccb5209bee1c3ebc7,0xdc054fb5cb170758f9fe7d1b5f63ebc7,0xc0d6edec3ac87edf8499d1885fd03e7b,0x81cb302f36ecd3ff93cd6314ce059e14,0x0000dc136f586930b2b948e64bb6e653,0xfff1 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor128p65535.csv b/src/cz/crcs/ectester/data/cofactor/cofactor128p65535.csv
new file mode 100644
index 0000000..54da6cc
--- /dev/null
+++ b/src/cz/crcs/ectester/data/cofactor/cofactor128p65535.csv
@@ -0,0 +1 @@
+0xdd94e89ef3fba74afc2a67cb91546a93,0x6cf4828ab4960df2b9fcab3990e3959a,0x80a5c32206c83f769c5ed3e4f5b2ea4e,0xd7a4bb4b7e9ad9e81895caeaeac8b739,0x45ebc51cf353974b02b36b9912de041b,0x0000dd95c634ba30617af48fd4eb321b,0xffff \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor192p2.csv b/src/cz/crcs/ectester/data/cofactor/cofactor192p2.csv
new file mode 100644
index 0000000..4de7049
--- /dev/null
+++ b/src/cz/crcs/ectester/data/cofactor/cofactor192p2.csv
@@ -0,0 +1 @@
+0x79cb22319472d019a08f7ae4f99c3edea2f167773210eab7,0x2b1afa29b6e9f7e148f7eb306ae942a506546c7129d56a3f,0x704d348ecd838ed800911bab3298aeebbf1c03b5489bca5d,0x61fc509a9d967735e8f18b0a4ba323134989c7711f44c35b,0x4fe31f28e2ee2a41f6fd661e417d32832bee6f3e164b167e,0x3ce59118ca39680cd047bd72595564c3953a773f01833de3,0x02 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor192p4.csv b/src/cz/crcs/ectester/data/cofactor/cofactor192p4.csv
new file mode 100644
index 0000000..645f031
--- /dev/null
+++ b/src/cz/crcs/ectester/data/cofactor/cofactor192p4.csv
@@ -0,0 +1 @@
+0x8cceb84c81521937bef0925a3aaf09195a59c3f99ae06135,0x6ad5a0b617af4ac05f668ae0236f0a485290c36ef609efb5,0x3289c9a3f4f0364147634d40c2f7604e4bc98773daefc954,0x314789e7e4e448b000d235cc51251e70cd8c92c11d1858f9,0x74459b81d5322dc2c631d3ba964e8b4c8f1e4196939a5579,0x2333ae132054864defbc24965da70e7dbdb87ba264315991,0x04 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor192p8.csv b/src/cz/crcs/ectester/data/cofactor/cofactor192p8.csv
new file mode 100644
index 0000000..ee39445
--- /dev/null
+++ b/src/cz/crcs/ectester/data/cofactor/cofactor192p8.csv
@@ -0,0 +1 @@
+0xa9a93bb887865d349841624bd8281c589a8e0196ae724eed,0x1b8b108f729cc205fb0ec88825d7d696e3df62ed328bd535,0x81078fdf85b1ee56ea3e27f6dedcca6f5eb9b645f536dc68,0x37369946896227fce5bfe8f760ba827080caa6700d8d8aaa,0x7f54e11bf72549866571fb70b383b6d1451973c11e3fd082,0x1535277710f0cba693082c4985a9197e9e759aa3571eb787,0x08 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/cofactor/curves.xml b/src/cz/crcs/ectester/data/cofactor/curves.xml
index 7cf2a9a..0b8c52e 100644
--- a/src/cz/crcs/ectester/data/cofactor/curves.xml
+++ b/src/cz/crcs/ectester/data/cofactor/curves.xml
@@ -44,6 +44,24 @@
<field>prime</field>
<file>cofactor128p128.csv</file>
</curve>
+ <curve>
+ <id>large/cofactor128p56467</id>
+ <bits>128</bits>
+ <field>prime</field>
+ <file>cofactor128p56467.csv</file>
+ </curve>
+ <curve>
+ <id>large/cofactor128p65521</id>
+ <bits>128</bits>
+ <field>prime</field>
+ <file>cofactor128p65521.csv</file>
+ </curve>
+ <curve>
+ <id>large/cofactor128p65535</id>
+ <bits>128</bits>
+ <field>prime</field>
+ <file>cofactor128p65535.csv</file>
+ </curve>
<curve>
<id>cofactor160p2</id>
@@ -88,6 +106,18 @@
<field>prime</field>
<file>cofactor192p2.csv</file>
</curve>
+ <curve>
+ <id>cofactor192p4</id>
+ <bits>192</bits>
+ <field>prime</field>
+ <file>cofactor192p4.csv</file>
+ </curve>
+ <curve>
+ <id>cofactor192p8</id>
+ <bits>192</bits>
+ <field>prime</field>
+ <file>cofactor192p8.csv</file>
+ </curve>
<curve>
<id>cofactor163t2</id>
diff --git a/src/cz/crcs/ectester/data/cofactor/keys.xml b/src/cz/crcs/ectester/data/cofactor/keys.xml
index b4c0c90..2be7238 100644
--- a/src/cz/crcs/ectester/data/cofactor/keys.xml
+++ b/src/cz/crcs/ectester/data/cofactor/keys.xml
@@ -702,4 +702,23 @@
<curve>composite/pq/composite256/2</curve>
<desc>cofactor order = 0x000000000000000000000000000000000000000000000000743bc7ea193d40db</desc>
</pubkey>
+
+ <pubkey>
+ <id>large/cofactor128p56467/0</id>
+ <inline>0x8afd6cc280e0be7163bb6f285a7c6391,0xae64e0f1afc7bd5c75e2f36a7d85f668</inline>
+ <curve>cofactor/large/cofactor128p56467</curve>
+ <desc>cofactor order = 0xdc93</desc>
+ </pubkey>
+ <pubkey>
+ <id>large/cofactor128p65521/0</id>
+ <inline>0x70e43816ed51388caa54a68b6c500352,0xab05b43e2cde6086b12350abe79b9175</inline>
+ <curve>cofactor/large/cofactor128p65521</curve>
+ <desc>cofactor order = 0xfff1</desc>
+ </pubkey>
+ <pubkey>
+ <id>large/cofactor128p65535/0</id>
+ <inline>0x39d6ea56c3eb6382d2d7a9d327a191fd,0x3ebb3f4626d05df38572af3ae5fa60f2</inline>
+ <curve>cofactor/large/cofactor128p65535</curve>
+ <desc>cofactor order = 0xffff</desc>
+ </pubkey>
</keys>
diff --git a/src/cz/crcs/ectester/data/degenerate/cofactor.xml b/src/cz/crcs/ectester/data/degenerate/cofactor.xml
new file mode 100644
index 0000000..647515b
--- /dev/null
+++ b/src/cz/crcs/ectester/data/degenerate/cofactor.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>cofactor128p4/0</id>
+ <inline>0x00000000000000000000000000000000,0x94d9020b666fbb599609485472a9246e</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>degenerate order = 2</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/1</id>
+ <inline>0x00000000000000000000000000000000,0x2d3a81f8b8d96e6db96a04fb6cf432de</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>degenerate order = 3</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/2</id>
+ <inline>0x00000000000000000000000000000000,0x639272497e0865cea0e17677b6bc5575</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>degenerate order = 7</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/3</id>
+ <inline>0x00000000000000000000000000000000,0x072aba3ae7aeb770332600a630e503d1</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>degenerate order = 5297</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/4</id>
+ <inline>0x00000000000000000000000000000000,0x17b45a35afdff5c5150a7c0a7ee34825</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>degenerate order = 31134053800693</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/5</id>
+ <inline>0x00000000000000000000000000000000,0x6fd5d6e491bf5a15eb1d38554caad86c</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>degenerate order = 28564500657606656383</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/gen</id>
+ <inline>0x00000000000000000000000000000000,0x00000000000000000000000000000005</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>generator of Fp^*</desc>
+</pubkey>
+
+<pubkey>
+ <id>cofactor160p4/0</id>
+ <inline>0x0000000000000000000000000000000000000000,0x93ab454ad26dae3b521d5b61a48c94cab3c4aa9c</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>degenerate order = 2</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/1</id>
+ <inline>0x0000000000000000000000000000000000000000,0xbad87d0931716ec918e43e76b57971cc613e153</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>degenerate order = 4</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/2</id>
+ <inline>0x0000000000000000000000000000000000000000,0x4428069aa7ac1865eb52c5b4c885ec832d89b36d</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>degenerate order = 3</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/3</id>
+ <inline>0x0000000000000000000000000000000000000000,0x6eb71aefce923ebf8b07c6f1f59b1c30d43b74ae</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>degenerate order = 23</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/4</id>
+ <inline>0x0000000000000000000000000000000000000000,0x3c5ff8c94b31b46f92575e0b77b0366afe24dfc1</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>degenerate order = 11443</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/5</id>
+ <inline>0x0000000000000000000000000000000000000000,0xd8e2287382e057de70e1f45f70d8dad85d27025</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>degenerate order = 352281613501590816479</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/5</id>
+ <inline>0x0000000000000000000000000000000000000000,0x36911d265f6d795a2efd10c20aae0f3ec5f815f4</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>degenerate order = 757721821606925858951</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/gen</id>
+ <inline>0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000002</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>generator of Fp^*</desc>
+</pubkey>
+
+<pubkey>
+ <id>cofactor192p4/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000,0x8cceb84c81521937bef0925a3aaf09195a59c3f99ae06134</inline>
+ <curve>cofactor/cofactor192p4</curve>
+ <desc>degenerate order = 2</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor192p4/1</id>
+ <inline>0x000000000000000000000000000000000000000000000000,0x63ca4f21e0e4f6a833f914468e00e4d817f472d54aca5a64</inline>
+ <curve>cofactor/cofactor192p4</curve>
+ <desc>degenerate order = 4</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor192p4/2</id>
+ <inline>0x000000000000000000000000000000000000000000000000,0x7ce088c401bfc705e70da9928c04ed6e1bf100c26b253028</inline>
+ <curve>cofactor/cofactor192p4</curve>
+ <desc>degenerate order = 5</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor192p4/3</id>
+ <inline>0x000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000100000</inline>
+ <curve>cofactor/cofactor192p4</curve>
+ <desc>degenerate order = 172629492300688965054638881592440218548130640356589228457</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor192p4/gen</id>
+ <inline>0x000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000002</inline>
+ <curve>cofactor/cofactor192p4</curve>
+ <desc>generator of Fp^*</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/degenerate/keys.xml b/src/cz/crcs/ectester/data/degenerate/keys.xml
index b999ca0..498cf26 100644
--- a/src/cz/crcs/ectester/data/degenerate/keys.xml
+++ b/src/cz/crcs/ectester/data/degenerate/keys.xml
@@ -2,6 +2,7 @@
<!DOCTYPE keys [
<!ENTITY secg SYSTEM "degenerate/secg.xml">
<!ENTITY brainpool SYSTEM "degenerate/brainpool.xml">
+ <!ENTITY cofactor SYSTEM "degenerate/cofactor.xml">
]>
<keys xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../schema.xsd">
@@ -11,4 +12,5 @@
-->
&secg;
&brainpool;
+ &cofactor;
</keys> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/invalid/secg/secp128r1.xml b/src/cz/crcs/ectester/data/invalid/secg/secp128r1.xml
index 8903688..e010003 100644
--- a/src/cz/crcs/ectester/data/invalid/secg/secp128r1.xml
+++ b/src/cz/crcs/ectester/data/invalid/secg/secp128r1.xml
@@ -85,7 +85,7 @@
</pubkey>
<pubkey>
<id>secp128r1/14</id>
- <inline>0x98b36c442de5c741c70fa80a31d72fa,0x251e9a04ffe799cf4776575be582f108</inline>
+ <inline>0x098b36c442de5c741c70fa80a31d72fa,0x251e9a04ffe799cf4776575be582f108</inline>
<curve>secg/secp128r1</curve>
<desc>invalid order = 47</desc>
</pubkey>
@@ -109,7 +109,7 @@
</pubkey>
<pubkey>
<id>secp128r1/18</id>
- <inline>0x9ce43ec4dcaf95993d8ab00efcc7199a,0x7fb6d895c27bc326a33cb8111e865a9</inline>
+ <inline>0x9ce43ec4dcaf95993d8ab00efcc7199a,0x07fb6d895c27bc326a33cb8111e865a9</inline>
<curve>secg/secp128r1</curve>
<desc>invalid order = 67</desc>
</pubkey>
@@ -139,7 +139,7 @@
</pubkey>
<pubkey>
<id>secp128r1/23</id>
- <inline>0x6803013e75597fb7f83f1f8681af11d,0x32490d391f8a2b1de83212dd218b3a5a</inline>
+ <inline>0x06803013e75597fb7f83f1f8681af11d,0x32490d391f8a2b1de83212dd218b3a5a</inline>
<curve>secg/secp128r1</curve>
<desc>invalid order = 89</desc>
</pubkey>
diff --git a/src/cz/crcs/ectester/data/misc/results.xml b/src/cz/crcs/ectester/data/misc/results.xml
index ba8c83c..07601b1 100644
--- a/src/cz/crcs/ectester/data/misc/results.xml
+++ b/src/cz/crcs/ectester/data/misc/results.xml
@@ -7,8 +7,8 @@
<inline>0xdb6f7cd6a06846bf9da9b4928caa5e4b7c8f58d9</inline>
<!-- == SHA1(0x1D0F27241C177385B0D5025029FABD5D5D8475DA4E267DCD177B49C63605C25A) -->
<curve>secg/secp256r1</curve>
- <onekey>other/openssl-bug/pkey</onekey>
- <otherkey>other/openssl-bug/skey</otherkey>
+ <onekey>misc/openssl-bug/pkey</onekey>
+ <otherkey>misc/openssl-bug/skey</otherkey>
<desc>https://eprint.iacr.org/2011/633</desc>
</kaResult>
</results> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/twist/cofactor/cofactor128p4.xml b/src/cz/crcs/ectester/data/twist/cofactor/cofactor128p4.xml
new file mode 100644
index 0000000..b558f8e
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/cofactor/cofactor128p4.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>cofactor128p4/0</id>
+ <inline>0x72294f8a7c88d510343c19b8251d7dd6,0x00000000000000000000000000000000</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>twist order = 2</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/1</id>
+ <inline>0x5d20662769138fe1506f2a2b44fd34c1,0x15d63a5aba305ccdee9f65e3f2c1d4e8</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>twist order = 4</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/2</id>
+ <inline>0x0b843b9da795292bfc598bae47fd0955,0x2944056236d430e404f6fd058a7a6624</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>twist order = 17</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/3</id>
+ <inline>0x663a7a5a7370a48f98ef5ba0cc2d19a1,0x13d59851b95e3916e1149b1f8345325d</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>twist order = 37</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/4</id>
+ <inline>0x415d46d2beb2357a567efeedd3e052a0,0x8b202b706af555d470fb42fb5919a64</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>twist order = 24422261</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/5</id>
+ <inline>0x6707ea110f83e67a9f6a43c184587bc6,0x1c44db735c6b30165e40660ecc5d8c3c</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>twist order = 87024861802858114445834597</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor128p4/gen</id>
+ <inline>0x5a1c6fd7a138377f22dabe0840a02ede,0x39395b4be5f4c131a0a5f778be1166e5</inline>
+ <curve>cofactor/cofactor128p4</curve>
+ <desc>twist generator</desc>
+</pubkey>
+
diff --git a/src/cz/crcs/ectester/data/twist/cofactor/cofactor160p4.xml b/src/cz/crcs/ectester/data/twist/cofactor/cofactor160p4.xml
new file mode 100644
index 0000000..bb712af
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/cofactor/cofactor160p4.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>cofactor160p4/0</id>
+ <inline>0x0c43497bdc7c1fddd18368da4894a98a612f09ec,0x0000000000000000000000000000000000000000</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 2</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/1</id>
+ <inline>0x526ba726c52a6c998994733747dc27db793ce64b,0x3f432767051371f91355e6a14488883bc51c881e</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 4</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/2</id>
+ <inline>0x380cd2b93ff179b2411c721879d7fbed95ef1d68,0x7b36aafe70fa88d2522931555d91e072a89eaff0</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 8</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/3</id>
+ <inline>0x640d26a5aa07b529bf39bb4d4ad79346f677e2e9,0x22c90f648dfd349f8ac76c4aa0e4fd7278bc4516</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 16</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/4</id>
+ <inline>0x8dab044b1a87809667b940b43d913b00fa194c8,0x20652c81133c9e51a16d0ecbcd6f81111afc03c3</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 3</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/5</id>
+ <inline>0x66e27b0bfaf5269dbca67fa71ea3a117f29f4ef9,0x2b9499a775ae8f7fba1884b3d852429757312c93</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 13</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/6</id>
+ <inline>0x4758716ac3b6cfb971ea0a673c4eebbad085fbd8,0x6ab9c8044435062299d14bdb6d6a41faf0bb0067</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 169</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/7</id>
+ <inline>0x76690f13f9fdec12b156a40f5a7c0f25b420e7e0,0x8cab0d69936dcb3b64007f2fd2881f18f627ade5</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 107</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/8</id>
+ <inline>0x178c6e5bb98247299631a52d32a55e61711a21fb,0x6e9171b2aab5bbbe488d9c3c367cf0536bf19e1a</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 15259</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/9</id>
+ <inline>0x08e82adfcb0ff539bf58e4f232f4721f3a014904,0x7ba4d134fa420dbf7fdff4986361d625e87ca27d</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 322336986893916431</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/10</id>
+ <inline>0x1d6ee4ac5b0da602078684f14bab3510915f7fef,0x229903e44fe1dd7e4ef1d3dd4edc0ed05c712bef</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist order = 197469859348064237101</desc>
+</pubkey>
+<pubkey>
+ <id>cofactor160p4/gen</id>
+ <inline>0x5603c1fd03c11eb2ab5f7abb998658a791a71202,0x3151be9d7f447756c8e85f5ac82c1ee410727157</inline>
+ <curve>cofactor/cofactor160p4</curve>
+ <desc>twist generator</desc>
+</pubkey>
+
diff --git a/src/cz/crcs/ectester/data/twist/keys.xml b/src/cz/crcs/ectester/data/twist/keys.xml
index df208bf..3292004 100644
--- a/src/cz/crcs/ectester/data/twist/keys.xml
+++ b/src/cz/crcs/ectester/data/twist/keys.xml
@@ -21,6 +21,9 @@
<!ENTITY secp256r1 SYSTEM "twist/secg/secp256r1.xml">
<!ENTITY secp384r1 SYSTEM "twist/secg/secp384r1.xml">
<!ENTITY secp521r1 SYSTEM "twist/secg/secp521r1.xml">
+
+ <!ENTITY cofactor128p4 SYSTEM "twist/cofactor/cofactor128p4.xml">
+ <!ENTITY cofactor160p4 SYSTEM "twist/cofactor/cofactor160p4.xml">
]>
<keys xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../schema.xsd">
@@ -45,4 +48,7 @@
&secp256r1;
&secp384r1;
&secp521r1;
+
+ &cofactor128p4;
+ &cofactor160p4;
</keys> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/wycheproof/keys.xml b/src/cz/crcs/ectester/data/wycheproof/keys.xml
index 46359df..7ca174d 100644
--- a/src/cz/crcs/ectester/data/wycheproof/keys.xml
+++ b/src/cz/crcs/ectester/data/wycheproof/keys.xml
@@ -302,7 +302,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP224r1/1s</id>
- <inline>0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a792dd</inline>
+ <inline>0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a792dd</inline>
<curve>brainpool/brainpoolP224r1</curve>
<desc>tcId = 441</desc>
</privkey>
@@ -315,7 +315,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP224r1/2s</id>
- <inline>0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7935d</inline>
+ <inline>0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7935d</inline>
<curve>brainpool/brainpoolP224r1</curve>
<desc>tcId = 442</desc>
</privkey>
@@ -328,7 +328,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP224r1/3s</id>
- <inline>0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939d</inline>
+ <inline>0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939d</inline>
<curve>brainpool/brainpoolP224r1</curve>
<desc>tcId = 444</desc>
</privkey>
@@ -341,7 +341,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP256r1/1s</id>
- <inline>0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974855f5</inline>
+ <inline>0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974855f5</inline>
<curve>brainpool/brainpoolP256r1</curve>
<desc>tcId = 524</desc>
</privkey>
@@ -354,7 +354,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP256r1/2s</id>
- <inline>0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485675</inline>
+ <inline>0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485675</inline>
<curve>brainpool/brainpoolP256r1</curve>
<desc>tcId = 525</desc>
</privkey>
@@ -367,7 +367,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP256r1/3s</id>
- <inline>0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485695</inline>
+ <inline>0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485695</inline>
<curve>brainpool/brainpoolP256r1</curve>
<desc>tcId = 526</desc>
</privkey>
@@ -380,7 +380,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP256r1/4s</id>
- <inline>0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a5</inline>
+ <inline>0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a5</inline>
<curve>brainpool/brainpoolP256r1</curve>
<desc>tcId = 528</desc>
</privkey>
@@ -393,7 +393,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320r1/1s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59233</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59233</inline>
<curve>brainpool/brainpoolP320r1</curve>
<desc>tcId = 604</desc>
</privkey>
@@ -406,7 +406,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320r1/2s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592b3</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592b3</inline>
<curve>brainpool/brainpoolP320r1</curve>
<desc>tcId = 605</desc>
</privkey>
@@ -419,7 +419,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320r1/3s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592f3</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592f3</inline>
<curve>brainpool/brainpoolP320r1</curve>
<desc>tcId = 606</desc>
</privkey>
@@ -432,7 +432,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320r1/4s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59303</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59303</inline>
<curve>brainpool/brainpoolP320r1</curve>
<desc>tcId = 607</desc>
</privkey>
@@ -445,7 +445,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320r1/5s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930b</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930b</inline>
<curve>brainpool/brainpoolP320r1</curve>
<desc>tcId = 608</desc>
</privkey>
@@ -458,7 +458,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320r1/6s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930f</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930f</inline>
<curve>brainpool/brainpoolP320r1</curve>
<desc>tcId = 610</desc>
</privkey>
@@ -471,7 +471,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP384r1/1s</id>
- <inline>0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904652f</inline>
+ <inline>0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904652f</inline>
<curve>brainpool/brainpoolP384r1</curve>
<desc>tcId = 684</desc>
</privkey>
@@ -484,7 +484,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP384r1/2s</id>
- <inline>0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904654f</inline>
+ <inline>0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904654f</inline>
<curve>brainpool/brainpoolP384r1</curve>
<desc>tcId = 685</desc>
</privkey>
@@ -497,7 +497,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP384r1/3s</id>
- <inline>0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904655f</inline>
+ <inline>0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904655f</inline>
<curve>brainpool/brainpoolP384r1</curve>
<desc>tcId = 686</desc>
</privkey>
@@ -510,7 +510,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP384r1/4s</id>
- <inline>0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046563</inline>
+ <inline>0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046563</inline>
<curve>brainpool/brainpoolP384r1</curve>
<desc>tcId = 688</desc>
</privkey>
@@ -523,7 +523,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP512r1/1s</id>
- <inline>0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9003b</inline>
+ <inline>0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9003b</inline>
<curve>brainpool/brainpoolP512r1</curve>
<desc>tcId = 774</desc>
</privkey>
@@ -536,7 +536,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP512r1/2s</id>
- <inline>0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9005b</inline>
+ <inline>0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9005b</inline>
<curve>brainpool/brainpoolP512r1</curve>
<desc>tcId = 775</desc>
</privkey>
@@ -549,7 +549,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP512r1/3s</id>
- <inline>0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90063</inline>
+ <inline>0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90063</inline>
<curve>brainpool/brainpoolP512r1</curve>
<desc>tcId = 776</desc>
</privkey>
@@ -562,7 +562,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP512r1/4s</id>
- <inline>0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90067</inline>
+ <inline>0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90067</inline>
<curve>brainpool/brainpoolP512r1</curve>
<desc>tcId = 778</desc>
</privkey>
@@ -575,7 +575,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP224t1/1s</id>
- <inline>0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a792dd</inline>
+ <inline>0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a792dd</inline>
<curve>brainpool/brainpoolP224t1</curve>
<desc>tcId = 854</desc>
</privkey>
@@ -588,7 +588,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP224t1/2s</id>
- <inline>0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7935d</inline>
+ <inline>0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7935d</inline>
<curve>brainpool/brainpoolP224t1</curve>
<desc>tcId = 855</desc>
</privkey>
@@ -601,7 +601,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP224t1/3s</id>
- <inline>0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939d</inline>
+ <inline>0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939d</inline>
<curve>brainpool/brainpoolP224t1</curve>
<desc>tcId = 857</desc>
</privkey>
@@ -614,7 +614,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP256t1/1s</id>
- <inline>0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974855f5</inline>
+ <inline>0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974855f5</inline>
<curve>brainpool/brainpoolP256t1</curve>
<desc>tcId = 935</desc>
</privkey>
@@ -627,7 +627,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP256t1/2s</id>
- <inline>0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485675</inline>
+ <inline>0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485675</inline>
<curve>brainpool/brainpoolP256t1</curve>
<desc>tcId = 936</desc>
</privkey>
@@ -640,7 +640,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP256t1/3s</id>
- <inline>0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485695</inline>
+ <inline>0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485695</inline>
<curve>brainpool/brainpoolP256t1</curve>
<desc>tcId = 937</desc>
</privkey>
@@ -653,7 +653,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP256t1/4s</id>
- <inline>0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a5</inline>
+ <inline>0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a5</inline>
<curve>brainpool/brainpoolP256t1</curve>
<desc>tcId = 939</desc>
</privkey>
@@ -666,7 +666,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320t1/1s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59233</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59233</inline>
<curve>brainpool/brainpoolP320t1</curve>
<desc>tcId = 1015</desc>
</privkey>
@@ -679,7 +679,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320t1/2s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592b3</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592b3</inline>
<curve>brainpool/brainpoolP320t1</curve>
<desc>tcId = 1016</desc>
</privkey>
@@ -692,7 +692,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320t1/3s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592f3</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592f3</inline>
<curve>brainpool/brainpoolP320t1</curve>
<desc>tcId = 1017</desc>
</privkey>
@@ -705,7 +705,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320t1/4s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59303</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59303</inline>
<curve>brainpool/brainpoolP320t1</curve>
<desc>tcId = 1018</desc>
</privkey>
@@ -718,7 +718,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320t1/5s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930b</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930b</inline>
<curve>brainpool/brainpoolP320t1</curve>
<desc>tcId = 1019</desc>
</privkey>
@@ -731,7 +731,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP320t1/6s</id>
- <inline>0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930f</inline>
+ <inline>0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930f</inline>
<curve>brainpool/brainpoolP320t1</curve>
<desc>tcId = 1021</desc>
</privkey>
@@ -744,7 +744,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP384t1/1s</id>
- <inline>0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904652f</inline>
+ <inline>0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904652f</inline>
<curve>brainpool/brainpoolP384t1</curve>
<desc>tcId = 1093</desc>
</privkey>
@@ -757,7 +757,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP384t1/2s</id>
- <inline>0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904654f</inline>
+ <inline>0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904654f</inline>
<curve>brainpool/brainpoolP384t1</curve>
<desc>tcId = 1094</desc>
</privkey>
@@ -770,7 +770,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP384t1/3s</id>
- <inline>0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904655f</inline>
+ <inline>0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904655f</inline>
<curve>brainpool/brainpoolP384t1</curve>
<desc>tcId = 1095</desc>
</privkey>
@@ -783,7 +783,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP384t1/4s</id>
- <inline>0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046563</inline>
+ <inline>0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046563</inline>
<curve>brainpool/brainpoolP384t1</curve>
<desc>tcId = 1097</desc>
</privkey>
@@ -796,7 +796,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP512t1/1s</id>
- <inline>0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9003b</inline>
+ <inline>0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9003b</inline>
<curve>brainpool/brainpoolP512t1</curve>
<desc>tcId = 1185</desc>
</privkey>
@@ -809,7 +809,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP512t1/2s</id>
- <inline>0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9005b</inline>
+ <inline>0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9005b</inline>
<curve>brainpool/brainpoolP512t1</curve>
<desc>tcId = 1186</desc>
</privkey>
@@ -822,7 +822,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP512t1/3s</id>
- <inline>0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90063</inline>
+ <inline>0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90063</inline>
<curve>brainpool/brainpoolP512t1</curve>
<desc>tcId = 1187</desc>
</privkey>
@@ -835,7 +835,7 @@
</pubkey>
<privkey>
<id>addsub/brainpoolP512t1/4s</id>
- <inline>0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90067</inline>
+ <inline>0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90067</inline>
<curve>brainpool/brainpoolP512t1</curve>
<desc>tcId = 1189</desc>
</privkey>
@@ -878,7 +878,7 @@
<!-- CVE-2017-10176 tests -->
<privkey>
<id>cve_2017_10176/secp521r1/1s</id>
- <inline>0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863f7</inline>
+ <inline>0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863f7</inline>
<curve>secg/secp521r1</curve>
<desc>tcId = 280</desc>
</privkey>
diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java
index e6835dd..8b6241d 100644
--- a/src/cz/crcs/ectester/reader/CardMngr.java
+++ b/src/cz/crcs/ectester/reader/CardMngr.java
@@ -72,7 +72,14 @@ public class CardMngr {
terminal = terminalList.get(i);
if (terminal.isCardPresent()) {
- card = terminal.connect("*");
+ try {
+ card = terminal.connect("T=1");
+ } catch (CardException ex) {
+ if (verbose)
+ System.out.println("T=1 failed, trying protocol '*'");
+ card = terminal.connect("*");
+ }
+
if (verbose)
System.out.println("card: " + card);
channel = card.getBasicChannel();
@@ -345,7 +352,7 @@ public class CardMngr {
return responseAPDU;
}
- public ResponseAPDU sendAPDU(byte apdu[]) throws CardException {
+ public ResponseAPDU sendAPDU(byte[] apdu) throws CardException {
CommandAPDU commandAPDU = new CommandAPDU(apdu);
return sendAPDU(commandAPDU);
}
diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java
index c94a544..e5e6061 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;
@@ -46,14 +48,13 @@ 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.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Scanner;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
import java.util.jar.Manifest;
import static cz.crcs.ectester.applet.EC_Consts.KeyAgreement_ALG_EC_SVDP_DH;
@@ -331,10 +332,15 @@ public class ECTesterReader {
opts.addOption(Option.builder("v").longOpt("verbose").desc("Turn on verbose logging.").build());
opts.addOption(Option.builder().longOpt("format").desc("Output format to use. One of: text,yml,xml.").hasArg().argName("format").build());
+ opts.addOption(Option.builder().longOpt("fixed").desc("Generate key(s) only once, keep them for later operations.").build());
+ opts.addOption(Option.builder().longOpt("fixed-private").desc("Generate private key only once, keep it for later ECDH.").build());
+ opts.addOption(Option.builder().longOpt("fixed-public").desc("Generate public key only once, keep it for later ECDH.").build());
opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build());
+ opts.addOption(Option.builder().longOpt("time").desc("Output better timing values, by running command in dry run mode and normal mode, and subtracting the two.").build());
opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations.").build());
opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build());
opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build());
+ opts.addOption(Option.builder("to").longOpt("test-options").desc("Test options to use.").hasArg().argName("options").build());
opts.addOption(Option.builder("ka").longOpt("ka-type").desc("Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants.").hasArg().argName("type").optionalArg(true).build());
opts.addOption(Option.builder("sig").longOpt("sig-type").desc("Set Signature object [type], corresponds to JC.Signature constants.").hasArg().argName("type").optionalArg(true).build());
@@ -364,6 +370,8 @@ public class ECTesterReader {
System.out.println("\t" + line);
}
}
+ System.out.println();
+ System.out.println("For more information, look at the documentation at https://github.com/crocs-muni/ECTester.");
}
private void info() throws CardException {
@@ -439,7 +447,7 @@ public class ECTesterReader {
respWriter.outputResponse(allocate);
OutputStreamWriter keysFile = FileUtil.openFiles(cfg.outputs);
- keysFile.write("index;genTime;exportTime;pubW;privS\n");
+ keysFile.write("index;genTime[milli];exportTime[milli];pubW;privS\n");
int generated = 0;
int retry = 0;
@@ -450,7 +458,12 @@ public class ECTesterReader {
}
Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL);
+ long time = 0;
+ if (cfg.time) {
+ time = -Command.dryRunTime(cardManager, generate, 2, respWriter);
+ }
Response.Generate response = generate.send();
+ time += response.getDuration();
respWriter.outputResponse(response);
Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send();
@@ -468,7 +481,7 @@ public class ECTesterReader {
String pub = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
String priv = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
- String line = String.format("%d;%d;%d;%s;%s\n", generated, response.getDuration() / 1000000, export.getDuration() / 1000000, pub, priv);
+ String line = String.format("%d;%d;%d;%s;%s\n", generated, time / 1000000, export.getDuration() / 1000000, pub, priv);
keysFile.write(line);
keysFile.flush();
generated++;
@@ -572,38 +585,63 @@ public class ECTesterReader {
respWriter.outputResponse(r);
}
- byte pubkey = (cfg.anyPublicKey || cfg.anyKey) ? ECTesterApplet.KEYPAIR_REMOTE : ECTesterApplet.KEYPAIR_LOCAL;
- byte privkey = (cfg.anyPrivateKey || cfg.anyKey) ? ECTesterApplet.KEYPAIR_REMOTE : ECTesterApplet.KEYPAIR_LOCAL;
-
- List<Command> generate = new LinkedList<>();
- generate.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH));
- if (cfg.anyPublicKey || cfg.anyPrivateKey || cfg.anyKey) {
- generate.add(Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_REMOTE));
- }
-
OutputStreamWriter out = null;
if (cfg.outputs != null) {
out = FileUtil.openFiles(cfg.outputs);
- out.write("index;time;pubW;privS;secret\n");
+ out.write("index;time[milli];pubW;privS;secret\n");
+ }
+
+ Response gen = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH).send();
+ respWriter.outputResponse(gen);
+ if (cfg.anyPublicKey || cfg.anyKey) {
+ Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_REMOTE).send();
+ respWriter.outputResponse(prep);
+ }
+ if (cfg.anyPrivateKey || cfg.anyKey) {
+ Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL).send();
+ respWriter.outputResponse(prep);
+ }
+
+ byte kp = ECTesterApplet.KEYPAIR_BOTH;
+ if (cfg.fixedPrivate || cfg.anyPrivateKey) {
+ kp ^= ECTesterApplet.KEYPAIR_LOCAL;
+ }
+ if (cfg.fixedPublic || cfg.anyPublicKey) {
+ kp ^= ECTesterApplet.KEYPAIR_REMOTE;
+ }
+ if (cfg.fixedKey || cfg.anyKey) {
+ kp = 0;
+ }
+
+ Command generate = null;
+ if (kp != 0) {
+ generate = new Command.Generate(cardManager, kp);
}
int retry = 0;
int done = 0;
while (done < cfg.ECKACount) {
- List<Response> ecdh = Command.sendAll(generate);
- for (Response r : ecdh) {
- respWriter.outputResponse(r);
+ if (generate != null) {
+ Response regen = generate.send();
+ respWriter.outputResponse(regen);
}
Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send();
respWriter.outputResponse(export);
- byte pubkey_bytes[] = export.getParameter(pubkey, EC_Consts.PARAMETER_W);
- byte privkey_bytes[] = export.getParameter(privkey, EC_Consts.PARAMETER_S);
+ byte[] pubkey_bytes = export.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W);
+ byte[] privkey_bytes = export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S);
+
+ Command.ECDH perform = new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType);
- Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType).send();
- respWriter.outputResponse(perform);
+ long time = 0;
+ if (cfg.time) {
+ time = -Command.dryRunTime(cardManager, perform, 2, respWriter);
+ }
+
+ Response.ECDH result = perform.send();
+ respWriter.outputResponse(result);
- if (!perform.successful() || !perform.hasSecret()) {
+ if (!result.successful() || !result.hasSecret()) {
if (retry < 10) {
++retry;
continue;
@@ -614,7 +652,9 @@ public class ECTesterReader {
}
if (out != null) {
- out.write(String.format("%d;%d;%s;%s;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(perform.getSecret(), false)));
+ time += result.getDuration();
+
+ out.write(String.format("%d;%d;%s;%s;%s\n", done, time / 1000000, ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(result.getSecret(), false)));
}
++done;
@@ -636,7 +676,7 @@ public class ECTesterReader {
*/
private void ecdsa() throws CardException, IOException {
//read file, if asked to sign
- byte[] data = null;
+ byte[] data;
if (cfg.input != null) {
File in = new File(cfg.input);
long len = in.length();
@@ -644,6 +684,10 @@ public class ECTesterReader {
throw new FileNotFoundException(cfg.input);
}
data = Files.readAllBytes(in.toPath());
+ } else {
+ Random rand = new Random();
+ data = new byte[32];
+ rand.nextBytes(data);
}
Command generate;
@@ -667,18 +711,56 @@ public class ECTesterReader {
OutputStreamWriter out = FileUtil.openFiles(cfg.outputs);
if (out != null) {
- out.write("index;time;signature\n");
+ out.write("index;signTime[milli];verifyTime[milli];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);
+ Response.Export exported = null;
+ if (cfg.fixedKey) {
+ respWriter.outputResponse(generate.send());
+ exported = export.send();
+ respWriter.outputResponse(exported);
}
int retry = 0;
int done = 0;
while (done < cfg.ECDSACount) {
- respWriter.outputResponse(generate.send());
+ if (!cfg.fixedKey) {
+ respWriter.outputResponse(generate.send());
+ exported = export.send();
+ respWriter.outputResponse(exported);
+ }
+
+ Command.ECDSA_sign sign = new Command.ECDSA_sign(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data);
- Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data).send();
- respWriter.outputResponse(perform);
+ long signTime = 0;
+ if (cfg.time) {
+ signTime = -Command.dryRunTime(cardManager, sign, 2, respWriter);
+ }
- if (!perform.successful() || !perform.hasSignature()) {
+ Response.ECDSA signResp = sign.send();
+ signTime += signResp.getDuration();
+ respWriter.outputResponse(signResp);
+ if (!signResp.successful() || !signResp.hasSignature()) {
+ if (retry < 10) {
+ ++retry;
+ continue;
+ } else {
+ System.err.println(Colors.error("Couldn't obtain ECDSA signature from card response."));
+ break;
+ }
+ }
+ byte[] signature = signResp.getSignature();
+ Command.ECDSA_verify verify = new Command.ECDSA_verify(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, data, signature);
+ long verifyTime = 0;
+ if (cfg.time) {
+ verifyTime = -Command.dryRunTime(cardManager, verify, 2, respWriter);
+ }
+ Response.ECDSA verifyResp = verify.send();
+ verifyTime += verifyResp.getDuration();
+ respWriter.outputResponse(verifyResp);
+
+ if (verifyResp.error()) {
if (retry < 10) {
++retry;
continue;
@@ -689,7 +771,20 @@ public class ECTesterReader {
}
if (out != null) {
- out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(perform.getSignature(), false)));
+ 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);
+ 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, signTime / 1000000, verifyTime / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k, verifyResp.successful() ? 1 : 0));
}
++done;
@@ -733,6 +828,9 @@ public class ECTesterReader {
public String key;
public boolean anyKeypart = false;
+ public boolean fixedKey = false;
+ public boolean fixedPrivate = false;
+ public boolean fixedPublic = false;
public String log;
@@ -740,6 +838,7 @@ public class ECTesterReader {
public String input;
public String[] outputs;
public boolean fresh = false;
+ public boolean time = false;
public boolean cleanup = false;
public boolean simulate = false;
public boolean yes = false;
@@ -756,6 +855,7 @@ public class ECTesterReader {
public byte ECKAType = KeyAgreement_ALG_EC_SVDP_DH;
public int ECDSACount;
public byte ECDSAType = Signature_ALG_ECDSA_SHA;
+ public Set<String> testOptions;
/**
* Reads and validates options, also sets defaults.
@@ -786,6 +886,9 @@ public class ECTesterReader {
key = cli.getOptionValue("key");
anyKey = (key != null) || (namedKey != null);
anyKeypart = anyKey || anyPublicKey || anyPrivateKey;
+ fixedKey = cli.hasOption("fixed");
+ fixedPrivate = cli.hasOption("fixed-private");
+ fixedPublic = cli.hasOption("fixed-public");
if (cli.hasOption("log")) {
log = cli.getOptionValue("log", String.format("ECTESTER_log_%d.log", System.currentTimeMillis() / 1000));
@@ -795,6 +898,7 @@ public class ECTesterReader {
input = cli.getOptionValue("input");
outputs = cli.getOptionValues("output");
fresh = cli.hasOption("fresh");
+ time = cli.hasOption("time");
cleanup = cli.hasOption("cleanup");
simulate = cli.hasOption("simulate");
yes = cli.hasOption("yes");
@@ -807,7 +911,7 @@ public class ECTesterReader {
}
format = cli.getOptionValue("format");
- String formats[] = new String[]{"text", "xml", "yaml", "yml"};
+ String[] formats = new String[]{"text", "xml", "yaml", "yml"};
if (format != null && !Arrays.asList(formats).contains(format)) {
System.err.println(Colors.error("Wrong output format " + format + ". Should be one of " + Arrays.toString(formats)));
return false;
@@ -906,6 +1010,21 @@ public class ECTesterReader {
System.err.println(Colors.error("Unknown test suite " + testSuite + ". Should be one of: " + Arrays.toString(tests)));
return false;
}
+
+ String[] opts = cli.getOptionValue("test-options", "").split(",");
+ List<String> validOpts = Arrays.asList("preset");
+ testOptions = new HashSet<>();
+ for (String opt : opts) {
+ if (opt.equals("")) {
+ continue;
+ }
+ if (!validOpts.contains(opt)) {
+ System.err.println(Colors.error("Unknown test option " + opt + ". Should be one of: " + "preset."));
+ return false;
+ } else {
+ testOptions.add(opt);
+ }
+ }
} else if (cli.hasOption("ecdh")) {
if (primeField == binaryField) {
System.err.print(Colors.error("Need to specify field with -fp or -f2m. (not both)"));
diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java
index a3560df..bf2441f 100644
--- a/src/cz/crcs/ectester/reader/command/Command.java
+++ b/src/cz/crcs/ectester/reader/command/Command.java
@@ -11,6 +11,7 @@ import cz.crcs.ectester.common.util.CardUtil;
import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.output.ResponseWriter;
import cz.crcs.ectester.reader.response.Response;
import javacard.security.KeyPair;
@@ -28,6 +29,11 @@ import java.util.List;
public abstract class Command implements Cloneable {
CommandAPDU cmd;
CardMngr cardManager;
+ // Workaround for a stupid Java bug that went unfixed for !12! years,
+ // and for the even more stupid module system, which cannot properly work
+ // with the fact that JCardSim has some java.* packages...
+ final byte[] GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM = new byte[]{0};
+
Command(CardMngr cardManager) {
this.cardManager = cardManager;
@@ -54,23 +60,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 +75,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;
+ }
+ }
+
+
+ /**
+ * @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);
+ }
- byte[] external = curve.flatten();
- if (external == null) {
- throw new IOException("Couldn't read the curve file correctly.");
+ 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());
}
@@ -196,6 +200,19 @@ public abstract class Command implements Cloneable {
return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, params, data);
}
+ public static long dryRunTime(CardMngr cardManager, Command cmd, int num, ResponseWriter respWriter) throws CardException {
+ long time = 0;
+ respWriter.outputResponse(new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_DRY_RUN).send());
+ for (int i = 0; i < num; ++i) {
+ Response dry = cmd.send();
+ respWriter.outputResponse(dry);
+ time += dry.getDuration();
+ }
+ time /= num;
+ respWriter.outputResponse(new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_NORMAL).send());
+ return time;
+ }
+
/**
*
*/
@@ -324,7 +341,7 @@ public abstract class Command implements Cloneable {
super(cardManager);
this.keyPair = keyPair;
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEAR, keyPair, 0x00);
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEAR, keyPair, 0x00, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM);
}
@Override
@@ -474,7 +491,7 @@ public abstract class Command implements Cloneable {
super(cardManager);
this.keyPair = keyPair;
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GENERATE, keyPair, 0);
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GENERATE, keyPair, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM);
}
@Override
@@ -846,7 +863,7 @@ public abstract class Command implements Cloneable {
public Cleanup(CardMngr cardManager) {
super(cardManager);
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEANUP, 0, 0);
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEANUP, 0, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM);
}
@Override
@@ -874,7 +891,7 @@ public abstract class Command implements Cloneable {
public GetInfo(CardMngr cardManager) {
super(cardManager);
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GET_INFO, 0, 0);
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GET_INFO, 0, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM);
}
@Override
@@ -890,5 +907,36 @@ public abstract class Command implements Cloneable {
return "Get applet info";
}
}
+
+ /**
+ *
+ */
+ public static class SetDryRunMode extends Command {
+ private byte dryRunMode;
+
+ /**
+ * @param cardManager
+ * @param dryRunMode
+ */
+ public SetDryRunMode(CardMngr cardManager, byte dryRunMode) {
+ super(cardManager);
+ this.dryRunMode = dryRunMode;
+
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SET_DRY_RUN_MODE, dryRunMode, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM);
+ }
+
+ @Override
+ public Response.SetDryRunMode send() throws CardException {
+ long elapsed = -System.nanoTime();
+ ResponseAPDU response = cardManager.send(cmd);
+ elapsed += System.nanoTime();
+ return new Response.SetDryRunMode(response, getDescription(), elapsed);
+ }
+
+ @Override
+ public String getDescription() {
+ return (dryRunMode == ECTesterApplet.MODE_NORMAL ? "Disable" : "Enable") + " dry run mode";
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java
index e89d403..2775647 100644
--- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java
@@ -52,6 +52,7 @@ public class TextTestWriter extends BaseTextTestWriter {
sb.append("═══ ").append(Colors.underline("Card ATR:")).append(" ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator());
sb.append("═══ ").append(Colors.underline("JavaCard version:")).append(" ").append(info.getJavaCardVersion()).append(System.lineSeparator());
sb.append("═══ ").append(Colors.underline("Array sizes (apduBuf, ram, ram2, apduArr):")).append(" ").append(String.format("%d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength())).append(System.lineSeparator());
+ sb.append("═══ ").append(Colors.underline("Test options:")).append(" ").append(String.join(",", cardSuite.getCfg().testOptions)).append(System.lineSeparator());
CardMngr.CPLC cplc = cardSuite.getCard().getCPLC();
if (!cplc.values().isEmpty()) {
sb.append("═══ ").append(Colors.underline("Card CPLC data:")).append(System.lineSeparator());
diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
index 9add072..fc41805 100644
--- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
@@ -114,7 +114,7 @@ public class XMLTestWriter extends BaseXMLTestWriter {
Response.GetInfo info = new Command.GetInfo(card).send();
result.setAttribute("version", info.getVersion());
result.setAttribute("javacard", String.format("%.1f", info.getJavaCardVersion()));
- result.setAttribute("base", String.format("%#x",info.getBase()));
+ result.setAttribute("base", String.format("%#x", info.getBase()));
result.setAttribute("cleanup", String.valueOf(info.getCleanupSupport()));
Element arrays = doc.createElement("arrays");
Element apduBuf = doc.createElement("length");
diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java
index 235564e..6232423 100644
--- a/src/cz/crcs/ectester/reader/response/Response.java
+++ b/src/cz/crcs/ectester/reader/response/Response.java
@@ -474,11 +474,11 @@ public abstract class Response {
byte major = (byte) (jcVersion >> 8);
byte minor = (byte) (jcVersion & 0xff);
int minorSize;
- if (minor == 0) {
- minorSize = 1;
- } else {
- minorSize = (int) Math.ceil(Math.log10(minor));
- }
+ if (minor == 0) {
+ minorSize = 1;
+ } else {
+ minorSize = (int) Math.ceil(Math.log10(minor));
+ }
return (major + ((float) (minor) / (minorSize * 10)));
}
@@ -502,4 +502,16 @@ public abstract class Response {
return apduArrayLength;
}
}
+
+ /**
+ *
+ */
+ public static class SetDryRunMode extends Response {
+
+ public SetDryRunMode(ResponseAPDU response, String description, long time) {
+ super(response, description, time);
+
+ parse(1, 0);
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
index 172c8af..982e07a 100644
--- a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
@@ -25,7 +25,8 @@ import static cz.crcs.ectester.common.test.Result.ExpectedValue;
*/
public class CardCofactorSuite extends CardTestSuite {
public CardCofactorSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "cofactor", "The cofactor test suite tests whether the card correctly rejects points on the curve but not in the subgroup generated by the generator during ECDH.");
+ super(writer, cfg, cardManager, "cofactor", "The cofactor test suite tests whether the card correctly rejects points on the curve",
+ "but not in the subgroup generated by the generator(so of small order, dividing the cofactor) during ECDH.");
}
@Override
@@ -38,7 +39,7 @@ public class CardCofactorSuite extends CardTestSuite {
Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS);
Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS);
+ Test generate = genOrPreset(curve, ExpectedValue.SUCCESS);
Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
diff --git a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
index 4bf9290..93d50e8 100644
--- a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
@@ -25,7 +25,8 @@ import static cz.crcs.ectester.common.test.Result.ExpectedValue;
public class CardCompositeSuite extends CardTestSuite {
public CardCompositeSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "composite", "The composite suite runs ECDH over curves with composite order. This should generally fail, as using such a curve is unsafe.");
+ super(writer, cfg, cardManager, "composite", "The composite suite runs ECDH over curves with composite order.",
+ "Various types of compositeness is tested: smooth numbers, Carmichael pseudoprime, prime square, product of two large primes.");
}
@Override
@@ -48,11 +49,18 @@ public class CardCompositeSuite extends CardTestSuite {
}
tests.add(allocate);
tests.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY));
- tests.add(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY));
+
+ String name;
+ if (cfg.testOptions.contains("preset")) {
+ name = "preset semi-random key";
+ } else {
+ name = "generated key";
+ }
+ tests.add(genOrPreset(curve, ExpectedValue.ANY));
for (EC_Key key : curveKeys.getValue()) {
Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, key.flatten());
Test ecdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key.");
- tests.add(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ", " + key.getDesc(), ecdh));
+ tests.add(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ", with " + name + ", " + key.getDesc(), ecdh));
}
doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ".", tests.toArray(new Test[0])));
}
diff --git a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
index 291cc04..c86c0b1 100644
--- a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
@@ -29,7 +29,9 @@ import java.util.Map;
public class CardCompressionSuite extends CardTestSuite {
public CardCompressionSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
super(writer, cfg, cardManager, "compression", "The compression test suite tests cards support for compressed points in ECDH (as per ANSI X9.62).",
- "It also tests for handling of bogus input by using the point at infinity and a hybrid point with the y coordinate corrupted.");
+ "It also tests for handling of bogus input in ECDH by using the point at infinity and a hybrid point with the y coordinate corrupted.",
+ "It also tests handling of compressed point in ECDH, where the x coordinate is invalid and therefore",
+ "a quadratic non-residue will be computed and (square root-ed) during decompression.");
}
@Override
diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
index 91f9ef6..ebece61 100644
--- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
@@ -10,7 +10,6 @@ import cz.crcs.ectester.common.util.CardUtil;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
import javacard.security.KeyPair;
import java.util.LinkedList;
@@ -29,7 +28,7 @@ import static cz.crcs.ectester.common.test.Result.Value;
public class CardDefaultSuite extends CardTestSuite {
public CardDefaultSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "default", "The default test suite tests basic support of ECDH and ECDSA.");
+ super(writer, cfg, cardManager, "default", "The default test suite tests basic support and performance of ECDH and ECDSA.");
}
@Override
@@ -83,7 +82,7 @@ public class CardDefaultSuite extends CardTestSuite {
Test compound;
if (ka.ok()) {
- Test perfTest = runTest(PerformanceTest.repeat(ecdh, 10));
+ Test perfTest = runTest(PerformanceTest.repeat(this.card, ecdh, 10));
compound = runTest(CompoundTest.function(kaCallback, kaDesc, allocate, ka, kaCompressed, perfTest));
} else {
compound = runTest(CompoundTest.function(kaCallback, kaDesc, allocate, ka, kaCompressed));
@@ -114,10 +113,10 @@ public class CardDefaultSuite extends CardTestSuite {
Test compound;
if (expect.ok()) {
Command ecdsaSign = new Command.ECDSA_sign(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, ECTesterApplet.EXPORT_TRUE, sigData);
- PerformanceTest signTest = runTest(PerformanceTest.repeat("Sign", ecdsaSign, 10));
+ PerformanceTest signTest = runTest(PerformanceTest.repeat(this.card, "Sign", ecdsaSign, 10));
byte[] signature = signTest.getResponses()[0].getParam(0);
Command ecdsaVerify = new Command.ECDSA_verify(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, sigData, signature);
- PerformanceTest verifyTest = runTest(PerformanceTest.repeat("Verify", ecdsaVerify, 10));
+ PerformanceTest verifyTest = runTest(PerformanceTest.repeat(this.card, "Verify", ecdsaVerify, 10));
compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect, signTest, verifyTest));
} else {
compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect));
diff --git a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
index f434d4d..730c70b 100644
--- a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
@@ -25,7 +25,7 @@ public class CardDegenerateSuite extends CardTestSuite {
public CardDegenerateSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
super(writer, cfg, cardManager, "degenerate", "The degenerate suite tests whether the card rejects points outside of the curve during ECDH.",
- "The tested points lie on a part of the plane for which some Edwards, Hessian and Huff form addition formulas work.");
+ "The tested points lie on a part of the plane for which some Edwards, Hessian and Huff form addition formulas degenerate into exponentiation in the base finite field.");
}
@Override
@@ -36,27 +36,32 @@ public class CardDegenerateSuite extends CardTestSuite {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
- Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS);
+ Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
+ if (!allocate.ok()) {
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate));
+ continue;
+ }
Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
- Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId(), allocate, set, generate);
+ Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
List<Test> ecdhTests = new LinkedList<>();
for (EC_Key.Public pub : keys) {
Test setPub = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE);
+ Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve.");
Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with degenerate pubkey.", setPub, ecdh);
Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
Test rawEcdh = CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve.");
ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " degenerate key test.", objectEcdh, rawEcdh));
+ //TODO: actually get the result of ECDH here, as well as export privkey and compare to exponentiation in Fp^*.
}
- Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with degenerate public points", ecdhTests.toArray(new Test[0]));
+ Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with degenerate public points.", ecdhTests.toArray(new Test[0]));
if (cfg.cleanup) {
Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId(), prepare, ecdh, cleanup));
+ doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId() + ".", prepare, ecdh, cleanup));
} else {
- doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId(), prepare, ecdh));
+ doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId() + ".", prepare, ecdh));
}
}
diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
index ccec401..53f3b6b 100644
--- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
@@ -33,6 +33,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
public CardEdgeCasesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
super(writer, cfg, cardManager, "edge-cases", "The edge-cases test suite tests various inputs to ECDH which may cause an implementation to achieve a certain edge-case state during it.",
"Some of the data is from the google/Wycheproof project. Tests include CVE-2017-10176 and CVE-2017-8932.",
+ "Also tests values of the private key and public key that would trigger the OpenSSL modualr multiplication bug on the P-256 curve.",
"Various edge private key values are also tested.");
}
@@ -91,7 +92,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
int firstDiff = ByteUtil.diffBytes(dh.getSecret(), 0, value.getData(0), 0, dh.secretLength());
System.err.println(ByteUtil.bytesToHex(dh.getSecret()));
System.err.println(ByteUtil.bytesToHex(value.getData(0)));
- return new Result(Result.Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + String.valueOf(firstDiff) + ".");
+ return new Result(Result.Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + firstDiff + ".");
}
return new Result(Result.Value.SUCCESS);
}
@@ -104,6 +105,10 @@ public class CardEdgeCasesSuite extends CardTestSuite {
curveTests.add(one);
}
+ if (cfg.cleanup) {
+ curveTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY));
+ }
+
Test curveTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests", curveTests.toArray(new Test[0]));
groupTests.add(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Tests on " + curve.getId() + ".", prepareCurve, curveTest));
}
@@ -149,8 +154,22 @@ public class CardEdgeCasesSuite extends CardTestSuite {
continue;
}
Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
- Test setup = CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate);
+ Test generate = genOrPreset(curve, Result.ExpectedValue.SUCCESS);
+ CommandTest export = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W), Result.ExpectedValue.SUCCESS);
+ Test setup = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate, export));
+
+ byte[] pParam = curve.getParam(EC_Consts.PARAMETER_FP)[0];
+ BigInteger p = new BigInteger(1, pParam);
+ byte[] wParam = ((Response.Export) export.getResponse()).getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W);
+ byte[] yValue = new byte[(wParam.length - 1) / 2];
+ System.arraycopy(wParam, (wParam.length / 2) + 1, yValue, 0, yValue.length);
+ BigInteger y = new BigInteger(1, yValue);
+ BigInteger negY = p.subtract(y);
+ byte[] newY = ECUtil.toByteArray(negY, curve.getBits());
+ System.arraycopy(newY, 0, wParam, (wParam.length / 2) + 1, newY.length);
+
+ EC_Params negYParams = makeParams(newY);
+ Test negYTest = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, negYParams.getParams(), negYParams.flatten()), "ECDH with pubkey negated.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
Test zeroS = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, EC_Consts.TRANSFORMATION_ZERO), "ECDH with S = 0.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
Test oneS = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, EC_Consts.TRANSFORMATION_ONE), "ECDH with S = 1.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
@@ -164,8 +183,21 @@ public class CardEdgeCasesSuite extends CardTestSuite {
BigInteger full = BigInteger.valueOf(1).shiftLeft(R.bitLength() - 1).subtract(BigInteger.ONE);
+ BigInteger alternate = full;
+ for (int i = 0; i < R.bitLength(); i += 2) {
+ alternate = alternate.clearBit(i);
+ }
+
+ BigInteger alternateOther = alternate.xor(full);
+
+ EC_Params alternateParams = makeParams(alternate);
+ Test alternateS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, alternateParams.getParams(), alternateParams.flatten()), "ECDH with S = 101010101...01010.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
+
+ EC_Params alternateOtherParams = makeParams(alternateOther);
+ Test alternateOtherS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, alternateOtherParams.getParams(), alternateOtherParams.flatten()), "ECDH with S = 010101010...10101.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
+
EC_Params fullParams = makeParams(full);
- Test fullS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, fullParams.getParams(), fullParams.flatten()), "ECDH with S = 2^((log2 r) - 1) - 1.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
+ Test fullS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, fullParams.getParams(), fullParams.flatten()), "ECDH with S = 111111111...11111 (but < r).", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
EC_Params smallerParams = makeParams(smaller);
Test smallerS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, smallerParams.getParams(), smallerParams.flatten()), "ECDH with S < r.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
@@ -191,20 +223,22 @@ public class CardEdgeCasesSuite extends CardTestSuite {
BigInteger krm1 = kr.subtract(BigInteger.ONE);
BigInteger krp1 = kr.add(BigInteger.ONE);
+ Result.ExpectedValue kExpected = K.equals(BigInteger.ONE) ? Result.ExpectedValue.SUCCESS : Result.ExpectedValue.FAILURE;
+
EC_Params krParams = makeParams(kr);
Test krS /*ONE!*/ = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krParams.getParams(), krParams.flatten()), "ECDH with S = k * r.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
EC_Params krm1Params = makeParams(krm1);
- Test krm1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krm1Params.getParams(), krm1Params.flatten()), "ECDH with S = (k * r) - 1.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
+ Test krm1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krm1Params.getParams(), krm1Params.flatten()), "ECDH with S = (k * r) - 1.", kExpected, kExpected);
EC_Params krp1Params = makeParams(krp1);
- Test krp1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krp1Params.getParams(), krp1Params.flatten()), "ECDH with S = (k * r) + 1.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
+ Test krp1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krp1Params.getParams(), krp1Params.flatten()), "ECDH with S = (k * r) + 1.", Result.ExpectedValue.ANY, Result.ExpectedValue.ANY);
if (cfg.cleanup) {
Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, zeroS, oneS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S, cleanup));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, negYTest, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S, cleanup));
} else {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, zeroS, oneS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, negYTest, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S));
}
}
@@ -249,7 +283,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
int i = 0;
for (BigInteger nearZero : zeros) {
EC_Params params = makeParams(nearZero);
- zeroTests[i++] = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearZero.toString(16), Result.ExpectedValue.ANY, Result.ExpectedValue.ANY);
+ zeroTests[i++] = ecdhTestBoth(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearZero.toString(16), Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
}
Test zeroTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near zero.", zeroTests);
@@ -257,7 +291,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
i = 0;
for (BigInteger nearP : ps) {
EC_Params params = makeParams(nearP);
- pTests[i++] = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearP.toString(16) + (nearP.compareTo(p) > 0 ? " (>p)" : " (<=p)"), Result.ExpectedValue.ANY, Result.ExpectedValue.ANY);
+ pTests[i++] = ecdhTestBoth(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearP.toString(16) + (nearP.compareTo(p) > 0 ? " (>p)" : " (<=p)"), Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
}
Test pTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near p.", pTests);
@@ -265,12 +299,23 @@ public class CardEdgeCasesSuite extends CardTestSuite {
i = 0;
for (BigInteger nearR : rs) {
EC_Params params = makeParams(nearR);
- rTests[i++] = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearR.toString(16) + (nearR.compareTo(r) > 0 ? " (>r)" : " (<=r)"), Result.ExpectedValue.ANY, Result.ExpectedValue.ANY);
+ if (nearR.compareTo(r) >= 0) {
+ rTests[i++] = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearR.toString(16) + " (>=r)", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
+ } else {
+ rTests[i++] = ecdhTestBoth(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearR.toString(16) + " (<r)", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
+ }
}
Test rTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near r.", rTests);
doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Test private key values near zero, near p and near/larger than the order.", setup, zeroTest, pTest, rTest));
}
+ private Test ecdhTestBoth(Command setPriv, String desc, Result.ExpectedValue setExpect, Result.ExpectedValue ecdhExpect) {
+ Test set = CommandTest.expect(setPriv, setExpect);
+ Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), ecdhExpect);
+
+ return CompoundTest.all(Result.ExpectedValue.SUCCESS, desc, set, ecdh);
+ }
+
private Test ecdhTest(Command setPriv, String desc, Result.ExpectedValue setExpect, Result.ExpectedValue ecdhExpect) {
Test set = CommandTest.expect(setPriv, setExpect);
Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), ecdhExpect);
diff --git a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
index 3b9e0e5..9c4b54c 100644
--- a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
@@ -40,11 +40,15 @@ public class CardInvalidSuite extends CardTestSuite {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
- Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS);
+ Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ if (!allocate.ok()) {
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate));
+ continue;
+ }
Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS);
Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS);
- Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId(), allocate, set, generate);
+ Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
List<Test> ecdhTests = new LinkedList<>();
for (EC_Key.Public pub : keys) {
@@ -55,13 +59,13 @@ public class CardInvalidSuite extends CardTestSuite {
Test rawEcdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve.", "Card incorrectly accepted point on invalid curve.");
ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " invalid key test.", objectEcdh, rawEcdh));
}
- Test ecdh = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH with invalid public points", ecdhTests.toArray(new Test[0]));
+ Test ecdh = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH with invalid public points.", ecdhTests.toArray(new Test[0]));
if (cfg.cleanup) {
Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY);
- doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), prepare, ecdh, cleanup));
+ doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId() + ".", prepare, ecdh, cleanup));
} else {
- doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), prepare, ecdh));
+ doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId() + ".", prepare, ecdh));
}
}
}
diff --git a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
index a2ce2ce..b1163c3 100644
--- a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
@@ -56,7 +56,7 @@ public class CardMiscSuite extends CardTestSuite {
}
Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.ANY);
+ Test generate = genOrPreset(curve, Result.ExpectedValue.ANY);
Test ka = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), expected);
Test sig = CommandTest.expect(new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), expected);
Test perform = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH and ECDSA.", ka, sig);
diff --git a/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java b/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
index 20546c8..0fa58d3 100644
--- a/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
@@ -22,7 +22,7 @@ import java.util.Map;
*/
public class CardSignatureSuite extends CardTestSuite {
public CardSignatureSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "signature", "Test verifying various wrong ECDSA values.");
+ super(writer, cfg, cardManager, "signature", "The signature test suite tests verifying various malformed and well-formed but invalid ECDSA signatures.");
}
@Override
diff --git a/src/cz/crcs/ectester/reader/test/CardTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTestSuite.java
index 3578f9c..73acbe7 100644
--- a/src/cz/crcs/ectester/reader/test/CardTestSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardTestSuite.java
@@ -1,9 +1,17 @@
package cz.crcs.ectester.reader.test;
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Params;
import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
import cz.crcs.ectester.common.test.TestSuite;
+import cz.crcs.ectester.common.util.ECUtil;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
/**
* @author Jan Jancar johny@neuromancer.sk
@@ -21,4 +29,18 @@ public abstract class CardTestSuite extends TestSuite {
public CardMngr getCard() {
return card;
}
+
+ public ECTesterReader.Config getCfg() {
+ return cfg;
+ }
+
+ public Test genOrPreset(EC_Curve curve, Result.ExpectedValue expected) {
+ if (cfg.testOptions.contains("preset")) {
+ byte[] presetPriv = ECUtil.semiRandomKey(curve);
+ EC_Params privParms = new EC_Params(EC_Consts.PARAMETER_S, new byte[][]{presetPriv});
+ return CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, privParms.getParams(), privParms.flatten()), expected);
+ } else {
+ return CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), expected);
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
index 3abcebb..b6dc904 100644
--- a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
@@ -30,6 +30,7 @@ import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.function.BiFunction;
import java.util.stream.Collectors;
import static cz.crcs.ectester.common.test.Result.ExpectedValue;
@@ -84,7 +85,7 @@ public class CardTestVectorSuite extends CardTestSuite {
return new Result(Value.FAILURE, "ECDH response did not contain the derived secret.");
if (!ByteUtil.compareBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength())) {
int firstDiff = ByteUtil.diffBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength());
- return new Result(Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + String.valueOf(firstDiff) + ".");
+ return new Result(Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + firstDiff + ".");
}
return new Result(Value.SUCCESS);
}
@@ -96,10 +97,12 @@ public class CardTestVectorSuite extends CardTestSuite {
}
KeyAgreement ka;
+ Signature sig;
KeyFactory kf;
MessageDigest md;
try {
ka = KeyAgreement.getInstance("ECDH", "BC");
+ sig = Signature.getInstance("ECDSAwithSHA1", "BC");
kf = KeyFactory.getInstance("ECDH", "BC");
md = MessageDigest.getInstance("SHA1", "BC");
} catch (NoSuchAlgorithmException | NoSuchProviderException ex) {
@@ -119,8 +122,26 @@ public class CardTestVectorSuite extends CardTestSuite {
testVector.add(allocate);
testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
testVector.add(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
- CommandTest export = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR), ExpectedValue.ANY);
- testVector.add(export);
+ CommandTest exportLocal = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W), ExpectedValue.ANY);
+ CommandTest exportRemote = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PRIVATE, EC_Consts.PARAMETER_S), ExpectedValue.ANY);
+ testVector.add(exportLocal);
+ testVector.add(exportRemote);
+ BiFunction<Response.Export, Response.Export, Key[]> getKeys = (localData, remoteData) -> {
+ byte[] pkey = localData.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W);
+ byte[] skey = remoteData.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_S);
+ ECParameterSpec spec = curve.toSpec();
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger(1, skey), spec);
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(ECUtil.fromX962(pkey, curve.toCurve()), spec);
+ PrivateKey privKey;
+ PublicKey pubKey;
+ try {
+ privKey = kf.generatePrivate(privKeySpec);
+ pubKey = kf.generatePublic(pubKeySpec);
+ } catch (InvalidKeySpecException ex) {
+ return null;
+ }
+ return new Key[]{privKey, pubKey};
+ };
TestCallback<CommandTestable> kaCallback = new TestCallback<CommandTestable>() {
@Override
public Result apply(CommandTestable testable) {
@@ -131,19 +152,17 @@ public class CardTestVectorSuite extends CardTestSuite {
return new Result(Value.FAILURE, "ECDH response did not contain the derived secret.");
}
byte[] secret = ecdhData.getSecret();
- Response.Export keyData = (Response.Export) export.getResponse();
- byte[] pkey = keyData.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W);
- byte[] skey = keyData.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_S);
- ECParameterSpec spec = curve.toSpec();
- ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger(1, skey), spec);
- ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(ECUtil.fromX962(pkey, curve.toCurve()), spec);
- PrivateKey privKey;
- PublicKey pubkey;
+ Response.Export localData = (Response.Export) exportLocal.getResponse();
+ Response.Export remoteData = (Response.Export) exportRemote.getResponse();
+ Key[] keys = getKeys.apply(localData, remoteData);
+ if (keys == null) {
+ return new Result(Value.SUCCESS, "Result could not be verified. keyData unavailable.");
+ }
+ PrivateKey privKey = (PrivateKey) keys[0];
+ PublicKey pubKey = (PublicKey) keys[1];
try {
- privKey = kf.generatePrivate(privKeySpec);
- pubkey = kf.generatePublic(pubKeySpec);
ka.init(privKey);
- ka.doPhase(pubkey, true);
+ ka.doPhase(pubKey, true);
byte[] rawDerived = ka.generateSecret();
int fieldSize = (curve.getBits() + 7) / 8;
if (rawDerived.length < fieldSize) {
@@ -163,14 +182,47 @@ public class CardTestVectorSuite extends CardTestSuite {
if (diff == secret.length) {
return new Result(Value.SUCCESS, "Derived secret matched expected value.");
} else {
- return new Result(Value.FAILURE, "Derived secret does not match expected value, first difference was at byte " + String.valueOf(diff) + ".");
+ return new Result(Value.FAILURE, "Derived secret does not match expected value, first difference was at byte " + diff + ".");
+ }
+ } catch (InvalidKeyException ex) {
+ return new Result(Value.SUCCESS, "Result could not be verified. " + ex.getMessage());
+ }
+ }
+ };
+ Test ecdhTest = CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), kaCallback);
+ byte[] data = new byte[32];
+ TestCallback<CommandTestable> sigCallback = new TestCallback<CommandTestable>() {
+ @Override
+ public Result apply(CommandTestable testable) {
+ Response.ECDSA ecdsaData = (Response.ECDSA) testable.getResponse();
+ if (!ecdsaData.successful())
+ return new Result(Value.FAILURE, "ECDSA was unsuccessful.");
+ if (!ecdsaData.hasSignature()) {
+ return new Result(Value.FAILURE, "ECDSA response did not contain the signature.");
+ }
+ byte[] signature = ecdsaData.getSignature();
+ Response.Export localData = (Response.Export) exportLocal.getResponse();
+ Response.Export remoteData = (Response.Export) exportRemote.getResponse();
+ Key[] keys = getKeys.apply(localData, remoteData);
+ if (keys == null) {
+ return new Result(Value.SUCCESS, "Result could not be verified. keyData unavailable.");
+ }
+ PublicKey pubKey = (PublicKey) keys[1];
+ try {
+ sig.initVerify(pubKey);
+ sig.update(data);
+ if (sig.verify(signature)) {
+ return new Result(Value.SUCCESS, "Signature verified.");
+ } else {
+ return new Result(Value.FAILURE, "Signature failed to verify.");
}
- } catch (InvalidKeySpecException | InvalidKeyException ex) {
+ } catch (InvalidKeyException | SignatureException ex) {
return new Result(Value.SUCCESS, "Result could not be verified. " + ex.getMessage());
}
}
};
- testVector.add(CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), kaCallback));
+ Test ecdsaTest = CommandTest.function(new Command.ECDSA_sign(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_TRUE, data), sigCallback);
+ testVector.add(CompoundTest.all(ExpectedValue.SUCCESS, "", ecdhTest, ecdsaTest));
if (cfg.cleanup) {
testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY));
}
diff --git a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
index 3df4c65..4929d52 100644
--- a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
@@ -34,29 +34,33 @@ public class CardTwistSuite extends CardTestSuite {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
- Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS);
+ Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
+ if (!allocate.ok()) {
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate));
+ continue;
+ }
Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
- Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId(), allocate, set, generate);
+ Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
List<Test> ecdhTests = new LinkedList<>();
for (EC_Key.Public pub : keys) {
Test setPub = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE);
+ Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE, "Card correctly rejected point on twist.", "Card incorrectly accepted point on twist.");
Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with twist pubkey.", setPub, ecdh);
Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
Test rawEcdh = CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on twist.", "Card incorrectly accepted point on twist.");
ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " twist key test.", objectEcdh, rawEcdh));
}
- Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with public points on twist", ecdhTests.toArray(new Test[0]));
+ Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with public points on twist.", ecdhTests.toArray(new Test[0]));
Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", ecdh);
if (cfg.cleanup) {
Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), prepare, tests, cleanup));
+ doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId() + ".", prepare, tests, cleanup));
} else {
- doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), prepare, tests));
+ doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId() + ".", prepare, tests));
}
}
}
diff --git a/src/cz/crcs/ectester/reader/test/CommandTest.java b/src/cz/crcs/ectester/reader/test/CommandTest.java
index adad191..b05d3e4 100644
--- a/src/cz/crcs/ectester/reader/test/CommandTest.java
+++ b/src/cz/crcs/ectester/reader/test/CommandTest.java
@@ -32,7 +32,7 @@ public class CommandTest extends SimpleTest<CommandTestable> {
@Override
public Result apply(CommandTestable commandTestable) {
Result.Value resultValue = Result.Value.fromExpected(expected, commandTestable.ok(), commandTestable.error());
- return new Result(resultValue, resultValue.ok() ? ok : nok);
+ return new Result(resultValue, commandTestable.error() ? commandTestable.errorCause() : (resultValue.ok() ? ok : nok));
}
});
}
diff --git a/src/cz/crcs/ectester/reader/test/PerformanceTest.java b/src/cz/crcs/ectester/reader/test/PerformanceTest.java
index f9a4472..f9cba46 100644
--- a/src/cz/crcs/ectester/reader/test/PerformanceTest.java
+++ b/src/cz/crcs/ectester/reader/test/PerformanceTest.java
@@ -1,18 +1,24 @@
package cz.crcs.ectester.reader.test;
+import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.common.test.Result;
import cz.crcs.ectester.common.test.SimpleTest;
import cz.crcs.ectester.common.test.TestCallback;
+import cz.crcs.ectester.common.test.TestException;
+import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.command.Command;
import cz.crcs.ectester.reader.response.Response;
+import javax.smartcardio.CardException;
import java.util.Arrays;
/**
* @author Jan Jancar johny@neuromancer.sk
*/
public class PerformanceTest extends SimpleTest<CommandTestable> {
+ private CardMngr cardManager;
private long[] times;
+ private long[] reducedTimes;
private Response[] responses;
private long mean;
private long median;
@@ -20,23 +26,24 @@ public class PerformanceTest extends SimpleTest<CommandTestable> {
private int count;
private String desc;
- private PerformanceTest(CommandTestable testable, int count, String desc) {
+ private PerformanceTest(CardMngr cardManager, CommandTestable testable, int count, String desc) {
super(testable, new TestCallback<CommandTestable>() {
@Override
public Result apply(CommandTestable testable) {
return new Result(Result.Value.SUCCESS);
}
});
+ this.cardManager = cardManager;
this.count = count;
this.desc = desc;
}
- public static PerformanceTest repeat(Command cmd, int count) {
- return new PerformanceTest(new CommandTestable(cmd), count, null);
+ public static PerformanceTest repeat(CardMngr cardManager, Command cmd, int count) {
+ return new PerformanceTest(cardManager, new CommandTestable(cmd), count, null);
}
- public static PerformanceTest repeat(String desc, Command cmd, int count) {
- return new PerformanceTest(new CommandTestable(cmd), count, desc);
+ public static PerformanceTest repeat(CardMngr cardManager, String desc, Command cmd, int count) {
+ return new PerformanceTest(cardManager, new CommandTestable(cmd), count, desc);
}
@Override
@@ -47,18 +54,35 @@ public class PerformanceTest extends SimpleTest<CommandTestable> {
@Override
protected void runSelf() {
+ long baseTime;
+ try {
+ new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_DRY_RUN).send();
+ testable.run();
+ baseTime = testable.getResponse().getDuration();
+ testable.reset();
+ testable.run();
+ baseTime += testable.getResponse().getDuration();
+ testable.reset();
+ baseTime /= 2;
+ new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_NORMAL).send();
+ } catch (CardException ce) {
+ throw new TestException(ce);
+ }
+
times = new long[count];
+ reducedTimes = new long[count];
responses = new Response[count];
for (int i = 0; i < count; ++i) {
testable.run();
responses[i] = testable.getResponse();
times[i] = responses[i].getDuration();
+ reducedTimes[i] = times[i] - baseTime;
testable.reset();
}
- mean = Arrays.stream(times).sum() / count;
+ mean = Arrays.stream(reducedTimes).sum() / count;
- long[] sorted = times.clone();
+ long[] sorted = reducedTimes.clone();
Arrays.sort(sorted);
if (count % 2 == 0) {
median = (sorted[(count / 2) - 1] + sorted[count / 2]) / 2;
@@ -99,6 +123,10 @@ public class PerformanceTest extends SimpleTest<CommandTestable> {
return times;
}
+ public long[] getReducedTimes() {
+ return reducedTimes;
+ }
+
public long getMean() {
return mean;
}
diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
index 707f031..f3fe840 100644
--- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
+++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -24,6 +24,8 @@ package cz.crcs.ectester.standalone;
import cz.crcs.ectester.common.cli.*;
import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.ec.EC_Keypair;
import cz.crcs.ectester.common.output.TestWriter;
import cz.crcs.ectester.common.test.TestException;
import cz.crcs.ectester.common.util.ByteUtil;
@@ -51,6 +53,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
+import java.math.BigInteger;
import java.nio.file.Files;
import java.security.*;
import java.security.interfaces.ECPrivateKey;
@@ -140,7 +143,6 @@ public class ECTesterStandalone {
System.err.println("Invalid algorithm parameter: " + e.getMessage());
} catch (NoSuchAlgorithmException nsaex) {
System.err.println("Algorithm not supported by the selected library: " + nsaex.getMessage());
- nsaex.printStackTrace();
} catch (InvalidKeyException | SignatureException e) {
e.printStackTrace();
}
@@ -150,6 +152,8 @@ public class ECTesterStandalone {
Map<String, ParserOptions> actions = new TreeMap<>();
Option namedCurve = Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: <cat/id>").hasArg().argName("cat/id").optionalArg(false).build();
+ Option namedPublic = Option.builder("npub").longOpt("named-public").desc("Use a named public key, from CurveDB: <cat/id>").hasArg().argName("cat/id").optionalArg(false).build();
+ Option namedPrivate = Option.builder("npriv").longOpt("named-private").desc("Use a named private key, from CurveDB: <cat/id>").hasArg().argName("cat/id").optionalArg(false).build();
Option curveName = Option.builder("cn").longOpt("curve-name").desc("Use a named curve, search from curves supported by the library: <name>").hasArg().argName("name").optionalArg(false).build();
Option bits = Option.builder("b").longOpt("bits").hasArg().argName("n").optionalArg(false).desc("What size of curve to use.").build();
Option output = Option.builder("o").longOpt("output").desc("Output into file <output_file>.").hasArgs().argName("output_file").optionalArg(false).build();
@@ -176,7 +180,9 @@ public class ECTesterStandalone {
ecdhOpts.addOption(Option.builder("t").longOpt("type").desc("Set KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build());
ecdhOpts.addOption(Option.builder().longOpt("key-type").desc("Set the key [algorithm] for which the key should be derived in KeyAgreements with KDF. Default is \"AES\".").hasArg().argName("algorithm").optionalArg(false).build());
ecdhOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDH [amount] times.").build());
+ ecdhOpts.addOption(namedPrivate);
ecdhOpts.addOption(Option.builder().longOpt("fixed-private").desc("Perform ECDH with fixed private key.").build());
+ ecdhOpts.addOption(namedPublic);
ecdhOpts.addOption(Option.builder().longOpt("fixed-public").desc("Perform ECDH with fixed public key.").build());
ParserOptions ecdh = new ParserOptions(new DefaultParser(), ecdhOpts, "Perform EC based KeyAgreement.");
actions.put("ecdh", ecdh);
@@ -185,7 +191,9 @@ public class ECTesterStandalone {
ecdsaOpts.addOption(bits);
ecdsaOpts.addOption(namedCurve);
ecdsaOpts.addOption(curveName);
- ecdhOpts.addOption(output);
+ ecdsaOpts.addOption(output);
+ ecdsaOpts.addOption(namedPrivate);
+ ecdsaOpts.addOption(namedPublic);
ecdsaOpts.addOption(Option.builder("t").longOpt("type").desc("Set Signature object [type].").hasArg().argName("type").optionalArg(false).build());
ecdsaOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDSA [amount] times.").build());
ecdsaOpts.addOption(Option.builder("f").longOpt("file").hasArg().argName("file").optionalArg(false).desc("Input [file] to sign.").build());
@@ -196,7 +204,7 @@ public class ECTesterStandalone {
generateOpts.addOption(bits);
generateOpts.addOption(namedCurve);
generateOpts.addOption(curveName);
- ecdhOpts.addOption(output);
+ generateOpts.addOption(output);
generateOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Generate [amount] of EC keys.").build());
generateOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPairGenerator object [type].").build());
ParserOptions generate = new ParserOptions(new DefaultParser(), generateOpts, "Generate EC keypairs.");
@@ -204,7 +212,7 @@ public class ECTesterStandalone {
Options exportOpts = new Options();
exportOpts.addOption(bits);
- ecdhOpts.addOption(output);
+ exportOpts.addOption(output);
exportOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPair object [type].").build());
ParserOptions export = new ParserOptions(new DefaultParser(), exportOpts, "Export default curve parameters.");
actions.put("export", export);
@@ -345,28 +353,48 @@ public class ECTesterStandalone {
out.println("index;time[nano];pubW;privS;secret");
KeyPair one = null;
- if (cli.hasOption("ecdh.fixed-private")) {
+ if (cli.hasOption("ecdh.fixed-private") && !cli.hasOption("ecdh.named-private")) {
one = kpg.genKeyPair();
}
KeyPair other = null;
- if (cli.hasOption("ecdh.fixed-public")) {
+ if (cli.hasOption("ecdh.fixed-public") && !cli.hasOption("ecdh.named-public")) {
other = kpg.genKeyPair();
}
+ ECPrivateKey privkey = null;
+ if (cli.hasOption("ecdh.named-private")) {
+ privkey = ECUtil.toPrivateKey(EC_Store.getInstance().getObject(EC_Key.Private.class, cli.getOptionValue("ecdh.named-private")));
+ if (privkey == null) {
+ privkey = (ECPrivateKey) ECUtil.toKeyPair(EC_Store.getInstance().getObject(EC_Keypair.class, cli.getOptionValue("ecdh.named-private"))).getPrivate();
+ }
+ }
+ ECPublicKey pubkey = null;
+ if (cli.hasOption("ecdh.named-public")) {
+ pubkey = ECUtil.toPublicKey(EC_Store.getInstance().getObject(EC_Key.Public.class, cli.getOptionValue("ecdh.named-public")));
+ if (pubkey == null) {
+ pubkey = (ECPublicKey) ECUtil.toKeyPair(EC_Store.getInstance().getObject(EC_Keypair.class, cli.getOptionValue("ecdh.named-public"))).getPublic();
+ }
+ }
+
int amount = Integer.parseInt(cli.getOptionValue("ecdh.amount", "1"));
for (int i = 0; i < amount; ++i) {
- if (!cli.hasOption("ecdh.fixed-private")) {
+ if (!cli.hasOption("ecdh.fixed-private") && !cli.hasOption("ecdh.named-private")) {
one = kpg.genKeyPair();
}
- if (!cli.hasOption("ecdh.fixed-public")) {
+ if (!cli.hasOption("ecdh.fixed-public") && !cli.hasOption("ecdh.named-public")) {
other = kpg.genKeyPair();
}
- ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
- ECPublicKey pubkey = (ECPublicKey) other.getPublic();
+ if (!cli.hasOption("ecdh.named-private")) {
+ privkey = (ECPrivateKey) one.getPrivate();
+ }
+
+ if (!cli.hasOption("ecdh.named-public")) {
+ pubkey = (ECPublicKey) other.getPublic();
+ }
long elapsed = -System.nanoTime();
- if (spec instanceof ECParameterSpec) {
+ if (spec instanceof ECParameterSpec && lib instanceof NativeECLibrary) {
ka.init(privkey, spec);
} else {
ka.init(privkey);
@@ -415,7 +443,7 @@ public class ECTesterStandalone {
data = Files.readAllBytes(in.toPath());
dataString = "";
} else {
- SecureRandom random = new SecureRandom();
+ Random random = new Random();
data = new byte[32];
random.nextBytes(data);
dataString = ByteUtil.bytesToHex(data, false);
@@ -455,6 +483,7 @@ public class ECTesterStandalone {
}
Signature sig = sigIdent.getInstance(lib.getProvider());
KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
+ ECParameterSpec spec = null;
if (cli.hasOption("ecdsa.bits")) {
int bits = Integer.parseInt(cli.getOptionValue("ecdsa.bits"));
kpg.initialize(bits);
@@ -465,7 +494,8 @@ public class ECTesterStandalone {
System.err.println("Curve not found: " + curveName);
return;
}
- kpg.initialize(curve.toSpec());
+ spec = curve.toSpec();
+ kpg.initialize(spec);
} else if (cli.hasOption("ecdsa.curve-name")) {
String curveName = cli.getOptionValue("ecdsa.curve-name");
kpg.initialize(new ECGenParameterSpec(curveName));
@@ -478,14 +508,35 @@ public class ECTesterStandalone {
out = System.out;
}
- out.println("index;data;signTime[nano];verifyTime[nano];pubW;privS;signature;verified");
+ out.println("index;signTime[nano];verifyTime[nano];data;pubW;privS;signature;nonce;verified");
+
+ ECPrivateKey privkey = null;
+ if (cli.hasOption("ecdsa.named-private")) {
+ privkey = ECUtil.toPrivateKey(EC_Store.getInstance().getObject(EC_Key.Private.class, cli.getOptionValue("ecdsa.named-private")));
+ if (privkey == null) {
+ privkey = (ECPrivateKey) ECUtil.toKeyPair(EC_Store.getInstance().getObject(EC_Keypair.class, cli.getOptionValue("ecdsa.named-private"))).getPrivate();
+ }
+ }
+ ECPublicKey pubkey = null;
+ if (cli.hasOption("ecdsa.named-public")) {
+ pubkey = ECUtil.toPublicKey(EC_Store.getInstance().getObject(EC_Key.Public.class, cli.getOptionValue("ecdsa.named-public")));
+ if (pubkey == null) {
+ pubkey = (ECPublicKey) ECUtil.toKeyPair(EC_Store.getInstance().getObject(EC_Keypair.class, cli.getOptionValue("ecdsa.named-public"))).getPublic();
+ }
+ }
int amount = Integer.parseInt(cli.getOptionValue("ecdsa.amount", "1"));
for (int i = 0; i < amount; ++i) {
- KeyPair one = kpg.genKeyPair();
+ if (!cli.hasOption("ecdsa.named-private") || !cli.hasOption("ecdsa.named-public")) {
+ KeyPair one = kpg.genKeyPair();
- ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
- ECPublicKey pubkey = (ECPublicKey) one.getPublic();
+ if (!cli.hasOption("ecdsa.named-private")) {
+ privkey = (ECPrivateKey) one.getPrivate();
+ }
+ if (!cli.hasOption("ecdsa.named-public")) {
+ pubkey = (ECPublicKey) one.getPublic();
+ }
+ }
sig.initSign(privkey);
sig.update(data);
@@ -510,7 +561,14 @@ public class ECTesterStandalone {
String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
String sign = ByteUtil.bytesToHex(signature, false);
- out.println(String.format("%d;%s;%d;%d;%s;%s;%s;%d", i, dataString, signTime, verifyTime, pub, priv, sign, verified ? 1 : 0));
+ String k = "";
+ if (spec != null) {
+ BigInteger kValue = ECUtil.recoverSignatureNonce(signature, data, privkey.getS(), spec, sigIdent.getHashAlgo());
+ if (kValue != null) {
+ k = ByteUtil.bytesToHex(kValue.toByteArray(), false);
+ }
+ }
+ out.println(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d", i, signTime, verifyTime, dataString, pub, priv, sign, k, verified ? 1 : 0));
}
if (cli.hasOption("ecdsa.output")) {
diff --git a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
index e40731b..7f9adb4 100644
--- a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
+++ b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
@@ -104,6 +104,7 @@ public class SignatureIdent extends Ident {
int split = alias.indexOf("with");
this.hash = alias.substring(0, split);
this.sig = alias.substring(split + 4);
+ break;
}
}
}