From 370f65c33992f71b7d21296f0fe44fa1380d4541 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 4 Feb 2018 19:20:08 +0100 Subject: Update README, docs and test suites. --- src/cz/crcs/ectester/standalone/ECTesterStandalone.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index f5361c3..1429826 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -39,7 +39,7 @@ import java.util.stream.Collectors; * Standalone part of ECTester, a tool for testing Elliptic curve implementations in software libraries. * * @author Jan Jancar johny@neuromancer.sk - * @version v0.1.0 + * @version v0.2.0 */ public class ECTesterStandalone { private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib()}; @@ -48,7 +48,7 @@ public class ECTesterStandalone { private Options opts = new Options(); private TreeParser optParser; private TreeCommandLine cli; - private static final String VERSION = "v0.1.0"; + private static final String VERSION = "v0.2.0"; private static final String DESCRIPTION = "ECTesterStandalone " + VERSION + ", an Elliptic Curve Cryptography support tester/utility."; private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda "; private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; @@ -410,7 +410,7 @@ public class ECTesterStandalone { /** * */ - private void test() throws NoSuchAlgorithmException, TestException, ParserConfigurationException { + private void test() throws TestException, ParserConfigurationException { TestWriter writer; switch (cli.getOptionValue("test.format", "text").toLowerCase()) { case "yaml": @@ -434,7 +434,7 @@ public class ECTesterStandalone { * */ private void export() throws NoSuchAlgorithmException, IOException { - ProviderECLibrary lib = (ProviderECLibrary) cfg.selected; + ProviderECLibrary lib = cfg.selected; KeyPairGeneratorIdent ident = null; String algo = cli.getOptionValue("export.type", "EC"); for (KeyPairGeneratorIdent kpIdent : lib.getKPGs()) { -- cgit v1.2.3-70-g09d2 From 8eab5248e36615beae97c7d33bd0c9ac3a87895c Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 4 Feb 2018 19:27:30 +0100 Subject: Bump copyright years. --- LICENSE | 2 +- src/cz/crcs/ectester/applet/ECTesterApplet.java | 3 ++- src/cz/crcs/ectester/reader/ECTesterReader.java | 3 ++- .../ectester/standalone/ECTesterStandalone.java | 22 ++++++++++++++++++++++ 4 files changed, 27 insertions(+), 3 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/LICENSE b/LICENSE index 21ecc94..82e5bee 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016-2017 +Copyright (c) 2016-2018 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index 210b3e7..9689a51 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016-2017 Petr Svenda + * ECTester, tool for testing Elliptic curve cryptography implementations. + * Copyright (c) 2016-2018 Petr Svenda * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 087ec7b..e05f9be 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016-2017 Petr Svenda + * ECTester, tool for testing Elliptic curve cryptography implementations. + * Copyright (c) 2016-2018 Petr Svenda * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 1429826..5f335b9 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -1,3 +1,25 @@ +/* + * ECTester, tool for testing Elliptic curve cryptography implementations. + * Copyright (c) 2016-2018 Petr Svenda + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package cz.crcs.ectester.standalone; import cz.crcs.ectester.common.cli.*; -- cgit v1.2.3-70-g09d2 From 22e4cfaf40a259be007bddc7b5cd765390de1c11 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sat, 10 Feb 2018 19:59:41 +0100 Subject: Handle exceptions in Tests and TestSuites grafeully. --- .../ectester/common/output/BaseTextTestWriter.java | 27 ++- .../ectester/common/output/BaseXMLTestWriter.java | 57 ++++- .../ectester/common/output/BaseYAMLTestWriter.java | 21 +- src/cz/crcs/ectester/common/output/TestWriter.java | 17 ++ src/cz/crcs/ectester/common/test/CompoundTest.java | 102 +++++++-- src/cz/crcs/ectester/common/test/Result.java | 6 +- src/cz/crcs/ectester/common/test/SimpleTest.java | 6 + src/cz/crcs/ectester/common/test/Test.java | 44 ++-- .../crcs/ectester/common/test/TestException.java | 7 +- src/cz/crcs/ectester/common/test/TestSuite.java | 22 +- .../ectester/common/test/TestSuiteException.java | 13 ++ src/cz/crcs/ectester/common/test/Testable.java | 2 +- src/cz/crcs/ectester/common/util/CardUtil.java | 14 ++ src/cz/crcs/ectester/reader/ECTesterReader.java | 5 +- src/cz/crcs/ectester/reader/command/Command.java | 241 ++++++++++++++------- .../ectester/reader/output/TextTestWriter.java | 6 +- .../crcs/ectester/reader/output/XMLTestWriter.java | 11 + .../ectester/reader/output/YAMLTestWriter.java | 7 + src/cz/crcs/ectester/reader/response/Response.java | 194 +++-------------- .../ectester/reader/test/CardWrongCurvesSuite.java | 5 +- src/cz/crcs/ectester/reader/test/CommandTest.java | 18 +- .../crcs/ectester/reader/test/CommandTestable.java | 2 +- .../crcs/ectester/reader/test/PerformanceTest.java | 6 +- .../ectester/standalone/ECTesterStandalone.java | 2 +- .../ectester/standalone/test/KeyAgreementTest.java | 10 - .../standalone/test/KeyAgreementTestable.java | 2 +- .../ectester/standalone/test/KeyGeneratorTest.java | 9 - .../standalone/test/KeyGeneratorTestable.java | 2 +- .../ectester/standalone/test/SignatureTest.java | 10 - .../standalone/test/SignatureTestable.java | 2 +- 30 files changed, 491 insertions(+), 379 deletions(-) create mode 100644 src/cz/crcs/ectester/common/test/TestSuiteException.java (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java index 29eb671..f29d28e 100644 --- a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java @@ -28,11 +28,10 @@ public abstract class BaseTextTestWriter implements TestWriter { protected abstract String deviceString(TestSuite suite); private String testString(Test t, String prefix) { - if (!t.hasRun()) { - return null; - } boolean compound = t instanceof CompoundTest; + Result result = t.getResult(); + StringBuilder out = new StringBuilder(); out.append(t.ok() ? " OK " : "NOK "); out.append(compound ? "┳ " : "━ "); @@ -40,14 +39,14 @@ public abstract class BaseTextTestWriter implements TestWriter { String widthSpec = "%-" + String.valueOf(width) + "s"; out.append(String.format(widthSpec, t.getDescription())); out.append(" ┃ "); - out.append(String.format("%-9s", t.getResultValue().name())); + out.append(String.format("%-9s", result.getValue().name())); out.append(" ┃ "); if (compound) { CompoundTest test = (CompoundTest) t; - out.append(test.getResultCause()); + out.append(result.getCause().toString()); out.append(System.lineSeparator()); - Test[] tests = test.getTests(); + Test[] tests = test.getStartedTests(); for (int i = 0; i < tests.length; ++i) { if (i == tests.length - 1) { out.append(prefix).append(" ┗ "); @@ -76,6 +75,22 @@ public abstract class BaseTextTestWriter implements TestWriter { output.flush(); } + private String errorString(Throwable error) { + StringBuilder sb = new StringBuilder(); + for (Throwable t = error; t != null; t = t.getCause()) { + sb.append("═══ ").append(t.toString()).append(" ═══"); + sb.append(System.lineSeparator()); + } + return sb.toString(); + } + + @Override + public void outputError(Test t, Throwable cause) { + output.println(testString(t, "")); + output.print(errorString(cause)); + output.flush(); + } + @Override public void end() { } diff --git a/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java index f3e9411..5d6d53d 100644 --- a/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java @@ -24,6 +24,7 @@ public abstract class BaseXMLTestWriter implements TestWriter { private DocumentBuilder db; protected Document doc; private Node root; + private Node tests; public BaseXMLTestWriter(OutputStream output) throws ParserConfigurationException { this.output = output; @@ -40,19 +41,55 @@ public abstract class BaseXMLTestWriter implements TestWriter { root = rootElem; doc.appendChild(root); root.appendChild(deviceElement(suite)); + tests = doc.createElement("tests"); + root.appendChild(tests); } protected abstract Element testableElement(Testable t); protected abstract Element deviceElement(TestSuite suite); + private String causeString(Object cause) { + if (cause == null) { + return "null"; + } else if (cause instanceof String) { + return (String) cause; + } else if (cause instanceof Throwable) { + StringBuilder sb = new StringBuilder(); + for (Throwable t = (Throwable) cause; t != null; t = t.getCause()) { + sb.append(t.toString()); + sb.append(System.lineSeparator()); + } + return sb.toString(); + } else { + return cause.toString(); + } + } + + private Element resultElement(Result result) { + Element resultElem = doc.createElement("result"); + + Element ok = doc.createElement("ok"); + ok.setTextContent(String.valueOf(result.ok())); + Element value = doc.createElement("value"); + value.setTextContent(result.getValue().name()); + Element cause = doc.createElement("cause"); + cause.setTextContent(causeString(cause)); + + resultElem.appendChild(ok); + resultElem.appendChild(value); + resultElem.appendChild(cause); + + return resultElem; + } + private Element testElement(Test t) { Element testElem; if (t instanceof CompoundTest) { CompoundTest test = (CompoundTest) t; testElem = doc.createElement("test"); testElem.setAttribute("type", "compound"); - for (Test innerTest : test.getTests()) { + for (Test innerTest : test.getStartedTests()) { testElem.appendChild(testElement(innerTest)); } } else { @@ -64,16 +101,7 @@ public abstract class BaseXMLTestWriter implements TestWriter { description.setTextContent(t.getDescription()); testElem.appendChild(description); - Element result = doc.createElement("result"); - Element ok = doc.createElement("ok"); - ok.setTextContent(String.valueOf(t.ok())); - Element value = doc.createElement("value"); - value.setTextContent(t.getResultValue().name()); - Element cause = doc.createElement("cause"); - cause.setTextContent(t.getResultCause()); - result.appendChild(ok); - result.appendChild(value); - result.appendChild(cause); + Element result = resultElement(t.getResult()); testElem.appendChild(result); return testElem; @@ -83,7 +111,12 @@ public abstract class BaseXMLTestWriter implements TestWriter { public void outputTest(Test t) { if (!t.hasRun()) return; - root.appendChild(testElement(t)); + tests.appendChild(testElement(t)); + } + + @Override + public void outputError(Test t, Throwable cause) { + tests.appendChild(testElement(t)); } @Override diff --git a/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java index 0769e83..1e13082 100644 --- a/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java @@ -41,6 +41,14 @@ public abstract class BaseYAMLTestWriter implements TestWriter { abstract protected Map deviceObject(TestSuite suite); + private Map resultObject(Result result) { + Map resultObject = new HashMap<>(); + resultObject.put("ok", result.ok()); + resultObject.put("value", result.getValue().name()); + resultObject.put("cause", result.getCause()); + return resultObject; + } + private Map testObject(Test t) { Map testObj; if (t instanceof CompoundTest) { @@ -48,7 +56,7 @@ public abstract class BaseYAMLTestWriter implements TestWriter { testObj = new HashMap<>(); testObj.put("type", "compound"); List> innerTests = new LinkedList<>(); - for (Test innerTest : test.getTests()) { + for (Test innerTest : test.getStartedTests()) { innerTests.add(testObject(innerTest)); } testObj.put("tests", innerTests); @@ -58,11 +66,7 @@ public abstract class BaseYAMLTestWriter implements TestWriter { } testObj.put("desc", t.getDescription()); - Map result = new HashMap<>(); - result.put("ok", t.ok()); - result.put("value", t.getResultValue().name()); - result.put("cause", t.getResultCause()); - testObj.put("result", result); + testObj.put("result", resultObject(t.getResult())); return testObj; } @@ -74,6 +78,11 @@ public abstract class BaseYAMLTestWriter implements TestWriter { tests.add(testObject(t)); } + @Override + public void outputError(Test t, Throwable cause) { + tests.add(testObject(t)); + } + @Override public void end() { DumperOptions options = new DumperOptions(); diff --git a/src/cz/crcs/ectester/common/output/TestWriter.java b/src/cz/crcs/ectester/common/output/TestWriter.java index 0ecfd5a..5fa7f67 100644 --- a/src/cz/crcs/ectester/common/output/TestWriter.java +++ b/src/cz/crcs/ectester/common/output/TestWriter.java @@ -7,9 +7,26 @@ import cz.crcs.ectester.common.test.TestSuite; * @author Jan Jancar johny@neuromancer.sk */ public interface TestWriter { + /** + * @param suite + */ void begin(TestSuite suite); + /** + * + * @param t + */ void outputTest(Test t); + /** + * + * @param t + * @param cause + */ + void outputError(Test t, Throwable cause); + + /** + * + */ void end(); } diff --git a/src/cz/crcs/ectester/common/test/CompoundTest.java b/src/cz/crcs/ectester/common/test/CompoundTest.java index 69122b0..4b1df16 100644 --- a/src/cz/crcs/ectester/common/test/CompoundTest.java +++ b/src/cz/crcs/ectester/common/test/CompoundTest.java @@ -2,6 +2,7 @@ package cz.crcs.ectester.common.test; import java.util.Arrays; import java.util.Objects; +import java.util.function.Consumer; import java.util.function.Function; /** @@ -10,26 +11,34 @@ import java.util.function.Function; * @author Jan Jancar johny@neuromancer.sk */ public class CompoundTest extends Test { - private Function callback; + private Function resultCallback; + private Consumer runCallback; private Test[] tests; private String description = ""; - private CompoundTest(Function callback, Test... tests) { - this.callback = callback; + private final static Consumer RUN_ALL = tests -> { + for (Test t : tests) { + t.run(); + } + }; + + private CompoundTest(Function resultCallback, Consumer runCallback, Test... tests) { + this.resultCallback = resultCallback; + this.runCallback = runCallback; this.tests = Arrays.stream(tests).filter(Objects::nonNull).toArray(Test[]::new); } - private CompoundTest(Function callback, String descripiton, Test... tests) { - this(callback, tests); + private CompoundTest(Function callback, Consumer runCallback, String descripiton, Test... tests) { + this(callback, runCallback, tests); this.description = descripiton; } public static CompoundTest function(Function callback, Test... tests) { - return new CompoundTest(callback, tests); + return new CompoundTest(callback, RUN_ALL, tests); } public static CompoundTest function(Function callback, String description, Test... tests) { - return new CompoundTest(callback, description, tests); + return new CompoundTest(callback, RUN_ALL, description, tests); } public static CompoundTest all(Result.ExpectedValue what, Test... all) { @@ -40,7 +49,7 @@ public class CompoundTest extends Test { } } return new Result(Result.Value.SUCCESS, "All sub-tests had the expected result."); - }, all); + }, RUN_ALL, all); } public static CompoundTest all(Result.ExpectedValue what, String description, Test... all) { @@ -49,7 +58,31 @@ public class CompoundTest extends Test { return result; } - public static CompoundTest any(Result.ExpectedValue what, Test... any) { + public static CompoundTest greedyAll(Result.ExpectedValue what, Test... all) { + return new CompoundTest((tests) -> { + for (Test test : tests) { + if (!Result.Value.fromExpected(what, test.ok()).ok()) { + return new Result(Result.Value.FAILURE, "Some sub-tests did not have the expected result."); + } + } + return new Result(Result.Value.SUCCESS, "All sub-tests had the expected result."); + }, (tests) -> { + for (Test t : tests) { + t.run(); + if (!t.ok()) { + break; + } + } + }, all); + } + + public static CompoundTest greedyAll(Result.ExpectedValue what, String description, Test... all) { + CompoundTest result = CompoundTest.greedyAll(what, all); + result.setDescription(description); + return result; + } + + public static CompoundTest greedyAny(Result.ExpectedValue what, Test... any) { return new CompoundTest((tests) -> { for (Test test : tests) { if (Result.Value.fromExpected(what, test.ok()).ok()) { @@ -57,9 +90,33 @@ public class CompoundTest extends Test { } } return new Result(Result.Value.FAILURE, "None of the sub-tests had the expected result."); + }, (tests) -> { + for (Test t : tests) { + t.run(); + if (t.ok()) { + break; + } + } }, any); } + public static CompoundTest greedyAny(Result.ExpectedValue what, String description, Test... any) { + CompoundTest result = CompoundTest.greedyAny(what, any); + result.setDescription(description); + return result; + } + + public static CompoundTest any(Result.ExpectedValue what, Test... any) { + return new CompoundTest((tests) -> { + for (Test test : tests) { + if (Result.Value.fromExpected(what, test.ok()).ok()) { + return new Result(Result.Value.SUCCESS, "Some sub-tests did have the expected result."); + } + } + return new Result(Result.Value.FAILURE, "None of the sub-tests had the expected result."); + }, RUN_ALL, any); + } + public static CompoundTest any(Result.ExpectedValue what, String description, Test... any) { CompoundTest result = CompoundTest.any(what, any); result.setDescription(description); @@ -74,7 +131,7 @@ public class CompoundTest extends Test { } } return new Result(Result.Value.SUCCESS, "All sub-tests matched the expected mask."); - }, masked); + }, RUN_ALL, masked); } public static CompoundTest mask(Result.ExpectedValue[] results, String description, Test... masked) { @@ -84,20 +141,25 @@ public class CompoundTest extends Test { } public Test[] getTests() { - return tests; + return tests.clone(); } - @Override - public void run() throws TestException { - if (hasRun) - return; + public Test[] getRunTests() { + return Arrays.stream(tests).filter(Test::hasRun).toArray(Test[]::new); + } - for (Test test : tests) { - test.run(); - } + public Test[] getStartedTests() { + return Arrays.stream(tests).filter(Test::hasStarted).toArray(Test[]::new); + } - result = callback.apply(tests); - this.hasRun = true; + public Test[] getSkippedTests() { + return Arrays.stream(tests).filter((test) -> !test.hasRun()).toArray(Test[]::new); + } + + @Override + protected void runSelf() { + runCallback.accept(tests); + result = resultCallback.apply(tests); } public void setDescription(String description) { diff --git a/src/cz/crcs/ectester/common/test/Result.java b/src/cz/crcs/ectester/common/test/Result.java index 11fcb4d..5d15a60 100644 --- a/src/cz/crcs/ectester/common/test/Result.java +++ b/src/cz/crcs/ectester/common/test/Result.java @@ -8,13 +8,13 @@ package cz.crcs.ectester.common.test; public class Result { private Value value; - private String cause; + private Object cause; public Result(Value value) { this.value = value; } - public Result(Value value, String cause) { + public Result(Value value, Object cause) { this(value); this.cause = cause; } @@ -23,7 +23,7 @@ public class Result { return value; } - public String getCause() { + public Object getCause() { return cause; } diff --git a/src/cz/crcs/ectester/common/test/SimpleTest.java b/src/cz/crcs/ectester/common/test/SimpleTest.java index f68320a..85f1072 100644 --- a/src/cz/crcs/ectester/common/test/SimpleTest.java +++ b/src/cz/crcs/ectester/common/test/SimpleTest.java @@ -16,4 +16,10 @@ public abstract class SimpleTest extends Test { public T getTestable() { return testable; } + + @Override + protected void runSelf() { + testable.run(); + result = callback.apply(testable); + } } diff --git a/src/cz/crcs/ectester/common/test/Test.java b/src/cz/crcs/ectester/common/test/Test.java index 3d0baf6..868fd22 100644 --- a/src/cz/crcs/ectester/common/test/Test.java +++ b/src/cz/crcs/ectester/common/test/Test.java @@ -9,31 +9,15 @@ import static cz.crcs.ectester.common.test.Result.Value; */ public abstract class Test implements Testable { protected boolean hasRun; + protected boolean hasStarted; protected Result result; public Result getResult() { - if (!hasRun) { - return null; - } return result; } - public Value getResultValue() { - if (!hasRun) { - return null; - } - return result.getValue(); - } - - public String getResultCause() { - if (!hasRun) { - return null; - } - return result.getCause(); - } - public boolean ok() { - if (!hasRun) { + if (result == null) { return true; } return result.ok(); @@ -41,7 +25,7 @@ public abstract class Test implements Testable { @Override public boolean error() { - if (!hasRun) { + if (result == null) { return false; } return result.compareTo(Value.ERROR); @@ -52,15 +36,35 @@ public abstract class Test implements Testable { return hasRun; } + public boolean hasStarted() { + return hasStarted; + } + @Override public void reset() { hasRun = false; + hasStarted = false; result = null; } public abstract String getDescription(); @Override - public abstract void run() throws TestException; + public void run() { + if (hasRun) + return; + try { + hasStarted = true; + runSelf(); + hasRun = true; + } catch (TestException e) { + result = new Result(Value.ERROR, e); + throw e; + } catch (Exception e) { + result = new Result(Value.ERROR, e); + throw new TestException(e); + } + } + protected abstract void runSelf(); } diff --git a/src/cz/crcs/ectester/common/test/TestException.java b/src/cz/crcs/ectester/common/test/TestException.java index 008e9f6..291a073 100644 --- a/src/cz/crcs/ectester/common/test/TestException.java +++ b/src/cz/crcs/ectester/common/test/TestException.java @@ -2,11 +2,12 @@ package cz.crcs.ectester.common.test; /** * A TestException is an Exception that can be thrown during the running of a Testable, - * or a TestSuite. It means that the Testable/TestSuite encountered an unexpected error - * during it's run which points to an error in ECTester or it's runtime environment.cd + * or a Test. It means that the Testable/TestSuite encountered an unexpected error + * and has to terminate. + * * @author Jan Jancar johny@neuromancer.sk */ -public class TestException extends Exception { +public class TestException extends RuntimeException { public TestException(Throwable e) { super(e); } diff --git a/src/cz/crcs/ectester/common/test/TestSuite.java b/src/cz/crcs/ectester/common/test/TestSuite.java index 2de0b9c..ca1b199 100644 --- a/src/cz/crcs/ectester/common/test/TestSuite.java +++ b/src/cz/crcs/ectester/common/test/TestSuite.java @@ -9,6 +9,7 @@ public abstract class TestSuite { protected String name; protected String description; protected TestWriter writer; + private Test running; public TestSuite(TestWriter writer, String name, String description) { this.writer = writer; @@ -16,12 +17,18 @@ public abstract class TestSuite { this.description = description; } - public void run() throws TestException { + /** + * + */ + public void run() { writer.begin(this); try { runTests(); + } catch (TestException e) { + writer.outputError(running, e); } catch (Exception e) { - throw new TestException(e); + writer.end(); + throw new TestSuiteException(e); } writer.end(); } @@ -33,8 +40,10 @@ public abstract class TestSuite { * @return The test that was run. * @throws TestException */ - protected Test runTest(Test t) throws TestException { + protected Test runTest(Test t) { + running = t; t.run(); + running = null; return t; } @@ -45,12 +54,15 @@ public abstract class TestSuite { * @return The test that was run. * @throws TestException */ - protected Test doTest(Test t) throws TestException { - t.run(); + protected Test doTest(Test t) { + runTest(t); writer.outputTest(t); return t; } + /** + * + */ protected abstract void runTests() throws Exception; public String getName() { diff --git a/src/cz/crcs/ectester/common/test/TestSuiteException.java b/src/cz/crcs/ectester/common/test/TestSuiteException.java new file mode 100644 index 0000000..cc3cfda --- /dev/null +++ b/src/cz/crcs/ectester/common/test/TestSuiteException.java @@ -0,0 +1,13 @@ +package cz.crcs.ectester.common.test; + +/** + * An unexpected exception was thrown while running a TestSuite, outside Test + * or a Testable. + * + * @author Jan Jancar johny@neuromancer.sk + */ +public class TestSuiteException extends RuntimeException { + public TestSuiteException(Throwable e) { + super(e); + } +} diff --git a/src/cz/crcs/ectester/common/test/Testable.java b/src/cz/crcs/ectester/common/test/Testable.java index 33c9485..ea1380a 100644 --- a/src/cz/crcs/ectester/common/test/Testable.java +++ b/src/cz/crcs/ectester/common/test/Testable.java @@ -29,5 +29,5 @@ public interface Testable { * * @throws TestException If an unexpected exception/error is encountered. */ - void run() throws TestException; + void run(); } diff --git a/src/cz/crcs/ectester/common/util/CardUtil.java b/src/cz/crcs/ectester/common/util/CardUtil.java index dbe53be..7d7bb78 100644 --- a/src/cz/crcs/ectester/common/util/CardUtil.java +++ b/src/cz/crcs/ectester/common/util/CardUtil.java @@ -281,4 +281,18 @@ public class CardUtil { return ""; } } + + public static String getParameterString(short params) { + String what = ""; + if (params == EC_Consts.PARAMETERS_DOMAIN_F2M || params == EC_Consts.PARAMETERS_DOMAIN_FP) { + what = "curve"; + } else if (params == EC_Consts.PARAMETER_W) { + what = "pubkey"; + } else if (params == EC_Consts.PARAMETER_S) { + what = "privkey"; + } else if (params == EC_Consts.PARAMETERS_KEYPAIR) { + what = "keypair"; + } + return what; + } } diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index e05f9be..22621ef 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -179,7 +179,7 @@ public class ECTesterReader { System.err.println("File " + fnfe.getMessage() + " not found."); } catch (ParseException | IOException ex) { System.err.println(ex.getMessage()); - } catch (CardException | TestException ex) { + } catch (CardException ex) { if (logger != null) logger.println(ex.getMessage()); ex.printStackTrace(); @@ -394,10 +394,9 @@ public class ECTesterReader { /** * Tests Elliptic curve support for a given curve/curves. * - * @throws CardException if APDU transmission fails * @throws IOException if an IO error occurs when writing to key file. */ - private void test() throws IOException, TestException, ParserConfigurationException { + private void test() throws IOException, ParserConfigurationException { TestWriter writer = null; if (cfg.format == null) { writer = new TextTestWriter(logger.getPrintStream()); diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index eefbc27..5e025d8 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -2,15 +2,16 @@ package cz.crcs.ectester.reader.command; 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_Key; +import cz.crcs.ectester.common.ec.EC_Keypair; +import cz.crcs.ectester.common.ec.EC_Params; import cz.crcs.ectester.common.util.ByteUtil; +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.response.Response; -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.ec.EC_Params; import javacard.security.KeyPair; import javax.smartcardio.CardException; @@ -46,6 +47,8 @@ public abstract class Command { return result; } + public abstract String getDescription(); + /** * @param keyPair which keyPair/s (local/remote) to set curve domain parameters on @@ -179,111 +182,117 @@ public abstract class Command { return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, params, data); } - /** * */ - public static class Allocate extends Command { - private byte keyPair; - private short keyLength; - private byte keyClass; + public static class AllocateKeyAgreement extends Command { + private byte kaType; /** - * Creates the INS_ALLOCATE instruction. + * Creates the INS_ALLOCATE_KA instruction. * * @param cardManager cardManager to send APDU through - * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...) - * @param keyLength key length to set - * @param keyClass key class to allocate + * @param kaType which type of KeyAgreement to use */ - public Allocate(CardMngr cardManager, byte keyPair, short keyLength, byte keyClass) { + public AllocateKeyAgreement(CardMngr cardManager, byte kaType) { super(cardManager); - this.keyPair = keyPair; - this.keyLength = keyLength; - this.keyClass = keyClass; - - byte[] data = new byte[]{0, 0, keyClass}; - ByteUtil.setShort(data, 0, keyLength); - this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE, keyPair, 0x00, data); + this.kaType = kaType; + byte[] data = new byte[]{kaType}; + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE_KA, 0x00, 0x00, data); } @Override - public Response.Allocate send() throws CardException { + public Response.AllocateKeyAgreement send() throws CardException { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.Allocate(response, elapsed, keyPair, keyLength, keyClass); + return new Response.AllocateKeyAgreement(response, getDescription(), elapsed, kaType); } @Override - public String toString() { - return "Allocate"; + public String getDescription() { + return String.format("Allocate KeyAgreement(%s) object", CardUtil.getKATypeString(kaType)); } } /** * */ - public static class AllocateKeyAgreement extends Command { - private byte kaType; + public static class AllocateSignature extends Command { + private byte sigType; /** - * Creates the INS_ALLOCATE_KA instruction. + * Creates the INS_ALLOCATE_SIG instruction. * * @param cardManager cardManager to send APDU through - * @param kaType which type of KeyAgreement to use + * @param sigType which type of Signature to use */ - public AllocateKeyAgreement(CardMngr cardManager, byte kaType) { + public AllocateSignature(CardMngr cardManager, byte sigType) { super(cardManager); - this.kaType = kaType; - byte[] data = new byte[]{kaType}; - this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE_KA, 0x00, 0x00, data); + this.sigType = sigType; + byte[] data = new byte[]{sigType}; + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE_SIG, 0x00, 0x00, data); } @Override - public Response.AllocateKeyAgreement send() throws CardException { + public Response.AllocateSignature send() throws CardException { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.AllocateKeyAgreement(response, elapsed, kaType); + return new Response.AllocateSignature(response, getDescription(), elapsed, sigType); } @Override - public String toString() { - return "AllocateKeyAgreement"; + public String getDescription() { + return String.format("Allocate Signature(%s) object", CardUtil.getSigTypeString(sigType)); } } /** * */ - public static class AllocateSignature extends Command { - private byte sigType; + public static class Allocate extends Command { + private byte keyPair; + private short keyLength; + private byte keyClass; /** - * Creates the INS_ALLOCATE_SIG instruction. + * Creates the INS_ALLOCATE instruction. * * @param cardManager cardManager to send APDU through - * @param sigType which type of Signature to use + * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...) + * @param keyLength key length to set + * @param keyClass key class to allocate */ - public AllocateSignature(CardMngr cardManager, byte sigType) { + public Allocate(CardMngr cardManager, byte keyPair, short keyLength, byte keyClass) { super(cardManager); - this.sigType = sigType; - byte[] data = new byte[]{sigType}; - this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE_SIG, 0x00, 0x00, data); + this.keyPair = keyPair; + this.keyLength = keyLength; + this.keyClass = keyClass; + + byte[] data = new byte[]{0, 0, keyClass}; + ByteUtil.setShort(data, 0, keyLength); + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE, keyPair, 0x00, data); } @Override - public Response.AllocateSignature send() throws CardException { + public Response.Allocate send() throws CardException { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.AllocateSignature(response, elapsed, sigType); + return new Response.Allocate(response, getDescription(), elapsed, keyPair, keyLength, keyClass); } @Override - public String toString() { - return "AllocateSignature"; + public String getDescription() { + String field = keyClass == KeyPair.ALG_EC_FP ? "ALG_EC_FP" : "ALG_EC_F2M"; + String key; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + key = "both keypairs"; + } else { + key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return String.format("Allocate %s %db %s", key, keyLength, field); } } @@ -309,12 +318,18 @@ public abstract class Command { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.Clear(response, elapsed, keyPair); + return new Response.Clear(response, getDescription(), elapsed, keyPair); } @Override - public String toString() { - return "Clear"; + public String getDescription() { + String key; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + key = "both keypairs"; + } else { + key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return String.format("Clear %s", key); } } @@ -358,12 +373,32 @@ public abstract class Command { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.Set(response, elapsed, keyPair, curve, params); + return new Response.Set(response, getDescription(), elapsed, keyPair, curve, params); } @Override - public String toString() { - return "Set"; + public String getDescription() { + String name; + switch (curve) { + case EC_Consts.CURVE_default: + name = "default"; + break; + case EC_Consts.CURVE_external: + name = "external"; + break; + default: + name = "custom"; + break; + } + String what = CardUtil.getParameterString(params); + + String pair; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + pair = "both keypairs"; + } else { + pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return String.format("Set %s %s parameters on %s", name, what, pair); } } @@ -402,12 +437,20 @@ public abstract class Command { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.Corrupt(response, elapsed, keyPair, key, params, corruption); + return new Response.Corrupt(response, getDescription(), elapsed, keyPair, key, params, corruption); } @Override - public String toString() { - return "Corrupt"; + public String getDescription() { + String corrupt = CardUtil.getCorruption(corruption); + + String pair; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + pair = "both keypairs"; + } else { + pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return String.format("Corrupt params of %s, %s", pair, corrupt); } } @@ -435,12 +478,18 @@ public abstract class Command { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.Generate(response, elapsed, keyPair); + return new Response.Generate(response, getDescription(), elapsed, keyPair); } @Override - public String toString() { - return "Generate"; + public String getDescription() { + String key; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + key = "both keypairs"; + } else { + key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return String.format("Generate %s", key); } } @@ -477,12 +526,26 @@ public abstract class Command { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.Export(response, elapsed, keyPair, key, params); + return new Response.Export(response, getDescription(), elapsed, keyPair, key, params); } @Override - public String toString() { - return "Export"; + public String getDescription() { + String what = CardUtil.getParameterString(params); + + String source; + if (key == EC_Consts.KEY_BOTH) { + source = "both keys"; + } else { + source = ((key == EC_Consts.KEY_PUBLIC) ? "public" : "private") + " key"; + } + String pair; + if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { + pair = "both keypairs"; + } else { + pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; + } + return String.format("Export %s params from %s of %s", what, source, pair); } } @@ -514,7 +577,7 @@ public abstract class Command { this.corruption = corruption; this.type = type; - byte[] data = new byte[]{export, 0,0, type}; + byte[] data = new byte[]{export, 0, 0, type}; ByteUtil.setShort(data, 1, corruption); this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDH, pubkey, privkey, data); @@ -525,12 +588,23 @@ public abstract class Command { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.ECDH(response, elapsed, pubkey, privkey, export, corruption, type); + return new Response.ECDH(response, getDescription(), elapsed, pubkey, privkey, export, corruption, type); } @Override - public String toString() { - return "ECDH"; + public String getDescription() { + String algo = CardUtil.getKATypeString(type); + + String pub = pubkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; + String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; + + String validity; + if (corruption == EC_Consts.CORRUPTION_NONE) { + validity = "unchanged"; + } else { + validity = CardUtil.getCorruption(corruption); + } + return String.format("%s of %s pubkey and %s privkey(%s point)", algo, pub, priv, validity); } } @@ -575,12 +649,22 @@ public abstract class Command { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.ECDH(response, elapsed, ECTesterApplet.KEYPAIR_REMOTE, privkey, export, corruption, type); + return new Response.ECDH(response, getDescription(), elapsed, ECTesterApplet.KEYPAIR_REMOTE, privkey, export, corruption, type); } @Override - public String toString() { - return "ECDH_direct"; + public String getDescription() { + String algo = CardUtil.getKATypeString(type); + + String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; + + String validity; + if (corruption == EC_Consts.CORRUPTION_NONE) { + validity = "unchanged"; + } else { + validity = CardUtil.getCorruption(corruption); + } + return String.format("%s of external pubkey and %s privkey(%s point)", algo, priv, validity); } } @@ -622,12 +706,15 @@ public abstract class Command { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.ECDSA(response, elapsed, keyPair, sigType, export, raw); + return new Response.ECDSA(response, getDescription(), elapsed, keyPair, sigType, export, raw); } @Override - public String toString() { - return "ECDSA"; + public String getDescription() { + String algo = CardUtil.getSigTypeString(sigType); + String key = keyPair == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; + String data = raw == null ? "random" : "provided"; + return String.format("%s with %s keypair(%s data)", algo, key, data); } } @@ -650,12 +737,12 @@ public abstract class Command { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.Cleanup(response, elapsed); + return new Response.Cleanup(response, getDescription(), elapsed); } @Override - public String toString() { - return "Cleanup"; + public String getDescription() { + return "Request JCSystem object deletion"; } } } diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java index eb52937..cc168de 100644 --- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java @@ -5,6 +5,7 @@ import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.reader.test.CardTestSuite; import cz.crcs.ectester.reader.test.CommandTestable; @@ -27,7 +28,10 @@ public class TextTestWriter extends BaseTextTestWriter { protected String testableString(Testable t) { if (t instanceof CommandTestable) { CommandTestable cmd = (CommandTestable) t; - return writer.responseSuffix(cmd.getResponse()); + Response response = cmd.getResponse(); + if (response != null) { + return writer.responseSuffix(response); + } } return ""; } diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java index d3674e8..ebe07a6 100644 --- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java @@ -26,16 +26,27 @@ public class XMLTestWriter extends BaseXMLTestWriter { private Element commandElement(Command c) { Element commandElem = doc.createElement("command"); + if (c == null) { + return commandElem; + } Element apdu = doc.createElement("apdu"); apdu.setTextContent(ByteUtil.bytesToHex(c.getAPDU().getBytes())); commandElem.appendChild(apdu); + Element description = doc.createElement("desc"); + description.setTextContent(c.getDescription()); + commandElem.appendChild(description); + return commandElem; } private Element responseElement(Response r) { Element responseElem = doc.createElement("response"); + if (r == null) { + return responseElem; + } + responseElem.setAttribute("successful", r.successful() ? "true" : "false"); Element apdu = doc.createElement("apdu"); diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java index 199f2c0..4f83ca8 100644 --- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java @@ -27,12 +27,19 @@ public class YAMLTestWriter extends BaseYAMLTestWriter { private Map commandObject(Command c) { Map commandObj = new HashMap<>(); + if (c == null) { + return commandObj; + } commandObj.put("apdu", ByteUtil.bytesToHex(c.getAPDU().getBytes())); + commandObj.put("desc", c.getDescription()); return commandObj; } private Map responseObject(Response r) { Map responseObj = new HashMap<>(); + if (r == null) { + return responseObj; + } responseObj.put("successful", r.successful()); responseObj.put("apdu", ByteUtil.bytesToHex(r.getAPDU().getBytes())); responseObj.put("natural_sw", Short.toUnsignedInt(r.getNaturalSW())); diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index 1ae59de..5a9a458 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -3,9 +3,7 @@ package cz.crcs.ectester.reader.response; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.common.util.ByteUtil; -import cz.crcs.ectester.common.util.CardUtil; import javacard.framework.ISO7816; -import javacard.security.KeyPair; import javax.smartcardio.ResponseAPDU; @@ -20,9 +18,11 @@ public abstract class Response { private byte[][] params; private boolean success = true; private boolean error = false; + private String description; - public Response(ResponseAPDU response, long time) { + public Response(ResponseAPDU response, String description, long time) { this.resp = response; + this.description = description; this.time = time; } @@ -127,7 +127,9 @@ public abstract class Response { return this.error; } - public abstract String getDescription(); + public String getDescription() { + return description; + } /** * @@ -135,17 +137,12 @@ public abstract class Response { public static class AllocateKeyAgreement extends Response { private byte kaType; - public AllocateKeyAgreement(ResponseAPDU response, long time, byte kaType) { - super(response, time); + public AllocateKeyAgreement(ResponseAPDU response, String description, long time, byte kaType) { + super(response, description, time); this.kaType = kaType; parse(1, 0); } - - @Override - public String getDescription() { - return String.format("Allocated KeyAgreement(%s) object", CardUtil.getKATypeString(this.kaType)); - } } /** @@ -154,17 +151,12 @@ public abstract class Response { public static class AllocateSignature extends Response { private byte sigType; - public AllocateSignature(ResponseAPDU response, long time, byte sigType) { - super(response, time); + public AllocateSignature(ResponseAPDU response, String description, long time, byte sigType) { + super(response, description, time); this.sigType = sigType; parse(1, 0); } - - @Override - public String getDescription() { - return String.format("Allocated Signature(%s) object", CardUtil.getSigTypeString(this.sigType)); - } } /** @@ -175,8 +167,8 @@ public abstract class Response { private short keyLength; private byte keyClass; - public Allocate(ResponseAPDU response, long time, byte keyPair, short keyLength, byte keyClass) { - super(response, time); + public Allocate(ResponseAPDU response, String description, long time, byte keyPair, short keyLength, byte keyClass) { + super(response, description, time); this.keyPair = keyPair; this.keyLength = keyLength; this.keyClass = keyClass; @@ -186,18 +178,6 @@ public abstract class Response { if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++; parse(pairs, 0); } - - @Override - public String getDescription() { - String field = keyClass == KeyPair.ALG_EC_FP ? "ALG_EC_FP" : "ALG_EC_F2M"; - String key; - if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { - key = "both keypairs"; - } else { - key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; - } - return String.format("Allocated %s %db %s", key, keyLength, field); - } } /** @@ -206,8 +186,8 @@ public abstract class Response { public static class Clear extends Response { private byte keyPair; - public Clear(ResponseAPDU response, long time, byte keyPair) { - super(response, time); + public Clear(ResponseAPDU response, String description, long time, byte keyPair) { + super(response, description, time); this.keyPair = keyPair; int pairs = 0; @@ -215,17 +195,6 @@ public abstract class Response { if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++; parse(pairs, 0); } - - @Override - public String getDescription() { - String key; - if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { - key = "both keypairs"; - } else { - key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; - } - return String.format("Cleared %s", key); - } } /** @@ -236,8 +205,8 @@ public abstract class Response { private byte curve; private short parameters; - public Set(ResponseAPDU response, long time, byte keyPair, byte curve, short parameters) { - super(response, time); + public Set(ResponseAPDU response, String description, long time, byte keyPair, byte curve, short parameters) { + super(response, description, time); this.keyPair = keyPair; this.curve = curve; this.parameters = parameters; @@ -248,41 +217,6 @@ public abstract class Response { parse(pairs, 0); } - - @Override - public String getDescription() { - String name; - switch (curve) { - case EC_Consts.CURVE_default: - name = "default"; - break; - case EC_Consts.CURVE_external: - name = "external"; - break; - default: - name = "custom"; - break; - } - String what = ""; - if (parameters == EC_Consts.PARAMETERS_DOMAIN_F2M || parameters == EC_Consts.PARAMETERS_DOMAIN_FP) { - what = "curve"; - } else if (parameters == EC_Consts.PARAMETER_W) { - what = "pubkey"; - } else if (parameters == EC_Consts.PARAMETER_S) { - what = "privkey"; - } else if (parameters == EC_Consts.PARAMETERS_KEYPAIR) { - what = "keypair"; - } - - String pair; - if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { - pair = "both keypairs"; - } else { - pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; - } - return String.format("Set %s %s parameters on %s", name, what, pair); - } - } /** @@ -294,8 +228,8 @@ public abstract class Response { private short params; private short corruption; - public Corrupt(ResponseAPDU response, long time, byte keyPair, byte key, short params, short corruption) { - super(response, time); + public Corrupt(ResponseAPDU response, String description, long time, byte keyPair, byte key, short params, short corruption) { + super(response, description, time); this.keyPair = keyPair; this.key = key; this.params = params; @@ -307,19 +241,6 @@ public abstract class Response { parse(pairs, 0); } - - @Override - public String getDescription() { - String corrupt = CardUtil.getCorruption(corruption); - - String pair; - if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { - pair = "both keypairs"; - } else { - pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; - } - return String.format("Corrupted params of %s, %s", pair, corrupt); - } } /** @@ -328,8 +249,8 @@ public abstract class Response { public static class Generate extends Response { private byte keyPair; - public Generate(ResponseAPDU response, long time, byte keyPair) { - super(response, time); + public Generate(ResponseAPDU response, String description, long time, byte keyPair) { + super(response, description, time); this.keyPair = keyPair; int generated = 0; @@ -337,18 +258,6 @@ public abstract class Response { if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) generated++; parse(generated, 0); } - - @Override - public String getDescription() { - String key; - if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { - key = "both keypairs"; - } else { - key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; - } - return String.format("Generated %s", key); - } - } /** @@ -359,8 +268,8 @@ public abstract class Response { private byte key; private short parameters; - public Export(ResponseAPDU response, long time, byte keyPair, byte key, short parameters) { - super(response, time); + public Export(ResponseAPDU response, String description, long time, byte keyPair, byte key, short parameters) { + super(response, description, time); this.keyPair = keyPair; this.key = key; this.parameters = parameters; @@ -440,23 +349,6 @@ public abstract class Response { public byte[] getParameter(byte keyPair, short param) { return getParam(getIndex(keyPair, param)); } - - @Override - public String getDescription() { - String source; - if (key == EC_Consts.KEY_BOTH) { - source = "both keys"; - } else { - source = ((key == EC_Consts.KEY_PUBLIC) ? "public" : "private") + " key"; - } - String pair; - if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { - pair = "both keypairs"; - } else { - pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; - } - return String.format("Exported params from %s of %s", source, pair); - } } /** @@ -469,8 +361,8 @@ public abstract class Response { private short corruption; private byte type; - public ECDH(ResponseAPDU response, long time, byte pubkey, byte privkey, byte export, short corruption, byte type) { - super(response, time); + public ECDH(ResponseAPDU response, String description, long time, byte pubkey, byte privkey, byte export, short corruption, byte type) { + super(response, description, time); this.pubkey = pubkey; this.privkey = privkey; this.export = export; @@ -491,22 +383,6 @@ public abstract class Response { public int secretLength() { return getParamLength(0); } - - @Override - public String getDescription() { - String algo = CardUtil.getKATypeString(type); - - String pub = pubkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; - String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; - - String validity; - if (corruption == EC_Consts.CORRUPTION_NONE) { - validity = "unchanged"; - } else { - validity = CardUtil.getCorruption(corruption); - } - return String.format("%s of %s pubkey and %s privkey(%s point)", algo, pub, priv, validity); - } } /** @@ -518,8 +394,8 @@ public abstract class Response { private byte export; private byte[] raw; - public ECDSA(ResponseAPDU response, long time, byte keyPair, byte sigType, byte export, byte[] raw) { - super(response, time); + public ECDSA(ResponseAPDU response, String description, long time, byte keyPair, byte sigType, byte export, byte[] raw) { + super(response, description, time); this.keyPair = keyPair; this.sigType = sigType; this.export = export; @@ -535,14 +411,6 @@ public abstract class Response { public byte[] getSignature() { return getParam(0); } - - @Override - public String getDescription() { - String algo = CardUtil.getSigTypeString(sigType); - String key = keyPair == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; - String data = raw == null ? "random" : "provided"; - return String.format("%s with %s keypair(%s data)", algo, key, data); - } } /** @@ -550,16 +418,10 @@ public abstract class Response { */ public static class Cleanup extends Response { - public Cleanup(ResponseAPDU response, long time) { - super(response, time); + public Cleanup(ResponseAPDU response, String description, long time) { + super(response, description, time); parse(1, 0); } - - @Override - public String getDescription() { - return "Requested JCSystem object deletion"; - } - } } diff --git a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java index 1c3ad94..4706bdd 100644 --- a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java @@ -8,7 +8,6 @@ import cz.crcs.ectester.common.output.TestWriter; import cz.crcs.ectester.common.test.CompoundTest; import cz.crcs.ectester.common.test.Result; import cz.crcs.ectester.common.test.Test; -import cz.crcs.ectester.common.test.TestException; import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.common.util.CardUtil; import cz.crcs.ectester.common.util.ECUtil; @@ -44,7 +43,7 @@ public class CardWrongCurvesSuite extends CardTestSuite { List tests = new LinkedList<>(); Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS)); if (!key.ok()) { - doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()), key)); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()), key)); continue; } tests.add(key); @@ -143,7 +142,7 @@ public class CardWrongCurvesSuite extends CardTestSuite { */ } - private Test ecdhTest(Command setupCmd, String prepareDesc, String fullDesc) throws TestException { + private Test ecdhTest(Command setupCmd, String prepareDesc, String fullDesc) { Test setup = runTest(CommandTest.expect(setupCmd, Result.ExpectedValue.FAILURE)); Test generate = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.FAILURE)); Test preparePhase = runTest(CompoundTest.any(Result.ExpectedValue.SUCCESS, prepareDesc, setup, generate)); diff --git a/src/cz/crcs/ectester/reader/test/CommandTest.java b/src/cz/crcs/ectester/reader/test/CommandTest.java index a08d820..d57dc17 100644 --- a/src/cz/crcs/ectester/reader/test/CommandTest.java +++ b/src/cz/crcs/ectester/reader/test/CommandTest.java @@ -3,13 +3,14 @@ package cz.crcs.ectester.reader.test; 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.command.Command; import cz.crcs.ectester.reader.response.Response; /** * A simple test that runs one Command to get and evaluate one Response * to get a Result and compare it with the expected one. + * + * @author Jan Jancar johny@neuromancer.sk */ public class CommandTest extends SimpleTest { private CommandTest(CommandTestable command, TestCallback callback) { @@ -28,8 +29,7 @@ public class CommandTest extends SimpleTest { return new CommandTest(command, new TestCallback() { @Override public Result apply(CommandTestable commandTestable) { - Response resp = commandTestable.getResponse(); - Result.Value resultValue = Result.Value.fromExpected(expected, resp.successful(), resp.error()); + Result.Value resultValue = Result.Value.fromExpected(expected, commandTestable.ok(), commandTestable.error()); return new Result(resultValue, resultValue.ok() ? ok : nok); } }); @@ -55,22 +55,12 @@ public class CommandTest extends SimpleTest { return testable.getResponse(); } - @Override - public void run() throws TestException { - if (hasRun) - return; - - testable.run(); - result = callback.apply(testable); - hasRun = true; - } - @Override public String getDescription() { if (hasRun) { return testable.getResponse().getDescription(); } else { - return testable.getCommand().toString(); + return testable.getCommand().getDescription(); } } } diff --git a/src/cz/crcs/ectester/reader/test/CommandTestable.java b/src/cz/crcs/ectester/reader/test/CommandTestable.java index 3bb55bf..f670534 100644 --- a/src/cz/crcs/ectester/reader/test/CommandTestable.java +++ b/src/cz/crcs/ectester/reader/test/CommandTestable.java @@ -27,7 +27,7 @@ public class CommandTestable extends BaseTestable { } @Override - public void run() throws TestException { + public void run() { try { response = command.send(); } catch (CardException e) { diff --git a/src/cz/crcs/ectester/reader/test/PerformanceTest.java b/src/cz/crcs/ectester/reader/test/PerformanceTest.java index 4a27bad..2e5f376 100644 --- a/src/cz/crcs/ectester/reader/test/PerformanceTest.java +++ b/src/cz/crcs/ectester/reader/test/PerformanceTest.java @@ -38,10 +38,7 @@ public class PerformanceTest extends SimpleTest { } @Override - public void run() throws TestException { - if (hasRun) - return; - + protected void runSelf() { times = new long[count]; for (int i = 0; i < count; ++i) { testable.run(); @@ -73,7 +70,6 @@ public class PerformanceTest extends SimpleTest { mode = current_value; } } - hasRun = true; result = callback.apply(testable); } diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 5f335b9..498fce1 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -120,7 +120,7 @@ public class ECTesterStandalone { } catch (NoSuchAlgorithmException nsaex) { System.err.println("Algorithm not supported by the selected library: " + nsaex.getMessage()); nsaex.printStackTrace(); - } catch (InvalidKeyException | SignatureException | TestException e) { + } catch (InvalidKeyException | SignatureException e) { e.printStackTrace(); } } diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java index 5f697c4..7672c4b 100644 --- a/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java +++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java @@ -3,7 +3,6 @@ package cz.crcs.ectester.standalone.test; 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 java.util.Arrays; @@ -45,13 +44,4 @@ public class KeyAgreementTest extends SimpleTest { public String getDescription() { return "KeyAgreement " + testable.getKa().getAlgorithm(); } - - @Override - public void run() throws TestException { - if (hasRun) - return; - testable.run(); - result = callback.apply(testable); - hasRun = true; - } } diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java index de9356b..8a635e0 100644 --- a/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java +++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java @@ -70,7 +70,7 @@ public class KeyAgreementTestable extends BaseTestable { } @Override - public void run() throws TestException { + public void run() { if (kgtPrivate != null) { privateKey = (ECPrivateKey) kgtPrivate.getKeyPair().getPrivate(); } diff --git a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java index 93273ca..a27c088 100644 --- a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java +++ b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java @@ -30,13 +30,4 @@ public class KeyGeneratorTest extends SimpleTest { public String getDescription() { return "KeyPairGenerator " + testable.getKpg().getAlgorithm(); } - - @Override - public void run() throws TestException { - if (hasRun) - return; - testable.run(); - result = callback.apply(testable); - hasRun = true; - } } diff --git a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java index c2fec5a..353e87a 100644 --- a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java +++ b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java @@ -40,7 +40,7 @@ public class KeyGeneratorTestable extends BaseTestable { } @Override - public void run() throws TestException { + public void run() { try { if (spec != null) { kpg.initialize(spec); diff --git a/src/cz/crcs/ectester/standalone/test/SignatureTest.java b/src/cz/crcs/ectester/standalone/test/SignatureTest.java index 9746b91..74c06f0 100644 --- a/src/cz/crcs/ectester/standalone/test/SignatureTest.java +++ b/src/cz/crcs/ectester/standalone/test/SignatureTest.java @@ -3,7 +3,6 @@ package cz.crcs.ectester.standalone.test; 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; /** * @author Jan Jancar johny@neuromancer.sk @@ -30,13 +29,4 @@ public class SignatureTest extends SimpleTest { public String getDescription() { return "Signature " + testable.getSig().getAlgorithm(); } - - @Override - public void run() throws TestException { - if (hasRun) - return; - testable.run(); - result = callback.apply(testable); - hasRun = true; - } } diff --git a/src/cz/crcs/ectester/standalone/test/SignatureTestable.java b/src/cz/crcs/ectester/standalone/test/SignatureTestable.java index 7b26af7..c77e9c5 100644 --- a/src/cz/crcs/ectester/standalone/test/SignatureTestable.java +++ b/src/cz/crcs/ectester/standalone/test/SignatureTestable.java @@ -56,7 +56,7 @@ public class SignatureTestable extends BaseTestable { } @Override - public void run() throws TestException { + public void run() { if (kgt != null) { signKey = (ECPrivateKey) kgt.getKeyPair().getPrivate(); verifyKey = (ECPublicKey) kgt.getKeyPair().getPublic(); -- cgit v1.2.3-70-g09d2 From 7e936e9d7c67c6b5162e10a1fe8b0d6086ccb72b Mon Sep 17 00:00:00 2001 From: J08nY Date: Sat, 3 Mar 2018 21:34:15 +0100 Subject: Fix selection of EC libs in standalone tester. --- src/cz/crcs/ectester/standalone/ECTesterStandalone.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 498fce1..caf99ae 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -517,7 +517,7 @@ public class ECTesterStandalone { if (libraryName != null) { List matchedLibs = new LinkedList<>(); for (ProviderECLibrary lib : libs) { - if (lib.name().toLowerCase().contains(libraryName.toLowerCase())) { + if (lib.isInitialized() && lib.name().toLowerCase().contains(libraryName.toLowerCase())) { matchedLibs.add(lib); } } -- cgit v1.2.3-70-g09d2 From 89ddc1ec043075dbd19c2ec0bcd77b9b83302837 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 25 Apr 2018 14:10:23 +0200 Subject: Add ECTester version to test run output. --- src/cz/crcs/ectester/reader/ECTesterReader.java | 4 ++-- src/cz/crcs/ectester/reader/output/TextTestWriter.java | 2 ++ src/cz/crcs/ectester/reader/output/XMLTestWriter.java | 2 ++ src/cz/crcs/ectester/reader/output/YAMLTestWriter.java | 2 ++ src/cz/crcs/ectester/standalone/ECTesterStandalone.java | 4 ++-- src/cz/crcs/ectester/standalone/output/TextTestWriter.java | 6 +++++- src/cz/crcs/ectester/standalone/output/XMLTestWriter.java | 2 ++ src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java | 2 ++ 8 files changed, 19 insertions(+), 5 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 84c0439..e982721 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -66,9 +66,9 @@ public class ECTesterReader { private Config cfg; private Options opts = new Options(); - private static final String VERSION = "v0.2.0"; + public static final String VERSION = "v0.2.0"; private static final String DESCRIPTION = "ECTesterReader " + VERSION + ", a javacard Elliptic Curve Cryptography support tester/utility."; - private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda "; + private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2018 Petr Svenda "; private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; private static final String CLI_FOOTER = "\n" + LICENSE; diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java index cc168de..1dd21ae 100644 --- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java @@ -5,6 +5,7 @@ import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.reader.test.CardTestSuite; import cz.crcs.ectester.reader.test.CommandTestable; @@ -41,6 +42,7 @@ public class TextTestWriter extends BaseTextTestWriter { if (suite instanceof CardTestSuite) { CardTestSuite cardSuite = (CardTestSuite) suite; StringBuilder sb = new StringBuilder(); + sb.append("═══ ECTester version: " + ECTesterReader.VERSION).append(System.lineSeparator()); sb.append("═══ Card ATR: ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator()); try { CardMngr.CPLC cplc = cardSuite.getCard().getCPLC(); diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java index ebe07a6..14b7763 100644 --- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java @@ -5,6 +5,7 @@ import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; 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 cz.crcs.ectester.reader.test.CardTestSuite; @@ -113,6 +114,7 @@ public class XMLTestWriter extends BaseXMLTestWriter { CardTestSuite cardSuite = (CardTestSuite) suite; Element result = doc.createElement("device"); result.setAttribute("type", "card"); + result.setAttribute("ectester", ECTesterReader.VERSION); result.appendChild(cplcElement(cardSuite.getCard())); Element atr = doc.createElement("ATR"); diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java index 4f83ca8..4c908cc 100644 --- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java @@ -5,6 +5,7 @@ import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; 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 cz.crcs.ectester.reader.test.CardTestSuite; @@ -88,6 +89,7 @@ public class YAMLTestWriter extends BaseYAMLTestWriter { CardTestSuite cardSuite = (CardTestSuite) suite; Map result = new HashMap<>(); result.put("type", "card"); + result.put("ectester", ECTesterReader.VERSION); result.put("cplc", cplcObject(cardSuite.getCard())); result.put("ATR", ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)); return result; diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index caf99ae..5f2a420 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -70,9 +70,9 @@ public class ECTesterStandalone { private Options opts = new Options(); private TreeParser optParser; private TreeCommandLine cli; - private static final String VERSION = "v0.2.0"; + public static final String VERSION = "v0.2.0"; private static final String DESCRIPTION = "ECTesterStandalone " + VERSION + ", an Elliptic Curve Cryptography support tester/utility."; - private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda "; + private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2018 Petr Svenda "; private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; private static final String CLI_FOOTER = "\n" + LICENSE; diff --git a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java index 716451b..26e1b1a 100644 --- a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java @@ -3,6 +3,7 @@ package cz.crcs.ectester.standalone.output; import cz.crcs.ectester.common.output.BaseTextTestWriter; import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; +import cz.crcs.ectester.standalone.ECTesterStandalone; import cz.crcs.ectester.standalone.test.StandaloneTestSuite; import java.io.PrintStream; @@ -25,7 +26,10 @@ public class TextTestWriter extends BaseTextTestWriter { protected String deviceString(TestSuite suite) { if (suite instanceof StandaloneTestSuite) { StandaloneTestSuite standaloneSuite = (StandaloneTestSuite) suite; - return standaloneSuite.getLibrary().name(); + StringBuilder sb = new StringBuilder(); + sb.append("═══ ECTester version: " + ECTesterStandalone.VERSION).append(System.lineSeparator()); + sb.append("═══ " + standaloneSuite.getLibrary().name()).append(System.lineSeparator()); + return sb.toString(); } return ""; } diff --git a/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java b/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java index 63838cb..2a35ce3 100644 --- a/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java @@ -4,6 +4,7 @@ import cz.crcs.ectester.common.output.BaseXMLTestWriter; import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.standalone.ECTesterStandalone; import cz.crcs.ectester.standalone.test.KeyAgreementTestable; import cz.crcs.ectester.standalone.test.KeyGeneratorTestable; import cz.crcs.ectester.standalone.test.SignatureTestable; @@ -118,6 +119,7 @@ public class XMLTestWriter extends BaseXMLTestWriter { StandaloneTestSuite standaloneSuite = (StandaloneTestSuite) suite; Element result = doc.createElement("device"); result.setAttribute("type", "library"); + result.setAttribute("ectester", ECTesterStandalone.VERSION); Element name = doc.createElement("name"); name.setTextContent(standaloneSuite.getLibrary().name()); diff --git a/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java b/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java index 1ec132d..c452133 100644 --- a/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java @@ -4,6 +4,7 @@ import cz.crcs.ectester.common.output.BaseYAMLTestWriter; import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.standalone.ECTesterStandalone; import cz.crcs.ectester.standalone.test.KeyAgreementTestable; import cz.crcs.ectester.standalone.test.KeyGeneratorTestable; import cz.crcs.ectester.standalone.test.SignatureTestable; @@ -97,6 +98,7 @@ public class YAMLTestWriter extends BaseYAMLTestWriter { StandaloneTestSuite standaloneSuite = (StandaloneTestSuite) suite; Map result = new HashMap<>(); result.put("type", "library"); + result.put("ectester", ECTesterStandalone.VERSION); result.put("name", standaloneSuite.getLibrary().name()); return result; } -- cgit v1.2.3-70-g09d2 From 90dcc61a9a9f47b93e043eba54602a96c26fce6f Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 28 May 2018 17:56:59 +0200 Subject: Add support for naming a curve to use by a library in standalone. --- src/cz/crcs/ectester/common/test/BaseTestable.java | 6 ++ src/cz/crcs/ectester/common/test/Test.java | 8 +++ src/cz/crcs/ectester/common/test/Testable.java | 5 ++ .../ectester/standalone/ECTesterStandalone.java | 27 ++++++-- .../standalone/test/KeyAgreementTestable.java | 79 +++++++++++----------- 5 files changed, 80 insertions(+), 45 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/src/cz/crcs/ectester/common/test/BaseTestable.java b/src/cz/crcs/ectester/common/test/BaseTestable.java index a4b9a00..979b2a4 100644 --- a/src/cz/crcs/ectester/common/test/BaseTestable.java +++ b/src/cz/crcs/ectester/common/test/BaseTestable.java @@ -7,6 +7,7 @@ public abstract class BaseTestable implements Testable { protected boolean hasRun; protected boolean ok; protected boolean error; + protected Object errorCause; @Override public boolean hasRun() { @@ -23,6 +24,11 @@ public abstract class BaseTestable implements Testable { return error; } + @Override + public Object errorCause() { + return errorCause; + } + @Override public void reset() { hasRun = false; diff --git a/src/cz/crcs/ectester/common/test/Test.java b/src/cz/crcs/ectester/common/test/Test.java index 868fd22..055ec1c 100644 --- a/src/cz/crcs/ectester/common/test/Test.java +++ b/src/cz/crcs/ectester/common/test/Test.java @@ -31,6 +31,14 @@ public abstract class Test implements Testable { return result.compareTo(Value.ERROR); } + @Override + public Object errorCause() { + if (result == null || !result.compareTo(Value.ERROR)) { + return null; + } + return result.getCause(); + } + @Override public boolean hasRun() { return hasRun; diff --git a/src/cz/crcs/ectester/common/test/Testable.java b/src/cz/crcs/ectester/common/test/Testable.java index ea1380a..7b4545c 100644 --- a/src/cz/crcs/ectester/common/test/Testable.java +++ b/src/cz/crcs/ectester/common/test/Testable.java @@ -14,6 +14,11 @@ public interface Testable { */ boolean error(); + /** + * @return The cause of an error, if it happened, otherwise null. + */ + Object errorCause(); + /** * @return Whether this runnable was run. */ diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 5f2a420..56dde42 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -53,6 +53,7 @@ import java.security.*; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; import java.util.*; import java.util.stream.Collectors; @@ -128,12 +129,14 @@ public class ECTesterStandalone { private TreeCommandLine parseArgs(String[] args) throws ParseException { Map actions = new TreeMap<>(); - Option namedCurve = Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: ").hasArg().argName("cat/id").build(); + Option namedCurve = Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: ").hasArg().argName("cat/id").optionalArg(false).build(); + Option curveName = Option.builder("cn").longOpt("curve-name").desc("Use a named curve, search from curves supported by the library: ").hasArg().argName("name").optionalArg(false).build(); Option bits = Option.builder("b").longOpt("bits").hasArg().argName("n").optionalArg(false).desc("What size of curve to use.").build(); Options testOpts = new Options(); testOpts.addOption(bits); testOpts.addOption(namedCurve); + testOpts.addOption(curveName); testOpts.addOption(Option.builder("gt").longOpt("kpg-type").desc("Set the KeyPairGenerator object [type].").hasArg().argName("type").optionalArg(false).build()); testOpts.addOption(Option.builder("kt").longOpt("ka-type").desc("Set the KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build()); testOpts.addOption(Option.builder("st").longOpt("sig-type").desc("Set the Signature object [type].").hasArg().argName("type").optionalArg(false).build()); @@ -146,6 +149,7 @@ public class ECTesterStandalone { Options ecdhOpts = new Options(); ecdhOpts.addOption(bits); ecdhOpts.addOption(namedCurve); + ecdhOpts.addOption(curveName); ecdhOpts.addOption(Option.builder("t").longOpt("type").desc("Set KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build()); ecdhOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDH [amount] times.").build()); ParserOptions ecdh = new ParserOptions(new DefaultParser(), ecdhOpts); @@ -154,6 +158,7 @@ public class ECTesterStandalone { Options ecdsaOpts = new Options(); ecdsaOpts.addOption(bits); ecdsaOpts.addOption(namedCurve); + ecdsaOpts.addOption(curveName); 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()); @@ -163,6 +168,7 @@ public class ECTesterStandalone { Options generateOpts = new Options(); generateOpts.addOption(bits); generateOpts.addOption(namedCurve); + generateOpts.addOption(curveName); 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); @@ -264,7 +270,11 @@ public class ECTesterStandalone { } spec = curve.toSpec(); kpg.initialize(spec); - }//TODO: allow ECGenNamedSpec + } else if (cli.hasOption("ecdh.curve-name")) { + String curveName = cli.getOptionValue("ecdh.curve-name"); + spec = new ECGenParameterSpec(curveName); + kpg.initialize(spec); + } System.out.println("index;nanotime;pubW;privS;secret"); @@ -349,6 +359,9 @@ public class ECTesterStandalone { return; } kpg.initialize(curve.toSpec()); + } else if (cli.hasOption("ecdsa.curve-name")) { + String curveName = cli.getOptionValue("ecdsa.curve-name"); + kpg.initialize(new ECGenParameterSpec(curveName)); } System.out.println("index;data;signtime;verifytime;pubW;privS;signature;verified"); @@ -411,6 +424,9 @@ public class ECTesterStandalone { return; } kpg.initialize(curve.toSpec()); + } else if (cli.hasOption("generate.curve-name")) { + String curveName = cli.getOptionValue("generate.curve-name"); + kpg.initialize(new ECGenParameterSpec(curveName)); } System.out.println("index;nanotime;pubW;privS"); @@ -507,8 +523,11 @@ public class ECTesterStandalone { } String next = cli.getNextName(); - if (cli.hasOption(next + ".bits") && cli.hasOption(next + ".named-curve")) { - System.err.println("You can only specify bitsize or a named curve, nor both."); + boolean hasBits = cli.hasOption(next + ".bits"); + boolean hasNamedCurve = cli.hasOption(next + ".named-curve"); + boolean hasCurveName = cli.hasOption(next + ".curve-name"); + if (hasBits ^ hasNamedCurve ? hasCurveName : hasBits) { + System.err.println("You can only specify bitsize or a named curve/curve name, nor both."); return false; } } diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java index 8a635e0..aac2127 100644 --- a/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java +++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java @@ -1,7 +1,6 @@ package cz.crcs.ectester.standalone.test; import cz.crcs.ectester.common.test.BaseTestable; -import cz.crcs.ectester.common.test.TestException; import javax.crypto.KeyAgreement; import java.security.InvalidAlgorithmParameterException; @@ -71,54 +70,52 @@ public class KeyAgreementTestable extends BaseTestable { @Override public void run() { - if (kgtPrivate != null) { - privateKey = (ECPrivateKey) kgtPrivate.getKeyPair().getPrivate(); - } + try { + if (kgtPrivate != null) { + privateKey = (ECPrivateKey) kgtPrivate.getKeyPair().getPrivate(); + } - if (kgtPublic != null) { - publicKey = (ECPublicKey) kgtPublic.getKeyPair().getPublic(); - } + if (kgtPublic != null) { + publicKey = (ECPublicKey) kgtPublic.getKeyPair().getPublic(); + } - try { - if (spec != null) { - ka.init(privateKey, spec); - } else { - ka.init(privateKey); + try { + if (spec != null) { + ka.init(privateKey, spec); + } else { + ka.init(privateKey); + } + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + ok = false; + error = false; + hasRun = true; + return; } - } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { - ok = false; - error = true; - hasRun = true; - return; - } - try { - ka.doPhase(publicKey, true); - } catch (IllegalStateException e) { - ok = false; - hasRun = true; - return; - } catch (InvalidKeyException e) { - ok = false; - error = true; - hasRun = true; - return; - } + try { + ka.doPhase(publicKey, true); + } catch (IllegalStateException | InvalidKeyException e) { + ok = false; + error = false; + hasRun = true; + return; + } - try { - secret = ka.generateSecret(); - } catch (IllegalStateException isex) { - ok = false; - hasRun = true; - return; - } catch (UnsupportedOperationException uoe) { + try { + secret = ka.generateSecret(); + } catch (IllegalStateException | UnsupportedOperationException isex) { + ok = false; + error = false; + hasRun = true; + return; + } + + ok = true; + } catch (Exception ex) { ok = false; error = true; - hasRun = false; - return; + errorCause = ex; } - - ok = true; hasRun = true; } } -- cgit v1.2.3-70-g09d2 From a4e52b21b1dad5f96df409c44e5b4d611bba01b9 Mon Sep 17 00:00:00 2001 From: J08nY Date: Mon, 28 May 2018 20:06:18 +0200 Subject: Implement tracking of stage of execution of standalone testables. - Output this stage in all the formats. --- .gitignore | 1 + src/cz/crcs/ectester/common/test/BaseTestable.java | 1 + .../ectester/standalone/ECTesterStandalone.java | 4 +- .../ectester/standalone/output/TextTestWriter.java | 10 +- .../ectester/standalone/output/XMLTestWriter.java | 36 ++++-- .../ectester/standalone/output/YAMLTestWriter.java | 30 +++-- .../ectester/standalone/test/KeyAgreementTest.java | 48 -------- .../standalone/test/KeyAgreementTestable.java | 121 ------------------ .../ectester/standalone/test/KeyGeneratorTest.java | 33 ----- .../standalone/test/KeyGeneratorTestable.java | 65 ---------- .../ectester/standalone/test/SignatureTest.java | 33 ----- .../standalone/test/SignatureTestable.java | 121 ------------------ .../standalone/test/StandaloneDefaultSuite.java | 77 ------------ .../standalone/test/StandaloneTestSuite.java | 25 ---- .../standalone/test/base/KeyAgreementTest.java | 48 ++++++++ .../standalone/test/base/KeyAgreementTestable.java | 129 ++++++++++++++++++++ .../standalone/test/base/KeyGeneratorTest.java | 33 +++++ .../standalone/test/base/KeyGeneratorTestable.java | 71 +++++++++++ .../standalone/test/base/SignatureTest.java | 33 +++++ .../standalone/test/base/SignatureTestable.java | 135 +++++++++++++++++++++ .../standalone/test/base/StandaloneTestable.java | 14 +++ .../test/suites/StandaloneDefaultSuite.java | 101 +++++++++++++++ .../test/suites/StandaloneTestSuite.java | 25 ++++ 23 files changed, 640 insertions(+), 554 deletions(-) delete mode 100644 src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java delete mode 100644 src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java delete mode 100644 src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java delete mode 100644 src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java delete mode 100644 src/cz/crcs/ectester/standalone/test/SignatureTest.java delete mode 100644 src/cz/crcs/ectester/standalone/test/SignatureTestable.java delete mode 100644 src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java delete mode 100644 src/cz/crcs/ectester/standalone/test/StandaloneTestSuite.java create mode 100644 src/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java create mode 100644 src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java create mode 100644 src/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java create mode 100644 src/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java create mode 100644 src/cz/crcs/ectester/standalone/test/base/SignatureTest.java create mode 100644 src/cz/crcs/ectester/standalone/test/base/SignatureTestable.java create mode 100644 src/cz/crcs/ectester/standalone/test/base/StandaloneTestable.java create mode 100644 src/cz/crcs/ectester/standalone/test/suites/StandaloneDefaultSuite.java create mode 100644 src/cz/crcs/ectester/standalone/test/suites/StandaloneTestSuite.java (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/.gitignore b/.gitignore index aecbbec..d05e75d 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ /dist/*.invalid /dist/*.twist /dist/*.degenerate +/dist/*.edge-cases /dist/*.xml # Built binaries in /src. diff --git a/src/cz/crcs/ectester/common/test/BaseTestable.java b/src/cz/crcs/ectester/common/test/BaseTestable.java index 979b2a4..4863abc 100644 --- a/src/cz/crcs/ectester/common/test/BaseTestable.java +++ b/src/cz/crcs/ectester/common/test/BaseTestable.java @@ -34,5 +34,6 @@ public abstract class BaseTestable implements Testable { hasRun = false; ok = false; error = false; + errorCause = null; } } diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 56dde42..392d604 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -36,8 +36,8 @@ import cz.crcs.ectester.standalone.libs.*; import cz.crcs.ectester.standalone.output.TextTestWriter; import cz.crcs.ectester.standalone.output.XMLTestWriter; import cz.crcs.ectester.standalone.output.YAMLTestWriter; -import cz.crcs.ectester.standalone.test.StandaloneDefaultSuite; -import cz.crcs.ectester.standalone.test.StandaloneTestSuite; +import cz.crcs.ectester.standalone.test.suites.StandaloneDefaultSuite; +import cz.crcs.ectester.standalone.test.suites.StandaloneTestSuite; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; diff --git a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java index 26e1b1a..691bea8 100644 --- a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java @@ -4,8 +4,10 @@ import cz.crcs.ectester.common.output.BaseTextTestWriter; import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.standalone.ECTesterStandalone; -import cz.crcs.ectester.standalone.test.StandaloneTestSuite; +import cz.crcs.ectester.standalone.test.base.*; +import cz.crcs.ectester.standalone.test.suites.StandaloneTestSuite; +import javax.crypto.KeyAgreement; import java.io.PrintStream; /** @@ -18,7 +20,9 @@ public class TextTestWriter extends BaseTextTestWriter { @Override protected String testableString(Testable t) { - //TODO + if (t instanceof StandaloneTestable) { + return ((StandaloneTestable)t).getStage().name(); + } return ""; } @@ -28,7 +32,7 @@ public class TextTestWriter extends BaseTextTestWriter { StandaloneTestSuite standaloneSuite = (StandaloneTestSuite) suite; StringBuilder sb = new StringBuilder(); sb.append("═══ ECTester version: " + ECTesterStandalone.VERSION).append(System.lineSeparator()); - sb.append("═══ " + standaloneSuite.getLibrary().name()).append(System.lineSeparator()); + sb.append("═══ ").append(standaloneSuite.getLibrary().name()).append(System.lineSeparator()); return sb.toString(); } return ""; diff --git a/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java b/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java index 2a35ce3..9332759 100644 --- a/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java @@ -5,10 +5,11 @@ import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.standalone.ECTesterStandalone; -import cz.crcs.ectester.standalone.test.KeyAgreementTestable; -import cz.crcs.ectester.standalone.test.KeyGeneratorTestable; -import cz.crcs.ectester.standalone.test.SignatureTestable; -import cz.crcs.ectester.standalone.test.StandaloneTestSuite; +import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable; +import cz.crcs.ectester.standalone.test.base.KeyGeneratorTestable; +import cz.crcs.ectester.standalone.test.base.SignatureTestable; +import cz.crcs.ectester.standalone.test.base.StandaloneTestable; +import cz.crcs.ectester.standalone.test.suites.StandaloneTestSuite; import org.w3c.dom.Element; import javax.xml.parsers.ParserConfigurationException; @@ -97,18 +98,27 @@ public class XMLTestWriter extends BaseXMLTestWriter { return sigElem; } + private Element stageElement(StandaloneTestable t) { + Element result = doc.createElement("stage"); + result.setTextContent(t.getStage().name()); + return result; + } + @Override protected Element testableElement(Testable t) { Element result = doc.createElement("test"); - if (t instanceof KeyGeneratorTestable) { - result.setAttribute("type", "key-pair-generator"); - result.appendChild(kgtElement((KeyGeneratorTestable) t)); - } else if (t instanceof KeyAgreementTestable) { - result.setAttribute("type", "key-agreement"); - result.appendChild(kaElement((KeyAgreementTestable) t)); - } else if (t instanceof SignatureTestable) { - result.setAttribute("type", "signature"); - result.appendChild(sigElement((SignatureTestable) t)); + if (t instanceof StandaloneTestable) { + if (t instanceof KeyGeneratorTestable) { + result.setAttribute("type", "key-pair-generator"); + result.appendChild(kgtElement((KeyGeneratorTestable) t)); + } else if (t instanceof KeyAgreementTestable) { + result.setAttribute("type", "key-agreement"); + result.appendChild(kaElement((KeyAgreementTestable) t)); + } else if (t instanceof SignatureTestable) { + result.setAttribute("type", "signature"); + result.appendChild(sigElement((SignatureTestable) t)); + } + result.appendChild(stageElement((StandaloneTestable) t)); } return result; } diff --git a/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java b/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java index c452133..0926b98 100644 --- a/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java @@ -5,10 +5,11 @@ import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.standalone.ECTesterStandalone; -import cz.crcs.ectester.standalone.test.KeyAgreementTestable; -import cz.crcs.ectester.standalone.test.KeyGeneratorTestable; -import cz.crcs.ectester.standalone.test.SignatureTestable; -import cz.crcs.ectester.standalone.test.StandaloneTestSuite; +import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable; +import cz.crcs.ectester.standalone.test.base.KeyGeneratorTestable; +import cz.crcs.ectester.standalone.test.base.SignatureTestable; +import cz.crcs.ectester.standalone.test.base.StandaloneTestable; +import cz.crcs.ectester.standalone.test.suites.StandaloneTestSuite; import java.io.PrintStream; import java.security.Key; @@ -79,15 +80,18 @@ public class YAMLTestWriter extends BaseYAMLTestWriter { @Override protected Map testableObject(Testable t) { Map result = new HashMap<>(); - if (t instanceof KeyGeneratorTestable) { - result.put("type", "key-pair-generator"); - result.put("key-pair-generator", kgtObject((KeyGeneratorTestable) t)); - } else if (t instanceof KeyAgreementTestable) { - result.put("type", "key-agreement"); - result.put("key-agreement", kaObject((KeyAgreementTestable) t)); - } else if (t instanceof SignatureTestable) { - result.put("type", "signature"); - result.put("signature", sigObject((SignatureTestable) t)); + if (t instanceof StandaloneTestable) { + if (t instanceof KeyGeneratorTestable) { + result.put("type", "key-pair-generator"); + result.put("key-pair-generator", kgtObject((KeyGeneratorTestable) t)); + } else if (t instanceof KeyAgreementTestable) { + result.put("type", "key-agreement"); + result.put("key-agreement", kaObject((KeyAgreementTestable) t)); + } else if (t instanceof SignatureTestable) { + result.put("type", "signature"); + result.put("signature", sigObject((SignatureTestable) t)); + } + result.put("stage", ((StandaloneTestable)t).getStage().name()); } return result; } diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java deleted file mode 100644 index 33c7385..0000000 --- a/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package cz.crcs.ectester.standalone.test; - -import cz.crcs.ectester.common.test.Result; -import cz.crcs.ectester.common.test.SimpleTest; -import cz.crcs.ectester.common.test.TestCallback; - -import java.util.Arrays; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class KeyAgreementTest extends SimpleTest { - private KeyAgreementTest(KeyAgreementTestable ka, TestCallback callback) { - super(ka, callback); - } - - public static KeyAgreementTest match(KeyAgreementTestable ka, byte[] expectedSecret) { - return new KeyAgreementTest(ka, new TestCallback() { - @Override - public Result apply(KeyAgreementTestable ka) { - if (Arrays.equals(ka.getSecret(), expectedSecret)) { - return new Result(Result.Value.SUCCESS, "The KeyAgreement result matched the expected derived secret."); - } else { - return new Result(Result.Value.FAILURE, "The KeyAgreement result did not match the expected derived secret."); - } - } - }); - } - - public static KeyAgreementTest expect(KeyAgreementTestable ka, Result.ExpectedValue expected) { - return new KeyAgreementTest(ka, new TestCallback() { - @Override - public Result apply(KeyAgreementTestable keyAgreementTestable) { - Result.Value value = Result.Value.fromExpected(expected, keyAgreementTestable.ok(), keyAgreementTestable.error()); - return new Result(value, value.description()); - } - }); - } - - public static KeyAgreementTest function(KeyAgreementTestable ka, TestCallback callback) { - return new KeyAgreementTest(ka, callback); - } - - @Override - public String getDescription() { - return "KeyAgreement " + testable.getKa().getAlgorithm(); - } -} diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java deleted file mode 100644 index aac2127..0000000 --- a/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java +++ /dev/null @@ -1,121 +0,0 @@ -package cz.crcs.ectester.standalone.test; - -import cz.crcs.ectester.common.test.BaseTestable; - -import javax.crypto.KeyAgreement; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.ECParameterSpec; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class KeyAgreementTestable extends BaseTestable { - private KeyAgreement ka; - private ECPrivateKey privateKey; - private ECPublicKey publicKey; - private KeyGeneratorTestable kgtPrivate; - private KeyGeneratorTestable kgtPublic; - private AlgorithmParameterSpec spec; - private byte[] secret; - - public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey) { - this.ka = ka; - this.privateKey = privateKey; - this.publicKey = publicKey; - } - - public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey, ECParameterSpec spec) { - this(ka, privateKey, publicKey); - this.spec = spec; - } - - public KeyAgreementTestable(KeyAgreement ka, KeyGeneratorTestable kgt, ECPrivateKey privateKey, ECParameterSpec spec) { - this(ka, privateKey, null, spec); - this.kgtPublic = kgt; - } - - public KeyAgreementTestable(KeyAgreement ka, ECPublicKey publicKey, KeyGeneratorTestable kgt, ECParameterSpec spec) { - this(ka, null, publicKey, spec); - this.kgtPrivate = kgt; - } - - public KeyAgreementTestable(KeyAgreement ka, KeyGeneratorTestable privKgt, KeyGeneratorTestable pubKgt, ECParameterSpec spec) { - this(ka, (ECPrivateKey) null, null, spec); - this.kgtPrivate = privKgt; - this.kgtPublic = pubKgt; - } - - public KeyAgreement getKa() { - return ka; - } - - public ECPublicKey getPublicKey() { - return publicKey; - } - - public ECPrivateKey getPrivateKey() { - return privateKey; - } - - public byte[] getSecret() { - if (!hasRun) { - return null; - } - return secret; - } - - @Override - public void run() { - try { - if (kgtPrivate != null) { - privateKey = (ECPrivateKey) kgtPrivate.getKeyPair().getPrivate(); - } - - if (kgtPublic != null) { - publicKey = (ECPublicKey) kgtPublic.getKeyPair().getPublic(); - } - - try { - if (spec != null) { - ka.init(privateKey, spec); - } else { - ka.init(privateKey); - } - } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { - ok = false; - error = false; - hasRun = true; - return; - } - - try { - ka.doPhase(publicKey, true); - } catch (IllegalStateException | InvalidKeyException e) { - ok = false; - error = false; - hasRun = true; - return; - } - - try { - secret = ka.generateSecret(); - } catch (IllegalStateException | UnsupportedOperationException isex) { - ok = false; - error = false; - hasRun = true; - return; - } - - ok = true; - } catch (Exception ex) { - ok = false; - error = true; - errorCause = ex; - } - hasRun = true; - } -} diff --git a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java deleted file mode 100644 index 02b81a4..0000000 --- a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package cz.crcs.ectester.standalone.test; - -import cz.crcs.ectester.common.test.Result; -import cz.crcs.ectester.common.test.SimpleTest; -import cz.crcs.ectester.common.test.TestCallback; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class KeyGeneratorTest extends SimpleTest { - private KeyGeneratorTest(KeyGeneratorTestable kg, TestCallback callback) { - super(kg, callback); - } - - public static KeyGeneratorTest expect(KeyGeneratorTestable kg, Result.ExpectedValue expected) { - return new KeyGeneratorTest(kg, new TestCallback() { - @Override - public Result apply(KeyGeneratorTestable keyGenerationTestable) { - Result.Value value = Result.Value.fromExpected(expected, keyGenerationTestable.ok(), keyGenerationTestable.error()); - return new Result(value, value.description()); - } - }); - } - - public static KeyGeneratorTest function(KeyGeneratorTestable ka, TestCallback callback) { - return new KeyGeneratorTest(ka, callback); - } - - @Override - public String getDescription() { - return "KeyPairGenerator " + testable.getKpg().getAlgorithm(); - } -} diff --git a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java deleted file mode 100644 index 774c3ec..0000000 --- a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java +++ /dev/null @@ -1,65 +0,0 @@ -package cz.crcs.ectester.standalone.test; - -import cz.crcs.ectester.common.test.BaseTestable; - -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.spec.ECParameterSpec; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class KeyGeneratorTestable extends BaseTestable { - private KeyPair kp; - private KeyPairGenerator kpg; - private int keysize = 0; - private ECParameterSpec spec = null; - - public KeyGeneratorTestable(KeyPairGenerator kpg) { - this.kpg = kpg; - } - - public KeyGeneratorTestable(KeyPairGenerator kpg, int keysize) { - this.kpg = kpg; - this.keysize = keysize; - } - - public KeyGeneratorTestable(KeyPairGenerator kpg, ECParameterSpec spec) { - this.kpg = kpg; - this.spec = spec; - } - - public KeyPairGenerator getKpg() { - return kpg; - } - - public KeyPair getKeyPair() { - return kp; - } - - @Override - public void run() { - try { - try { - if (spec != null) { - kpg.initialize(spec); - } else if (keysize != 0) { - kpg.initialize(keysize); - } - } catch (InvalidAlgorithmParameterException e) { - hasRun = true; - ok = false; - return; - } - kp = kpg.genKeyPair(); - ok = true; - - } catch (Exception ex) { - ok = false; - error = true; - errorCause = ex; - } - hasRun = true; - } -} diff --git a/src/cz/crcs/ectester/standalone/test/SignatureTest.java b/src/cz/crcs/ectester/standalone/test/SignatureTest.java deleted file mode 100644 index 481d289..0000000 --- a/src/cz/crcs/ectester/standalone/test/SignatureTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package cz.crcs.ectester.standalone.test; - -import cz.crcs.ectester.common.test.Result; -import cz.crcs.ectester.common.test.SimpleTest; -import cz.crcs.ectester.common.test.TestCallback; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class SignatureTest extends SimpleTest { - private SignatureTest(SignatureTestable sig, TestCallback callback) { - super(sig, callback); - } - - public static SignatureTest expect(SignatureTestable kg, Result.ExpectedValue expected) { - return new SignatureTest(kg, new TestCallback() { - @Override - public Result apply(SignatureTestable signatureTestable) { - Result.Value value = Result.Value.fromExpected(expected, signatureTestable.ok(), signatureTestable.error()); - return new Result(value, value.description()); - } - }); - } - - public static SignatureTest function(SignatureTestable ka, TestCallback callback) { - return new SignatureTest(ka, callback); - } - - @Override - public String getDescription() { - return "Signature " + testable.getSig().getAlgorithm(); - } -} diff --git a/src/cz/crcs/ectester/standalone/test/SignatureTestable.java b/src/cz/crcs/ectester/standalone/test/SignatureTestable.java deleted file mode 100644 index 6bc9b30..0000000 --- a/src/cz/crcs/ectester/standalone/test/SignatureTestable.java +++ /dev/null @@ -1,121 +0,0 @@ -package cz.crcs.ectester.standalone.test; - -import cz.crcs.ectester.common.test.BaseTestable; -import cz.crcs.ectester.common.test.TestException; - -import java.security.InvalidKeyException; -import java.security.SecureRandom; -import java.security.Signature; -import java.security.SignatureException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class SignatureTestable extends BaseTestable { - private Signature sig; - private ECPrivateKey signKey; - private ECPublicKey verifyKey; - private KeyGeneratorTestable kgt; - private byte[] data; - private byte[] signature; - private boolean verified; - - public SignatureTestable(Signature sig, ECPrivateKey signKey, ECPublicKey verifyKey, byte[] data) { - this.sig = sig; - this.signKey = signKey; - this.verifyKey = verifyKey; - this.data = data; - if (data == null) { - SecureRandom random = new SecureRandom(); - this.data = new byte[32]; - random.nextBytes(this.data); - } - } - - public SignatureTestable(Signature sig, KeyGeneratorTestable kgt, byte[] data) { - this(sig, null, null, data); - this.kgt = kgt; - } - - public Signature getSig() { - return sig; - } - - public byte[] getData() { - return data; - } - - public byte[] getSignature() { - return signature; - } - - public boolean getVerified() { - return verified; - } - - @Override - public void run() { - try { - if (kgt != null) { - signKey = (ECPrivateKey) kgt.getKeyPair().getPrivate(); - verifyKey = (ECPublicKey) kgt.getKeyPair().getPublic(); - } - - try { - sig.initSign(signKey); - } catch (InvalidKeyException e) { - ok = false; - hasRun = true; - return; - } - - try { - sig.update(data); - } catch (SignatureException e) { - ok = false; - hasRun = true; - return; - } - - try { - signature = sig.sign(); - } catch (SignatureException e) { - ok = false; - hasRun = true; - return; - } - - try { - sig.initVerify(verifyKey); - } catch (InvalidKeyException e) { - ok = false; - hasRun = true; - return; - } - - try { - sig.update(data); - } catch (SignatureException e) { - ok = false; - hasRun = true; - return; - } - - try { - verified = sig.verify(signature); - } catch (SignatureException e) { - ok = false; - hasRun = true; - } - - ok = true; - } catch (Exception ex) { - ok = false; - error = true; - errorCause = ex; - } - hasRun = true; - } -} diff --git a/src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java b/src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java deleted file mode 100644 index 572449a..0000000 --- a/src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java +++ /dev/null @@ -1,77 +0,0 @@ -package cz.crcs.ectester.standalone.test; - -import cz.crcs.ectester.common.cli.TreeCommandLine; -import cz.crcs.ectester.common.ec.EC_Curve; -import cz.crcs.ectester.common.output.TestWriter; -import cz.crcs.ectester.common.test.Result; -import cz.crcs.ectester.data.EC_Store; -import cz.crcs.ectester.standalone.ECTesterStandalone; -import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; -import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; -import cz.crcs.ectester.standalone.consts.SignatureIdent; -import cz.crcs.ectester.standalone.libs.ECLibrary; - -import javax.crypto.KeyAgreement; -import java.security.KeyPairGenerator; -import java.security.Signature; -import java.security.spec.ECParameterSpec; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class StandaloneDefaultSuite extends StandaloneTestSuite { - - public StandaloneDefaultSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) { - super(writer, cfg, cli, "default", "The default test suite run basic support of ECDH and ECDSA."); - } - - @Override - protected void runTests() throws Exception { - String kpgAlgo = cli.getOptionValue("test.kpg-type", "EC"); - String kaAlgo = cli.getOptionValue("test.ka-type"); - String sigAlgo = cli.getOptionValue("test.sig-type"); - - KeyPairGeneratorIdent kpgIdent = cfg.selected.getKPGs().stream() - .filter((ident) -> ident.contains(kpgAlgo)) - .findFirst().get(); - KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider()); - - KeyGeneratorTestable kgtOne; - KeyGeneratorTestable kgtOther; - ECParameterSpec spec = null; - if (cli.hasOption("test.bits")) { - int bits = Integer.parseInt(cli.getOptionValue("test.bits")); - kgtOne = new KeyGeneratorTestable(kpg, bits); - kgtOther = new KeyGeneratorTestable(kpg, bits); - } else if (cli.hasOption("test.named-curve")) { - String curveName = cli.getOptionValue("test.named-curve"); - EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName); - if (curve == null) { - System.err.println("Curve not found: " + curveName); - return; - } - spec = curve.toSpec(); - kgtOne = new KeyGeneratorTestable(kpg, spec); - kgtOther = new KeyGeneratorTestable(kpg, spec); - } else { - kgtOne = new KeyGeneratorTestable(kpg); - kgtOther = new KeyGeneratorTestable(kpg); - } - - doTest(KeyGeneratorTest.expect(kgtOne, Result.ExpectedValue.SUCCESS)); - doTest(KeyGeneratorTest.expect(kgtOther, Result.ExpectedValue.SUCCESS)); - - for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) { - if (kaAlgo == null || kaIdent.contains(kaAlgo)) { - KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider()); - doTest(KeyAgreementTest.expect(new KeyAgreementTestable(ka, kgtOne, kgtOther, spec), Result.ExpectedValue.SUCCESS)); - } - } - for (SignatureIdent sigIdent : cfg.selected.getSigs()) { - if (sigAlgo == null || sigIdent.contains(sigAlgo)) { - Signature sig = sigIdent.getInstance(cfg.selected.getProvider()); - doTest(SignatureTest.expect(new SignatureTestable(sig, kgtOne, null), Result.ExpectedValue.SUCCESS)); - } - } - } -} diff --git a/src/cz/crcs/ectester/standalone/test/StandaloneTestSuite.java b/src/cz/crcs/ectester/standalone/test/StandaloneTestSuite.java deleted file mode 100644 index 2949d52..0000000 --- a/src/cz/crcs/ectester/standalone/test/StandaloneTestSuite.java +++ /dev/null @@ -1,25 +0,0 @@ -package cz.crcs.ectester.standalone.test; - -import cz.crcs.ectester.common.cli.TreeCommandLine; -import cz.crcs.ectester.common.output.TestWriter; -import cz.crcs.ectester.common.test.TestSuite; -import cz.crcs.ectester.standalone.ECTesterStandalone; -import cz.crcs.ectester.standalone.libs.ProviderECLibrary; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public abstract class StandaloneTestSuite extends TestSuite { - TreeCommandLine cli; - ECTesterStandalone.Config cfg; - - public StandaloneTestSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli, String name, String description) { - super(writer, name, description); - this.cfg = cfg; - this.cli = cli; - } - - public ProviderECLibrary getLibrary() { - return cfg.selected; - } -} diff --git a/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java b/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java new file mode 100644 index 0000000..8297d76 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java @@ -0,0 +1,48 @@ +package cz.crcs.ectester.standalone.test.base; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.SimpleTest; +import cz.crcs.ectester.common.test.TestCallback; + +import java.util.Arrays; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyAgreementTest extends SimpleTest { + private KeyAgreementTest(KeyAgreementTestable ka, TestCallback callback) { + super(ka, callback); + } + + public static KeyAgreementTest match(KeyAgreementTestable ka, byte[] expectedSecret) { + return new KeyAgreementTest(ka, new TestCallback() { + @Override + public Result apply(KeyAgreementTestable ka) { + if (Arrays.equals(ka.getSecret(), expectedSecret)) { + return new Result(Result.Value.SUCCESS, "The KeyAgreement result matched the expected derived secret."); + } else { + return new Result(Result.Value.FAILURE, "The KeyAgreement result did not match the expected derived secret."); + } + } + }); + } + + public static KeyAgreementTest expect(KeyAgreementTestable ka, Result.ExpectedValue expected) { + return new KeyAgreementTest(ka, new TestCallback() { + @Override + public Result apply(KeyAgreementTestable keyAgreementTestable) { + Result.Value value = Result.Value.fromExpected(expected, keyAgreementTestable.ok(), keyAgreementTestable.error()); + return new Result(value, value.description()); + } + }); + } + + public static KeyAgreementTest function(KeyAgreementTestable ka, TestCallback callback) { + return new KeyAgreementTest(ka, callback); + } + + @Override + public String getDescription() { + return "KeyAgreement " + testable.getKa().getAlgorithm(); + } +} diff --git a/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java b/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java new file mode 100644 index 0000000..ffcfc67 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java @@ -0,0 +1,129 @@ +package cz.crcs.ectester.standalone.test.base; + +import javax.crypto.KeyAgreement; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyAgreementTestable extends StandaloneTestable { + private KeyAgreement ka; + private ECPrivateKey privateKey; + private ECPublicKey publicKey; + private KeyGeneratorTestable kgtPrivate; + private KeyGeneratorTestable kgtPublic; + private AlgorithmParameterSpec spec; + private byte[] secret; + + public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey) { + this.ka = ka; + this.privateKey = privateKey; + this.publicKey = publicKey; + } + + public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey, ECParameterSpec spec) { + this(ka, privateKey, publicKey); + this.spec = spec; + } + + public KeyAgreementTestable(KeyAgreement ka, KeyGeneratorTestable kgt, ECPrivateKey privateKey, ECParameterSpec spec) { + this(ka, privateKey, null, spec); + this.kgtPublic = kgt; + } + + public KeyAgreementTestable(KeyAgreement ka, ECPublicKey publicKey, KeyGeneratorTestable kgt, ECParameterSpec spec) { + this(ka, null, publicKey, spec); + this.kgtPrivate = kgt; + } + + public KeyAgreementTestable(KeyAgreement ka, KeyGeneratorTestable privKgt, KeyGeneratorTestable pubKgt, ECParameterSpec spec) { + this(ka, (ECPrivateKey) null, null, spec); + this.kgtPrivate = privKgt; + this.kgtPublic = pubKgt; + } + + public KeyAgreement getKa() { + return ka; + } + + public ECPublicKey getPublicKey() { + return publicKey; + } + + public ECPrivateKey getPrivateKey() { + return privateKey; + } + + public byte[] getSecret() { + if (!hasRun) { + return null; + } + return secret; + } + + @Override + public void run() { + try { + stage = KeyAgreementStage.GetPrivate; + if (kgtPrivate != null) { + privateKey = (ECPrivateKey) kgtPrivate.getKeyPair().getPrivate(); + } + + stage = KeyAgreementStage.GetPublic; + if (kgtPublic != null) { + publicKey = (ECPublicKey) kgtPublic.getKeyPair().getPublic(); + } + + stage = KeyAgreementStage.Init; + try { + if (spec != null) { + ka.init(privateKey, spec); + } else { + ka.init(privateKey); + } + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + ok = false; + hasRun = true; + return; + } + + stage = KeyAgreementStage.DoPhase; + try { + ka.doPhase(publicKey, true); + } catch (IllegalStateException | InvalidKeyException e) { + ok = false; + hasRun = true; + return; + } + + stage = KeyAgreementStage.GenerateSecret; + try { + secret = ka.generateSecret(); + } catch (IllegalStateException | UnsupportedOperationException isex) { + ok = false; + hasRun = true; + return; + } + + ok = true; + } catch (Exception ex) { + ok = false; + error = true; + errorCause = ex; + } + hasRun = true; + } + + public enum KeyAgreementStage { + GetPrivate, + GetPublic, + Init, + DoPhase, + GenerateSecret + } +} diff --git a/src/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java b/src/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java new file mode 100644 index 0000000..b232456 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java @@ -0,0 +1,33 @@ +package cz.crcs.ectester.standalone.test.base; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.SimpleTest; +import cz.crcs.ectester.common.test.TestCallback; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyGeneratorTest extends SimpleTest { + private KeyGeneratorTest(KeyGeneratorTestable kg, TestCallback callback) { + super(kg, callback); + } + + public static KeyGeneratorTest expect(KeyGeneratorTestable kg, Result.ExpectedValue expected) { + return new KeyGeneratorTest(kg, new TestCallback() { + @Override + public Result apply(KeyGeneratorTestable keyGenerationTestable) { + Result.Value value = Result.Value.fromExpected(expected, keyGenerationTestable.ok(), keyGenerationTestable.error()); + return new Result(value, value.description()); + } + }); + } + + public static KeyGeneratorTest function(KeyGeneratorTestable ka, TestCallback callback) { + return new KeyGeneratorTest(ka, callback); + } + + @Override + public String getDescription() { + return "KeyPairGenerator " + testable.getKpg().getAlgorithm(); + } +} diff --git a/src/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java b/src/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java new file mode 100644 index 0000000..b561b8b --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java @@ -0,0 +1,71 @@ +package cz.crcs.ectester.standalone.test.base; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.spec.ECParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyGeneratorTestable extends StandaloneTestable { + private KeyPair kp; + private KeyPairGenerator kpg; + private int keysize = 0; + private ECParameterSpec spec = null; + + public KeyGeneratorTestable(KeyPairGenerator kpg) { + this.kpg = kpg; + } + + public KeyGeneratorTestable(KeyPairGenerator kpg, int keysize) { + this.kpg = kpg; + this.keysize = keysize; + } + + public KeyGeneratorTestable(KeyPairGenerator kpg, ECParameterSpec spec) { + this.kpg = kpg; + this.spec = spec; + } + + public KeyPairGenerator getKpg() { + return kpg; + } + + public KeyPair getKeyPair() { + return kp; + } + + @Override + public void run() { + try { + stage = KeyGeneratorStage.Init; + try { + if (spec != null) { + kpg.initialize(spec); + } else if (keysize != 0) { + kpg.initialize(keysize); + } + } catch (InvalidAlgorithmParameterException e) { + ok = false; + hasRun = true; + return; + } + + stage = KeyGeneratorStage.GenKeyPair; + kp = kpg.genKeyPair(); + + ok = true; + } catch (Exception ex) { + ok = false; + error = true; + errorCause = ex; + } + hasRun = true; + } + + public enum KeyGeneratorStage { + Init, + GenKeyPair + } +} diff --git a/src/cz/crcs/ectester/standalone/test/base/SignatureTest.java b/src/cz/crcs/ectester/standalone/test/base/SignatureTest.java new file mode 100644 index 0000000..d8b3e0f --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/base/SignatureTest.java @@ -0,0 +1,33 @@ +package cz.crcs.ectester.standalone.test.base; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.SimpleTest; +import cz.crcs.ectester.common.test.TestCallback; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SignatureTest extends SimpleTest { + private SignatureTest(SignatureTestable sig, TestCallback callback) { + super(sig, callback); + } + + public static SignatureTest expect(SignatureTestable kg, Result.ExpectedValue expected) { + return new SignatureTest(kg, new TestCallback() { + @Override + public Result apply(SignatureTestable signatureTestable) { + Result.Value value = Result.Value.fromExpected(expected, signatureTestable.ok(), signatureTestable.error()); + return new Result(value, value.description()); + } + }); + } + + public static SignatureTest function(SignatureTestable ka, TestCallback callback) { + return new SignatureTest(ka, callback); + } + + @Override + public String getDescription() { + return "Signature " + testable.getSig().getAlgorithm(); + } +} diff --git a/src/cz/crcs/ectester/standalone/test/base/SignatureTestable.java b/src/cz/crcs/ectester/standalone/test/base/SignatureTestable.java new file mode 100644 index 0000000..873757b --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/base/SignatureTestable.java @@ -0,0 +1,135 @@ +package cz.crcs.ectester.standalone.test.base; + +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SignatureTestable extends StandaloneTestable { + private Signature sig; + private ECPrivateKey signKey; + private ECPublicKey verifyKey; + private KeyGeneratorTestable kgt; + private byte[] data; + private byte[] signature; + private boolean verified; + + public SignatureTestable(Signature sig, ECPrivateKey signKey, ECPublicKey verifyKey, byte[] data) { + this.sig = sig; + this.signKey = signKey; + this.verifyKey = verifyKey; + this.data = data; + if (data == null) { + SecureRandom random = new SecureRandom(); + this.data = new byte[64]; + random.nextBytes(this.data); + } + } + + public SignatureTestable(Signature sig, KeyGeneratorTestable kgt, byte[] data) { + this(sig, null, null, data); + this.kgt = kgt; + } + + public Signature getSig() { + return sig; + } + + public byte[] getData() { + return data; + } + + public byte[] getSignature() { + return signature; + } + + public boolean getVerified() { + return verified; + } + + @Override + public void run() { + try { + stage = SignatureStage.GetKeys; + if (kgt != null) { + signKey = (ECPrivateKey) kgt.getKeyPair().getPrivate(); + verifyKey = (ECPublicKey) kgt.getKeyPair().getPublic(); + } + + stage = SignatureStage.InitSign; + try { + sig.initSign(signKey); + } catch (InvalidKeyException e) { + ok = false; + hasRun = true; + return; + } + + stage = SignatureStage.UpdateSign; + try { + sig.update(data); + } catch (SignatureException e) { + ok = false; + hasRun = true; + return; + } + + stage = SignatureStage.Sign; + try { + signature = sig.sign(); + } catch (SignatureException e) { + ok = false; + hasRun = true; + return; + } + + stage = SignatureStage.InitVerify; + try { + sig.initVerify(verifyKey); + } catch (InvalidKeyException e) { + ok = false; + hasRun = true; + return; + } + + stage = SignatureStage.UpdateVerify; + try { + sig.update(data); + } catch (SignatureException e) { + ok = false; + hasRun = true; + return; + } + + stage = SignatureStage.Verify; + try { + verified = sig.verify(signature); + } catch (SignatureException e) { + ok = false; + hasRun = true; + } + + ok = true; + } catch (Exception ex) { + ok = false; + error = true; + errorCause = ex; + } + hasRun = true; + } + + public enum SignatureStage { + GetKeys, + InitSign, + UpdateSign, + Sign, + InitVerify, + UpdateVerify, + Verify + } +} diff --git a/src/cz/crcs/ectester/standalone/test/base/StandaloneTestable.java b/src/cz/crcs/ectester/standalone/test/base/StandaloneTestable.java new file mode 100644 index 0000000..8654e94 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/base/StandaloneTestable.java @@ -0,0 +1,14 @@ +package cz.crcs.ectester.standalone.test.base; + +import cz.crcs.ectester.common.test.BaseTestable; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class StandaloneTestable> extends BaseTestable { + protected T stage; + + public T getStage() { + return stage; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/suites/StandaloneDefaultSuite.java b/src/cz/crcs/ectester/standalone/test/suites/StandaloneDefaultSuite.java new file mode 100644 index 0000000..e030664 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/suites/StandaloneDefaultSuite.java @@ -0,0 +1,101 @@ +package cz.crcs.ectester.standalone.test.suites; + +import cz.crcs.ectester.common.cli.TreeCommandLine; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.standalone.ECTesterStandalone; +import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; +import cz.crcs.ectester.standalone.consts.SignatureIdent; +import cz.crcs.ectester.standalone.test.base.*; + +import javax.crypto.KeyAgreement; +import java.security.KeyPairGenerator; +import java.security.Signature; +import java.security.spec.ECParameterSpec; +import java.util.Optional; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class StandaloneDefaultSuite extends StandaloneTestSuite { + + public StandaloneDefaultSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) { + super(writer, cfg, cli, "default", "The default test suite run basic support of ECDH and ECDSA."); + } + + @Override + protected void runTests() throws Exception { + String kpgAlgo = cli.getOptionValue("test.kpg-type"); + String kaAlgo = cli.getOptionValue("test.ka-type"); + String sigAlgo = cli.getOptionValue("test.sig-type"); + + + KeyPairGeneratorIdent kpgIdent; + if (kpgAlgo == null) { + // try EC, if not, fail with: need to specify kpg algo. + Optional kpgIdentOpt = cfg.selected.getKPGs().stream() + .filter((ident) -> ident.contains("EC")) + .findFirst(); + if (kpgIdentOpt.isPresent()) { + kpgIdent = kpgIdentOpt.get(); + } else { + System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type."); + return; + } + } else { + // try the specified, if not, fail with: wrong kpg algo/not found. + Optional kpgIdentOpt = cfg.selected.getKPGs().stream() + .filter((ident) -> ident.contains(kpgAlgo)) + .findFirst(); + if (kpgIdentOpt.isPresent()) { + kpgIdent = kpgIdentOpt.get(); + } else { + System.err.println("The KeyPairGenerator algorithm type of \"" + kpgAlgo + "\" was not found."); + return; + } + } + + KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider()); + + KeyGeneratorTestable kgtOne; + KeyGeneratorTestable kgtOther; + ECParameterSpec spec = null; + if (cli.hasOption("test.bits")) { + int bits = Integer.parseInt(cli.getOptionValue("test.bits")); + kgtOne = new KeyGeneratorTestable(kpg, bits); + kgtOther = new KeyGeneratorTestable(kpg, bits); + } else if (cli.hasOption("test.named-curve")) { + String curveName = cli.getOptionValue("test.named-curve"); + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName); + if (curve == null) { + System.err.println("Curve not found: " + curveName); + return; + } + spec = curve.toSpec(); + kgtOne = new KeyGeneratorTestable(kpg, spec); + kgtOther = new KeyGeneratorTestable(kpg, spec); + } else { + kgtOne = new KeyGeneratorTestable(kpg); + kgtOther = new KeyGeneratorTestable(kpg); + } + + doTest(KeyGeneratorTest.expect(kgtOne, Result.ExpectedValue.SUCCESS)); + doTest(KeyGeneratorTest.expect(kgtOther, Result.ExpectedValue.SUCCESS)); + + for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) { + if (kaAlgo == null || kaIdent.contains(kaAlgo)) { + KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider()); + doTest(KeyAgreementTest.expect(new KeyAgreementTestable(ka, kgtOne, kgtOther, spec), Result.ExpectedValue.SUCCESS)); + } + } + for (SignatureIdent sigIdent : cfg.selected.getSigs()) { + if (sigAlgo == null || sigIdent.contains(sigAlgo)) { + Signature sig = sigIdent.getInstance(cfg.selected.getProvider()); + doTest(SignatureTest.expect(new SignatureTestable(sig, kgtOne, null), Result.ExpectedValue.SUCCESS)); + } + } + } +} diff --git a/src/cz/crcs/ectester/standalone/test/suites/StandaloneTestSuite.java b/src/cz/crcs/ectester/standalone/test/suites/StandaloneTestSuite.java new file mode 100644 index 0000000..c01f8cd --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/suites/StandaloneTestSuite.java @@ -0,0 +1,25 @@ +package cz.crcs.ectester.standalone.test.suites; + +import cz.crcs.ectester.common.cli.TreeCommandLine; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.TestSuite; +import cz.crcs.ectester.standalone.ECTesterStandalone; +import cz.crcs.ectester.standalone.libs.ProviderECLibrary; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class StandaloneTestSuite extends TestSuite { + TreeCommandLine cli; + ECTesterStandalone.Config cfg; + + public StandaloneTestSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli, String name, String description) { + super(writer, name, description); + this.cfg = cfg; + this.cli = cli; + } + + public ProviderECLibrary getLibrary() { + return cfg.selected; + } +} -- cgit v1.2.3-70-g09d2 From d970a9c64a8363a5b6b6fc65c1a767ea6951c298 Mon Sep 17 00:00:00 2001 From: J08nY Date: Tue, 29 May 2018 17:42:25 +0200 Subject: Support key algo parameter for KeyAgreements with KDF in standalone testing. --- src/cz/crcs/ectester/common/test/TestSuite.java | 6 +-- .../ectester/reader/test/CardCompressionSuite.java | 2 +- .../reader/test/CardDegenerateCurvesSuite.java | 2 +- .../ectester/reader/test/CardEdgeCasesSuite.java | 2 +- .../crcs/ectester/reader/test/CardTestSuite.java | 2 +- .../ectester/standalone/ECTesterStandalone.java | 1 + .../standalone/consts/KeyAgreementIdent.java | 31 ++++++++++----- .../standalone/libs/jni/NativeKeyAgreementSpi.java | 4 +- .../standalone/test/base/KeyAgreementTest.java | 3 +- .../standalone/test/base/KeyAgreementTestable.java | 46 +++++++++++++++++++++- .../test/suites/StandaloneDefaultSuite.java | 11 +++++- .../test/suites/StandaloneTestSuite.java | 2 +- 12 files changed, 89 insertions(+), 23 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/src/cz/crcs/ectester/common/test/TestSuite.java b/src/cz/crcs/ectester/common/test/TestSuite.java index 9e08891..c8bb3f8 100644 --- a/src/cz/crcs/ectester/common/test/TestSuite.java +++ b/src/cz/crcs/ectester/common/test/TestSuite.java @@ -7,11 +7,11 @@ import cz.crcs.ectester.common.output.TestWriter; */ public abstract class TestSuite { protected String name; - protected String description; + protected String[] description; private TestWriter writer; private Test running; - public TestSuite(TestWriter writer, String name, String description) { + public TestSuite(TestWriter writer, String name, String... description) { this.writer = writer; this.name = name; this.description = description; @@ -70,7 +70,7 @@ public abstract class TestSuite { } public String getDescription() { - return description; + return String.join(System.lineSeparator(), description); } } diff --git a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java index e58c38d..35cfd1d 100644 --- a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java @@ -24,7 +24,7 @@ import java.util.List; */ 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).\n" + + 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."); } diff --git a/src/cz/crcs/ectester/reader/test/CardDegenerateCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardDegenerateCurvesSuite.java index 217544b..0cc9186 100644 --- a/src/cz/crcs/ectester/reader/test/CardDegenerateCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardDegenerateCurvesSuite.java @@ -23,7 +23,7 @@ import java.util.Map; public class CardDegenerateCurvesSuite extends CardTestSuite { public CardDegenerateCurvesSuite(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.\n" + + 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."); } diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java index 0a4515a..211dc58 100644 --- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java @@ -27,7 +27,7 @@ import java.util.Map; */ 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 ECDH.\n" + + 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 ECDH.", "Some of the data is from the google/Wycheproof project. Tests include CVE-2017-10176 and CVE-2017-8932."); } diff --git a/src/cz/crcs/ectester/reader/test/CardTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTestSuite.java index 0eccd16..3578f9c 100644 --- a/src/cz/crcs/ectester/reader/test/CardTestSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardTestSuite.java @@ -12,7 +12,7 @@ public abstract class CardTestSuite extends TestSuite { ECTesterReader.Config cfg; CardMngr card; - CardTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager, String name, String description) { + CardTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager, String name, String... description) { super(writer, name, description); this.card = cardManager; this.cfg = cfg; diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 392d604..18bfce6 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -141,6 +141,7 @@ public class ECTesterStandalone { testOpts.addOption(Option.builder("kt").longOpt("ka-type").desc("Set the KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build()); testOpts.addOption(Option.builder("st").longOpt("sig-type").desc("Set the Signature object [type].").hasArg().argName("type").optionalArg(false).build()); testOpts.addOption(Option.builder("f").longOpt("format").desc("Set the output format, one of text,yaml,xml.").hasArg().argName("format").optionalArg(false).build()); + testOpts.addOption(Option.builder().longOpt("key-type").desc("Set the key [algorithm] for which the key should be derived in KeyAgreements with KDF.").hasArg().argName("algorithm").optionalArg(false).build()); List testArgs = new LinkedList<>(); testArgs.add(new Argument("test_suite", "The test suite to run.", true)); ParserOptions test = new ParserOptions(new DefaultParser(), testOpts, testArgs); diff --git a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java index 0e4d311..6aae423 100644 --- a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java +++ b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java @@ -10,6 +10,8 @@ import java.util.List; * @author Jan Jancar johny@neuromancer.sk */ public class KeyAgreementIdent extends Ident { + private boolean requiresKeyAlgo; + private static final List ALL = new LinkedList<>(); static { @@ -18,16 +20,16 @@ public class KeyAgreementIdent extends Ident { ALL.add(new KeyAgreementIdent("ECDH")); ALL.add(new KeyAgreementIdent("ECDHC", "ECCDH")); // ECDH and ECDHC with SHA as KDF, OIDs from RFC 3278 - ALL.add(new KeyAgreementIdent("ECDHwithSHA1KDF", "1.3.133.16.840.63.0.2")); - ALL.add(new KeyAgreementIdent("ECCDHwithSHA1KDF", "1.3.133.16.840.63.0.3")); - ALL.add(new KeyAgreementIdent("ECDHwithSHA224KDF", "1.3.132.1.11.0")); - ALL.add(new KeyAgreementIdent("ECCDHwithSHA224KDF", "1.3.132.1.14.0")); - ALL.add(new KeyAgreementIdent("ECDHwithSHA256KDF", "1.3.132.1.11.1")); - ALL.add(new KeyAgreementIdent("ECCDHwithSHA256KDF", "1.3.132.1.14.1")); - ALL.add(new KeyAgreementIdent("ECDHwithSHA384KDF", "1.3.132.1.11.2")); - ALL.add(new KeyAgreementIdent("ECCDHwithSHA384KDF", "1.3.132.1.14.2")); - ALL.add(new KeyAgreementIdent("ECDHwithSHA512KDF", "1.3.132.1.11.3")); - ALL.add(new KeyAgreementIdent("ECCDHwithSHA512KDF", "1.3.132.1.14.3")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA1KDF", true, "1.3.133.16.840.63.0.2")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA1KDF", true, "1.3.133.16.840.63.0.3")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA224KDF",true, "1.3.132.1.11.0")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA224KDF", true, "1.3.132.1.14.0")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA256KDF", true, "1.3.132.1.11.1")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA256KDF", true, "1.3.132.1.14.1")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA384KDF", true, "1.3.132.1.11.2")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA384KDF", true, "1.3.132.1.14.2")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA512KDF", true, "1.3.132.1.11.3")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA512KDF", true, "1.3.132.1.14.3")); // ECMQV - Disable for now as it needs diferent params(too different from DH) //ALL.add(new KeyAgreementIdent("ECMQV")); //ALL.add(new KeyAgreementIdent("ECMQVwithSHA1CKDF", "1.3.133.16.840.63.0.16")); @@ -54,6 +56,15 @@ public class KeyAgreementIdent extends Ident { super(name, aliases); } + private KeyAgreementIdent(String name, boolean requiresKeyAlgo, String... aliases) { + this(name, aliases); + this.requiresKeyAlgo = requiresKeyAlgo; + } + + public boolean requiresKeyAlgo() { + return requiresKeyAlgo; + } + public KeyAgreement getInstance(Provider provider) throws NoSuchAlgorithmException { KeyAgreement instance = getInstance((algorithm, provider1) -> { try { diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java index 37c9add..f3242ba 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java @@ -5,6 +5,7 @@ import cz.crcs.ectester.common.util.ECUtil; import javax.crypto.KeyAgreementSpi; import javax.crypto.SecretKey; import javax.crypto.ShortBufferException; +import javax.crypto.spec.SecretKeySpec; import java.security.*; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; @@ -77,7 +78,8 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { @Override protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException { - throw new NoSuchAlgorithmException(algorithm); + // TODO: This is dangerous! + return new SecretKeySpec(engineGenerateSecret(), algorithm); } abstract byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); diff --git a/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java b/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java index 8297d76..bfd39fc 100644 --- a/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java +++ b/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java @@ -43,6 +43,7 @@ public class KeyAgreementTest extends SimpleTest { @Override public String getDescription() { - return "KeyAgreement " + testable.getKa().getAlgorithm(); + String keyAlgo = testable.getKeyAlgorithm() == null ? "" : " (" + testable.getKeyAlgorithm() + ")"; + return "KeyAgreement " + testable.getKa().getAlgorithm() + keyAlgo; } } diff --git a/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java b/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java index 1447373..1382c28 100644 --- a/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java +++ b/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java @@ -1,6 +1,7 @@ package cz.crcs.ectester.standalone.test.base; import javax.crypto.KeyAgreement; +import javax.crypto.SecretKey; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.interfaces.ECPrivateKey; @@ -18,7 +19,9 @@ public class KeyAgreementTestable extends StandaloneTestable { pw.println(); - help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + depth + "s" + key + ":", " ")); + String description = value.getDescription() == null ? "" : " | " + value.getDescription() + " |"; + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + depth + "s" + key + ":" + description, " ")); CLITools.help(help, pw, value.getParser(), value.getOptions(), depth + 1); }); } diff --git a/src/cz/crcs/ectester/common/cli/ParserOptions.java b/src/cz/crcs/ectester/common/cli/ParserOptions.java index ee2097e..7300cbb 100644 --- a/src/cz/crcs/ectester/common/cli/ParserOptions.java +++ b/src/cz/crcs/ectester/common/cli/ParserOptions.java @@ -3,25 +3,22 @@ package cz.crcs.ectester.common.cli; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.Options; -import java.util.Collections; -import java.util.List; - /** * @author Jan Jancar johny@neuromancer.sk */ public class ParserOptions { private CommandLineParser parser; private Options options; - private List arguments; + private String description; public ParserOptions(CommandLineParser parser, Options options) { this.parser = parser; this.options = options; } - public ParserOptions(CommandLineParser parser, Options options, List arguments) { + public ParserOptions(CommandLineParser parser, Options options, String description) { this(parser, options); - this.arguments = arguments; + this.description = description; } public CommandLineParser getParser() { @@ -32,7 +29,7 @@ public class ParserOptions { return options; } - public List getArguments() { - return Collections.unmodifiableList(arguments); + public String getDescription() { + return description; } } diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java index 1b85f36..148466a 100644 --- a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java @@ -27,7 +27,7 @@ public abstract class BaseTextTestWriter implements TestWriter { @Override public void begin(TestSuite suite) { output.println("═══ Running test suite: " + suite.getName() + " ═══"); - for (String d : suite.getDescription().split("\n")) { + for (String d : suite.getDescription()) { output.println("═══ " + d); } DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); diff --git a/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java index 44037bf..4e0c236 100644 --- a/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java @@ -39,7 +39,7 @@ public abstract class BaseXMLTestWriter implements TestWriter { doc = db.newDocument(); Element rootElem = doc.createElement("testSuite"); rootElem.setAttribute("name", suite.getName()); - rootElem.setAttribute("desc", suite.getDescription()); + rootElem.setAttribute("desc", suite.getTextDescription()); DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); Date date = new Date(); rootElem.setAttribute("date", dateFormat.format(date)); diff --git a/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java index 609e46d..cab2632 100644 --- a/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java +++ b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java @@ -29,7 +29,7 @@ public abstract class BaseYAMLTestWriter implements TestWriter { testSuite = new LinkedHashMap<>(); tests = new LinkedList<>(); testSuite.put("name", suite.getName()); - testSuite.put("desc", suite.getDescription()); + testSuite.put("desc", suite.getTextDescription()); DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); Date date = new Date(); diff --git a/src/cz/crcs/ectester/common/test/TestSuite.java b/src/cz/crcs/ectester/common/test/TestSuite.java index c8bb3f8..5f26f52 100644 --- a/src/cz/crcs/ectester/common/test/TestSuite.java +++ b/src/cz/crcs/ectester/common/test/TestSuite.java @@ -69,8 +69,16 @@ public abstract class TestSuite { return name; } - public String getDescription() { + public String[] getDescription() { + return description; + } + + public String getTextDescription() { return String.join(System.lineSeparator(), description); } + public String toString() { + return null; + } + } diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 9d7df4e..92b5781 100644 --- a/src/cz/crcs/ectester/reader/ECTesterReader.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -102,6 +102,11 @@ public class ECTesterReader { return; } + if (cli.hasOption("list-suites")) { + listSuites(); + return; + } + //init CardManager cardManager = new CardMngr(cfg.verbose, cfg.simulate); @@ -250,6 +255,7 @@ public class ECTesterReader { actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- compression:\n- invalid:\n- twist:\n- degenerate:\n- cofactor:\n- wrong:\n- composite:\n- test-vectors:\n- edge-cases:").hasArg().argName("test_suite").optionalArg(true).build()); actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do EC KeyAgreement (ECDH...), [count] times.").hasArg().argName("count").optionalArg(true).build()); actions.addOption(Option.builder("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build()); + actions.addOption(Option.builder("ls").longOpt("list-suites").desc("List supported test suites.").build()); opts.addOptionGroup(actions); @@ -299,6 +305,26 @@ public class ECTesterReader { return parser.parse(opts, args); } + private void listSuites() { + CardTestSuite[] suites = new CardTestSuite[]{ + new CardDefaultSuite(null, null, null), + new CardTestVectorSuite(null, null, null), + new CardCompressionSuite(null, null, null), + new CardWrongCurvesSuite(null, null, null), + new CardDegenerateCurvesSuite(null, null, null), + new CardCofactorSuite(null, null, null), + new CardCompositeCurvesSuite(null, null, null), + new CardInvalidCurvesSuite(null, null, null), + new CardEdgeCasesSuite(null, null, null), + new CardTwistTestSuite(null, null, null)}; + for (CardTestSuite suite : suites) { + System.out.println(" - " + suite.getName()); + for (String line : suite.getDescription()) { + System.out.println("\t" + line); + } + } + } + /** * Exports default card/simulation EC domain parameters to output file. * diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 18bfce6..60a33f3 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -44,6 +44,7 @@ import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import javax.crypto.KeyAgreement; +import javax.crypto.SecretKey; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.FileNotFoundException; @@ -102,6 +103,8 @@ public class ECTesterStandalone { listLibraries(); } else if (cli.isNext("list-data")) { CLITools.listNamed(EC_Store.getInstance(), cli.getNext().getArg(0)); + } else if (cli.isNext("list-suites")) { + listSuites(); } else if (cli.isNext("ecdh")) { ecdh(); } else if (cli.isNext("ecdsa")) { @@ -141,10 +144,10 @@ public class ECTesterStandalone { testOpts.addOption(Option.builder("kt").longOpt("ka-type").desc("Set the KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build()); testOpts.addOption(Option.builder("st").longOpt("sig-type").desc("Set the Signature object [type].").hasArg().argName("type").optionalArg(false).build()); testOpts.addOption(Option.builder("f").longOpt("format").desc("Set the output format, one of text,yaml,xml.").hasArg().argName("format").optionalArg(false).build()); - testOpts.addOption(Option.builder().longOpt("key-type").desc("Set the key [algorithm] for which the key should be derived in KeyAgreements with KDF.").hasArg().argName("algorithm").optionalArg(false).build()); + testOpts.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()); List testArgs = new LinkedList<>(); - testArgs.add(new Argument("test_suite", "The test suite to run.", true)); - ParserOptions test = new ParserOptions(new DefaultParser(), testOpts, testArgs); + testArgs.add(new Argument("test-suite", "The test suite to run.", true)); + ParserOptions test = new ParserOptions(new TreeParser(Collections.emptyMap(), true, testArgs), testOpts, "Test a library."); actions.put("test", test); Options ecdhOpts = new Options(); @@ -152,8 +155,9 @@ public class ECTesterStandalone { ecdhOpts.addOption(namedCurve); ecdhOpts.addOption(curveName); 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()); - ParserOptions ecdh = new ParserOptions(new DefaultParser(), ecdhOpts); + ParserOptions ecdh = new ParserOptions(new DefaultParser(), ecdhOpts, "Perform EC based KeyAgreement."); actions.put("ecdh", ecdh); Options ecdsaOpts = new Options(); @@ -163,7 +167,7 @@ public class ECTesterStandalone { 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()); - ParserOptions ecdsa = new ParserOptions(new DefaultParser(), ecdsaOpts); + ParserOptions ecdsa = new ParserOptions(new DefaultParser(), ecdsaOpts, "Perform EC based Signature."); actions.put("ecdsa", ecdsa); Options generateOpts = new Options(); @@ -172,25 +176,29 @@ public class ECTesterStandalone { generateOpts.addOption(curveName); 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); + ParserOptions generate = new ParserOptions(new DefaultParser(), generateOpts, "Generate EC keypairs."); actions.put("generate", generate); Options exportOpts = new Options(); exportOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPair object [type].").build()); exportOpts.addOption(bits); - ParserOptions export = new ParserOptions(new DefaultParser(), exportOpts); + ParserOptions export = new ParserOptions(new DefaultParser(), exportOpts, "Export default curve parameters."); actions.put("export", export); Options listDataOpts = new Options(); List listDataArgs = new LinkedList<>(); listDataArgs.add(new Argument("what", "what to list.", false)); - ParserOptions listData = new ParserOptions(new TreeParser(Collections.emptyMap(), false, listDataArgs), listDataOpts); + ParserOptions listData = new ParserOptions(new TreeParser(Collections.emptyMap(), false, listDataArgs), listDataOpts, "List/show contained EC domain parameters/keys."); actions.put("list-data", listData); Options listLibsOpts = new Options(); - ParserOptions listLibs = new ParserOptions(new DefaultParser(), listLibsOpts); + ParserOptions listLibs = new ParserOptions(new DefaultParser(), listLibsOpts, "List supported libraries."); actions.put("list-libs", listLibs); + Options listSuitesOpts = new Options(); + ParserOptions listSuites = new ParserOptions(new DefaultParser(), listSuitesOpts, "List supported test suites."); + actions.put("list-suites", listSuites); + List baseArgs = new LinkedList<>(); baseArgs.add(new Argument("lib", "What library to use.", false)); optParser = new TreeParser(actions, false, baseArgs); @@ -229,6 +237,19 @@ public class ECTesterStandalone { } } + /** + * + */ + private void listSuites() { + StandaloneTestSuite[] suites = new StandaloneTestSuite[]{new StandaloneDefaultSuite(null, null, null)}; + for (StandaloneTestSuite suite : suites) { + System.out.println(" - " + suite.getName()); + for (String line : suite.getDescription()) { + System.out.println("\t" + line); + } + } + } + /** * */ @@ -236,6 +257,7 @@ public class ECTesterStandalone { ProviderECLibrary lib = cfg.selected; String algo = cli.getOptionValue("ecdh.type", "ECDH"); + String keyAlgo = cli.getOptionValue("ecdh.key-type", "AES"); KeyAgreementIdent kaIdent = lib.getKAs().stream() .filter((ident) -> ident.contains(algo)) .findFirst() @@ -295,7 +317,14 @@ public class ECTesterStandalone { } ka.doPhase(pubkey, true); elapsed += System.nanoTime(); - byte[] result = ka.generateSecret(); + SecretKey derived; + byte[] result; + if (kaIdent.requiresKeyAlgo()) { + derived = ka.generateSecret(keyAlgo); + result = derived.getEncoded(); + } else { + result = ka.generateSecret(); + } ka = kaIdent.getInstance(lib.getProvider()); String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false); -- cgit v1.2.3-70-g09d2 From f4063951527fa533d0b59998019b1a800dbc02d0 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 30 May 2018 01:50:23 +0200 Subject: Add basic support for the Crypto++ library. --- build-standalone.xml | 7 + docs/LIBS.md | 5 +- nbproject/reader/project.properties | 2 +- nbproject/standalone/project.properties | 2 +- .../ectester/standalone/ECTesterStandalone.java | 10 +- .../crcs/ectester/standalone/libs/CryptoppLib.java | 20 +++ src/cz/crcs/ectester/standalone/libs/jni/Makefile | 51 ++++--- .../standalone/libs/jni/NativeECPrivateKey.java | 6 + .../standalone/libs/jni/NativeECPublicKey.java | 7 + .../standalone/libs/jni/NativeKeyAgreementSpi.java | 20 ++- .../libs/jni/NativeKeyPairGeneratorSpi.java | 28 ++++ .../standalone/libs/jni/NativeProvider.java | 10 ++ src/cz/crcs/ectester/standalone/libs/jni/botan.cpp | 151 +++++---------------- .../ectester/standalone/libs/jni/cpp_utils.cpp | 24 ++++ .../ectester/standalone/libs/jni/cpp_utils.hpp | 8 +- .../crcs/ectester/standalone/libs/jni/cryptopp.cpp | 121 +++++++++++++++++ src/cz/crcs/ectester/standalone/libs/jni/native.h | 144 ++++++++++++++++++++ 17 files changed, 471 insertions(+), 145 deletions(-) create mode 100644 src/cz/crcs/ectester/standalone/libs/CryptoppLib.java create mode 100644 src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/build-standalone.xml b/build-standalone.xml index dcfb1f3..9d0fa75 100644 --- a/build-standalone.xml +++ b/build-standalone.xml @@ -115,6 +115,13 @@ + + + + + + + diff --git a/docs/LIBS.md b/docs/LIBS.md index 5c132f7..f6d3896 100644 --- a/docs/LIBS.md +++ b/docs/LIBS.md @@ -2,7 +2,6 @@ Popular libraries with at least some ECC support: - - [Crypto++](https://cryptopp.com/) - [libgcrypt](https://www.gnupg.org/related_software/libgcrypt/) - [mbedTLS](https://tls.mbed.org/) - [Nettle](http://www.lysator.liu.se/~nisse/nettle/) @@ -27,4 +26,6 @@ Popular libraries with at least some ECC support: - [libtomcrypt](http://www.libtom.net/LibTomCrypt/) - C - Uses Jacobian coordinates. - - Sliding window scalar multiplication algorithm. \ No newline at end of file + - Sliding window scalar multiplication algorithm. + - [Crypto++](https://cryptopp.com/) + - C++ \ No newline at end of file diff --git a/nbproject/reader/project.properties b/nbproject/reader/project.properties index b738c2d..8e11520 100644 --- a/nbproject/reader/project.properties +++ b/nbproject/reader/project.properties @@ -6,7 +6,7 @@ annotation.processing.source.output=${build.generated.sources.dir}/ap-source-out application.title=ECTesterReader application.vendor=xsvenda build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.h,**/*.a,**/*.o,**/Makefile +build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile # This directory is removed when the project is cleaned: build.dir=build build.generated.dir=${build.dir}/generated diff --git a/nbproject/standalone/project.properties b/nbproject/standalone/project.properties index 355ea58..ee584b2 100644 --- a/nbproject/standalone/project.properties +++ b/nbproject/standalone/project.properties @@ -6,7 +6,7 @@ annotation.processing.source.output=${build.generated.sources.dir}/ap-source-out application.title=ECTesterStandalone application.vendor=xsvenda build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.h,**/*.a,**/*.o,**/Makefile +build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile # This directory is removed when the project is cleaned: build.dir=build build.generated.dir=${build.dir}/generated diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 60a33f3..5a7b79a 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -66,7 +66,7 @@ import java.util.stream.Collectors; * @version v0.2.0 */ public class ECTesterStandalone { - private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib()}; + private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib()}; private Config cfg; private Options opts = new Options(); @@ -218,19 +218,19 @@ public class ECTesterStandalone { System.out.println("\t- " + lib.name()); Set kpgs = lib.getKPGs(); if (!kpgs.isEmpty()) { - System.out.println("\t\t- KeyPairGenerators: " + String.join(",", kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.toList()))); + System.out.println("\t\t- KeyPairGenerators: " + String.join(", ", kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.toList()))); } Set eckas = lib.getKAs(); if (!eckas.isEmpty()) { - System.out.println("\t\t- KeyAgreements: " + String.join(",", eckas.stream().map(KeyAgreementIdent::getName).collect(Collectors.toList()))); + System.out.println("\t\t- KeyAgreements: " + String.join(", ", eckas.stream().map(KeyAgreementIdent::getName).collect(Collectors.toList()))); } Set sigs = lib.getSigs(); if (!sigs.isEmpty()) { - System.out.println("\t\t- Signatures: " + String.join(",", sigs.stream().map(SignatureIdent::getName).collect(Collectors.toList()))); + System.out.println("\t\t- Signatures: " + String.join(", ", sigs.stream().map(SignatureIdent::getName).collect(Collectors.toList()))); } Set curves = lib.getCurves(); if (!curves.isEmpty()) { - System.out.println("\t\t- Curves: " + String.join(",", curves)); + System.out.println("\t\t- Curves: " + String.join(", ", curves)); } System.out.println(); } diff --git a/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java b/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java new file mode 100644 index 0000000..5112d7d --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java @@ -0,0 +1,20 @@ +package cz.crcs.ectester.standalone.libs; + +import java.security.Provider; +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CryptoppLib extends NativeECLibrary { + + public CryptoppLib() { + super("cryptopp_provider", "cryptopp"); + } + + @Override + native Provider createProvider(); + + @Override + public native Set getCurves(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile index 732ab20..beeefdf 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile +++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile @@ -1,31 +1,32 @@ ifeq ($(JAVA_HOME),) -ifeq ($(OS),Windows_NT) -which = $(shell where $1) -else -which = $(shell which $1) -endif -JAVAC ?= $(realpath $(call which,javac)) -JAVA_HOME = $(abspath $(dir $(JAVAC))..) + ifeq ($(OS),Windows_NT) + which = $(shell where $1) + else + which = $(shell which $1) + endif + JAVAC ?= $(realpath $(call which,javac)) + JAVA_HOME = $(abspath $(dir $(JAVAC))..) endif ifneq ($(JAVA_HOME),) -JNI_INCLUDEDIR ?= $(JAVA_HOME)/include + JNI_INCLUDEDIR ?= $(JAVA_HOME)/include endif ifeq ($(JNI_INCLUDEDIR),) -$(error could not determine JNI include dir, try specifying either JAVA_HOME or JNI_INCLUDEDIR) + $(error Could not determine JNI include dir. Try specifying either JAVA_HOME or JNI_INCLUDEDIR.) endif TARGETTRIPLET := $(shell $(CC) -dumpmachine) + ifeq ($(JNI_PLATFORM),) -ifeq ($(findstring mingw,$(TARGETTRIPLET)),mingw) -JNI_PLATFORM:= win32 -else -ifeq ($(findstring linux,$(TARGETTRIPLET)),linux) -JNI_PLATFORM:= linux -# add more checks here -endif -endif + ifeq ($(findstring mingw,$(TARGETTRIPLET)),mingw) + JNI_PLATFORM:= win32 + else + ifeq ($(findstring linux,$(TARGETTRIPLET)),linux) + JNI_PLATFORM:= linux + # add more checks here + endif + endif endif JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM) @@ -40,8 +41,9 @@ CFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. CXXFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. -all: tomcrypt_provider.so botan_provider.so +all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so +# Common utils c_utils.o: c_utils.c $(CC) $(CFLAGS) -c $< @@ -49,6 +51,7 @@ cpp_utils.o: cpp_utils.cpp $(CXX) $(CXXFLAGS) -c $< +# Libtomcrypt shim tomcrypt_provider.so: tomcrypt.o c_utils.o $(CC) -fPIC -g -shared -o $@ $^ -L. -ltommath $(shell pkg-config --libs libtomcrypt) @@ -56,11 +59,21 @@ tomcrypt.o: tomcrypt.c $(CC) -DLTM_DESC $(shell pkg-config --cflags libtomcrypt) $(CFLAGS) -c $< +# Botan-2 shim botan_provider.so: botan.o cpp_utils.o $(CXX) -fPIC -g -shared -o $@ $^ -L. $(shell pkg-config --libs botan-2) botan.o: botan.cpp - $(CXX) $(shell pkg-config --cflags botan-2) $(CFLAGS) -c $< + $(CXX) $(shell pkg-config --cflags botan-2) $(CXXFLAGS) -c $< + + +# Crypto++ shim +cryptopp_provider.so: cryptopp.o cpp_utils.o + $(CXX) -fPIC -g -shared -o $@ $^ -L. $(shell pkg-config --libs libcrypto++) + +cryptopp.o: cryptopp.cpp + $(CXX) $(shell pkg-config --cflags libcrypto++) $(CXXFLAGS) -c $< + clean: rm -rf *.o diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java index 22e5329..a209fa1 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java @@ -65,4 +65,10 @@ public abstract class NativeECPrivateKey implements ECPrivateKey { super(keyData, params); } } + + public static class Cryptopp extends Raw { + public Cryptopp(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java index 8fc4747..f53cd26 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java @@ -3,6 +3,7 @@ package cz.crcs.ectester.standalone.libs.jni; import cz.crcs.ectester.common.util.ECUtil; import org.bouncycastle.util.Arrays; +import javax.swing.event.AncestorEvent; import java.security.interfaces.ECPublicKey; import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; @@ -66,4 +67,10 @@ public abstract class NativeECPublicKey implements ECPublicKey { super(keyData, params); } } + + public static class Cryptopp extends ANSIX962 { + public Cryptopp(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java index f3242ba..fc1b8d7 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java @@ -78,7 +78,7 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { @Override protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException { - // TODO: This is dangerous! + // TODO: This is dangerous/not correct ! Need to actually implement KDF1 and KDF2 here probably. return new SecretKeySpec(engineGenerateSecret(), algorithm); } @@ -93,6 +93,7 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { public abstract static class Botan extends NativeKeyAgreementSpi { private String type; + public Botan(String type) { this.type = type; } @@ -136,4 +137,21 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { super("ECDHwithSHA512KDF"); } } + + public abstract static class Cryptopp extends NativeKeyAgreementSpi { + private String type; + + public Cryptopp(String type) { + this.type = type; + } + + @Override + native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + } + + public static class CryptoppECDH extends Cryptopp { + public CryptoppECDH() { + super("ECDH"); + } + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java index 9461251..54aa37e 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java @@ -120,4 +120,32 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { super("ECGDSA"); } } + + public static abstract class Cryptopp extends NativeKeyPairGeneratorSpi { + private String type; + + public Cryptopp(String type) { + this.type = type; + initialize(256, new SecureRandom()); + } + + @Override + native boolean keysizeSupported(int keysize); + + @Override + native boolean paramsSupported(AlgorithmParameterSpec params); + + @Override + native KeyPair generate(int keysize, SecureRandom random); + + @Override + native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); + } + + public static class CryptoppECDH extends Botan { + + public CryptoppECDH() { + super("ECDH"); + } + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java index a0689d6..593295e 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java @@ -39,4 +39,14 @@ public abstract class NativeProvider extends Provider { @Override native void setup(); } + + public static class Cryptopp extends NativeProvider { + + public Cryptopp(String name, double version, String info) { + super(name, version, info); + } + + @Override + native void setup(); + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp index 3bb43a2..6a1e6d6 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp @@ -52,117 +52,38 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createP JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Botan_setup(JNIEnv *env, jobject self){ jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); - jstring ecdh = env->NewStringUTF("KeyPairGenerator.ECDH"); - jstring ecdh_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECDH"); - env->CallObjectMethod(self, provider_put, ecdh, ecdh_value); - - jstring ecdsa = env->NewStringUTF("KeyPairGenerator.ECDSA"); - jstring ecdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECDSA"); - env->CallObjectMethod(self, provider_put, ecdsa, ecdsa_value); - - jstring eckcdsa = env->NewStringUTF("KeyPairGenerator.ECKCDSA"); - jstring eckcdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECKCDSA"); - env->CallObjectMethod(self, provider_put, eckcdsa, eckcdsa_value); - - jstring ecgdsa = env->NewStringUTF("KeyPairGenerator.ECGDSA"); - jstring ecgdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECGDSA"); - env->CallObjectMethod(self, provider_put, ecgdsa, ecgdsa_value); - - jstring ecdh_ka = env->NewStringUTF("KeyAgreement.ECDH"); - jstring ecdh_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDH"); - env->CallObjectMethod(self, provider_put, ecdh_ka, ecdh_ka_value); - - jstring ecdh_sha1_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA1KDF"); - jstring ecdh_sha1_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA1KDF"); - env->CallObjectMethod(self, provider_put, ecdh_sha1_ka, ecdh_sha1_ka_value); - - jstring ecdh_sha224_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA224KDF"); - jstring ecdh_sha224_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA224KDF"); - env->CallObjectMethod(self, provider_put, ecdh_sha224_ka, ecdh_sha224_ka_value); - - jstring ecdh_sha256_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA256KDF"); - jstring ecdh_sha256_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA256KDF"); - env->CallObjectMethod(self, provider_put, ecdh_sha256_ka, ecdh_sha256_ka_value); - - jstring ecdh_sha384_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA384KDF"); - jstring ecdh_sha384_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA384KDF"); - env->CallObjectMethod(self, provider_put, ecdh_sha384_ka, ecdh_sha384_ka_value); - - jstring ecdh_sha512_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA512KDF"); - jstring ecdh_sha512_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA512KDF"); - env->CallObjectMethod(self, provider_put, ecdh_sha512_ka, ecdh_sha512_ka_value); - - jstring ecdsa_sig = env->NewStringUTF("Signature.NONEwithECDSA"); - jstring ecdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithNONE"); - env->CallObjectMethod(self, provider_put, ecdsa_sig, ecdsa_sig_value); - - jstring ecdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECDSA"); - jstring ecdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA1"); - env->CallObjectMethod(self, provider_put, ecdsa_sha1_sig, ecdsa_sha1_sig_value); - - jstring ecdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECDSA"); - jstring ecdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA224"); - env->CallObjectMethod(self, provider_put, ecdsa_sha224_sig, ecdsa_sha224_sig_value); - - jstring ecdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECDSA"); - jstring ecdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA256"); - env->CallObjectMethod(self, provider_put, ecdsa_sha256_sig, ecdsa_sha256_sig_value); - - jstring ecdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECDSA"); - jstring ecdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA384"); - env->CallObjectMethod(self, provider_put, ecdsa_sha384_sig, ecdsa_sha384_sig_value); - - jstring ecdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECDSA"); - jstring ecdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA512"); - env->CallObjectMethod(self, provider_put, ecdsa_sha512_sig, ecdsa_sha512_sig_value); + add_kpg(env, "ECDH", "BotanECDH", self, provider_put); + add_kpg(env, "ECDSA", "BotanECDSA", self, provider_put); + add_kpg(env, "ECKCDSA", "BotanECKCDSA", self, provider_put); + add_kpg(env, "ECGDSA", "BotanECGDSA", self, provider_put); + + add_ka(env, "ECDH", "BotanECDH", self, provider_put); + add_ka(env, "ECDHwithSHA1KDF", "BotanECDHwithSHA1KDF", self, provider_put); + add_ka(env, "ECDHwithSHA224KDF", "BotanECDHwithSHA224KDF", self, provider_put); + add_ka(env, "ECDHwithSHA256KDF", "BotanECDHwithSHA256KDF", self, provider_put); + add_ka(env, "ECDHwithSHA384KDF", "BotanECDHwithSHA384KDF", self, provider_put); + add_ka(env, "ECDHwithSHA512KDF", "BotanECDHwithSHA512KDF", self, provider_put); + + add_sig(env, "NONEwithECDSA", "BotanECDSAwithNONE", self, provider_put); + add_sig(env, "SHA1withECDSA", "BotanECDSAwithSHA1", self, provider_put); + add_sig(env, "SHA224withECDSA", "BotanECDSAwithSHA224", self, provider_put); + add_sig(env, "SHA256withECDSA", "BotanECDSAwithSHA256", self, provider_put); + add_sig(env, "SHA384withECDSA", "BotanECDSAwithSHA384", self, provider_put); + add_sig(env, "SHA512withECDSA", "BotanECDSAwithSHA512", self, provider_put); + + add_sig(env, "NONEwithECKCDSA", "BotanECKCDSAwithNONE", self, provider_put); + add_sig(env, "SHA1withECKCDSA", "BotanECKCDSAwithSHA1", self, provider_put); + add_sig(env, "SHA224withECKCDSA", "BotanECKCDSAwithSHA224", self, provider_put); + add_sig(env, "SHA256withECKCDSA", "BotanECKCDSAwithSHA256", self, provider_put); + add_sig(env, "SHA384withECKCDSA", "BotanECKCDSAwithSHA384", self, provider_put); + add_sig(env, "SHA512withECKCDSA", "BotanECKCDSAwithSHA512", self, provider_put); - jstring eckcdsa_sig = env->NewStringUTF("Signature.NONEwithECKCDSA"); - jstring eckcdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithNONE"); - env->CallObjectMethod(self, provider_put, eckcdsa_sig, eckcdsa_sig_value); - - jstring eckcdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECKCDSA"); - jstring eckcdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA1"); - env->CallObjectMethod(self, provider_put, eckcdsa_sha1_sig, eckcdsa_sha1_sig_value); - - jstring eckcdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECKCDSA"); - jstring eckcdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA224"); - env->CallObjectMethod(self, provider_put, eckcdsa_sha224_sig, eckcdsa_sha224_sig_value); - - jstring eckcdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECKCDSA"); - jstring eckcdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA256"); - env->CallObjectMethod(self, provider_put, eckcdsa_sha256_sig, eckcdsa_sha256_sig_value); - - jstring eckcdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECKCDSA"); - jstring eckcdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA384"); - env->CallObjectMethod(self, provider_put, eckcdsa_sha384_sig, eckcdsa_sha384_sig_value); - - jstring eckcdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECKCDSA"); - jstring eckcdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA512"); - env->CallObjectMethod(self, provider_put, eckcdsa_sha512_sig, eckcdsa_sha512_sig_value); - - jstring ecgdsa_sig = env->NewStringUTF("Signature.NONEwithECGDSA"); - jstring ecgdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithNONE"); - env->CallObjectMethod(self, provider_put, ecgdsa_sig, ecgdsa_sig_value); - - jstring ecgdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECGDSA"); - jstring ecgdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA1"); - env->CallObjectMethod(self, provider_put, ecgdsa_sha1_sig, ecgdsa_sha1_sig_value); - - jstring ecgdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECGDSA"); - jstring ecgdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA224"); - env->CallObjectMethod(self, provider_put, ecgdsa_sha224_sig, ecgdsa_sha224_sig_value); - - jstring ecgdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECGDSA"); - jstring ecgdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA256"); - env->CallObjectMethod(self, provider_put, ecgdsa_sha256_sig, ecgdsa_sha256_sig_value); - - jstring ecgdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECGDSA"); - jstring ecgdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA384"); - env->CallObjectMethod(self, provider_put, ecgdsa_sha384_sig, ecgdsa_sha384_sig_value); - - jstring ecgdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECGDSA"); - jstring ecgdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA512"); - env->CallObjectMethod(self, provider_put, ecgdsa_sha512_sig, ecgdsa_sha512_sig_value); + add_sig(env, "NONEwithECGDSA", "BotanECGDSAwithNONE", self, provider_put); + add_sig(env, "SHA1withECGDSA", "BotanECGDSAwithSHA1", self, provider_put); + add_sig(env, "SHA224withECGDSA", "BotanECGDSAwithSHA224", self, provider_put); + add_sig(env, "SHA256withECGDSA", "BotanECGDSAwithSHA256", self, provider_put); + add_sig(env, "SHA384withECGDSA", "BotanECGDSAwithSHA384", self, provider_put); + add_sig(env, "SHA512withECGDSA", "BotanECGDSAwithSHA512", self, provider_put); init_classes(env, "Botan"); } @@ -173,18 +94,18 @@ JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_ * Signature: ()Ljava/util/Set; */ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurves(JNIEnv *env, jobject self){ - jclass hash_set_class = env->FindClass("java/util/TreeSet"); + jclass set_class = env->FindClass("java/util/TreeSet"); - jmethodID hash_set_ctr = env->GetMethodID(hash_set_class, "", "()V"); - jmethodID hash_set_add = env->GetMethodID(hash_set_class, "add", "(Ljava/lang/Object;)Z"); + jmethodID set_ctr = env->GetMethodID(set_class, "", "()V"); + jmethodID set_add = env->GetMethodID(set_class, "add", "(Ljava/lang/Object;)Z"); - jobject result = env->NewObject(hash_set_class, hash_set_ctr); + jobject result = env->NewObject(set_class, set_ctr); const std::set& curves = Botan::EC_Group::known_named_groups(); for (auto it = curves.begin(); it != curves.end(); ++it) { std::string curve_name = *it; jstring name_str = env->NewStringUTF(curve_name.c_str()); - env->CallBooleanMethod(result, hash_set_add, name_str); + env->CallBooleanMethod(result, set_add, name_str); } return result; diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp index cef4bfe..2e93a71 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp @@ -56,4 +56,28 @@ void init_classes(JNIEnv *env, std::string lib_name) { void throw_new(JNIEnv *env, const std::string& klass, const std::string& message) { jclass clazz = env->FindClass(klass.c_str()); env->ThrowNew(clazz, message.c_str()); +} + +static void add_provider_property(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method) { + jstring type_str = env->NewStringUTF(type.c_str()); + jstring class_str = env->NewStringUTF(klass.c_str()); + env->CallObjectMethod(provider, put_method, type_str, class_str); +} + +void add_kpg(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method) { + const std::string full_type = "KeyPairGenerator." + type; + const std::string full_class = "cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$" + klass; + add_provider_property(env, full_type, full_class, provider, put_method); +} + +void add_ka(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method) { + const std::string full_type = "KeyAgreement." + type; + const std::string full_class = "cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$" + klass; + add_provider_property(env, full_type, full_class, provider, put_method); +} + +void add_sig(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method) { + const std::string full_type = "Signature." + type; + const std::string full_class = "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$" + klass; + add_provider_property(env, full_type, full_class, provider, put_method); } \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp index bbca521..f647bd6 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp @@ -26,4 +26,10 @@ void init_classes(JNIEnv *env, std::string lib_name); /** * Throw a new exception of class with message. */ -void throw_new(JNIEnv *env, const std::string& klass, const std::string& message); \ No newline at end of file +void throw_new(JNIEnv *env, const std::string& klass, const std::string& message); + +void add_kpg(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method); + +void add_ka(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method); + +void add_sig(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method); \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp new file mode 100644 index 0000000..0432247 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp @@ -0,0 +1,121 @@ +#include "native.h" + +#include +using std::cout; +using std::cerr; +using std::endl; + +#include +#include +using std::string; + +#include +using std::runtime_error; + +#include +using std::exit; + +#include "cryptopp/osrng.h" +using CryptoPP::AutoSeededRandomPool; +using CryptoPP::AutoSeededX917RNG; + +#include "cryptopp/aes.h" +using CryptoPP::AES; + +#include "cryptopp/eccrypto.h" +using CryptoPP::ECP; +using CryptoPP::ECDH; +using CryptoPP::DL_GroupParameters_EC; + +#include "cryptopp/secblock.h" +using CryptoPP::SecByteBlock; + +#include "cryptopp/oids.h" +using CryptoPP::OID; + +// ASN1 is a namespace, not an object +#include "cryptopp/asn.h" +using namespace CryptoPP::ASN1; + +#include "cryptopp/integer.h" +using CryptoPP::Integer; + + +#include "cpp_utils.hpp" + +static jclass provider_class; + + +/* + * Class: cz_crcs_ectester_standalone_libs_CryptoppLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_createProvider(JNIEnv *env, jobject self) { + /* Create the custom provider. */ + jclass local_provider_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeProvider$Cryptopp"); + provider_class = (jclass) env->NewGlobalRef(local_provider_class); + + jmethodID init = env->GetMethodID(local_provider_class, "", "(Ljava/lang/String;DLjava/lang/String;)V"); + + std::string lib_name = "Crypto++"; + + int lib_version = CRYPTOPP_VERSION; + std::string info_str = std::to_string(lib_version); + std::stringstream ss; + ss << lib_name << " "; + ss << info_str[0]; + for (int i = 1; i < info_str.size(); ++i) { + ss << "." << info_str[i]; + } + + jstring name = env->NewStringUTF(lib_name.c_str()); + double version = lib_version / 100; + jstring info = env->NewStringUTF(ss.str().c_str()); + + return env->NewObject(provider_class, init, name, version, info); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Cryptopp_setup(JNIEnv *env, jobject self){ + jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + init_classes(env, "Cryptopp"); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_CryptoppLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getCurves(JNIEnv *env, jobject self){ + jclass set_class = env->FindClass("java/util/TreeSet"); + + jmethodID set_ctr = env->GetMethodID(set_class, "", "()V"); + jmethodID set_add = env->GetMethodID(set_class, "add", "(Ljava/lang/Object;)Z"); + + jobject result = env->NewObject(set_class, set_ctr); + + OID it = OID(); + do { + it = DL_GroupParameters_EC::GetNextRecommendedParametersOID(it); + if (it == OID()) { + break; + } + const std::vector& oid_values = it.GetValues(); + std::stringstream ss; + for (size_t i = 0; i < oid_values.size(); ++i) { + if(i != 0) + ss << "."; + ss << std::to_string(oid_values[i]); + } + jstring name_str = env->NewStringUTF(ss.str().c_str()); + env->CallBooleanMethod(result, set_add, name_str); + } while (true); + + return result; +} \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index d714b39..61c4411 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -342,3 +342,147 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna } #endif #endif +/* Header for class cz_crcs_ectester_standalone_libs_CryptoppLib */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_CryptoppLib +#define _Included_cz_crcs_ectester_standalone_libs_CryptoppLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_CryptoppLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_createProvider + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_CryptoppLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getCurves + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID 1421746759512286392LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_MAX_ARRAY_SIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_MAX_ARRAY_SIZE 2147483639L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_KEYS +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_KEYS 0L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_VALUES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_VALUES 1L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_ENTRIES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_ENTRIES 2L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID 4112578634029874840LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID -4298000515446427739LL +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Cryptopp_setup + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_keysizeSupported + (JNIEnv *, jobject, jint); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_paramsSupported + (JNIEnv *, jobject, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__ILjava_security_SecureRandom_2 + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2 + (JNIEnv *, jobject, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Cryptopp */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Cryptopp +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Cryptopp +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Cryptopp */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Cryptopp +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Cryptopp +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Cryptopp_generateSecret + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif -- cgit v1.2.3-70-g09d2 From 46f3b1218d55ea856986cd7afb4804152c230c4f Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 30 May 2018 21:38:20 +0200 Subject: Add support for key generation using Crypto++. --- nbproject/dist-build.xml | 2 +- nbproject/standalone/project.properties | 2 +- .../ectester/standalone/ECTesterStandalone.java | 35 +- .../libs/jni/NativeKeyPairGeneratorSpi.java | 8 +- .../crcs/ectester/standalone/libs/jni/cryptopp.cpp | 482 ++++++++++++++++++++- 5 files changed, 493 insertions(+), 36 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/nbproject/dist-build.xml b/nbproject/dist-build.xml index cde2e4a..c317d95 100644 --- a/nbproject/dist-build.xml +++ b/nbproject/dist-build.xml @@ -25,7 +25,7 @@ + excludes="META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA, ${dist.archive.excludes}"/> diff --git a/nbproject/standalone/project.properties b/nbproject/standalone/project.properties index ee584b2..7ad08a1 100644 --- a/nbproject/standalone/project.properties +++ b/nbproject/standalone/project.properties @@ -22,7 +22,7 @@ debug.classpath=\ debug.test.classpath=\ ${run.test.classpath} # Files in build.classes.dir which should be excluded from distribution jar -dist.archive.excludes= +dist.archive.excludes=**/*.java,**/*.form,**/*.c,**/*.cpp,**/*.hpp,**/*.h,**/*.a,**/*.o,**/Makefile # This directory is removed when the project is cleaned: dist.dir=dist dist.jar=${dist.dir}/ECTesterStandalone.jar diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 5a7b79a..92a3a27 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -213,7 +213,7 @@ public class ECTesterStandalone { * */ private void listLibraries() { - for (ECLibrary lib : libs) { + for (ProviderECLibrary lib : libs) { if (lib.isInitialized() && (cfg.selected == null || lib == cfg.selected)) { System.out.println("\t- " + lib.name()); Set kpgs = lib.getKPGs(); @@ -233,6 +233,7 @@ public class ECTesterStandalone { System.out.println("\t\t- Curves: " + String.join(", ", curves)); } System.out.println(); + System.out.println(lib.getProvider().entrySet()); } } } @@ -562,22 +563,24 @@ public class ECTesterStandalone { } } - String libraryName = cli.getArg(-1); - if (libraryName != null) { - List matchedLibs = new LinkedList<>(); - for (ProviderECLibrary lib : libs) { - if (lib.isInitialized() && lib.name().toLowerCase().contains(libraryName.toLowerCase())) { - matchedLibs.add(lib); + if (!cli.isNext("list-data") && !cli.isNext("list-suites")) { + String libraryName = cli.getArg(-1); + if (libraryName != null) { + List matchedLibs = new LinkedList<>(); + for (ProviderECLibrary lib : libs) { + if (lib.isInitialized() && lib.name().toLowerCase().contains(libraryName.toLowerCase())) { + matchedLibs.add(lib); + } + } + if (matchedLibs.size() == 0) { + System.err.println("No library " + libraryName + " found."); + return false; + } else if (matchedLibs.size() > 1) { + System.err.println("Multiple matching libraries found: " + String.join(",", matchedLibs.stream().map(ECLibrary::name).collect(Collectors.toList()))); + return false; + } else { + selected = matchedLibs.get(0); } - } - if (matchedLibs.size() == 0) { - System.err.println("No library " + libraryName + " found."); - return false; - } else if (matchedLibs.size() > 1) { - System.err.println("Multiple matching libraries found: " + String.join(",", matchedLibs.stream().map(ECLibrary::name).collect(Collectors.toList()))); - return false; - } else { - selected = matchedLibs.get(0); } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java index 54aa37e..7a2d6a0 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java @@ -56,7 +56,7 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { public static class TomCrypt extends NativeKeyPairGeneratorSpi { public TomCrypt() { - initialize(256, new SecureRandom()); + initialize(256, new SecureRandom());//TODO: maybe remove this default init? } @Override @@ -77,7 +77,7 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { public Botan(String type) { this.type = type; - initialize(256, new SecureRandom()); + initialize(256, new SecureRandom());//TODO: maybe remove this default init? } @Override @@ -126,7 +126,7 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { public Cryptopp(String type) { this.type = type; - initialize(256, new SecureRandom()); + initialize(256, new SecureRandom());//TODO: maybe remove this default init? } @Override @@ -142,7 +142,7 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); } - public static class CryptoppECDH extends Botan { + public static class CryptoppECDH extends Cryptopp { public CryptoppECDH() { super("ECDH"); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp index 0432247..f707891 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp @@ -15,6 +15,9 @@ using std::runtime_error; #include using std::exit; +#include "cryptopp/config.h" +using CryptoPP::byte; + #include "cryptopp/osrng.h" using CryptoPP::AutoSeededRandomPool; using CryptoPP::AutoSeededX917RNG; @@ -22,8 +25,18 @@ using CryptoPP::AutoSeededX917RNG; #include "cryptopp/aes.h" using CryptoPP::AES; +#include "cryptopp/modarith.h" +using CryptoPP::ModularArithmetic; + +#include "cryptopp/gf2n.h" +using CryptoPP::PolynomialMod2; +using CryptoPP::GF2NP; +using CryptoPP::GF2NT; +using CryptoPP::GF2NPP; + #include "cryptopp/eccrypto.h" using CryptoPP::ECP; +using CryptoPP::EC2N; using CryptoPP::ECDH; using CryptoPP::DL_GroupParameters_EC; @@ -84,9 +97,47 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_crea JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Cryptopp_setup(JNIEnv *env, jobject self){ jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + add_kpg(env, "ECDH", "CryptoppECDH", self, provider_put); + //add_kpg(env, "ECDH", "CryptoppECDH", self, provider_put); + init_classes(env, "Cryptopp"); } +template static std::vector get_curve_oids() { + std::vector oids; + OID it = OID(); + do { + it = DL_GroupParameters_EC::GetNextRecommendedParametersOID(it); + if (it == OID()) { + break; + } + oids.push_back(it); + } while (true); + + return oids; +} + +static std::vector get_all_curve_oids() { + std::vector ecp_oids = get_curve_oids(); + std::vector ec2n_oids = get_curve_oids(); + + std::vector all_oids; + all_oids.insert(all_oids.end(), ecp_oids.begin(), ecp_oids.end()); + all_oids.insert(all_oids.end(), ec2n_oids.begin(), ec2n_oids.end()); + return all_oids; +} + +static std::string oid_to_str(const OID &oid) { + const std::vector& oid_values = oid.GetValues(); + std::stringstream ss; + for (size_t i = 0; i < oid_values.size(); ++i) { + if(i != 0) + ss << "."; + ss << std::to_string(oid_values[i]); + } + return ss.str(); +} + /* * Class: cz_crcs_ectester_standalone_libs_CryptoppLib * Method: getCurves @@ -100,22 +151,425 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getC jobject result = env->NewObject(set_class, set_ctr); - OID it = OID(); - do { - it = DL_GroupParameters_EC::GetNextRecommendedParametersOID(it); - if (it == OID()) { - break; + std::vector all_oids = get_all_curve_oids(); + + for (auto oid = all_oids.begin(); oid != all_oids.end(); ++oid) { + jstring name_str = env->NewStringUTF(oid_to_str(*oid).c_str()); + env->CallBooleanMethod(result, set_add, name_str); + } + + return result; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_keysizeSupported(JNIEnv *env, jobject self, jint keysize){ + std::vector ecp_oids = get_curve_oids(); + for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) { + DL_GroupParameters_EC group(*oid); + if (((jint) group.GetCurve().GetField().MaxElementBitLength()) == keysize) { + return JNI_TRUE; } - const std::vector& oid_values = it.GetValues(); - std::stringstream ss; - for (size_t i = 0; i < oid_values.size(); ++i) { - if(i != 0) - ss << "."; - ss << std::to_string(oid_values[i]); + } + + std::vector e2n_oids = get_curve_oids(); + for (auto oid = e2n_oids.begin(); oid != e2n_oids.end(); ++oid) { + DL_GroupParameters_EC group(*oid); + if (((jint) group.GetCurve().FieldSize().ConvertToLong()) == keysize) { + return JNI_TRUE; } - jstring name_str = env->NewStringUTF(ss.str().c_str()); - env->CallBooleanMethod(result, set_add, name_str); - } while (true); + } + return JNI_FALSE; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_paramsSupported(JNIEnv *env, jobject self, jobject params){ + if (params == NULL) { + return JNI_FALSE; + } + + if (env->IsInstanceOf(params, ec_parameter_spec_class)) { + // Any custom params should be supported. + return JNI_TRUE; + } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) { + // Compare with OIDs I guess? + jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (jstring) env->CallObjectMethod(params, get_name); + const char *utf_name = env->GetStringUTFChars(name, NULL); + std::string str_name(utf_name); + env->ReleaseStringUTFChars(name, utf_name); + + std::vector all_oids = get_all_curve_oids(); + for (auto oid = all_oids.begin(); oid != all_oids.end(); ++oid) { + std::string oid_s = oid_to_str(*oid); + if (str_name == oid_s) { + return JNI_TRUE; + } + } + } + return JNI_FALSE; +} +static Integer integer_from_biginteger(JNIEnv *env, jobject bigint) { + jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B"); + + jbyteArray byte_array = (jbyteArray) env->CallObjectMethod(bigint, to_byte_array); + jsize byte_length = env->GetArrayLength(byte_array); + jbyte *byte_data = env->GetByteArrayElements(byte_array, NULL); + Integer result((byte *) byte_data, (size_t) byte_length); + env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT); return result; +} + +static jobject biginteger_from_integer(JNIEnv *env, const Integer &integer) { + jbyteArray byte_array = (jbyteArray) env->NewByteArray(integer.MinEncodedSize()); + + jbyte *bigint_bytes = env->GetByteArrayElements(byte_array, NULL); + integer.Encode((byte *) bigint_bytes, integer.MinEncodedSize()); + env->ReleaseByteArrayElements(byte_array, bigint_bytes, JNI_COMMIT); + + jmethodID biginteger_init = env->GetMethodID(biginteger_class, "", "(I[B)V"); + return env->NewObject(biginteger_class, biginteger_init, (jint) 1, byte_array); +} + +static jobject biginteger_from_polmod2(JNIEnv *env, const PolynomialMod2 &polmod) { + jmethodID biginteger_init = env->GetMethodID(biginteger_class, "", "(I[B)V"); + + jbyteArray mod_array = env->NewByteArray(polmod.MinEncodedSize()); + jbyte *mod_data = env->GetByteArrayElements(mod_array, NULL); + polmod.Encode((byte *) mod_data, polmod.MinEncodedSize()); + env->ReleaseByteArrayElements(mod_array, mod_data, JNI_COMMIT); + + return env->NewObject(biginteger_class, biginteger_init, (jint) 1, mod_array); +} + +static std::unique_ptr> fp_group_from_params(JNIEnv *env, jobject params) { + if (env->IsInstanceOf(params, ec_parameter_spec_class)) { + jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject elliptic_curve = env->CallObjectMethod(params, get_curve); + + jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = env->CallObjectMethod(elliptic_curve, get_field); + + if (!env->IsInstanceOf(field, fp_field_class)) { + return nullptr; + } + + jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); + jobject a = env->CallObjectMethod(elliptic_curve, get_a); + Integer ai = integer_from_biginteger(env, a); + + jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject b = env->CallObjectMethod(elliptic_curve, get_b); + Integer bi = integer_from_biginteger(env, b); + + jmethodID get_g = env->GetMethodID(ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;"); + jobject g = env->CallObjectMethod(params, get_g); + + jmethodID get_x = env->GetMethodID(point_class, "getAffineX", "()Ljava/math/BigInteger;"); + jobject gx = env->CallObjectMethod(g, get_x); + + jmethodID get_y = env->GetMethodID(point_class, "getAffineY", "()Ljava/math/BigInteger;"); + jobject gy = env->CallObjectMethod(g, get_y); + + jmethodID get_n = env->GetMethodID(ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;"); + jobject n = env->CallObjectMethod(params, get_n); + Integer ni = integer_from_biginteger(env, n); + + jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I"); + jint h = env->CallIntMethod(params, get_h); + Integer hi(h); + + jmethodID get_p = env->GetMethodID(fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject p = env->CallObjectMethod(field, get_p); + Integer pi = integer_from_biginteger(env, p); + + ECP curve(pi, ai, bi); + + Integer gxi = integer_from_biginteger(env, gx); + Integer gyi = integer_from_biginteger(env, gy); + ECP::Point g_point(gxi, gyi); + + return std::make_unique>(curve, g_point, ni, hi); + } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) { + jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (jstring) env->CallObjectMethod(params, get_name); + const char *utf_name = env->GetStringUTFChars(name, NULL); + std::string str_name(utf_name); + env->ReleaseStringUTFChars(name, utf_name); + + std::vector ecp_oids = get_curve_oids(); + for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) { + std::string oid_s = oid_to_str(*oid); + if (str_name == oid_s) { + return std::make_unique>(*oid); + } + } + } + + return nullptr; +} + +static std::unique_ptr> f2m_group_from_params(JNIEnv *env, jobject params) { + if (env->IsInstanceOf(params, ec_parameter_spec_class)) { + jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject elliptic_curve = env->CallObjectMethod(params, get_curve); + + jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = env->CallObjectMethod(elliptic_curve, get_field); + + if (!env->IsInstanceOf(field, f2m_field_class)) { + return nullptr; + } + + jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); + jobject a = env->CallObjectMethod(elliptic_curve, get_a); + Integer ai = integer_from_biginteger(env, a); + + jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject b = env->CallObjectMethod(elliptic_curve, get_b); + Integer bi = integer_from_biginteger(env, b); + + jmethodID get_g = env->GetMethodID(ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;"); + jobject g = env->CallObjectMethod(params, get_g); + + jmethodID get_x = env->GetMethodID(point_class, "getAffineX", "()Ljava/math/BigInteger;"); + jobject gx = env->CallObjectMethod(g, get_x); + + jmethodID get_y = env->GetMethodID(point_class, "getAffineY", "()Ljava/math/BigInteger;"); + jobject gy = env->CallObjectMethod(g, get_y); + + jmethodID get_n = env->GetMethodID(ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;"); + jobject n = env->CallObjectMethod(params, get_n); + Integer ni = integer_from_biginteger(env, n); + + jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I"); + jint h = env->CallIntMethod(params, get_h); + Integer hi(h); + + jmethodID get_midterms = env->GetMethodID(f2m_field_class, "getMidTermsOfReductionPolynomial", "()[I"); + jintArray midterms = (jintArray) env->CallObjectMethod(field, get_midterms); + jsize midterm_length = env->GetArrayLength(midterms); + jint *midterm_data = env->GetIntArrayElements(midterms, NULL); + + jmethodID get_m = env->GetMethodID(f2m_field_class, "getM", "()I"); + jint m = env->CallIntMethod(field, get_m); + + std::unique_ptr base_field; + if (midterm_length == 1) { + //trinomial, use GF2NT + base_field = std::make_unique((unsigned int) m, (unsigned int) midterm_data[0], 0); + } else { + //pentanomial, use GF2NPP + base_field = std::make_unique((unsigned int) m, (unsigned int) midterm_data[0], (unsigned int) midterm_data[1], (unsigned int) midterm_data[2], 0); + } + env->ReleaseIntArrayElements(midterms, midterm_data, JNI_ABORT); + + jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B"); + jbyteArray a_array = (jbyteArray) env->CallObjectMethod(a, to_byte_array); + jsize a_length = env->GetArrayLength(a_array); + jbyte *a_data = env->GetByteArrayElements(a_array, NULL); + + jbyteArray b_array = (jbyteArray) env->CallObjectMethod(b, to_byte_array); + jsize b_length = env->GetArrayLength(b_array); + jbyte *b_data = env->GetByteArrayElements(b_array, NULL); + + EC2N curve(*base_field, EC2N::FieldElement((byte *) a_data, (size_t) a_length), EC2N::FieldElement((byte *) b_data, (size_t) b_length)); + env->ReleaseByteArrayElements(a_array, a_data, JNI_ABORT); + env->ReleaseByteArrayElements(b_array, b_data, JNI_ABORT); + + jbyteArray gx_array = (jbyteArray) env->CallObjectMethod(gx, to_byte_array); + jsize gx_length = env->GetArrayLength(gx_array); + jbyte *gx_data = env->GetByteArrayElements(gx_array, NULL); + PolynomialMod2 gxm((byte *) gx_data, (size_t) gx_length); + env->ReleaseByteArrayElements(gx_array, gx_data, JNI_ABORT); + + jbyteArray gy_array = (jbyteArray) env->CallObjectMethod(gy, to_byte_array); + jsize gy_length = env->GetArrayLength(gy_array); + jbyte *gy_data = env->GetByteArrayElements(gy_array, NULL); + PolynomialMod2 gym((byte *) gy_data, (size_t) gy_length); + env->ReleaseByteArrayElements(gy_array, gy_data, JNI_ABORT); + + EC2N::Point g_point(gxm, gym); + + return std::make_unique>(curve, g_point, ni, hi); + } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) { + jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (jstring) env->CallObjectMethod(params, get_name); + const char *utf_name = env->GetStringUTFChars(name, NULL); + std::string str_name(utf_name); + env->ReleaseStringUTFChars(name, utf_name); + + std::vector e2n_oids = get_curve_oids(); + for (auto oid = e2n_oids.begin(); oid != e2n_oids.end(); ++oid) { + std::string oid_s = oid_to_str(*oid); + if (str_name == oid_s) { + return std::make_unique>(*oid); + } + } + } + return nullptr; +} + + +template jobject finish_params(JNIEnv *env, jobject field, jobject a, jobject b, jobject gx, jobject gy, DL_GroupParameters_EC group) { + jmethodID point_init = env->GetMethodID(point_class, "", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject g = env->NewObject(point_class, point_init, gx, gy); + + jmethodID elliptic_curve_init = env->GetMethodID(elliptic_curve_class, "", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject elliptic_curve = env->NewObject(elliptic_curve_class, elliptic_curve_init, field, a, b); + + // Integer GetSubgroupOrder + // Integer GetCofactor + jobject order = biginteger_from_integer(env, group.GetSubgroupOrder()); + jint cofactor = (jint) group.GetCofactor().ConvertToLong(); + + jmethodID ec_parameter_spec_init = env->GetMethodID(ec_parameter_spec_class, "", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V"); + return env->NewObject(ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, order, cofactor); +} + +template jobject params_from_group(JNIEnv *env, DL_GroupParameters_EC group) { + return NULL; +} + +template <> jobject params_from_group(JNIEnv *env, DL_GroupParameters_EC group) { + ECP curve = group.GetCurve(); + jmethodID fp_field_init = env->GetMethodID(fp_field_class, "", "(Ljava/math/BigInteger;)V"); + ModularArithmetic mod = curve.GetField(); + jobject p = biginteger_from_integer(env, mod.GetModulus()); + jobject a = biginteger_from_integer(env, curve.GetA()); + jobject b = biginteger_from_integer(env, curve.GetB()); + + jobject field = env->NewObject(fp_field_class, fp_field_init, p); + + ECP::Point gp = group.GetBasePrecomputation().GetBase(group.GetGroupPrecomputation()); + jobject gx = biginteger_from_integer(env, gp.x); + jobject gy = biginteger_from_integer(env, gp.y); + return finish_params(env, field, a, b, gx, gy, group); +} + +template <> jobject params_from_group(JNIEnv *env, DL_GroupParameters_EC group) { + EC2N curve = group.GetCurve(); + PolynomialMod2 mod = curve.GetField().GetModulus(); + int m = mod.Degree(); + unsigned int coeff_count = mod.CoefficientCount(); + jintArray ks; + int to_find; + int found = 0; + if (coeff_count == 3) { + //trinomial + ks = env->NewIntArray(1); + to_find = 1; + } else if (coeff_count == 5) { + //pentanomial + ks = env->NewIntArray(3); + to_find = 3; + } + jint *ks_data = env->GetIntArrayElements(ks, NULL); + for (int i = m - 1; i > 0 && found < to_find; --i) { + if (mod.GetCoefficient(i) == 1) { + ks_data[found++] = i; + } + } + env->ReleaseIntArrayElements(ks, ks_data, JNI_COMMIT); + + jmethodID f2m_field_init = env->GetMethodID(f2m_field_class, "", "(I[I)V"); + jobject field = env->NewObject(f2m_field_class, f2m_field_init, (jint) m, ks); + + jobject a = biginteger_from_polmod2(env, curve.GetA()); + jobject b = biginteger_from_polmod2(env, curve.GetB()); + + EC2N::Point gp = group.GetBasePrecomputation().GetBase(group.GetGroupPrecomputation()); + jobject gx = biginteger_from_polmod2(env, gp.x); + jobject gy = biginteger_from_polmod2(env, gp.y); + return finish_params(env, field, a, b, gx, gy, group); +} + +template jobject generate_from_group(JNIEnv *env, DL_GroupParameters_EC group, jobject params) { + AutoSeededRandomPool rng; + typename ECDH::Domain ec_domain(group); + SecByteBlock priv(ec_domain.PrivateKeyLength()), pub(ec_domain.PublicKeyLength()); + + ec_domain.GenerateKeyPair(rng, priv, pub); + + jbyteArray pub_bytearray = env->NewByteArray(pub.SizeInBytes()); + jbyte *pub_bytes = env->GetByteArrayElements(pub_bytearray, NULL); + std::copy(pub.BytePtr(), pub.BytePtr()+pub.SizeInBytes(), pub_bytes); + env->ReleaseByteArrayElements(pub_bytearray, pub_bytes, JNI_COMMIT); + + jobject ec_pub_param_spec = env->NewLocalRef(params); + jmethodID ec_pub_init = env->GetMethodID(pubkey_class, "", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject pubkey = env->NewObject(pubkey_class, ec_pub_init, pub_bytearray, ec_pub_param_spec); + + jbyteArray priv_bytearray = env->NewByteArray(priv.SizeInBytes()); + jbyte *priv_bytes = env->GetByteArrayElements(priv_bytearray, NULL); + std::copy(priv.BytePtr(), priv.BytePtr()+priv.SizeInBytes(), priv_bytes); + env->ReleaseByteArrayElements(priv_bytearray, priv_bytes, JNI_COMMIT); + + jobject ec_priv_param_spec = env->NewLocalRef(params); + jmethodID ec_priv_init = env->GetMethodID(privkey_class, "", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject privkey = env->NewObject(privkey_class, ec_priv_init, priv_bytearray, ec_priv_param_spec); + + jmethodID keypair_init = env->GetMethodID(keypair_class, "", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); + + return env->NewObject(keypair_class, keypair_init, pubkey, privkey); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random){ + std::vector ecp_oids = get_curve_oids(); + for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) { + DL_GroupParameters_EC group(*oid); + if (((jint) group.GetCurve().GetField().MaxElementBitLength()) == keysize) { + jobject params = params_from_group(env, group); + return generate_from_group(env, group, params); + } + } + + std::vector e2n_oids = get_curve_oids(); + for (auto oid = e2n_oids.begin(); oid != e2n_oids.end(); ++oid) { + DL_GroupParameters_EC group(*oid); + if ((jint) group.GetCurve().FieldSize().ConvertToLong() == keysize) { + jobject params = params_from_group(env, group); + return generate_from_group(env, group, params); + } + } + return NULL; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random) { + std::unique_ptr> ecp_group = fp_group_from_params(env, params); + if (ecp_group == nullptr) { + std::unique_ptr> ec2n_group = f2m_group_from_params(env, params); + return generate_from_group(env, *ec2n_group, params); + } else { + return generate_from_group(env, *ecp_group, params); + } + return NULL; +} + + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Cryptopp_generateSecret(JNIEnv *, jobject, jbyteArray, jbyteArray, jobject) { + return NULL; } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 662cc82a470a833a11e19a2dc8c1ce0e79c35935 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 27 Jun 2018 22:00:59 +0200 Subject: Implement more tests for wrong parameters. Implement cloning for Tests. - Test G = infinity. - Test wrong r, where [r]G != infinity, - prime - composite --- src/cz/crcs/ectester/applet/EC_Consts.java | 6 +- src/cz/crcs/ectester/common/test/BaseTestable.java | 7 +- src/cz/crcs/ectester/common/test/CompoundTest.java | 7 +- src/cz/crcs/ectester/common/test/SimpleTest.java | 15 ++- src/cz/crcs/ectester/common/test/Test.java | 7 +- src/cz/crcs/ectester/common/util/CardUtil.java | 129 +++++++++++++++++---- src/cz/crcs/ectester/reader/command/Command.java | 10 +- .../ectester/reader/test/CardWrongCurvesSuite.java | 27 ++++- .../ectester/standalone/ECTesterStandalone.java | 1 - 9 files changed, 174 insertions(+), 35 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/src/cz/crcs/ectester/applet/EC_Consts.java b/src/cz/crcs/ectester/applet/EC_Consts.java index c24283a..3f3ddb6 100644 --- a/src/cz/crcs/ectester/applet/EC_Consts.java +++ b/src/cz/crcs/ectester/applet/EC_Consts.java @@ -995,6 +995,7 @@ public class EC_Consts { public static final short TRANSFORMATION_INFINITY = (short) 0x80; public static final short TRANSFORMATION_COMPRESS = (short) 0x0100; public static final short TRANSFORMATION_COMPRESS_HYBRID = (short) 0x0200; + public static final short TRANSFORMATION_04_MASK = (short) 0x0400; // toX962 FORM types public static final byte X962_UNCOMPRESSED = (byte) 0x00; @@ -1333,7 +1334,7 @@ public class EC_Consts { } short transformationMask = TRANSFORMATION_FIXED; - while (transformationMask <= TRANSFORMATION_COMPRESS) { + while (transformationMask <= TRANSFORMATION_04_MASK) { short transformationPart = (short) (transformationMask & transformation); switch (transformationPart) { case (short) 0: @@ -1408,6 +1409,9 @@ public class EC_Consts { buffer[offset] += 4; } break; + case TRANSFORMATION_04_MASK: + buffer[offset] = 4; + break; default: ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); } diff --git a/src/cz/crcs/ectester/common/test/BaseTestable.java b/src/cz/crcs/ectester/common/test/BaseTestable.java index 4863abc..3c304d9 100644 --- a/src/cz/crcs/ectester/common/test/BaseTestable.java +++ b/src/cz/crcs/ectester/common/test/BaseTestable.java @@ -3,7 +3,7 @@ package cz.crcs.ectester.common.test; /** * @author Jan Jancar johny@neuromancer.sk */ -public abstract class BaseTestable implements Testable { +public abstract class BaseTestable implements Testable, Cloneable { protected boolean hasRun; protected boolean ok; protected boolean error; @@ -36,4 +36,9 @@ public abstract class BaseTestable implements Testable { error = false; errorCause = null; } + + @Override + protected BaseTestable clone() throws CloneNotSupportedException { + return (BaseTestable) super.clone(); + } } diff --git a/src/cz/crcs/ectester/common/test/CompoundTest.java b/src/cz/crcs/ectester/common/test/CompoundTest.java index 607dadb..ba4ad4f 100644 --- a/src/cz/crcs/ectester/common/test/CompoundTest.java +++ b/src/cz/crcs/ectester/common/test/CompoundTest.java @@ -10,7 +10,7 @@ import java.util.function.Function; * * @author Jan Jancar johny@neuromancer.sk */ -public class CompoundTest extends Test { +public class CompoundTest extends Test implements Cloneable { private Function resultCallback; private Consumer runCallback; private Test[] tests; @@ -206,4 +206,9 @@ public class CompoundTest extends Test { public String getDescription() { return description; } + + @Override + public CompoundTest clone() throws CloneNotSupportedException { + return (CompoundTest) super.clone(); + } } diff --git a/src/cz/crcs/ectester/common/test/SimpleTest.java b/src/cz/crcs/ectester/common/test/SimpleTest.java index 85f1072..d2b3e94 100644 --- a/src/cz/crcs/ectester/common/test/SimpleTest.java +++ b/src/cz/crcs/ectester/common/test/SimpleTest.java @@ -4,11 +4,17 @@ package cz.crcs.ectester.common.test; * @param * @author Jan Jancar johny@neuromancer.sk */ -public abstract class SimpleTest extends Test { +public abstract class SimpleTest extends Test implements Testable { protected T testable; protected TestCallback callback; public SimpleTest(T testable, TestCallback callback) { + if (testable == null) { + throw new IllegalArgumentException("testable is null."); + } + if (callback == null) { + throw new IllegalArgumentException("callback is null."); + } this.testable = testable; this.callback = callback; } @@ -22,4 +28,11 @@ public abstract class SimpleTest extends Test { testable.run(); result = callback.apply(testable); } + + @Override + public SimpleTest clone() throws CloneNotSupportedException { + SimpleTest clone = (SimpleTest) super.clone(); + clone.testable = testable.clone(); + return clone; + } } diff --git a/src/cz/crcs/ectester/common/test/Test.java b/src/cz/crcs/ectester/common/test/Test.java index 055ec1c..8bf9502 100644 --- a/src/cz/crcs/ectester/common/test/Test.java +++ b/src/cz/crcs/ectester/common/test/Test.java @@ -7,7 +7,7 @@ import static cz.crcs.ectester.common.test.Result.Value; * * @author Jan Jancar johny@neuromancer.sk */ -public abstract class Test implements Testable { +public abstract class Test implements Testable, Cloneable { protected boolean hasRun; protected boolean hasStarted; protected Result result; @@ -57,6 +57,11 @@ public abstract class Test implements Testable { public abstract String getDescription(); + @Override + public Test clone() throws CloneNotSupportedException { + return (Test) super.clone(); + } + @Override public void run() { if (hasRun) diff --git a/src/cz/crcs/ectester/common/util/CardUtil.java b/src/cz/crcs/ectester/common/util/CardUtil.java index 26fdb78..a628d5b 100644 --- a/src/cz/crcs/ectester/common/util/CardUtil.java +++ b/src/cz/crcs/ectester/common/util/CardUtil.java @@ -6,6 +6,9 @@ import javacard.framework.ISO7816; import javacard.security.CryptoException; import javacard.security.KeyPair; +import java.util.LinkedList; +import java.util.List; + /** * @author Petr Svenda petr@svenda.com * @author Jan Jancar johny@neuromancer.sk @@ -183,32 +186,106 @@ public class CardUtil { } } + public static String getParams(short params) { + if (params == 0) { + return ""; + } + List ps = new LinkedList<>(); + short paramMask = EC_Consts.PARAMETER_FP; + while (paramMask <= EC_Consts.PARAMETER_S) { + short paramValue = (short) (paramMask & params); + if (paramValue != 0) { + switch (paramValue) { + case EC_Consts.PARAMETER_FP: + ps.add("P"); + break; + case EC_Consts.PARAMETER_F2M: + ps.add("2^M"); + break; + case EC_Consts.PARAMETER_A: + ps.add("A"); + break; + case EC_Consts.PARAMETER_B: + ps.add("B"); + break; + case EC_Consts.PARAMETER_G: + ps.add("G"); + break; + case EC_Consts.PARAMETER_R: + ps.add("R"); + break; + case EC_Consts.PARAMETER_K: + ps.add("K"); + break; + case EC_Consts.PARAMETER_W: + ps.add("W"); + break; + case EC_Consts.PARAMETER_S: + ps.add("S"); + break; + } + } + paramMask = (short) (paramMask << 1); + } + + if (ps.size() != 0) { + return "[" + String.join(",", ps) + "]"; + } else { + return "unknown"; + } + } + public static String getTransformation(short transformationType) { - switch (transformationType) { - case EC_Consts.TRANSFORMATION_NONE: - return "NONE"; - case EC_Consts.TRANSFORMATION_FIXED: - return "FIXED"; - case EC_Consts.TRANSFORMATION_ONE: - return "ONE"; - case EC_Consts.TRANSFORMATION_ZERO: - return "ZERO"; - case EC_Consts.TRANSFORMATION_ONEBYTERANDOM: - return "ONE_BYTE_RANDOM"; - case EC_Consts.TRANSFORMATION_FULLRANDOM: - return "FULL_RANDOM"; - case EC_Consts.TRANSFORMATION_INCREMENT: - return "INCREMENT"; - case EC_Consts.TRANSFORMATION_INFINITY: - return "INFINITY"; - case EC_Consts.TRANSFORMATION_COMPRESS: - return "COMPRESSED"; - case EC_Consts.TRANSFORMATION_COMPRESS_HYBRID: - return "HYBRID"; - case EC_Consts.TRANSFORMATION_MAX: - return "MAX"; - default: - return "unknown"; + if (transformationType == 0) { + return "NONE"; + } + List names = new LinkedList<>(); + short transformationMask = 1; + while (transformationMask <= EC_Consts.TRANSFORMATION_04_MASK) { + short transformationValue = (short) (transformationMask & transformationType); + if (transformationValue != 0) { + switch (transformationValue) { + case EC_Consts.TRANSFORMATION_FIXED: + names.add("FIXED"); + break; + case EC_Consts.TRANSFORMATION_ONE: + names.add("ONE"); + break; + case EC_Consts.TRANSFORMATION_ZERO: + names.add("ZERO"); + break; + case EC_Consts.TRANSFORMATION_ONEBYTERANDOM: + names.add("ONE_BYTE_RANDOM"); + break; + case EC_Consts.TRANSFORMATION_FULLRANDOM: + names.add("FULL_RANDOM"); + break; + case EC_Consts.TRANSFORMATION_INCREMENT: + names.add("INCREMENT"); + break; + case EC_Consts.TRANSFORMATION_INFINITY: + names.add("INFINITY"); + break; + case EC_Consts.TRANSFORMATION_COMPRESS: + names.add("COMPRESSED"); + break; + case EC_Consts.TRANSFORMATION_COMPRESS_HYBRID: + names.add("HYBRID"); + break; + case EC_Consts.TRANSFORMATION_04_MASK: + names.add("MASK(O4)"); + break; + case EC_Consts.TRANSFORMATION_MAX: + names.add("MAX"); + break; + } + } + transformationMask = (short) ((transformationMask) << 1); + } + if (names.size() != 0) { + return String.join(" + ", names); + } else { + return "unknown"; } } @@ -325,6 +402,8 @@ public class CardUtil { what = "privkey"; } else if (params == EC_Consts.PARAMETERS_KEYPAIR) { what = "keypair"; + } else { + what = getParams(params); } return what; } diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index 8af2218..b3af731 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -25,7 +25,7 @@ import java.util.List; /** * @author Jan Jancar johny@neuromancer.sk */ -public abstract class Command { +public abstract class Command implements Cloneable { CommandAPDU cmd; CardMngr cardManager; @@ -49,6 +49,11 @@ public abstract class Command { public abstract String getDescription(); + @Override + protected Command clone() throws CloneNotSupportedException { + return (Command) super.clone(); + } + /** * @param keyPair which keyPair/s (local/remote) to set curve domain parameters on @@ -442,6 +447,7 @@ public abstract class Command { @Override public String getDescription() { + String stringParams = CardUtil.getParams(params); String transform = CardUtil.getTransformation(transformation); String pair; @@ -450,7 +456,7 @@ public abstract class Command { } else { pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair"; } - return String.format("Transform params of %s, %s", pair, transform); + return String.format("Transform params %s of %s, %s", stringParams, pair, transform); } } diff --git a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java index 6768591..4bf38f2 100644 --- a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java @@ -107,8 +107,31 @@ public class CardWrongCurvesSuite extends CardTestSuite { EC_Params compositeData = new EC_Params(EC_Consts.PARAMETER_FP, new byte[][]{compositeBytes}); Test composite = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, compositeData.getParams(), compositeData.flatten()), "Set p = product of two primes.", "ECDH with p = q * s."); - Test wrong = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted prime parameter.", prime0, prime1, primePower, composite); - doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_FP), setup, wrong)); + Test wrongPrime = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted prime parameter.", prime0, prime1, primePower, composite); + + Test resetSetup = CompoundTest.all(ExpectedValue.SUCCESS, "Reset keypair.", set.clone()); + + Test zeroG = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, EC_Consts.TRANSFORMATION_INFINITY), "Set G = inifnity.", "ECDH with G = infinity."); + Test randomG = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, (short) (EC_Consts.TRANSFORMATION_FULLRANDOM | EC_Consts.TRANSFORMATION_04_MASK)), "Set G = random non-point/point-like.", "ECDH with non-point G."); + Test wrongG = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted G parameter.", zeroG, randomG); + + byte[] originalR = new byte[keyLength]; + EC_Consts.getCurveParameter(curve, EC_Consts.PARAMETER_R, originalR, (short) 0); + BigInteger originalBigR = new BigInteger(1, originalR); + BigInteger nextPrimeR = originalBigR.nextProbablePrime(); + byte[] nextRBytes = ECUtil.toByteArray(nextPrimeR, keyLength); + EC_Params nextRData = new EC_Params(EC_Consts.PARAMETER_R, new byte[][]{nextRBytes}); + Test primeWrongR = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, nextRData.getParams(), nextRData.flatten()), "Set R = some prime (but [r]G != infinity).", "ECDH with wrong R, prime."); + byte[] nonprimeRBytes = nextRBytes.clone(); + nonprimeRBytes[0] ^= 1; + EC_Params nonprimeWrongRData = new EC_Params(EC_Consts.PARAMETER_R, new byte[][]{nonprimeRBytes}); + Test nonprimeWrongR = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, nonprimeWrongRData.getParams(), nonprimeWrongRData.flatten()), "Set R = some composite (but [r]G != infinity).", "ECDH with wrong R, composite."); + + Test wrongR = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted R parameter.", primeWrongR, nonprimeWrongR); + + + + doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_FP), setup, wrongPrime, resetSetup, wrongG, resetSetup.clone(), wrongR, resetSetup.clone())); } /* diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 92a3a27..c223af6 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -233,7 +233,6 @@ public class ECTesterStandalone { System.out.println("\t\t- Curves: " + String.join(", ", curves)); } System.out.println(); - System.out.println(lib.getProvider().entrySet()); } } } -- cgit v1.2.3-70-g09d2 From 41e5246ed925eee65d86b8463635ea57e2eb706c Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 18 Jul 2018 23:04:35 +0200 Subject: Elementary support for OpenSSL. --- build-standalone.xml | 5 + docs/LIBS.md | 9 +- .../ectester/reader/output/TextTestWriter.java | 6 +- .../ectester/standalone/ECTesterStandalone.java | 17 +- .../crcs/ectester/standalone/libs/OpensslLib.java | 19 + src/cz/crcs/ectester/standalone/libs/jni/Makefile | 10 +- .../standalone/libs/jni/NativeECPrivateKey.java | 6 + .../standalone/libs/jni/NativeECPublicKey.java | 6 + .../libs/jni/NativeKeyPairGeneratorSpi.java | 18 + .../standalone/libs/jni/NativeProvider.java | 10 + src/cz/crcs/ectester/standalone/libs/jni/botan.cpp | 50 --- .../crcs/ectester/standalone/libs/jni/cryptopp.cpp | 53 --- src/cz/crcs/ectester/standalone/libs/jni/native.h | 125 +++++++ src/cz/crcs/ectester/standalone/libs/jni/openssl.c | 393 +++++++++++++++++++++ .../crcs/ectester/standalone/libs/jni/tomcrypt.c | 1 + .../ectester/standalone/output/TextTestWriter.java | 5 +- 16 files changed, 617 insertions(+), 116 deletions(-) create mode 100644 src/cz/crcs/ectester/standalone/libs/OpensslLib.java create mode 100644 src/cz/crcs/ectester/standalone/libs/jni/openssl.c (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/build-standalone.xml b/build-standalone.xml index 4190300..f1ff001 100644 --- a/build-standalone.xml +++ b/build-standalone.xml @@ -122,6 +122,11 @@ + + + + + diff --git a/docs/LIBS.md b/docs/LIBS.md index bfe20cd..59a183f 100644 --- a/docs/LIBS.md +++ b/docs/LIBS.md @@ -5,8 +5,8 @@ Popular libraries with at least some ECC support: - [libgcrypt](https://www.gnupg.org/related_software/libgcrypt/) - [mbedTLS](https://tls.mbed.org/) - [Nettle](http://www.lysator.liu.se/~nisse/nettle/) - - [OpenSSL](https://www.openssl.org/) - [OpenSSL (FIPS mode)](https://www.openssl.org/docs/fipsnotes.html) + - BoringSSL - [Microsoft CNG](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376210(v=vs.85).aspx) - [Microsoft .NET crypto](https://docs.microsoft.com/en-us/dotnet/standard/security/cryptography-model) @@ -54,6 +54,13 @@ Popular libraries with at least some ECC support: - Uses Lopez-Dahab (Montgomery) ladder, XZ coordinates (ec2_mont.c): Fast multiplication on elliptic curves over GF(2^m) without precomputation (Algorithm 2P) - Contains an implementation of IEEE P1363 algorithm A.10.3 using affine coordinates (ec2_aff.c) - Has some custom arithmetic for some of the NIST primes. + - [OpenSSL](https://www.openssl.org/) + - C + - For prime field curves: + - Uses Jacobian coordinates, and Montgomery ladder, also uses wNAF-based interleaving multi-exponentiation method(ec_mult.c): http://www.bmoeller.de/pdf/TI-01-08.multiexp.pdf + - Also uses multiplication with precomputation by wNAF splitting(ec_mult.c) + - For binary field curves: + - Uses Jacobian coordinates, and Lopez-Dahab ladder, also uses wNAF-based interleaving multi-exponentiation method(ec2_smpl.c) - [Botan](https://botan.randombit.net/) - C++ - Uses blinded(randomized) Montgomery ladder. diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java index a8e4ce9..ad35012 100644 --- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java @@ -43,12 +43,12 @@ public class TextTestWriter extends BaseTextTestWriter { if (suite instanceof CardTestSuite) { CardTestSuite cardSuite = (CardTestSuite) suite; StringBuilder sb = new StringBuilder(); - sb.append("═══ " + Colors.underline("ECTester version:") + " " + ECTesterReader.VERSION + ECTesterReader.GIT_COMMIT).append(System.lineSeparator()); - sb.append("═══ " + Colors.underline("Card ATR:") + " ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator()); + sb.append("═══ ").append(Colors.underline("ECTester version:")).append(" ").append(ECTesterReader.VERSION).append(ECTesterReader.GIT_COMMIT).append(System.lineSeparator()); + sb.append("═══ ").append(Colors.underline("Card ATR:")).append(" ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator()); try { CardMngr.CPLC cplc = cardSuite.getCard().getCPLC(); if (!cplc.values().isEmpty()) { - sb.append("═══ " + Colors.underline("Card CPLC data:")).append(System.lineSeparator()); + sb.append("═══ ").append(Colors.underline("Card CPLC data:")).append(System.lineSeparator()); for (Map.Entry entry : cplc.values().entrySet()) { CardMngr.CPLC.Field field = entry.getKey(); byte[] value = entry.getValue(); diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index c223af6..9df6c61 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -66,7 +66,7 @@ import java.util.stream.Collectors; * @version v0.2.0 */ public class ECTesterStandalone { - private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib()}; + private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib(), new OpensslLib()}; private Config cfg; private Options opts = new Options(); @@ -205,6 +205,7 @@ public class ECTesterStandalone { opts.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); opts.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); + opts.addOption(Option.builder("C").longOpt("color").desc("Print stuff with color, requires ANSI terminal.").build()); return optParser.parse(opts, args); } @@ -215,22 +216,22 @@ public class ECTesterStandalone { private void listLibraries() { for (ProviderECLibrary lib : libs) { if (lib.isInitialized() && (cfg.selected == null || lib == cfg.selected)) { - System.out.println("\t- " + lib.name()); + System.out.println("\t- " + Colors.bold(lib.name())); Set kpgs = lib.getKPGs(); if (!kpgs.isEmpty()) { - System.out.println("\t\t- KeyPairGenerators: " + String.join(", ", kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.toList()))); + System.out.println(Colors.bold("\t\t- KeyPairGenerators: ") + String.join(", ", kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.toList()))); } Set eckas = lib.getKAs(); if (!eckas.isEmpty()) { - System.out.println("\t\t- KeyAgreements: " + String.join(", ", eckas.stream().map(KeyAgreementIdent::getName).collect(Collectors.toList()))); + System.out.println(Colors.bold("\t\t- KeyAgreements: ") + String.join(", ", eckas.stream().map(KeyAgreementIdent::getName).collect(Collectors.toList()))); } Set sigs = lib.getSigs(); if (!sigs.isEmpty()) { - System.out.println("\t\t- Signatures: " + String.join(", ", sigs.stream().map(SignatureIdent::getName).collect(Collectors.toList()))); + System.out.println(Colors.bold("\t\t- Signatures: ") + String.join(", ", sigs.stream().map(SignatureIdent::getName).collect(Collectors.toList()))); } Set curves = lib.getCurves(); if (!curves.isEmpty()) { - System.out.println("\t\t- Curves: " + String.join(", ", curves)); + System.out.println(Colors.bold("\t\t- Curves: ") + String.join(", ", curves)); } System.out.println(); } @@ -540,12 +541,16 @@ public class ECTesterStandalone { public static class Config { private ProviderECLibrary[] libs; public ProviderECLibrary selected = null; + public boolean color = false; public Config(ProviderECLibrary[] libs) { this.libs = libs; } boolean readOptions(TreeCommandLine cli) { + color = cli.hasOption("color"); + Colors.enabled = color; + if (cli.isNext("generate") || cli.isNext("export") || cli.isNext("ecdh") || cli.isNext("ecdsa") || cli.isNext("test")) { if (!cli.hasArg(-1)) { System.err.println("Missing library name argument."); diff --git a/src/cz/crcs/ectester/standalone/libs/OpensslLib.java b/src/cz/crcs/ectester/standalone/libs/OpensslLib.java new file mode 100644 index 0000000..e558336 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/OpensslLib.java @@ -0,0 +1,19 @@ +package cz.crcs.ectester.standalone.libs; + +import java.security.Provider; +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class OpensslLib extends NativeECLibrary { + public OpensslLib() { + super("openssl_provider", "crypto"); + } + + @Override + native Provider createProvider(); + + @Override + public native Set getCurves(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile index 17c1efb..9c3557c 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile +++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile @@ -42,7 +42,7 @@ CFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. CXXFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. -all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so +all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so # Common utils c_utils.o: c_utils.c @@ -52,6 +52,14 @@ cpp_utils.o: cpp_utils.cpp $(CXX) $(CXXFLAGS) -c $< +# OpenSSL shim +openssl_provider.so: openssl.o c_utils.o + $(CC) -fPIC -g -shared -o $@ $^ -L. $(shell pkg-config --libs openssl) + +openssl.o: openssl.c + $(CC) $(shel pkg-config --cflags openssl) $(CFLAGS) -c $< + + # Libtomcrypt shim tomcrypt_provider.so: tomcrypt.o c_utils.o $(CC) -fPIC -g -shared -o $@ $^ -L. -ltommath $(shell pkg-config --libs libtomcrypt) diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java index a209fa1..39539df 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java @@ -71,4 +71,10 @@ public abstract class NativeECPrivateKey implements ECPrivateKey { super(keyData, params); } } + + public static class Openssl extends Raw { + public Openssl(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java index f53cd26..1085083 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java @@ -73,4 +73,10 @@ public abstract class NativeECPublicKey implements ECPublicKey { super(keyData, params); } } + + public static class Openssl extends ANSIX962 { + public Openssl(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java index a7b1a61..6e441e5 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java @@ -155,4 +155,22 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { super("ECDSA"); } } + + public static class Openssl extends NativeKeyPairGeneratorSpi { + public Openssl() { + initialize(256, new SecureRandom()); + } + + @Override + native boolean keysizeSupported(int keysize); + + @Override + native boolean paramsSupported(AlgorithmParameterSpec params); + + @Override + native KeyPair generate(int keysize, SecureRandom random); + + @Override + native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java index 593295e..a4967e5 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java @@ -49,4 +49,14 @@ public abstract class NativeProvider extends Provider { @Override native void setup(); } + + public static class Openssl extends NativeProvider { + + public Openssl(String name, double version, String info) { + super(name, version, info); + } + + @Override + native void setup(); + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp index 6a1e6d6..a37cb88 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp @@ -20,11 +20,6 @@ static jclass provider_class; -/* - * Class: cz_crcs_ectester_standalone_libs_BotanLib - * Method: createProvider - * Signature: ()Ljava/security/Provider; - */ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider(JNIEnv *env, jobject self) { /* Create the custom provider. */ jclass local_provider_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeProvider$Botan"); @@ -44,11 +39,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createP return env->NewObject(provider_class, init, name, version, info); } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan - * Method: setup - * Signature: ()V - */ JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Botan_setup(JNIEnv *env, jobject self){ jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); @@ -88,11 +78,6 @@ JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_ init_classes(env, "Botan"); } -/* - * Class: cz_crcs_ectester_standalone_libs_BotanLib - * Method: getCurves - * Signature: ()Ljava/util/Set; - */ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurves(JNIEnv *env, jobject self){ jclass set_class = env->FindClass("java/util/TreeSet"); @@ -111,20 +96,10 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurv return result; } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan - * Method: keysizeSupported - * Signature: (I)Z - */ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_keysizeSupported(JNIEnv *env, jobject self, jint keysize){ return JNI_TRUE; } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan - * Method: paramsSupported - * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z - */ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_paramsSupported(JNIEnv *env, jobject self, jobject params){ if (params == NULL) { return JNI_FALSE; @@ -319,11 +294,6 @@ static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group gr return env->NewObject(keypair_class, keypair_init, pubkey, privkey); } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan - * Method: generate - * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; - */ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random){ const std::set& curves = Botan::EC_Group::known_named_groups(); for (auto it = curves.begin(); it != curves.end(); ++it) { @@ -339,21 +309,11 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai return NULL; } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan - * Method: generate - * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; - */ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random){ Botan::EC_Group curve_group = group_from_params(env, params); return generate_from_group(env, self, curve_group); } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan - * Method: generateSecret - * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B - */ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params){ Botan::EC_Group curve_group = group_from_params(env, params); @@ -420,11 +380,6 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey return result; } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan - * Method: sign - * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B - */ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params){ Botan::EC_Group curve_group = group_from_params(env, params); @@ -488,11 +443,6 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig return result; } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan - * Method: verify - * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z - */ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params){ Botan::EC_Group curve_group = group_from_params(env, params); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp index e83f808..0ba026f 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp +++ b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp @@ -70,11 +70,6 @@ using CryptoPP::Integer; static jclass provider_class; -/* - * Class: cz_crcs_ectester_standalone_libs_CryptoppLib - * Method: createProvider - * Signature: ()Ljava/security/Provider; - */ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_createProvider(JNIEnv *env, jobject self) { /* Create the custom provider. */ jclass local_provider_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeProvider$Cryptopp"); @@ -100,11 +95,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_crea return env->NewObject(provider_class, init, name, version, info); } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp - * Method: setup - * Signature: ()V - */ JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Cryptopp_setup(JNIEnv *env, jobject self){ jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); @@ -157,11 +147,6 @@ static std::string oid_to_str(const OID &oid) { return ss.str(); } -/* - * Class: cz_crcs_ectester_standalone_libs_CryptoppLib - * Method: getCurves - * Signature: ()Ljava/util/Set; - */ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getCurves(JNIEnv *env, jobject self){ jclass set_class = env->FindClass("java/util/TreeSet"); @@ -180,11 +165,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getC return result; } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp - * Method: keysizeSupported - * Signature: (I)Z - */ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_keysizeSupported(JNIEnv *env, jobject self, jint keysize){ std::vector ecp_oids = get_curve_oids(); for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) { @@ -204,11 +184,6 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPa return JNI_FALSE; } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp - * Method: paramsSupported - * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z - */ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_paramsSupported(JNIEnv *env, jobject self, jobject params){ if (params == NULL) { return JNI_FALSE; @@ -546,11 +521,6 @@ template jobject generate_from_group(JNIEnv *env, DL_GroupParameters_ return env->NewObject(keypair_class, keypair_init, pubkey, privkey); } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp - * Method: generate - * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; - */ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random){ std::vector ecp_oids = get_curve_oids(); for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) { @@ -572,11 +542,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai return NULL; } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp - * Method: generate - * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; - */ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random) { std::unique_ptr> ecp_group = fp_group_from_params(env, params); if (ecp_group == nullptr) { @@ -588,12 +553,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai return NULL; } - -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp - * Method: generateSecret - * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B - */ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Cryptopp_generateSecret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) { jsize privkey_length = env->GetArrayLength(privkey); jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL); @@ -663,12 +622,6 @@ jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC group, jbyteArray return result; } - -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Cryptopp - * Method: sign - * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B - */ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Cryptopp_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) { jclass cryptopp_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Cryptopp"); jfieldID type_id = env->GetFieldID(cryptopp_sig_class, "type", "Ljava/lang/String;"); @@ -715,7 +668,6 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig return result; } - template jboolean verify_message(JNIEnv *env, DL_GroupParameters_EC group, jbyteArray data, jbyteArray signature, jbyteArray pubkey) { typename EC::Point pkey_point; @@ -739,11 +691,6 @@ jboolean verify_message(JNIEnv *env, DL_GroupParameters_EC group, jbyteArray return result; } -/* - * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Cryptopp - * Method: verify - * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z - */ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Cryptopp_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) { jclass cryptopp_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Cryptopp"); jfieldID type_id = env->GetFieldID(cryptopp_sig_class, "type", "Ljava/lang/String;"); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index 9385a4b..6aacdd3 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -513,3 +513,128 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna } #endif #endif +/* Header for class cz_crcs_ectester_standalone_libs_OpensslLib */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_OpensslLib +#define _Included_cz_crcs_ectester_standalone_libs_OpensslLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_OpensslLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_createProvider + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_OpensslLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getCurves + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID 1421746759512286392LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_MAX_ARRAY_SIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_MAX_ARRAY_SIZE 2147483639L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_KEYS +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_KEYS 0L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_VALUES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_VALUES 1L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_ENTRIES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_ENTRIES 2L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID 4112578634029874840LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -4298000515446427739LL +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Openssl_setup + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_keysizeSupported + (JNIEnv *, jobject, jint); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_paramsSupported + (JNIEnv *, jobject, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_generate__ILjava_security_SecureRandom_2 + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2 + (JNIEnv *, jobject, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Openssl */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Openssl +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Openssl +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Openssl */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Openssl +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Openssl +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c new file mode 100644 index 0000000..ae6a222 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c @@ -0,0 +1,393 @@ +#include "native.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "c_utils.h" + + +static jclass provider_class; + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_createProvider(JNIEnv *env, jobject self) { + /* Create the custom provider. */ + jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Openssl"); + provider_class = (*env)->NewGlobalRef(env, local_provider_class); + + jmethodID init = (*env)->GetMethodID(env, local_provider_class, "", "(Ljava/lang/String;DLjava/lang/String;)V"); + + jstring name = (*env)->NewStringUTF(env, OPENSSL_VERSION_TEXT); + double version = ((double)((OPENSSL_VERSION_NUMBER & 0xff000000L) >> 30)) + ((double)((OPENSSL_VERSION_NUMBER & 0xff0000L) >> 20)); + + return (*env)->NewObject(env, provider_class, init, name, version, name); +} + +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Openssl_setup(JNIEnv *env, jobject self) { + OPENSSL_no_config(); + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + + jmethodID provider_put = (*env)->GetMethodID(env, provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + jstring ec = (*env)->NewStringUTF(env, "KeyPairGenerator.EC"); + jstring ec_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$Openssl"); + (*env)->CallObjectMethod(env, self, provider_put, ec, ec_value); + + init_classes(env, "Openssl"); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getCurves(JNIEnv *env, jobject self) { + jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet"); + + jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "", "()V"); + jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z"); + + jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr); + + size_t ncurves = EC_get_builtin_curves(NULL, 0); + EC_builtin_curve curves[ncurves]; + EC_get_builtin_curves(curves, ncurves); + + for (size_t i = 0; i < ncurves; ++i) { + jstring curve_name = (*env)->NewStringUTF(env, OBJ_nid2sn(curves[i].nid)); + (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name); + } + + return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_keysizeSupported(JNIEnv *env, jobject self, jint keysize) { + size_t ncurves = EC_get_builtin_curves(NULL, 0); + EC_builtin_curve curves[ncurves]; + EC_get_builtin_curves(curves, ncurves); + + for (size_t i = 0; i < ncurves; ++i) { + EC_GROUP *curve = EC_GROUP_new_by_curve_name(curves[i].nid); + if (EC_GROUP_get_degree(curve) == keysize) { + EC_GROUP_clear_free(curve); + return JNI_TRUE; + } + EC_GROUP_free(curve); + } + return JNI_FALSE; +} + +static jobject bignum_to_biginteger(JNIEnv *env, const BIGNUM *bn) { + jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "", "(I[B)V"); + int size = BN_num_bytes(bn); + jbyteArray bytes = (*env)->NewByteArray(env, size); + jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL); + BN_bn2bin(bn, data); + (*env)->ReleaseByteArrayElements(env, bytes, data, JNI_COMMIT); + jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 0, bytes); + return result; +} + +static BIGNUM *biginteger_to_bignum(JNIEnv *env, jobject bigint) { + jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B"); + + jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array); + jsize byte_length = (*env)->GetArrayLength(env, byte_array); + jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL); + BIGNUM *result = BN_bin2bn(byte_data, byte_length, NULL); + (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT); + return result; +} + +static EC_GROUP *create_curve(JNIEnv *env, jobject params) { + jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve); + + jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field); + + jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); + jint bits = (*env)->CallIntMethod(env, field, get_bits); + jint bytes = (bits + 7) / 8; + + jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); + jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a); + BIGNUM *a_bn = biginteger_to_bignum(env, a); + + jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b); + BIGNUM *b_bn = biginteger_to_bignum(env, b); + + jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;"); + jobject g = (*env)->CallObjectMethod(env, params, get_g); + + jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;"); + jobject gx = (*env)->CallObjectMethod(env, g, get_x); + BIGNUM *gx_bn = biginteger_to_bignum(env, gx); + + jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;"); + jobject gy = (*env)->CallObjectMethod(env, g, get_y); + BIGNUM *gy_bn = biginteger_to_bignum(env, gy); + + EC_GROUP *result; + EC_POINT *g_point; + + if ((*env)->IsInstanceOf(env, field, fp_field_class)) { + jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject p = (*env)->CallObjectMethod(env, field, get_p); + + BIGNUM *p_bn = biginteger_to_bignum(env, p); + result = EC_GROUP_new_curve_GFp(p_bn, a_bn, b_bn, NULL); + BN_free(p_bn); + + g_point = EC_POINT_new(result); + EC_POINT_set_affine_coordinates_GFp(result, g_point, gx_bn, gy_bn, NULL); + } else if ((*env)->IsInstanceOf(env, field, f2m_field_class)) { + + jmethodID get_reduction_poly = (*env)->GetMethodID(env, f2m_field_class, "getReductionPolynomial", "()Ljava/math/BigInteger;"); + jobject red_poly = (*env)->CallObjectMethod(env, field, get_reduction_poly); + + BIGNUM *p_bn = biginteger_to_bignum(env, red_poly); + result = EC_GROUP_new_curve_GF2m(p_bn, a_bn, b_bn, NULL); + BN_free(p_bn); + + g_point = EC_POINT_new(result); + EC_POINT_set_affine_coordinates_GF2m(result, g_point, gx_bn, gy_bn, NULL); + } else { + return NULL; + } + + BN_free(a_bn); + BN_free(b_bn); + + jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;"); + jobject n = (*env)->CallObjectMethod(env, params, get_n); + BIGNUM *n_bn = biginteger_to_bignum(env, n); + + jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I"); + jint h = (*env)->CallIntMethod(env, params, get_h); + BIGNUM *h_bn = BN_new(); + BN_set_word(h_bn, h); + + EC_GROUP_set_generator(result, g_point, n_bn, h_bn); + + BN_free(gx_bn); + BN_free(gy_bn); + BN_free(n_bn); + BN_free(h_bn); + + return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_paramsSupported(JNIEnv *env, jobject self, jobject params){ + if (params == NULL) { + return JNI_FALSE; + } + + if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + EC_GROUP *curve = create_curve(env, params); + jboolean result = (EC_GROUP_check(curve, NULL) == 1) ? JNI_TRUE : JNI_FALSE; + EC_GROUP_free(curve); + return result; + } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { + jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (*env)->CallObjectMethod(env, params, get_name); + const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL); + size_t ncurves = EC_get_builtin_curves(NULL, 0); + EC_builtin_curve curves[ncurves]; + EC_get_builtin_curves(curves, ncurves); + for (size_t i = 0; i < ncurves; ++i) { + if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) { + (*env)->ReleaseStringUTFChars(env, name, utf_name); + return JNI_TRUE; + } + } + (*env)->ReleaseStringUTFChars(env, name, utf_name); + return JNI_FALSE; + } else { + return JNI_FALSE; + } +} + +static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) { + int field_type = EC_METHOD_get_field_type(EC_GROUP_method_of(curve)); + BIGNUM *a; + BIGNUM *b; + + BIGNUM *gx; + BIGNUM *gy; + jobject field; + + if (field_type == NID_X9_62_prime_field) { + BIGNUM *p = BN_new(); + a = BN_new(); + b = BN_new(); + EC_GROUP_get_curve_GFp(curve, p, a, b, NULL); + + jobject p_int = bignum_to_biginteger(env, p); + + jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "", "(Ljava/math/BigInteger;)V"); + field = (*env)->NewObject(env, fp_field_class, fp_field_init, p_int); + + BN_free(p); + + gx = BN_new(); + gy = BN_new(); + EC_POINT_get_affine_coordinates_GFp(curve, EC_GROUP_get0_generator(curve), gx, gy, NULL); + + } else if (field_type == NID_X9_62_characteristic_two_field) { + a = BN_new(); + b = BN_new(); + EC_GROUP_get_curve_GF2m(curve, NULL, a, b, NULL); + + int basis_type = EC_GROUP_get_basis_type(curve); + jintArray ks; + jint *ks_data; + if (basis_type == NID_X9_62_tpBasis) { + ks = (*env)->NewIntArray(env, 1); + ks_data = (*env)->GetIntArrayElements(env, ks, NULL); + EC_GROUP_get_trinomial_basis(curve, &ks_data[0]); + } else if (basis_type == NID_X9_62_ppBasis) { + ks = (*env)->NewIntArray(env, 3); + ks_data = (*env)->GetIntArrayElements(env, ks, NULL); + EC_GROUP_get_pentanomial_basis(curve, &ks_data[0], &ks_data[1], &ks_data[2]); + } else { + return NULL; + } + (*env)->ReleaseIntArrayElements(env, ks, ks_data, JNI_COMMIT); + + jint m = EC_GROUP_get_degree(curve); + + jmethodID f2m_field_init = (*env)->GetMethodID(env, f2m_field_class, "", "(I[I)V"); + field = (*env)->NewObject(env, f2m_field_class, f2m_field_init, m, ks); + + gx = BN_new(); + gy = BN_new(); + EC_POINT_get_affine_coordinates_GF2m(curve, EC_GROUP_get0_generator(curve), gx, gy, NULL); + } else { + return NULL; + } + + jobject a_int = bignum_to_biginteger(env, a); + jobject b_int = bignum_to_biginteger(env, b); + + jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a_int, b_int); + fprintf(stderr, "field: %p, a_int: %p, b_int: %p\n", field, a_int, b_int); + fflush(stderr); + + BN_free(a); + BN_free(b); + + jobject gx_int = bignum_to_biginteger(env, gx); + jobject gy_int = bignum_to_biginteger(env, gy); + + BN_free(gx); + BN_free(gy); + + jmethodID point_init = (*env)->GetMethodID(env, point_class, "", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject g = (*env)->NewObject(env, point_class, point_init, gx_int, gy_int); + + jobject order = bignum_to_biginteger(env, EC_GROUP_get0_order(curve)); + jint cofactor = BN_get_word(EC_GROUP_get0_cofactor(curve)); + + jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V"); + return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, order, cofactor); +} + +static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) { + jint keysize = EC_GROUP_get_degree(curve); + unsigned long key_bytes = (keysize + 7) / 8; + + EC_KEY *key = EC_KEY_new(); + EC_KEY_set_group(key, curve); + EC_KEY_generate_key(key); + + jbyteArray priv_bytes = (*env)->NewByteArray(env, key_bytes); + jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); + BN_bn2binpad(EC_KEY_get0_private_key(key), key_priv, key_bytes); + (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, JNI_COMMIT); + + unsigned long key_len = 2*keysize + 1; + jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len); + jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL); + EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, key_pub, key_len, NULL); + (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, JNI_COMMIT); + + EC_KEY_free(key); + + jobject ec_param_spec = create_ec_param_spec(env, curve); + + jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec); + jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_param_spec); + + jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec); + jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec); + + jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); + return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) { + size_t ncurves = EC_get_builtin_curves(NULL, 0); + EC_builtin_curve curves[ncurves]; + EC_get_builtin_curves(curves, ncurves); + + EC_GROUP *curve = NULL; + for (size_t i = 0; i < ncurves; ++i) { + curve = EC_GROUP_new_by_curve_name(curves[i].nid); + if (EC_GROUP_get_degree(curve) == keysize) { + break; + } + EC_GROUP_free(curve); + } + + if (!curve) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found."); + return NULL; + } + + jobject result = generate_from_curve(env, curve); + EC_GROUP_free(curve); + return result; +} + + + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random) { + if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + EC_GROUP *curve = create_curve(env, params); + jobject result = generate_from_curve(env, curve); + EC_GROUP_free(curve); + return result; + } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { + jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (*env)->CallObjectMethod(env, params, get_name); + const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL); + size_t ncurves = EC_get_builtin_curves(NULL, 0); + EC_builtin_curve curves[ncurves]; + EC_get_builtin_curves(curves, ncurves); + EC_GROUP *curve; + for (size_t i = 0; i < ncurves; ++i) { + if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) { + curve = EC_GROUP_new_by_curve_name(curves[i].nid); + break; + } + } + (*env)->ReleaseStringUTFChars(env, name, utf_name); + if (!curve) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found."); + return NULL; + } + jobject result = generate_from_curve(env, curve); + EC_GROUP_free(curve); + return result; + } else { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); + return NULL; + } +} \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c index 29ee707..dc3abd9 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c @@ -128,6 +128,7 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPa } curve++; } + (*env)->ReleaseStringUTFChars(env, name, utf_name); return JNI_FALSE; } else { return JNI_FALSE; diff --git a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java index 2e29b07..93be3a8 100644 --- a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java @@ -1,5 +1,6 @@ package cz.crcs.ectester.standalone.output; +import cz.crcs.ectester.common.cli.Colors; import cz.crcs.ectester.common.output.BaseTextTestWriter; import cz.crcs.ectester.common.test.TestSuite; import cz.crcs.ectester.common.test.Testable; @@ -45,8 +46,8 @@ public class TextTestWriter extends BaseTextTestWriter { if (suite instanceof StandaloneTestSuite) { StandaloneTestSuite standaloneSuite = (StandaloneTestSuite) suite; StringBuilder sb = new StringBuilder(); - sb.append("═══ ECTester version: " + ECTesterStandalone.VERSION).append(System.lineSeparator()); - sb.append("═══ ").append(standaloneSuite.getLibrary().name()).append(System.lineSeparator()); + sb.append("═══ ").append(Colors.underline("ECTester version:")).append(" ").append(ECTesterStandalone.VERSION).append(System.lineSeparator()); + sb.append("═══ ").append(Colors.underline("Library:")).append(standaloneSuite.getLibrary().name()).append(System.lineSeparator()); return sb.toString(); } return ""; -- cgit v1.2.3-70-g09d2 From 2e91b252aa7ce4400c0fb6b586e78216717147e5 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 25 Jul 2018 21:51:21 +0200 Subject: Fix releasing memory in LibTomCrypt shim, fix ECDH time measurement. --- .../ectester/standalone/ECTesterStandalone.java | 2 ++ .../crcs/ectester/standalone/libs/jni/tomcrypt.c | 33 ++++++++++++++-------- 2 files changed, 24 insertions(+), 11 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 9df6c61..c3d42dc 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -320,12 +320,14 @@ public class ECTesterStandalone { elapsed += System.nanoTime(); SecretKey derived; byte[] result; + elapsed -= System.nanoTime(); if (kaIdent.requiresKeyAlgo()) { derived = ka.generateSecret(keyAlgo); result = derived.getEncoded(); } else { result = ka.generateSecret(); } + elapsed += System.nanoTime(); ka = kaIdent.getInstance(lib.getProvider()); String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c index b62dd61..d609a48 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c @@ -230,6 +230,17 @@ static ltc_ecc_set_type* create_curve(JNIEnv *env, jobject params) { return curve; } +static void free_curve(ltc_ecc_set_type *curve) { + if (curve) { + free((void*)curve->prime); + free((void*)curve->B); + free((void*)curve->order); + free((void*)curve->Gx); + free((void*)curve->Gy); + free(curve); + } +} + static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) { ecc_key key; int err; @@ -287,7 +298,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { ltc_ecc_set_type *curve = create_curve(env, params); jobject result = generate_from_curve(env, curve); - free(curve); + free_curve(curve); return result; } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); @@ -357,13 +368,13 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey ecc_key pub; if (!pubkey_from_bytes(env, pubkey, curve, &pub)) { - free(curve); + free_curve(curve); return NULL; } ecc_key priv; if (!privkey_from_bytes(env, privkey, curve, &priv)) { - free(curve); + free_curve(curve); return NULL; } @@ -372,7 +383,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey int err; if ((err = ecc_shared_secret(&priv, &pub, result, &output_len)) != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); - free(curve); + free_curve(curve); return NULL; } @@ -382,7 +393,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey (*env)->ReleaseByteArrayElements(env, output, output_data, 0); ltc_cleanup_multi(&pub.pubkey.x, &pub.pubkey.y, &pub.pubkey.z, &priv.k, NULL); - free(curve); + free_curve(curve); return output; } @@ -391,7 +402,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig ecc_key priv; if (!privkey_from_bytes(env, privkey, curve, &priv)) { - free(curve); + free_curve(curve); return NULL; } @@ -403,7 +414,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig int err; if ((err = ecc_sign_hash(data_data, data_size, result, &output_len, <c_prng, find_prng("yarrow"), &priv)) != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); - free(curve); + free_curve(curve); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); return NULL; } @@ -415,7 +426,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig memcpy(output_data, result, output_len); (*env)->ReleaseByteArrayElements(env, output, output_data, 0); - free(curve); + free_curve(curve); return output; } @@ -424,7 +435,7 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna ecc_key pub; if (!pubkey_from_bytes(env, pubkey, curve, &pub)) { - free(curve); + free_curve(curve); return JNI_FALSE; } @@ -438,7 +449,7 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna int result; if ((err = ecc_verify_hash(sig_data, sig_size, data_data, data_size, &result, &pub)) != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); - free(curve); + free_curve(curve); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT); return JNI_FALSE; @@ -446,6 +457,6 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT); - free(curve); + free_curve(curve); return result; } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 713b14add9496ae5b3df5bb51b02d449f4ca0cef Mon Sep 17 00:00:00 2001 From: J08nY Date: Tue, 24 Jul 2018 22:46:49 +0200 Subject: WIP: Microsoft CryptoAPI Next Generation support. --- build-standalone.xml | 5 + .../ectester/standalone/ECTesterStandalone.java | 2 +- src/cz/crcs/ectester/standalone/libs/MscngLib.java | 20 ++ src/cz/crcs/ectester/standalone/libs/jni/Makefile | 5 +- .../standalone/libs/jni/NativeECPrivateKey.java | 6 + .../standalone/libs/jni/NativeECPublicKey.java | 7 + .../libs/jni/NativeKeyPairGeneratorSpi.java | 40 ++- .../standalone/libs/jni/NativeProvider.java | 10 + src/cz/crcs/ectester/standalone/libs/jni/mscng.c | 324 +++++++++++++++++++++ src/cz/crcs/ectester/standalone/libs/jni/native.h | 125 ++++++++ 10 files changed, 540 insertions(+), 4 deletions(-) create mode 100644 src/cz/crcs/ectester/standalone/libs/MscngLib.java create mode 100644 src/cz/crcs/ectester/standalone/libs/jni/mscng.c (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/build-standalone.xml b/build-standalone.xml index 3783f59..1e6a3d5 100644 --- a/build-standalone.xml +++ b/build-standalone.xml @@ -129,6 +129,11 @@ + + + + + diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index c3d42dc..2897d20 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -66,7 +66,7 @@ import java.util.stream.Collectors; * @version v0.2.0 */ public class ECTesterStandalone { - private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib(), new OpensslLib()}; + private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib(), new OpensslLib(), new MscngLib()}; private Config cfg; private Options opts = new Options(); diff --git a/src/cz/crcs/ectester/standalone/libs/MscngLib.java b/src/cz/crcs/ectester/standalone/libs/MscngLib.java new file mode 100644 index 0000000..527a65b --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/MscngLib.java @@ -0,0 +1,20 @@ +package cz.crcs.ectester.standalone.libs; + +import java.security.Provider; +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class MscngLib extends NativeECLibrary { + + public MscngLib() { + super("mscng_provider", "bcrypt"); + } + + @Override + native Provider createProvider(); + + @Override + public native Set getCurves(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile index 22e41cb..6fe6857 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile +++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile @@ -43,7 +43,7 @@ CFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. CXXFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. -all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so +all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so mscng_provider.dll # Common utils c_utils.o: c_utils.c @@ -85,6 +85,9 @@ cryptopp.o: cryptopp.cpp $(CXX) $(shell pkg-config --cflags libcrypto++) $(CXXFLAGS) -c $< +mscng_provider.dll: mscng.c + + clean: rm -rf *.o rm -rf *.so diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java index 39539df..277ffa7 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java @@ -77,4 +77,10 @@ public abstract class NativeECPrivateKey implements ECPrivateKey { super(keyData, params); } } + + public static class Mscng extends Raw { + public Mscng(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java index 1085083..18cc2cb 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java @@ -1,5 +1,6 @@ package cz.crcs.ectester.standalone.libs.jni; +import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.common.util.ECUtil; import org.bouncycastle.util.Arrays; @@ -79,4 +80,10 @@ public abstract class NativeECPublicKey implements ECPublicKey { super(keyData, params); } } + + public static class Mscng extends ANSIX962 { + public Mscng(byte[] x, byte[] y, ECParameterSpec params) { + super(ByteUtil.concatenate(new byte[]{0x04}, x, y), params); + } + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java index 6e441e5..f7e7653 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java @@ -27,7 +27,7 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { @Override public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { if (!paramsSupported(params)) { - throw new InvalidAlgorithmParameterException("not supported."); + throw new InvalidAlgorithmParameterException("Not supported."); } this.params = params; this.random = random; @@ -41,8 +41,9 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { return generate(keysize, random); } else if (useParams) { return generate(params, random); + } else { + throw new IllegalStateException("Uninitialized KeyPair."); } - return null; } abstract boolean keysizeSupported(int keysize); @@ -173,4 +174,39 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { @Override native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); } + + public static abstract class Mscng extends NativeKeyPairGeneratorSpi { + private String type; + + public Mscng(String type) { + this.type = type; + initialize(256, new SecureRandom());//TODO: maybe remove this default init? + } + + @Override + native boolean keysizeSupported(int keysize); + + @Override + native boolean paramsSupported(AlgorithmParameterSpec params); + + @Override + native KeyPair generate(int keysize, SecureRandom random); + + @Override + native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); + } + + public static class MscngECDH extends Cryptopp { + + public MscngECDH() { + super("ECDH"); + } + } + + public static class MscngECDSA extends Cryptopp { + + public MscngECDSA() { + super("ECDSA"); + } + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java index a4967e5..f580d74 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java @@ -59,4 +59,14 @@ public abstract class NativeProvider extends Provider { @Override native void setup(); } + + public static class Mscng extends NativeProvider { + + public Mscng(String name, double version, String info) { + super(name, version, info); + } + + @Override + native void setup(); + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c new file mode 100644 index 0000000..94a0f60 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c @@ -0,0 +1,324 @@ +#include "native.h" +#include +#include + +#include "c_utils.h" + +static jclass provider_class; + +#define NT_SUCCESS(status) (((NTSTATUS)(status)) >= 0) +#define NT_FAILURE(status) !NT_SUCCESS(status) + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_createProvider(JNIEnv *env, jobject self){ + jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Mscng"); + provider_class = (*env)->NewGlobalRef(env, local_provider_class); + + jmethodID init = (*env)->GetMethodID(env, local_provider_class, "", "(Ljava/lang/String;DLjava/lang/String;)V"); + + jstring name = (*env)->NewStringUTF(env, "Microsoft CNG"); + double version = 1.0; + return (*env)->NewObject(env, provider_class, init, name, version, name); +} + +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Mscng_setup(JNIEnv *env, jobject self) { + INIT_PROVIDER(env, provider_class); + + init_classes(env, "Mscng"); +} + +typedef struct { + const char *name; + ULONG bits; +} named_curve_t; + +static named_curve_t named_curves[] = { + {"curve25519", 256}, + {"brainpoolP160r1", 160}, + {"brainpoolP160t1", 160}, + {"brainpoolP192r1", 192}, + {"brainpoolP192t1", 192}, + {"brainpoolP224r1", 224}, + {"brainpoolP224t1", 224}, + {"brainpoolP256r1", 256}, + {"brainpoolP256t1", 256}, + {"brainpoolP320r1", 320}, + {"brainpoolP320t1", 320}, + {"brainpoolP384r1", 384}, + {"brainpoolP384t1", 384}, + {"brainpoolP512r1", 512}, + {"brainpoolP512t1", 512}, + {"ec192wapi", 192}, + {"nistP192", 192}, + {"nistP224", 224}, + {"nistP256", 256}, + {"nistP384", 384}, + {"nistP521", 521}, + {"numsP256t1", 256}, + {"numsP384t1", 384}, + {"numsP512t1", 512}, + {"secP160k1", 160}, + {"secP160r1", 160}, + {"secP160r2", 160}, + {"secP192k1", 192}, + {"secP192r1", 192}, + {"secP224k1", 224}, + {"secP224r1", 224}, + {"secP256k1", 256}, + {"secP256r1", 256}, + {"secP384r1", 384}, + {"secP521r1", 521}, + {"wtls12", 224}, + {"wtls7", 160}, + {"wtls9", 160}, + {"x962P192v1", 192}, + {"x962P192v2", 192}, + {"x962P192v3", 192}, + {"x962P239v1", 239}, + {"x962P239v2", 239}, + {"x962P239v3", 239}, + {"x962P256v1", 256} +}; + +static const named_curve_t* lookup_curve(const char *name) { + for (size_t i = 0; i < sizeof(named_curves)/sizeof(named_curve_t); ++i) { + if (strcasecmp(name, named_curves[i].name) == 0) { + return &named_curves[i]; + } + } + return NULL; +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getCurves(JNIEnv *env, jobject self) { + jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet"); + + jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "", "()V"); + jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z"); + + jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr); + + for (size_t i = 0; i < sizeof(named_curves)/sizeof(named_curve_t); ++i) { + jstring curve_name = (*env)->NewStringUTF(env, named_curves[i].name); + (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name); + } + return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_keysizeSupported(JNIEnv *env, jobject self, jint keysize) { + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_paramsSupported(JNIEnv *env, jobject self, jobject params) { + if (params == NULL) { + return JNI_FALSE; + } + + if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { + jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (*env)->CallObjectMethod(env, params, get_name); + const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL); + const named_curve_t *curve = lookup_curve(utf_name); + (*env)->ReleaseStringUTFChars(env, name, utf_name); + return curve == NULL ? JNI_FALSE : JNI_TRUE; + } else { + return JNI_FALSE; + } +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); + return NULL; +} + +static jobject bytes_to_biginteger(JNIEnv *env, PBYTE bytes, int len) { + jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "", "(I[B)V"); + jbyteArray bytes = (*env)->NewByteArray(env, len); + jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL); + memcpy(data, bytes, len); + (*env)->ReleaseByteArrayElements(env, bytes, data, 0); + jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes); + return result; +} + +static jobject create_ec_param_spec(JNIEnv *env, PBYTE eccParams, ULONG paramLength) { + // Taken from https://github.com/dotnet/corefx, thanks! This API is nowhere to be found. + // + // BCRYPT_ECC_PARAMETER_HEADER header + // byte[cbFieldLength] P + // byte[cbFieldLength] A + // byte[cbFieldLength] B + // byte[cbFieldLength] G.X + // byte[cbFieldLength] G.Y + // byte[cbSubgroupOrder] Order (n) + // byte[cbCofactor] Cofactor (h) + // byte[cbSeed] Seed + + // BCRYPT_ECC_PARAMETER_HEADER + // internal int Version; //Version of the structure + // internal ECC_CURVE_TYPE_ENUM CurveType; //Supported curve types. + // internal ECC_CURVE_ALG_ID_ENUM CurveGenerationAlgId; //For X.592 verification purposes, if we include Seed we will need to include the algorithm ID. + // internal int cbFieldLength; //Byte length of the fields P, A, B, X, Y. + // internal int cbSubgroupOrder; //Byte length of the subgroup. + // internal int cbCofactor; //Byte length of cofactor of G in E. + // internal int cbSeed; //Byte length of the seed used to generate the curve. + + // internal enum ECC_CURVE_TYPE_ENUM : int + // { + // BCRYPT_ECC_PRIME_SHORT_WEIERSTRASS_CURVE = 0x1, + // BCRYPT_ECC_PRIME_TWISTED_EDWARDS_CURVE = 0x2, + // BCRYPT_ECC_PRIME_MONTGOMERY_CURVE = 0x3, + // } + + // internal enum ECC_CURVE_ALG_ID_ENUM : int + // { + // BCRYPT_NO_CURVE_GENERATION_ALG_ID = 0x0, + // } + BCRYPT_ECC_PARAMETER_HEADER *header = (BCRYPT_ECC_PARAMETER_HEADER*)eccParams; + PBYTE paramsStart = &eccParams[sizeof(BCRYPT_ECC_PARAMETER_HEADER)]; + + //cbFieldLength + PBYTE P = paramsStart; + PBYTE A = p + header->cbFieldLength; + PBYTE B = A + header->cbFieldLength; + PBYTE GX = B + header->cbFieldLength; + PBYTE GY = GX + header->cbFieldLength; + + //cbSubgroupOrder + PBYTE N = GY + header->cbFieldLength; + + //cbCofactor + PBYTE H = N + header->cbSubgroupOrder; + + //cbSeed + PBYTE S = H + header->cbCofactor; + + jobject p_int = bytes_to_biginteger(env, P, header->cbFieldLength); + + jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "", "(Ljava/math/BigInteger;)V"); + jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p_int); + + jobject a_int = bytes_to_biginteger(env, A, header->cbFieldLength); + jobject b_int = bytes_to_biginteger(env, B, header->cbFieldLength); + + jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a_int, b_int); + + jobject gx_int = bytes_to_biginteger(env, GX, header->cbFieldLength); + jobject gy_int = bytes_to_biginteger(env, GY, header->cbFieldLength); + + jmethodID point_init = (*env)->GetMethodID(env, point_class, "", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject g = (*env)->NewObject(env, point_class, point_init, gx_int, gy_int); + + jobject n_int = bytes_to_biginteger(env, N, header->cbSubgroupOrder); + + jobject h_int = bytes_to_biginteger(env, H, header->cbCofactor); + jmethodID bigint_to_int = (*env)->GetMethodID(env, biginteger_class, "intValue", "()I"); + jint cof = (*env)->CallIntMethod(env, h_int, bigint_to_int); + + jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V"); + return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n_int, cof); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random){ + BCRYPT_ALG_HANDLE kaHandle = NULL; + BCRYPT_KEY_HANDLE key = NULL; + + //TODO: CUSTOM curve with BCRYPT_ECC_PARAMETERS?? + + jclass mscng_kpg_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi$Mscng"); + jfieldID type_id = (*env)->GetFieldID(env, mscng_kpg_class, "type", "Ljava/lang/String;"); + jstring type = (jstring) (*env)->GetObjectField(env, self, type_id); + const char* type_data = (*env)->GetStringUTFChars(env, type, NULL); + LPCWSTR algo; + if (strcmp(type_data, "ECDH") == 0) { + algo = BCRYPT_ECDH_ALGORITHM; + } else if (strcmp(type_data, "ECDSA") == 0) { + algo = BCRYPT_ECDSA_ALGORITHM; + } else { + //err + } + (*env)->ReleaseStringUTFChars(env, type, type_data); + + if (NT_FAILURE(BCryptOpenAlgorithmProvider(&kaHandle, algo, MS_PRIMITIVE_PROVIDER, 0))) { + //err + } + + jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (*env)->CallObjectMethod(env, params, get_name); + const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL); + const named_curve_t *curve = lookup_curve(utf_name); + if (NT_FAILURE(BCryptSetProperty(kaHandle, BCRYPT_ECC_CURVE_NAME, utf_name, strlen(utf_name), 0))) { + //err + } + (*env)->ReleaseStringUTFChars(env, name, utf_name); + + ULONG paramsSize; + if (NT_FAILURE(BCryptGetProperty(kaHandle, BCRYPT_ECC_PARAMETERS, NULL, 0, ¶msSize, 0))) { + //err + } + if (paramsSize == 0) { + //TODO: what now? + } + + BYTE params[paramsSize]; + if (NT_FAILURE(BCryptGetProperty(kaHandle, BCRYPT_ECC_PARAMETERS, params, paramsSize, ¶msSize, 0))) { + //err + } + + jobject ec_param_spec = create_ec_param_spec(env, params, paramsSize); + + if (NT_FAILURE(BCryptGenerateKeyPair(kaHandle, &key, curve.bits, 0)) { + //err + } + + if (NT_FAILURE(BCryptFinalizeKeyPair(key, 0))) { + //err + } + + ULONG bufSize; + if (NT_FAILURE(BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, NULL, 0, &bufSize, 0))) { + //err + } + + BYTE privBuf[bufSize]; + if (NT_FAILURE(BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, privBuf, bufsize, &bufSize, 0))) { + //err + } + + // privBuf looks like: + // BCRYPT_ECCKEY_BLOB header + // byte[cbKey] Q.X + // byte[cbKey] Q.Y + // byte[cbKey] D + BCRYPT_ECCKEY_BLOB *header = (BCRYPT_ECCKEY_BLOB*)privBuf; + PBYTE x = &privBuf[sizeof(BCRYPT_ECCKEY_BLOB)]; + PBYTE y = x + header->cbKey; + PBYTE priv = y + header->cbKey; + + jbyteArray priv_bytes = (*env)->NewByteArray(env, header->cbKey); + jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); + memcpy(key_priv, priv, header->cbKey); + (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); + + jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec); + jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec); + + jbyteArray x_bytes = (*env)->NewByteArray(env, header->cbKey); + jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); + memcpy(x_data, x, header->cbKey); + (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0); + jbyteArray y_bytes = (*env)->NewByteArray(env, header->cbKey); + jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL); + memcpy(y_data, y, header->cbKey); + (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0); + + jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec); + jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "", "([B[BLjava/security/spec/ECParameterSpec;)V"); + jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, x_bytes, y_bytes, ec_pub_param_spec); + + jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); + + BCryptDestroyKey(key); + BCryptCloseAlgorithmProvider(kaHandle, 0); + return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); +} \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index af68fd4..6e2b2bf 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -684,3 +684,128 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna } #endif #endif +/* Header for class cz_crcs_ectester_standalone_libs_MscngLib */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_MscngLib +#define _Included_cz_crcs_ectester_standalone_libs_MscngLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_MscngLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_createProvider + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_MscngLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getCurves + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID 1421746759512286392LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_MAX_ARRAY_SIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_MAX_ARRAY_SIZE 2147483639L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_KEYS +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_KEYS 0L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_VALUES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_VALUES 1L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_ENTRIES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_ENTRIES 2L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID 4112578634029874840LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID -4298000515446427739LL +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Mscng_setup + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_keysizeSupported + (JNIEnv *, jobject, jint); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_paramsSupported + (JNIEnv *, jobject, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_generate__ILjava_security_SecureRandom_2 + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2 + (JNIEnv *, jobject, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Mscng */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Mscng +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Mscng +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Mscng */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Mscng +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Mscng +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif -- cgit v1.2.3-70-g09d2 From f7cd2f14fec676fedc6484eff9a64ebc41d3d910 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sat, 28 Jul 2018 18:34:09 +0200 Subject: Redo Mscng key storage. --- .../ectester/standalone/ECTesterStandalone.java | 1 - .../standalone/libs/jni/NativeECPrivateKey.java | 19 +- .../standalone/libs/jni/NativeECPublicKey.java | 19 +- .../standalone/libs/jni/NativeSignatureSpi.java | 23 +- src/cz/crcs/ectester/standalone/libs/jni/mscng.c | 315 ++++++++++++++++++--- src/cz/crcs/ectester/standalone/libs/jni/native.h | 38 +-- 6 files changed, 345 insertions(+), 70 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 2897d20..2f132fa 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -275,7 +275,6 @@ public class ECTesterStandalone { .findFirst() .orElse(null))); - if (kaIdent == null || kpIdent == null) { throw new NoSuchAlgorithmException(algo); } else { diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java index 76786fe..4cd4a9d 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java @@ -86,23 +86,38 @@ public abstract class NativeECPrivateKey implements ECPrivateKey { } public static class Mscng extends Raw { + // 0 -> implicit (meta = curveName UTF16, header = full); + // 1 -> explicit (meta = null, header = full); + // 2 -> nist (meta = null, header = full) + private int flag; + private byte[] meta = null; private byte[] header; private byte[] x; private byte[] y; - public Mscng(byte[] header, byte[] x, byte[] y, byte[] keyData, ECParameterSpec params) { + public Mscng(int flag, byte[] meta, byte[] header, byte[] x, byte[] y, byte[] keyData, ECParameterSpec params) { super(keyData, params); + this.flag = flag; + this.meta = Arrays.clone(meta); this.header = Arrays.clone(header); this.x = Arrays.clone(x); this.y = Arrays.clone(y); } + public int getFlag() { + return flag; + } + + public byte[] getMeta() { + return Arrays.clone(meta); + } + public byte[] getHeader() { return Arrays.clone(header); } public byte[] getBlob() { - return ByteUtil.concatenate(header, x, y, keyData); + return ByteUtil.concatenate(header, x, y, keyData); } @Override diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java index e55ed33..ccf21c0 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java @@ -88,23 +88,38 @@ public abstract class NativeECPublicKey implements ECPublicKey { } public static class Mscng extends ANSIX962 { + // 0 -> implicit (meta = curveName UTF16, header = full); + // 1 -> explicit (meta = null, header = full); + // 2 -> nist (meta = null, header = full) + private int flag; + private byte[] meta = null; private byte[] header; private byte[] x; private byte[] y; - public Mscng(byte[] header, byte[] x, byte[] y, ECParameterSpec params) { + public Mscng(int flag, byte[] meta, byte[] header, byte[] x, byte[] y, ECParameterSpec params) { super(ByteUtil.concatenate(new byte[]{0x04}, x, y), params); + this.flag = flag; + this.meta = Arrays.clone(meta); this.header = Arrays.clone(header); this.x = Arrays.clone(x); this.y = Arrays.clone(y); } + public int getFlag() { + return flag; + } + + public byte[] getMeta() { + return Arrays.clone(meta); + } + public byte[] getHeader() { return Arrays.clone(header); } public byte[] getBlob() { - return ByteUtil.concatenate(header, x, y); + return ByteUtil.concatenate(header, x, y); } @Override diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java index 81c7948..b60f2c6 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java @@ -92,6 +92,23 @@ public abstract class NativeSignatureSpi extends SignatureSpi { abstract boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); } + private abstract static class ExtendedSignatureSpi extends NativeSignatureSpi { + + @Override + protected byte[] engineSign() throws SignatureException { + return sign(buffer.toByteArray(), signKey, params); + } + + @Override + protected boolean engineVerify(byte[] sigBytes) throws SignatureException { + return verify(sigBytes, buffer.toByteArray(), verifyKey, params); + } + + abstract byte[] sign(byte[] data, ECPrivateKey privkey, ECParameterSpec params); + + abstract boolean verify(byte[] signature, byte[] data, ECPublicKey pubkey, ECParameterSpec params); + } + public static class TomCryptRaw extends SimpleSignatureSpi { @Override @@ -311,7 +328,7 @@ public abstract class NativeSignatureSpi extends SignatureSpi { } } - public abstract static class Mscng extends SimpleSignatureSpi { + public abstract static class Mscng extends ExtendedSignatureSpi { private String type; public Mscng(String type) { @@ -319,10 +336,10 @@ public abstract class NativeSignatureSpi extends SignatureSpi { } @Override - native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + native byte[] sign(byte[] data, ECPrivateKey privkey, ECParameterSpec params); @Override - native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + native boolean verify(byte[] signature, byte[] data, ECPublicKey pubkey, ECParameterSpec params); } public static class MscngECDSAwithSHA1 extends Mscng { diff --git a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c index 12cc13d..8cd96fc 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c @@ -6,8 +6,9 @@ #include -static jclass provider_class; + +// BCRYPT and NT things. #define NT_SUCCESS(status) (((NTSTATUS)(status)) >= 0) #define NT_FAILURE(status) !NT_SUCCESS(status) @@ -24,6 +25,13 @@ typedef struct { ULONG cbSeed; //Byte length of the seed used to generate the curve. } BCRYPT_ECC_PARAMETER_HEADER; +//Provider things +static jclass provider_class; + +#define KEYFLAG_IMPLICIT 0 +#define KEYFLAG_EXPLICIT 1 +#define KEYFLAG_NIST 2 + JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_createProvider(JNIEnv *env, jobject self) { jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Mscng"); provider_class = (*env)->NewGlobalRef(env, local_provider_class); @@ -138,8 +146,8 @@ static ULONG utf_8to16(NWPSTR *out_buf, LPCSTR in_str) { return MultiByteToWideChar(CP_UTF8, 0, in_str, -1, *out_buf, result); } -// Convert Java String to UTF-16 LPCWSTR null-terminated. -// Returns: Length of LPCWSTR in bytes! +// Convert Java String to UTF-16 NWPSTR null-terminated. +// Returns: Length of NWPSTR in bytes! static ULONG utf_strto16(NWPSTR *out_buf, JNIEnv *env, jobject str) { jsize len = (*env)->GetStringLength(env, str); *out_buf = calloc(len * sizeof(jchar) + 1, 1); @@ -378,7 +386,7 @@ static ULONG create_curve(JNIEnv *env, jobject params, PBYTE *curve) { return bufSize; } -static ULONG init_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR algo, jobject params) { +static ULONG init_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, jint *keyflag, NWPSTR *curve_name, LPCWSTR algo, jobject params) { NTSTATUS status; if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(handle, algo, MS_PRIMITIVE_PROVIDER, 0))) { wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); @@ -392,15 +400,14 @@ static ULONG init_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR algo, job PUCHAR chars = calloc(utf_length + 1, 1); (*env)->GetStringUTFRegion(env, name, 0, utf_length, chars); const named_curve_t *curve = lookup_curve(chars); - NWPSTR curve_utf16; - ULONG ret = utf_8to16(&curve_utf16, chars); - if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_CURVE_NAME, (PUCHAR)curve_utf16, ret * sizeof(WCHAR), 0))) { + ULONG ret = utf_8to16(curve_name, chars); + if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_CURVE_NAME, (PUCHAR)*curve_name, ret * sizeof(WCHAR), 0))) { wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status); return 0; } free(chars); - free(curve_utf16); result = curve->bits; + *keyflag = KEYFLAG_IMPLICIT; } else if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { PBYTE curve; ULONG curveLen = create_curve(env, params, &curve); @@ -419,11 +426,13 @@ static ULONG init_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR algo, job jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); jint bits = (*env)->CallIntMethod(env, field, get_bits); result = bits; + *keyflag = KEYFLAG_EXPLICIT; + *curve_name = NULL; } return result; } -static jobject key_to_privkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { +static jobject key_to_privkey(JNIEnv *env, BCRYPT_KEY_HANDLE key, jint flag, LPCWSTR curve) { NTSTATUS status; ULONG bufSize = 0; if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, NULL, 0, &bufSize, 0))) { @@ -438,6 +447,7 @@ static jobject key_to_privkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { PBYTE fullBuf = calloc(bufSize, 1); if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, fullBuf, bufSize, &bufSize, 0))) { wprintf(L"**** Error 0x%x returned by BCryptExportKey(full, whole)\n", status); + free(fullBuf); return NULL; } @@ -462,10 +472,59 @@ static jobject key_to_privkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { PBYTE priv_y = priv_x + privHeader->cbFieldLength; PBYTE priv = priv_y + privHeader->cbFieldLength; - jbyteArray header_bytes = (*env)->NewByteArray(env, paramLength); - jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); - memcpy(header_data, privHeader, paramLength); - (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); + + jbyteArray meta_bytes = NULL; + jbyteArray header_bytes = NULL; + switch (flag) { + case 0: { + // meta = curve + jint meta_len = (wcslen(curve) + 1) * sizeof(WCHAR); + meta_bytes = (*env)->NewByteArray(env, meta_len); + jbyte *meta_data = (*env)->GetByteArrayElements(env, meta_bytes, NULL); + memcpy(meta_data, curve, meta_len); + (*env)->ReleaseByteArrayElements(env, meta_bytes, meta_data, 0); + } + case 1: + case 2: { + // meta = null + // header = full + header_bytes = (*env)->NewByteArray(env, paramLength); + jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); + memcpy(header_data, fullBuf, paramLength); + (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); + break; + } + default: + // header = small + if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, NULL, 0, &bufSize, 0))) { + wprintf(L"**** Error 0x%x returned by BCryptExportKey(small, length only)\n", status); + free(fullBuf); + return NULL; + } + if (bufSize == 0) { + printf("buf 0\n"); + free(fullBuf); + return NULL; + } + PBYTE smallBuf = calloc(bufSize, 1); + if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, smallBuf, bufSize, &bufSize, 0))) { + wprintf(L"**** Error 0x%x returned by BCryptExportKey(small, whole)\n", status); + free(fullBuf); + free(smallBuf); + return NULL; + } + // smallBuf looks like: + // BCRYPT_ECCKEY_BLOB header + // Qx[cbFieldLength] X-coordinate of the public point. + // Qy[cbFieldLength] Y-coordinate of the public point. + // d[cbSubgroupOrder] Private key. + header_bytes = (*env)->NewByteArray(env, sizeof(BCRYPT_ECCKEY_BLOB)); + jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); + memcpy(header_data, smallBuf, sizeof(BCRYPT_ECCKEY_BLOB)); + (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); + free(smallBuf); + break; + } jbyteArray x_bytes = (*env)->NewByteArray(env, privHeader->cbFieldLength); jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); @@ -484,11 +543,11 @@ static jobject key_to_privkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { free(fullBuf); - jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "", "([B[B[B[BLjava/security/spec/ECParameterSpec;)V"); - return (*env)->NewObject(env, privkey_class, ec_priv_init, header_bytes, x_bytes, y_bytes, priv_bytes, ec_priv_param_spec); + jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "", "(I[B[B[B[B[BLjava/security/spec/ECParameterSpec;)V"); + return (*env)->NewObject(env, privkey_class, ec_priv_init, flag, meta_bytes, header_bytes, x_bytes, y_bytes, priv_bytes, ec_priv_param_spec); } -static jobject key_to_pubkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { +static jobject key_to_pubkey(JNIEnv *env, BCRYPT_KEY_HANDLE key, jint flag, LPCWSTR curve) { NTSTATUS status; ULONG bufSize = 0; if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, NULL, 0, &bufSize, 0))) { @@ -525,10 +584,55 @@ static jobject key_to_pubkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { PBYTE pub_x = &fullBuf[paramLength]; PBYTE pub_y = pub_x + pubHeader->cbFieldLength; - jbyteArray header_bytes = (*env)->NewByteArray(env, paramLength); - jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); - memcpy(header_data, pubHeader, paramLength); - (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); + jbyteArray meta_bytes = NULL; + jbyteArray header_bytes = NULL; + switch (flag) { + case 0: { + // meta = curve + jint meta_len = (wcslen(curve) + 1) * sizeof(WCHAR); + meta_bytes = (*env)->NewByteArray(env, meta_len); + jbyte *meta_data = (*env)->GetByteArrayElements(env, meta_bytes, NULL); + memcpy(meta_data, curve, meta_len); + (*env)->ReleaseByteArrayElements(env, meta_bytes, meta_data, 0); + } + case 1: + case 2: { + header_bytes = (*env)->NewByteArray(env, paramLength); + jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); + memcpy(header_data, pubHeader, paramLength); + (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); + break; + } + default: + // header = small + if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, 0, &bufSize, 0))) { + wprintf(L"**** Error 0x%x returned by BCryptExportKey(small, length only)\n", status); + free(fullBuf); + return NULL; + } + if (bufSize == 0) { + printf("buf 0\n"); + free(fullBuf); + return NULL; + } + PBYTE smallBuf = calloc(bufSize, 1); + if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, smallBuf, bufSize, &bufSize, 0))) { + wprintf(L"**** Error 0x%x returned by BCryptExportKey(small, whole)\n", status); + free(fullBuf); + free(smallBuf); + return NULL; + } + // smallBuf looks like: + // BCRYPT_ECCKEY_BLOB header + // Qx[cbFieldLength] X-coordinate of the public point. + // Qy[cbFieldLength] Y-coordinate of the public point. + header_bytes = (*env)->NewByteArray(env, sizeof(BCRYPT_ECCKEY_BLOB)); + jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); + memcpy(header_data, smallBuf, sizeof(BCRYPT_ECCKEY_BLOB)); + (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); + free(smallBuf); + break; + } jbyteArray x_bytes = (*env)->NewByteArray(env, pubHeader->cbFieldLength); jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); @@ -542,8 +646,8 @@ static jobject key_to_pubkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { free(fullBuf); - jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "", "([B[B[BLjava/security/spec/ECParameterSpec;)V"); - return (*env)->NewObject(env, pubkey_class, ec_pub_init, header_bytes, x_bytes, y_bytes, ec_pub_param_spec); + jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "", "(I[B[B[B[BLjava/security/spec/ECParameterSpec;)V"); + return (*env)->NewObject(env, pubkey_class, ec_pub_init, flag, meta_bytes, header_bytes, x_bytes, y_bytes, ec_pub_param_spec); } JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) { @@ -610,8 +714,8 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai return NULL; } - jobject privkey = key_to_privkey(env, key); - jobject pubkey = key_to_pubkey(env, key); + jobject privkey = key_to_privkey(env, key, KEYFLAG_NIST, NULL); + jobject pubkey = key_to_pubkey(env, key, KEYFLAG_NIST, NULL); jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); @@ -640,7 +744,9 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai } (*env)->ReleaseStringUTFChars(env, type, type_data); - ULONG bits = init_algo(env, &handle, algo, params); + jint keyflag; + NWPSTR curveName; + ULONG bits = init_algo(env, &handle, &keyflag, &curveName, algo, params); if (bits == 0) { throw_new(env, "java/security/GeneralSecurityException", "Couldn't initialize algo."); return NULL; @@ -658,8 +764,12 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai return NULL; } - jobject privkey = key_to_privkey(env, key); - jobject pubkey = key_to_pubkey(env, key); + jobject privkey = key_to_privkey(env, key, keyflag, curveName); + jobject pubkey = key_to_pubkey(env, key, keyflag, curveName); + + if (curveName) { + free(curveName); + } jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); @@ -668,9 +778,109 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); } +static NTSTATUS init_use_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR type, jint keyflag, jbyteArray meta, jobject params) { + LPCWSTR ecdh_algos[] = { + BCRYPT_ECDH_ALGORITHM, + BCRYPT_ECDH_P256_ALGORITHM, + BCRYPT_ECDH_P384_ALGORITHM, + BCRYPT_ECDH_P521_ALGORITHM + }; + LPCWSTR ecdsa_algos[] = { + BCRYPT_ECDSA_ALGORITHM, + BCRYPT_ECDSA_P256_ALGORITHM, + BCRYPT_ECDSA_P384_ALGORITHM, + BCRYPT_ECDSA_P521_ALGORITHM + }; + + LPCWSTR *algos; + LPCWSTR algo; + if (lstrcmpW(type, BCRYPT_ECDH_ALGORITHM) == 0) { + algos = ecdh_algos; + } else if (lstrcmpW(type, BCRYPT_ECDSA_ALGORITHM) == 0) { + algos = ecdsa_algos; + } else { + //unreachable + return STATUS_INVALID_PARAMETER; + } + + switch (keyflag) { + case 0: + case 1: + algo = algos[0]; + break; + case 2: { + jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve); + + jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field); + + jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); + jint bits = (*env)->CallIntMethod(env, field, get_bits); + switch (bits) { + case 256: + algo = algos[1]; + break; + case 384: + algo = algos[2]; + break; + case 521: + algo = algos[3]; + break; + default: + return STATUS_INVALID_PARAMETER; + } + break; + } + } + NTSTATUS status; + + if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(handle, algo, MS_PRIMITIVE_PROVIDER, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); + return status; + } + + switch (keyflag) { + case 0: { + jint meta_len = (*env)->GetArrayLength(env, meta); + jbyte *meta_data = (*env)->GetByteArrayElements(env, meta, NULL); + //if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_CURVE_NAME, meta_data, meta_len, 0))) { + // throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptSetProperty(curve name)\n", status); + // (*env)->ReleaseByteArrayElements(env, meta, meta_data, JNI_ABORT); + // return status; + //} + (*env)->ReleaseByteArrayElements(env, meta, meta_data, JNI_ABORT); + break; + } + case 1: { + PBYTE curve; + ULONG curve_len = create_curve(env, params, &curve); + if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_PARAMETERS, curve, curve_len, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptSetProperty(parameters)\n", status); + free(curve); + return status; + } + free(curve); + break; + } + } + return STATUS_SUCCESS; +} + +static jint get_keyflag(JNIEnv *env, jobject key) { + jclass key_class = (*env)->GetObjectClass(env, key); + jmethodID get_flag = (*env)->GetMethodID(env, key_class, "getFlag", "()I"); + return (*env)->CallIntMethod(env, key, get_flag); +} + +static jbyteArray get_meta(JNIEnv *env, jobject key) { + jclass key_class = (*env)->GetObjectClass(env, key); + jmethodID get_meta = (*env)->GetMethodID(env, key_class, "getMeta", "()[B"); + return (jbyteArray)(*env)->CallObjectMethod(env, key, get_meta); +} + JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Mscng_generateSecret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) { NTSTATUS status; - printf("generateSecret!\n"); jclass mscng_ka_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi$Mscng"); jfieldID type_id = (*env)->GetFieldID(env, mscng_ka_class, "type", "Ljava/lang/String;"); @@ -693,9 +903,10 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey BCRYPT_ALG_HANDLE kaHandle = NULL; - ULONG bits = init_algo(env, &kaHandle, BCRYPT_ECDH_ALGORITHM, params); - if (bits == 0) { - throw_new(env, "java/security/GeneralSecurityException", "Couldn't initialize algo."); + jint pub_flag = get_keyflag(env, pubkey); + jbyteArray meta = get_meta(env, pubkey); + + if (NT_FAILURE(status = init_use_algo(env, &kaHandle, BCRYPT_ECDH_ALGORITHM, pub_flag, meta, params))) { return NULL; } @@ -712,6 +923,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey } (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + jint priv_flag = get_keyflag(env, privkey); jint priv_length = (*env)->GetArrayLength(env, privkey); jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); if (NT_FAILURE(status = BCryptImportKeyPair(kaHandle, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, &skey, priv_data, priv_length, 0))) { @@ -791,12 +1003,19 @@ static LPCWSTR get_sighash_algo(JNIEnv *env, jobject self) { return hash_algo; } -JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) { +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_sign(JNIEnv *env, jobject self, jbyteArray data, jobject privkey, jobject params) { NTSTATUS status; LPCWSTR hash_algo = get_sighash_algo(env, self); BCRYPT_ALG_HANDLE sigHandle = NULL; + jint keyflag = get_keyflag(env, privkey); + jbyteArray meta = get_meta(env, privkey); + + if (NT_FAILURE(status = init_use_algo(env, &sigHandle, BCRYPT_ECDSA_ALGORITHM, keyflag, meta, params))) { + return NULL; + } + if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&sigHandle, BCRYPT_ECDSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0))) { throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); return NULL; @@ -835,17 +1054,21 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig BCRYPT_KEY_HANDLE skey = NULL; - jint priv_length = (*env)->GetArrayLength(env, privkey); - jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); + jmethodID get_data = (*env)->GetMethodID(env, privkey_class, "getData", "()[B"); + jbyteArray privkey_barray = (jbyteArray)(*env)->CallObjectMethod(env, privkey, get_data); + + + jint priv_length = (*env)->GetArrayLength(env, privkey_barray); + jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey_barray, NULL); if (NT_FAILURE(status = BCryptImportKeyPair(sigHandle, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, &skey, priv_data, priv_length, 0))) { throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptImportKeyPair\n", status); BCryptCloseAlgorithmProvider(sigHandle, 0); BCryptCloseAlgorithmProvider(hashHandle, 0); free(hash); - (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, privkey_barray, priv_data, JNI_ABORT); return NULL; } - (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, privkey_barray, priv_data, JNI_ABORT); DWORD sig_len = 0; if (NT_FAILURE(status = BCryptSignHash(skey, NULL, hash, hash_len, NULL, 0, &sig_len, 0))) { @@ -877,14 +1100,16 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig return sig; } -JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_verify(JNIEnv *env, jobject self, jbyteArray sig, jbyteArray data, jbyteArray pubkey, jobject params) { +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_verify(JNIEnv *env, jobject self, jbyteArray sig, jbyteArray data, jobject pubkey, jobject params) { NTSTATUS status; LPCWSTR hash_algo = get_sighash_algo(env, self); BCRYPT_ALG_HANDLE sigHandle = NULL; - if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&sigHandle, BCRYPT_ECDSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0))) { - throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); + jint keyflag = get_keyflag(env, pubkey); + jbyteArray meta = get_meta(env, pubkey); + + if (NT_FAILURE(status = init_use_algo(env, &sigHandle, BCRYPT_ECDSA_ALGORITHM, keyflag, meta, params))) { return JNI_FALSE; } @@ -921,17 +1146,21 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna BCRYPT_KEY_HANDLE pkey = NULL; - jint pub_length = (*env)->GetArrayLength(env, pubkey); - jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL); + jmethodID get_data = (*env)->GetMethodID(env, pubkey_class, "getData", "()[B"); + jbyteArray pubkey_barray = (jbyteArray)(*env)->CallObjectMethod(env, pubkey, get_data); + + + jint pub_length = (*env)->GetArrayLength(env, pubkey_barray); + jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey_barray, NULL); if (NT_FAILURE(status = BCryptImportKeyPair(sigHandle, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, &pkey, pub_data, pub_length, 0))) { throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptImportKeyPair\n", status); BCryptCloseAlgorithmProvider(sigHandle, 0); BCryptCloseAlgorithmProvider(hashHandle, 0); free(hash); - (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, pubkey_barray, pub_data, JNI_ABORT); return JNI_FALSE; } - (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, pubkey_barray, pub_data, JNI_ABORT); jint sig_len = (*env)->GetArrayLength(env, sig); jbyte *sig_data = (*env)->GetByteArrayElements(env, sig, NULL); diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index a2dedae..e8dff88 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -35,7 +35,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getC extern "C" { #endif #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 1421746759512286392LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 1421746759512286392i64 #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_MAX_ARRAY_SIZE #define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_MAX_ARRAY_SIZE 2147483639L #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_KEYS @@ -45,9 +45,9 @@ extern "C" { #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_ENTRIES #define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_ENTRIES 2L #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 4112578634029874840LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 4112578634029874840i64 #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID -4298000515446427739LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID -4298000515446427739i64 /* * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt * Method: setup @@ -206,7 +206,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurv extern "C" { #endif #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 1421746759512286392LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 1421746759512286392i64 #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_MAX_ARRAY_SIZE #define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_MAX_ARRAY_SIZE 2147483639L #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_KEYS @@ -216,9 +216,9 @@ extern "C" { #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_ENTRIES #define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_ENTRIES 2L #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 4112578634029874840LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 4112578634029874840i64 #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID -4298000515446427739LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID -4298000515446427739i64 /* * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan * Method: setup @@ -377,7 +377,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getC extern "C" { #endif #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID 1421746759512286392LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID 1421746759512286392i64 #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_MAX_ARRAY_SIZE #define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_MAX_ARRAY_SIZE 2147483639L #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_KEYS @@ -387,9 +387,9 @@ extern "C" { #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_ENTRIES #define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_ENTRIES 2L #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID 4112578634029874840LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID 4112578634029874840i64 #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID -4298000515446427739LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID -4298000515446427739i64 /* * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp * Method: setup @@ -548,7 +548,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getCu extern "C" { #endif #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID 1421746759512286392LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID 1421746759512286392i64 #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_MAX_ARRAY_SIZE #define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_MAX_ARRAY_SIZE 2147483639L #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_KEYS @@ -558,9 +558,9 @@ extern "C" { #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_ENTRIES #define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_ENTRIES 2L #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID 4112578634029874840LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID 4112578634029874840i64 #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -4298000515446427739LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -4298000515446427739i64 /* * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl * Method: setup @@ -719,7 +719,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getCurv extern "C" { #endif #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID 1421746759512286392LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID 1421746759512286392i64 #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_MAX_ARRAY_SIZE #define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_MAX_ARRAY_SIZE 2147483639L #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_KEYS @@ -729,9 +729,9 @@ extern "C" { #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_ENTRIES #define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_ENTRIES 2L #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID 4112578634029874840LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID 4112578634029874840i64 #undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID -#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID -4298000515446427739LL +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID -4298000515446427739i64 /* * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng * Method: setup @@ -838,18 +838,18 @@ extern "C" { /* * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Mscng * Method: sign - * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + * Signature: ([BLjava/security/interfaces/ECPrivateKey;Ljava/security/spec/ECParameterSpec;)[B */ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_sign - (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + (JNIEnv *, jobject, jbyteArray, jobject, jobject); /* * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Mscng * Method: verify - * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z + * Signature: ([B[BLjava/security/interfaces/ECPublicKey;Ljava/security/spec/ECParameterSpec;)Z */ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_verify - (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject); + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jobject); #ifdef __cplusplus } -- cgit v1.2.3-70-g09d2 From 8d21a87b25550215a4c59ff4ef8d32e2f0736b3f Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 29 Jul 2018 14:07:04 +0200 Subject: Update docs on Standalone testing. --- README.md | 78 ++++++++++++++-------- .../ectester/standalone/ECTesterStandalone.java | 2 +- 2 files changed, 53 insertions(+), 27 deletions(-) (limited to 'src/cz/crcs/ectester/standalone/ECTesterStandalone.java') diff --git a/README.md b/README.md index 7121027..b18ebbd 100644 --- a/README.md +++ b/README.md @@ -231,6 +231,11 @@ For more information on ECC libraries see [LIBS](docs/LIBS.md). ### Setup +OpenJDK JRE is required to test ECDH on Windows properly, as Oracle JRE requires the Java Cryptography Providers +for certain classes (such as a [KeyAgreement](https://docs.oracle.com/javase/8/docs/api/javax/crypto/KeyAgreement.html)) +to be signed by keys that are signed by their JCA Code Signing Authority. ECTester internally uses Java Cryptography Provider +API to expose and test native libraries. OpenJDK for Windows can be obtained from [ojdkbuild/ojdkbuild](https://github.com/ojdkbuild/ojdkbuild). + Installing the Java Cryptography Extension Unlimited Strength policy files is necessary to do testing with quite a lot of practical key sizes, they are available for download: @@ -243,49 +248,70 @@ To install, place them in `${java.home}/jre/lib/security/`. ### Options ``` -usage: ECTesterStandalone.jar [-V] [-h] [ (ecdh [-t ] [-n ] [-b ] [-nc ]) | -(ecdsa [-t ] [-n ] [-b ] [-nc ] [-f ]) | -(export [-t ] [-b ]) | (generate [-nc ] [-n ] [-t -] [-b ]) | (list-data [what]) | (list-libs) | (test [-gt ] -[-kt ] [-st ] [-b ] [-nc ]) ] [lib] - - -V,--version Print version info. - -h,--help Print help. - [lib] What library to use. - - ecdh: +usage: ECTesterStandalone.jar [-V] [-h] [-C] + [ (ecdh [-b ] [-nc ] [-cn ] [-t ] [--key-type ] [-n ]) | + (ecdsa [-b ] [-nc ] [-cn ] [-t ] [-n ] [-f ]) | + (export [-b ] [-t ]) | + (generate [-b ] [-nc ] [-cn ] [-n ] [-t ]) | + (list-data [what]) | + (list-libs) | + (list-suites) | + (test [-b ] [-nc ] [-cn ] [-gt ] [-kt ] [-st ] [-f ] [--key-type ] + ) ] + [lib] + + ecdh: | Perform EC based KeyAgreement. | + -b,--bits What size of curve to use. + -nc,--named-curve Use a named curve, from CurveDB: + -cn,--curve-name Use a named curve, search from curves + supported by the library: -t,--type Set KeyAgreement object [type]. + --key-type Set the key [algorithm] for which the key + should be derived in KeyAgreements with + KDF. Default is "AES". -n,--amount Do ECDH [amount] times. + + ecdsa: | Perform EC based Signature. | -b,--bits What size of curve to use. -nc,--named-curve Use a named curve, from CurveDB: - - ecdsa: + -cn,--curve-name Use a named curve, search from curves + supported by the library: -t,--type Set Signature object [type]. -n,--amount Do ECDSA [amount] times. - -b,--bits What size of curve to use. - -nc,--named-curve Use a named curve, from CurveDB: -f,--file Input [file] to sign. - export: - -t,--type Set KeyPair object [type]. - -b,--bits What size of curve to use. + export: | Export default curve parameters. | + -b,--bits What size of curve to use. + -t,--type Set KeyPair object [type]. - generate: + generate: | Generate EC keypairs. | + -b,--bits What size of curve to use. -nc,--named-curve Use a named curve, from CurveDB: + -cn,--curve-name Use a named curve, search from curves + supported by the library: -n,--amount Generate [amount] of EC keys. -t,--type Set KeyPairGenerator object [type]. - -b,--bits What size of curve to use. - list-data: - [what] what to list. + list-data: | List/show contained EC domain parameters/keys. | + [what] what to list. + + list-libs: | List supported libraries. | - list-libs: + list-suites: | List supported test suites. | - test: + test: | Test a library. | + -b,--bits What size of curve to use. + -nc,--named-curve Use a named curve, from CurveDB: + -cn,--curve-name Use a named curve, search from curves + supported by the library: -gt,--kpg-type Set the KeyPairGenerator object [type]. -kt,--ka-type Set the KeyAgreement object [type]. -st,--sig-type Set the Signature object [type]. - -b,--bits What size of curve to use. - -nc,--named-curve Use a named curve, from CurveDB: + -f,--format Set the output format, one of + text,yaml,xml. + --key-type Set the key [algorithm] for which the key + should be derived in KeyAgreements with + KDF. Default is "AES". + The test suite to run. ``` diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 2f132fa..31d291c 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -180,8 +180,8 @@ public class ECTesterStandalone { actions.put("generate", generate); Options exportOpts = new Options(); - exportOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPair object [type].").build()); exportOpts.addOption(bits); + 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); -- cgit v1.2.3-70-g09d2