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