aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2017-01-31 20:15:24 +0100
committerJ08nY2017-01-31 20:15:24 +0100
commitabe9f00e15993d55a71b8b328f430421f2f2f151 (patch)
tree237e1be2bf0209ab422c1b6ce02671bcf33f5d2d
parentc3e48df92858bad5e74e9cec69c16397b6b12481 (diff)
downloadECTester-abe9f00e15993d55a71b8b328f430421f2f2f151.tar.gz
ECTester-abe9f00e15993d55a71b8b328f430421f2f2f151.tar.zst
ECTester-abe9f00e15993d55a71b8b328f430421f2f2f151.zip
-rw-r--r--!uploader/ectester.capbin13641 -> 13691 bytes
-rw-r--r--dist/ECTester.jarbin78703 -> 284484 bytes
-rw-r--r--src/cz/crcs/ectester/applet/ECKeyGenerator.java115
-rw-r--r--src/cz/crcs/ectester/applet/ECKeyTester.java22
-rw-r--r--src/cz/crcs/ectester/applet/ECTesterApplet.java182
-rw-r--r--src/cz/crcs/ectester/applet/EC_Consts.java15
-rw-r--r--src/cz/crcs/ectester/reader/Command.java66
-rw-r--r--src/cz/crcs/ectester/reader/ECParams.java (renamed from src/cz/crcs/ectester/reader/ParamReader.java)81
-rw-r--r--src/cz/crcs/ectester/reader/ECTester.java196
-rw-r--r--src/cz/crcs/ectester/reader/Response.java217
-rw-r--r--src/cz/crcs/ectester/reader/Util.java2
11 files changed, 527 insertions, 369 deletions
diff --git a/!uploader/ectester.cap b/!uploader/ectester.cap
index 8d1bff8..f570b6f 100644
--- a/!uploader/ectester.cap
+++ b/!uploader/ectester.cap
Binary files differ
diff --git a/dist/ECTester.jar b/dist/ECTester.jar
index f0a8c3b..a3429fe 100644
--- a/dist/ECTester.jar
+++ b/dist/ECTester.jar
Binary files differ
diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
index 427577b..1a17d3c 100644
--- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java
+++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
@@ -13,10 +13,6 @@ import javacard.security.KeyPair;
*/
public class ECKeyGenerator {
- public static final byte KEY_PUBLIC = 0x01;
- public static final byte KEY_PRIVATE = 0x02;
- public static final byte KEY_BOTH = KEY_PUBLIC | KEY_PRIVATE;
-
private short sw = ISO7816.SW_NO_ERROR;
/**
@@ -47,8 +43,8 @@ public class ECKeyGenerator {
public short clearPair(KeyPair keypair, byte key) {
sw = ISO7816.SW_NO_ERROR;
try {
- if ((key & KEY_PUBLIC) != 0) keypair.getPublic().clearKey();
- if ((key & KEY_PRIVATE) != 0) keypair.getPrivate().clearKey();
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) keypair.getPublic().clearKey();
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) keypair.getPrivate().clearKey();
} catch (CryptoException ce) {
sw = ce.getReason();
} catch (Exception e) {
@@ -78,7 +74,7 @@ public class ECKeyGenerator {
}
public short setCurve(KeyPair keypair, byte curve, short params, byte[] buffer, short offset) {
- return setCurve(keypair, KEY_BOTH, curve, params, buffer, offset);
+ return setCurve(keypair, EC_Consts.KEY_BOTH, curve, params, buffer, offset);
}
public short setCurve(KeyPair keypair, byte key, byte curve, short params, byte[] buffer, short offset) {
@@ -90,6 +86,7 @@ public class ECKeyGenerator {
}
short length;
+ //handle fp and f2m differently, as a FP KeyPair doesnt contain a F2M field and vice versa.
if (alg == KeyPair.ALG_EC_FP && (params & EC_Consts.PARAMETER_FP) != 0) {
length = EC_Consts.getCurveParameter(curve, EC_Consts.PARAMETER_FP, buffer, offset);
sw = setParameter(keypair, key, EC_Consts.PARAMETER_FP, buffer, offset, length);
@@ -122,7 +119,7 @@ public class ECKeyGenerator {
* @return
*/
public short corruptCurve(KeyPair keypair, short corruptParams, byte corruption, byte[] buffer, short offset) {
- return corruptCurve(keypair, KEY_BOTH, corruptParams, corruption, buffer, offset);
+ return corruptCurve(keypair, EC_Consts.KEY_BOTH, corruptParams, corruption, buffer, offset);
}
/**
@@ -170,48 +167,42 @@ public class ECKeyGenerator {
try {
switch (param) {
- case EC_Consts.PARAMETER_FP: {
- if ((key & KEY_PUBLIC) != 0) ecPublicKey.setFieldFP(data, offset, length);
- if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setFieldFP(data, offset, length);
+ 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);
break;
- }
- case EC_Consts.PARAMETER_F2M: {
+ case EC_Consts.PARAMETER_F2M:
if (length == 2) {
short i = Util.makeShort(data[offset], data[(short) (offset + 1)]);
- if ((key & KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i);
- if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i);
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i);
} else if (length == 6) {
short i1 = Util.makeShort(data[offset], data[(short) (offset + 1)]);
short i2 = Util.makeShort(data[(short) (offset + 2)], data[(short) (offset + 3)]);
short i3 = Util.makeShort(data[(short) (offset + 4)], data[(short) (offset + 5)]);
- if ((key & KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3);
- if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3);
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3);
} else {
sw = ISO7816.SW_UNKNOWN;
}
break;
- }
- case EC_Consts.PARAMETER_A: {
- if ((key & KEY_PUBLIC) != 0) ecPublicKey.setA(data, offset, length);
- if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setA(data, offset, length);
+ 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);
break;
- }
- case EC_Consts.PARAMETER_B: {
- if ((key & KEY_PUBLIC) != 0) ecPublicKey.setB(data, offset, length);
- if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setB(data, offset, length);
+ 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);
break;
- }
- case EC_Consts.PARAMETER_G: {
- if ((key & KEY_PUBLIC) != 0) ecPublicKey.setG(data, offset, length);
- if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setG(data, offset, length);
+ 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);
break;
- }
- case EC_Consts.PARAMETER_R: {
- if ((key & KEY_PUBLIC) != 0) ecPublicKey.setR(data, offset, length);
- if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setR(data, offset, length);
+ 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);
break;
- }
- case EC_Consts.PARAMETER_K: {
+ case EC_Consts.PARAMETER_K:
short k = 0;
if (length > 2 || length <= 0) {
sw = ISO7816.SW_UNKNOWN;
@@ -221,19 +212,17 @@ public class ECKeyGenerator {
} else if (length == 1) {
k = data[offset];
}
- if ((key & KEY_PUBLIC) != 0) ecPublicKey.setK(k);
- if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setK(k);
+ 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 & KEY_PRIVATE) != 0) ecPrivateKey.setS(data, offset, length);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setS(data, offset, length);
break;
case EC_Consts.PARAMETER_W:
- if ((key & KEY_PUBLIC) != 0) ecPublicKey.setW(data, offset, length);
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setW(data, offset, length);
break;
- default: {
+ default:
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
- }
}
} catch (CryptoException ce) {
sw = ce.getReason();
@@ -251,7 +240,7 @@ public class ECKeyGenerator {
* @return
*/
public short setExternalCurve(KeyPair keypair, short params, byte[] inBuffer, short inOffset) {
- return setExternalCurve(keypair, KEY_BOTH, params, inBuffer, inOffset);
+ return setExternalCurve(keypair, EC_Consts.KEY_BOTH, params, inBuffer, inOffset);
}
/**
@@ -303,35 +292,37 @@ public class ECKeyGenerator {
switch (param) {
case EC_Consts.PARAMETER_FP:
case EC_Consts.PARAMETER_F2M:
- if ((key & KEY_PUBLIC) != 0) length = ecPublicKey.getField(outputBuffer, outputOffset);
- if ((key & KEY_PRIVATE) != 0) length = ecPrivateKey.getField(outputBuffer, outputOffset);
+ 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_A:
- if ((key & KEY_PUBLIC) != 0) length = ecPublicKey.getA(outputBuffer, outputOffset);
- if ((key & KEY_PRIVATE) != 0) length = ecPrivateKey.getA(outputBuffer, outputOffset);
+ 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 & KEY_PUBLIC) != 0) length = ecPublicKey.getB(outputBuffer, outputOffset);
- if ((key & KEY_PRIVATE) != 0) length = ecPrivateKey.getB(outputBuffer, outputOffset);
+ 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 & KEY_PUBLIC) != 0) length = ecPublicKey.getG(outputBuffer, outputOffset);
- if ((key & KEY_PRIVATE) != 0) length = ecPrivateKey.getG(outputBuffer, outputOffset);
+ 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 & KEY_PUBLIC) != 0) length = ecPublicKey.getR(outputBuffer, outputOffset);
- if ((key & KEY_PRIVATE) != 0) length = ecPrivateKey.getR(outputBuffer, outputOffset);
+ 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:
- if ((key & KEY_PUBLIC) != 0) Util.setShort(outputBuffer, outputOffset, ecPublicKey.getK());
- if ((key & KEY_PRIVATE) != 0) Util.setShort(outputBuffer, outputOffset, ecPrivateKey.getK());
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 & KEY_PUBLIC) != 0) length = ecPublicKey.getW(outputBuffer, outputOffset);
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getW(outputBuffer, outputOffset);
break;
case EC_Consts.PARAMETER_S:
- if ((key & KEY_PRIVATE) != 0) length = ecPrivateKey.getS(outputBuffer, outputOffset);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getS(outputBuffer, outputOffset);
break;
default:
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
@@ -387,17 +378,21 @@ public class ECKeyGenerator {
*
* @param from keyPair to copy from
* @param to keyPair to copy to
+ * @param params parameters to copy
* @param buffer buffer to use for copying
* @param offset offset to use in buffer
* @return sw
*/
- public short copyCurve(KeyPair from, KeyPair to, byte[] buffer, short offset) {
+ public short copyCurve(KeyPair from, KeyPair to, short params, byte[] buffer, short offset) {
sw = ISO7816.SW_NO_ERROR;
try {
short param = EC_Consts.PARAMETER_FP;
while (param <= EC_Consts.PARAMETER_K) {
- short paramLength = exportParameter(from, KEY_PUBLIC, param, buffer, offset);
- setParameter(to, KEY_BOTH, param, buffer, offset, paramLength);
+ short masked = (short) (param & params);
+ if (masked != 0) {
+ short paramLength = exportParameter(from, EC_Consts.KEY_PUBLIC, masked, buffer, offset);
+ setParameter(to, EC_Consts.KEY_BOTH, masked, buffer, offset, paramLength);
+ }
param = (short) (param << 1);
}
} catch (CryptoException ce) {
diff --git a/src/cz/crcs/ectester/applet/ECKeyTester.java b/src/cz/crcs/ectester/applet/ECKeyTester.java
index 72fa165..2e3e86e 100644
--- a/src/cz/crcs/ectester/applet/ECKeyTester.java
+++ b/src/cz/crcs/ectester/applet/ECKeyTester.java
@@ -73,22 +73,19 @@ public class ECKeyTester {
}
private short testKA_invalidPoint(KeyAgreement ka, ECPrivateKey privateKey, byte[] pubkeyBuffer, short pubkeyOffset, short pubkeyLength, byte[] outputBuffer, short outputOffset) {
- pubkeyBuffer[(short)(pubkeyLength - 2)] += 0xcc;
- pubkeyBuffer[(short)(pubkeyLength - 3)] += 0xcc;
+ pubkeyBuffer[(short) (pubkeyLength - 2)] += 0xcc;
+ pubkeyBuffer[(short) (pubkeyLength - 3)] += 0xcc;
short result = testKA(ka, privateKey, pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset);
- pubkeyBuffer[(short)(pubkeyLength - 2)] -= 0xcc;
- pubkeyBuffer[(short)(pubkeyLength - 3)] -= 0xcc;
+ pubkeyBuffer[(short) (pubkeyLength - 2)] -= 0xcc;
+ pubkeyBuffer[(short) (pubkeyLength - 3)] -= 0xcc;
return result;
}
- public short testECDH(ECPrivateKey privateKey, byte[] pubkeyBuffer, short pubkeyOffset, short pubkeyLength, byte[] outputBuffer, short outputOffset) {
- return testKA(ecdhKeyAgreement, privateKey, pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset);
- }
-
/**
* Tests ECDH secret generation with given {@code privateKey} and {@code publicKey}.
* Uses {@code pubkeyBuffer} at {@code pubkeyOffset} for computations.
* Output should equal with ECDHC output.
+ *
* @param privateKey
* @param publicKey
* @param pubkeyBuffer
@@ -96,7 +93,6 @@ public class ECKeyTester {
* @param outputBuffer
* @param outputOffset
* @return derived secret length
- *
**/
public short testECDH_validPoint(ECPrivateKey privateKey, ECPublicKey publicKey, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset) {
short length = publicKey.getW(pubkeyBuffer, pubkeyOffset);
@@ -113,14 +109,15 @@ public class ECKeyTester {
* Tests ECDHC secret generation with given {@code privateKey} and {@code publicKey}.
* Uses {@code pubkeyBuffer} at {@code pubkeyOffset} for computations.
* Output should equal to ECDH output.
+ *
* @param privateKey
* @param publicKey
* @param pubkeyBuffer
* @param pubkeyOffset
* @param outputBuffer
* @param outputOffset
- * @return ISO7816.SW_NO_ERROR on correct operation,
- * exception reason otherwise
+ * @return ISO7816.SW_NO_ERROR on correct operation,
+ * exception reason otherwise
*/
public short testECDHC_validPoint(ECPrivateKey privateKey, ECPublicKey publicKey, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset) {
short length = publicKey.getW(pubkeyBuffer, pubkeyOffset);
@@ -136,6 +133,7 @@ public class ECKeyTester {
* Uses {@code signKey} to sign data from {@code inputBuffer} at {@code inputOffset} with {@code inputOffset}.
* Then checks for correct signature length.
* Then tries verifying the data with {@code verifyKey}.
+ *
* @param signKey
* @param verifyKey
* @param inputBuffer
@@ -143,7 +141,7 @@ public class ECKeyTester {
* @param inputLength
* @param sigBuffer
* @param sigOffset
- * @return signature length
+ * @return signature length
*/
public short testECDSA(ECPrivateKey signKey, ECPublicKey verifyKey, byte[] inputBuffer, short inputOffset, short inputLength, byte[] sigBuffer, short sigOffset) {
sw = ISO7816.SW_NO_ERROR;
diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java
index cb2c43f..ae19e28 100644
--- a/src/cz/crcs/ectester/applet/ECTesterApplet.java
+++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java
@@ -20,8 +20,8 @@
* SOFTWARE.
*/
/*
- * PACKAGEID: 4C6162616B417070
- * APPLETID: 4C6162616B4170706C6574
+ * PACKAGEID: 4543546573746572
+ * APPLETID: 45435465737465723031
*/
package cz.crcs.ectester.applet;
@@ -32,7 +32,7 @@ import javacard.security.KeyPair;
import javacard.security.RandomData;
/**
- * Reader part of ECTester, a tool for testing Elliptic curve support on javacards.
+ * Applet part of ECTester, a tool for testing Elliptic curve support on javacards.
*
* @author Petr Svenda petr@svenda.com
* @author Jan Jancar johny@neuromancer.sk
@@ -42,35 +42,32 @@ public class ECTesterApplet extends Applet {
// MAIN INSTRUCTION CLASS
public static final byte CLA_ECTESTERAPPLET = (byte) 0xB0;
- //INSTRUCTIONS
+ // INSTRUCTIONS
public static final byte INS_ALLOCATE = (byte) 0x5a;
public static final byte INS_CLEAR = (byte) 0x5b;
public static final byte INS_SET = (byte) 0x5c;
public static final byte INS_GENERATE = (byte) 0x5d;
- public static final byte INS_ECDH = (byte) 0x5e;
- public static final byte INS_ECDSA = (byte) 0x5f;
+ public static final byte INS_EXPORT = (byte) 0x5e;
+ public static final byte INS_ECDH = (byte) 0x5f;
+ public static final byte INS_ECDSA = (byte) 0x60;
- //PARAMETERS for P1 and P2
+ // PARAMETERS for P1 and P2
public static final byte KEYPAIR_LOCAL = (byte) 0x01;
public static final byte KEYPAIR_REMOTE = (byte) 0x02;
public static final byte KEYPAIR_BOTH = KEYPAIR_LOCAL | KEYPAIR_REMOTE;
- public static final byte EXPORT_NONE = (byte) 0x00;
- public static final byte EXPORT_PUBLIC = (byte) 0x04;
- public static final byte EXPORT_PRIVATE = (byte) 0x08;
- public static final byte EXPORT_BOTH = EXPORT_PUBLIC | EXPORT_PRIVATE;
- public static final byte EXPORT_ECDH = (byte) 0x10;
- public static final byte EXPORT_SIG = (byte) 0x20;
+ public static final byte EXPORT_TRUE = (byte) 0xff;
+ public static final byte EXPORT_FALSE = (byte) 0x00;
- //STATUS WORDS
+ // STATUS WORDS
public static final short SW_SIG_VERIFY_FAIL = (short) 0x0ee1;
private static final short ARRAY_LENGTH = (short) 0xff;
// TEMPORARRY ARRAY IN RAM
- private byte ramArray[] = null;
- private byte ramArray2[] = null;
+ private byte[] ramArray = null;
+ private byte[] ramArray2 = null;
// PERSISTENT ARRAY IN EEPROM
- private byte dataArray[] = null; // unused
+ private byte[] dataArray = null; // unused
private RandomData randomData = null;
@@ -120,8 +117,9 @@ public class ECTesterApplet extends Applet {
byte[] apduBuffer = apdu.getBuffer();
// ignore the applet select command dispached to the process
- if (selectingApplet())
+ if (selectingApplet()) {
return;
+ }
if (apduBuffer[ISO7816.OFFSET_CLA] == CLA_ECTESTERAPPLET) {
switch (apduBuffer[ISO7816.OFFSET_INS]) {
@@ -137,6 +135,9 @@ public class ECTesterApplet extends Applet {
case INS_GENERATE:
insGenerate(apdu);
break;
+ case INS_EXPORT:
+ insExport(apdu);
+ break;
case INS_ECDH:
insECDH(apdu);
break;
@@ -174,6 +175,8 @@ public class ECTesterApplet extends Applet {
}
/**
+ * Clears local and remote keyPair's keys {@code .clearKey()}.
+ * returns clearKey SWs
*
* @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
* P2 =
@@ -184,10 +187,12 @@ public class ECTesterApplet extends Applet {
byte keyPair = apdubuf[ISO7816.OFFSET_P1];
short len = 0;
- if ((keyPair & KEYPAIR_LOCAL) != 0)
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
len += clear(localKeypair, apdubuf, (short) 0);
- if ((keyPair & KEYPAIR_REMOTE) != 0)
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
len += clear(remoteKeypair, apdubuf, len);
+ }
apdu.setOutgoingAndSend((short) 0, len);
}
@@ -197,9 +202,8 @@ public class ECTesterApplet extends Applet {
* returns setCurve SWs, set params if export
*
* @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
- * P2 = byte export (EXPORT_* | KEYPAIR_*)
- * DATA = byte curve (EC_Consts.CURVE_*)
- * short params (EC_Consts.PARAMETER_* | ...)
+ * P2 = byte curve (EC_Consts.CURVE_*)
+ * DATA = short params (EC_Consts.PARAMETER_* | ...)
* short corruptedParams (EC_Consts.PARAMETER_* | ...)
* byte corruptionType (EC_Consts.CORRUPTION_*)
* <p>
@@ -213,22 +217,19 @@ public class ECTesterApplet extends Applet {
byte[] apdubuf = apdu.getBuffer();
byte keyPair = apdubuf[ISO7816.OFFSET_P1];
- byte export = apdubuf[ISO7816.OFFSET_P2];
- byte curve = apdubuf[ISO7816.OFFSET_CDATA];
- short params = Util.getShort(apdubuf, (short) (ISO7816.OFFSET_CDATA + 1));
- short corruptedParams = Util.getShort(apdubuf, (short) (ISO7816.OFFSET_CDATA + 3));
- byte corruptionType = apdubuf[(short) (ISO7816.OFFSET_CDATA + 5)];
+ byte curve = apdubuf[ISO7816.OFFSET_P2];
+ short params = Util.getShort(apdubuf, ISO7816.OFFSET_CDATA);
+ short corruptedParams = Util.getShort(apdubuf, (short) (ISO7816.OFFSET_CDATA + 2));
+ byte corruptionType = apdubuf[(short) (ISO7816.OFFSET_CDATA + 4)];
short len = 0;
- if ((keyPair & KEYPAIR_LOCAL) != 0)
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
len += set(localKeypair, curve, params, corruptedParams, corruptionType, apdubuf, (short) (ISO7816.OFFSET_CDATA + 6), (short) 0);
- if ((keyPair & KEYPAIR_REMOTE) != 0)
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
len += set(remoteKeypair, curve, params, corruptedParams, corruptionType, apdubuf, (short) (ISO7816.OFFSET_CDATA + 6), len);
- if ((export & KEYPAIR_LOCAL) != 0)
- len += export(localKeypair, export, params, apdubuf, len);
- if ((export & KEYPAIR_REMOTE) != 0)
- len += export(remoteKeypair, export, params, apdubuf, len);
+ }
apdu.setOutgoingAndSend((short) 0, len);
}
@@ -238,35 +239,61 @@ public class ECTesterApplet extends Applet {
* returns generate SWs, pubkey and privkey if export
*
* @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
- * P2 = byte export (EXPORT_* | KEYPAIR_*)
+ * P2 =
*/
private void insGenerate(APDU apdu) {
apdu.setIncomingAndReceive();
byte[] apdubuf = apdu.getBuffer();
byte keyPair = apdubuf[ISO7816.OFFSET_P1];
- byte export = apdubuf[ISO7816.OFFSET_P2];
short len = 0;
- if ((keyPair & KEYPAIR_LOCAL) != 0)
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
len += generate(localKeypair, apdubuf, (short) 0);
- if ((keyPair & KEYPAIR_REMOTE) != 0)
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
len += generate(remoteKeypair, apdubuf, len);
- if ((export & KEYPAIR_LOCAL) != 0)
- len += export(localKeypair, export, (short) (EC_Consts.PARAMETER_W | EC_Consts.PARAMETER_S), apdubuf, len);
- if ((export & KEYPAIR_REMOTE) != 0)
- len += export(remoteKeypair, export, (short) (EC_Consts.PARAMETER_W | EC_Consts.PARAMETER_S), apdubuf, len);
+ }
+
+ apdu.setOutgoingAndSend((short) 0, len);
+ }
+
+ /**
+ * Exports selected key and domain parameters from the selected keyPair and key.
+ *
+ * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
+ * P2 = byte key (EC_Consts.KEY_* | ...)
+ * DATA = short params
+ */
+ private void insExport(APDU apdu) {
+ apdu.setIncomingAndReceive();
+ byte[] apdubuf = apdu.getBuffer();
+
+ byte keyPair = apdubuf[ISO7816.OFFSET_P1];
+ byte key = apdubuf[ISO7816.OFFSET_P2];
+ short params = Util.getShort(apdubuf, ISO7816.OFFSET_CDATA);
+
+ short swOffset = 0;
+ short len = (short) (keyPair == KEYPAIR_BOTH ? 4 : 2);
+
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += export(localKeypair, key, params, apdubuf, swOffset, len);
+ swOffset += 2;
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += export(remoteKeypair, key, params, apdubuf, swOffset, len);
+ }
apdu.setOutgoingAndSend((short) 0, len);
}
/**
* Performs ECDH, between the pubkey specified in P1(local/remote) and the privkey specified in P2(local/remote).
- * returns deriveSecret SW, if export != 0 => short secretlen, byte[] secret
+ * returns deriveSecret SW, {@code if(export == EXPORT_TRUE)} => short secretlen, byte[] secret
*
* @param apdu P1 = byte pubkey (KEYPAIR_*)
* P2 = byte privkey (KEYPAIR_*)
- * DATA = byte export (EXPORT_ECDH || 0)
+ * DATA = byte export (EXPORT_TRUE || EXPORT_FALSE)
* byte invalid (00 = valid, !00 = invalid)
*/
private void insECDH(APDU apdu) {
@@ -285,10 +312,10 @@ public class ECTesterApplet extends Applet {
/**
* Performs ECDSA signature and verification on data provided or random, using the keyPair in P1(local/remote).
- * returns ecdsa SW, if export != 0 => short signature_length, byte[] signature
+ * returns ecdsa SW, {@code if(export == EXPORT_TRUE)} => short signature_length, byte[] signature
*
* @param apdu P1 = byte keyPair (KEYPAIR_*)
- * P2 = byte export (EXPORT_SIG || 0)
+ * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
* DATA = short dataLength (00 = random data generated, !00 = data length)
* byte[] data
*/
@@ -299,7 +326,13 @@ public class ECTesterApplet extends Applet {
byte keyPair = apdubuf[ISO7816.OFFSET_P1];
byte export = apdubuf[ISO7816.OFFSET_P2];
- short len = ecdsa(keyPair, export, apdubuf, ISO7816.OFFSET_CDATA, (short) 0);
+ short len = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += ecdsa(localKeypair, export, apdubuf, ISO7816.OFFSET_CDATA, (short) 0);
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += ecdsa(remoteKeypair, export, apdubuf, ISO7816.OFFSET_CDATA, len);
+ }
apdu.setOutgoingAndSend((short) 0, len);
}
@@ -308,8 +341,8 @@ public class ECTesterApplet extends Applet {
* @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...)
* @param keyLength key length to set
* @param keyClass key class to allocate
- * @param buffer apdu buffer
- * @param offset offset into apdu buffer
+ * @param buffer buffer to write sw to
+ * @param offset offset into buffer
* @return length of data written to the buffer
*/
private short allocate(byte keyPair, short keyLength, byte keyClass, byte[] buffer, short offset) {
@@ -329,8 +362,14 @@ public class ECTesterApplet extends Applet {
return length;
}
+ /**
+ * @param keyPair KeyPair to clear
+ * @param buffer buffer to write sw to
+ * @param offset offset into buffer
+ * @return length of data written to the buffer
+ */
private short clear(KeyPair keyPair, byte[] buffer, short offset) {
- short sw = keyGenerator.clearPair(keyPair, ECKeyGenerator.KEY_BOTH);
+ short sw = keyGenerator.clearPair(keyPair, EC_Consts.KEY_BOTH);
Util.setShort(buffer, offset, sw);
return 2;
@@ -384,26 +423,31 @@ public class ECTesterApplet extends Applet {
}
/**
- * @param keyPair KeyPair to export from
- * @param export which key to export from (EXPORT_PUBLIC | EXPORT_PRIVATE)
- * @param params which params to export (EC_Consts.PARAMETER_* | ...)
- * @param buffer buffer to export params to
- * @param offset output offset in buffer
+ * @param keyPair KeyPair to export from
+ * @param key which key to export from (EC_Consts.KEY_PUBLIC | EC_Consts.KEY_PRIVATE)
+ * @param params which params to export (EC_Consts.PARAMETER_* | ...)
+ * @param buffer buffer to export params to
+ * @param swOffset offset to output sw to buffer
+ * @param offset output offset in buffer
* @return length of data written to the buffer
*/
- private short export(KeyPair keyPair, byte export, short params, byte[] buffer, short offset) {
+ private short export(KeyPair keyPair, byte key, short params, byte[] buffer, short swOffset, short offset) {
short length = 0;
- if ((export & EXPORT_PUBLIC) != 0) {
+ short sw = ISO7816.SW_NO_ERROR;
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) {
//export params from public
- length += keyGenerator.exportParameters(keyPair, ECKeyGenerator.KEY_PUBLIC, params, buffer, offset);
+ length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PUBLIC, params, buffer, offset);
+ sw = keyGenerator.getSW();
}
-
- if ((export & EXPORT_PRIVATE) != 0) {
+ //TODO unify this, now that param key == the passed on param.
+ if ((key & EC_Consts.KEY_PRIVATE) != 0 && sw == ISO7816.SW_NO_ERROR) {
//export params from private
- length += keyGenerator.exportParameters(keyPair, ECKeyGenerator.KEY_PRIVATE, params, buffer, (short) (offset + length));
-
+ length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PRIVATE, params, buffer, (short) (offset + length));
+ sw = keyGenerator.getSW();
}
+ Util.setShort(buffer, swOffset, sw);
+
return length;
}
@@ -412,7 +456,7 @@ public class ECTesterApplet extends Applet {
* @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
* @param export whether to export ECDH secret
* @param invalid whether to invalidate the pubkey before ECDH
- * @param buffer buffer to write sw to, and export ECDH secret if (export & EXPORT_ECDH) != 0
+ * @param buffer buffer to write sw to, and export ECDH secret {@code if(export == EXPORT_TRUE)}
* @param offset output offset in buffer
* @return length of data written to the buffer
*/
@@ -432,7 +476,7 @@ public class ECTesterApplet extends Applet {
Util.setShort(buffer, offset, keyTester.getSW());
length += 2;
- if ((export & EXPORT_ECDH) != 0) {
+ if ((export == EXPORT_TRUE)) {
Util.setShort(buffer, (short) (offset + length), secretLength);
length += 2;
Util.arrayCopyNonAtomic(ramArray2, (short) 0, buffer, (short) (offset + length), secretLength);
@@ -443,14 +487,14 @@ public class ECTesterApplet extends Applet {
}
/**
- * @param keyPair keyPair to use for signing and verification (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
+ * @param sign keyPair to use for signing and verification
* @param export whether to export ECDSA signature
- * @param buffer buffer to write sw to, and export ECDSA signature if (export & EXPORT_SIG) != 0
+ * @param buffer buffer to write sw to, and export ECDSA signature {@code if(export == EXPORT_TRUE)}
* @param inOffset input offset in buffer
* @param outOffset output offset in buffer
* @return length of data written to the buffer
*/
- private short ecdsa(byte keyPair, byte export, byte[] buffer, short inOffset, short outOffset) {
+ private short ecdsa(KeyPair sign, byte export, byte[] buffer, short inOffset, short outOffset) {
short length = 0;
short dataLength = Util.getShort(buffer, inOffset);
@@ -462,13 +506,11 @@ public class ECTesterApplet extends Applet {
Util.arrayCopyNonAtomic(buffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength);
}
- KeyPair sign = ((keyPair & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair;
-
short signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
Util.setShort(buffer, outOffset, keyTester.getSW());
length += 2;
- if ((export & EXPORT_SIG) != 0) {
+ if (export == EXPORT_TRUE) {
Util.setShort(buffer, (short) (outOffset + length), signatureLength);
length += 2;
diff --git a/src/cz/crcs/ectester/applet/EC_Consts.java b/src/cz/crcs/ectester/applet/EC_Consts.java
index c70919c..fc62c67 100644
--- a/src/cz/crcs/ectester/applet/EC_Consts.java
+++ b/src/cz/crcs/ectester/applet/EC_Consts.java
@@ -39,21 +39,28 @@ public class EC_Consts {
public static final short PARAMETER_S = 0x0100;
public static final short PARAMETERS_NONE = 0x0000;
- public static final short PARAMETERS_DOMAIN_FP = 0x007d;
/**
* FP,A,B,G,R,K
*/
- public static final short PARAMETERS_DOMAIN_F2M = 0x007e;
+ public static final short PARAMETERS_DOMAIN_FP = 0x007d;
/**
* F2M,A,B,G,R,K
*/
+ public static final short PARAMETERS_DOMAIN_F2M = 0x007e;
+ /**
+ * W,S
+ */
public static final short PARAMETERS_KEYPAIR = 0x0180;
public static final short PARAMETERS_ALL = 0x01ff;
+ public static final byte KEY_PUBLIC = 0x01;
+ public static final byte KEY_PRIVATE = 0x02;
+ public static final byte KEY_BOTH = KEY_PUBLIC | KEY_PRIVATE;
+
public static RandomData randomData = null;
- // secp128r1
+ // secp128r1 from http://www.secg.org/sec2-v2.pdf
public static final byte[] EC128_FP_P = new byte[]{
(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFD,
(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
@@ -94,7 +101,7 @@ public class EC_Consts {
// cofactor of G
public static final short EC128_FP_K = 1;
- // secp160r1
+ // secp160r1 from http://www.secg.org/sec2-v2.pdf
public static final byte[] EC160_FP_P = new byte[]{
(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
diff --git a/src/cz/crcs/ectester/reader/Command.java b/src/cz/crcs/ectester/reader/Command.java
index 31cde4d..c6ce2b5 100644
--- a/src/cz/crcs/ectester/reader/Command.java
+++ b/src/cz/crcs/ectester/reader/Command.java
@@ -96,7 +96,6 @@ public abstract class Command {
*/
public static class Set extends Command {
private byte keyPair;
- private byte export;
private byte curve;
private short params;
private short corrupted;
@@ -108,34 +107,31 @@ public abstract class Command {
*
* @param cardManager
* @param keyPair which keyPair to set params on, local/remote (KEYPAIR_* || ...)
- * @param export whether to export set params from keyPair
* @param curve curve to set (EC_Consts.CURVE_*)
* @param params parameters to set (EC_Consts.PARAMETER_* | ...)
* @param corrupted parameters to corrupt (EC_Consts.PARAMETER_* | ...)
* @param corruption corruption type (EC_Consts.CORRUPTION_*)
* @param external external curve data, can be null
*/
- public Set(CardMngr cardManager, byte keyPair, byte export, byte curve, short params, short corrupted, byte corruption, byte[] external) {
+ public Set(CardMngr cardManager, byte keyPair, byte curve, short params, short corrupted, byte corruption, byte[] external) {
super(cardManager);
this.keyPair = keyPair;
- this.export = export;
this.curve = curve;
this.params = params;
this.corrupted = corrupted;
this.corruption = corruption;
this.external = external;
- int len = external != null ? 6 + 2 + external.length : 6;
+ int len = external != null ? 5 + 2 + external.length : 5;
byte[] data = new byte[len];
- data[0] = curve;
- Util.setShort(data, 1, params);
- Util.setShort(data, 3, corrupted);
- data[5] = corruption;
+ Util.setShort(data, 0, params);
+ Util.setShort(data, 2, corrupted);
+ data[4] = corruption;
if (external != null) {
- System.arraycopy(external, 0, data, 6, external.length);
+ System.arraycopy(external, 0, data, 5, external.length);
}
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SET, keyPair, export, data);
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SET, keyPair, curve, data);
}
@Override
@@ -143,7 +139,7 @@ public abstract class Command {
long elapsed = -System.nanoTime();
ResponseAPDU response = cardManager.send(cmd);
elapsed += System.nanoTime();
- return new Response.Set(response, elapsed, keyPair, export, curve, params, corrupted);
+ return new Response.Set(response, elapsed, keyPair, curve, params, corrupted);
}
}
@@ -152,21 +148,18 @@ public abstract class Command {
*/
public static class Generate extends Command {
private byte keyPair;
- private byte export;
/**
* Creates the INS_GENERATE instruction.
*
* @param cardManager
* @param keyPair which keyPair to generate, local/remote (KEYPAIR_* || ...)
- * @param export whether to export generated keys from keyPair
*/
- public Generate(CardMngr cardManager, byte keyPair, byte export) {
+ public Generate(CardMngr cardManager, byte keyPair) {
super(cardManager);
this.keyPair = keyPair;
- this.export = export;
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GENERATE, keyPair, export);
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GENERATE, keyPair, 0);
}
@Override
@@ -174,7 +167,44 @@ public abstract class Command {
long elapsed = -System.nanoTime();
ResponseAPDU response = cardManager.send(cmd);
elapsed += System.nanoTime();
- return new Response.Generate(response, elapsed, keyPair, export);
+ return new Response.Generate(response, elapsed, keyPair);
+ }
+ }
+
+ /**
+ *
+ */
+ public static class Export extends Command {
+ private byte keyPair;
+ private byte key;
+ private short params;
+
+ /**
+ * Creates the INS_EXPORT instruction.
+ *
+ * @param cardManager
+ * @param keyPair keyPair to export from (KEYPAIR_* | ...)
+ * @param key key to export from (EC_Consts.KEY_* | ...)
+ * @param params params to export (EC_Consts.PARAMETER_* | ...)
+ */
+ public Export(CardMngr cardManager, byte keyPair, byte key, short params) {
+ super(cardManager);
+ this.keyPair = keyPair;
+ this.key = key;
+ this.params = params;
+
+ byte[] data = new byte[2];
+ Util.setShort(data, 0, params);
+
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_EXPORT, keyPair, key, data);
+ }
+
+ @Override
+ public Response.Export send() throws CardException {
+ long elapsed = -System.nanoTime();
+ ResponseAPDU response = cardManager.send(cmd);
+ elapsed += System.nanoTime();
+ return new Response.Export(response, elapsed, keyPair, key, params);
}
}
diff --git a/src/cz/crcs/ectester/reader/ParamReader.java b/src/cz/crcs/ectester/reader/ECParams.java
index ca14d2d..c19640e 100644
--- a/src/cz/crcs/ectester/reader/ParamReader.java
+++ b/src/cz/crcs/ectester/reader/ECParams.java
@@ -3,22 +3,23 @@ package cz.crcs.ectester.reader;
import cz.crcs.ectester.applet.EC_Consts;
import java.io.*;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Pattern;
/**
- *
* @author Jan Jancar johny@neuromancer.sk
*/
-public class ParamReader {
+public class ECParams {
private static final Pattern hex = Pattern.compile("[a-fA-F\\d]+");
/**
* Flattens params read from String[] data into a byte[] with their lengths prepended as short entries.
+ *
* @param params (EC_Consts.PARAMETER_* | ...)
- * @param data data read by readString, readFile, readResource
+ * @param data data read by readString, readFile, readResource
* @return byte[] with params flattened, or null
*/
public static byte[] flatten(short params, String[] data) {
@@ -38,16 +39,16 @@ public class ParamReader {
param = Util.concatenate(param, parse(data[i + 1]), parse(data[i + 2]));
i += 2;
if (param.length != 6)
- return null;
+ throw new RuntimeException("PARAMETER_F2M length is not 6.(should be)");
}
if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) {
//read another param (the y coord) and put into X962 format.
byte[] y = parse(data[i + 1]);
- param = Util.concatenate(new byte[]{4}, param, y);//<- ugly but works!
+ param = Util.concatenate(new byte[]{4}, param, y); //<- ugly but works!
i++;
}
if (param.length == 0)
- return null;
+ throw new RuntimeException("Empty parameter read?");
//write length
byte[] length = new byte[2];
@@ -64,7 +65,60 @@ public class ParamReader {
}
/**
+ * @param data
+ * @param params
+ * @return
+ */
+ public static String[] expand(byte[][] data, short params) {
+ List<String> out = new ArrayList<>();
+
+ short paramMask = EC_Consts.PARAMETER_FP;
+ int index = 0;
+ while (paramMask <= EC_Consts.PARAMETER_S) {
+ short masked = (short) (params & paramMask);
+ if (masked != 0) {
+ byte[] param = data[index];
+
+ if (masked == EC_Consts.PARAMETER_F2M) {
+ //split into three shorts
+ if (param.length != 6) {
+ throw new RuntimeException("PARAMETER_F2M length is not 6.(should be)");
+ }
+ for (int i = 0; i < 3; ++i) {
+ out.add(String.format("%04x", Util.getShort(param, i*2)));
+ }
+
+ } else if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) {
+ //split from X962 format into X and Y
+ //disregard the first 04 and then split into half(uncompress)
+ int half = (param.length - 1) / 2;
+ out.add(Util.bytesToHex(param, 1, half, false));
+ out.add(Util.bytesToHex(param, half + 1, half, false));
+ } else {
+ //read raw
+ out.add(Util.bytesToHex(data[index], false));
+ }
+ index++;
+ }
+ paramMask = (short) (paramMask << 1);
+ }
+ return out.toArray(new String[out.size()]);
+ }
+
+ /**
+ * @param filePath
+ * @param data
+ * @throws IOException
+ */
+ public static void writeFile(String filePath, String[] data) throws IOException {
+ FileOutputStream out = new FileOutputStream(filePath);
+ write(out, data);
+ out.close();
+ }
+
+ /**
* Reads hex params from a CSV String data.
+ *
* @param data String containing CSV data(hex)
* @return String array containing the CSV entries
*/
@@ -74,15 +128,17 @@ public class ParamReader {
/**
* Reads hex params from a CSV Resource (inside jar).
+ *
* @param resourcePath path to the resourse
* @return String array containing the CSV entries
*/
public static String[] readResource(String resourcePath) {
- return read(ParamReader.class.getResourceAsStream(resourcePath));
+ return read(ECParams.class.getResourceAsStream(resourcePath));
}
/**
* Reads hex params from a CSV file.
+ *
* @param filePath path to the file
* @return String array containing the CSV entries
* @throws FileNotFoundException if the file cannot be opened
@@ -132,4 +188,15 @@ public class ParamReader {
}
return null;
}
+
+ private static void write(OutputStream out, String[] data) throws IOException {
+ Writer w = new OutputStreamWriter(out);
+ for (int i = 0; i < data.length; ++i) {
+ w.write(data[i]);
+ if (i < data.length - 1) {
+ w.write(",");
+ }
+ }
+ w.flush();
+ }
}
diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java
index 4cb63f7..b359e16 100644
--- a/src/cz/crcs/ectester/reader/ECTester.java
+++ b/src/cz/crcs/ectester/reader/ECTester.java
@@ -62,73 +62,19 @@ public class ECTester {
private boolean optFresh = false;
private boolean optSimulate = false;
+ //Action-related options
private int optGenerateAmount;
private String optECDSASign;
private Options opts = new Options();
- private static final String CLI_HEADER = "";
- private static final String CLI_FOOTER = "";
-
+ private static final String CLI_HEADER = "\nECTester, a javacard Elliptic Curve Cryptograhy support tester/utility.\n\n";
+ private static final String CLI_FOOTER = "\nMIT Licensed\nCopyright (c) 2016-2017 Petr Svenda <petr@svenda.com>";
private static final byte[] SELECT_ECTESTERAPPLET = {(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x0a,
(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x31};
- private static final byte[] AID = {(byte) 0x4C, (byte) 0x61, (byte) 0x62, (byte) 0x61, (byte) 0x6B, (byte) 0x41, (byte) 0x70, (byte) 0x70, (byte) 0x6C, (byte) 0x65, (byte) 0x74};
+ private static final byte[] AID = {(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x31};
private static final byte[] INSTALL_DATA = new byte[10];
- /*
- private static final byte[] ALLOCATE = {
- (byte) 0xB0,
- (byte) 0x5a, //INS ALLOCATE
- (byte) 0x00, //P1 *byte keyPair
- (byte) 0x00, //P2
- (byte) 0x03, //LC
- (byte) 0x00, //DATA *short keyLength
- (byte) 0x00,
- (byte) 0x00 // *byte keyClass
- };
-
- private static final byte[] SET = {
- (byte) 0xB0,
- (byte) 0x5B, //INS SET
- (byte) 0x00, //P1 *byte keyPair
- (byte) 0x00, //P2 *byte export
- (byte) 0x06, //LC
- (byte) 0x00, //DATA *byte curve
- (byte) 0x00, // *short params
- (byte) 0x00, //
- (byte) 0x00, // *short corruptedParams
- (byte) 0x00, //
- (byte) 0x00 // *byte corruptionType
- // [short paramLength, byte[] param] for all params in params
- };
-
- private static final byte[] GENERATE = {
- (byte) 0xB0,
- (byte) 0x5C, //INS GENERATE
- (byte) 0x00, //P1 *byte keyPair
- (byte) 0x00, //P2 *byte export
- (byte) 0x00 //LC
- };
-
- private static final byte[] ECDH = {
- (byte) 0xB0,
- (byte) 0x5D, //INS ECDH
- (byte) 0x00, //P1 *byte keyPair
- (byte) 0x00, //P2 *byte export
- (byte) 0x01, //LC
- (byte) 0x00 //DATA *byte valid
- };
-
- private static final byte[] ECDSA = {
- (byte) 0xB0,
- (byte) 0x5E, //INS ECDSA
- (byte) 0x00, //P1 *byte keyPair
- (byte) 0x00, //P2 *byte export
- (byte) 0x00, //LC
- //DATA [*short dataLength, byte[] data]
- };
- */
-
private void run(String[] args) {
try {
CommandLine cli = parseArgs(args);
@@ -144,6 +90,7 @@ public class ECTester {
}
cardManager = new CardMngr(optSimulate);
+ //connect or simulate connection
if (optSimulate) {
if (!cardManager.prepareLocalSimulatorApplet(AID, INSTALL_DATA, ECTesterApplet.class)) {
System.err.println("Failed to establish a simulator.");
@@ -160,7 +107,9 @@ public class ECTester {
systemOutLogger = new DirtyLogger(optLog, true);
//do action
- if (cli.hasOption("generate")) {
+ if (cli.hasOption("export")) {
+ export();
+ } else if (cli.hasOption("generate")) {
generate();
} else if (cli.hasOption("test")) {
test();
@@ -170,6 +119,7 @@ public class ECTester {
ecdsa();
}
+ //disconnect
cardManager.disconnectFromCard();
systemOutLogger.close();
@@ -186,15 +136,13 @@ public class ECTester {
}
} catch (MissingArgumentException maex) {
System.err.println("Option, " + maex.getOption().getOpt() + " requires an argument: " + maex.getOption().getArgName());
- } catch (ParseException | CardException pex) {
- System.err.println(pex.getMessage());
} catch (NumberFormatException nfex) {
System.err.println("Not a number. " + nfex.getMessage());
nfex.printStackTrace(System.err);
} catch (FileNotFoundException fnfe) {
System.err.println("File " + fnfe.getMessage() + " not found.");
- } catch (IOException e) {
- e.printStackTrace();
+ } catch (ParseException | IOException | CardException ex) {
+ System.err.println(ex.getMessage());
}
}
@@ -209,6 +157,7 @@ public class ECTester {
/*
* Actions:
* -h / --help
+ * -e / --export
* -g / --generate [amount]
* -t / --test
* -dh / --ecdh
@@ -228,6 +177,7 @@ public class ECTester {
OptionGroup actions = new OptionGroup();
actions.setRequired(true);
actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build());
+ actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build());
actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build());
actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support.").build());
actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do ECDH.").build());
@@ -297,7 +247,26 @@ public class ECTester {
return false;
}
- if (cli.hasOption("generate")) {
+
+ if (cli.hasOption("export")) {
+ if (optPrimeField == optBinaryField) {
+ System.err.print("Need to specify field with -fp or -f2m. (not both)");
+ return false;
+ }
+ if (optKey != null || optPublic != null || optPrivate != null) {
+ System.err.println("Keys should not be specified when generating keys.");
+ return false;
+ }
+ if (optOutput == null) {
+ System.err.println("You have to specify an output file for curve parameter export.");
+ return false;
+ }
+ if (optAll) {
+ System.err.println("You have to specify curve bit-size with -b");
+ return false;
+ }
+
+ } else if (cli.hasOption("generate")) {
if (optPrimeField == optBinaryField) {
System.err.print("Need to specify field with -fp or -f2m. (not both)");
return false;
@@ -361,10 +330,34 @@ public class ECTester {
*/
private void help() {
HelpFormatter help = new HelpFormatter();
+ help.setOptionComparator(null);
help.printHelp("ECTester.jar", CLI_HEADER, opts, CLI_FOOTER, true);
}
/**
+ * Exports default card/simulation EC domain parameters to output file.
+ *
+ * @throws CardException if APDU transmission fails
+ * @throws IOException if an IO error occurs when writing to key file.
+ */
+ private void export() throws CardException, IOException {
+ byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
+ //skip cofactor in domain export, since it doesnt need to be initialized for the key to be initialized.
+ //and generally isn't initialized on cards with default domain params(TODO, check, is it assumed to be ==1?)
+ short domain = (short) ((optPrimeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M) ^ EC_Consts.PARAMETER_K);
+
+ List<Response> sent = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ sent.add(new Command.Clear(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
+ sent.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
+ Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send();
+ sent.add(export);
+
+ systemOutLogger.println(Response.toString(sent));
+
+ ECParams.writeFile(optOutput, ECParams.expand(export.getParams(), domain));
+ }
+
+ /**
* Generates EC keyPairs and outputs them to output file.
*
* @throws CardException if APDU transmission fails
@@ -372,8 +365,9 @@ public class ECTester {
*/
private void generate() throws CardException, IOException {
byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- List<Response> prepare = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
- prepare.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass)));
+
+ Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ List<Command> curve = prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass);
FileWriter keysFile = new FileWriter(optOutput);
keysFile.write("index;time;pubW;privS\n");
@@ -381,15 +375,17 @@ public class ECTester {
int generated = 0;
int retry = 0;
while (generated < optGenerateAmount || optGenerateAmount == 0) {
- if (optFresh) {
- Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ if (optFresh || generated == 0) {
+ Command.sendAll(curve);
}
- Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (byte) (ECTesterApplet.EXPORT_BOTH | ECTesterApplet.KEYPAIR_LOCAL));
+ Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL);
Response.Generate response = generate.send();
long elapsed = response.getDuration();
- if (!response.successful()) {
+ Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send();
+
+ if (!response.successful() || !export.successful()) {
if (retry < 10) {
retry++;
continue;
@@ -400,8 +396,8 @@ public class ECTester {
}
systemOutLogger.println(response.toString());
- String pub = Util.bytesToHex(response.getPublic(ECTesterApplet.KEYPAIR_LOCAL), false);
- String priv = Util.bytesToHex(response.getPrivate(ECTesterApplet.KEYPAIR_LOCAL), false);
+ String pub = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
+ String priv = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
String line = String.format("%d;%d;%s;%s\n", generated, elapsed / 1000000, pub, priv);
keysFile.write(line);
keysFile.flush();
@@ -456,16 +452,13 @@ public class ECTester {
ecdh.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass)));
if (optPublic != null || optPrivate != null || optKey != null) {
- Response local = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_NONE).send();
- Response remote = prepareKey(ECTesterApplet.KEYPAIR_REMOTE).send();
- ecdh.add(local);
- ecdh.add(remote);
+ ecdh.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
+ ecdh.add(prepareKey(ECTesterApplet.KEYPAIR_REMOTE).send());
} else {
- Response both = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH, ECTesterApplet.EXPORT_NONE).send();
- ecdh.add(both);
+ ecdh.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH).send());
}
- Response.ECDH perform = new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_ECDH, (byte) 0).send();
+ Response.ECDH perform = new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, (byte) 0).send();
ecdh.add(perform);
systemOutLogger.println(Response.toString(ecdh));
@@ -495,7 +488,7 @@ public class ECTester {
if (optKey != null || (optPublic != null && optPrivate != null)) {
keys = prepareKey(ECTesterApplet.KEYPAIR_LOCAL).send();
} else {
- keys = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_NONE).send();
+ keys = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send();
}
ecdsa.add(keys);
@@ -510,7 +503,7 @@ public class ECTester {
data = Files.readAllBytes(in.toPath());
}
- Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_SIG, data).send();
+ Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, data).send();
ecdsa.add(perform);
systemOutLogger.println(Response.toString(ecdsa));
@@ -550,14 +543,14 @@ public class ECTester {
short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
if (optNamed) {
// Set named curve (one of the SECG curves embedded applet-side)
- commands.add(new Command.Set(cardManager, keyPair, ECTesterApplet.EXPORT_NONE, EC_Consts.getCurve(keyLength, keyClass), domainParams, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, null));
+ commands.add(new Command.Set(cardManager, keyPair, EC_Consts.getCurve(keyLength, keyClass), domainParams, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, null));
} else if (optCurve != null) {
// Set curve loaded from a file
- byte[] external = ParamReader.flatten(domainParams, ParamReader.readFile(optCurve));
+ byte[] external = ECParams.flatten(domainParams, ECParams.readFile(optCurve));
if (external == null) {
throw new IOException("Couldn't read the curve file correctly.");
}
- commands.add(new Command.Set(cardManager, keyPair, ECTesterApplet.EXPORT_NONE, EC_Consts.CURVE_external, domainParams, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, external));
+ commands.add(new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, domainParams, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, external));
} else {
// Set default curve
commands.add(new Command.Clear(cardManager, keyPair));
@@ -576,26 +569,29 @@ public class ECTester {
byte[] data = null;
if (optKey != null) {
params |= EC_Consts.PARAMETERS_KEYPAIR;
- data = ParamReader.flatten(EC_Consts.PARAMETERS_KEYPAIR, ParamReader.readFile(optKey));
+ data = ECParams.flatten(EC_Consts.PARAMETERS_KEYPAIR, ECParams.readFile(optKey));
+ if (data == null) {
+ throw new IOException("Couldn't read the key file correctly.");
+ }
}
if (optPublic != null) {
params |= EC_Consts.PARAMETER_W;
- data = ParamReader.flatten(EC_Consts.PARAMETER_W, ParamReader.readFile(optPublic));
+ byte[] pubkey = ECParams.flatten(EC_Consts.PARAMETER_W, ECParams.readFile(optPublic));
+ if (pubkey == null) {
+ throw new IOException("Couldn't read the key file correctly.");
+ }
+ data = pubkey;
}
if (optPrivate != null) {
params |= EC_Consts.PARAMETER_S;
- data = Util.concatenate(data, ParamReader.flatten(EC_Consts.PARAMETER_S, ParamReader.readFile(optPrivate)));
- }
-
- if (data == null && params != EC_Consts.PARAMETERS_NONE) {
- /*
- TODO: this is not correct, in case (optPublic != null) and (optPrivate != null),
- only one can actually load(return not null from ParamReader.flatten) and an exception will not be thrown
- */
- throw new IOException("Couldn't read the key file correctly.");
+ byte[] privkey = ECParams.flatten(EC_Consts.PARAMETER_S, ECParams.readFile(optPrivate));
+ if (privkey == null) {
+ throw new IOException("Couldn't read the key file correctly.");
+ }
+ data = Util.concatenate(data, privkey);
}
- return new Command.Set(cardManager, keyPair, ECTesterApplet.EXPORT_NONE, EC_Consts.CURVE_external, params, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, data);
+ return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, params, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, data);
}
/**
@@ -608,10 +604,10 @@ public class ECTester {
List<Command> commands = new LinkedList<>();
commands.addAll(prepareKeyPair(ECTesterApplet.KEYPAIR_BOTH, keyLength, keyClass));
commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, keyLength, keyClass));
- commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH, ECTesterApplet.EXPORT_NONE));
- commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_NONE, (byte) 0));
- commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_NONE, (byte) 1));
- commands.add(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_NONE, null));
+ commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH));
+ commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, (byte) 0));
+ commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, (byte) 1));
+ commands.add(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, null));
return commands;
}
diff --git a/src/cz/crcs/ectester/reader/Response.java b/src/cz/crcs/ectester/reader/Response.java
index 05cd92a..368a8ef 100644
--- a/src/cz/crcs/ectester/reader/Response.java
+++ b/src/cz/crcs/ectester/reader/Response.java
@@ -102,6 +102,10 @@ public abstract class Response {
return params[index];
}
+ public byte[][] getParams() {
+ return params;
+ }
+
public int getLength() {
return resp.getNr();
}
@@ -192,15 +196,13 @@ public abstract class Response {
*/
public static class Set extends Response {
private byte keyPair;
- private byte export;
private byte curve;
private short parameters;
private short corrupted;
- protected Set(ResponseAPDU response, long time, byte keyPair, byte export, byte curve, short parameters, short corrupted) {
+ protected Set(ResponseAPDU response, long time, byte keyPair, byte curve, short parameters, short corrupted) {
super(response, time);
this.keyPair = keyPair;
- this.export = export;
this.curve = curve;
this.parameters = parameters;
this.corrupted = corrupted;
@@ -208,65 +210,8 @@ public abstract class Response {
int pairs = 0;
if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++;
if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++;
- int exported = 0;
- if ((export & ECTesterApplet.KEYPAIR_LOCAL) != 0) exported++;
- if ((export & ECTesterApplet.KEYPAIR_REMOTE) != 0) exported++;
- int keys = 0;
- if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0) keys++;
- if ((export & ECTesterApplet.EXPORT_PRIVATE) != 0) keys++;
- int paramCount = 0;
- short mask = EC_Consts.PARAMETER_FP;
- while (mask <= EC_Consts.PARAMETER_K) {
- if ((mask & parameters) != 0) {
- paramCount++;
- }
- mask = (short) (mask << 1);
- }
- int other = 0;
- if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0 && (parameters & EC_Consts.PARAMETER_W) != 0) other++;
- if ((export & ECTesterApplet.EXPORT_PRIVATE) != 0 && (parameters & EC_Consts.PARAMETER_S) != 0) other++;
-
- parse(pairs, exported * keys * paramCount + exported * other);
- }
-
- private int getIndex(byte keyPair, short param) {
- byte key = ECTesterApplet.KEYPAIR_LOCAL;
- int index = 0;
- while (key <= ECTesterApplet.KEYPAIR_REMOTE) {
- short mask = EC_Consts.PARAMETER_FP;
- while (mask <= EC_Consts.PARAMETER_S) {
- if (key == keyPair && param == mask) {
- return index;
- }
- if ((parameters & mask) != 0 && (key & export) != 0) {
- if (mask == EC_Consts.PARAMETER_W) {
- if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0)
- index++;
- } else if (mask == EC_Consts.PARAMETER_S) {
- if ((export & ECTesterApplet.EXPORT_PRIVATE) != 0)
- index++;
- } else {
- index++;
- }
- }
- mask = (short) (mask << 1);
- }
-
- key = (byte) (key << 1);
- }
- return -1;
- }
- public boolean hasParameter(byte keyPair, short param) {
- if ((export & keyPair) == 0 || (parameters & param) == 0) {
- return false;
- }
- int index = getIndex(keyPair, param);
- return index != -1 && hasParam(index);
- }
-
- public byte[] getParameter(byte keyPair, short param) {
- return getParam(getIndex(keyPair, param));
+ parse(pairs, 0);
}
@Override
@@ -299,49 +244,18 @@ public abstract class Response {
*/
public static class Generate extends Response {
private byte keyPair;
- private byte export;
- private short[] contents;
- protected Generate(ResponseAPDU response, long time, byte keyPair, byte export) {
+ protected Generate(ResponseAPDU response, long time, byte keyPair) {
super(response, time);
this.keyPair = keyPair;
- this.export = export;
- int keys = 0;
- if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0) keys++;
- if ((export & ECTesterApplet.EXPORT_PRIVATE) != 0) keys++;
- int pairs = 0;
- if ((export & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++;
- if ((export & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++;
int generated = 0;
if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) generated++;
if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) generated++;
- parse(generated, keys * pairs);
-
- this.contents = new short[4];
- int offset = 0;
- if ((export & ECTesterApplet.KEYPAIR_LOCAL) != 0) {
- if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0) {
- this.contents[offset] = ECTesterApplet.KEYPAIR_LOCAL | ECTesterApplet.EXPORT_PUBLIC;
- offset++;
- }
- if ((export & ECTesterApplet.EXPORT_PRIVATE) != 0) {
- this.contents[offset] = ECTesterApplet.KEYPAIR_LOCAL | ECTesterApplet.EXPORT_PRIVATE;
- offset++;
- }
- }
- if ((export & ECTesterApplet.KEYPAIR_REMOTE) != 0) {
- if ((export & ECTesterApplet.EXPORT_PUBLIC) != 0) {
- this.contents[offset] = ECTesterApplet.KEYPAIR_REMOTE | ECTesterApplet.EXPORT_PUBLIC;
- offset++;
- }
- if ((export & ECTesterApplet.EXPORT_PRIVATE) != 0) {
- this.contents[offset] = ECTesterApplet.KEYPAIR_REMOTE | ECTesterApplet.EXPORT_PRIVATE;
- offset++;
- }
- }
+ parse(generated, 0);
}
+ /*
private int getIndex(byte key) {
for (int i = 0; i < contents.length; i++) {
if (key == contents[i])
@@ -375,6 +289,7 @@ public abstract class Response {
int index = getIndex((byte) (keyPair | ECTesterApplet.EXPORT_PRIVATE));
return getParam(index);
}
+ */
@Override
public String toString() {
@@ -392,6 +307,114 @@ public abstract class Response {
/**
*
*/
+ public static class Export extends Response {
+ private byte keyPair;
+ private byte key;
+ private short parameters;
+
+ public Export(ResponseAPDU response, long time, byte keyPair, byte key, short parameters) {
+ super(response, time);
+ this.keyPair = keyPair;
+ this.key = key;
+ this.parameters = parameters;
+
+ int exported = 0;
+ if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) exported++;
+ if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) exported++;
+ int keys = 0;
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) keys++;
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) keys++;
+ int paramCount = 0;
+ short mask = EC_Consts.PARAMETER_FP;
+ while (mask <= EC_Consts.PARAMETER_K) {
+ if ((mask & parameters) != 0) {
+ paramCount++;
+ }
+ mask = (short) (mask << 1);
+ }
+ int other = 0;
+ if ((key & EC_Consts.KEY_PUBLIC) != 0 && (parameters & EC_Consts.PARAMETER_W) != 0) other++;
+ if ((key & EC_Consts.KEY_PRIVATE) != 0 && (parameters & EC_Consts.PARAMETER_S) != 0) other++;
+
+ parse(exported, exported * keys * paramCount + exported * other);
+ }
+
+ private int getIndex(byte keyPair, short param) {
+ byte pair = ECTesterApplet.KEYPAIR_LOCAL;
+ int index = 0;
+ while (pair <= ECTesterApplet.KEYPAIR_REMOTE) {
+ short mask = EC_Consts.PARAMETER_FP;
+ while (mask <= EC_Consts.PARAMETER_S) {
+ if (pair == keyPair && param == mask) {
+ return index;
+ }
+ if ((parameters & mask) != 0 && (pair & keyPair) != 0) {
+ if (mask == EC_Consts.PARAMETER_W) {
+ if ((key & EC_Consts.KEY_PUBLIC) != 0)
+ index++;
+ } else if (mask == EC_Consts.PARAMETER_S) {
+ if ((key & EC_Consts.KEY_PRIVATE) != 0)
+ index++;
+ } else {
+ index++;
+ }
+ }
+ mask = (short) (mask << 1);
+ }
+
+ pair = (byte) (pair << 1);
+ }
+ return -1;
+ }
+
+ public boolean hasParameters(byte keyPair, short params) {
+ if ((keyPair & this.keyPair) == 0 || (params ^ parameters) != 0) {
+ return false;
+ }
+ short param = EC_Consts.PARAMETER_FP;
+ while (param <= EC_Consts.PARAMETER_S) {
+ short masked = (short) (param & params);
+ if (masked != 0 && !hasParameter(keyPair, masked)) {
+ return false;
+ }
+ param = (short) (param << 1);
+ }
+ return true;
+ }
+
+ public boolean hasParameter(byte keyPair, short param) {
+ if ((keyPair & this.keyPair) == 0 || (parameters & param) == 0) {
+ return false;
+ }
+ int index = getIndex(keyPair, param);
+ return index != -1 && hasParam(index);
+ }
+
+ public byte[] getParameter(byte keyPair, short param) {
+ return getParam(getIndex(keyPair, param));
+ }
+
+ @Override
+ public String toString() {
+ String source;
+ if (key == EC_Consts.KEY_BOTH) {
+ source = "both keys";
+ } else {
+ source = ((key == EC_Consts.KEY_PUBLIC) ? "public" : "private") + " key";
+ }
+ String pair;
+ if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
+ pair = "both keypairs";
+ } else {
+ pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
+ }
+ return String.format("Exported params from %s of %s", source, pair);
+ }
+ }
+
+ /**
+ *
+ */
public static class ECDH extends Response {
private byte pubkey;
private byte privkey;
@@ -405,7 +428,7 @@ public abstract class Response {
this.export = export;
this.invalid = invalid;
- parse(1, (export & ECTesterApplet.EXPORT_ECDH) != 0 ? 1 : 0);
+ parse(1, (export == ECTesterApplet.EXPORT_TRUE) ? 1 : 0);
}
public boolean hasSecret() {
@@ -439,7 +462,7 @@ public abstract class Response {
this.export = export;
this.raw = raw;
- parse(1, (export & ECTesterApplet.EXPORT_SIG) != 0 ? 1 : 0);
+ parse(1, (export == ECTesterApplet.EXPORT_TRUE) ? 1 : 0);
}
public boolean hasSignature() {
diff --git a/src/cz/crcs/ectester/reader/Util.java b/src/cz/crcs/ectester/reader/Util.java
index 38db3bf..f876fe4 100644
--- a/src/cz/crcs/ectester/reader/Util.java
+++ b/src/cz/crcs/ectester/reader/Util.java
@@ -115,7 +115,7 @@ public class Util {
codeStr = "SIG_VERIFY_FAIL";
break;
}
- return String.format("fail\t(%s,\t0x%4x)", codeStr, code);
+ return String.format("fail\t(%s,\t0x%04x)", codeStr, code);
}
}
}