From abe9f00e15993d55a71b8b328f430421f2f2f151 Mon Sep 17 00:00:00 2001 From: J08nY Date: Tue, 31 Jan 2017 20:15:24 +0100 Subject: Added export instruction, and action to reader One can now export the default domain parameters of the card/simulation with: `ectester.jar -e -fp -b 192 -o params.txt` - Renamed ParamReader to ECParams - Added Command.Export and Response.Export - Moved ECKeyGenerator.KEY_* to EC_Consts.KEY_* --- src/cz/crcs/ectester/applet/ECKeyGenerator.java | 115 ++++++------- src/cz/crcs/ectester/applet/ECKeyTester.java | 22 ++- src/cz/crcs/ectester/applet/ECTesterApplet.java | 184 ++++++++++++-------- src/cz/crcs/ectester/applet/EC_Consts.java | 15 +- src/cz/crcs/ectester/reader/Command.java | 66 +++++-- src/cz/crcs/ectester/reader/ECParams.java | 202 ++++++++++++++++++++++ src/cz/crcs/ectester/reader/ECTester.java | 196 +++++++++++---------- src/cz/crcs/ectester/reader/ParamReader.java | 135 --------------- src/cz/crcs/ectester/reader/Response.java | 217 +++++++++++++----------- src/cz/crcs/ectester/reader/Util.java | 2 +- 10 files changed, 656 insertions(+), 498 deletions(-) create mode 100644 src/cz/crcs/ectester/reader/ECParams.java delete mode 100644 src/cz/crcs/ectester/reader/ParamReader.java (limited to 'src') 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; - - //STATUS WORDS + public static final byte EXPORT_TRUE = (byte) 0xff; + public static final byte EXPORT_FALSE = (byte) 0x00; + + // 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_*) *
@@ -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/ECParams.java b/src/cz/crcs/ectester/reader/ECParams.java
new file mode 100644
index 0000000..c19640e
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/ECParams.java
@@ -0,0 +1,202 @@
+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 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
+ * @return byte[] with params flattened, or null
+ */
+ public static byte[] flatten(short params, String[] data) {
+ if (!validate(data)) {
+ return null;
+ }
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ short paramMask = EC_Consts.PARAMETER_FP;
+ int i = 0;
+ while (paramMask <= EC_Consts.PARAMETER_S) {
+ short masked = (short) (params & paramMask);
+ if (masked != 0) {
+ byte[] param = parse(data[i]);
+ if (masked == EC_Consts.PARAMETER_F2M && data.length == 9) {
+ //read and pad and append e_2, e_3
+ param = Util.concatenate(param, parse(data[i + 1]), parse(data[i + 2]));
+ i += 2;
+ if (param.length != 6)
+ 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!
+ i++;
+ }
+ if (param.length == 0)
+ throw new RuntimeException("Empty parameter read?");
+
+ //write length
+ byte[] length = new byte[2];
+ Util.setShort(length, 0, (short) param.length);
+ out.write(length, 0, 2);
+ //write data
+ out.write(param, 0, param.length);
+ i++;
+ }
+ paramMask = (short) (paramMask << 1);
+ }
+
+ return (out.size() == 0) ? null : out.toByteArray();
+ }
+
+ /**
+ * @param data
+ * @param params
+ * @return
+ */
+ public static String[] expand(byte[][] data, short params) {
+ List