diff options
| author | J08nY | 2017-01-31 20:15:24 +0100 |
|---|---|---|
| committer | J08nY | 2017-01-31 20:15:24 +0100 |
| commit | abe9f00e15993d55a71b8b328f430421f2f2f151 (patch) | |
| tree | 237e1be2bf0209ab422c1b6ce02671bcf33f5d2d | |
| parent | c3e48df92858bad5e74e9cec69c16397b6b12481 (diff) | |
| download | ECTester-abe9f00e15993d55a71b8b328f430421f2f2f151.tar.gz ECTester-abe9f00e15993d55a71b8b328f430421f2f2f151.tar.zst ECTester-abe9f00e15993d55a71b8b328f430421f2f2f151.zip | |
| -rw-r--r-- | !uploader/ectester.cap | bin | 13641 -> 13691 bytes | |||
| -rw-r--r-- | dist/ECTester.jar | bin | 78703 -> 284484 bytes | |||
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECKeyGenerator.java | 115 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECKeyTester.java | 22 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECTesterApplet.java | 182 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/applet/EC_Consts.java | 15 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/Command.java | 66 | ||||
| -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.java | 196 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/Response.java | 217 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/Util.java | 2 |
11 files changed, 527 insertions, 369 deletions
diff --git a/!uploader/ectester.cap b/!uploader/ectester.cap Binary files differindex 8d1bff8..f570b6f 100644 --- a/!uploader/ectester.cap +++ b/!uploader/ectester.cap diff --git a/dist/ECTester.jar b/dist/ECTester.jar Binary files differindex f0a8c3b..a3429fe 100644 --- a/dist/ECTester.jar +++ b/dist/ECTester.jar 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); } } } |
