From a058a9162e894a740d3a11893bd831a72c936c05 Mon Sep 17 00:00:00 2001 From: J08nY Date: Fri, 30 Nov 2018 19:33:50 +0100 Subject: Add dry run mode to enable precise time measurement via overhead subtraction. --- src/cz/crcs/ectester/applet/AppletBase.java | 36 +++++ src/cz/crcs/ectester/applet/ECKeyGenerator.java | 154 ++++++++++++++------- src/cz/crcs/ectester/applet/ECKeyTester.java | 63 ++++++--- src/cz/crcs/ectester/common/ec/EC_Category.java | 2 +- src/cz/crcs/ectester/reader/command/Command.java | 31 +++++ src/cz/crcs/ectester/reader/response/Response.java | 12 ++ .../ectester/reader/test/CardDefaultSuite.java | 6 +- .../crcs/ectester/reader/test/PerformanceTest.java | 38 ++++- 8 files changed, 259 insertions(+), 83 deletions(-) diff --git a/src/cz/crcs/ectester/applet/AppletBase.java b/src/cz/crcs/ectester/applet/AppletBase.java index 48e7785..154b209 100644 --- a/src/cz/crcs/ectester/applet/AppletBase.java +++ b/src/cz/crcs/ectester/applet/AppletBase.java @@ -24,6 +24,7 @@ public abstract class AppletBase extends Applet { public static final byte INS_ALLOCATE_KA = (byte) 0x76; public static final byte INS_ALLOCATE_SIG = (byte) 0x77; public static final byte INS_GET_INFO = (byte) 0x78; + public static final byte INS_SET_DRY_RUN_MODE = (byte) 0x79; // PARAMETERS for P1 and P2 public static final byte KEYPAIR_LOCAL = (byte) 0x01; @@ -31,6 +32,8 @@ public abstract class AppletBase extends Applet { public static final byte KEYPAIR_BOTH = KEYPAIR_LOCAL | KEYPAIR_REMOTE; public static final byte EXPORT_TRUE = (byte) 0xff; public static final byte EXPORT_FALSE = (byte) 0x00; + public static final byte MODE_NORMAL = (byte) 0xaa; + public static final byte MODE_DRY_RUN = (byte) 0xbb; // STATUS WORDS public static final short SW_SIG_VERIFY_FAIL = (short) 0x0ee1; @@ -159,6 +162,8 @@ public abstract class AppletBase extends Applet { case INS_GET_INFO: length = insGetInfo(apdu); break; + case INS_SET_DRY_RUN_MODE: + length = insSetDryRunMode(apdu); default: // The INS code is not supported by the dispatcher ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); @@ -544,6 +549,26 @@ public abstract class AppletBase extends Applet { return getInfo(apdubuf, (short) 0); } + /** + * Set the dry run mode of the applet. + * + * @param apdu P1 = byte mode (MODE_* || ...) + * @return length of response + */ + private short insSetDryRunMode(APDU apdu) { + byte[] apdubuf = apdu.getBuffer(); + byte mode = apduArray[ISO7816.OFFSET_P1]; + + short len = 0; + if (mode == MODE_NORMAL) { + len = setDryRunMode(apdubuf, false, (short) 0); + } + if (mode == MODE_DRY_RUN) { + len = setDryRunMode(apdubuf, true, (short) 0); + } + return len; + } + /** * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...) * @param keyLength key length to set @@ -883,4 +908,15 @@ public abstract class AppletBase extends Applet { length += 2; return length; } + + private short setDryRunMode(byte[] buffer, boolean mode, short offset) { + if (keyTester != null) { + keyTester.setDryRun(mode); + } + if (keyGenerator != null) { + keyGenerator.setDryRun(mode); + } + Util.setShort(buffer, offset, ISO7816.SW_NO_ERROR); + return 2; + } } diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java index 4326752..30910ca 100644 --- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java +++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java @@ -14,6 +14,7 @@ import javacard.security.KeyPair; public class ECKeyGenerator { private short sw = ISO7816.SW_NO_ERROR; + private boolean dryRun = false; /** * @param keyClass @@ -24,12 +25,14 @@ public class ECKeyGenerator { sw = ISO7816.SW_NO_ERROR; KeyPair ecKeyPair = null; try { - ecKeyPair = new KeyPair(keyClass, keyLength); + if (!dryRun) { + ecKeyPair = new KeyPair(keyClass, keyLength); - if (ecKeyPair.getPublic() == null || ecKeyPair.getPrivate() == null) { - try { - ecKeyPair.genKeyPair(); - } catch (Exception ignored) { + if (ecKeyPair.getPublic() == null || ecKeyPair.getPrivate() == null) { + try { + ecKeyPair.genKeyPair(); + } catch (Exception ignored) { + } } } } catch (CardRuntimeException ce) { @@ -46,8 +49,10 @@ public class ECKeyGenerator { public short clearPair(KeyPair keypair, byte key) { try { sw = AppletUtil.keypairCheck(keypair); - if ((key & EC_Consts.KEY_PUBLIC) != 0) keypair.getPublic().clearKey(); - if ((key & EC_Consts.KEY_PRIVATE) != 0) keypair.getPrivate().clearKey(); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) keypair.getPublic().clearKey(); + if ((key & EC_Consts.KEY_PRIVATE) != 0) keypair.getPrivate().clearKey(); + } } catch (CardRuntimeException ce) { sw = ce.getReason(); } @@ -61,7 +66,9 @@ public class ECKeyGenerator { public short generatePair(KeyPair keypair) { try { sw = AppletUtil.keypairCheck(keypair); - keypair.genKeyPair(); + if (!dryRun) { + keypair.genKeyPair(); + } } catch (CardRuntimeException ce) { sw = ce.getReason(); } @@ -187,25 +194,35 @@ public class ECKeyGenerator { try { sw = AppletUtil.keypairCheck(keypair); - ECPublicKey ecPublicKey = (ECPublicKey) keypair.getPublic(); - ECPrivateKey ecPrivateKey = (ECPrivateKey) keypair.getPrivate(); + ECPublicKey ecPublicKey = null; + ECPrivateKey ecPrivateKey = null; + if (!dryRun) { + ecPublicKey = (ECPublicKey) keypair.getPublic(); + ecPrivateKey = (ECPrivateKey) keypair.getPrivate(); + } switch (param) { case EC_Consts.PARAMETER_FP: - if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldFP(data, offset, length); - if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldFP(data, offset, length); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldFP(data, offset, length); + if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldFP(data, offset, length); + } break; case EC_Consts.PARAMETER_F2M: if (length == 4) { short i = Util.getShort(data, (short) (offset + 2)); - if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i); - if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i); + if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i); + } } else if (length == 8) { short i1 = Util.getShort(data, (short) (offset + 2)); short i2 = Util.getShort(data, (short) (offset + 4)); short i3 = Util.getShort(data, (short) (offset + 6)); - if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3); - if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3); + if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3); + } // if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i3, i2, i1); // if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i3, i2, i1); } else { @@ -213,20 +230,28 @@ public class ECKeyGenerator { } break; case EC_Consts.PARAMETER_A: - if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setA(data, offset, length); - if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setA(data, offset, length); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setA(data, offset, length); + if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setA(data, offset, length); + } break; case EC_Consts.PARAMETER_B: - if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setB(data, offset, length); - if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setB(data, offset, length); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setB(data, offset, length); + if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setB(data, offset, length); + } break; case EC_Consts.PARAMETER_G: - if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setG(data, offset, length); - if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setG(data, offset, length); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setG(data, offset, length); + if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setG(data, offset, length); + } break; case EC_Consts.PARAMETER_R: - if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setR(data, offset, length); - if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setR(data, offset, length); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setR(data, offset, length); + if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setR(data, offset, length); + } break; case EC_Consts.PARAMETER_K: short k = 0; @@ -238,14 +263,20 @@ public class ECKeyGenerator { } else if (length == 1) { k = data[offset]; } - if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setK(k); - if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setK(k); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setK(k); + if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setK(k); + } break; case EC_Consts.PARAMETER_S: - if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setS(data, offset, length); + if (!dryRun) { + if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setS(data, offset, length); + } break; case EC_Consts.PARAMETER_W: - if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setW(data, offset, length); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setW(data, offset, length); + } break; default: ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); @@ -310,54 +341,75 @@ public class ECKeyGenerator { short length = 0; try { sw = AppletUtil.keypairCheck(keypair); - ECPublicKey ecPublicKey = (ECPublicKey) keypair.getPublic(); - ECPrivateKey ecPrivateKey = (ECPrivateKey) keypair.getPrivate(); + + ECPublicKey ecPublicKey = null; + ECPrivateKey ecPrivateKey = null; + if (!dryRun) { + ecPublicKey = (ECPublicKey) keypair.getPublic(); + ecPrivateKey = (ECPrivateKey) keypair.getPrivate(); + } switch (param) { case EC_Consts.PARAMETER_FP: - if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getField(outputBuffer, outputOffset); - if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getField(outputBuffer, outputOffset); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) + length = ecPublicKey.getField(outputBuffer, outputOffset); + if ((key & EC_Consts.KEY_PRIVATE) != 0) + length = ecPrivateKey.getField(outputBuffer, outputOffset); + } break; case EC_Consts.PARAMETER_F2M: - if ((key & EC_Consts.KEY_PUBLIC) != 0) { + if ((key & EC_Consts.KEY_PUBLIC) != 0 && !dryRun) { Util.setShort(outputBuffer, outputOffset, ecPublicKey.getSize()); length = 2; length += ecPublicKey.getField(outputBuffer, (short) (outputOffset + 2)); } - if ((key & EC_Consts.KEY_PRIVATE) != 0) { + if ((key & EC_Consts.KEY_PRIVATE) != 0 && !dryRun) { Util.setShort(outputBuffer, outputOffset, ecPrivateKey.getSize()); length = 2; length += ecPrivateKey.getField(outputBuffer, (short) (outputOffset + 2)); } break; case EC_Consts.PARAMETER_A: - if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getA(outputBuffer, outputOffset); - if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getA(outputBuffer, outputOffset); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getA(outputBuffer, outputOffset); + if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getA(outputBuffer, outputOffset); + } break; case EC_Consts.PARAMETER_B: - if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getB(outputBuffer, outputOffset); - if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getB(outputBuffer, outputOffset); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getB(outputBuffer, outputOffset); + if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getB(outputBuffer, outputOffset); + } break; case EC_Consts.PARAMETER_G: - if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getG(outputBuffer, outputOffset); - if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getG(outputBuffer, outputOffset); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getG(outputBuffer, outputOffset); + if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getG(outputBuffer, outputOffset); + } break; case EC_Consts.PARAMETER_R: - if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getR(outputBuffer, outputOffset); - if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getR(outputBuffer, outputOffset); + if (!dryRun) { + if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getR(outputBuffer, outputOffset); + if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getR(outputBuffer, outputOffset); + } break; case EC_Consts.PARAMETER_K: - length = 2; - if ((key & EC_Consts.KEY_PUBLIC) != 0) - Util.setShort(outputBuffer, outputOffset, ecPublicKey.getK()); - if ((key & EC_Consts.KEY_PRIVATE) != 0) - Util.setShort(outputBuffer, outputOffset, ecPrivateKey.getK()); + if (!dryRun) { + length = 2; + if ((key & EC_Consts.KEY_PUBLIC) != 0) + Util.setShort(outputBuffer, outputOffset, ecPublicKey.getK()); + if ((key & EC_Consts.KEY_PRIVATE) != 0) + Util.setShort(outputBuffer, outputOffset, ecPrivateKey.getK()); + } break; case EC_Consts.PARAMETER_W: - if ((key & EC_Consts.KEY_PUBLIC) != 0) length = ecPublicKey.getW(outputBuffer, outputOffset); + if ((key & EC_Consts.KEY_PUBLIC) != 0 && !dryRun) + length = ecPublicKey.getW(outputBuffer, outputOffset); break; case EC_Consts.PARAMETER_S: - if ((key & EC_Consts.KEY_PRIVATE) != 0) length = ecPrivateKey.getS(outputBuffer, outputOffset); + if ((key & EC_Consts.KEY_PRIVATE) != 0 && !dryRun) + length = ecPrivateKey.getS(outputBuffer, outputOffset); break; default: ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); @@ -439,4 +491,8 @@ public class ECKeyGenerator { public short getSW() { return sw; } + + public void setDryRun(boolean dryRun) { + this.dryRun = dryRun; + } } diff --git a/src/cz/crcs/ectester/applet/ECKeyTester.java b/src/cz/crcs/ectester/applet/ECKeyTester.java index 0e46971..89590d0 100644 --- a/src/cz/crcs/ectester/applet/ECKeyTester.java +++ b/src/cz/crcs/ectester/applet/ECKeyTester.java @@ -18,12 +18,15 @@ public class ECKeyTester { private short sigType = 0; private short sw = ISO7816.SW_NO_ERROR; + private boolean dryRun = false; public short allocateKA(byte algorithm) { sw = ISO7816.SW_NO_ERROR; try { - ecKeyAgreement = KeyAgreement.getInstance(algorithm, false); - kaType = algorithm; + if (!dryRun) { + ecKeyAgreement = KeyAgreement.getInstance(algorithm, false); + kaType = algorithm; + } } catch (CardRuntimeException ce) { sw = ce.getReason(); } @@ -33,8 +36,10 @@ public class ECKeyTester { public short allocateSig(byte algorithm) { sw = ISO7816.SW_NO_ERROR; try { - ecdsaSignature = Signature.getInstance(algorithm, false); - sigType = algorithm; + if (!dryRun) { + ecdsaSignature = Signature.getInstance(algorithm, false); + sigType = algorithm; + } } catch (CardRuntimeException ce) { sw = ce.getReason(); } @@ -61,11 +66,13 @@ public class ECKeyTester { sw = AppletUtil.kaCheck(ecKeyAgreement); sw = AppletUtil.keypairCheck(privatePair); sw = AppletUtil.keypairCheck(publicPair); - short pubkeyLength = ((ECPublicKey) publicPair.getPublic()).getW(pubkeyBuffer, pubkeyOffset); - ecKeyAgreement.init(privatePair.getPrivate()); + if (!dryRun) { + short pubkeyLength = ((ECPublicKey) publicPair.getPublic()).getW(pubkeyBuffer, pubkeyOffset); + ecKeyAgreement.init(privatePair.getPrivate()); - pubkeyLength = EC_Consts.transformParameter(transformation, pubkeyBuffer, pubkeyOffset, pubkeyLength); - length = ecKeyAgreement.generateSecret(pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset); + pubkeyLength = EC_Consts.transformParameter(transformation, pubkeyBuffer, pubkeyOffset, pubkeyLength); + length = ecKeyAgreement.generateSecret(pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset); + } } catch (CardRuntimeException ce) { sw = ce.getReason(); } @@ -88,9 +95,11 @@ public class ECKeyTester { sw = AppletUtil.kaCheck(ecKeyAgreement); sw = AppletUtil.keypairCheck(privatePair); - ecKeyAgreement.init(privatePair.getPrivate()); - pubkeyLength = EC_Consts.transformParameter(transformation, pubkey, pubkeyOffset, pubkeyLength); - length = ecKeyAgreement.generateSecret(pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset); + if (!dryRun) { + ecKeyAgreement.init(privatePair.getPrivate()); + pubkeyLength = EC_Consts.transformParameter(transformation, pubkey, pubkeyOffset, pubkeyLength); + length = ecKeyAgreement.generateSecret(pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset); + } } catch (CardRuntimeException ce) { sw = ce.getReason(); } @@ -116,13 +125,14 @@ public class ECKeyTester { try { sw = AppletUtil.signCheck(ecdsaSignature); - ecdsaSignature.init(signKey, Signature.MODE_SIGN); - length = ecdsaSignature.sign(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset); + if (!dryRun) { + ecdsaSignature.init(signKey, Signature.MODE_SIGN); + length = ecdsaSignature.sign(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset); - ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY); - boolean correct = ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, length); - if (!correct) { - sw = AppletBase.SW_SIG_VERIFY_FAIL; + ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY); + if (!ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, length)) { + sw = AppletBase.SW_SIG_VERIFY_FAIL; + } } } catch (CardRuntimeException ce) { sw = ce.getReason(); @@ -144,8 +154,10 @@ public class ECKeyTester { try { sw = AppletUtil.signCheck(ecdsaSignature); - ecdsaSignature.init(signKey, Signature.MODE_SIGN); - length = ecdsaSignature.sign(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset); + if (!dryRun) { + ecdsaSignature.init(signKey, Signature.MODE_SIGN); + length = ecdsaSignature.sign(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset); + } } catch (CardRuntimeException ce) { sw = ce.getReason(); } @@ -167,10 +179,11 @@ public class ECKeyTester { try { sw = AppletUtil.signCheck(ecdsaSignature); - ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY); - boolean correct = ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, sigLength); - if (!correct) { - sw = AppletBase.SW_SIG_VERIFY_FAIL; + if (!dryRun) { + ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY); + if (!ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, sigLength)) { + sw = AppletBase.SW_SIG_VERIFY_FAIL; + } } } catch (CardRuntimeException ce) { sw = ce.getReason(); @@ -205,4 +218,8 @@ public class ECKeyTester { public short getSW() { return sw; } + + public void setDryRun(boolean dryRun) { + this.dryRun = dryRun; + } } diff --git a/src/cz/crcs/ectester/common/ec/EC_Category.java b/src/cz/crcs/ectester/common/ec/EC_Category.java index 05c910c..1eb818f 100644 --- a/src/cz/crcs/ectester/common/ec/EC_Category.java +++ b/src/cz/crcs/ectester/common/ec/EC_Category.java @@ -92,7 +92,7 @@ public class EC_Category { } String[] headers = new String[]{"Public keys", "Private keys", "KeyPairs", "Results(KA)", "Results(SIG)"}; - Class[] classes = new Class[]{EC_Key.Public.class, EC_Key.Private.class, EC_Keypair.class, EC_KAResult.class, EC_SigResult.class}; + Class[] classes = new Class[]{EC_Key.Public.class, EC_Key.Private.class, EC_Keypair.class, EC_KAResult.class, EC_SigResult.class}; for (int i = 0; i < headers.length; ++i) { Map data = getObjects(classes[i]); size = data.size(); diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index a3560df..1b1ec33 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -890,5 +890,36 @@ public abstract class Command implements Cloneable { return "Get applet info"; } } + + /** + * + */ + public static class SetDryRunMode extends Command { + private byte dryRunMode; + /** + * + * @param cardManager + * @param dryRunMode + */ + public SetDryRunMode(CardMngr cardManager, byte dryRunMode) { + super(cardManager); + this.dryRunMode = dryRunMode; + + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SET_DRY_RUN_MODE, dryRunMode, 0); + } + + @Override + public Response send() throws CardException { + long elapsed = -System.nanoTime(); + ResponseAPDU response = cardManager.send(cmd); + elapsed += System.nanoTime(); + return new Response.SetDryRunMode(response, getDescription(), elapsed); + } + + @Override + public String getDescription() { + return (dryRunMode == ECTesterApplet.MODE_NORMAL ? "Disable" : "Enable") + " dry run mode"; + } + } } diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index 235564e..0dded7c 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -502,4 +502,16 @@ public abstract class Response { return apduArrayLength; } } + + /** + * + */ + public static class SetDryRunMode extends Response { + + public SetDryRunMode(ResponseAPDU response, String description, long time) { + super(response, description, time); + + parse(1, 0); + } + } } diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java index 91f9ef6..f42af23 100644 --- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java @@ -83,7 +83,7 @@ public class CardDefaultSuite extends CardTestSuite { Test compound; if (ka.ok()) { - Test perfTest = runTest(PerformanceTest.repeat(ecdh, 10)); + Test perfTest = runTest(PerformanceTest.repeat(this.card, ecdh, 10)); compound = runTest(CompoundTest.function(kaCallback, kaDesc, allocate, ka, kaCompressed, perfTest)); } else { compound = runTest(CompoundTest.function(kaCallback, kaDesc, allocate, ka, kaCompressed)); @@ -114,10 +114,10 @@ public class CardDefaultSuite extends CardTestSuite { Test compound; if (expect.ok()) { Command ecdsaSign = new Command.ECDSA_sign(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, ECTesterApplet.EXPORT_TRUE, sigData); - PerformanceTest signTest = runTest(PerformanceTest.repeat("Sign", ecdsaSign, 10)); + PerformanceTest signTest = runTest(PerformanceTest.repeat(this.card, "Sign", ecdsaSign, 10)); byte[] signature = signTest.getResponses()[0].getParam(0); Command ecdsaVerify = new Command.ECDSA_verify(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, sigData, signature); - PerformanceTest verifyTest = runTest(PerformanceTest.repeat("Verify", ecdsaVerify, 10)); + PerformanceTest verifyTest = runTest(PerformanceTest.repeat(this.card, "Verify", ecdsaVerify, 10)); compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect, signTest, verifyTest)); } else { compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect)); diff --git a/src/cz/crcs/ectester/reader/test/PerformanceTest.java b/src/cz/crcs/ectester/reader/test/PerformanceTest.java index f9a4472..ce6780d 100644 --- a/src/cz/crcs/ectester/reader/test/PerformanceTest.java +++ b/src/cz/crcs/ectester/reader/test/PerformanceTest.java @@ -1,18 +1,24 @@ package cz.crcs.ectester.reader.test; +import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.common.test.Result; import cz.crcs.ectester.common.test.SimpleTest; import cz.crcs.ectester.common.test.TestCallback; +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; +import javax.smartcardio.CardException; import java.util.Arrays; /** * @author Jan Jancar johny@neuromancer.sk */ public class PerformanceTest extends SimpleTest { + private CardMngr cardManager; private long[] times; + private long[] reducedTimes; private Response[] responses; private long mean; private long median; @@ -20,23 +26,24 @@ public class PerformanceTest extends SimpleTest { private int count; private String desc; - private PerformanceTest(CommandTestable testable, int count, String desc) { + private PerformanceTest(CardMngr cardManager, CommandTestable testable, int count, String desc) { super(testable, new TestCallback() { @Override public Result apply(CommandTestable testable) { return new Result(Result.Value.SUCCESS); } }); + this.cardManager = cardManager; this.count = count; this.desc = desc; } - public static PerformanceTest repeat(Command cmd, int count) { - return new PerformanceTest(new CommandTestable(cmd), count, null); + public static PerformanceTest repeat(CardMngr cardManager, Command cmd, int count) { + return new PerformanceTest(cardManager, new CommandTestable(cmd), count, null); } - public static PerformanceTest repeat(String desc, Command cmd, int count) { - return new PerformanceTest(new CommandTestable(cmd), count, desc); + public static PerformanceTest repeat(CardMngr cardManager, String desc, Command cmd, int count) { + return new PerformanceTest(cardManager, new CommandTestable(cmd), count, desc); } @Override @@ -47,18 +54,31 @@ public class PerformanceTest extends SimpleTest { @Override protected void runSelf() { + long baseTime = 0; + try { + new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_DRY_RUN).send(); + testable.run(); + baseTime = testable.getResponse().getDuration(); + testable.reset(); + new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_NORMAL).send(); + } catch (CardException ce) { + throw new TestException(ce); + } + times = new long[count]; + reducedTimes = new long[count]; responses = new Response[count]; for (int i = 0; i < count; ++i) { testable.run(); responses[i] = testable.getResponse(); times[i] = responses[i].getDuration(); + reducedTimes[i] = times[i] - baseTime; testable.reset(); } - mean = Arrays.stream(times).sum() / count; + mean = Arrays.stream(reducedTimes).sum() / count; - long[] sorted = times.clone(); + long[] sorted = reducedTimes.clone(); Arrays.sort(sorted); if (count % 2 == 0) { median = (sorted[(count / 2) - 1] + sorted[count / 2]) / 2; @@ -99,6 +119,10 @@ public class PerformanceTest extends SimpleTest { return times; } + public long[] getReducedTimes() { + return reducedTimes; + } + public long getMean() { return mean; } -- cgit v1.2.3-70-g09d2 From 713a3bb2f997ad8e50e2d8c226cbb1e1abc8f858 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sat, 1 Dec 2018 17:01:27 +0100 Subject: Add more cofactor curves. --- src/cz/crcs/ectester/data/cofactor/cofactor192p2.csv | 1 + src/cz/crcs/ectester/data/cofactor/cofactor192p4.csv | 1 + src/cz/crcs/ectester/data/cofactor/cofactor192p8.csv | 1 + src/cz/crcs/ectester/data/cofactor/curves.xml | 12 ++++++++++++ 4 files changed, 15 insertions(+) create mode 100644 src/cz/crcs/ectester/data/cofactor/cofactor192p2.csv create mode 100644 src/cz/crcs/ectester/data/cofactor/cofactor192p4.csv create mode 100644 src/cz/crcs/ectester/data/cofactor/cofactor192p8.csv diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor192p2.csv b/src/cz/crcs/ectester/data/cofactor/cofactor192p2.csv new file mode 100644 index 0000000..4de7049 --- /dev/null +++ b/src/cz/crcs/ectester/data/cofactor/cofactor192p2.csv @@ -0,0 +1 @@ +0x79cb22319472d019a08f7ae4f99c3edea2f167773210eab7,0x2b1afa29b6e9f7e148f7eb306ae942a506546c7129d56a3f,0x704d348ecd838ed800911bab3298aeebbf1c03b5489bca5d,0x61fc509a9d967735e8f18b0a4ba323134989c7711f44c35b,0x4fe31f28e2ee2a41f6fd661e417d32832bee6f3e164b167e,0x3ce59118ca39680cd047bd72595564c3953a773f01833de3,0x02 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor192p4.csv b/src/cz/crcs/ectester/data/cofactor/cofactor192p4.csv new file mode 100644 index 0000000..645f031 --- /dev/null +++ b/src/cz/crcs/ectester/data/cofactor/cofactor192p4.csv @@ -0,0 +1 @@ +0x8cceb84c81521937bef0925a3aaf09195a59c3f99ae06135,0x6ad5a0b617af4ac05f668ae0236f0a485290c36ef609efb5,0x3289c9a3f4f0364147634d40c2f7604e4bc98773daefc954,0x314789e7e4e448b000d235cc51251e70cd8c92c11d1858f9,0x74459b81d5322dc2c631d3ba964e8b4c8f1e4196939a5579,0x2333ae132054864defbc24965da70e7dbdb87ba264315991,0x04 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor192p8.csv b/src/cz/crcs/ectester/data/cofactor/cofactor192p8.csv new file mode 100644 index 0000000..ee39445 --- /dev/null +++ b/src/cz/crcs/ectester/data/cofactor/cofactor192p8.csv @@ -0,0 +1 @@ +0xa9a93bb887865d349841624bd8281c589a8e0196ae724eed,0x1b8b108f729cc205fb0ec88825d7d696e3df62ed328bd535,0x81078fdf85b1ee56ea3e27f6dedcca6f5eb9b645f536dc68,0x37369946896227fce5bfe8f760ba827080caa6700d8d8aaa,0x7f54e11bf72549866571fb70b383b6d1451973c11e3fd082,0x1535277710f0cba693082c4985a9197e9e759aa3571eb787,0x08 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/cofactor/curves.xml b/src/cz/crcs/ectester/data/cofactor/curves.xml index 7cf2a9a..ddc8746 100644 --- a/src/cz/crcs/ectester/data/cofactor/curves.xml +++ b/src/cz/crcs/ectester/data/cofactor/curves.xml @@ -88,6 +88,18 @@ prime cofactor192p2.csv + + cofactor192p4 + 192 + prime + cofactor192p4.csv + + + cofactor192p8 + 192 + prime + cofactor192p8.csv + cofactor163t2 -- cgit v1.2.3-70-g09d2 From 832bb8ddbe0d5b19813fa48491b1c9f21c146098 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sat, 1 Dec 2018 21:21:44 +0100 Subject: Add entropy estimation to plot_gen. --- util/plot_gen.py | 36 +++++++++++++++++++----------------- util/utils.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 util/utils.py diff --git a/util/plot_gen.py b/util/plot_gen.py index 0d518e6..b562404 100755 --- a/util/plot_gen.py +++ b/util/plot_gen.py @@ -18,12 +18,13 @@ from matplotlib import ticker, colors from copy import deepcopy import argparse -from utils import hw, moving_average, plot_hist +from utils import hw, moving_average, plot_hist, jackknife_entropy, miller_correction if __name__ == "__main__": parser = argparse.ArgumentParser(description="Plot results of ECTester key generation timing.") parser.add_argument("-o", "--output", dest="output", type=argparse.FileType("wb"), help="Write image to [file], do not display.", metavar="file") parser.add_argument("--priv", dest="priv", action="store_true", help="Show private key MSB heatmap plot.") + parser.add_argument("--entropy", dest="entropy", action="store_true", help="Show estimated entropy of private key MSB conditioned on time of generation.") parser.add_argument("--hist", dest="hist", action="store_true", help="Show keygen time histogram.") parser.add_argument("--export-hist", dest="export_hist", action="store_true", help="Show export time histogram.") parser.add_argument("--avg", dest="avg", action="store_true", help="Show moving average of keygen time.") @@ -103,21 +104,6 @@ if __name__ == "__main__": sorted_data = np.sort(data, order="gen_time") - i = 0 - entropies = {} - while i < len(data): - time_val = sorted_data["gen_time"][i] - j = i - msbs = [0 for _ in range(256)] - while j < len(data) and sorted_data["gen_time"][j] == time_val: - msbs[(sorted_data["priv"][j] >> (bit_size - 8)) & 0xff] += 1 - j += 1 - if j - 100 > i: - entropies[time_val] = entropy(msbs, base=2) - i = j - - entropy = sum(entropies.values())/len(entropies) - cmap = deepcopy(plt.cm.plasma) cmap.set_bad("black") @@ -174,7 +160,23 @@ if __name__ == "__main__": fig.colorbar(im, ax=axe_priv_hist) fig.text(0.01, 0.02, "Data size: {}".format(len(gen_time_data)), size="small") - fig.text(0.01, 0.04, "Entropy of privkey MSB(estimated): {:.2f} b".format(entropy), size="small") + + if opts.entropy: + i = 0 + entropies = {} + while i < len(data): + time_val = sorted_data["gen_time"][i] + j = i + msbs = [0 for _ in range(256)] + while j < len(data) and sorted_data["gen_time"][j] == time_val: + msbs[(sorted_data["priv"][j] >> (bit_size - 8)) & 0xff] += 1 + j += 1 + if j - 100 > i: + entropies[time_val] = miller_correction(entropy(msbs, base=2), j - i, 256) + i = j + + entropy = sum(entropies.values())/len(entropies) + fig.text(0.01, 0.04, "Entropy of privkey MSB(estimated): {:.2f} b".format(entropy), size="small") if opts.output is None: plt.show() diff --git a/util/utils.py b/util/utils.py new file mode 100644 index 0000000..bddfc35 --- /dev/null +++ b/util/utils.py @@ -0,0 +1,34 @@ +import numpy as np +from matplotlib import ticker + + +def hw(i): + res = 0 + while i: + res += 1 + i &= i - 1 + return res + + +def moving_average(a, n) : + ret = np.cumsum(a, dtype=float) + ret[n:] = ret[n:] - ret[:-n] + return ret[n - 1:] / n + + +def plot_hist(axes, data, xlabel=None, log=False): + time_max = max(data) + time_min = min(data) + time_avg = np.average(data) + time_median = np.median(data) + axes.hist(data, bins=time_max - time_min, log=log) + axes.axvline(x=time_avg, alpha=0.7, linestyle="dotted", color="blue", label="avg = {}".format(time_avg)) + axes.axvline(x=time_median, alpha=0.7, linestyle="dotted", color="green", label="median = {}".format(time_median)) + axes.set_ylabel("count" + ("\n(log)" if log else "")) + axes.set_xlabel("time" if xlabel is None else xlabel) + axes.xaxis.set_major_locator(ticker.MaxNLocator()) + axes.legend(loc="best") + + +def miller_correction(entropy, samples, bins): + return entropy + (bins - 1)/(2*samples) -- cgit v1.2.3-70-g09d2 From bd990776812eddbb50f073b8e1dcef2f69820768 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 2 Dec 2018 00:53:36 +0100 Subject: Add more output to signature command in reader app. --- docs/IMPLEMENTATIONS.md | 16 ++++++-- src/cz/crcs/ectester/reader/ECTesterReader.java | 52 ++++++++++++++++++++----- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/docs/IMPLEMENTATIONS.md b/docs/IMPLEMENTATIONS.md index b4a4ea8..724150f 100644 --- a/docs/IMPLEMENTATIONS.md +++ b/docs/IMPLEMENTATIONS.md @@ -536,17 +536,27 @@ y_n &= \frac{(x_n + x_1)((x_n + x_1)(x_{n+1} + x_1) + x_1^2 + y_1)}{x_1} + y_1 ## References [^1]: HANKERSON, Darrel; MENEZES, Alfred J.; VANSTONE, Scott. Guide to Elliptic Curve Cryptography. New York, USA: Springer, 2004. ISBN 9780387218465. Available from DOI: [10.1007/b97644](https://dx.doi.org/10.1007/b97644). -[^2]: COHEN, Henri; FREY, Gerhard; AVANZI, Roberto M.; DOCHE, Christophe; LANGE, -Tanja; NGUYEN, Kim; VERCAUTEREN, Frederik. Handbook of Elliptic and Hyper- -elliptic Curve Cryptography. CRC Press, 2005-07-19. Discrete Mathematics and It’s Applications, no. 34. ISBN 9781584885184. + +[^2]: COHEN, Henri; FREY, Gerhard; AVANZI, Roberto M.; DOCHE, Christophe; LANGE, Tanja; NGUYEN, Kim; VERCAUTEREN, Frederik. Handbook of Elliptic and Hyper-elliptic Curve Cryptography. CRC Press, 2005-07-19. Discrete Mathematics and It’s Applications, no. 34. ISBN 9781584885184. + [^3]: BERNSTEIN, Daniel J.; LANGE, Tanja. Explicit Formulas Database, + [^4]: + [^5]: KNUTH, Donald: The Art of Computer Programming, Volume 2: Seminumerical algorithms + [^6]: GORDON, Daniel M.: A survey of fast exponentiation methods. + [^7]: MORAIN, Francois; OLIVOS, Jorge: Speeding up the computations on an elliptic curve using addition-subtraction chains. + [^8]: JOYE, Marc; YEN, Sung-Ming: The Montgomery Powering Ladder. + [^9]: MOLLER, Bodo: Securing Elliptic Curve Point Multiplication against Side-Channel Attacks. + [^10]: MOLLER, Bodo: Improved Techniques for Fast Exponentiation. + [^11]: MOLLER, Bodo: Fractional Windows Revisited: Improved Signed-Digit Representations for Efficient Exponentiation. + [^12]: KOYAMA, Kenji; TSURUOKA, Yukio: Speeding up Elliptic Cryptosystems by Using a Signed Binary Window Method. + [^13]: GALLANT, Robert P.; LAMBERT, Robert J.; VANSTONE, Scott A.: Faster point multiplication on elliptic curves with efficient endomorphisms. \ No newline at end of file diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index c94a544..c442ec1 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -50,10 +50,7 @@ import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; import java.security.Security; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Scanner; +import java.util.*; import java.util.jar.Manifest; import static cz.crcs.ectester.applet.EC_Consts.KeyAgreement_ALG_EC_SVDP_DH; @@ -331,6 +328,7 @@ public class ECTesterReader { opts.addOption(Option.builder("v").longOpt("verbose").desc("Turn on verbose logging.").build()); opts.addOption(Option.builder().longOpt("format").desc("Output format to use. One of: text,yml,xml.").hasArg().argName("format").build()); + opts.addOption(Option.builder().longOpt("static").desc("Generate key(s) only once, keep them for later operations.").build()); opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build()); opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations.").build()); opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build()); @@ -614,6 +612,7 @@ public class ECTesterReader { } if (out != null) { + out.write(String.format("%d;%d;%s;%s;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(perform.getSecret(), false))); } @@ -644,6 +643,10 @@ public class ECTesterReader { throw new FileNotFoundException(cfg.input); } data = Files.readAllBytes(in.toPath()); + } else { + Random rand = new Random(); + data = new byte[32]; + rand.nextBytes(data); } Command generate; @@ -667,18 +670,42 @@ public class ECTesterReader { OutputStreamWriter out = FileUtil.openFiles(cfg.outputs); if (out != null) { - out.write("index;time;signature\n"); + out.write("index;signTime;verifyTime;data;pubW;privS;signature;valid\n"); + } + + Command.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR); + Response.Export exported = null; + if (cfg.staticKey) { + respWriter.outputResponse(generate.send()); + exported = export.send(); + respWriter.outputResponse(exported); } int retry = 0; int done = 0; while (done < cfg.ECDSACount) { - respWriter.outputResponse(generate.send()); + if (!cfg.staticKey) { + respWriter.outputResponse(generate.send()); + exported = export.send(); + respWriter.outputResponse(exported); + } - Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data).send(); - respWriter.outputResponse(perform); + Response.ECDSA sign = new Command.ECDSA_sign(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data).send(); + respWriter.outputResponse(sign); + if (!sign.successful() || ! sign.hasSignature()) { + if (retry < 10) { + ++retry; + continue; + } else { + System.err.println(Colors.error("Couldn't obtain ECDSA signature from card response.")); + break; + } + } + byte[] signature = sign.getSignature(); + Response.ECDSA verify = new Command.ECDSA_verify(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, data, signature).send(); + respWriter.outputResponse(verify); - if (!perform.successful() || !perform.hasSignature()) { + if (verify.error()) { if (retry < 10) { ++retry; continue; @@ -689,7 +716,10 @@ public class ECTesterReader { } if (out != null) { - out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(perform.getSignature(), false))); + String pub = ByteUtil.bytesToHex(exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false); + String priv = ByteUtil.bytesToHex(exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false); + String dataString = (cfg.input != null) ? "" : ByteUtil.bytesToHex(data, false); + out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%d\n", done, sign.getDuration() / 1000000, verify.getDuration() / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), verify.successful() ? 1 : 0)); } ++done; @@ -733,6 +763,7 @@ public class ECTesterReader { public String key; public boolean anyKeypart = false; + public boolean staticKey = false; public String log; @@ -786,6 +817,7 @@ public class ECTesterReader { key = cli.getOptionValue("key"); anyKey = (key != null) || (namedKey != null); anyKeypart = anyKey || anyPublicKey || anyPrivateKey; + staticKey = cli.hasOption("static"); if (cli.hasOption("log")) { log = cli.getOptionValue("log", String.format("ECTESTER_log_%d.log", System.currentTimeMillis() / 1000)); -- cgit v1.2.3-70-g09d2 From 03f77379b28826cef1599b8aa70645037a6ddaa9 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 2 Dec 2018 14:51:52 +0100 Subject: Add nonce recovery and output in ECDSA utility function. --- src/cz/crcs/ectester/common/util/CardUtil.java | 17 ++++++ src/cz/crcs/ectester/common/util/ECUtil.java | 41 ++++++++++++-- src/cz/crcs/ectester/reader/ECTesterReader.java | 22 +++++++- src/cz/crcs/ectester/reader/command/Command.java | 68 ++++++++++++------------ 4 files changed, 108 insertions(+), 40 deletions(-) diff --git a/src/cz/crcs/ectester/common/util/CardUtil.java b/src/cz/crcs/ectester/common/util/CardUtil.java index 7483c32..a761949 100644 --- a/src/cz/crcs/ectester/common/util/CardUtil.java +++ b/src/cz/crcs/ectester/common/util/CardUtil.java @@ -31,6 +31,23 @@ public class CardUtil { } } + public static String getSigHashAlgo(byte sigType) { + switch (sigType) { + case EC_Consts.Signature_ALG_ECDSA_SHA: + return "SHA-1"; + case EC_Consts.Signature_ALG_ECDSA_SHA_224: + return "SHA-224"; + case EC_Consts.Signature_ALG_ECDSA_SHA_256: + return "SHA-256"; + case EC_Consts.Signature_ALG_ECDSA_SHA_384: + return "SHA-384"; + case EC_Consts.Signature_ALG_ECDSA_SHA_512: + return "SHA-512"; + default: + return null; + } + } + public static byte getKA(String name) { switch (name) { case "DH": diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java index 1706ca0..0260e95 100644 --- a/src/cz/crcs/ectester/common/util/ECUtil.java +++ b/src/cz/crcs/ectester/common/util/ECUtil.java @@ -3,9 +3,16 @@ package cz.crcs.ectester.common.util; import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.common.ec.*; import cz.crcs.ectester.data.EC_Store; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1StreamParser; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERSequenceParser; +import java.io.IOException; import java.math.BigInteger; import java.security.KeyPair; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.*; @@ -196,7 +203,7 @@ public class ECUtil { public static ECPublicKey toPublicKey(EC_Key.Public pubkey) { EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, pubkey.getCurve()); if (curve == null) { - throw new IllegalArgumentException("pubkey curve nor found: " + pubkey.getCurve()); + throw new IllegalArgumentException("pubkey curve not found: " + pubkey.getCurve()); } return new RawECPublicKey(toPoint(pubkey), curve.toSpec()); } @@ -204,7 +211,7 @@ public class ECUtil { public static ECPrivateKey toPrivateKey(EC_Key.Private privkey) { EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, privkey.getCurve()); if (curve == null) { - throw new IllegalArgumentException("privkey curve nor found: " + privkey.getCurve()); + throw new IllegalArgumentException("privkey curve not found: " + privkey.getCurve()); } return new RawECPrivateKey(toScalar(privkey), curve.toSpec()); } @@ -212,7 +219,7 @@ public class ECUtil { public static KeyPair toKeyPair(EC_Keypair kp) { EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, kp.getCurve()); if (curve == null) { - throw new IllegalArgumentException("keypair curve nor found: " + kp.getCurve()); + throw new IllegalArgumentException("keypair curve not found: " + kp.getCurve()); } ECPublicKey pubkey = new RawECPublicKey(toPoint(kp), curve.toSpec()); ECPrivateKey privkey = new RawECPrivateKey(toScalar(kp), curve.toSpec()); @@ -222,4 +229,32 @@ public class ECUtil { public static byte[] toDERSignature(byte[] r, byte[] s) { return ByteUtil.concatenate(new byte[]{0x30, (byte) (r.length + s.length + 4), 0x02, (byte) r.length}, r, new byte[]{0x02, (byte) s.length}, s); } + + public static BigInteger[] fromDERSignature(byte[] signature) throws IOException { + ASN1StreamParser parser = new ASN1StreamParser(signature); + DERSequence sequence = (DERSequence) ((DERSequenceParser) parser.readObject()).getLoadedObject(); + ASN1Integer r = (ASN1Integer) sequence.getObjectAt(0); + ASN1Integer s = (ASN1Integer) sequence.getObjectAt(1); + return new BigInteger[]{r.getPositiveValue(), s.getPositiveValue()}; + } + + public static BigInteger recoverSignatureNonce(byte[] signature, byte[] data, BigInteger privkey, ECParameterSpec params, String hashType) { + try { + int bitSize = params.getOrder().bitLength(); + MessageDigest md = MessageDigest.getInstance(hashType); + byte[] hash = md.digest(data); + BigInteger hashInt = new BigInteger(1, hash); + hashInt = hashInt.and(BigInteger.ONE.shiftLeft(bitSize + 1).subtract(BigInteger.ONE)); + + BigInteger[] sigPair = fromDERSignature(signature); + BigInteger r = sigPair[0]; + BigInteger s = sigPair[1]; + + BigInteger rd = privkey.multiply(r).mod(params.getOrder()); + BigInteger hrd = hashInt.add(rd).mod(params.getOrder()); + return s.modInverse(params.getOrder()).multiply(hrd).mod(params.getOrder()); + } catch (NoSuchAlgorithmException | IOException nsae) { + return null; + } + } } diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index c442ec1..fe44709 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -26,10 +26,12 @@ import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.common.cli.CLITools; import cz.crcs.ectester.common.cli.Colors; +import cz.crcs.ectester.common.ec.EC_Curve; import cz.crcs.ectester.common.output.OutputLogger; import cz.crcs.ectester.common.output.TestWriter; import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.common.util.CardUtil; +import cz.crcs.ectester.common.util.ECUtil; import cz.crcs.ectester.common.util.FileUtil; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.command.Command; @@ -40,16 +42,22 @@ import cz.crcs.ectester.reader.test.*; import javacard.framework.ISO7816; import javacard.security.KeyPair; import org.apache.commons.cli.*; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1StreamParser; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERSequenceParser; import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.smartcardio.CardException; import javax.smartcardio.ResponseAPDU; import javax.xml.parsers.ParserConfigurationException; import java.io.*; +import java.math.BigInteger; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; import java.security.Security; +import java.security.spec.ECParameterSpec; import java.util.*; import java.util.jar.Manifest; @@ -670,7 +678,7 @@ public class ECTesterReader { OutputStreamWriter out = FileUtil.openFiles(cfg.outputs); if (out != null) { - out.write("index;signTime;verifyTime;data;pubW;privS;signature;valid\n"); + out.write("index;signTime;verifyTime;data;pubW;privS;signature;nonce;valid\n"); } Command.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR); @@ -719,7 +727,17 @@ public class ECTesterReader { String pub = ByteUtil.bytesToHex(exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false); String priv = ByteUtil.bytesToHex(exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false); String dataString = (cfg.input != null) ? "" : ByteUtil.bytesToHex(data, false); - out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%d\n", done, sign.getDuration() / 1000000, verify.getDuration() / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), verify.successful() ? 1 : 0)); + BigInteger privkey = new BigInteger(1, exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S)); + EC_Curve actualCurve = Command.findCurve(EC_Store.getInstance(), cfg, cfg.bits, keyClass); + String k = ""; + if (actualCurve != null) { + ECParameterSpec params = actualCurve.toSpec(); + BigInteger kValue = ECUtil.recoverSignatureNonce(signature, data, privkey, params, CardUtil.getSigHashAlgo(cfg.ECDSAType)); + if (kValue != null) { + k = ByteUtil.bytesToHex(kValue.toByteArray(), false); + } + } + out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, sign.getDuration() / 1000000, verify.getDuration() / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k,verify.successful() ? 1 : 0)); } ++done; diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index 1b1ec33..a92017e 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -54,23 +54,11 @@ public abstract class Command implements Cloneable { return (Command) super.clone(); } - - /** - * @param keyPair which keyPair/s (local/remote) to set curve domain parameters on - * @param keyLength key length to choose - * @param keyClass key class to choose - * @return a Command to send in order to prepare the curve on the keypairs. - * @throws IOException if curve file cannot be found/opened - */ - public static Command prepareCurve(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException { - + public static EC_Curve findCurve(EC_Store dataStore, ECTesterReader.Config cfg, short keyLength, byte keyClass) throws IOException { if (cfg.customCurve) { - // Set custom curve (one of the SECG curves embedded applet-side) - short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; - return new Command.Set(cardManager, keyPair, EC_Consts.getCurve(keyLength, keyClass), domainParams, null); + byte curveId = EC_Consts.getCurve(keyLength, keyClass); + return dataStore.getObject(EC_Curve.class, "secg", CardUtil.getCurveName(curveId)); } else if (cfg.namedCurve != null) { - // Set a named curve. - // parse cfg.namedCurve -> cat / id | cat | id EC_Curve curve = dataStore.getObject(EC_Curve.class, cfg.namedCurve); if (curve == null) { throw new IOException("Curve could no be found."); @@ -81,34 +69,44 @@ public abstract class Command implements Cloneable { if (curve.getField() != keyClass) { throw new IOException("Curve field mismatch."); } - - byte[] external = curve.flatten(); - if (external == null) { - throw new IOException("Couldn't read named curve data."); - } - return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, curve.getParams(), external); + return curve; } else if (cfg.curveFile != null) { - // Set curve loaded from a file EC_Curve curve = new EC_Curve(null, keyLength, keyClass); FileInputStream in = new FileInputStream(cfg.curveFile); curve.readCSV(in); in.close(); + return curve; + } else { + return null; + } + } - byte[] external = curve.flatten(); - if (external == null) { - throw new IOException("Couldn't read the curve file correctly."); + + /** + * @param keyPair which keyPair/s (local/remote) to set curve domain parameters on + * @param keyLength key length to choose + * @param keyClass key class to choose + * @return a Command to send in order to prepare the curve on the keypairs. + * @throws IOException if curve file cannot be found/opened + */ + public static Command prepareCurve(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException { + if (cfg.customCurve) { + // Set custom curve (one of the SECG curves embedded applet-side) + short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M; + return new Command.Set(cardManager, keyPair, EC_Consts.getCurve(keyLength, keyClass), domainParams, null); + } + + EC_Curve curve = findCurve(dataStore, cfg, keyLength, keyClass); + if ((curve == null || curve.flatten() == null) && (cfg.namedCurve != null || cfg.curveFile != null)) { + if (cfg.namedCurve != null) { + throw new IOException("Couldn't read named curve data."); } - return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, curve.getParams(), external); - } else { - // Set default curve - /* This command was generally causing problems for simulating on jcardsim. - * Since there, .clearKey() resets all the keys values, even the domain. - * This might break some other stuff.. But should not. - */ - //commands.add(new Command.Clear(cardManager, keyPair)); + throw new IOException("Couldn't read the curve file correctly."); + } else if (curve == null) { return null; } + return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()); } @@ -896,8 +894,8 @@ public abstract class Command implements Cloneable { */ public static class SetDryRunMode extends Command { private byte dryRunMode; + /** - * * @param cardManager * @param dryRunMode */ @@ -918,7 +916,7 @@ public abstract class Command implements Cloneable { @Override public String getDescription() { - return (dryRunMode == ECTesterApplet.MODE_NORMAL ? "Disable" : "Enable") + " dry run mode"; + return (dryRunMode == ECTesterApplet.MODE_NORMAL ? "Disable" : "Enable") + " dry run mode"; } } } -- cgit v1.2.3-70-g09d2 From 0b69ee96a04d09ad81b03d67173b49658cfb2b9c Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 2 Dec 2018 20:42:34 +0100 Subject: Add nonce output to standalone ECDSA function. --- src/cz/crcs/ectester/common/util/ECUtil.java | 1 + .../crcs/ectester/standalone/ECTesterStandalone.java | 18 ++++++++++++++---- .../ectester/standalone/consts/SignatureIdent.java | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java index 0260e95..919986b 100644 --- a/src/cz/crcs/ectester/common/util/ECUtil.java +++ b/src/cz/crcs/ectester/common/util/ECUtil.java @@ -254,6 +254,7 @@ public class ECUtil { BigInteger hrd = hashInt.add(rd).mod(params.getOrder()); return s.modInverse(params.getOrder()).multiply(hrd).mod(params.getOrder()); } catch (NoSuchAlgorithmException | IOException nsae) { + nsae.printStackTrace(); return null; } } diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 707f031..e250b10 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -51,6 +51,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; +import java.math.BigInteger; import java.nio.file.Files; import java.security.*; import java.security.interfaces.ECPrivateKey; @@ -415,7 +416,7 @@ public class ECTesterStandalone { data = Files.readAllBytes(in.toPath()); dataString = ""; } else { - SecureRandom random = new SecureRandom(); + Random random = new Random(); data = new byte[32]; random.nextBytes(data); dataString = ByteUtil.bytesToHex(data, false); @@ -455,6 +456,7 @@ public class ECTesterStandalone { } Signature sig = sigIdent.getInstance(lib.getProvider()); KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider()); + ECParameterSpec spec = null; if (cli.hasOption("ecdsa.bits")) { int bits = Integer.parseInt(cli.getOptionValue("ecdsa.bits")); kpg.initialize(bits); @@ -465,7 +467,8 @@ public class ECTesterStandalone { System.err.println("Curve not found: " + curveName); return; } - kpg.initialize(curve.toSpec()); + spec = curve.toSpec(); + kpg.initialize(spec); } else if (cli.hasOption("ecdsa.curve-name")) { String curveName = cli.getOptionValue("ecdsa.curve-name"); kpg.initialize(new ECGenParameterSpec(curveName)); @@ -478,7 +481,7 @@ public class ECTesterStandalone { out = System.out; } - out.println("index;data;signTime[nano];verifyTime[nano];pubW;privS;signature;verified"); + out.println("index;signTime[nano];verifyTime[nano];data;pubW;privS;signature;nonce;verified"); int amount = Integer.parseInt(cli.getOptionValue("ecdsa.amount", "1")); for (int i = 0; i < amount; ++i) { @@ -510,7 +513,14 @@ public class ECTesterStandalone { String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false); String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false); String sign = ByteUtil.bytesToHex(signature, false); - out.println(String.format("%d;%s;%d;%d;%s;%s;%s;%d", i, dataString, signTime, verifyTime, pub, priv, sign, verified ? 1 : 0)); + String k = ""; + if (spec != null) { + BigInteger kValue = ECUtil.recoverSignatureNonce(signature, data, privkey.getS(), spec, sigIdent.getHashAlgo()); + if (kValue != null) { + k = ByteUtil.bytesToHex(kValue.toByteArray(), false); + } + } + out.println(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d", i, signTime, verifyTime, dataString, pub, priv, sign, k, verified ? 1 : 0)); } if (cli.hasOption("ecdsa.output")) { diff --git a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java index e40731b..7f9adb4 100644 --- a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java +++ b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java @@ -104,6 +104,7 @@ public class SignatureIdent extends Ident { int split = alias.indexOf("with"); this.hash = alias.substring(0, split); this.sig = alias.substring(split + 4); + break; } } } -- cgit v1.2.3-70-g09d2 From 5848a64d506231bfa8de73b433a76b1017b4d33e Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 10 Dec 2018 15:34:09 +0100 Subject: Add degenerate tests for curves with cofactor = 4. --- src/cz/crcs/ectester/data/degenerate/cofactor.xml | 122 +++++++++++++++++++++ src/cz/crcs/ectester/data/degenerate/keys.xml | 2 + src/cz/crcs/ectester/reader/ECTesterReader.java | 14 +-- .../ectester/reader/test/CardDegenerateSuite.java | 9 +- 4 files changed, 134 insertions(+), 13 deletions(-) create mode 100644 src/cz/crcs/ectester/data/degenerate/cofactor.xml diff --git a/src/cz/crcs/ectester/data/degenerate/cofactor.xml b/src/cz/crcs/ectester/data/degenerate/cofactor.xml new file mode 100644 index 0000000..2ceaeb5 --- /dev/null +++ b/src/cz/crcs/ectester/data/degenerate/cofactor.xml @@ -0,0 +1,122 @@ + + cofactor128p4/0 + 0x00000000000000000000000000000000,0x94d9020b666fbb599609485472a9246e + cofactor/cofactor128p4 + degenerate order = 2 + + + cofactor128p4/1 + 0x00000000000000000000000000000000,0x2d3a81f8b8d96e6db96a04fb6cf432de + cofactor/cofactor128p4 + degenerate order = 3 + + + cofactor128p4/2 + 0x00000000000000000000000000000000,0x639272497e0865cea0e17677b6bc5575 + cofactor/cofactor128p4 + degenerate order = 7 + + + cofactor128p4/3 + 0x00000000000000000000000000000000,0x072aba3ae7aeb770332600a630e503d1 + cofactor/cofactor128p4 + degenerate order = 5297 + + + cofactor128p4/4 + 0x00000000000000000000000000000000,0x17b45a35afdff5c5150a7c0a7ee34825 + cofactor/cofactor128p4 + degenerate order = 31134053800693 + + + cofactor128p4/5 + 0x00000000000000000000000000000000,0x6fd5d6e491bf5a15eb1d38554caad86c + cofactor/cofactor128p4 + degenerate order = 28564500657606656383 + + + cofactor128p4/gen + 0x00000000000000000000000000000000,0x00000000000000000000000000000005 + cofactor/cofactor128p4 + generator of Fp^* + + + + cofactor160p4/0 + 0x0000000000000000000000000000000000000000,0x93ab454ad26dae3b521d5b61a48c94cab3c4aa9c + cofactor/cofactor160p4 + degenerate order = 2 + + + cofactor160p4/1 + 0x0000000000000000000000000000000000000000,0xbad87d0931716ec918e43e76b57971cc613e153 + cofactor/cofactor160p4 + degenerate order = 4 + + + cofactor160p4/2 + 0x0000000000000000000000000000000000000000,0x4428069aa7ac1865eb52c5b4c885ec832d89b36d + cofactor/cofactor160p4 + degenerate order = 3 + + + cofactor160p4/3 + 0x0000000000000000000000000000000000000000,0x6eb71aefce923ebf8b07c6f1f59b1c30d43b74ae + cofactor/cofactor160p4 + degenerate order = 23 + + + cofactor160p4/4 + 0x0000000000000000000000000000000000000000,0x3c5ff8c94b31b46f92575e0b77b0366afe24dfc1 + cofactor/cofactor160p4 + degenerate order = 11443 + + + cofactor160p4/5 + 0x0000000000000000000000000000000000000000,0xd8e2287382e057de70e1f45f70d8dad85d27025 + cofactor/cofactor160p4 + degenerate order = 352281613501590816479 + + + cofactor160p4/5 + 0x0000000000000000000000000000000000000000,0x36911d265f6d795a2efd10c20aae0f3ec5f815f4 + cofactor/cofactor160p4 + degenerate order = 757721821606925858951 + + + cofactor160p4/gen + 0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000002 + cofactor/cofactor160p4 + generator of Fp^* + + + + cofactor192p4/0 + 0x000000000000000000000000000000000000000000000000,0x8cceb84c81521937bef0925a3aaf09195a59c3f99ae06134 + cofactor/cofactor192p4 + degenerate order = 2 + + + cofactor192p4/1 + 0x000000000000000000000000000000000000000000000000,0x63ca4f21e0e4f6a833f914468e00e4d817f472d54aca5a64 + cofactor/cofactor192p4 + degenerate order = 4 + + + cofactor192p4/2 + 0x000000000000000000000000000000000000000000000000,0x7ce088c401bfc705e70da9928c04ed6e1bf100c26b253028 + cofactor/cofactor192p4 + degenerate order = 5 + + + cofactor192p4/3 + 0x000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000100000 + cofactor/cofactor192p4 + degenerate order = 172629492300688965054638881592440218548130640356589228457 + + + cofactor192p4/gen + 0x000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000002 + cofactor/cofactor192p4 + generator of Fp^* + diff --git a/src/cz/crcs/ectester/data/degenerate/keys.xml b/src/cz/crcs/ectester/data/degenerate/keys.xml index b999ca0..498cf26 100644 --- a/src/cz/crcs/ectester/data/degenerate/keys.xml +++ b/src/cz/crcs/ectester/data/degenerate/keys.xml @@ -2,6 +2,7 @@ + ]> @@ -11,4 +12,5 @@ --> &secg; &brainpool; + &cofactor; \ No newline at end of file diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index fe44709..9f0d8cc 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -42,10 +42,6 @@ import cz.crcs.ectester.reader.test.*; import javacard.framework.ISO7816; import javacard.security.KeyPair; import org.apache.commons.cli.*; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1StreamParser; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERSequenceParser; import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.smartcardio.CardException; @@ -603,8 +599,8 @@ public class ECTesterReader { Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send(); respWriter.outputResponse(export); - byte pubkey_bytes[] = export.getParameter(pubkey, EC_Consts.PARAMETER_W); - byte privkey_bytes[] = export.getParameter(privkey, EC_Consts.PARAMETER_S); + byte[] pubkey_bytes = export.getParameter(pubkey, EC_Consts.PARAMETER_W); + byte[] privkey_bytes = export.getParameter(privkey, EC_Consts.PARAMETER_S); Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType).send(); respWriter.outputResponse(perform); @@ -643,7 +639,7 @@ public class ECTesterReader { */ private void ecdsa() throws CardException, IOException { //read file, if asked to sign - byte[] data = null; + byte[] data; if (cfg.input != null) { File in = new File(cfg.input); long len = in.length(); @@ -700,7 +696,7 @@ public class ECTesterReader { Response.ECDSA sign = new Command.ECDSA_sign(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data).send(); respWriter.outputResponse(sign); - if (!sign.successful() || ! sign.hasSignature()) { + if (!sign.successful() || !sign.hasSignature()) { if (retry < 10) { ++retry; continue; @@ -737,7 +733,7 @@ public class ECTesterReader { k = ByteUtil.bytesToHex(kValue.toByteArray(), false); } } - out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, sign.getDuration() / 1000000, verify.getDuration() / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k,verify.successful() ? 1 : 0)); + out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, sign.getDuration() / 1000000, verify.getDuration() / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k, verify.successful() ? 1 : 0)); } ++done; diff --git a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java index f434d4d..87613fe 100644 --- a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java @@ -40,7 +40,7 @@ public class CardDegenerateSuite extends CardTestSuite { Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS); Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS); - Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId(), allocate, set, generate); + Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate); List ecdhTests = new LinkedList<>(); for (EC_Key.Public pub : keys) { @@ -50,13 +50,14 @@ public class CardDegenerateSuite extends CardTestSuite { Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten()); Test rawEcdh = CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve."); ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " degenerate key test.", objectEcdh, rawEcdh)); + //TODO: actually get the result of ECDH here, as well as export privkey and compare to exponentiation in Fp^*. } - Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with degenerate public points", ecdhTests.toArray(new Test[0])); + Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with degenerate public points.", ecdhTests.toArray(new Test[0])); if (cfg.cleanup) { Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY); - doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId(), prepare, ecdh, cleanup)); + doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId() + ".", prepare, ecdh, cleanup)); } else { - doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId(), prepare, ecdh)); + doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId() + ".", prepare, ecdh)); } } -- cgit v1.2.3-70-g09d2 From 4569f864edeab4e2d309905fd37f87c977cdb2cd Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 10 Dec 2018 15:50:02 +0100 Subject: Add more tests of bit-patterns to edge-cases test sutie. --- src/cz/crcs/ectester/data/misc/results.xml | 4 ++-- .../crcs/ectester/reader/test/CardEdgeCasesSuite.java | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/cz/crcs/ectester/data/misc/results.xml b/src/cz/crcs/ectester/data/misc/results.xml index ba8c83c..07601b1 100644 --- a/src/cz/crcs/ectester/data/misc/results.xml +++ b/src/cz/crcs/ectester/data/misc/results.xml @@ -7,8 +7,8 @@ 0xdb6f7cd6a06846bf9da9b4928caa5e4b7c8f58d9 secg/secp256r1 - other/openssl-bug/pkey - other/openssl-bug/skey + misc/openssl-bug/pkey + misc/openssl-bug/skey https://eprint.iacr.org/2011/633 \ No newline at end of file diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java index ccec401..7695867 100644 --- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java @@ -164,8 +164,21 @@ public class CardEdgeCasesSuite extends CardTestSuite { BigInteger full = BigInteger.valueOf(1).shiftLeft(R.bitLength() - 1).subtract(BigInteger.ONE); + BigInteger alternate = full; + for (int i = 0; i < R.bitLength(); i += 2) { + alternate = alternate.clearBit(i); + } + + BigInteger alternateOther = alternate.xor(full); + + EC_Params alternateParams = makeParams(alternate); + Test alternateS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, alternateParams.getParams(), alternateParams.flatten()), "ECDH with S = 101010101...01010.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); + + EC_Params alternateOtherParams = makeParams(alternateOther); + Test alternateOtherS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, alternateOtherParams.getParams(), alternateOtherParams.flatten()), "ECDH with S = 01010101...10101.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); + EC_Params fullParams = makeParams(full); - Test fullS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, fullParams.getParams(), fullParams.flatten()), "ECDH with S = 2^((log2 r) - 1) - 1.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); + Test fullS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, fullParams.getParams(), fullParams.flatten()), "ECDH with S = 111111...11111 (but < r).", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); EC_Params smallerParams = makeParams(smaller); Test smallerS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, smallerParams.getParams(), smallerParams.flatten()), "ECDH with S < r.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); @@ -202,9 +215,9 @@ public class CardEdgeCasesSuite extends CardTestSuite { if (cfg.cleanup) { Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY); - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, zeroS, oneS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S, cleanup)); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S, cleanup)); } else { - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, zeroS, oneS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S)); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S)); } } -- cgit v1.2.3-70-g09d2 From 72791aa688159f90dacf3aaa59ec5e679197651d Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 10 Dec 2018 16:34:57 +0100 Subject: Add points on twists for additional cofactor = 4 curves. --- src/cz/crcs/ectester/data/degenerate/cofactor.xml | 1 + .../ectester/data/twist/cofactor/cofactor128p4.xml | 44 +++++++++++++ .../ectester/data/twist/cofactor/cofactor160p4.xml | 74 ++++++++++++++++++++++ src/cz/crcs/ectester/data/twist/keys.xml | 6 ++ 4 files changed, 125 insertions(+) create mode 100644 src/cz/crcs/ectester/data/twist/cofactor/cofactor128p4.xml create mode 100644 src/cz/crcs/ectester/data/twist/cofactor/cofactor160p4.xml diff --git a/src/cz/crcs/ectester/data/degenerate/cofactor.xml b/src/cz/crcs/ectester/data/degenerate/cofactor.xml index 2ceaeb5..647515b 100644 --- a/src/cz/crcs/ectester/data/degenerate/cofactor.xml +++ b/src/cz/crcs/ectester/data/degenerate/cofactor.xml @@ -1,3 +1,4 @@ + cofactor128p4/0 0x00000000000000000000000000000000,0x94d9020b666fbb599609485472a9246e diff --git a/src/cz/crcs/ectester/data/twist/cofactor/cofactor128p4.xml b/src/cz/crcs/ectester/data/twist/cofactor/cofactor128p4.xml new file mode 100644 index 0000000..b558f8e --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/cofactor/cofactor128p4.xml @@ -0,0 +1,44 @@ + + + cofactor128p4/0 + 0x72294f8a7c88d510343c19b8251d7dd6,0x00000000000000000000000000000000 + cofactor/cofactor128p4 + twist order = 2 + + + cofactor128p4/1 + 0x5d20662769138fe1506f2a2b44fd34c1,0x15d63a5aba305ccdee9f65e3f2c1d4e8 + cofactor/cofactor128p4 + twist order = 4 + + + cofactor128p4/2 + 0x0b843b9da795292bfc598bae47fd0955,0x2944056236d430e404f6fd058a7a6624 + cofactor/cofactor128p4 + twist order = 17 + + + cofactor128p4/3 + 0x663a7a5a7370a48f98ef5ba0cc2d19a1,0x13d59851b95e3916e1149b1f8345325d + cofactor/cofactor128p4 + twist order = 37 + + + cofactor128p4/4 + 0x415d46d2beb2357a567efeedd3e052a0,0x8b202b706af555d470fb42fb5919a64 + cofactor/cofactor128p4 + twist order = 24422261 + + + cofactor128p4/5 + 0x6707ea110f83e67a9f6a43c184587bc6,0x1c44db735c6b30165e40660ecc5d8c3c + cofactor/cofactor128p4 + twist order = 87024861802858114445834597 + + + cofactor128p4/gen + 0x5a1c6fd7a138377f22dabe0840a02ede,0x39395b4be5f4c131a0a5f778be1166e5 + cofactor/cofactor128p4 + twist generator + + diff --git a/src/cz/crcs/ectester/data/twist/cofactor/cofactor160p4.xml b/src/cz/crcs/ectester/data/twist/cofactor/cofactor160p4.xml new file mode 100644 index 0000000..bb712af --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/cofactor/cofactor160p4.xml @@ -0,0 +1,74 @@ + + + cofactor160p4/0 + 0x0c43497bdc7c1fddd18368da4894a98a612f09ec,0x0000000000000000000000000000000000000000 + cofactor/cofactor160p4 + twist order = 2 + + + cofactor160p4/1 + 0x526ba726c52a6c998994733747dc27db793ce64b,0x3f432767051371f91355e6a14488883bc51c881e + cofactor/cofactor160p4 + twist order = 4 + + + cofactor160p4/2 + 0x380cd2b93ff179b2411c721879d7fbed95ef1d68,0x7b36aafe70fa88d2522931555d91e072a89eaff0 + cofactor/cofactor160p4 + twist order = 8 + + + cofactor160p4/3 + 0x640d26a5aa07b529bf39bb4d4ad79346f677e2e9,0x22c90f648dfd349f8ac76c4aa0e4fd7278bc4516 + cofactor/cofactor160p4 + twist order = 16 + + + cofactor160p4/4 + 0x8dab044b1a87809667b940b43d913b00fa194c8,0x20652c81133c9e51a16d0ecbcd6f81111afc03c3 + cofactor/cofactor160p4 + twist order = 3 + + + cofactor160p4/5 + 0x66e27b0bfaf5269dbca67fa71ea3a117f29f4ef9,0x2b9499a775ae8f7fba1884b3d852429757312c93 + cofactor/cofactor160p4 + twist order = 13 + + + cofactor160p4/6 + 0x4758716ac3b6cfb971ea0a673c4eebbad085fbd8,0x6ab9c8044435062299d14bdb6d6a41faf0bb0067 + cofactor/cofactor160p4 + twist order = 169 + + + cofactor160p4/7 + 0x76690f13f9fdec12b156a40f5a7c0f25b420e7e0,0x8cab0d69936dcb3b64007f2fd2881f18f627ade5 + cofactor/cofactor160p4 + twist order = 107 + + + cofactor160p4/8 + 0x178c6e5bb98247299631a52d32a55e61711a21fb,0x6e9171b2aab5bbbe488d9c3c367cf0536bf19e1a + cofactor/cofactor160p4 + twist order = 15259 + + + cofactor160p4/9 + 0x08e82adfcb0ff539bf58e4f232f4721f3a014904,0x7ba4d134fa420dbf7fdff4986361d625e87ca27d + cofactor/cofactor160p4 + twist order = 322336986893916431 + + + cofactor160p4/10 + 0x1d6ee4ac5b0da602078684f14bab3510915f7fef,0x229903e44fe1dd7e4ef1d3dd4edc0ed05c712bef + cofactor/cofactor160p4 + twist order = 197469859348064237101 + + + cofactor160p4/gen + 0x5603c1fd03c11eb2ab5f7abb998658a791a71202,0x3151be9d7f447756c8e85f5ac82c1ee410727157 + cofactor/cofactor160p4 + twist generator + + diff --git a/src/cz/crcs/ectester/data/twist/keys.xml b/src/cz/crcs/ectester/data/twist/keys.xml index df208bf..3292004 100644 --- a/src/cz/crcs/ectester/data/twist/keys.xml +++ b/src/cz/crcs/ectester/data/twist/keys.xml @@ -21,6 +21,9 @@ + + + ]> @@ -45,4 +48,7 @@ &secp256r1; &secp384r1; &secp521r1; + + &cofactor128p4; + &cofactor160p4; \ No newline at end of file -- cgit v1.2.3-70-g09d2 From f1b891db1bced0881c2ed4926fa0ff516a647bd0 Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 10 Dec 2018 16:54:08 +0100 Subject: Cleaner evaluation of twist/degenerate tests. --- .../crcs/ectester/reader/test/CardDegenerateSuite.java | 8 ++++++-- src/cz/crcs/ectester/reader/test/CardInvalidSuite.java | 14 +++++++++----- src/cz/crcs/ectester/reader/test/CardTwistSuite.java | 16 ++++++++++------ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java index 87613fe..755c746 100644 --- a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java @@ -36,7 +36,11 @@ public class CardDegenerateSuite extends CardTestSuite { EC_Curve curve = e.getKey(); List keys = e.getValue(); - Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS); + Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS)); + if (!allocate.ok()) { + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate)); + continue; + } Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS); Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS); @@ -45,7 +49,7 @@ public class CardDegenerateSuite extends CardTestSuite { List ecdhTests = new LinkedList<>(); for (EC_Key.Public pub : keys) { Test setPub = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE); - Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE); + Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve."); Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with degenerate pubkey.", setPub, ecdh); Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten()); Test rawEcdh = CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve."); diff --git a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java index 3b9e0e5..9c4b54c 100644 --- a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java @@ -40,11 +40,15 @@ public class CardInvalidSuite extends CardTestSuite { EC_Curve curve = e.getKey(); List keys = e.getValue(); - Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS); + Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + if (!allocate.ok()) { + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate)); + continue; + } Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS); Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS); - Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId(), allocate, set, generate); + Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate); List ecdhTests = new LinkedList<>(); for (EC_Key.Public pub : keys) { @@ -55,13 +59,13 @@ public class CardInvalidSuite extends CardTestSuite { Test rawEcdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve.", "Card incorrectly accepted point on invalid curve."); ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " invalid key test.", objectEcdh, rawEcdh)); } - Test ecdh = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH with invalid public points", ecdhTests.toArray(new Test[0])); + Test ecdh = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH with invalid public points.", ecdhTests.toArray(new Test[0])); if (cfg.cleanup) { Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY); - doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), prepare, ecdh, cleanup)); + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId() + ".", prepare, ecdh, cleanup)); } else { - doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), prepare, ecdh)); + doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId() + ".", prepare, ecdh)); } } } diff --git a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java index 3df4c65..4929d52 100644 --- a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java @@ -34,29 +34,33 @@ public class CardTwistSuite extends CardTestSuite { EC_Curve curve = e.getKey(); List keys = e.getValue(); - Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS); + Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS)); + if (!allocate.ok()) { + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate)); + continue; + } Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS); Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS); - Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId(), allocate, set, generate); + Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate); List ecdhTests = new LinkedList<>(); for (EC_Key.Public pub : keys) { Test setPub = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE); - Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE); + Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE, "Card correctly rejected point on twist.", "Card incorrectly accepted point on twist."); Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with twist pubkey.", setPub, ecdh); Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten()); Test rawEcdh = CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on twist.", "Card incorrectly accepted point on twist."); ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " twist key test.", objectEcdh, rawEcdh)); } - Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with public points on twist", ecdhTests.toArray(new Test[0])); + Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with public points on twist.", ecdhTests.toArray(new Test[0])); Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", ecdh); if (cfg.cleanup) { Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY); - doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), prepare, tests, cleanup)); + doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId() + ".", prepare, tests, cleanup)); } else { - doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), prepare, tests)); + doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId() + ".", prepare, tests)); } } } -- cgit v1.2.3-70-g09d2 From bb5de2b3b731f7b022be9703fc2f5eae99893ac1 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 16 Dec 2018 01:42:40 +0100 Subject: Add test of ECDH when keypair has engated pubkey. --- docs/IMPLEMENTATIONS.md | 18 ++++++------- .../ectester/common/output/BaseTextTestWriter.java | 6 ++--- .../ectester/reader/test/CardEdgeCasesSuite.java | 30 +++++++++++++++++----- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/docs/IMPLEMENTATIONS.md b/docs/IMPLEMENTATIONS.md index 724150f..d333ed5 100644 --- a/docs/IMPLEMENTATIONS.md +++ b/docs/IMPLEMENTATIONS.md @@ -249,7 +249,7 @@ Uses binary addition chain. INPUT: k = (k_{t-1}, ..., k_1, k_0)_2, P ∈ E(F_q). OUTPUT: [k]P. 1. Q ← ∞. - 2. For i from t - 1 downto 0 do + 2. For i from 0 to t-1 do 2.1 If k_i = 1 then Q ← Q + P. 2.2 P ← 2P. 3. Return(Q). @@ -432,7 +432,7 @@ The same name, Montgomery ladder, is used both for the general ladder idea of ex INPUT: k = (k_{t-1}, ..., k_1, k_0)_2, P ∈ E(F_q). OUTPUT: [k]P . 1. P_1 ← P and P_2 ← [2]P - 2. For i = t − 2 downto 0 do + 2. For i = t − 1 downto 0 do 2.1 If k_i = 0 then P_1 ← [2]P_1; P_2 ← P_1 + P_2. Else @@ -443,13 +443,13 @@ The same name, Montgomery ladder, is used both for the general ladder idea of ex INPUT: G ∈ E(F_q), k = (1, k_{t−2}, ..., k_0)2 OUTPUT: Y = kG - R0 ← G; R1 ← [2]G - for j = t − 2 downto 0 do - if (k_j = 0) then - R1 ← R0 + R1; R0 ← [2]R0 - else [if (kj = 1)] - R0 ← R0 + R1; R1 ← [2]R1 - return R0 + 1. R0 ← G; R1 ← [2]G + 2. for j = t − 2 downto 0 do + 2.1 if (k_j = 0) then + R1 ← R0 + R1; R0 ← [2]R0 + else [if (kj = 1)] + R0 ← R0 + R1; R1 ← [2]R1 + 3. return R0 Montgomery addition formulas (Projective coordinates/XZ coordinates):[^2] diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java index 85b32a4..8ad50c7 100644 --- a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java @@ -56,7 +56,7 @@ public abstract class BaseTextTestWriter implements TestWriter { String line = ""; if (prefix.equals("")) { - char charLine[] = new char[BASE_WIDTH + 24]; + char[] charLine = new char[BASE_WIDTH + 24]; new String(new char[BASE_WIDTH + 24]).replace("\0", "━").getChars(0, charLine.length - 1, charLine, 0); charLine[0] = '■'; charLine[4] = '┳'; @@ -70,7 +70,7 @@ public abstract class BaseTextTestWriter implements TestWriter { out.append(t.ok() ? Colors.ok(" OK ") : Colors.error("NOK ")); out.append(compound ? (prefix.equals("") ? "╋ " : "┳ ") : "━ "); int width = BASE_WIDTH - (prefix.length() + 6); - String widthSpec = "%-" + String.valueOf(width) + "s"; + String widthSpec = "%-" + width + "s"; String desc = ((prefix.equals("")) ? "(" + index + ") " : "") + t.getDescription(); out.append(String.format(widthSpec, desc)); out.append(" ┃ "); @@ -87,7 +87,7 @@ public abstract class BaseTextTestWriter implements TestWriter { if (compound) { CompoundTest test = (CompoundTest) t; - out.append(String.valueOf(result.getCause())); + out.append(result.getCause()); out.append(System.lineSeparator()); Test[] tests = test.getStartedTests(); for (int i = 0; i < tests.length; ++i) { diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java index 7695867..221cbe1 100644 --- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java @@ -150,7 +150,21 @@ public class CardEdgeCasesSuite extends CardTestSuite { } Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS); Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS); - Test setup = CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate); + CommandTest export = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W), Result.ExpectedValue.SUCCESS); + Test setup = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate, export)); + + byte[] pParam = curve.getParam(EC_Consts.PARAMETER_FP)[0]; + BigInteger p = new BigInteger(1, pParam); + byte[] wParam = ((Response.Export) export.getResponse()).getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W); + byte[] yValue = new byte[(wParam.length - 1) / 2]; + System.arraycopy(wParam, (wParam.length/2) + 1, yValue, 0, yValue.length); + BigInteger y = new BigInteger(1, yValue); + BigInteger negY = p.subtract(y); + byte[] newY = ECUtil.toByteArray(negY, curve.getBits()); + System.arraycopy(newY, 0, wParam, (wParam.length/2) + 1, newY.length); + + EC_Params negYParams = makeParams(newY); + Test negYTest = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, negYParams.getParams(), negYParams.flatten()), "ECDH with pubkey negated.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE); Test zeroS = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, EC_Consts.TRANSFORMATION_ZERO), "ECDH with S = 0.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE); Test oneS = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, EC_Consts.TRANSFORMATION_ONE), "ECDH with S = 1.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE); @@ -175,10 +189,10 @@ public class CardEdgeCasesSuite extends CardTestSuite { Test alternateS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, alternateParams.getParams(), alternateParams.flatten()), "ECDH with S = 101010101...01010.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); EC_Params alternateOtherParams = makeParams(alternateOther); - Test alternateOtherS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, alternateOtherParams.getParams(), alternateOtherParams.flatten()), "ECDH with S = 01010101...10101.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); + Test alternateOtherS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, alternateOtherParams.getParams(), alternateOtherParams.flatten()), "ECDH with S = 010101010...10101.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); EC_Params fullParams = makeParams(full); - Test fullS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, fullParams.getParams(), fullParams.flatten()), "ECDH with S = 111111...11111 (but < r).", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); + Test fullS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, fullParams.getParams(), fullParams.flatten()), "ECDH with S = 111111111...11111 (but < r).", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); EC_Params smallerParams = makeParams(smaller); Test smallerS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, smallerParams.getParams(), smallerParams.flatten()), "ECDH with S < r.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); @@ -204,20 +218,22 @@ public class CardEdgeCasesSuite extends CardTestSuite { BigInteger krm1 = kr.subtract(BigInteger.ONE); BigInteger krp1 = kr.add(BigInteger.ONE); + Result.ExpectedValue kExpected = K.equals(BigInteger.ONE) ? Result.ExpectedValue.SUCCESS : Result.ExpectedValue.FAILURE; + EC_Params krParams = makeParams(kr); Test krS /*ONE!*/ = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krParams.getParams(), krParams.flatten()), "ECDH with S = k * r.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE); EC_Params krm1Params = makeParams(krm1); - Test krm1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krm1Params.getParams(), krm1Params.flatten()), "ECDH with S = (k * r) - 1.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE); + Test krm1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krm1Params.getParams(), krm1Params.flatten()), "ECDH with S = (k * r) - 1.", kExpected, kExpected); EC_Params krp1Params = makeParams(krp1); - Test krp1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krp1Params.getParams(), krp1Params.flatten()), "ECDH with S = (k * r) + 1.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE); + Test krp1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krp1Params.getParams(), krp1Params.flatten()), "ECDH with S = (k * r) + 1.", Result.ExpectedValue.ANY, Result.ExpectedValue.ANY); if (cfg.cleanup) { Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY); - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S, cleanup)); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, negYTest, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S, cleanup)); } else { - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S)); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, negYTest, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S)); } } -- cgit v1.2.3-70-g09d2 From 9577bff6eca3b713c9c29b2f0cff2f13368df527 Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 17 Dec 2018 10:53:59 +0100 Subject: Allow fixed key in ECDH. --- src/cz/crcs/ectester/reader/ECTesterReader.java | 68 +++++++++++++++++-------- util/plot_gen.py | 2 +- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 9f0d8cc..382f2e1 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -332,7 +332,9 @@ public class ECTesterReader { opts.addOption(Option.builder("v").longOpt("verbose").desc("Turn on verbose logging.").build()); opts.addOption(Option.builder().longOpt("format").desc("Output format to use. One of: text,yml,xml.").hasArg().argName("format").build()); - opts.addOption(Option.builder().longOpt("static").desc("Generate key(s) only once, keep them for later operations.").build()); + opts.addOption(Option.builder().longOpt("fixed").desc("Generate key(s) only once, keep them for later operations.").build()); + opts.addOption(Option.builder().longOpt("fixed-private").desc("Generate private key only once, keep it for later ECDH.").build()); + opts.addOption(Option.builder().longOpt("fixed-public").desc("Generate public key only once, keep it for later ECDH.").build()); opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build()); opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations.").build()); opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build()); @@ -574,35 +576,53 @@ public class ECTesterReader { respWriter.outputResponse(r); } - byte pubkey = (cfg.anyPublicKey || cfg.anyKey) ? ECTesterApplet.KEYPAIR_REMOTE : ECTesterApplet.KEYPAIR_LOCAL; - byte privkey = (cfg.anyPrivateKey || cfg.anyKey) ? ECTesterApplet.KEYPAIR_REMOTE : ECTesterApplet.KEYPAIR_LOCAL; - - List generate = new LinkedList<>(); - generate.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH)); - if (cfg.anyPublicKey || cfg.anyPrivateKey || cfg.anyKey) { - generate.add(Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_REMOTE)); - } - OutputStreamWriter out = null; if (cfg.outputs != null) { out = FileUtil.openFiles(cfg.outputs); - out.write("index;time;pubW;privS;secret\n"); + out.write("index;time[milli];pubW;privS;secret\n"); + } + + Response gen = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH).send(); + respWriter.outputResponse(gen); + if (cfg.anyPublicKey || cfg.anyKey) { + Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_REMOTE).send(); + respWriter.outputResponse(prep); + } + if (cfg.anyPrivateKey || cfg.anyKey) { + Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL).send(); + respWriter.outputResponse(prep); + } + + byte kp = ECTesterApplet.KEYPAIR_BOTH; + if (cfg.fixedPrivate || cfg.anyPrivateKey) { + kp ^= ECTesterApplet.KEYPAIR_LOCAL; + } + if (cfg.fixedPublic || cfg.anyPublicKey) { + kp ^= ECTesterApplet.KEYPAIR_REMOTE; + } + if (cfg.fixedKey || cfg.anyKey) { + kp = 0; + } + + Command generate = null; + if (kp != 0) { + generate = new Command.Generate(cardManager, kp); } int retry = 0; int done = 0; while (done < cfg.ECKACount) { - List ecdh = Command.sendAll(generate); - for (Response r : ecdh) { - respWriter.outputResponse(r); + if (generate != null) { + Response regen = generate.send(); + respWriter.outputResponse(regen); } Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send(); respWriter.outputResponse(export); - byte[] pubkey_bytes = export.getParameter(pubkey, EC_Consts.PARAMETER_W); - byte[] privkey_bytes = export.getParameter(privkey, EC_Consts.PARAMETER_S); + byte[] pubkey_bytes = export.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W); + byte[] privkey_bytes = export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S); - Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType).send(); + Response.ECDH perform = new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType).send(); respWriter.outputResponse(perform); if (!perform.successful() || !perform.hasSecret()) { @@ -674,12 +694,12 @@ public class ECTesterReader { OutputStreamWriter out = FileUtil.openFiles(cfg.outputs); if (out != null) { - out.write("index;signTime;verifyTime;data;pubW;privS;signature;nonce;valid\n"); + out.write("index;signTime[milli];verifyTime[milli];data;pubW;privS;signature;nonce;valid\n"); } Command.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR); Response.Export exported = null; - if (cfg.staticKey) { + if (cfg.fixedKey) { respWriter.outputResponse(generate.send()); exported = export.send(); respWriter.outputResponse(exported); @@ -688,7 +708,7 @@ public class ECTesterReader { int retry = 0; int done = 0; while (done < cfg.ECDSACount) { - if (!cfg.staticKey) { + if (!cfg.fixedKey) { respWriter.outputResponse(generate.send()); exported = export.send(); respWriter.outputResponse(exported); @@ -777,7 +797,9 @@ public class ECTesterReader { public String key; public boolean anyKeypart = false; - public boolean staticKey = false; + public boolean fixedKey = false; + public boolean fixedPrivate = false; + public boolean fixedPublic = false; public String log; @@ -831,7 +853,9 @@ public class ECTesterReader { key = cli.getOptionValue("key"); anyKey = (key != null) || (namedKey != null); anyKeypart = anyKey || anyPublicKey || anyPrivateKey; - staticKey = cli.hasOption("static"); + fixedKey = cli.hasOption("fixed"); + fixedPrivate = cli.hasOption("fixed-private"); + fixedPublic = cli.hasOption("fixed-public"); if (cli.hasOption("log")) { log = cli.getOptionValue("log", String.format("ECTESTER_log_%d.log", System.currentTimeMillis() / 1000)); diff --git a/util/plot_gen.py b/util/plot_gen.py index b562404..4ee1ddc 100755 --- a/util/plot_gen.py +++ b/util/plot_gen.py @@ -18,7 +18,7 @@ from matplotlib import ticker, colors from copy import deepcopy import argparse -from utils import hw, moving_average, plot_hist, jackknife_entropy, miller_correction +from utils import hw, moving_average, plot_hist, miller_correction if __name__ == "__main__": parser = argparse.ArgumentParser(description="Plot results of ECTester key generation timing.") -- cgit v1.2.3-70-g09d2 From 0033299b5da2751e73a2595f6d875864f79f94fe Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 17 Dec 2018 11:48:12 +0100 Subject: Add named key opts to standalone. --- src/cz/crcs/ectester/common/util/ECUtil.java | 9 +++ .../ectester/standalone/ECTesterStandalone.java | 73 ++++++++++++++++++---- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java index 919986b..e29bfdd 100644 --- a/src/cz/crcs/ectester/common/util/ECUtil.java +++ b/src/cz/crcs/ectester/common/util/ECUtil.java @@ -201,6 +201,9 @@ public class ECUtil { } public static ECPublicKey toPublicKey(EC_Key.Public pubkey) { + if (pubkey == null) { + return null; + } EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, pubkey.getCurve()); if (curve == null) { throw new IllegalArgumentException("pubkey curve not found: " + pubkey.getCurve()); @@ -209,6 +212,9 @@ public class ECUtil { } public static ECPrivateKey toPrivateKey(EC_Key.Private privkey) { + if (privkey == null) { + return null; + } EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, privkey.getCurve()); if (curve == null) { throw new IllegalArgumentException("privkey curve not found: " + privkey.getCurve()); @@ -217,6 +223,9 @@ public class ECUtil { } public static KeyPair toKeyPair(EC_Keypair kp) { + if (kp == null) { + return null; + } EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, kp.getCurve()); if (curve == null) { throw new IllegalArgumentException("keypair curve not found: " + kp.getCurve()); diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index e250b10..8b60602 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -24,6 +24,8 @@ package cz.crcs.ectester.standalone; import cz.crcs.ectester.common.cli.*; import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Key; +import cz.crcs.ectester.common.ec.EC_Keypair; import cz.crcs.ectester.common.output.TestWriter; import cz.crcs.ectester.common.test.TestException; import cz.crcs.ectester.common.util.ByteUtil; @@ -151,6 +153,8 @@ public class ECTesterStandalone { Map actions = new TreeMap<>(); Option namedCurve = Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: ").hasArg().argName("cat/id").optionalArg(false).build(); + Option namedPublic = Option.builder("npub").longOpt("named-public").desc("Use a named public key, from CurveDB: ").hasArg().argName("cat/id").optionalArg(false).build(); + Option namedPrivate = Option.builder("npriv").longOpt("named-private").desc("Use a named private key, from CurveDB: ").hasArg().argName("cat/id").optionalArg(false).build(); Option curveName = Option.builder("cn").longOpt("curve-name").desc("Use a named curve, search from curves supported by the library: ").hasArg().argName("name").optionalArg(false).build(); Option bits = Option.builder("b").longOpt("bits").hasArg().argName("n").optionalArg(false).desc("What size of curve to use.").build(); Option output = Option.builder("o").longOpt("output").desc("Output into file .").hasArgs().argName("output_file").optionalArg(false).build(); @@ -177,7 +181,9 @@ public class ECTesterStandalone { ecdhOpts.addOption(Option.builder("t").longOpt("type").desc("Set KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build()); ecdhOpts.addOption(Option.builder().longOpt("key-type").desc("Set the key [algorithm] for which the key should be derived in KeyAgreements with KDF. Default is \"AES\".").hasArg().argName("algorithm").optionalArg(false).build()); ecdhOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDH [amount] times.").build()); + ecdhOpts.addOption(namedPrivate); ecdhOpts.addOption(Option.builder().longOpt("fixed-private").desc("Perform ECDH with fixed private key.").build()); + ecdhOpts.addOption(namedPublic); ecdhOpts.addOption(Option.builder().longOpt("fixed-public").desc("Perform ECDH with fixed public key.").build()); ParserOptions ecdh = new ParserOptions(new DefaultParser(), ecdhOpts, "Perform EC based KeyAgreement."); actions.put("ecdh", ecdh); @@ -186,7 +192,9 @@ public class ECTesterStandalone { ecdsaOpts.addOption(bits); ecdsaOpts.addOption(namedCurve); ecdsaOpts.addOption(curveName); - ecdhOpts.addOption(output); + ecdsaOpts.addOption(output); + ecdsaOpts.addOption(namedPrivate); + ecdsaOpts.addOption(namedPublic); ecdsaOpts.addOption(Option.builder("t").longOpt("type").desc("Set Signature object [type].").hasArg().argName("type").optionalArg(false).build()); ecdsaOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDSA [amount] times.").build()); ecdsaOpts.addOption(Option.builder("f").longOpt("file").hasArg().argName("file").optionalArg(false).desc("Input [file] to sign.").build()); @@ -197,7 +205,7 @@ public class ECTesterStandalone { generateOpts.addOption(bits); generateOpts.addOption(namedCurve); generateOpts.addOption(curveName); - ecdhOpts.addOption(output); + generateOpts.addOption(output); generateOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Generate [amount] of EC keys.").build()); generateOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPairGenerator object [type].").build()); ParserOptions generate = new ParserOptions(new DefaultParser(), generateOpts, "Generate EC keypairs."); @@ -205,7 +213,7 @@ public class ECTesterStandalone { Options exportOpts = new Options(); exportOpts.addOption(bits); - ecdhOpts.addOption(output); + exportOpts.addOption(output); exportOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPair object [type].").build()); ParserOptions export = new ParserOptions(new DefaultParser(), exportOpts, "Export default curve parameters."); actions.put("export", export); @@ -346,25 +354,45 @@ public class ECTesterStandalone { out.println("index;time[nano];pubW;privS;secret"); KeyPair one = null; - if (cli.hasOption("ecdh.fixed-private")) { + if (cli.hasOption("ecdh.fixed-private") && !cli.hasOption("ecdh.named-private")) { one = kpg.genKeyPair(); } KeyPair other = null; - if (cli.hasOption("ecdh.fixed-public")) { + if (cli.hasOption("ecdh.fixed-public") && !cli.hasOption("ecdh.named-public")) { other = kpg.genKeyPair(); } + ECPrivateKey privkey = null; + if (cli.hasOption("ecdh.named-private")) { + privkey = ECUtil.toPrivateKey(EC_Store.getInstance().getObject(EC_Key.Private.class, cli.getOptionValue("ecdh.named-private"))); + if (privkey == null) { + privkey = (ECPrivateKey) ECUtil.toKeyPair(EC_Store.getInstance().getObject(EC_Keypair.class, cli.getOptionValue("ecdh.named-private"))).getPrivate(); + } + } + ECPublicKey pubkey = null; + if (cli.hasOption("ecdh.named-public")) { + pubkey = ECUtil.toPublicKey(EC_Store.getInstance().getObject(EC_Key.Public.class, cli.getOptionValue("ecdh.named-public"))); + if (pubkey == null) { + pubkey = (ECPublicKey) ECUtil.toKeyPair(EC_Store.getInstance().getObject(EC_Keypair.class, cli.getOptionValue("ecdh.named-public"))).getPublic(); + } + } + int amount = Integer.parseInt(cli.getOptionValue("ecdh.amount", "1")); for (int i = 0; i < amount; ++i) { - if (!cli.hasOption("ecdh.fixed-private")) { + if (!cli.hasOption("ecdh.fixed-private") && !cli.hasOption("ecdh.named-private")) { one = kpg.genKeyPair(); } - if (!cli.hasOption("ecdh.fixed-public")) { + if (!cli.hasOption("ecdh.fixed-public") && !cli.hasOption("ecdh.named-public")) { other = kpg.genKeyPair(); } - ECPrivateKey privkey = (ECPrivateKey) one.getPrivate(); - ECPublicKey pubkey = (ECPublicKey) other.getPublic(); + if (!cli.hasOption("ecdh.named-private")) { + privkey = (ECPrivateKey) one.getPrivate(); + } + + if (!cli.hasOption("ecdh.named-public")) { + pubkey = (ECPublicKey) other.getPublic(); + } long elapsed = -System.nanoTime(); if (spec instanceof ECParameterSpec) { @@ -483,12 +511,33 @@ public class ECTesterStandalone { out.println("index;signTime[nano];verifyTime[nano];data;pubW;privS;signature;nonce;verified"); + ECPrivateKey privkey = null; + if (cli.hasOption("ecdsa.named-private")) { + privkey = ECUtil.toPrivateKey(EC_Store.getInstance().getObject(EC_Key.Private.class, cli.getOptionValue("ecdsa.named-private"))); + if (privkey == null) { + privkey = (ECPrivateKey) ECUtil.toKeyPair(EC_Store.getInstance().getObject(EC_Keypair.class, cli.getOptionValue("ecdsa.named-private"))).getPrivate(); + } + } + ECPublicKey pubkey = null; + if (cli.hasOption("ecdsa.named-public")) { + pubkey = ECUtil.toPublicKey(EC_Store.getInstance().getObject(EC_Key.Public.class, cli.getOptionValue("ecdsa.named-public"))); + if (pubkey == null) { + pubkey = (ECPublicKey) ECUtil.toKeyPair(EC_Store.getInstance().getObject(EC_Keypair.class, cli.getOptionValue("ecdsa.named-public"))).getPublic(); + } + } + int amount = Integer.parseInt(cli.getOptionValue("ecdsa.amount", "1")); for (int i = 0; i < amount; ++i) { - KeyPair one = kpg.genKeyPair(); + if (!cli.hasOption("ecdsa.named-private") || !cli.hasOption("ecdsa.named-public")) { + KeyPair one = kpg.genKeyPair(); - ECPrivateKey privkey = (ECPrivateKey) one.getPrivate(); - ECPublicKey pubkey = (ECPublicKey) one.getPublic(); + if (!cli.hasOption("ecdsa.named-private")) { + privkey = (ECPrivateKey) one.getPrivate(); + } + if (!cli.hasOption("ecdsa.named-public")) { + pubkey = (ECPublicKey) one.getPublic(); + } + } sig.initSign(privkey); sig.update(data); -- cgit v1.2.3-70-g09d2 From 41fc9f173c86531c2060a72dc8cdc26e5db1b1f1 Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 17 Dec 2018 13:31:50 +0100 Subject: Fix applet switch fall-through and standalone ECDH on BouncyCastle. --- src/cz/crcs/ectester/applet/AppletBase.java | 1 + src/cz/crcs/ectester/standalone/ECTesterStandalone.java | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cz/crcs/ectester/applet/AppletBase.java b/src/cz/crcs/ectester/applet/AppletBase.java index 154b209..c77294e 100644 --- a/src/cz/crcs/ectester/applet/AppletBase.java +++ b/src/cz/crcs/ectester/applet/AppletBase.java @@ -164,6 +164,7 @@ public abstract class AppletBase extends Applet { break; case INS_SET_DRY_RUN_MODE: length = insSetDryRunMode(apdu); + break; default: // The INS code is not supported by the dispatcher ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 8b60602..f3fe840 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -143,7 +143,6 @@ public class ECTesterStandalone { System.err.println("Invalid algorithm parameter: " + e.getMessage()); } catch (NoSuchAlgorithmException nsaex) { System.err.println("Algorithm not supported by the selected library: " + nsaex.getMessage()); - nsaex.printStackTrace(); } catch (InvalidKeyException | SignatureException e) { e.printStackTrace(); } @@ -395,7 +394,7 @@ public class ECTesterStandalone { } long elapsed = -System.nanoTime(); - if (spec instanceof ECParameterSpec) { + if (spec instanceof ECParameterSpec && lib instanceof NativeECLibrary) { ka.init(privkey, spec); } else { ka.init(privkey); -- cgit v1.2.3-70-g09d2 From 07a3d6ff46765fec03fe88e7bebbd0ea204d11b4 Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 17 Dec 2018 14:12:26 +0100 Subject: Use dry-run mode of applet for all commands. --- src/cz/crcs/ectester/reader/ECTesterReader.java | 56 +++++++++++++++++----- src/cz/crcs/ectester/reader/command/Command.java | 16 ++++++- .../crcs/ectester/reader/test/PerformanceTest.java | 6 ++- 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 382f2e1..6e1d508 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -336,6 +336,7 @@ public class ECTesterReader { opts.addOption(Option.builder().longOpt("fixed-private").desc("Generate private key only once, keep it for later ECDH.").build()); opts.addOption(Option.builder().longOpt("fixed-public").desc("Generate public key only once, keep it for later ECDH.").build()); opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build()); + opts.addOption(Option.builder().longOpt("time").desc("Output better timing values, by running command in dry run mode and normal mode, and subtracting the two.").build()); opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations.").build()); opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build()); opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build()); @@ -454,7 +455,12 @@ public class ECTesterReader { } Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL); + long time = 0; + if (cfg.time) { + time = -Command.dryRunTime(cardManager, generate, 2, respWriter); + } Response.Generate response = generate.send(); + time += response.getDuration(); respWriter.outputResponse(response); Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send(); @@ -472,7 +478,7 @@ public class ECTesterReader { String pub = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false); String priv = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false); - String line = String.format("%d;%d;%d;%s;%s\n", generated, response.getDuration() / 1000000, export.getDuration() / 1000000, pub, priv); + String line = String.format("%d;%d;%d;%s;%s\n", generated, time / 1000000, export.getDuration() / 1000000, pub, priv); keysFile.write(line); keysFile.flush(); generated++; @@ -622,10 +628,17 @@ public class ECTesterReader { byte[] pubkey_bytes = export.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W); byte[] privkey_bytes = export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S); - Response.ECDH perform = new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType).send(); - respWriter.outputResponse(perform); + Command.ECDH perform = new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType); + + long time = 0; + if (cfg.time) { + time = -Command.dryRunTime(cardManager, perform, 2, respWriter); + } + + Response.ECDH result = perform.send(); + respWriter.outputResponse(result); - if (!perform.successful() || !perform.hasSecret()) { + if (!result.successful() || !result.hasSecret()) { if (retry < 10) { ++retry; continue; @@ -636,8 +649,9 @@ public class ECTesterReader { } if (out != null) { + time += result.getDuration(); - out.write(String.format("%d;%d;%s;%s;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(perform.getSecret(), false))); + out.write(String.format("%d;%d;%s;%s;%s\n", done, time / 1000000, ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(result.getSecret(), false))); } ++done; @@ -714,9 +728,17 @@ public class ECTesterReader { respWriter.outputResponse(exported); } - Response.ECDSA sign = new Command.ECDSA_sign(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data).send(); - respWriter.outputResponse(sign); - if (!sign.successful() || !sign.hasSignature()) { + Command.ECDSA_sign sign = new Command.ECDSA_sign(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data); + + long signTime = 0; + if (cfg.time) { + signTime = -Command.dryRunTime(cardManager, sign, 2, respWriter); + } + + Response.ECDSA signResp = sign.send(); + signTime += signResp.getDuration(); + respWriter.outputResponse(signResp); + if (!signResp.successful() || !signResp.hasSignature()) { if (retry < 10) { ++retry; continue; @@ -725,11 +747,17 @@ public class ECTesterReader { break; } } - byte[] signature = sign.getSignature(); - Response.ECDSA verify = new Command.ECDSA_verify(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, data, signature).send(); - respWriter.outputResponse(verify); + byte[] signature = signResp.getSignature(); + Command.ECDSA_verify verify = new Command.ECDSA_verify(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, data, signature); + long verifyTime = 0; + if (cfg.time) { + verifyTime = -Command.dryRunTime(cardManager, verify, 2, respWriter); + } + Response.ECDSA verifyResp = verify.send(); + verifyTime += verifyResp.getDuration(); + respWriter.outputResponse(verifyResp); - if (verify.error()) { + if (verifyResp.error()) { if (retry < 10) { ++retry; continue; @@ -753,7 +781,7 @@ public class ECTesterReader { k = ByteUtil.bytesToHex(kValue.toByteArray(), false); } } - out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, sign.getDuration() / 1000000, verify.getDuration() / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k, verify.successful() ? 1 : 0)); + out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, signTime / 1000000, verifyTime / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k, verifyResp.successful() ? 1 : 0)); } ++done; @@ -807,6 +835,7 @@ public class ECTesterReader { public String input; public String[] outputs; public boolean fresh = false; + public boolean time = false; public boolean cleanup = false; public boolean simulate = false; public boolean yes = false; @@ -865,6 +894,7 @@ public class ECTesterReader { input = cli.getOptionValue("input"); outputs = cli.getOptionValues("output"); fresh = cli.hasOption("fresh"); + time = cli.hasOption("time"); cleanup = cli.hasOption("cleanup"); simulate = cli.hasOption("simulate"); yes = cli.hasOption("yes"); diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index a92017e..ce35fcc 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -11,6 +11,7 @@ import cz.crcs.ectester.common.util.CardUtil; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; +import cz.crcs.ectester.reader.output.ResponseWriter; import cz.crcs.ectester.reader.response.Response; import javacard.security.KeyPair; @@ -194,6 +195,19 @@ public abstract class Command implements Cloneable { return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, params, data); } + public static long dryRunTime(CardMngr cardManager, Command cmd, int num, ResponseWriter respWriter) throws CardException { + long time = 0; + respWriter.outputResponse(new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_DRY_RUN).send()); + for (int i = 0; i < num; ++i) { + Response dry = cmd.send(); + respWriter.outputResponse(dry); + time += dry.getDuration(); + } + time /= num; + respWriter.outputResponse(new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_NORMAL).send()); + return time; + } + /** * */ @@ -907,7 +921,7 @@ public abstract class Command implements Cloneable { } @Override - public Response send() throws CardException { + public Response.SetDryRunMode send() throws CardException { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); diff --git a/src/cz/crcs/ectester/reader/test/PerformanceTest.java b/src/cz/crcs/ectester/reader/test/PerformanceTest.java index ce6780d..f9cba46 100644 --- a/src/cz/crcs/ectester/reader/test/PerformanceTest.java +++ b/src/cz/crcs/ectester/reader/test/PerformanceTest.java @@ -54,12 +54,16 @@ public class PerformanceTest extends SimpleTest { @Override protected void runSelf() { - long baseTime = 0; + long baseTime; try { new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_DRY_RUN).send(); testable.run(); baseTime = testable.getResponse().getDuration(); testable.reset(); + testable.run(); + baseTime += testable.getResponse().getDuration(); + testable.reset(); + baseTime /= 2; new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_NORMAL).send(); } catch (CardException ce) { throw new TestException(ce); -- cgit v1.2.3-70-g09d2 From 2abc59f61ea68af03256127e27b310b7f2026c0a Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 17 Dec 2018 14:17:44 +0100 Subject: Update README. --- README.md | 154 ++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index d23922d..4a04671 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ See `java -jar ECTesterReader.jar -h`, `java -jar ECTesterReader.jar -ls` and [D -V,--version Print version info. -h,--help Print help. -ln,--list-named Print the list of supported named - curves and keys, (CurveDB and KeyDB). + curves and keys. -ls,--list-suites List supported test suites. -e,--export Export the defaut curve parameters of the card(if any). @@ -53,46 +53,40 @@ See `java -jar ECTesterReader.jar -h`, `java -jar ECTesterReader.jar -ls` and [D -t,--test Test ECC support. Optionally specify a test number to run only a part of a test suite. : - - default - - compression - - invalid - - twist - - degenerate - - cofactor - - wrong - - signature - - composite - - test-vectors - - edge-cases - - miscellaneous + - default: + - compression: + - invalid: + - twist: + - degenerate: + - cofactor: + - wrong: + - signature: + - composite: + - test-vectors: + - edge-cases: + - miscellaneous: -dh,--ecdh Do EC KeyAgreement (ECDH...), [count] times. -dsa,--ecdsa Sign data with ECDSA, [count] times. -nf,--info Get applet info. - -b,--bit-size Set curve size. -fp,--prime-field Use a prime field. -f2m,--binary-field Use a binary field. - -nc,--named-curve Use a named curve, from CurveDB: -c,--curve Use curve from file (field,a,b,gx,gy,r,k). -u,--custom Use a custom curve (applet-side embedded, SECG curves). - -npub,--named-public Use public key from KeyDB: -pub,--public Use public key from file (wx,wy). - -npriv,--named-private Use private key from KeyDB: -priv,--private Use private key from file (s). - - -nk,--named-key Use KeyPair from KeyDB: - -k,--key Use KeyPair from file  + -nk,--named-key Use keyPair from KeyDB: + -k,--key Use keyPair from file  (wx,wy,s). - -i,--input Input from file , for ECDSA signing. -o,--output Output into file . The @@ -103,9 +97,18 @@ See `java -jar ECTesterReader.jar -h`, `java -jar ECTesterReader.jar -ls` and [D -v,--verbose Turn on verbose logging. --format Output format to use. One of: text,yml,xml. - + --fixed Generate key(s) only once, keep them + for later operations. + --fixed-private Generate private key only once, keep + it for later ECDH. + --fixed-public Generate public key only once, keep + it for later ECDH. -f,--fresh Generate fresh keys (set domain parameters before every generation). + --time Output better timing values, by + running command in dry run mode and + normal mode, and subtracting the + two. --cleanup Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations. @@ -113,10 +116,10 @@ See `java -jar ECTesterReader.jar -h`, `java -jar ECTesterReader.jar -ls` and [D instead of using a terminal. -y,--yes Accept all warnings and prompts. -ka,--ka-type Set KeyAgreement object [type], - corresponds to JavaCard KeyAgreement + corresponds to JC.KeyAgreement constants. -sig,--sig-type Set Signature object [type], - corresponds to JavaCard Signature + corresponds to JC.Signature constants. -C,--color Print stuff with color, requires ANSI terminal. @@ -298,58 +301,81 @@ To install, place them in `${java.home}/jre/lib/security/`. ### Options ``` -usage: ECTesterStandalone.jar [-V] [-h] [-C] - [ (ecdh [-b ] [-nc ] [-cn ] [-t ] [--key-type ] [-n ]) | - (ecdsa [-b ] [-nc ] [-cn ] [-t ] [-n ] [-f ]) | - (export [-b ] [-t ]) | - (generate [-b ] [-nc ] [-cn ] [-n ] [-t ]) | - (list-data [what]) | - (list-libs) | - (list-suites) | - (test [-b ] [-nc ] [-cn ] [-gt ] [-kt ] [-st ] [-f ] [--key-type ] - ) ] - [lib] - - ecdh: | Perform EC based KeyAgreement. | - -b,--bits What size of curve to use. - -nc,--named-curve Use a named curve, from CurveDB: - -cn,--curve-name Use a named curve, search from curves - supported by the library: - -t,--type Set KeyAgreement object [type]. - --key-type Set the key [algorithm] for which the key - should be derived in KeyAgreements with - KDF. Default is "AES". - -n,--amount Do ECDH [amount] times. - - ecdsa: | Perform EC based Signature. | - -b,--bits What size of curve to use. - -nc,--named-curve Use a named curve, from CurveDB: - -cn,--curve-name Use a named curve, search from curves - supported by the library: - -t,--type Set Signature object [type]. - -n,--amount Do ECDSA [amount] times. - -f,--file Input [file] to sign. - - export: | Export default curve parameters. | +usage: ECTesterStandalone.jar [-V] [-h ] [-C] [ +(ecdh [-b ] [-nc ] [-cn ] [-o ] [-t ] [--key-type ] [-n ] + [-npriv ] [--fixed-private] [-npub ] [--fixed-public]) | +(ecdsa [-b ] [-nc ] [-cn ] [-o ] [-npriv ] [-npub ] [-t ] + [-n ] [-f ]) | +(export [-b ] [-o ] [-t ]) | +(generate [-b ] [-nc ] [-cn ] [-o ] [-n ] [-t ]) | +(list-data [what]) | +(list-libs) | +(list-suites) | +(test [-b ] [-nc ] [-cn ] [-gt ] [-kt ] [-st ] [-f ] [--key-type ] ) ] +[lib] + + -V,--version Print version info. + -h,--help Print help(about ). + -C,--color Print stuff with color, requires ANSI terminal. + [lib] What library to use. + + ecdh: | Perform EC based KeyAgreement. | + -b,--bits What size of curve to use. + -nc,--named-curve Use a named curve, from CurveDB: + + -cn,--curve-name Use a named curve, search from curves + supported by the library: + -o,--output Output into file . + -t,--type Set KeyAgreement object [type]. + --key-type Set the key [algorithm] for which the + key should be derived in + KeyAgreements with KDF. Default is + "AES". + -n,--amount Do ECDH [amount] times. + -npriv,--named-private Use a named private key, from + CurveDB: + --fixed-private Perform ECDH with fixed private key. + -npub,--named-public Use a named public key, from CurveDB: + + --fixed-public Perform ECDH with fixed public key. + + ecdsa: | Perform EC based Signature. | + -b,--bits What size of curve to use. + -nc,--named-curve Use a named curve, from CurveDB: + + -cn,--curve-name Use a named curve, search from curves + supported by the library: + -o,--output Output into file . + -npriv,--named-private Use a named private key, from + CurveDB: + -npub,--named-public Use a named public key, from CurveDB: + + -t,--type Set Signature object [type]. + -n,--amount Do ECDSA [amount] times. + -f,--file Input [file] to sign. + + export: | Export default curve parameters. | -b,--bits What size of curve to use. + -o,--output Output into file . -t,--type Set KeyPair object [type]. - generate: | Generate EC keypairs. | + generate: | Generate EC keypairs. | -b,--bits What size of curve to use. -nc,--named-curve Use a named curve, from CurveDB: -cn,--curve-name Use a named curve, search from curves supported by the library: + -o,--output Output into file . -n,--amount Generate [amount] of EC keys. -t,--type Set KeyPairGenerator object [type]. - list-data: | List/show contained EC domain parameters/keys. | - [what] what to list. + list-data: | List/show contained EC domain parameters/keys. | + [what] what to list. - list-libs: | List supported libraries. | + list-libs: | List supported libraries. | - list-suites: | List supported test suites. | + list-suites: | List supported test suites. | - test: | Test a library. | + test: | Test a library. | -b,--bits What size of curve to use. -nc,--named-curve Use a named curve, from CurveDB: -cn,--curve-name Use a named curve, search from curves @@ -362,6 +388,6 @@ usage: ECTesterStandalone.jar [-V] [-h] [-C] --key-type Set the key [algorithm] for which the key should be derived in KeyAgreements with KDF. Default is "AES". - The test suite to run. + The test suite to run. ``` -- cgit v1.2.3-70-g09d2 From 4e67d9eddb478aadc6fda39dcef43b2a25e28d4e Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 17 Dec 2018 17:15:54 +0100 Subject: Fixup edgecases test suite. --- src/cz/crcs/ectester/data/wycheproof/keys.xml | 86 +++++++++++----------- .../ectester/reader/test/CardEdgeCasesSuite.java | 21 +++++- 2 files changed, 61 insertions(+), 46 deletions(-) diff --git a/src/cz/crcs/ectester/data/wycheproof/keys.xml b/src/cz/crcs/ectester/data/wycheproof/keys.xml index 46359df..7ca174d 100644 --- a/src/cz/crcs/ectester/data/wycheproof/keys.xml +++ b/src/cz/crcs/ectester/data/wycheproof/keys.xml @@ -302,7 +302,7 @@ addsub/brainpoolP224r1/1s - 0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a792dd + 0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a792dd brainpool/brainpoolP224r1 tcId = 441 @@ -315,7 +315,7 @@ addsub/brainpoolP224r1/2s - 0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7935d + 0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7935d brainpool/brainpoolP224r1 tcId = 442 @@ -328,7 +328,7 @@ addsub/brainpoolP224r1/3s - 0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939d + 0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939d brainpool/brainpoolP224r1 tcId = 444 @@ -341,7 +341,7 @@ addsub/brainpoolP256r1/1s - 0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974855f5 + 0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974855f5 brainpool/brainpoolP256r1 tcId = 524 @@ -354,7 +354,7 @@ addsub/brainpoolP256r1/2s - 0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485675 + 0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485675 brainpool/brainpoolP256r1 tcId = 525 @@ -367,7 +367,7 @@ addsub/brainpoolP256r1/3s - 0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485695 + 0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485695 brainpool/brainpoolP256r1 tcId = 526 @@ -380,7 +380,7 @@ addsub/brainpoolP256r1/4s - 0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a5 + 0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a5 brainpool/brainpoolP256r1 tcId = 528 @@ -393,7 +393,7 @@ addsub/brainpoolP320r1/1s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59233 + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59233 brainpool/brainpoolP320r1 tcId = 604 @@ -406,7 +406,7 @@ addsub/brainpoolP320r1/2s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592b3 + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592b3 brainpool/brainpoolP320r1 tcId = 605 @@ -419,7 +419,7 @@ addsub/brainpoolP320r1/3s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592f3 + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592f3 brainpool/brainpoolP320r1 tcId = 606 @@ -432,7 +432,7 @@ addsub/brainpoolP320r1/4s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59303 + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59303 brainpool/brainpoolP320r1 tcId = 607 @@ -445,7 +445,7 @@ addsub/brainpoolP320r1/5s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930b + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930b brainpool/brainpoolP320r1 tcId = 608 @@ -458,7 +458,7 @@ addsub/brainpoolP320r1/6s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930f + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930f brainpool/brainpoolP320r1 tcId = 610 @@ -471,7 +471,7 @@ addsub/brainpoolP384r1/1s - 0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904652f + 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904652f brainpool/brainpoolP384r1 tcId = 684 @@ -484,7 +484,7 @@ addsub/brainpoolP384r1/2s - 0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904654f + 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904654f brainpool/brainpoolP384r1 tcId = 685 @@ -497,7 +497,7 @@ addsub/brainpoolP384r1/3s - 0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904655f + 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904655f brainpool/brainpoolP384r1 tcId = 686 @@ -510,7 +510,7 @@ addsub/brainpoolP384r1/4s - 0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046563 + 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046563 brainpool/brainpoolP384r1 tcId = 688 @@ -523,7 +523,7 @@ addsub/brainpoolP512r1/1s - 0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9003b + 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9003b brainpool/brainpoolP512r1 tcId = 774 @@ -536,7 +536,7 @@ addsub/brainpoolP512r1/2s - 0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9005b + 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9005b brainpool/brainpoolP512r1 tcId = 775 @@ -549,7 +549,7 @@ addsub/brainpoolP512r1/3s - 0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90063 + 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90063 brainpool/brainpoolP512r1 tcId = 776 @@ -562,7 +562,7 @@ addsub/brainpoolP512r1/4s - 0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90067 + 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90067 brainpool/brainpoolP512r1 tcId = 778 @@ -575,7 +575,7 @@ addsub/brainpoolP224t1/1s - 0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a792dd + 0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a792dd brainpool/brainpoolP224t1 tcId = 854 @@ -588,7 +588,7 @@ addsub/brainpoolP224t1/2s - 0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7935d + 0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7935d brainpool/brainpoolP224t1 tcId = 855 @@ -601,7 +601,7 @@ addsub/brainpoolP224t1/3s - 0x0d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939d + 0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939d brainpool/brainpoolP224t1 tcId = 857 @@ -614,7 +614,7 @@ addsub/brainpoolP256t1/1s - 0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974855f5 + 0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974855f5 brainpool/brainpoolP256t1 tcId = 935 @@ -627,7 +627,7 @@ addsub/brainpoolP256t1/2s - 0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485675 + 0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485675 brainpool/brainpoolP256t1 tcId = 936 @@ -640,7 +640,7 @@ addsub/brainpoolP256t1/3s - 0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485695 + 0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e8297485695 brainpool/brainpoolP256t1 tcId = 937 @@ -653,7 +653,7 @@ addsub/brainpoolP256t1/4s - 0x0a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a5 + 0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a5 brainpool/brainpoolP256t1 tcId = 939 @@ -666,7 +666,7 @@ addsub/brainpoolP320t1/1s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59233 + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59233 brainpool/brainpoolP320t1 tcId = 1015 @@ -679,7 +679,7 @@ addsub/brainpoolP320t1/2s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592b3 + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592b3 brainpool/brainpoolP320t1 tcId = 1016 @@ -692,7 +692,7 @@ addsub/brainpoolP320t1/3s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592f3 + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c592f3 brainpool/brainpoolP320t1 tcId = 1017 @@ -705,7 +705,7 @@ addsub/brainpoolP320t1/4s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59303 + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c59303 brainpool/brainpoolP320t1 tcId = 1018 @@ -718,7 +718,7 @@ addsub/brainpoolP320t1/5s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930b + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930b brainpool/brainpoolP320t1 tcId = 1019 @@ -731,7 +731,7 @@ addsub/brainpoolP320t1/6s - 0x0d35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930f + 0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e98691555b44c5930f brainpool/brainpoolP320t1 tcId = 1021 @@ -744,7 +744,7 @@ addsub/brainpoolP384t1/1s - 0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904652f + 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904652f brainpool/brainpoolP384t1 tcId = 1093 @@ -757,7 +757,7 @@ addsub/brainpoolP384t1/2s - 0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904654f + 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904654f brainpool/brainpoolP384t1 tcId = 1094 @@ -770,7 +770,7 @@ addsub/brainpoolP384t1/3s - 0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904655f + 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e904655f brainpool/brainpoolP384t1 tcId = 1095 @@ -783,7 +783,7 @@ addsub/brainpoolP384t1/4s - 0x08cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046563 + 0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046563 brainpool/brainpoolP384t1 tcId = 1097 @@ -796,7 +796,7 @@ addsub/brainpoolP512t1/1s - 0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9003b + 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9003b brainpool/brainpoolP512t1 tcId = 1185 @@ -809,7 +809,7 @@ addsub/brainpoolP512t1/2s - 0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9005b + 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca9005b brainpool/brainpoolP512t1 tcId = 1186 @@ -822,7 +822,7 @@ addsub/brainpoolP512t1/3s - 0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90063 + 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90063 brainpool/brainpoolP512t1 tcId = 1187 @@ -835,7 +835,7 @@ addsub/brainpoolP512t1/4s - 0x0aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90067 + 0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90067 brainpool/brainpoolP512t1 tcId = 1189 @@ -878,7 +878,7 @@ cve_2017_10176/secp521r1/1s - 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863f7 + 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863f7 secg/secp521r1 tcId = 280 diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java index 221cbe1..39eaf07 100644 --- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java @@ -104,6 +104,10 @@ public class CardEdgeCasesSuite extends CardTestSuite { curveTests.add(one); } + if (cfg.cleanup) { + curveTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY)); + } + Test curveTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests", curveTests.toArray(new Test[0])); groupTests.add(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Tests on " + curve.getId() + ".", prepareCurve, curveTest)); } @@ -278,7 +282,7 @@ public class CardEdgeCasesSuite extends CardTestSuite { int i = 0; for (BigInteger nearZero : zeros) { EC_Params params = makeParams(nearZero); - zeroTests[i++] = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearZero.toString(16), Result.ExpectedValue.ANY, Result.ExpectedValue.ANY); + zeroTests[i++] = ecdhTestBoth(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearZero.toString(16), Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); } Test zeroTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near zero.", zeroTests); @@ -286,7 +290,7 @@ public class CardEdgeCasesSuite extends CardTestSuite { i = 0; for (BigInteger nearP : ps) { EC_Params params = makeParams(nearP); - pTests[i++] = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearP.toString(16) + (nearP.compareTo(p) > 0 ? " (>p)" : " (<=p)"), Result.ExpectedValue.ANY, Result.ExpectedValue.ANY); + pTests[i++] = ecdhTestBoth(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearP.toString(16) + (nearP.compareTo(p) > 0 ? " (>p)" : " (<=p)"), Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS); } Test pTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near p.", pTests); @@ -294,12 +298,23 @@ public class CardEdgeCasesSuite extends CardTestSuite { i = 0; for (BigInteger nearR : rs) { EC_Params params = makeParams(nearR); - rTests[i++] = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearR.toString(16) + (nearR.compareTo(r) > 0 ? " (>r)" : " (<=r)"), Result.ExpectedValue.ANY, Result.ExpectedValue.ANY); + if (nearR.compareTo(r) >= 0) { + rTests[i++] = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearR.toString(16) + " (>=r)", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE); + } else { + rTests[i++] = ecdhTestBoth(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearR.toString(16) +" ([:start_index[:stop_index]]`. @@ -149,15 +149,19 @@ For more info about the test suites see [TESTS](docs/TESTS.md). #### Generate `-g / --generate [amount]` -Generates batches of EC keypairs and exports them. +Generates batch of EC keypairs and exports them. + Use with `-o / --output [out_file]` to output the generated keys to a file. +Use with `--time` to measure time as a difference of real duration of the operation and the dry-run duration of the operation. For format of this file see [FORMAT](docs/FORMAT.md). #### ECDH `-dh / --ecdh [count]` Performs ECDH. + Use with `-o / --output [out_file]` to output into a file. +Use with `--time` to measure time as a difference of real duration of the operation and the dry-run duration of the operation. For format of this file see [FORMAT](docs/FORMAT.md). Respects the KeyAgreement type specified in `-ka / --ka-type [type]`. @@ -168,6 +172,7 @@ Respects the KeyAgreement type specified in `-ka / --ka-type [type]`. Performs ECDSA. Useful with `-i / --input [in_file]` to sign the contents of a file. Use with `-o / --output [out_file]` to output into a file. +Use with `--time` to measure time as a difference of real duration of the operation and the dry-run duration of the operation. For format of these files see [FORMAT](docs/FORMAT.md). Respects the Signature type specified in `-sig / --sig-type [type]`. @@ -175,9 +180,7 @@ Respects the Signature type specified in `-sig / --sig-type [type]`. `-ln / --list-named []` Lists categories of curves, keys and keypairs embedded in ECTester's jar, along with some information about them. -These can be used as arguments to the `-n[c|k|pub|priv] / --named-[curve|key|public|private]` parameters. - -With the format: `category/name`. +These can be used as arguments to the `-n[c|k|pub|priv] / --named-[curve|key|public|private]` parameters, using the format: `category/name`. For example: `secg/secp192r1` identifies the SECG 192 bit prime field curve known as `secp192r1`. @@ -197,9 +200,10 @@ Get and print ECTester applet info from an applet installed on a card. Outputs: - ECTester applet version - - ECTester APDU support + - ECTester APDU support (basic/extended APDU) - JavaCard API version - JavaCard cleanup support + - ECTester internal array sizes and APDU buffer size ### Example diff --git a/docs/FORMAT.md b/docs/FORMAT.md index bde2543..16af130 100644 --- a/docs/FORMAT.md +++ b/docs/FORMAT.md @@ -1,6 +1,14 @@ # Format ECTester mostly reads/outputs data in either human-readable format or using CSV. +## Test runs +By default test runs are output in a human readable format, however YAML and XML is also supported and can be selected +by using the `--format` option. Also, prefixing the output file name when using the `-o/--output` option allows to output +the same test run in different formats to different files. + +For example: +`--format yaml -o default_output.yaml -o xml:output_file.xml -o text:readable_text_file.txt ` + ## Curves Input files for the `-c/--curve` option should be in CSV, little-endian hexadecimal format. Output of the `-e/--export` option will also be in this format. @@ -42,22 +50,37 @@ Input files for the `-k/--key`, `-pub/--public` and `-priv/--private` options sh ## Key generation output(CSV) Output of the `-g/--generate` option. -`index;time;pubW;privS` +For ECTesterReader this has the format: + +`index;genTime[milli];exportTime[milli];pubW;privS` where `pubW` is the public key used in ANSI X9.62 format, +`privS` is the private key, `genTime` is the time required to generate the keypair and `exportTime` is the time required to export it (send it to the reader). + +For ECTesterStandalone: + +`index;time[nano];pubW;privS` ## KeyAgreement output(CSV) Output of the `-dh/--ecdh` option. -`index;time;pubW;privS;secret` +For ECTesterReader this has the format: + +`index;time[milli];pubW;privS;secret` where `pubW` is the public key used in ANSI X9.62 format, `privS` is the private key +and `secret` is the KeyAgreement result. + +For ECTesterStandalone this has the format: and the same meaning as for ECTesterReader. + +`index;time[nano];pubW;privS;secret` and the same meaning as for ECTesterReader. ## Signature output(CSV) Output of the `-dsa/--ecdsa` option. -`index;time;signature` +For ECTesterReader this has the format: -## Test runs -By default test runs are output in a human readable format, however YAML and XML is also supported and can be selected -by using the `--format` option. Also, prefixing the output file name when using the `-o/--output` option allows to output -the same test run in different formats to different files. +`index;signTime[milli];verifyTime[milli];data;pubW;privS;signature;nonce;valid` where `pubW` is the public key used +in ANSI X9.62 format, `privS` is the private key, `signTime` and `verifyTime` are the durations of the sign and verify operations, +`data` is the signed data (if available), `signature` is the produced signature, `nonce` is the `k` (nonce) value recovered from the signature +abd the private key (if possible), `valid` denotes the verification result. -For example: -`--format yaml -o default_output.yaml -o xml:output_file.xml -o text:readable_text_file.txt ` +For ECTesterStandalone this has the format: + + `index;signTime[nano];verifyTime[nano];data;pubW;privS;signature;nonce;verified` and the same meaning as for ECTesterReader. \ No newline at end of file diff --git a/docs/TESTS.md b/docs/TESTS.md index 25f61a8..a2d3642 100644 --- a/docs/TESTS.md +++ b/docs/TESTS.md @@ -17,7 +17,7 @@ confirmation before running, be cautious.** ## Default -Tests the default curves present on the card. These might not be present or the card might not even support ECC. +Tests support for ECC and the presence of default curves on the target. These might not be present or the target might not even support ECC. Tests keypair allocation, generation, ECDH and ECDSA. ECDH is first tested with two valid generated keypairs, then with a compressed public key to test support for compressed points. @@ -25,7 +25,7 @@ This test suite is run if no argument is provided to `-t / --test`. ## Test-Vectors -Tests using known test vectors provided by NIST/SECG/Brainpool: +Tests ECDH using known test vectors provided by NIST/SECG/Brainpool: [SECG - GEC2](http://read.pudn.com/downloads168/doc/772358/TestVectorsforSEC%201-gec2.pdf) @@ -37,8 +37,12 @@ Tests using known test vectors provided by NIST/SECG/Brainpool: ## Compression -Tests support for compression of public points in ECDH as specified in ANSI X9.62. Tests ECDH with points in compressed -and hybrid form. Also tests card response to a hybrid point with wrong `y` coordinate and to the point at infinity(as public key in ECDH). +Tests support for compression of public points in ECDH as specified in ANSI X9.62. The standard specifies two forms of point compression, +fully compressed point contains the `x` coordinate and one bit of the `y` coordinate, from which the whole point can be reconstructed, hybrid form +of a compressed point contains both the `x` and `y` coordinates but also one bit of the `y` coordinate. + +Tests ECDH with points in compressed and hybrid form. Also tests target response to a hybrid point with wrong `y` coordinate and to the point at infinity(as public key in ECDH). +Tests ECDH with invalid compressed point, where `x` does not lie on the curve. - Compressed form, valid - Hybrid form, valid @@ -48,29 +52,35 @@ and hybrid form. Also tests card response to a hybrid point with wrong `y` coord ## Miscellaneous -Some miscellaneous tests, tries ECDH and ECDSA over supersingular curves, anomalous curves and Barreto-Naehrig curves with small embedding degree and CM discriminant. +Some miscellaneous tests, tries ECDH and ECDSA over super-singular curves, anomalous curves and Barreto-Naehrig curves with small embedding degree and CM discriminant. +Also tests ECDH over MNT curves, M curves and Curve25519 transformed into short Weierstrass form. ## Signature -Tests ECDSA verification, with invalid signatures. - - - Well-formed(DER) invalid signatures: - - r = random, s = random - - r = 0, s = random - - r = random, s = 0 - - r = 1, s = random - - r = random, s = 1 - - r = 0, s = 0 - - r = 0, s = 1 - - r = 1, s = 0 - - r = 1, s = 1 - - s = p - - s = 2 * p - - Invalid signatures: - - Signature shorter than specified in ASN.1 SEQUENCE header. - - Signature longer than specified in ASN.1 SEQUENCE header. - - r shorter/longer than specified in its ASN.1 header. - - s shorter/longer than specified in its ASN.1 header. +Tests ECDSA verification, with well-formed but invalid and malformed signatures. + +- Well-formed(DER) invalid signatures: + - r = random, s = random + - r = 0, s = random + - r = random, s = 0 + - r = 1, s = random + - r = random, s = 1 + - r = 0, s = 0 + - r = 0, s = 1 + - r = 1, s = 0 + - r = 1, s = 1 + - r = random, s = p + - r = random, s = 2 * p +- Invalid signatures: + - Signature shorter than specified in ASN.1 SEQUENCE header. + - Signature longer than specified in ASN.1 SEQUENCE header. + - r shorter/longer than specified in its ASN.1 header. + - s shorter/longer than specified in its ASN.1 header. + - ASN.1 SEQUENCE has indefinite length. + - ASN.1 SEQUENCE has length that will overflow a 16 bit integer. + - ASN.1 SEQUENCE has length that will overflow a 32 bit integer. + - ASN.1 SEQUENCE has length that will overflow a 64 bit integer. +- Test verifying a valid signature, but with a negated public key. ## Wrong @@ -104,7 +114,7 @@ This test suite also does some additional tests with corrupting the parameters: ## Composite Tests using curves that don't have a prime order/nearly prime order. -These tests should generally fail, a success here implies the card will use a non-secure curve if such curve is set +These tests should generally fail, a success here implies the target will use a non-secure curve if such curve is set by the applet. Operations over such curves are susceptible to small-subgroup attacks. - r = quite a smooth number, many small factors, r = \|G\| @@ -121,29 +131,29 @@ by the applet. Operations over such curves are susceptible to small-subgroup att ## Invalid Tests using known named curves from several categories(SECG/NIST/Brainpool) against pre-generated *invalid* public keys. -ECDH should definitely fail, a success here implies the card is susceptible to invalid curve attacks. +ECDH should definitely fail, a success here implies the target is susceptible to invalid curve attacks. See [Practical Invalid Curve Attacks on TLS-ECDH](https://www.nds.rub.de/media/nds/veroeffentlichungen/2015/09/14/main-full.pdf) for more information. ## Twist Tests using known named curves froms several categories(SECG/NIST) against pre-generated points on twists of said curves. -ECDH should fail, a success here implies the card is not twist secure, if a curve with an unsecure twist is used, -the card might compute on the twist, if a point on the twist is supplied. +ECDH should fail, a success here implies the target is not twist secure, if a curve with an unsecure twist is used, +the target might compute on the twist, if a point on the twist is supplied. See [SafeCurves on twist security](https://safecurves.cr.yp.to/twist.html) for more information. ## Degenerate Tests using known named curves froms several categories(SECG/NIST) against pre-generated points on the degenerate line -`Y: x = 0`. ECDH should fail, a success here might mean the card does not check that the point lies on the correct curve +`Y: x = 0`. ECDH should fail, a success here might mean the target does not check that the point lies on the correct curve and uses a curve model vulnerable to such degenerate points. See [Degenerate Curve Attacks - Extending Invalid Curve Attacks to Edwards Curves and Other Models](https://eprint.iacr.org/2015/1233.pdf) for more information. ## Cofactor -Tests whether the card correctly rejects points that lie on the curve but not on the subgroup generated by the specified generator +Tests whether the target correctly rejects points that lie on the curve but not on the subgroup generated by the specified generator during ECDH. Does this with curves where the cofactor subgroup has small order, then with curves that have order equal to the product of two large primes, sets the generator with order of one prime and tries points on the subgroup of the other prime order. @@ -166,6 +176,7 @@ Custom edge-case private key values over SECG curves are tested: - s < r, s = r, s > r - s = r - 1, s = r + 1 - s = k\*r - 1, s = k\*r, s = k\*r + 1 + - s = 111111...1111, s = 101010...1010, s = 010101...0101 - s around r (s < r, on a curve where \|r\| > \|p\|) - s around p (on a curve where where \|r\| > \|p\|) - s around 0 (s > 0, on a curve where \|r\| > \|p\|) diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 6e1d508..a255b18 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -369,6 +369,8 @@ public class ECTesterReader { System.out.println("\t" + line); } } + System.out.println(); + System.out.println("For more information, look at the documentation at https://github.com/crocs-muni/ECTester."); } private void info() throws CardException { @@ -444,7 +446,7 @@ public class ECTesterReader { respWriter.outputResponse(allocate); OutputStreamWriter keysFile = FileUtil.openFiles(cfg.outputs); - keysFile.write("index;genTime;exportTime;pubW;privS\n"); + keysFile.write("index;genTime[milli];exportTime[milli];pubW;privS\n"); int generated = 0; int retry = 0; diff --git a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java index 172c8af..5c22607 100644 --- a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java @@ -25,7 +25,8 @@ import static cz.crcs.ectester.common.test.Result.ExpectedValue; */ public class CardCofactorSuite extends CardTestSuite { public CardCofactorSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { - super(writer, cfg, cardManager, "cofactor", "The cofactor test suite tests whether the card correctly rejects points on the curve but not in the subgroup generated by the generator during ECDH."); + super(writer, cfg, cardManager, "cofactor", "The cofactor test suite tests whether the card correctly rejects points on the curve", + "but not in the subgroup generated by the generator(so of small order, dividing the cofactor) during ECDH."); } @Override diff --git a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java index 4bf9290..d987e05 100644 --- a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java @@ -25,7 +25,8 @@ import static cz.crcs.ectester.common.test.Result.ExpectedValue; public class CardCompositeSuite extends CardTestSuite { public CardCompositeSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { - super(writer, cfg, cardManager, "composite", "The composite suite runs ECDH over curves with composite order. This should generally fail, as using such a curve is unsafe."); + super(writer, cfg, cardManager, "composite", "The composite suite runs ECDH over curves with composite order.", + "Various types of compositeness is tested: smooth numbers, Carmichael pseudoprime, prime square, product of two large primes."); } @Override diff --git a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java index 291cc04..c86c0b1 100644 --- a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java @@ -29,7 +29,9 @@ import java.util.Map; public class CardCompressionSuite extends CardTestSuite { public CardCompressionSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { super(writer, cfg, cardManager, "compression", "The compression test suite tests cards support for compressed points in ECDH (as per ANSI X9.62).", - "It also tests for handling of bogus input by using the point at infinity and a hybrid point with the y coordinate corrupted."); + "It also tests for handling of bogus input in ECDH by using the point at infinity and a hybrid point with the y coordinate corrupted.", + "It also tests handling of compressed point in ECDH, where the x coordinate is invalid and therefore", + "a quadratic non-residue will be computed and (square root-ed) during decompression."); } @Override diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java index f42af23..29e2ef9 100644 --- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java @@ -29,7 +29,7 @@ import static cz.crcs.ectester.common.test.Result.Value; public class CardDefaultSuite extends CardTestSuite { public CardDefaultSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { - super(writer, cfg, cardManager, "default", "The default test suite tests basic support of ECDH and ECDSA."); + super(writer, cfg, cardManager, "default", "The default test suite tests basic support and performance of ECDH and ECDSA."); } @Override diff --git a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java index 755c746..730c70b 100644 --- a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java @@ -25,7 +25,7 @@ public class CardDegenerateSuite extends CardTestSuite { public CardDegenerateSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { super(writer, cfg, cardManager, "degenerate", "The degenerate suite tests whether the card rejects points outside of the curve during ECDH.", - "The tested points lie on a part of the plane for which some Edwards, Hessian and Huff form addition formulas work."); + "The tested points lie on a part of the plane for which some Edwards, Hessian and Huff form addition formulas degenerate into exponentiation in the base finite field."); } @Override diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java index 39eaf07..f5ea86f 100644 --- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java @@ -33,6 +33,7 @@ public class CardEdgeCasesSuite extends CardTestSuite { public CardEdgeCasesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { super(writer, cfg, cardManager, "edge-cases", "The edge-cases test suite tests various inputs to ECDH which may cause an implementation to achieve a certain edge-case state during it.", "Some of the data is from the google/Wycheproof project. Tests include CVE-2017-10176 and CVE-2017-8932.", + "Also tests values of the private key and public key that would trigger the OpenSSL modualr multiplication bug on the P-256 curve.", "Various edge private key values are also tested."); } diff --git a/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java b/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java index 20546c8..0fa58d3 100644 --- a/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java @@ -22,7 +22,7 @@ import java.util.Map; */ public class CardSignatureSuite extends CardTestSuite { public CardSignatureSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { - super(writer, cfg, cardManager, "signature", "Test verifying various wrong ECDSA values."); + super(writer, cfg, cardManager, "signature", "The signature test suite tests verifying various malformed and well-formed but invalid ECDSA signatures."); } @Override -- cgit v1.2.3-70-g09d2 From d9108d4a036363d26d8d83153e98d52e62d1be04 Mon Sep 17 00:00:00 2001 From: J08nY Date: Tue, 19 Feb 2019 22:24:53 +0100 Subject: Workaround for a Java bug... --- docs/TESTS.md | 10 +++++----- src/cz/crcs/ectester/data/cofactor/cofactor128p56467.csv | 1 + src/cz/crcs/ectester/data/cofactor/cofactor128p65521.csv | 1 + src/cz/crcs/ectester/data/cofactor/cofactor128p65535.csv | 1 + src/cz/crcs/ectester/data/invalid/secg/secp128r1.xml | 6 +++--- src/cz/crcs/ectester/reader/command/Command.java | 15 ++++++++++----- 6 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 src/cz/crcs/ectester/data/cofactor/cofactor128p56467.csv create mode 100644 src/cz/crcs/ectester/data/cofactor/cofactor128p65521.csv create mode 100644 src/cz/crcs/ectester/data/cofactor/cofactor128p65535.csv diff --git a/docs/TESTS.md b/docs/TESTS.md index a2d3642..5d32d9d 100644 --- a/docs/TESTS.md +++ b/docs/TESTS.md @@ -101,9 +101,9 @@ This test suite also does some additional tests with corrupting the parameters: - G = infinity - r = 0 - r = 1 - - r = some prime larger than original r (and \[r\]G != infinity) - - r = some prime smaller than original r (and \[r\]G != infninity) - - r = some composite number (and \[r\]G != infinity) + - r = some prime larger than original r (and [r]G != infinity) + - r = some prime smaller than original r (and [r]G != infninity) + - r = some composite number (and [r]G != infinity) - k = 0xff - k = 0 @@ -123,10 +123,10 @@ by the applet. Operations over such curves are susceptible to small-subgroup att This is performed over a 160 bit field size, in two passes: - First pass tests the full range from 2 bits to 152, with more frequent tests towards the beginning and end. - The second pass tests the range 140 - 158 bits with one bit steps. - + - r = p * q = \|G\| - r = G = Carmichael number = p * q * s - - \[r\]G = infinity but r != \|G\|, so \|G\| divides r + - [r]G = infinity but r != \|G\|, so \|G\| divides r ## Invalid diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor128p56467.csv b/src/cz/crcs/ectester/data/cofactor/cofactor128p56467.csv new file mode 100644 index 0000000..193f6a7 --- /dev/null +++ b/src/cz/crcs/ectester/data/cofactor/cofactor128p56467.csv @@ -0,0 +1 @@ +0xe8e100a50b479105f40c312de4bc7127,0x854c8cdc7389dbb3da8a949ce4598ebe,0x4e592cbd1471bba6dec1106cfa99f969,0x7a6c7f7f8305853831d7c99dd23b03aa,0xa3ad04379cb4789bd64e7d99a7874e0b,0x00010e47ea4c399c7ddb49c9915c3b5d,0xdc93 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor128p65521.csv b/src/cz/crcs/ectester/data/cofactor/cofactor128p65521.csv new file mode 100644 index 0000000..80a1eb3 --- /dev/null +++ b/src/cz/crcs/ectester/data/cofactor/cofactor128p65521.csv @@ -0,0 +1 @@ +0xdc068a34e30288e08b495798af63ebc7,0xdc068a34e3027b1ccb5209bee1c3ebc7,0xdc054fb5cb170758f9fe7d1b5f63ebc7,0xc0d6edec3ac87edf8499d1885fd03e7b,0x81cb302f36ecd3ff93cd6314ce059e14,0x0000dc136f586930b2b948e64bb6e653,0xfff1 \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/cofactor/cofactor128p65535.csv b/src/cz/crcs/ectester/data/cofactor/cofactor128p65535.csv new file mode 100644 index 0000000..54da6cc --- /dev/null +++ b/src/cz/crcs/ectester/data/cofactor/cofactor128p65535.csv @@ -0,0 +1 @@ +0xdd94e89ef3fba74afc2a67cb91546a93,0x6cf4828ab4960df2b9fcab3990e3959a,0x80a5c32206c83f769c5ed3e4f5b2ea4e,0xd7a4bb4b7e9ad9e81895caeaeac8b739,0x45ebc51cf353974b02b36b9912de041b,0x0000dd95c634ba30617af48fd4eb321b,0xffff \ No newline at end of file diff --git a/src/cz/crcs/ectester/data/invalid/secg/secp128r1.xml b/src/cz/crcs/ectester/data/invalid/secg/secp128r1.xml index 8903688..e010003 100644 --- a/src/cz/crcs/ectester/data/invalid/secg/secp128r1.xml +++ b/src/cz/crcs/ectester/data/invalid/secg/secp128r1.xml @@ -85,7 +85,7 @@ secp128r1/14 - 0x98b36c442de5c741c70fa80a31d72fa,0x251e9a04ffe799cf4776575be582f108 + 0x098b36c442de5c741c70fa80a31d72fa,0x251e9a04ffe799cf4776575be582f108 secg/secp128r1 invalid order = 47 @@ -109,7 +109,7 @@ secp128r1/18 - 0x9ce43ec4dcaf95993d8ab00efcc7199a,0x7fb6d895c27bc326a33cb8111e865a9 + 0x9ce43ec4dcaf95993d8ab00efcc7199a,0x07fb6d895c27bc326a33cb8111e865a9 secg/secp128r1 invalid order = 67 @@ -139,7 +139,7 @@ secp128r1/23 - 0x6803013e75597fb7f83f1f8681af11d,0x32490d391f8a2b1de83212dd218b3a5a + 0x06803013e75597fb7f83f1f8681af11d,0x32490d391f8a2b1de83212dd218b3a5a secg/secp128r1 invalid order = 89 diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index ce35fcc..1ebd8bb 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -29,6 +29,11 @@ import java.util.List; public abstract class Command implements Cloneable { CommandAPDU cmd; CardMngr cardManager; + // Workaround for a stupid Java bug that went unfixed for !12! years, + // and for the even more stupid module system, which cannot properly work + // with the fact that JCardSim has some java.* packages... + final byte[] GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM = new byte[]{0}; + Command(CardMngr cardManager) { this.cardManager = cardManager; @@ -336,7 +341,7 @@ public abstract class Command implements Cloneable { super(cardManager); this.keyPair = keyPair; - this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEAR, keyPair, 0x00); + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEAR, keyPair, 0x00, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM); } @Override @@ -486,7 +491,7 @@ public abstract class Command implements Cloneable { super(cardManager); this.keyPair = keyPair; - this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GENERATE, keyPair, 0); + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GENERATE, keyPair, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM); } @Override @@ -858,7 +863,7 @@ public abstract class Command implements Cloneable { public Cleanup(CardMngr cardManager) { super(cardManager); - this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEANUP, 0, 0); + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEANUP, 0, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM); } @Override @@ -886,7 +891,7 @@ public abstract class Command implements Cloneable { public GetInfo(CardMngr cardManager) { super(cardManager); - this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GET_INFO, 0, 0); + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GET_INFO, 0, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM); } @Override @@ -917,7 +922,7 @@ public abstract class Command implements Cloneable { super(cardManager); this.dryRunMode = dryRunMode; - this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SET_DRY_RUN_MODE, dryRunMode, 0); + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SET_DRY_RUN_MODE, dryRunMode, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM); } @Override -- cgit v1.2.3-70-g09d2 From edc96e582c3dc62999c020a108bf13c3f6bf035a Mon Sep 17 00:00:00 2001 From: J08nY Date: Tue, 19 Feb 2019 22:59:08 +0100 Subject: Prefer T=1 protocol. --- src/cz/crcs/ectester/reader/CardMngr.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index e6835dd..8f88ebb 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -72,7 +72,14 @@ public class CardMngr { terminal = terminalList.get(i); if (terminal.isCardPresent()) { - card = terminal.connect("*"); + try { + card = terminal.connect("T=1"); + } catch (CardException ex) { + if (verbose) + System.out.println("T=1 failed, trying protocol '*'"); + card = terminal.connect("*"); + } + if (verbose) System.out.println("card: " + card); channel = card.getBasicChannel(); -- cgit v1.2.3-70-g09d2 From 3beace9c4aa21487b0bc43b483850acd5bf2320d Mon Sep 17 00:00:00 2001 From: J08nY Date: Thu, 21 Feb 2019 11:33:16 +0100 Subject: Add large cofactor curves to tests. --- src/cz/crcs/ectester/data/cofactor/curves.xml | 18 ++++++++++++++++++ src/cz/crcs/ectester/data/cofactor/keys.xml | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/cz/crcs/ectester/data/cofactor/curves.xml b/src/cz/crcs/ectester/data/cofactor/curves.xml index ddc8746..0b8c52e 100644 --- a/src/cz/crcs/ectester/data/cofactor/curves.xml +++ b/src/cz/crcs/ectester/data/cofactor/curves.xml @@ -44,6 +44,24 @@ prime cofactor128p128.csv + + large/cofactor128p56467 + 128 + prime + cofactor128p56467.csv + + + large/cofactor128p65521 + 128 + prime + cofactor128p65521.csv + + + large/cofactor128p65535 + 128 + prime + cofactor128p65535.csv + cofactor160p2 diff --git a/src/cz/crcs/ectester/data/cofactor/keys.xml b/src/cz/crcs/ectester/data/cofactor/keys.xml index b4c0c90..2be7238 100644 --- a/src/cz/crcs/ectester/data/cofactor/keys.xml +++ b/src/cz/crcs/ectester/data/cofactor/keys.xml @@ -702,4 +702,23 @@ composite/pq/composite256/2 cofactor order = 0x000000000000000000000000000000000000000000000000743bc7ea193d40db + + + large/cofactor128p56467/0 + 0x8afd6cc280e0be7163bb6f285a7c6391,0xae64e0f1afc7bd5c75e2f36a7d85f668 + cofactor/large/cofactor128p56467 + cofactor order = 0xdc93 + + + large/cofactor128p65521/0 + 0x70e43816ed51388caa54a68b6c500352,0xab05b43e2cde6086b12350abe79b9175 + cofactor/large/cofactor128p65521 + cofactor order = 0xfff1 + + + large/cofactor128p65535/0 + 0x39d6ea56c3eb6382d2d7a9d327a191fd,0x3ebb3f4626d05df38572af3ae5fa60f2 + cofactor/large/cofactor128p65535 + cofactor order = 0xffff + -- cgit v1.2.3-70-g09d2 From f98fb059fe39855784e03e1a7c117b12cdc8e5f5 Mon Sep 17 00:00:00 2001 From: J08nY Date: Thu, 21 Feb 2019 15:57:06 +0100 Subject: Add option to use preset semi-random private key in tests. --- src/cz/crcs/ectester/common/util/ECUtil.java | 23 ++++++++++++++++++++++ src/cz/crcs/ectester/reader/ECTesterReader.java | 17 ++++++++++++++++ .../ectester/reader/output/TextTestWriter.java | 1 + .../ectester/reader/test/CardCofactorSuite.java | 2 +- .../ectester/reader/test/CardCompositeSuite.java | 11 +++++++++-- .../crcs/ectester/reader/test/CardMiscSuite.java | 2 +- .../crcs/ectester/reader/test/CardTestSuite.java | 22 +++++++++++++++++++++ src/cz/crcs/ectester/reader/test/CommandTest.java | 2 +- 8 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java index e29bfdd..511f93f 100644 --- a/src/cz/crcs/ectester/common/util/ECUtil.java +++ b/src/cz/crcs/ectester/common/util/ECUtil.java @@ -7,9 +7,11 @@ import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1StreamParser; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERSequenceParser; +import org.bouncycastle.crypto.digests.SHA1Digest; import java.io.IOException; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -190,6 +192,27 @@ public class ECUtil { } } + public static byte[] semiRandomKey(EC_Curve curve) { + int bytes = (curve.getBits() + 7) / 8; + byte[] result = new byte[bytes]; + SHA1Digest digest = new SHA1Digest(); + byte[] curveName = curve.getId().getBytes(StandardCharsets.US_ASCII); + digest.update(curveName, 0, curveName.length); + int written = 0; + while (written < bytes) { + byte[] dig = new byte[digest.getDigestSize()]; + digest.doFinal(dig, 0); + int toWrite = digest.getDigestSize() > bytes - written ? bytes - written : digest.getDigestSize(); + System.arraycopy(dig, 0, result, written, toWrite); + written += toWrite; + digest.update(dig, 0, dig.length); + } + BigInteger priv = new BigInteger(1, result); + BigInteger order = new BigInteger(1, curve.getParam(EC_Consts.PARAMETER_R)[0]); + priv = priv.mod(order); + return toByteArray(priv, curve.getBits()); + } + private static ECPoint toPoint(EC_Params params) { return new ECPoint( new BigInteger(1, params.getParam(EC_Consts.PARAMETER_W)[0]), diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index a255b18..dc49656 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -340,6 +340,7 @@ public class ECTesterReader { opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations.").build()); opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build()); opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build()); + opts.addOption(Option.builder("to").longOpt("test-options").desc("Test options to use.").hasArg().argName("options").build()); opts.addOption(Option.builder("ka").longOpt("ka-type").desc("Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants.").hasArg().argName("type").optionalArg(true).build()); opts.addOption(Option.builder("sig").longOpt("sig-type").desc("Set Signature object [type], corresponds to JC.Signature constants.").hasArg().argName("type").optionalArg(true).build()); @@ -854,6 +855,7 @@ public class ECTesterReader { public byte ECKAType = KeyAgreement_ALG_EC_SVDP_DH; public int ECDSACount; public byte ECDSAType = Signature_ALG_ECDSA_SHA; + public Set testOptions; /** * Reads and validates options, also sets defaults. @@ -1008,6 +1010,21 @@ public class ECTesterReader { System.err.println(Colors.error("Unknown test suite " + testSuite + ". Should be one of: " + Arrays.toString(tests))); return false; } + + String[] opts = cli.getOptionValue("test-options", "").split(","); + List validOpts = Arrays.asList("preset"); + testOptions = new HashSet<>(); + for (String opt : opts) { + if (opt.equals("")) { + continue; + } + if (!validOpts.contains(opt)) { + System.err.println(Colors.error("Unknown test option " + opt + ". Should be one of: " + "preset.")); + return false; + } else { + testOptions.add(opt); + } + } } else if (cli.hasOption("ecdh")) { if (primeField == binaryField) { System.err.print(Colors.error("Need to specify field with -fp or -f2m. (not both)")); diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java index e89d403..2775647 100644 --- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java @@ -52,6 +52,7 @@ public class TextTestWriter extends BaseTextTestWriter { sb.append("═══ ").append(Colors.underline("Card ATR:")).append(" ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator()); sb.append("═══ ").append(Colors.underline("JavaCard version:")).append(" ").append(info.getJavaCardVersion()).append(System.lineSeparator()); sb.append("═══ ").append(Colors.underline("Array sizes (apduBuf, ram, ram2, apduArr):")).append(" ").append(String.format("%d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength())).append(System.lineSeparator()); + sb.append("═══ ").append(Colors.underline("Test options:")).append(" ").append(String.join(",", cardSuite.getCfg().testOptions)).append(System.lineSeparator()); CardMngr.CPLC cplc = cardSuite.getCard().getCPLC(); if (!cplc.values().isEmpty()) { sb.append("═══ ").append(Colors.underline("Card CPLC data:")).append(System.lineSeparator()); diff --git a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java index 5c22607..982e07a 100644 --- a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java @@ -39,7 +39,7 @@ public class CardCofactorSuite extends CardTestSuite { Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS); Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS); - Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS); + Test generate = genOrPreset(curve, ExpectedValue.SUCCESS); Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate); diff --git a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java index d987e05..93d50e8 100644 --- a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java @@ -49,11 +49,18 @@ public class CardCompositeSuite extends CardTestSuite { } tests.add(allocate); tests.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY)); - tests.add(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY)); + + String name; + if (cfg.testOptions.contains("preset")) { + name = "preset semi-random key"; + } else { + name = "generated key"; + } + tests.add(genOrPreset(curve, ExpectedValue.ANY)); for (EC_Key key : curveKeys.getValue()) { Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, key.flatten()); Test ecdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key."); - tests.add(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ", " + key.getDesc(), ecdh)); + tests.add(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ", with " + name + ", " + key.getDesc(), ecdh)); } doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ".", tests.toArray(new Test[0]))); } diff --git a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java index a2ce2ce..b1163c3 100644 --- a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java @@ -56,7 +56,7 @@ public class CardMiscSuite extends CardTestSuite { } Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS); - Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.ANY); + Test generate = genOrPreset(curve, Result.ExpectedValue.ANY); Test ka = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), expected); Test sig = CommandTest.expect(new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), expected); Test perform = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH and ECDSA.", ka, sig); diff --git a/src/cz/crcs/ectester/reader/test/CardTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTestSuite.java index 3578f9c..73acbe7 100644 --- a/src/cz/crcs/ectester/reader/test/CardTestSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardTestSuite.java @@ -1,9 +1,17 @@ package cz.crcs.ectester.reader.test; +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Params; import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.Test; import cz.crcs.ectester.common.test.TestSuite; +import cz.crcs.ectester.common.util.ECUtil; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; +import cz.crcs.ectester.reader.command.Command; /** * @author Jan Jancar johny@neuromancer.sk @@ -21,4 +29,18 @@ public abstract class CardTestSuite extends TestSuite { public CardMngr getCard() { return card; } + + public ECTesterReader.Config getCfg() { + return cfg; + } + + public Test genOrPreset(EC_Curve curve, Result.ExpectedValue expected) { + if (cfg.testOptions.contains("preset")) { + byte[] presetPriv = ECUtil.semiRandomKey(curve); + EC_Params privParms = new EC_Params(EC_Consts.PARAMETER_S, new byte[][]{presetPriv}); + return CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, privParms.getParams(), privParms.flatten()), expected); + } else { + return CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), expected); + } + } } diff --git a/src/cz/crcs/ectester/reader/test/CommandTest.java b/src/cz/crcs/ectester/reader/test/CommandTest.java index adad191..b05d3e4 100644 --- a/src/cz/crcs/ectester/reader/test/CommandTest.java +++ b/src/cz/crcs/ectester/reader/test/CommandTest.java @@ -32,7 +32,7 @@ public class CommandTest extends SimpleTest { @Override public Result apply(CommandTestable commandTestable) { Result.Value resultValue = Result.Value.fromExpected(expected, commandTestable.ok(), commandTestable.error()); - return new Result(resultValue, resultValue.ok() ? ok : nok); + return new Result(resultValue, commandTestable.error() ? commandTestable.errorCause() : (resultValue.ok() ? ok : nok)); } }); } -- cgit v1.2.3-70-g09d2 From 950f5c0fe204d64e3d1b60b1958b0342bfae4f86 Mon Sep 17 00:00:00 2001 From: J08nY Date: Fri, 22 Feb 2019 09:35:18 +0100 Subject: Add signature validation tests. --- .../ectester/reader/test/CardTestVectorSuite.java | 83 ++++++++++++++++++---- 1 file changed, 68 insertions(+), 15 deletions(-) diff --git a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java index 3abcebb..fec1a64 100644 --- a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java @@ -30,6 +30,8 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; import java.util.stream.Collectors; import static cz.crcs.ectester.common.test.Result.ExpectedValue; @@ -96,10 +98,12 @@ public class CardTestVectorSuite extends CardTestSuite { } KeyAgreement ka; + Signature sig; KeyFactory kf; MessageDigest md; try { ka = KeyAgreement.getInstance("ECDH", "BC"); + sig = Signature.getInstance("ECDSAwithSHA1", "BC"); kf = KeyFactory.getInstance("ECDH", "BC"); md = MessageDigest.getInstance("SHA1", "BC"); } catch (NoSuchAlgorithmException | NoSuchProviderException ex) { @@ -119,8 +123,26 @@ public class CardTestVectorSuite extends CardTestSuite { testVector.add(allocate); testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); testVector.add(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS)); - CommandTest export = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR), ExpectedValue.ANY); - testVector.add(export); + CommandTest exportLocal = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W), ExpectedValue.ANY); + CommandTest exportRemote = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PRIVATE, EC_Consts.PARAMETER_S), ExpectedValue.ANY); + testVector.add(exportLocal); + testVector.add(exportRemote); + BiFunction getKeys = (localData, remoteData) -> { + byte[] pkey = localData.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W); + byte[] skey = remoteData.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_S); + ECParameterSpec spec = curve.toSpec(); + ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger(1, skey), spec); + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(ECUtil.fromX962(pkey, curve.toCurve()), spec); + PrivateKey privKey; + PublicKey pubKey; + try { + privKey = kf.generatePrivate(privKeySpec); + pubKey = kf.generatePublic(pubKeySpec); + } catch (InvalidKeySpecException ex) { + return null; + } + return new Key[]{privKey, pubKey}; + }; TestCallback kaCallback = new TestCallback() { @Override public Result apply(CommandTestable testable) { @@ -131,19 +153,17 @@ public class CardTestVectorSuite extends CardTestSuite { return new Result(Value.FAILURE, "ECDH response did not contain the derived secret."); } byte[] secret = ecdhData.getSecret(); - Response.Export keyData = (Response.Export) export.getResponse(); - byte[] pkey = keyData.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W); - byte[] skey = keyData.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_S); - ECParameterSpec spec = curve.toSpec(); - ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger(1, skey), spec); - ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(ECUtil.fromX962(pkey, curve.toCurve()), spec); - PrivateKey privKey; - PublicKey pubkey; + Response.Export localData = (Response.Export) exportLocal.getResponse(); + Response.Export remoteData = (Response.Export) exportRemote.getResponse(); + Key[] keys = getKeys.apply(localData, remoteData); + if (keys == null) { + return new Result(Value.SUCCESS, "Result could not be verified. keyData unavailable."); + } + PrivateKey privKey = (PrivateKey) keys[0]; + PublicKey pubKey = (PublicKey) keys[1]; try { - privKey = kf.generatePrivate(privKeySpec); - pubkey = kf.generatePublic(pubKeySpec); ka.init(privKey); - ka.doPhase(pubkey, true); + ka.doPhase(pubKey, true); byte[] rawDerived = ka.generateSecret(); int fieldSize = (curve.getBits() + 7) / 8; if (rawDerived.length < fieldSize) { @@ -165,12 +185,45 @@ public class CardTestVectorSuite extends CardTestSuite { } else { return new Result(Value.FAILURE, "Derived secret does not match expected value, first difference was at byte " + String.valueOf(diff) + "."); } - } catch (InvalidKeySpecException | InvalidKeyException ex) { + } catch (InvalidKeyException ex) { + return new Result(Value.SUCCESS, "Result could not be verified. " + ex.getMessage()); + } + } + }; + Test ecdhTest = CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), kaCallback); + byte[] data = new byte[32]; + TestCallback sigCallback = new TestCallback() { + @Override + public Result apply(CommandTestable testable) { + Response.ECDSA ecdsaData = (Response.ECDSA) testable.getResponse(); + if (!ecdsaData.successful()) + return new Result(Value.FAILURE, "ECDSA was unsuccessful."); + if (!ecdsaData.hasSignature()) { + return new Result(Value.FAILURE, "ECDSA response did not contain the signature."); + } + byte[] signature = ecdsaData.getSignature(); + Response.Export localData = (Response.Export) exportLocal.getResponse(); + Response.Export remoteData = (Response.Export) exportRemote.getResponse(); + Key[] keys = getKeys.apply(localData, remoteData); + if (keys == null) { + return new Result(Value.SUCCESS, "Result could not be verified. keyData unavailable."); + } + PublicKey pubKey = (PublicKey) keys[1]; + try { + sig.initVerify(pubKey); + sig.update(data); + if (sig.verify(signature)) { + return new Result(Value.SUCCESS, "Signature verified."); + } else { + return new Result(Value.FAILURE, "Signature failed to verify."); + } + } catch (InvalidKeyException | SignatureException ex) { return new Result(Value.SUCCESS, "Result could not be verified. " + ex.getMessage()); } } }; - testVector.add(CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), kaCallback)); + Test ecdsaTest = CommandTest.function(new Command.ECDSA_sign(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_TRUE, data), sigCallback); + testVector.add(CompoundTest.all(ExpectedValue.SUCCESS, "", ecdhTest, ecdsaTest)); if (cfg.cleanup) { testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY)); } -- cgit v1.2.3-70-g09d2 From fea5c7b1cbd539b105b42c4bde65d0b9b6f0b8fc Mon Sep 17 00:00:00 2001 From: J08nY Date: Fri, 22 Feb 2019 10:23:27 +0100 Subject: Make edge-cases suite take preset keys. Reformat code. --- src/cz/crcs/ectester/reader/CardMngr.java | 2 +- src/cz/crcs/ectester/reader/ECTesterReader.java | 2 +- src/cz/crcs/ectester/reader/command/Command.java | 2 +- src/cz/crcs/ectester/reader/output/XMLTestWriter.java | 2 +- src/cz/crcs/ectester/reader/response/Response.java | 10 +++++----- src/cz/crcs/ectester/reader/test/CardDefaultSuite.java | 1 - src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java | 10 +++++----- src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java | 5 ++--- 8 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index 8f88ebb..8b6241d 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -352,7 +352,7 @@ public class CardMngr { return responseAPDU; } - public ResponseAPDU sendAPDU(byte apdu[]) throws CardException { + public ResponseAPDU sendAPDU(byte[] apdu) throws CardException { CommandAPDU commandAPDU = new CommandAPDU(apdu); return sendAPDU(commandAPDU); } diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index dc49656..e5e6061 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -911,7 +911,7 @@ public class ECTesterReader { } format = cli.getOptionValue("format"); - String formats[] = new String[]{"text", "xml", "yaml", "yml"}; + String[] formats = new String[]{"text", "xml", "yaml", "yml"}; if (format != null && !Arrays.asList(formats).contains(format)) { System.err.println(Colors.error("Wrong output format " + format + ". Should be one of " + Arrays.toString(formats))); return false; diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index 1ebd8bb..bf2441f 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -33,7 +33,7 @@ public abstract class Command implements Cloneable { // and for the even more stupid module system, which cannot properly work // with the fact that JCardSim has some java.* packages... final byte[] GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM = new byte[]{0}; - + Command(CardMngr cardManager) { this.cardManager = cardManager; diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java index 9add072..fc41805 100644 --- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java @@ -114,7 +114,7 @@ public class XMLTestWriter extends BaseXMLTestWriter { Response.GetInfo info = new Command.GetInfo(card).send(); result.setAttribute("version", info.getVersion()); result.setAttribute("javacard", String.format("%.1f", info.getJavaCardVersion())); - result.setAttribute("base", String.format("%#x",info.getBase())); + result.setAttribute("base", String.format("%#x", info.getBase())); result.setAttribute("cleanup", String.valueOf(info.getCleanupSupport())); Element arrays = doc.createElement("arrays"); Element apduBuf = doc.createElement("length"); diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index 0dded7c..6232423 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -474,11 +474,11 @@ public abstract class Response { byte major = (byte) (jcVersion >> 8); byte minor = (byte) (jcVersion & 0xff); int minorSize; - if (minor == 0) { - minorSize = 1; - } else { - minorSize = (int) Math.ceil(Math.log10(minor)); - } + if (minor == 0) { + minorSize = 1; + } else { + minorSize = (int) Math.ceil(Math.log10(minor)); + } return (major + ((float) (minor) / (minorSize * 10))); } diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java index 29e2ef9..ebece61 100644 --- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java @@ -10,7 +10,6 @@ import cz.crcs.ectester.common.util.CardUtil; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.response.Response; import javacard.security.KeyPair; import java.util.LinkedList; diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java index f5ea86f..53f3b6b 100644 --- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java @@ -92,7 +92,7 @@ public class CardEdgeCasesSuite extends CardTestSuite { int firstDiff = ByteUtil.diffBytes(dh.getSecret(), 0, value.getData(0), 0, dh.secretLength()); System.err.println(ByteUtil.bytesToHex(dh.getSecret())); System.err.println(ByteUtil.bytesToHex(value.getData(0))); - return new Result(Result.Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + String.valueOf(firstDiff) + "."); + return new Result(Result.Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + firstDiff + "."); } return new Result(Result.Value.SUCCESS); } @@ -154,7 +154,7 @@ public class CardEdgeCasesSuite extends CardTestSuite { continue; } Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS); - Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS); + Test generate = genOrPreset(curve, Result.ExpectedValue.SUCCESS); CommandTest export = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W), Result.ExpectedValue.SUCCESS); Test setup = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate, export)); @@ -162,11 +162,11 @@ public class CardEdgeCasesSuite extends CardTestSuite { BigInteger p = new BigInteger(1, pParam); byte[] wParam = ((Response.Export) export.getResponse()).getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W); byte[] yValue = new byte[(wParam.length - 1) / 2]; - System.arraycopy(wParam, (wParam.length/2) + 1, yValue, 0, yValue.length); + System.arraycopy(wParam, (wParam.length / 2) + 1, yValue, 0, yValue.length); BigInteger y = new BigInteger(1, yValue); BigInteger negY = p.subtract(y); byte[] newY = ECUtil.toByteArray(negY, curve.getBits()); - System.arraycopy(newY, 0, wParam, (wParam.length/2) + 1, newY.length); + System.arraycopy(newY, 0, wParam, (wParam.length / 2) + 1, newY.length); EC_Params negYParams = makeParams(newY); Test negYTest = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, negYParams.getParams(), negYParams.flatten()), "ECDH with pubkey negated.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE); @@ -302,7 +302,7 @@ public class CardEdgeCasesSuite extends CardTestSuite { if (nearR.compareTo(r) >= 0) { rTests[i++] = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearR.toString(16) + " (>=r)", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE); } else { - rTests[i++] = ecdhTestBoth(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearR.toString(16) +" (