summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2018-01-23 17:31:15 +0100
committerJ08nY2018-01-23 17:31:15 +0100
commitcb6c6b8b1274fe5a340c4317a4b015ea0ef15396 (patch)
tree864a54dcdf07da33cd139312c8b0ee693e1a0eff
parent6c46a27a52854aee24f7a37e74002bd6f4485723 (diff)
parentc581e39e539e6dadb49d9f83f563ab2b375f6e0b (diff)
downloadECTester-cb6c6b8b1274fe5a340c4317a4b015ea0ef15396.tar.gz
ECTester-cb6c6b8b1274fe5a340c4317a4b015ea0ef15396.tar.zst
ECTester-cb6c6b8b1274fe5a340c4317a4b015ea0ef15396.zip
-rw-r--r--!uploader/ectester.capbin16008 -> 0 bytes
-rw-r--r--!uploader/simpleECC_NXP_JCOP_CJ2A081.txt54
-rw-r--r--!uploader/simpleECC_test.txt27
-rw-r--r--!uploader/simpleECC_testDHSecret.txt23
-rw-r--r--!uploader/simpleECC_testECFull.txt12
-rw-r--r--!uploader/simpleECC_testSetParams.txt27
-rw-r--r--.gitignore14
-rw-r--r--.travis.yml28
-rw-r--r--LICENSE2
-rw-r--r--README.md155
-rw-r--r--applet/GPPcScConnectionPlugin.dll (renamed from !uploader/GPPcScConnectionPlugin.dll)bin15360 -> 15360 bytes
-rw-r--r--applet/GPShell.exe (renamed from !uploader/GPShell.exe)bin33280 -> 33280 bytes
-rw-r--r--applet/GlobalPlatform.dll (renamed from !uploader/GlobalPlatform.dll)bin117248 -> 117248 bytes
-rw-r--r--applet/gp.exe (renamed from !uploader/gp.exe)bin908346 -> 908346 bytes
-rw-r--r--applet/gp.jar (renamed from !uploader/gp.jar)bin894200 -> 894200 bytes
-rw-r--r--applet/gppro_upload.bat (renamed from !uploader/gppro_upload.bat)0
-rwxr-xr-xapplet/gppro_upload.sh (renamed from !uploader/gppro_upload.sh)0
-rw-r--r--applet/gppro_upload_emv.bat (renamed from !uploader/gppro_upload_emv.bat)0
-rwxr-xr-xapplet/gppro_upload_emv.sh (renamed from !uploader/gppro_upload_emv.sh)0
-rw-r--r--applet/libeay32.dll (renamed from !uploader/libeay32.dll)bin1017344 -> 1017344 bytes
-rw-r--r--applet/openkms-gp.jar (renamed from !uploader/openkms-gp.jar)bin78142 -> 78142 bytes
-rw-r--r--applet/ssleay32.dll (renamed from !uploader/ssleay32.dll)bin200704 -> 200704 bytes
-rw-r--r--applet/zlib1.dll (renamed from !uploader/zlib1.dll)bin75264 -> 75264 bytes
-rw-r--r--build-applet.xml32
-rw-r--r--build-reader.xml (renamed from build.xml)69
-rw-r--r--build-standalone.xml120
-rw-r--r--dist/README.TXT34
-rw-r--r--docs/CURVES.md40
-rw-r--r--docs/FORMAT.md30
-rw-r--r--docs/LIBS.md31
-rw-r--r--docs/TESTS.md20
-rw-r--r--jcbuild.xml31
-rw-r--r--lib/bcprov-jdk15on-1.58.jarbin0 -> 3955990 bytes
-rw-r--r--nbproject/copylibstask.jarbin22335 -> 11902 bytes
-rw-r--r--nbproject/dist-build.xml34
-rw-r--r--nbproject/reader/build-impl.xml (renamed from nbproject/build-impl.xml)4
-rw-r--r--nbproject/reader/manifest.mf (renamed from manifest.mf)2
-rw-r--r--nbproject/reader/project.properties (renamed from nbproject/project.properties)13
-rw-r--r--nbproject/reader/project.xml (renamed from nbproject/project.xml)2
-rw-r--r--nbproject/standalone/build-impl.xml1413
-rw-r--r--nbproject/standalone/manifest.mf4
-rw-r--r--nbproject/standalone/project.properties80
-rw-r--r--nbproject/standalone/project.xml15
-rw-r--r--src/cz/crcs/ectester/applet/ECKeyGenerator.java8
-rw-r--r--src/cz/crcs/ectester/applet/ECKeyTester.java202
-rw-r--r--src/cz/crcs/ectester/applet/ECTesterApplet.java206
-rw-r--r--src/cz/crcs/ectester/applet/EC_Consts.java30
-rw-r--r--src/cz/crcs/ectester/common/cli/Argument.java29
-rw-r--r--src/cz/crcs/ectester/common/cli/CLITools.java140
-rw-r--r--src/cz/crcs/ectester/common/cli/ParserOptions.java38
-rw-r--r--src/cz/crcs/ectester/common/cli/TreeCommandLine.java178
-rw-r--r--src/cz/crcs/ectester/common/cli/TreeParser.java128
-rw-r--r--src/cz/crcs/ectester/common/ec/EC_Category.java (renamed from src/cz/crcs/ectester/reader/ec/EC_Category.java)2
-rw-r--r--src/cz/crcs/ectester/common/ec/EC_Curve.java132
-rw-r--r--src/cz/crcs/ectester/common/ec/EC_Data.java (renamed from src/cz/crcs/ectester/reader/ec/EC_Data.java)41
-rw-r--r--src/cz/crcs/ectester/common/ec/EC_KAResult.java (renamed from src/cz/crcs/ectester/reader/ec/EC_KAResult.java)22
-rw-r--r--src/cz/crcs/ectester/common/ec/EC_Key.java (renamed from src/cz/crcs/ectester/reader/ec/EC_Key.java)2
-rw-r--r--src/cz/crcs/ectester/common/ec/EC_Keypair.java (renamed from src/cz/crcs/ectester/reader/ec/EC_Keypair.java)2
-rw-r--r--src/cz/crcs/ectester/common/ec/EC_Params.java (renamed from src/cz/crcs/ectester/reader/ec/EC_Params.java)69
-rw-r--r--src/cz/crcs/ectester/common/output/BaseTextTestWriter.java82
-rw-r--r--src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java103
-rw-r--r--src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java91
-rw-r--r--src/cz/crcs/ectester/common/output/OutputLogger.java (renamed from src/cz/crcs/ectester/reader/output/OutputLogger.java)2
-rw-r--r--src/cz/crcs/ectester/common/output/TeeOutputStream.java (renamed from src/cz/crcs/ectester/reader/output/TeeOutputStream.java)2
-rw-r--r--src/cz/crcs/ectester/common/output/TestWriter.java (renamed from src/cz/crcs/ectester/reader/output/TestWriter.java)6
-rw-r--r--src/cz/crcs/ectester/common/test/BaseTestable.java32
-rw-r--r--src/cz/crcs/ectester/common/test/CompoundTest.java111
-rw-r--r--src/cz/crcs/ectester/common/test/Result.java (renamed from src/cz/crcs/ectester/reader/test/Result.java)8
-rw-r--r--src/cz/crcs/ectester/common/test/SimpleTest.java19
-rw-r--r--src/cz/crcs/ectester/common/test/Test.java66
-rw-r--r--src/cz/crcs/ectester/common/test/TestCallback.java12
-rw-r--r--src/cz/crcs/ectester/common/test/TestException.java13
-rw-r--r--src/cz/crcs/ectester/common/test/TestSuite.java56
-rw-r--r--src/cz/crcs/ectester/common/test/Testable.java33
-rw-r--r--src/cz/crcs/ectester/common/util/ByteUtil.java128
-rw-r--r--src/cz/crcs/ectester/common/util/CardUtil.java272
-rw-r--r--src/cz/crcs/ectester/common/util/ECUtil.java172
-rw-r--r--src/cz/crcs/ectester/data/EC_Store.java37
-rw-r--r--src/cz/crcs/ectester/data/categories.xml10
-rw-r--r--src/cz/crcs/ectester/data/nist/b163.csv2
-rw-r--r--src/cz/crcs/ectester/data/nist/b233.csv2
-rw-r--r--src/cz/crcs/ectester/data/nist/b283.csv2
-rw-r--r--src/cz/crcs/ectester/data/nist/b409.csv10
-rw-r--r--src/cz/crcs/ectester/data/nist/b571.csv2
-rw-r--r--src/cz/crcs/ectester/data/nist/k163.csv2
-rw-r--r--src/cz/crcs/ectester/data/nist/k233.csv2
-rw-r--r--src/cz/crcs/ectester/data/nist/k283.csv2
-rw-r--r--src/cz/crcs/ectester/data/nist/k409.csv2
-rw-r--r--src/cz/crcs/ectester/data/nist/k571.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect163k1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect163r1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect163r2.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect233k1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect233r1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect239k1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect283k1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect283r1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect409k1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect409r1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect571k1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect571r1.csv2
-rw-r--r--src/cz/crcs/ectester/data/twist/keys.xml50
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/b163.xml37
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/b233.xml43
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/b283.xml43
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/k163.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/k233.xml37
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/k283.xml13
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/p192.xml19
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/p224.xml43
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/p256.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/p384.xml7
-rw-r--r--src/cz/crcs/ectester/data/twist/nist/p521.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp112r1.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp112r2.xml37
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp128r1.xml25
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp128r2.xml19
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp160k1.xml37
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp160r1.xml19
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp160r2.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp192k1.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp192r1.xml19
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp224r1.xml43
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp256k1.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp256r1.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp384r1.xml7
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/secp521r1.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/sect163k1.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/sect163r1.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/sect163r2.xml37
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/sect233k1.xml37
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/sect233r1.xml43
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/sect239k1.xml31
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/sect283k1.xml13
-rw-r--r--src/cz/crcs/ectester/data/twist/secg/sect283r1.xml43
-rw-r--r--src/cz/crcs/ectester/data/wrong/wrongt163.csv2
-rw-r--r--src/cz/crcs/ectester/data/wrong/wrongt233.csv2
-rw-r--r--src/cz/crcs/ectester/data/wrong/wrongt239.csv2
-rw-r--r--src/cz/crcs/ectester/data/wrong/wrongt283.csv2
-rw-r--r--src/cz/crcs/ectester/data/wrong/wrongt409.csv2
-rw-r--r--src/cz/crcs/ectester/data/wrong/wrongt571.csv2
-rw-r--r--src/cz/crcs/ectester/data/x962/curves.xml48
-rw-r--r--src/cz/crcs/ectester/data/x962/prime192v1.csv1
-rw-r--r--src/cz/crcs/ectester/data/x962/prime192v2.csv1
-rw-r--r--src/cz/crcs/ectester/data/x962/prime192v3.csv1
-rw-r--r--src/cz/crcs/ectester/data/x962/prime239v1.csv1
-rw-r--r--src/cz/crcs/ectester/data/x962/prime239v2.csv1
-rw-r--r--src/cz/crcs/ectester/data/x962/prime239v3.csv1
-rw-r--r--src/cz/crcs/ectester/data/x962/prime256v1.csv1
-rw-r--r--src/cz/crcs/ectester/reader/CardMngr.java179
-rw-r--r--src/cz/crcs/ectester/reader/ECTesterReader.java (renamed from src/cz/crcs/ectester/reader/ECTester.java)215
-rw-r--r--src/cz/crcs/ectester/reader/Util.java379
-rw-r--r--src/cz/crcs/ectester/reader/command/Command.java160
-rw-r--r--src/cz/crcs/ectester/reader/ec/EC_Curve.java52
-rw-r--r--src/cz/crcs/ectester/reader/output/ResponseWriter.java14
-rw-r--r--src/cz/crcs/ectester/reader/output/TextTestWriter.java102
-rw-r--r--src/cz/crcs/ectester/reader/output/XMLTestWriter.java131
-rw-r--r--src/cz/crcs/ectester/reader/output/YAMLTestWriter.java115
-rw-r--r--src/cz/crcs/ectester/reader/response/Response.java78
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java51
-rw-r--r--src/cz/crcs/ectester/reader/test/CardDefaultSuite.java94
-rw-r--r--src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java67
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTestSuite.java24
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java83
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java62
-rw-r--r--src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java58
-rw-r--r--src/cz/crcs/ectester/reader/test/CommandTest.java76
-rw-r--r--src/cz/crcs/ectester/reader/test/CommandTestable.java44
-rw-r--r--src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java53
-rw-r--r--src/cz/crcs/ectester/reader/test/DefaultSuite.java69
-rw-r--r--src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java68
-rw-r--r--src/cz/crcs/ectester/reader/test/PerformanceTest.java103
-rw-r--r--src/cz/crcs/ectester/reader/test/Test.java217
-rw-r--r--src/cz/crcs/ectester/reader/test/TestRunner.java29
-rw-r--r--src/cz/crcs/ectester/reader/test/TestSuite.java135
-rw-r--r--src/cz/crcs/ectester/reader/test/TestVectorSuite.java83
-rw-r--r--src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java34
-rw-r--r--src/cz/crcs/ectester/scripts/ectester.bat34
-rwxr-xr-xsrc/cz/crcs/ectester/scripts/ectester.sh48
-rw-r--r--src/cz/crcs/ectester/standalone/ECTesterStandalone.java525
-rw-r--r--src/cz/crcs/ectester/standalone/consts/Ident.java80
-rw-r--r--src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java68
-rw-r--r--src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java50
-rw-r--r--src/cz/crcs/ectester/standalone/consts/SignatureIdent.java109
-rw-r--r--src/cz/crcs/ectester/standalone/libs/BotanLib.java20
-rw-r--r--src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java28
-rw-r--r--src/cz/crcs/ectester/standalone/libs/ECLibrary.java26
-rw-r--r--src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java119
-rw-r--r--src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java93
-rw-r--r--src/cz/crcs/ectester/standalone/libs/SunECLib.java28
-rw-r--r--src/cz/crcs/ectester/standalone/libs/TomcryptLib.java20
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/Makefile70
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java68
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java69
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java137
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java123
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java42
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java227
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/botan.cpp631
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_utils.c66
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_utils.h28
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp59
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp29
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/native.h344
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c450
-rw-r--r--src/cz/crcs/ectester/standalone/output/TextTestWriter.java28
-rw-r--r--src/cz/crcs/ectester/standalone/output/XMLTestWriter.java119
-rw-r--r--src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java98
-rw-r--r--src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java57
-rw-r--r--src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java124
-rw-r--r--src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java42
-rw-r--r--src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java56
-rw-r--r--src/cz/crcs/ectester/standalone/test/SignatureTest.java42
-rw-r--r--src/cz/crcs/ectester/standalone/test/SignatureTestable.java107
-rw-r--r--src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java76
-rw-r--r--src/cz/crcs/ectester/standalone/test/StandaloneTestSuite.java23
-rwxr-xr-xutil/plot_dh.py69
-rwxr-xr-xutil/plot_gen.py93
218 files changed, 10864 insertions, 2398 deletions
diff --git a/!uploader/ectester.cap b/!uploader/ectester.cap
deleted file mode 100644
index b883965..0000000
--- a/!uploader/ectester.cap
+++ /dev/null
Binary files differ
diff --git a/!uploader/simpleECC_NXP_JCOP_CJ2A081.txt b/!uploader/simpleECC_NXP_JCOP_CJ2A081.txt
deleted file mode 100644
index bec8ef7..0000000
--- a/!uploader/simpleECC_NXP_JCOP_CJ2A081.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-# Usable for: NXP_JCOP_CJ2A081
-mode_211
-enable_trace
-establish_context
-card_connect
-select -AID a000000003000000
-open_sc -security 1 -keyind 0 -keyver 0 -mac_key 404142434445464748494a4b4c4d4e4f -enc_key 404142434445464748494a4b4c4d4e4f
-
-delete -AID 010203040506070809
-delete -AID 010203040506
-delete -AID e1e2e3e4e5e6e7e8e9
-delete -AID e1e2e3e4e5e6
-delete -AID d1d2d3d4d5d6d7d8d9
-delete -AID d1d2d3d4d5d6
-delete -AID d1d2d3d4d5
-delete -AID b1b2b3b4b5b6b7b8b9
-delete -AID b1b2b3b4b5b6
-delete -AID a1a2a3a4a5a6a7a8a9
-delete -AID a1a2a3a4a5a6
-delete -AID 6D7970616330303031
-delete -AID 6D797061636B616731
-delete -AID a1a2a3a4a5a6a7a8a9
-delete -AID F1F2F3F4F5F6F7F8F9
-delete -AID F1F2F3F4F5F6
-delete -AID 313233343536373839
-delete -AID 313233343536
-
-delete -AID 4c6162616b4170706c6574
-delete -AID 4c6162616b
-delete -AID 4C6162616B4170706C6574
-delete -AID 4C6162616B417070
-
-install -file simpleECC.cap -nvDataLimit 2000 -instParam 00a2a3a40002000000000000
-
-select -AID 4C6162616B4170706C6574
-
-send_apdu -APDU B05c0000020080
-
-send_apdu -APDU B05c00000200A0
-
-send_apdu -APDU B05c00000200c0
-
-send_apdu -APDU B05c0000020100
-
-
-
-
-send_apdu -APDU B05b0000
-
-send_apdu -APDU B05a0000
-
-
-card_disconnect
-release_context
diff --git a/!uploader/simpleECC_test.txt b/!uploader/simpleECC_test.txt
deleted file mode 100644
index 8139511..0000000
--- a/!uploader/simpleECC_test.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-mode_211
-enable_trace
-establish_context
-card_connect
-
-select -AID 4C6162616B4170706C6574
-
-send_apdu -APDU B05c0000020080
-send_apdu -APDU B05c0100020080
-
-send_apdu -APDU B05c00000200A0
-send_apdu -APDU B05c01000200A0
-
-send_apdu -APDU B05c00000200c0
-send_apdu -APDU B05c01000200c0
-
-send_apdu -APDU B05c0000020100
-send_apdu -APDU B05c0100020100
-
-
-send_apdu -APDU B05b0000
-
-send_apdu -APDU B05a0000
-
-
-card_disconnect
-release_context
diff --git a/!uploader/simpleECC_testDHSecret.txt b/!uploader/simpleECC_testDHSecret.txt
deleted file mode 100644
index eb6ab5f..0000000
--- a/!uploader/simpleECC_testDHSecret.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-mode_211
-enable_trace
-establish_context
-card_connect
-
-select -AID 4C6162616B4170706C6574
-
-send_apdu -APDU B05c01020200c0
-send_apdu -APDU B05d000000
-
-send_apdu -APDU B05d000031049d42769dfdbe113a851bb6b01b1a515d893b5adbc1f6132974749ac0967a8ff4cc54d93187602dd67eb3d22970aca2ca
-send_apdu -APDU B05d000031040178e496f67c822b0d33636bcb1e046f716d8d978d6e4cbc3bfef0789e5d3c42c43598d1b0cb44a654c79c21a6a3686a
-
-send_apdu -APDU B05d00003104e56ae9ef1f7d2a9dfdb6fd2906218138d72ef0a0ad1e8edd288e33450b0e723a3ab9c72a886360026f37482f86f56242
-
-
-
-send_apdu -APDU B05d00003104C9C0EDFB27B71EBE3093FC4F337638CEE02F78F63CEA902261328E9F038AFD60A0CE019B7634597964D7798E3B16D515
-send_apdu -APDU B05d00003104C9C0EDFB27B71EBE3113FC4F337638CEE02F78F63CEA902261328E9F038AFD60A0CE019B7634597964D7798E3B16D515
-
-
-card_disconnect
-release_context
diff --git a/!uploader/simpleECC_testECFull.txt b/!uploader/simpleECC_testECFull.txt
deleted file mode 100644
index acb4c4d..0000000
--- a/!uploader/simpleECC_testECFull.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-mode_211
-enable_trace
-establish_context
-card_connect
-
-select -AID 4C6162616B4170706C6574
-
-send_apdu -APDU B05e000000
-
-
-card_disconnect
-release_context
diff --git a/!uploader/simpleECC_testSetParams.txt b/!uploader/simpleECC_testSetParams.txt
deleted file mode 100644
index 09d967a..0000000
--- a/!uploader/simpleECC_testSetParams.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-mode_211
-enable_trace
-establish_context
-card_connect
-
-select -AID 4C6162616B4170706C6574
-send_apdu -APDU B05c0000020180
-
-send_apdu -APDU B05c0000020080
-send_apdu -APDU B05c0100020080
-send_apdu -APDU B05c0102020080
-
-send_apdu -APDU B05c00000200a0
-send_apdu -APDU B05c01000200a0
-send_apdu -APDU B05c01020200a0
-
-send_apdu -APDU B05c00000200c0
-send_apdu -APDU B05c01000200c0
-send_apdu -APDU B05c01020200c0
-
-send_apdu -APDU B05c0000020100
-send_apdu -APDU B05c0100020100
-send_apdu -APDU B05c0102020100
-
-
-card_disconnect
-release_context
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1953275
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+# Built artifacts in /dist and /applet.
+/dist/lib/
+/dist/ECTesterReader.jar
+/dist/ECTesterReader-dist.jar
+/dist/ectester-reader.sh
+/dist/ectester-reader.bat
+/dist/ECTesterStandalone.jar
+/dist/ECTesterStandalone-dist.jar
+/applet/ectester.cap
+
+# Built binaries in /src.
+/src/**/*.a
+/src/**/*.o
+/src/**/*.so
diff --git a/.travis.yml b/.travis.yml
index 3959c4d..62681d6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,17 +1,33 @@
+addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - libtomcrypt-dev
+ - libtommath-dev
+ - gcc-6
+ - g++-6
language: java
jdk:
-- oraclejdk8
+ - oraclejdk8
+env:
+ - CC=gcc-6 CXX=g++-6
+
script:
-- ant -f jcbuild.xml build
-- ant -f build.xml package
+ - ant -f build-applet.xml build
+ - ant -f build-reader.xml package
+ - ant -f build-standalone.xml package
+
deploy:
provider: releases
api_key:
secure: q2aJvu32K+nfbMR60nFCEkn+jYCKprlCRlIoPjuRz1HySX233Ccwpx1CAdNzEjY6FDFcoReKAg6r5vdPjJ4FRPAQ23TxffIYZPkykL5K/pUZJbM5xkazJY0Fp8i6Vyl0JfeanVib1PTyOSugplhCttFk5nb9JUFV36Tre66XntOl5y80Trn94F5aTlRjfW26UH65W7Aa6WZ0N4OX/ZsX+vEOJPAu+RLfOq9oBOx/loB8ntYM/e/6bEwJp6EedRQLDsiS4NavP3svH+GXsPLs5p3soyRXYsvvGKVnVjcjZURxDDdxv5YuCWUUfl9PbNB+Mqmx/HQxl50BKoKFqwap1+TnlbuTAiWaXeh3zdXuGB+TPg8KE8h6ueDneHd3Lpivgq79IvPWIH+N4b3Pa952+rD+JKBZ807efB+97OtWrkQL7/sLZESQUdIszE724HHOiArKpNajIX+kN6NJdul5xFCiQQHG+O7iDFQBavCGM9fk63mZRyGPxZQzS06BV2vIIHg0yx3igN+OKKMFCH+P3hYR1zL6o65OlgbL1ifTZ18GDvmVRNdi53/fxQ2n/mQmI4tQpn4ZB7Ddoxx4GlpjFjzdKk/P9nKwng0M9wrp8row/vb5S+1aPwSxp9/4ASP9dkvLcNjTkWhmGPrWe+82Y9JPK47uesx0YeaVI2C7IR0=
file:
- - "dist/ECTester-dist.jar"
- - "dist/ECTester.jar"
- - "!uploader/ectester.cap"
+ - "dist/ECTesterReader-dist.jar"
+ - "dist/ECTesterReader.jar"
+ - "applet/ectester.cap"
+ - "dist/ECTesterStandalone-dist.jar"
+ - "dist/ECTesterStandalone.jar"
skip_cleanup: true
on:
tags: true
diff --git a/LICENSE b/LICENSE
index a8fc851..21ecc94 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2016
+Copyright (c) 2016-2017
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/README.md b/README.md
index 5096bd3..6184b84 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,23 @@
# ECTester
+[![Build status](https://api.travis-ci.org/crocs-muni/ECTester.svg?branch=master)](https://travis-ci.org/crocs-muni/ECTester) [![GitHub release](https://img.shields.io/github/release/crocs-muni/ECTEster.svg)](https://github.com/crocs-muni/ECTester/releases) [![license](https://img.shields.io/github/license/crocs-muni/ECTester.svg)](https://github.com/crocs-muni/ECTester/blob/master/LICENSE)
-Tests support and behavior of smartcards with JavaCard platform with focus on Eliptic curves (`TYPE_EC_FP` and `TYPE_EC_F2M`).
+Tests support and behavior of elliptic curve cryptography implementations on JavaCards (`TYPE_EC_FP` and `TYPE_EC_F2M`) and on selected software libraries.
## Build
-ECTester uses ant.
+ECTester uses ant. There are three parts of ECTester, the JavaCard applet used for testing, the reader app which controls it and the standalone app which tests software libraries.
```bash
-ant package # To build the reader tool (jar).
-ant -f jcbuild.xml build # To build the applet (cap).
+ant -f build-reader.xml package # To build the reader tool (jar) -> "dist/ECTesterReader.jar"
+ant -f build-standalone.xml package # To build the standalone tool (jar) -> "dist/ECTesterStandalone.jar"
+ant -f build-applet.xml build # To build the applet (cap) -> "applet/ectester.cap".
```
+Build produces both a lightweight version of the JARs and a full version of the JARs with dependencies included, the latter has the `*-dist.jar` suffix.
+The standalone build tries building test binaries for all the supported libraries, and silently fails if the library is not properly supported.
-## Usage
+## JavaCard testing
1. Upload `!uploader/ectester.cap` using your favorite tool (e.g., [GlobalPlatformPro tool](https://github.com/martinpaljak/GlobalPlatform))
-2. Run `java -jar dist/ECTester.jar -t -a`
+2. Run `java -jar dist/ECTesterReader.jar -t -a`
3. Inspect output log with annotated results
Following operations are tested:
@@ -24,25 +28,33 @@ Following operations are tested:
- Signature via ECDSA
- Behavior of card when invalid curves/points are provided (should fail)
-See `java -jar ECTester.jar -h` for more.
+See `java -jar ECTesterReader.jar -h` for more.
### Options
```
- -ln,--list-named <what> Print the list of supported named
- curves and keys.
-dsa,--ecdsa <count> Sign data with ECDSA, [count] times.
- -t,--test <test_case> Test ECC support.
- -dh,--ecdh <count> Do ECDH, [count] times.
+ -t,--test <test_suite> Test ECC support. [test_suite]:
+ - default:
+ - invalid:
+ - wrong:
+ - composite:
+ - test-vectors:
+ -dh,--ecdh <count> Do EC KeyAgreement (ECDH...), [count]
+ times.
-e,--export Export the defaut curve parameters of
the card(if any).
- -g,--generate <amount> Generate [amount] of EC keys.
+ -V,--version Print version info.
+ -ln,--list-named <what> Print the list of supported named
+ curves and keys.
-h,--help Print help.
- -dhc,--ecdhc <count> Do ECDHC, [count] times.
+
-a,--all Test all curve sizes.
-b,--bit-size <bits> Set curve size.
+
-fp,--prime-field Use a prime field.
-f2m,--binary-field Use a binary field.
+
-c,--curve <curve_file> Use curve from file <curve_file>
(field,a,b,gx,gy,r,k).
-nc,--named-curve <cat/id> Use a named curve, from CurveDB:
@@ -58,20 +70,25 @@ See `java -jar ECTester.jar -h` for more.
-k,--key <key_file> Use keyPair from file <key_file>
(wx,wy,s).
-nk,--named-key <cat/id> Use keyPair from KeyDB: <cat/id>
+
-i,--input <input_file> Input from file <input_file>, for ECDSA
signing.
-o,--output <output_file> Output into file <output_file>.
-l,--log <log_file> Log output into file [log_file].
-v,--verbose Turn on verbose logging.
- --format <format> Output format to use.
+ --format <format> Output format to use. One of:
+ text,yml,xml.
-f,--fresh Generate fresh keys (set domain
parameters before every generation).
-s,--simulate Simulate a card with jcardsim instead
of using a terminal.
-y,--yes Accept all warnings and prompts.
+
-ka,--ka-type <type> Set KeyAgreement object [type],
corresponds to JC.KeyAgreement
- constants.
+ constants.
+ -sig,--sig-type <type> Set Signature object [type],
+ corresponds to JC.Signature constants.
```
### Actions
@@ -98,10 +115,10 @@ Use with `-o / --output [out_file]` to output the generated keys to a file.
#### ECDH
`-dh / --ecdh [count]`
-`-dhc / --ecdhc [count]`
Performs ECDH.
Use with `-o / --output [out_file]` to output into a file.
+Respects the KeyAgreement type specified in `-ka / --ka-type [type]`.
#### ECDSA
`-dsa / --ecdsa [count]`
@@ -109,6 +126,7 @@ Use with `-o / --output [out_file]` to output into a file.
Performs ECDSA.
Useful with `-i / --input [in_file]` to sign the contents of a file.
Use with `-o / --output [out_file]` to output into a file.
+Respects the Signature type specified in `-sig / --sig-type [type]`.
#### List named curves
`-ln / --list-named []`
@@ -125,27 +143,92 @@ For more info about the curves see [CURVES](docs/CURVES.md).
### Example
-
- ### Test for support and with valid and invalid EC curves
- EC type: ALG_EC_FP
- EC key length (bits): 256 bits
- KeyPair object allocation: OK (0x9000)
- Generate key with def curve (fails if no def): OK (0x9000)
- Set valid custom curve: OK (0x9000)
- Generate key with valid curve: OK (0x9000)
- !! ECDH agreement with valid point: fail (unknown, 0x6f00)
- ECDH agreement with invalid point (fail is good): fail (ILLEGAL_VALUE, 0x 1)
- ECDSA signature on random data: OK (0x9000)
- Set anomalous custom curve (may fail): OK (0x9000)
- Generate key with anomalous curve (may fail): fail (unknown, 0x6f00)
- ECDH agreement with small order point (fail is good):fail (skipped, 0x ee1)
- Set invalid custom curve (may fail): OK (0x9000)
- Generate key with invalid curve (fail is good): fail (unknown, 0x6f00)
- Set invalid field (may fail): OK (0x9000)
- Generate key with invalid field (fail si good): fail (unknown, 0x6f00)
-
-*Explanation: ALG_EC_FP with 256b curve was tested. Is supported by card (KeyPair object allocation: OK), don't have preset default curve (Generate key with def curve: fail), custom curve can be set (Set valid custom curve: OK), new keypair can be generated (Generate key with valid curve: OK), ECDH key agreement failed to execute (ECDH agreement with valid point: fail) although it was supposed to succeed (log line is therefore marked with !!), ECDH wil fail (expected behavior) if invalid point is provided (ECDH agreement with invalid point: fail), ECDSA signature worked and verified correctly (ECDSA signature on random data: OK), anomalous curve can be set (Set anomalous custom curve: OK), however generating a key on it will fail (Generate key with anomalous curve: fail), ECDH with small-order public key provided will fail as intended (ECDH agreement with small order point: fail), invalid custom curve could be set (Set invalid custom curve: OK), new keypair cannot be generated with invalid curve (Generate key with invalid curve: fail), invalid field (non-prime) could be set (Set invalid field: OK), however a key could not be generated (Generate key with invalid field: fail).*
+ > java -jar ECTesterReader.jar -t -a -s
+ ═══ Running test suite: default ═══
+ ═══ The default test suite run basic support of ECDH and ECDSA.
+ ═══ Card ATR: 3bfa1800008131fe454a434f5033315632333298
+ NOK ┳ Tests of 112b ALG_EC_FP support. Some. ┃ FAILURE ┃ Some sub-tests did not have the expected result.
+ ┣ OK ━ Allocated both keypairs 112b ALG_EC_FP ┃ SUCCESS ┃ 50 ms ┃ OK (0x9000) OK (0x9000)
+ ┣ OK ━ Generated both keypairs ┃ SUCCESS ┃ 37 ms ┃ OK (0x9000) OK (0x9000)
+ ┣ OK ━ Set custom curve parameters on both keypairs ┃ SUCCESS ┃ 0 ms ┃ OK (0x9000) OK (0x9000)
+ ┣ OK ━ Generated both keypairs ┃ SUCCESS ┃ 16 ms ┃ OK (0x9000) OK (0x9000)
+ ┣ OK ┳ Test of the ALG_EC_SVDP_DH KeyAgreement. ┃ SUCCESS ┃ All sub-tests had the expected result.
+ ┃ ┣ OK ━ Allocated KeyAgreement(ALG_EC_SVDP_DH) object ┃ SUCCESS ┃ 2 ms ┃ OK (0x9000)
+ ┃ ┣ OK ━ ALG_EC_SVDP_DH of local pubkey and remote privkey(unchanged point) ┃ SUCCESS ┃ 7 ms ┃ OK (0x9000)
+ ┃ ┗ OK ━ ALG_EC_SVDP_DH of local pubkey and remote privkey(COMPRESSED point) ┃ SUCCESS ┃ 14 ms ┃ OK (0x9000)
+ ┣ OK ┳ Test of the ALG_EC_SVDP_DHC KeyAgreement. ┃ SUCCESS ┃ All sub-tests had the expected result.
+ ┃ ┣ OK ━ Allocated KeyAgreement(ALG_EC_SVDP_DHC) object ┃ SUCCESS ┃ 0 ms ┃ OK (0x9000)
+ ┃ ┣ OK ━ ALG_EC_SVDP_DHC of local pubkey and remote privkey(unchanged point) ┃ SUCCESS ┃ 3 ms ┃ OK (0x9000)
+ ┃ ┗ OK ━ ALG_EC_SVDP_DHC of local pubkey and remote privkey(COMPRESSED point) ┃ SUCCESS ┃ 5 ms ┃ OK (0x9000)
+ ┣ NOK ━ Allocated KeyAgreement(ALG_EC_SVDP_DH_PLAIN) object ┃ FAILURE ┃ 0 ms ┃ fail (NO_SUCH_ALG, 0x0003)
+ ┣ NOK ━ Allocated KeyAgreement(ALG_EC_SVDP_DHC_PLAIN) object ┃ FAILURE ┃ 0 ms ┃ fail (NO_SUCH_ALG, 0x0003)
+ ┣ NOK ━ Allocated KeyAgreement(ALG_EC_PACE_GM) object ┃ FAILURE ┃ 0 ms ┃ fail (NO_SUCH_ALG, 0x0003)
+ ┣ NOK ━ Allocated KeyAgreement(ALG_EC_SVDP_DH_PLAIN_XY) object ┃ FAILURE ┃ 0 ms ┃ fail (NO_SUCH_ALG, 0x0003)
+ ┣ OK ┳ Test of the ALG_ECDSA_SHA signature. ┃ SUCCESS ┃ All sub-tests had the expected result.
+ ┃ ┣ OK ━ Allocated Signature(ALG_ECDSA_SHA) object ┃ SUCCESS ┃ 7 ms ┃ OK (0x9000)
+ ┃ ┗ OK ━ ALG_ECDSA_SHA with local keypair(random data) ┃ SUCCESS ┃ 43 ms ┃ OK (0x9000)
+ ┣ NOK ━ Allocated Signature(ALG_ECDSA_SHA_224) object ┃ FAILURE ┃ 0 ms ┃ fail (NO_SUCH_ALG, 0x0003)
+ ┣ NOK ━ Allocated Signature(ALG_ECDSA_SHA_256) object ┃ FAILURE ┃ 0 ms ┃ fail (NO_SUCH_ALG, 0x0003)
+ ┣ NOK ━ Allocated Signature(ALG_ECDSA_SHA_384) object ┃ FAILURE ┃ 0 ms ┃ fail (NO_SUCH_ALG, 0x0003)
+ ┗ NOK ━ Allocated Signature(ALG_ECDSA_SHA_512) object ┃ FAILURE ┃ 0 ms ┃ fail (NO_SUCH_ALG, 0x0003)
If you are interested in testing support for other JavaCard algorithms, please visit JCAlgTester project: https://github.com/crocs-muni/JCAlgTest
+
+## Standalone library testing
+
+Currently supported libraries include:
+ - BouncyCastle
+ - SunEC
+ - libtomcrypt
+ - botan
+
+
+```
+usage: ECTesterStandalone.jar [-V] [-h] [ (ecdh [-t <type>] [-n <amount>] [-b <n>] [-nc <cat/id>]) |
+(ecdsa [-t <type>] [-n <amount>] [-b <n>] [-nc <cat/id>] [-f <file>]) |
+(export [-t <type>] [-b <n>]) | (generate [-nc <cat/id>] [-n <amount>] [-t
+<type>] [-b <n>]) | (list-data [what]) | (list-libs) | (test [-gt <type>]
+[-kt <type>] [-st <type>] [-b <n>] [-nc <cat/id>]) ] [lib]
+
+ -V,--version Print version info.
+ -h,--help Print help.
+ [lib] What library to use.
+
+ ecdh:
+ -t,--type <type> Set KeyAgreement object [type].
+ -n,--amount <amount> Do ECDH [amount] times.
+ -b,--bits <n> What size of curve to use.
+ -nc,--named-curve <cat/id> Use a named curve, from CurveDB: <cat/id>
+
+ ecdsa:
+ -t,--type <type> Set Signature object [type].
+ -n,--amount <amount> Do ECDSA [amount] times.
+ -b,--bits <n> What size of curve to use.
+ -nc,--named-curve <cat/id> Use a named curve, from CurveDB: <cat/id>
+ -f,--file <file> Input [file] to sign.
+
+ export:
+ -t,--type <type> Set KeyPair object [type].
+ -b,--bits <n> What size of curve to use.
+
+ generate:
+ -nc,--named-curve <cat/id> Use a named curve, from CurveDB: <cat/id>
+ -n,--amount <amount> Generate [amount] of EC keys.
+ -t,--type <type> Set KeyPairGenerator object [type].
+ -b,--bits <n> What size of curve to use.
+
+ list-data:
+ [what] what to list.
+
+ list-libs:
+
+ test:
+ -gt,--kpg-type <type> Set the KeyPairGenerator object [type].
+ -kt,--ka-type <type> Set the KeyAgreement object [type].
+ -st,--sig-type <type> Set the Signature object [type].
+ -b,--bits <n> What size of curve to use.
+ -nc,--named-curve <cat/id> Use a named curve, from CurveDB: <cat/id>
+
+``` \ No newline at end of file
diff --git a/!uploader/GPPcScConnectionPlugin.dll b/applet/GPPcScConnectionPlugin.dll
index 3b27f6b..3b27f6b 100644
--- a/!uploader/GPPcScConnectionPlugin.dll
+++ b/applet/GPPcScConnectionPlugin.dll
Binary files differ
diff --git a/!uploader/GPShell.exe b/applet/GPShell.exe
index 091eece..091eece 100644
--- a/!uploader/GPShell.exe
+++ b/applet/GPShell.exe
Binary files differ
diff --git a/!uploader/GlobalPlatform.dll b/applet/GlobalPlatform.dll
index 6dca172..6dca172 100644
--- a/!uploader/GlobalPlatform.dll
+++ b/applet/GlobalPlatform.dll
Binary files differ
diff --git a/!uploader/gp.exe b/applet/gp.exe
index 6478bf2..6478bf2 100644
--- a/!uploader/gp.exe
+++ b/applet/gp.exe
Binary files differ
diff --git a/!uploader/gp.jar b/applet/gp.jar
index 774d81a..774d81a 100644
--- a/!uploader/gp.jar
+++ b/applet/gp.jar
Binary files differ
diff --git a/!uploader/gppro_upload.bat b/applet/gppro_upload.bat
index cbfd5ae..cbfd5ae 100644
--- a/!uploader/gppro_upload.bat
+++ b/applet/gppro_upload.bat
diff --git a/!uploader/gppro_upload.sh b/applet/gppro_upload.sh
index a94a948..a94a948 100755
--- a/!uploader/gppro_upload.sh
+++ b/applet/gppro_upload.sh
diff --git a/!uploader/gppro_upload_emv.bat b/applet/gppro_upload_emv.bat
index 737f8ac..737f8ac 100644
--- a/!uploader/gppro_upload_emv.bat
+++ b/applet/gppro_upload_emv.bat
diff --git a/!uploader/gppro_upload_emv.sh b/applet/gppro_upload_emv.sh
index c3b42b1..c3b42b1 100755
--- a/!uploader/gppro_upload_emv.sh
+++ b/applet/gppro_upload_emv.sh
diff --git a/!uploader/libeay32.dll b/applet/libeay32.dll
index b59a6b4..b59a6b4 100644
--- a/!uploader/libeay32.dll
+++ b/applet/libeay32.dll
Binary files differ
diff --git a/!uploader/openkms-gp.jar b/applet/openkms-gp.jar
index 9cd5de5..9cd5de5 100644
--- a/!uploader/openkms-gp.jar
+++ b/applet/openkms-gp.jar
Binary files differ
diff --git a/!uploader/ssleay32.dll b/applet/ssleay32.dll
index e8fabb6..e8fabb6 100644
--- a/!uploader/ssleay32.dll
+++ b/applet/ssleay32.dll
Binary files differ
diff --git a/!uploader/zlib1.dll b/applet/zlib1.dll
index 31996cd..31996cd 100644
--- a/!uploader/zlib1.dll
+++ b/applet/zlib1.dll
Binary files differ
diff --git a/build-applet.xml b/build-applet.xml
new file mode 100644
index 0000000..9d7d4d6
--- /dev/null
+++ b/build-applet.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project basedir="." default="build" name="ECTesterApplet">
+ <!-- Based on Martin Paljak's applets playground -->
+ <!-- Applet building dependencies -->
+ <property name="JC222" value="ext/java_card_kit-2_2_2"/>
+ <property name="JC221" value="ext/java_card_kit-2_2_1"/>
+ <property name="JC303" value="ext/java_card_kit-3_0_3"/>
+ <property name="OP20" value="ext/visa_openplatform-2_0"/>
+ <property name="GP211" value="ext/globalplatform-2_1_1"/>
+
+ <!-- ant-javacard task from javacard.pro -->
+ <taskdef name="javacard" classname="pro.javacard.ant.JavaCard" classpath="ext/ant-javacard.jar"/>
+
+ <target name="build" description="Builds the CAP file.">
+ <javacard jckit="${JC222}">
+ <cap output="applet/ectester.cap" sources="src/cz/crcs/ectester/applet" aid="4543546573746572">
+ <applet class="cz.crcs.ectester.applet.ECTesterApplet" aid="45435465737465723031"/>
+ </cap>
+ </javacard>
+ </target>
+
+ <target name="upload" depends="build" description="Uploads the CAP file to the card, using gp.jar">
+ <exec dir="applet" executable="./gppro_upload.sh" osfamily="unix"/>
+ <exec dir="applet" executable="./gppro_upload.bat" osfamily="windows"/>
+ </target>
+
+ <target name="upload-emv" depends="build"
+ description="Uploads the CAP file to the card, using gp.jar, uses the EMV protocol">
+ <exec dir="applet" executable="./gppro_upload_emv.sh" osfamily="unix"/>
+ <exec dir="applet" executable="./gppro_upload_emv.bat" osfamily="windows"/>
+ </target>
+</project>
diff --git a/build.xml b/build-reader.xml
index 3d778f3..11d6145 100644
--- a/build.xml
+++ b/build-reader.xml
@@ -7,9 +7,10 @@
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
-<project name="ECTester" default="default" basedir=".">
- <description>Builds, tests, and runs the project ECTester.</description>
- <import file="nbproject/build-impl.xml"/>
+<project name="ECTesterReader" default="default" basedir=".">
+ <description>Builds, tests, and runs the project ECTesterReader.</description>
+ <import file="nbproject/reader/build-impl.xml"/>
+ <import file="nbproject/dist-build.xml"/>
<!--
There exist several targets which are by default empty and which can be
@@ -70,61 +71,19 @@
nbproject/build-impl.xml file.
-->
- <!--
- <path id="classpath">
- <fileset dir="lib" includes="**/*.jar"/>
- </path>
-
- <target name="clean">
- <delete file="dist/ECTester.jar"/>
- </target>
- <target name="build">
- <javac srcdir="src" destdir="dist/production/ECTester" classpathref="classpath" excludes="**/SimpleAPDU.java"/>
- </target>
- <target name="jar" depends="build">
- <jar destfile="dist/ECTester.jar">
- <fileset dir="dist/production/ECTester"/>
- <fileset dir="dist/data"/>
- <manifest>
- <attribute name="Main-Class" value="ECTester"/>
- <attribute name="Class-Path" value="lib/jcardsim-2.2.2-all.jar lib/commons-cli-1.3.1.jar"/>
- </manifest>
- </jar>
+ <target name="-pre-jar">
+ <copy file="LICENSE" todir="${build.classes.dir}"/>
</target>
- -->
+
+ <!--
<target name="-post-jar">
- <copy file="src/cz/crcs/ectester/scripts/ectester.sh" todir="${dist.dir}"/>
- <copy file="src/cz/crcs/ectester/scripts/ectester.bat" todir="${dist.dir}"/>
+ <copy file="src/cz/crcs/ectester/scripts/ectester-reader.sh" todir="${dist.dir}"/>
+ <copy file="src/cz/crcs/ectester/scripts/ectester-reader.bat" todir="${dist.dir}"/>
</target>
- <target name="package" depends="jar">
- <property name="store.jar.name" value="ECTester-dist"/>
- <property name="store.dir" value="dist"/>
- <property name="store.jar" value="${store.dir}/${store.jar.name}.jar"/>
-
- <echo message="Packaging ${application.title} into a single JAR at ${store.jar}"/>
-
- <tempfile property="temp.file" destDir="${java.io.tmpdir}" suffix=".jar"/>
- <tempfile property="temp.previous_jar" destdir="${java.io.tmpdir}" suffix=".jar"/>
-
- <copy file="${store.jar}" tofile="${temp.previous_jar}" failonerror="false"/>
- <echo message="Backed up ${store.jar} into ${temp.previous_jar}"/>
-
- <delete file="${store.jar}" failonerror="false"/>
- <jar destfile="${temp.file}" filesetmanifest="skip">
- <zipgroupfileset dir="dist" includes="*.jar"/>
- <zipgroupfileset dir="dist/lib" includes="*.jar"/>
-
- <manifest>
- <attribute name="Main-Class" value="${main.class}"/>
- </manifest>
- </jar>
-
- <zip destfile="${store.jar}">
- <zipfileset src="${temp.file}"
- excludes="META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA"/>
- </zip>
+ -->
- <delete file="${temp.file}"/>
- <delete file="${temp.previous_jar}"/>
+ <target name="package" depends="jar">
+ <property name="store.jar.name" value="ECTesterReader-dist"/>
+ <antcall target="dist-build.package"/>
</target>
</project>
diff --git a/build-standalone.xml b/build-standalone.xml
new file mode 100644
index 0000000..dcfb1f3
--- /dev/null
+++ b/build-standalone.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="ECTesterStandalone" default="default" basedir=".">
+ <description>Builds, tests, and runs the project ECTesterStandalone.</description>
+ <import file="nbproject/standalone/build-impl.xml"/>
+ <import file="nbproject/dist-build.xml"/>
+ <!--
+
+ There exist several targets which are by default empty and which can be
+ used for execution of your tasks. These targets are usually executed
+ before and after some main targets. They are:
+
+ -pre-init: called before initialization of project properties
+ -post-init: called after initialization of project properties
+ -pre-compile: called before javac compilation
+ -post-compile: called after javac compilation
+ -pre-compile-single: called before javac compilation of single file
+ -post-compile-single: called after javac compilation of single file
+ -pre-compile-test: called before javac compilation of JUnit tests
+ -post-compile-test: called after javac compilation of JUnit tests
+ -pre-compile-test-single: called before javac compilation of single JUnit test
+ -post-compile-test-single: called after javac compilation of single JUunit test
+ -pre-jar: called before JAR building
+ -post-jar: called after JAR building
+ -post-clean: called after cleaning build products
+
+ (Targets beginning with '-' are not intended to be called on their own.)
+
+ Example of inserting an obfuscator after compilation could look like this:
+
+ <target name="-post-compile">
+ <obfuscate>
+ <fileset dir="${build.classes.dir}"/>
+ </obfuscate>
+ </target>
+
+ For list of available properties check the imported
+ nbproject/build-impl.xml file.
+
+
+ Another way to customize the build is by overriding existing main targets.
+ The targets of interest are:
+
+ -init-macrodef-javac: defines macro for javac compilation
+ -init-macrodef-junit: defines macro for junit execution
+ -init-macrodef-debug: defines macro for class debugging
+ -init-macrodef-java: defines macro for class execution
+ -do-jar: JAR building
+ run: execution of project
+ -javadoc-build: Javadoc generation
+ test-report: JUnit report generation
+
+ An example of overriding the target for project execution could look like this:
+
+ <target name="run" depends="SimpleECC-impl.jar">
+ <exec dir="bin" executable="launcher.exe">
+ <arg file="${dist.jar}"/>
+ </exec>
+ </target>
+
+ Notice that the overridden target depends on the jar target and not only on
+ the compile target as the regular run target does. Again, for a list of available
+ properties which you can use, check the target you are overriding in the
+ nbproject/build-impl.xml file.
+
+ -->
+ <target name="-pre-jar">
+ <copy file="LICENSE" todir="${build.classes.dir}"/>
+ </target>
+
+ <target name="package" depends="jar">
+ <property name="store.jar.name" value="ECTesterStandalone-dist"/>
+ <antcall target="dist-build.package"/>
+ </target>
+
+ <target name="libs-try">
+ <exec dir="src/cz/crcs/ectester/standalone/libs/jni" executable="make" osfamily="unix">
+ <arg value="-k"/>
+ </exec>
+ </target>
+ <target name="libs">
+ <exec dir="src/cz/crcs/ectester/standalone/libs/jni" failonerror="true" executable="make" osfamily="unix">
+ <arg value="-k"/>
+ </exec>
+ </target>
+
+ <target name="-post-compile" depends="libs-try"/>
+ <target name="-post-clean">
+ <exec dir="src/cz/crcs/ectester/standalone/libs/jni" failonerror="true" executable="make"
+ osfamily="unix">
+ <arg value="clean"/>
+ </exec>
+ </target>
+
+ <target name="headers" depends="compile">
+ <javah classpath="${build.classes.dir}" outputfile="src/cz/crcs/ectester/standalone/libs/jni/native.h">
+ <class name="cz.crcs.ectester.standalone.libs.TomcryptLib"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeProvider$TomCrypt"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$TomCrypt"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeECPublicKey$TomCrypt"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeECPrivateKey$TomCrypt"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$TomCrypt"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$TomCryptRaw"/>
+ <class name="cz.crcs.ectester.standalone.libs.BotanLib"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeProvider$Botan"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$Botan"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeECPublicKey$Botan"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeECPrivateKey$Botan"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$Botan"/>
+ <class name="cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$Botan"/>
+ </javah>
+ </target>
+</project>
diff --git a/dist/README.TXT b/dist/README.TXT
index 5d6fa17..64c76a6 100644
--- a/dist/README.TXT
+++ b/dist/README.TXT
@@ -2,31 +2,15 @@
BUILD OUTPUT DESCRIPTION
========================
-When you build an Java application project that has a main class, the IDE
-automatically copies all of the JAR
-files on the projects classpath to your projects dist/lib folder. The IDE
-also adds each of the JAR files to the Class-Path element in the application
-JAR files manifest file (MANIFEST.MF).
+After building (with package target) this directory should contain the files:
-To run the project from the command line, go to the dist folder and
-type the following:
+- ECTesterReader.jar
+- ECTesterReader-dist.jar
+- ECTesterStandalone.jar
+- ECTesterStandalone-dist.jar
+- ectester-reader.sh
+- ectester-reader.bat
-java -jar "ECTester.jar"
+The *-dist.jar variants of JAR files are self-contained executable JAR files with
+all the dependencies inside them.
-To distribute this project, zip up the dist folder (including the lib folder)
-and distribute the ZIP file.
-
-Notes:
-
-* If two JAR files on the project classpath have the same name, only the first
-JAR file is copied to the lib folder.
-* Only JAR files are copied to the lib folder.
-If the classpath contains other types of files or folders, these files (folders)
-are not copied.
-* If a library on the projects classpath also has a Class-Path element
-specified in the manifest,the content of the Class-Path element has to be on
-the projects runtime path.
-* To set a main class in a standard Java project, right-click the project node
-in the Projects window and choose Properties. Then click Run and enter the
-class name in the Main Class field. Alternatively, you can manually type the
-class name in the manifest Main-Class element.
diff --git a/docs/CURVES.md b/docs/CURVES.md
index d1749df..4a80d49 100644
--- a/docs/CURVES.md
+++ b/docs/CURVES.md
@@ -1,15 +1,47 @@
# Curves
-## anomalous
+## SECG
+SEC 2: Recommended Elliptic Curve Domain Parameters version 2.0 January 27, 2010
+
+[Source](http://www.secg.org/sec2-v2.pdf)
+
+## NIST
+RECOMMENDED ELLIPTIC CURVES FOR FEDERAL GOVERNMENT USE July 1999
+
+[Source](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf)
+
+## x962
+ANSI X9.62 example curves.
## Brainpool
+ECC Brainpool Standard Curves and Curve Generation v. 1.0 19.10.2005
+
+[Source](http://www.ecc-brainpool.org/download/Domain-parameters.pdf)
+
+## anssi
+Agence nationale de la sécurité des systèmes d'information: Publication d'un paramétrage de courbe elliptique visant des applications de passeport électronique et de l'administration électronique française. 21 November 2011
+
+## GOST
+GOST R 34.10-2001: RFC5832 curves.
+
+[Source](https://tools.ietf.org/html/rfc5832)
+
+## anomalous
+These prime field curves have the same order as the field order, and are susceptible to attacks reducing ECDLP over a multiplicative group of the curve, to DLP over an additive group of the underlying field, which is easy (linear time).
+
+Some of these are from Atsuko Miyaji's [paper](https://dspace.jaist.ac.jp/dspace/bitstream/10119/4464/1/73-61.pdf), others were generated using [ecgen](htps://github.com/J08nY/ecgen).
## invalid
+This category contains pre-generated invalid curves for a large subset of NIST, SECG and Brainpool curves. Invalid curves for a given curve, are short Weierstrass curves with all parameters equal to the given curve except the `b` parameter. These curves can be used to [attack some implementations](https://www.nds.rub.de/media/nds/veroeffentlichungen/2015/09/14/main-full.pdf).
-## NIST
+Generated using [ecgen](https://github.com/J08nY/ecgen)
-## nonprime
+## composite
+Contains curves of composite order, with small order points.
-## SECG
+Generated using [ecgen](https://github.com/J08nY/ecgen)
## wrong
+Contains parameters that are not elliptic curves(over Fp and F2m), such as `p` parameter that is not prime, irreducible polynomial that is not irreducible and similar.
+
+Generated manually. \ No newline at end of file
diff --git a/docs/FORMAT.md b/docs/FORMAT.md
index b68db39..849a62c 100644
--- a/docs/FORMAT.md
+++ b/docs/FORMAT.md
@@ -1,7 +1,10 @@
# Format
-CSV based, little-endian hexadecimal values.
+ECTester mostly reads/outputs data in either human-readable format or using CSV.
## Curves
+Input files for the `-c/--curve` option should be in CSV, little-endian hexadecimal format.
+Output of the `-e/--export` option will also be in this format.
+
### Prime field
`p,a,b,gx,gy,n,h`
@@ -9,6 +12,8 @@ CSV based, little-endian hexadecimal values.
`m,e1,e2,e3,a,b,gx,gy,n,h`
## Key material
+Input files for the `-k/--key`, `-pub/--public` and `-priv/--private` options should be in CSV, little-endian hexadecimal format.
+
### Keypair
`wx,wy,s`
@@ -18,7 +23,7 @@ CSV based, little-endian hexadecimal values.
### Private key
`s`
-# Notation
+### Notation
- `p` - prime F_p
- `m` - binary field exponent F_2^m
- `e1` - largest exponent of the field polynomial
@@ -32,4 +37,23 @@ CSV based, little-endian hexadecimal values.
- `h` - the base-point cofactor
- `wx` - the x coordinate of the public key
- `wy` - the y coordinate of th public key
- - `s` - the private key value \ No newline at end of file
+ - `s` - the private key value
+
+## Key generation output(CSV)
+Output of the `-g/--generate` option.
+
+`index;time;pubW;privS`
+
+## KeyAgreement output(CSV)
+Output of the `-dh/--ecdh` option.
+
+`index;time;pubW;privS;secret`
+
+## Signature output(CSV)
+Output of the `-dsa/--ecdsa` option.
+
+`index;time;signature`
+
+## Test runs
+By default test runs are output in a human readable format, however YAML and XML is also supported and can be selected
+by using the `-o/--output` option.
diff --git a/docs/LIBS.md b/docs/LIBS.md
new file mode 100644
index 0000000..4fac57b
--- /dev/null
+++ b/docs/LIBS.md
@@ -0,0 +1,31 @@
+# Libraries with ECC
+
+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/)
+ - [OpenSSL](https://www.openssl.org/)
+ - [OpenSSL (FIPS mode)](https://www.openssl.org/docs/fipsnotes.html)
+
+ - [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)
+
+# Supported libraries
+
+ - [BouncyCastle](https://bouncycastle.org/java.html)
+ - Java
+ - [Sun EC](https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SunEC)
+ - Java + C
+ - [Botan](https://botan.randombit.net/), since 2.4.0 (unreleased)
+ - C++
+ - Uses blinded(randomized) Montgomery ladder.
+ - https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
+ - https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-1986-cc
+ - https://eprint.iacr.org/2015/657
+ - [libtomcrypt](http://www.libtom.net/LibTomCrypt/)
+ - C
+ - Uses Jacobian coordinates.
+ - Sliding window scalar multiplication algorithm. \ No newline at end of file
diff --git a/docs/TESTS.md b/docs/TESTS.md
index 21298dc..c4f38dc 100644
--- a/docs/TESTS.md
+++ b/docs/TESTS.md
@@ -11,29 +11,21 @@ confirmation before running, be cautious.**
## Default
Tests the default curves present on the card. These might not be present or the card might not even support ECC.
-Tests keypair allocation, generation, ECDH and ECDSA. ECDH is first tested with two valid generated keypairs, then a with a
-public key that is corrupted in various ways, these tests should fail.
+Tests keypair allocation, generation, ECDH and ECDSA. ECDH is first tested with two valid generated keypairs, then
+with a compressed public key to test support for compressed points.
This test suite is run if no argument is provided to `-t / --test`.
-Supports the `-nc / --named-curve` option so you can specify a category of curves or a curve to use if the card doesn't
-have default curves preset.
-
For example:
```bash
-java -jar ECTester.jar -nc secg -a -fp -t
-```
-tests all(`-a`), prime field(`-fp`) SECG curves, using the default test suite.
-
-```bash
-java -jar ECTester.jar -u -a -f2m -t
+java -jar ECTester.jar -a -fp -t
```
-tests all(`-a`), binary field(`-f2m`), custom(`-u`) curves.
+tests all(`-a`), prime field(`-fp`), using the default test suite.
```bash
-java -jar ECTester.jar -b 128 -fp -t
+java -jar ECTester.jar-a -f2m -t
```
-tests a 128 bit(`-b`), prime field(`-fp`) curve, (if a default one is present).
+tests all(`-a`), binary field(`-f2m`), curves.
## Test-Vectors
Tests using known test vectors provided by NIST/SECG/Brainpool:
diff --git a/jcbuild.xml b/jcbuild.xml
deleted file mode 100644
index 793060c..0000000
--- a/jcbuild.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project basedir="." default="build" name="ECTesterApplet">
- <!-- Based on Martin Paljak's applets playground -->
- <!-- Applet building dependencies -->
- <property name="JC222" value="ext/java_card_kit-2_2_2"/>
- <property name="JC221" value="ext/java_card_kit-2_2_1"/>
- <property name="JC303" value="ext/java_card_kit-3_0_3"/>
- <property name="OP20" value="ext/visa_openplatform-2_0"/>
- <property name="GP211" value="ext/globalplatform-2_1_1"/>
-
- <!-- ant-javacard task from javacard.pro -->
- <taskdef name="javacard" classname="pro.javacard.ant.JavaCard" classpath="ext/ant-javacard.jar"/>
-
- <target name="build" description="Builds the CAP file.">
- <javacard jckit="${JC222}">
- <cap output="!uploader/ectester.cap" sources="src/cz/crcs/ectester/applet" aid="4543546573746572" >
- <applet class="cz.crcs.ectester.applet.ECTesterApplet" aid="45435465737465723031"/>
- </cap>
- </javacard>
- </target>
-
- <target name="upload" depends="build" description="Uploads the CAP file to the card, using gp.jar">
- <exec dir="!uploader" executable="./gppro_upload.sh" osfamily="unix"/>
- <exec dir="!uploader" executable="./gppro_upload.bat" osfamily="windows"/>
- </target>
-
- <target name="upload-emv" depends="build" description="Uploads the CAP file to the card, using gp.jar, uses the EMV protocol">
- <exec dir="!uploader" executable="./gppro_upload_emv.sh" osfamily="unix"/>
- <exec dir="!uploader" executable="./gppro_upload_emv.bat" osfamily="windows"/>
- </target>
-</project>
diff --git a/lib/bcprov-jdk15on-1.58.jar b/lib/bcprov-jdk15on-1.58.jar
new file mode 100644
index 0000000..dae02cb
--- /dev/null
+++ b/lib/bcprov-jdk15on-1.58.jar
Binary files differ
diff --git a/nbproject/copylibstask.jar b/nbproject/copylibstask.jar
index ad1d2ac..45fdbe1 100644
--- a/nbproject/copylibstask.jar
+++ b/nbproject/copylibstask.jar
Binary files differ
diff --git a/nbproject/dist-build.xml b/nbproject/dist-build.xml
new file mode 100644
index 0000000..b980e2d
--- /dev/null
+++ b/nbproject/dist-build.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="dist-build">
+ <description>.</description>
+ <target name="package">
+ <property name="store.dir" value="dist"/>
+ <property name="store.jar" value="${store.dir}/${store.jar.name}.jar"/>
+
+ <echo message="Packaging ${application.title} into a single JAR at ${store.jar}"/>
+
+ <tempfile property="temp.file" destDir="${java.io.tmpdir}" suffix=".jar"/>
+ <tempfile property="temp.previous_jar" destdir="${java.io.tmpdir}" suffix=".jar"/>
+
+ <copy file="${store.jar}" tofile="${temp.previous_jar}" failonerror="false"/>
+ <echo message="Backed up ${store.jar} into ${temp.previous_jar}"/>
+
+ <delete file="${store.jar}" failonerror="false"/>
+ <jar destfile="${temp.file}" filesetmanifest="skip">
+ <zipgroupfileset dir="dist" includes="*.jar"/>
+ <zipgroupfileset dir="dist/lib" includes="*.jar"/>
+
+ <manifest>
+ <attribute name="Main-Class" value="${main.class}"/>
+ </manifest>
+ </jar>
+
+ <zip destfile="${store.jar}">
+ <zipfileset src="${temp.file}"
+ excludes="META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA"/>
+ </zip>
+
+ <delete file="${temp.file}"/>
+ <delete file="${temp.previous_jar}"/>
+ </target>
+</project> \ No newline at end of file
diff --git a/nbproject/build-impl.xml b/nbproject/reader/build-impl.xml
index 3b01c7f..f7c43a2 100644
--- a/nbproject/build-impl.xml
+++ b/nbproject/reader/build-impl.xml
@@ -19,7 +19,7 @@ is divided into following sections:
- cleanup
-->
-<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="ECTester-impl">
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir="../../../" default="default" name="ECTesterReader-impl">
<fail message="Please build using Ant 1.8.0 or higher.">
<condition>
<not>
@@ -51,7 +51,7 @@ is divided into following sections:
</target>
<target depends="-pre-init,-init-private,-init-user" name="-init-project">
<property file="nbproject/configs/${config}.properties"/>
- <property file="nbproject/project.properties"/>
+ <property file="nbproject/reader/project.properties"/>
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
<property name="platform.java" value="${java.home}/bin/java"/>
diff --git a/manifest.mf b/nbproject/reader/manifest.mf
index 2cb1a50..cbfea93 100644
--- a/manifest.mf
+++ b/nbproject/reader/manifest.mf
@@ -1,4 +1,4 @@
Manifest-Version: 1.0
Class-Path: lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.3.1.jar lib/snakeyaml-1.19.jar
-Main-Class: cz.crcs.ectester.reader.ECTester
+Main-Class: cz.crcs.ectester.reader.ECTesterReader
diff --git a/nbproject/project.properties b/nbproject/reader/project.properties
index 152dc9c..69db523 100644
--- a/nbproject/project.properties
+++ b/nbproject/reader/project.properties
@@ -3,10 +3,10 @@ annotation.processing.enabled.in.editor=false
annotation.processing.processors.list=
annotation.processing.run.all.processors=true
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
-application.title=ECTester
+application.title=ECTesterReader
application.vendor=xsvenda
build.classes.dir=${build.dir}/classes
-build.classes.excludes=**/*.java,**/*.form
+build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.h,**/*.a,**/*.o,**/Makefile
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
@@ -25,14 +25,15 @@ debug.test.classpath=\
dist.archive.excludes=
# This directory is removed when the project is cleaned:
dist.dir=dist
-dist.jar=${dist.dir}/ECTester.jar
+dist.jar=${dist.dir}/ECTesterReader.jar
dist.javadoc.dir=${dist.dir}/javadoc
libs.CopyLibs.classpath=nbproject/copylibstask.jar
endorsed.classpath=
excludes=
-includes=**
+includes=**/applet/**,**/common/**,**/data/**,**/reader/**
jar.compress=false
javac.classpath=\
+ lib/bcprov-jdk15on-1.58.jar:\
lib/jcardsim-3.0.4-SNAPSHOT.jar:\
lib/commons-cli-1.3.1.jar:\
lib/snakeyaml-1.19.jar
@@ -59,8 +60,8 @@ javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
-main.class=cz.crcs.ectester.reader.ECTester
-manifest.file=manifest.mf
+main.class=cz.crcs.ectester.reader.ECTesterReader
+manifest.file=nbproject/reader/manifest.mf
meta.inf.dir=${src.dir}/META-INF
mkdist.disabled=false
platform.active=default_platform
diff --git a/nbproject/project.xml b/nbproject/reader/project.xml
index 6e5a48e..aebe217 100644
--- a/nbproject/project.xml
+++ b/nbproject/reader/project.xml
@@ -3,7 +3,7 @@
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
- <name>ECTester</name>
+ <name>ECTesterReader</name>
<source-roots>
<root id="src.dir"/>
</source-roots>
diff --git a/nbproject/standalone/build-impl.xml b/nbproject/standalone/build-impl.xml
new file mode 100644
index 0000000..a1f91c2
--- /dev/null
+++ b/nbproject/standalone/build-impl.xml
@@ -0,0 +1,1413 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT ***
+*** EDIT ../build.xml INSTEAD ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+ - initialization
+ - compilation
+ - jar
+ - execution
+ - debugging
+ - javadoc
+ - test compilation
+ - test execution
+ - test debugging
+ - applet
+ - cleanup
+
+ -->
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir="../../../" default="default" name="ECTesterStandalone-impl">
+ <fail message="Please build using Ant 1.8.0 or higher.">
+ <condition>
+ <not>
+ <antversion atleast="1.8.0"/>
+ </not>
+ </condition>
+ </fail>
+ <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+ <!--
+ ======================
+ INITIALIZATION SECTION
+ ======================
+ -->
+ <target name="-pre-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="-pre-init" name="-init-private">
+ <property file="nbproject/private/config.properties"/>
+ <property file="nbproject/private/configs/${config}.properties"/>
+ <property file="nbproject/private/private.properties"/>
+ </target>
+ <target depends="-pre-init,-init-private" name="-init-user">
+ <property file="${user.properties.file}"/>
+ <!-- The two properties below are usually overridden -->
+ <!-- by the active platform. Just a fallback. -->
+ <property name="default.javac.source" value="1.4"/>
+ <property name="default.javac.target" value="1.4"/>
+ </target>
+ <target depends="-pre-init,-init-private,-init-user" name="-init-project">
+ <property file="nbproject/configs/${config}.properties"/>
+ <property file="nbproject/standalone/project.properties"/>
+ </target>
+ <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+ <property name="platform.java" value="${java.home}/bin/java"/>
+ <available file="${manifest.file}" property="manifest.available"/>
+ <condition property="splashscreen.available">
+ <and>
+ <not>
+ <equals arg1="${application.splash}" arg2="" trim="true"/>
+ </not>
+ <available file="${application.splash}"/>
+ </and>
+ </condition>
+ <condition property="main.class.available">
+ <and>
+ <isset property="main.class"/>
+ <not>
+ <equals arg1="${main.class}" arg2="" trim="true"/>
+ </not>
+ </and>
+ </condition>
+ <condition property="profile.available">
+ <and>
+ <isset property="javac.profile"/>
+ <length length="0" string="${javac.profile}" when="greater"/>
+ <matches pattern="1\.[89](\..*)?" string="${javac.source}"/>
+ </and>
+ </condition>
+ <condition property="do.archive">
+ <or>
+ <not>
+ <istrue value="${jar.archive.disabled}"/>
+ </not>
+ <istrue value="${not.archive.disabled}"/>
+ </or>
+ </condition>
+ <condition property="do.mkdist">
+ <and>
+ <isset property="do.archive"/>
+ <isset property="libs.CopyLibs.classpath"/>
+ <not>
+ <istrue value="${mkdist.disabled}"/>
+ </not>
+ </and>
+ </condition>
+ <condition property="do.archive+manifest.available">
+ <and>
+ <isset property="manifest.available"/>
+ <istrue value="${do.archive}"/>
+ </and>
+ </condition>
+ <condition property="do.archive+main.class.available">
+ <and>
+ <isset property="main.class.available"/>
+ <istrue value="${do.archive}"/>
+ </and>
+ </condition>
+ <condition property="do.archive+splashscreen.available">
+ <and>
+ <isset property="splashscreen.available"/>
+ <istrue value="${do.archive}"/>
+ </and>
+ </condition>
+ <condition property="do.archive+profile.available">
+ <and>
+ <isset property="profile.available"/>
+ <istrue value="${do.archive}"/>
+ </and>
+ </condition>
+ <condition property="have.tests">
+ <or>
+ <available file="${test.src.dir}"/>
+ </or>
+ </condition>
+ <condition property="have.sources">
+ <or>
+ <available file="${src.dir}"/>
+ </or>
+ </condition>
+ <condition property="netbeans.home+have.tests">
+ <and>
+ <isset property="netbeans.home"/>
+ <isset property="have.tests"/>
+ </and>
+ </condition>
+ <condition property="no.javadoc.preview">
+ <and>
+ <isset property="javadoc.preview"/>
+ <isfalse value="${javadoc.preview}"/>
+ </and>
+ </condition>
+ <property name="run.jvmargs" value=""/>
+ <property name="run.jvmargs.ide" value=""/>
+ <property name="javac.compilerargs" value=""/>
+ <property name="work.dir" value="${basedir}"/>
+ <condition property="no.deps">
+ <and>
+ <istrue value="${no.dependencies}"/>
+ </and>
+ </condition>
+ <property name="javac.debug" value="true"/>
+ <property name="javadoc.preview" value="true"/>
+ <property name="application.args" value=""/>
+ <property name="source.encoding" value="${file.encoding}"/>
+ <property name="runtime.encoding" value="${source.encoding}"/>
+ <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+ <and>
+ <isset property="javadoc.encoding"/>
+ <not>
+ <equals arg1="${javadoc.encoding}" arg2=""/>
+ </not>
+ </and>
+ </condition>
+ <property name="javadoc.encoding.used" value="${source.encoding}"/>
+ <property name="includes" value="**"/>
+ <property name="excludes" value=""/>
+ <property name="do.depend" value="false"/>
+ <condition property="do.depend.true">
+ <istrue value="${do.depend}"/>
+ </condition>
+ <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+ <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+ <and>
+ <isset property="endorsed.classpath"/>
+ <not>
+ <equals arg1="${endorsed.classpath}" arg2="" trim="true"/>
+ </not>
+ </and>
+ </condition>
+ <condition else="" property="javac.profile.cmd.line.arg" value="-profile ${javac.profile}">
+ <isset property="profile.available"/>
+ </condition>
+ <condition else="false" property="jdkBug6558476">
+ <and>
+ <matches pattern="1\.[56]" string="${java.specification.version}"/>
+ <not>
+ <os family="unix"/>
+ </not>
+ </and>
+ </condition>
+ <property name="javac.fork" value="${jdkBug6558476}"/>
+ <property name="jar.index" value="false"/>
+ <property name="jar.index.metainf" value="${jar.index}"/>
+ <property name="copylibs.rebase" value="true"/>
+ <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
+ <condition property="junit.available">
+ <or>
+ <available classname="org.junit.Test" classpath="${run.test.classpath}"/>
+ <available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
+ </or>
+ </condition>
+ <condition property="testng.available">
+ <available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
+ </condition>
+ <condition property="junit+testng.available">
+ <and>
+ <istrue value="${junit.available}"/>
+ <istrue value="${testng.available}"/>
+ </and>
+ </condition>
+ <condition else="testng" property="testng.mode" value="mixed">
+ <istrue value="${junit+testng.available}"/>
+ </condition>
+ <condition else="" property="testng.debug.mode" value="-mixed">
+ <istrue value="${junit+testng.available}"/>
+ </condition>
+ </target>
+ <target name="-post-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+ <fail unless="src.dir">Must set src.dir</fail>
+ <fail unless="test.src.dir">Must set test.src.dir</fail>
+ <fail unless="build.dir">Must set build.dir</fail>
+ <fail unless="dist.dir">Must set dist.dir</fail>
+ <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+ <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+ <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+ <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+ <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+ <fail unless="dist.jar">Must set dist.jar</fail>
+ </target>
+ <target name="-init-macrodef-property">
+ <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+ <attribute name="name"/>
+ <attribute name="value"/>
+ <sequential>
+ <property name="@{name}" value="${@{value}}"/>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
+ <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${src.dir}" name="srcdir"/>
+ <attribute default="${build.classes.dir}" name="destdir"/>
+ <attribute default="${javac.classpath}" name="classpath"/>
+ <attribute default="${javac.processorpath}" name="processorpath"/>
+ <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="${javac.debug}" name="debug"/>
+ <attribute default="${empty.dir}" name="sourcepath"/>
+ <attribute default="${empty.dir}" name="gensrcdir"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property location="${build.dir}/empty" name="empty.dir"/>
+ <mkdir dir="${empty.dir}"/>
+ <mkdir dir="@{apgeneratedsrcdir}"/>
+ <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+ <src>
+ <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+ <include name="*"/>
+ </dirset>
+ </src>
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <compilerarg line="${javac.profile.cmd.line.arg}"/>
+ <compilerarg line="${javac.compilerargs}"/>
+ <compilerarg value="-processorpath"/>
+ <compilerarg path="@{processorpath}:${empty.dir}"/>
+ <compilerarg line="${ap.processors.internal}"/>
+ <compilerarg line="${annotation.processing.processor.options}"/>
+ <compilerarg value="-s"/>
+ <compilerarg path="@{apgeneratedsrcdir}"/>
+ <compilerarg line="${ap.proc.none.internal}"/>
+ <customize/>
+ </javac>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
+ <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${src.dir}" name="srcdir"/>
+ <attribute default="${build.classes.dir}" name="destdir"/>
+ <attribute default="${javac.classpath}" name="classpath"/>
+ <attribute default="${javac.processorpath}" name="processorpath"/>
+ <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="${javac.debug}" name="debug"/>
+ <attribute default="${empty.dir}" name="sourcepath"/>
+ <attribute default="${empty.dir}" name="gensrcdir"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property location="${build.dir}/empty" name="empty.dir"/>
+ <mkdir dir="${empty.dir}"/>
+ <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+ <src>
+ <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+ <include name="*"/>
+ </dirset>
+ </src>
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <compilerarg line="${javac.profile.cmd.line.arg}"/>
+ <compilerarg line="${javac.compilerargs}"/>
+ <customize/>
+ </javac>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
+ <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${src.dir}" name="srcdir"/>
+ <attribute default="${build.classes.dir}" name="destdir"/>
+ <attribute default="${javac.classpath}" name="classpath"/>
+ <sequential>
+ <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ </depend>
+ </sequential>
+ </macrodef>
+ <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${build.classes.dir}" name="destdir"/>
+ <sequential>
+ <fail unless="javac.includes">Must set javac.includes</fail>
+ <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
+ <path>
+ <filelist dir="@{destdir}" files="${javac.includes}"/>
+ </path>
+ <globmapper from="*.java" to="*.class"/>
+ </pathconvert>
+ <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
+ <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
+ <delete>
+ <files includesfile="${javac.includesfile.binary}"/>
+ </delete>
+ <delete>
+ <fileset file="${javac.includesfile.binary}"/>
+ </delete>
+ </sequential>
+ </macrodef>
+ </target>
+ <target if="${junit.available}" name="-init-macrodef-junit-init">
+ <condition else="false" property="nb.junit.batch" value="true">
+ <and>
+ <istrue value="${junit.available}"/>
+ <not>
+ <isset property="test.method"/>
+ </not>
+ </and>
+ </condition>
+ <condition else="false" property="nb.junit.single" value="true">
+ <and>
+ <istrue value="${junit.available}"/>
+ <isset property="test.method"/>
+ </and>
+ </condition>
+ </target>
+ <target name="-init-test-properties">
+ <property name="test.binaryincludes" value="&lt;nothing&gt;"/>
+ <property name="test.binarytestincludes" value=""/>
+ <property name="test.binaryexcludes" value=""/>
+ </target>
+ <target if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
+ <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property name="junit.forkmode" value="perTest"/>
+ <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+ <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ <jvmarg value="-ea"/>
+ <customize/>
+ </junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
+ <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property name="junit.forkmode" value="perTest"/>
+ <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+ <batchtest todir="${build.test.results.dir}">
+ <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+ <filename name="@{testincludes}"/>
+ </fileset>
+ <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+ <filename name="${test.binarytestincludes}"/>
+ </fileset>
+ </batchtest>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ <jvmarg value="-ea"/>
+ <customize/>
+ </junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
+ <target if="${testng.available}" name="-init-macrodef-testng">
+ <macrodef name="testng" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
+ <isset property="test.method"/>
+ </condition>
+ <union id="test.set">
+ <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
+ <filename name="@{testincludes}"/>
+ </fileset>
+ </union>
+ <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
+ <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="ECTester" testname="TestNG tests" workingDir="${work.dir}">
+ <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
+ <propertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </propertyset>
+ <customize/>
+ </testng>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-macrodef-test-impl">
+ <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <echo>No tests executed.</echo>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
+ <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <j2seproject3:junit excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize/>
+ </j2seproject3:junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
+ <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <j2seproject3:testng excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize/>
+ </j2seproject3:testng>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
+ <macrodef name="test" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <sequential>
+ <j2seproject3:test-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ </customize>
+ </j2seproject3:test-impl>
+ </sequential>
+ </macrodef>
+ </target>
+ <target if="${junit.available}" name="-init-macrodef-junit-debug" unless="${nb.junit.batch}">
+ <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property name="junit.forkmode" value="perTest"/>
+ <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+ <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ <jvmarg value="-ea"/>
+ <jvmarg line="${debug-args-line}"/>
+ <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+ <customize/>
+ </junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-debug-batch">
+ <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property name="junit.forkmode" value="perTest"/>
+ <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+ <batchtest todir="${build.test.results.dir}">
+ <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+ <filename name="@{testincludes}"/>
+ </fileset>
+ <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+ <filename name="${test.binarytestincludes}"/>
+ </fileset>
+ </batchtest>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ <jvmarg value="-ea"/>
+ <jvmarg line="${debug-args-line}"/>
+ <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+ <customize/>
+ </junit>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit-debug,-init-macrodef-junit-debug-batch" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
+ <macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <element implicit="true" name="customize" optional="true"/>
+ <sequential>
+ <j2seproject3:junit-debug excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize/>
+ </j2seproject3:junit-debug>
+ </sequential>
+ </macrodef>
+ </target>
+ <target if="${testng.available}" name="-init-macrodef-testng-debug">
+ <macrodef name="testng-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <element name="customize2" optional="true"/>
+ <sequential>
+ <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
+ <isset property="test.method"/>
+ </condition>
+ <condition else="-suitename ECTester -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+ <matches pattern=".*\.xml" string="@{testClass}"/>
+ </condition>
+ <delete dir="${build.test.results.dir}" quiet="true"/>
+ <mkdir dir="${build.test.results.dir}"/>
+ <j2seproject3:debug classname="org.testng.TestNG" classpath="${debug.test.classpath}">
+ <customize>
+ <customize2/>
+ <jvmarg value="-ea"/>
+ <arg line="${testng.debug.mode}"/>
+ <arg line="-d ${build.test.results.dir}"/>
+ <arg line="-listener org.testng.reporters.VerboseReporter"/>
+ <arg line="${testng.cmd.args}"/>
+ </customize>
+ </j2seproject3:debug>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
+ <macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <element implicit="true" name="customize2" optional="true"/>
+ <sequential>
+ <j2seproject3:testng-debug testClass="@{testClass}" testMethod="@{testMethod}">
+ <customize2/>
+ </j2seproject3:testng-debug>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
+ <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <sequential>
+ <j2seproject3:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+ <customize>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ </customize>
+ </j2seproject3:test-debug-impl>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
+ <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${includes}" name="includes"/>
+ <attribute default="${excludes}" name="excludes"/>
+ <attribute default="**" name="testincludes"/>
+ <attribute default="" name="testmethods"/>
+ <attribute default="${main.class}" name="testClass"/>
+ <attribute default="" name="testMethod"/>
+ <sequential>
+ <j2seproject3:testng-debug-impl testClass="@{testClass}" testMethod="@{testMethod}">
+ <customize2>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ </customize2>
+ </j2seproject3:testng-debug-impl>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
+ <!--
+ pre NB7.2 profiling section; consider it deprecated
+ -->
+ <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
+ <target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="profiler.info.jvmargs.agent" name="-profile-post-init">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="profiler.info.jvmargs.agent" name="-profile-init-macrodef-profile">
+ <macrodef name="resolve">
+ <attribute name="name"/>
+ <attribute name="value"/>
+ <sequential>
+ <property name="@{name}" value="${env.@{value}}"/>
+ </sequential>
+ </macrodef>
+ <macrodef name="profile">
+ <attribute default="${main.class}" name="classname"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property environment="env"/>
+ <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
+ <java classname="@{classname}" dir="${profiler.info.dir}" fork="true" jvm="${profiler.info.jvm}">
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg value="${profiler.info.jvmargs.agent}"/>
+ <jvmarg line="${profiler.info.jvmargs}"/>
+ <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+ <arg line="${application.args}"/>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ <syspropertyset>
+ <propertyref prefix="run-sys-prop."/>
+ <mapper from="run-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <customize/>
+ </java>
+ </sequential>
+ </macrodef>
+ </target>
+ <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" if="profiler.info.jvmargs.agent" name="-profile-init-check">
+ <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
+ <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
+ </target>
+ <!--
+ end of pre NB7.2 profiling section
+ -->
+ <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+ <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+ <attribute default="${main.class}" name="name"/>
+ <attribute default="${debug.classpath}" name="classpath"/>
+ <attribute default="" name="stopclassname"/>
+ <sequential>
+ <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ </nbjpdastart>
+ </sequential>
+ </macrodef>
+ <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+ <attribute default="${build.classes.dir}" name="dir"/>
+ <sequential>
+ <nbjpdareload>
+ <fileset dir="@{dir}" includes="${fix.classes}">
+ <include name="${fix.includes}*.class"/>
+ </fileset>
+ </nbjpdareload>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-debug-args">
+ <property name="version-output" value="java version &quot;${ant.java.version}"/>
+ <condition property="have-jdk-older-than-1.4">
+ <or>
+ <contains string="${version-output}" substring="java version &quot;1.0"/>
+ <contains string="${version-output}" substring="java version &quot;1.1"/>
+ <contains string="${version-output}" substring="java version &quot;1.2"/>
+ <contains string="${version-output}" substring="java version &quot;1.3"/>
+ </or>
+ </condition>
+ <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+ <istrue value="${have-jdk-older-than-1.4}"/>
+ </condition>
+ <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+ <os family="windows"/>
+ </condition>
+ <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+ <isset property="debug.transport"/>
+ </condition>
+ </target>
+ <target depends="-init-debug-args" name="-init-macrodef-debug">
+ <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${main.class}" name="classname"/>
+ <attribute default="${debug.classpath}" name="classpath"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <java classname="@{classname}" dir="${work.dir}" fork="true">
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg line="${debug-args-line}"/>
+ <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+ <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+ <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ <syspropertyset>
+ <propertyref prefix="run-sys-prop."/>
+ <mapper from="run-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <customize/>
+ </java>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-macrodef-java">
+ <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+ <attribute default="${main.class}" name="classname"/>
+ <attribute default="${run.classpath}" name="classpath"/>
+ <attribute default="jvm" name="jvm"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <java classname="@{classname}" dir="${work.dir}" fork="true">
+ <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+ <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+ <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+ <jvmarg line="${run.jvmargs}"/>
+ <jvmarg line="${run.jvmargs.ide}"/>
+ <classpath>
+ <path path="@{classpath}"/>
+ </classpath>
+ <syspropertyset>
+ <propertyref prefix="run-sys-prop."/>
+ <mapper from="run-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <customize/>
+ </java>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-macrodef-copylibs">
+ <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+ <attribute default="${manifest.file}" name="manifest"/>
+ <element name="customize" optional="true"/>
+ <sequential>
+ <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+ <pathconvert property="run.classpath.without.build.classes.dir">
+ <path path="${run.classpath}"/>
+ <map from="${build.classes.dir.resolved}" to=""/>
+ </pathconvert>
+ <pathconvert pathsep=" " property="jar.classpath">
+ <path path="${run.classpath.without.build.classes.dir}"/>
+ <chainedmapper>
+ <flattenmapper/>
+ <filtermapper>
+ <replacestring from=" " to="%20"/>
+ </filtermapper>
+ <globmapper from="*" to="lib/*"/>
+ </chainedmapper>
+ </pathconvert>
+ <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+ <copylibs compress="${jar.compress}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+ <fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
+ <manifest>
+ <attribute name="Class-Path" value="${jar.classpath}"/>
+ <customize/>
+ </manifest>
+ </copylibs>
+ </sequential>
+ </macrodef>
+ </target>
+ <target name="-init-presetdef-jar">
+ <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+ <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
+ <j2seproject1:fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
+ </jar>
+ </presetdef>
+ </target>
+ <target name="-init-ap-cmdline-properties">
+ <property name="annotation.processing.enabled" value="true"/>
+ <property name="annotation.processing.processors.list" value=""/>
+ <property name="annotation.processing.processor.options" value=""/>
+ <property name="annotation.processing.run.all.processors" value="true"/>
+ <property name="javac.processorpath" value="${javac.classpath}"/>
+ <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+ <condition property="ap.supported.internal" value="true">
+ <not>
+ <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
+ </not>
+ </condition>
+ </target>
+ <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
+ <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+ <isfalse value="${annotation.processing.run.all.processors}"/>
+ </condition>
+ <condition else="" property="ap.proc.none.internal" value="-proc:none">
+ <isfalse value="${annotation.processing.enabled}"/>
+ </condition>
+ </target>
+ <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+ <property name="ap.cmd.line.internal" value=""/>
+ </target>
+ <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+ <!--
+ ===================
+ COMPILATION SECTION
+ ===================
+ -->
+ <target name="-deps-jar-init" unless="built-jar.properties">
+ <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+ <delete file="${built-jar.properties}" quiet="true"/>
+ </target>
+ <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+ <echo level="warn" message="Cycle detected: ECTester was already built"/>
+ </target>
+ <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+ <mkdir dir="${build.dir}"/>
+ <touch file="${built-jar.properties}" verbose="false"/>
+ <property file="${built-jar.properties}" prefix="already.built.jar."/>
+ <antcall target="-warn-already-built-jar"/>
+ <propertyfile file="${built-jar.properties}">
+ <entry key="${basedir}" value=""/>
+ </propertyfile>
+ </target>
+ <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+ <target depends="init" name="-check-automatic-build">
+ <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+ </target>
+ <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+ <antcall target="clean"/>
+ </target>
+ <target depends="init,deps-jar" name="-pre-pre-compile">
+ <mkdir dir="${build.classes.dir}"/>
+ </target>
+ <target name="-pre-compile">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="do.depend.true" name="-compile-depend">
+ <pathconvert property="build.generated.subdirs">
+ <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+ <include name="*"/>
+ </dirset>
+ </pathconvert>
+ <j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
+ </target>
+ <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
+ <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+ <copy todir="${build.classes.dir}">
+ <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+ </copy>
+ </target>
+ <target if="has.persistence.xml" name="-copy-persistence-xml">
+ <mkdir dir="${build.classes.dir}/META-INF"/>
+ <copy todir="${build.classes.dir}/META-INF">
+ <fileset dir="${meta.inf.dir}" includes="persistence.xml orm.xml"/>
+ </copy>
+ </target>
+ <target name="-post-compile">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+ <target name="-pre-compile-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+ <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+ <j2seproject3:force-recompile/>
+ <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
+ </target>
+ <target name="-post-compile-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+ <!--
+ ====================
+ JAR BUILDING SECTION
+ ====================
+ -->
+ <target depends="init" name="-pre-pre-jar">
+ <dirname file="${dist.jar}" property="dist.jar.dir"/>
+ <mkdir dir="${dist.jar.dir}"/>
+ </target>
+ <target name="-pre-jar">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init" if="do.archive" name="-do-jar-create-manifest" unless="manifest.available">
+ <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+ <touch file="${tmp.manifest.file}" verbose="false"/>
+ </target>
+ <target depends="init" if="do.archive+manifest.available" name="-do-jar-copy-manifest">
+ <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+ <copy file="${manifest.file}" tofile="${tmp.manifest.file}"/>
+ </target>
+ <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+main.class.available" name="-do-jar-set-mainclass">
+ <manifest file="${tmp.manifest.file}" mode="update">
+ <attribute name="Main-Class" value="${main.class}"/>
+ </manifest>
+ </target>
+ <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+profile.available" name="-do-jar-set-profile">
+ <manifest file="${tmp.manifest.file}" mode="update">
+ <attribute name="Profile" value="${javac.profile}"/>
+ </manifest>
+ </target>
+ <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-set-splashscreen">
+ <basename file="${application.splash}" property="splashscreen.basename"/>
+ <mkdir dir="${build.classes.dir}/META-INF"/>
+ <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
+ <manifest file="${tmp.manifest.file}" mode="update">
+ <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+ </manifest>
+ </target>
+ <target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen" if="do.mkdist" name="-do-jar-copylibs">
+ <j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
+ <echo level="info">To run this application from the command line without Ant, try:</echo>
+ <property location="${dist.jar}" name="dist.jar.resolved"/>
+ <echo level="info">java -jar "${dist.jar.resolved}"</echo>
+ </target>
+ <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen" if="do.archive" name="-do-jar-jar" unless="do.mkdist">
+ <j2seproject1:jar manifest="${tmp.manifest.file}"/>
+ <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+ <property location="${dist.jar}" name="dist.jar.resolved"/>
+ <pathconvert property="run.classpath.with.dist.jar">
+ <path path="${run.classpath}"/>
+ <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+ </pathconvert>
+ <condition else="" property="jar.usage.message" value="To run this application from the command line without Ant, try:${line.separator}${platform.java} -cp ${run.classpath.with.dist.jar} ${main.class}">
+ <isset property="main.class.available"/>
+ </condition>
+ <condition else="debug" property="jar.usage.level" value="info">
+ <isset property="main.class.available"/>
+ </condition>
+ <echo level="${jar.usage.level}" message="${jar.usage.message}"/>
+ </target>
+ <target depends="-do-jar-copylibs" if="do.archive" name="-do-jar-delete-manifest">
+ <delete>
+ <fileset file="${tmp.manifest.file}"/>
+ </delete>
+ </target>
+ <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen,-do-jar-jar,-do-jar-delete-manifest" name="-do-jar-without-libraries"/>
+ <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen,-do-jar-copylibs,-do-jar-delete-manifest" name="-do-jar-with-libraries"/>
+ <target name="-post-jar">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,compile,-pre-jar,-do-jar-without-libraries,-do-jar-with-libraries,-post-jar" name="-do-jar"/>
+ <target depends="init,compile,-pre-jar,-do-jar,-post-jar" description="Build JAR." name="jar"/>
+ <!--
+ =================
+ EXECUTION SECTION
+ =================
+ -->
+ <target depends="init,compile" description="Run a main class." name="run">
+ <j2seproject1:java>
+ <customize>
+ <arg line="${application.args}"/>
+ </customize>
+ </j2seproject1:java>
+ </target>
+ <target name="-do-not-recompile">
+ <property name="javac.includes.binary" value=""/>
+ </target>
+ <target depends="init,compile-single" name="run-single">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <j2seproject1:java classname="${run.class}"/>
+ </target>
+ <target depends="init,compile-test-single" name="run-test-with-main">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
+ </target>
+ <!--
+ =================
+ DEBUGGING SECTION
+ =================
+ -->
+ <target depends="init" if="netbeans.home" name="-debug-start-debugger">
+ <j2seproject1:nbjpdastart name="${debug.class}"/>
+ </target>
+ <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
+ <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
+ </target>
+ <target depends="init,compile" name="-debug-start-debuggee">
+ <j2seproject3:debug>
+ <customize>
+ <arg line="${application.args}"/>
+ </customize>
+ </j2seproject3:debug>
+ </target>
+ <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+ <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
+ <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
+ </target>
+ <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+ <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
+ <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+ <j2seproject3:debug classname="${debug.class}"/>
+ </target>
+ <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+ <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
+ <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+ <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
+ </target>
+ <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+ <target depends="init" name="-pre-debug-fix">
+ <fail unless="fix.includes">Must set fix.includes</fail>
+ <property name="javac.includes" value="${fix.includes}.java"/>
+ </target>
+ <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+ <j2seproject1:nbjpdareload/>
+ </target>
+ <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+ <!--
+ =================
+ PROFILING SECTION
+ =================
+ -->
+ <!--
+ pre NB7.2 profiler integration
+ -->
+ <target depends="profile-init,compile" description="Profile a project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <profile/>
+ </target>
+ <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="profiler.info.jvmargs.agent" name="-profile-single-pre72">
+ <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <profile classname="${profile.class}"/>
+ </target>
+ <target depends="profile-init,compile-single" if="profiler.info.jvmargs.agent" name="-profile-applet-pre72">
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <profile classname="sun.applet.AppletViewer">
+ <customize>
+ <arg value="${applet.url}"/>
+ </customize>
+ </profile>
+ </target>
+ <target depends="profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
+ <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+ <nbprofiledirect>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ </nbprofiledirect>
+ <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
+ <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+ <jvmarg value="${profiler.info.jvmargs.agent}"/>
+ <jvmarg line="${profiler.info.jvmargs}"/>
+ <test name="${profile.class}"/>
+ <classpath>
+ <path path="${run.test.classpath}"/>
+ </classpath>
+ <syspropertyset>
+ <propertyref prefix="test-sys-prop."/>
+ <mapper from="test-sys-prop.*" to="*" type="glob"/>
+ </syspropertyset>
+ <formatter type="brief" usefile="false"/>
+ <formatter type="xml"/>
+ </junit>
+ </target>
+ <!--
+ end of pre NB72 profiling section
+ -->
+ <target if="netbeans.home" name="-profile-check">
+ <condition property="profiler.configured">
+ <or>
+ <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
+ <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
+ </or>
+ </condition>
+ </target>
+ <target depends="-profile-check,-profile-pre72" description="Profile a project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
+ <startprofiler/>
+ <antcall target="run"/>
+ </target>
+ <target depends="-profile-check,-profile-single-pre72" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-single" unless="profiler.info.jvmargs.agent">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <startprofiler/>
+ <antcall target="run-single"/>
+ </target>
+ <target depends="-profile-test-single-pre72" description="Profile a selected test in the IDE." name="profile-test-single"/>
+ <target depends="-profile-check" description="Profile a selected test in the IDE." if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs">
+ <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+ <startprofiler/>
+ <antcall target="test-single"/>
+ </target>
+ <target depends="-profile-check" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-test-with-main">
+ <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+ <startprofiler/>
+ <antcal target="run-test-with-main"/>
+ </target>
+ <target depends="-profile-check,-profile-applet-pre72" if="profiler.configured" name="profile-applet" unless="profiler.info.jvmargs.agent">
+ <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+ <startprofiler/>
+ <antcall target="run-applet"/>
+ </target>
+ <!--
+ ===============
+ JAVADOC SECTION
+ ===============
+ -->
+ <target depends="init" if="have.sources" name="-javadoc-build">
+ <mkdir dir="${dist.javadoc.dir}"/>
+ <condition else="" property="javadoc.endorsed.classpath.cmd.line.arg" value="-J${endorsed.classpath.cmd.line.arg}">
+ <and>
+ <isset property="endorsed.classpath.cmd.line.arg"/>
+ <not>
+ <equals arg1="${endorsed.classpath.cmd.line.arg}" arg2=""/>
+ </not>
+ </and>
+ </condition>
+ <condition else="" property="bug5101868workaround" value="*.java">
+ <matches pattern="1\.[56](\..*)?" string="${java.version}"/>
+ </condition>
+ <javadoc additionalparam="-J-Dfile.encoding=${file.encoding} ${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+ <classpath>
+ <path path="${javac.classpath}"/>
+ </classpath>
+ <fileset dir="${src.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}">
+ <filename name="**/*.java"/>
+ </fileset>
+ <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+ <include name="**/*.java"/>
+ <exclude name="*.java"/>
+ </fileset>
+ <arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
+ </javadoc>
+ <copy todir="${dist.javadoc.dir}">
+ <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+ <filename name="**/doc-files/**"/>
+ </fileset>
+ <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+ <include name="**/doc-files/**"/>
+ </fileset>
+ </copy>
+ </target>
+ <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+ <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+ </target>
+ <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+ <!--
+ =========================
+ TEST COMPILATION SECTION
+ =========================
+ -->
+ <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+ <mkdir dir="${build.test.classes.dir}"/>
+ </target>
+ <target name="-pre-compile-test">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target if="do.depend.true" name="-compile-test-depend">
+ <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+ </target>
+ <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+ <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir="${test.src.dir}"/>
+ <copy todir="${build.test.classes.dir}">
+ <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+ </copy>
+ </target>
+ <target name="-post-compile-test">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+ <target name="-pre-compile-test-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+ <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+ <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
+ <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
+ <copy todir="${build.test.classes.dir}">
+ <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+ </copy>
+ </target>
+ <target name="-post-compile-test-single">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+ <!--
+ =======================
+ TEST EXECUTION SECTION
+ =======================
+ -->
+ <target depends="init" if="have.tests" name="-pre-test-run">
+ <mkdir dir="${build.test.results.dir}"/>
+ </target>
+ <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
+ <j2seproject3:test includes="${includes}" testincludes="**/*Test.java"/>
+ </target>
+ <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+ <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+ </target>
+ <target depends="init" if="have.tests" name="test-report"/>
+ <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+ <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+ <target depends="init" if="have.tests" name="-pre-test-run-single">
+ <mkdir dir="${build.test.results.dir}"/>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+ <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+ <j2seproject3:test excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+ <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+ <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
+ <fail unless="test.class">Must select some files in the IDE or set test.class</fail>
+ <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+ <j2seproject3:test excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
+ <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
+ <!--
+ =======================
+ TEST DEBUGGING SECTION
+ =======================
+ -->
+ <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
+ <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+ <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
+ </target>
+ <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
+ <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+ <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+ <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
+ </target>
+ <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+ <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
+ </target>
+ <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+ <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
+ <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+ <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
+ </target>
+ <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+ <!--
+ =========================
+ APPLET EXECUTION SECTION
+ =========================
+ -->
+ <target depends="init,compile-single" name="run-applet">
+ <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+ <j2seproject1:java classname="sun.applet.AppletViewer">
+ <customize>
+ <arg value="${applet.url}"/>
+ </customize>
+ </j2seproject1:java>
+ </target>
+ <!--
+ =========================
+ APPLET DEBUGGING SECTION
+ =========================
+ -->
+ <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
+ <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+ <j2seproject3:debug classname="sun.applet.AppletViewer">
+ <customize>
+ <arg value="${applet.url}"/>
+ </customize>
+ </j2seproject3:debug>
+ </target>
+ <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
+ <!--
+ ===============
+ CLEANUP SECTION
+ ===============
+ -->
+ <target name="-deps-clean-init" unless="built-clean.properties">
+ <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+ <delete file="${built-clean.properties}" quiet="true"/>
+ </target>
+ <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+ <echo level="warn" message="Cycle detected: ECTester was already built"/>
+ </target>
+ <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+ <mkdir dir="${build.dir}"/>
+ <touch file="${built-clean.properties}" verbose="false"/>
+ <property file="${built-clean.properties}" prefix="already.built.clean."/>
+ <antcall target="-warn-already-built-clean"/>
+ <propertyfile file="${built-clean.properties}">
+ <entry key="${basedir}" value=""/>
+ </propertyfile>
+ </target>
+ <target depends="init" name="-do-clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+ </target>
+ <target name="-post-clean">
+ <!-- Empty placeholder for easier customization. -->
+ <!-- You can override this target in the ../build.xml file. -->
+ </target>
+ <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+ <target name="-check-call-dep">
+ <property file="${call.built.properties}" prefix="already.built."/>
+ <condition property="should.call.dep">
+ <and>
+ <not>
+ <isset property="already.built.${call.subproject}"/>
+ </not>
+ <available file="${call.script}"/>
+ </and>
+ </condition>
+ </target>
+ <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+ <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+ <propertyset>
+ <propertyref prefix="transfer."/>
+ <mapper from="transfer.*" to="*" type="glob"/>
+ </propertyset>
+ </ant>
+ </target>
+</project>
diff --git a/nbproject/standalone/manifest.mf b/nbproject/standalone/manifest.mf
new file mode 100644
index 0000000..02f1e3e
--- /dev/null
+++ b/nbproject/standalone/manifest.mf
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Class-Path: lib/bcprov-jdk15on-1.58.jar lib/jcardsim-3.0.4-SNAPSHOT.jar lib/commons-cli-1.3.1.jar lib/snakeyaml-1.19.jar
+Main-Class: cz.crcs.ectester.standalone.ECTesterStandalone
+
diff --git a/nbproject/standalone/project.properties b/nbproject/standalone/project.properties
new file mode 100644
index 0000000..9fed4c2
--- /dev/null
+++ b/nbproject/standalone/project.properties
@@ -0,0 +1,80 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+application.title=ECTesterStandalone
+application.vendor=xsvenda
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form,**/*.c,**/*.h,**/*.a,**/*.o,**/Makefile
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+ ${run.classpath}
+debug.test.classpath=\
+ ${run.test.classpath}
+# Files in build.classes.dir which should be excluded from distribution jar
+dist.archive.excludes=
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/ECTesterStandalone.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+libs.CopyLibs.classpath=nbproject/copylibstask.jar
+endorsed.classpath=
+excludes=
+includes=**/common/**,**/standalone/**,**/data/**,**/applet/*
+jar.compress=false
+javac.classpath=\
+ lib/bcprov-jdk15on-1.58.jar:\
+ lib/jcardsim-3.0.4-SNAPSHOT.jar:\
+ lib/commons-cli-1.3.1.jar:\
+ lib/snakeyaml-1.19.jar
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+ ${javac.classpath}
+javac.source=1.8
+javac.target=1.8
+javac.test.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+javac.test.processorpath=\
+ ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=cz.crcs.ectester.standalone.ECTesterStandalone
+manifest.file=nbproject/standalone/manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=default_platform
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=
+run.test.classpath=\
+ ${javac.test.classpath}:\
+ ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/nbproject/standalone/project.xml b/nbproject/standalone/project.xml
new file mode 100644
index 0000000..2f2fb3f
--- /dev/null
+++ b/nbproject/standalone/project.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+ <type>org.netbeans.modules.java.j2seproject</type>
+ <configuration>
+ <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
+ <name>ECTesterStandalone</name>
+ <source-roots>
+ <root id="src.dir"/>
+ </source-roots>
+ <test-roots>
+ <root id="test.src.dir"/>
+ </test-roots>
+ </data>
+ </configuration>
+</project>
diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
index 0c20333..b026cfe 100644
--- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java
+++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
@@ -201,13 +201,13 @@ public class ECKeyGenerator {
break;
case EC_Consts.PARAMETER_F2M:
if (length == 4) {
- short i = Util.makeShort(data[(short) (offset + 2)], data[(short) (offset + 3)]);
+ short i = Util.getShort(data, (short) (offset + 2));
if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i);
if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i);
} else if (length == 8) {
- short i1 = Util.makeShort(data[(short) (offset + 2)], data[(short) (offset + 3)]);
- short i2 = Util.makeShort(data[(short) (offset + 4)], data[(short) (offset + 5)]);
- short i3 = Util.makeShort(data[(short) (offset + 6)], data[(short) (offset + 7)]);
+ short i1 = Util.getShort(data, (short) (offset + 2));
+ short i2 = Util.getShort(data, (short) (offset + 4));
+ short i3 = Util.getShort(data, (short) (offset + 6));
// if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3);
// if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3);
// TODO: fix this, ^^ fails on jcardsim, but is up to spec
diff --git a/src/cz/crcs/ectester/applet/ECKeyTester.java b/src/cz/crcs/ectester/applet/ECKeyTester.java
index 0b3c1e0..36515ef 100644
--- a/src/cz/crcs/ectester/applet/ECKeyTester.java
+++ b/src/cz/crcs/ectester/applet/ECKeyTester.java
@@ -3,7 +3,6 @@ package cz.crcs.ectester.applet;
import javacard.framework.CardRuntimeException;
import javacard.framework.ISO7816;
-import javacard.framework.ISOException;
import javacard.security.*;
/**
@@ -13,77 +12,35 @@ import javacard.security.*;
* @author Jan Jancar johny@neuromancer.sk
*/
public class ECKeyTester {
-
- private KeyAgreement ecdhKeyAgreement = null;
- private KeyAgreement ecdhcKeyAgreement = null;
+ private KeyAgreement ecKeyAgreement = null;
+ private short kaType = 0;
private Signature ecdsaSignature = null;
+ private short sigType = 0;
private short sw = ISO7816.SW_NO_ERROR;
- public short allocateECDH(byte algorithm) {
+ public short allocateKA(byte algorithm) {
sw = ISO7816.SW_NO_ERROR;
try {
- ecdhKeyAgreement = KeyAgreement.getInstance(algorithm, false);
+ ecKeyAgreement = KeyAgreement.getInstance(algorithm, false);
+ kaType = algorithm;
} catch (CardRuntimeException ce) {
sw = ce.getReason();
}
return sw;
}
- public short allocateECDHC(byte algorithm) {
+ public short allocateSig(byte algorithm) {
sw = ISO7816.SW_NO_ERROR;
try {
- ecdhcKeyAgreement = KeyAgreement.getInstance(algorithm, false);
+ ecdsaSignature = Signature.getInstance(algorithm, false);
+ sigType = algorithm;
} catch (CardRuntimeException ce) {
sw = ce.getReason();
}
return sw;
}
- public short allocateECDSA() {
- sw = ISO7816.SW_NO_ERROR;
- try {
- ecdsaSignature = Signature.getInstance(Signature.ALG_ECDSA_SHA, false);
- } catch (CardRuntimeException ce) {
- sw = ce.getReason();
- }
- return sw;
- }
-
- private short testKA(KeyAgreement ka, KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) {
- short length = 0;
- try {
- sw = AppletUtil.kaCheck(ka);
- sw = AppletUtil.keypairCheck(privatePair);
- sw = AppletUtil.keypairCheck(publicPair);
- short pubkeyLength = ((ECPublicKey) publicPair.getPublic()).getW(pubkeyBuffer, pubkeyOffset);
- // reached ok
- ka.init(privatePair.getPrivate()); // throws UNITIALIZED KEY when ALG_EC_SVDP_DHC_PLAIN is used
- //ISOException.throwIt((short) 0x666);
-
- pubkeyLength = EC_Consts.corruptParameter(corruption, pubkeyBuffer, pubkeyOffset, pubkeyLength);
- length = ka.generateSecret(pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset);
- } catch (CardRuntimeException ce) {
- sw = ce.getReason();
- }
- return length;
- }
-
- private short testKA_direct(KeyAgreement ka, KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outpuBuffer, short outputOffset, short corruption) {
- short length = 0;
- try {
- sw = AppletUtil.kaCheck(ka);
- sw = AppletUtil.keypairCheck(privatePair);
-
- ka.init(privatePair.getPrivate());
- pubkeyLength = EC_Consts.corruptParameter(corruption, pubkey, pubkeyOffset, pubkeyLength);
- length = ka.generateSecret(pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset);
- } catch (CardRuntimeException ce) {
- sw = ce.getReason();
- }
- return length;
- }
-
/**
* Tests ECDH secret generation with keys from given {@code privatePair} and {@code publicPair}.
* Uses {@code pubkeyBuffer} at {@code pubkeyOffset} for computations.
@@ -98,100 +55,46 @@ public class ECKeyTester {
* @param corruption (EC_Consts.CORRUPTION_* | ...)
* @return derived secret length
**/
- public short testECDH(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) {
- return testKA(ecdhKeyAgreement, privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption);
- }
-
- public short testECDH_direct(KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outpuBuffer, short outputOffset, short corruption) {
- return testKA_direct(ecdhKeyAgreement, privatePair, pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset, corruption);
- }
-
- /**
- * Tests ECDHC secret generation with keys from given {@code privatePair} and {@code publicPair}.
- * Uses {@code pubkeyBuffer} at {@code pubkeyOffset} for computations.
- * Output should equal to ECDH output.
- *
- * @param privatePair KeyPair from which the private key is used
- * @param publicPair KeyPair from which the public key is used
- * @param pubkeyBuffer buffer to be used for the public key
- * @param pubkeyOffset offset into pubkeyBuffer that can be used for the public key
- * @param outputBuffer buffer to be used for the secret output
- * @param outputOffset offset into the outputBuffer
- * @param corruption (EC_Consts.CORRUPTION_* | ...)
- * @return derived secret length
- */
- public short testECDHC(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) {
- return testKA(ecdhcKeyAgreement, privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption);
- }
-
- public short testECDHC_direct(KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outpuBuffer, short outputOffset, short corruption) {
- return testKA_direct(ecdhcKeyAgreement, privatePair, pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset, corruption);
- }
-
- /**
- * @param privatePair KeyPair from which the private key is used
- * @param publicPair KeyPair from which the public key is used
- * @param pubkeyBuffer buffer to be used for the public key
- * @param pubkeyOffset offset into pubkeyBuffer that can be used for the public key
- * @param outputBuffer buffer to be used for the secret output
- * @param outputOffset offset into the outputBuffer
- * @param corruption (EC_Consts.CORRUPTION_* | ...)
- * @return
- */
- public short testBOTH(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) {
- short ecdhLength = testECDH(privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption);
- if (sw != ISO7816.SW_NO_ERROR) {
- return ecdhLength;
- }
- short ecdhcLength = testECDHC(privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, (short) (outputOffset + ecdhLength), corruption);
- short length = (short) (ecdhLength + ecdhcLength);
- if (sw != ISO7816.SW_NO_ERROR) {
- return length;
- }
- if (javacard.framework.Util.arrayCompare(outputBuffer, outputOffset, outputBuffer, (short) (outputOffset + ecdhLength), ecdhLength) != 0) {
- sw = ECTesterApplet.SW_DH_DHC_MISMATCH;
- }
- return length;
- }
+ public short testKA(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) {
+ short length = 0;
+ try {
+ sw = AppletUtil.kaCheck(ecKeyAgreement);
+ sw = AppletUtil.keypairCheck(privatePair);
+ sw = AppletUtil.keypairCheck(publicPair);
+ short pubkeyLength = ((ECPublicKey) publicPair.getPublic()).getW(pubkeyBuffer, pubkeyOffset);
+ ecKeyAgreement.init(privatePair.getPrivate());
- public short testBOTH_direct(KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outputBuffer, short outputOffset, short corruption) {
- short ecdhLength = testECDH_direct(privatePair, pubkey, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset, corruption);
- if (sw != ISO7816.SW_NO_ERROR) {
- return ecdhLength;
- }
- short ecdhcLength = testECDHC_direct(privatePair, pubkey, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset, corruption);
- short length = (short) (ecdhLength + ecdhcLength);
- if (sw != ISO7816.SW_NO_ERROR) {
- return length;
- }
- if (javacard.framework.Util.arrayCompare(outputBuffer, outputOffset, outputBuffer, (short) (outputOffset + ecdhLength), ecdhLength) != 0) {
- sw = ECTesterApplet.SW_DH_DHC_MISMATCH;
+ pubkeyLength = EC_Consts.corruptParameter(corruption, pubkeyBuffer, pubkeyOffset, pubkeyLength);
+ length = ecKeyAgreement.generateSecret(pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset);
+ } catch (CardRuntimeException ce) {
+ sw = ce.getReason();
}
return length;
}
/**
- * @param privatePair KeyPair from which the private key is used
- * @param publicPair KeyPair from which the public key is used
- * @param pubkeyBuffer buffer to be used for the public key
- * @param pubkeyOffset offset into pubkeyBuffer that can be used for the public key
- * @param outputBuffer buffer to be used for the secret output
- * @param outputOffset offset into the outputBuffer
- * @param corruption (EC_Consts.CORRUPTION_* | ...)
+ * @param privatePair
+ * @param pubkey
+ * @param pubkeyOffset
+ * @param pubkeyLength
+ * @param outpuBuffer
+ * @param outputOffset
+ * @param corruption
* @return
*/
- public short testANY(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) {
- short ecdhLength = testECDH(privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption);
- if (sw == ISO7816.SW_NO_ERROR)
- return ecdhLength;
- return testECDHC(privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption);
- }
+ public short testKA_direct(KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outpuBuffer, short outputOffset, short corruption) {
+ short length = 0;
+ try {
+ sw = AppletUtil.kaCheck(ecKeyAgreement);
+ sw = AppletUtil.keypairCheck(privatePair);
- public short testANY_direct(KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outputBuffer, short outputOffset, short corruption) {
- short ecdhLength = testECDH_direct(privatePair, pubkey, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset, corruption);
- if (sw == ISO7816.SW_NO_ERROR)
- return ecdhLength;
- return testECDHC_direct(privatePair, pubkey, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset, corruption);
+ ecKeyAgreement.init(privatePair.getPrivate());
+ pubkeyLength = EC_Consts.corruptParameter(corruption, pubkey, pubkeyOffset, pubkeyLength);
+ length = ecKeyAgreement.generateSecret(pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset);
+ } catch (CardRuntimeException ce) {
+ sw = ce.getReason();
+ }
+ return length;
}
/**
@@ -227,32 +130,31 @@ public class ECKeyTester {
return length;
}
- public KeyAgreement getECDH() {
- return ecdhKeyAgreement;
+ public KeyAgreement getKA() {
+ return ecKeyAgreement;
}
- public KeyAgreement getECDHC() {
- return ecdhcKeyAgreement;
+ public Signature getSig() {
+ return ecdsaSignature;
}
- public Signature getECDSA() {
- return ecdsaSignature;
+ public boolean hasKA() {
+ return ecKeyAgreement != null;
}
- public boolean hasECDH() {
- return ecdhKeyAgreement != null;
+ public boolean hasSig() {
+ return ecdsaSignature != null;
}
- public boolean hasECDHC() {
- return ecdhcKeyAgreement != null;
+ public short getKaType() {
+ return kaType;
}
- public boolean hasECDSA() {
- return ecdsaSignature != null;
+ public short getSigType() {
+ return sigType;
}
public short getSW() {
return sw;
}
-
}
diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java
index ecf97f2..20e3f05 100644
--- a/src/cz/crcs/ectester/applet/ECTesterApplet.java
+++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java
@@ -26,11 +26,7 @@
package cz.crcs.ectester.applet;
import javacard.framework.*;
-import javacard.security.ECPrivateKey;
-import javacard.security.ECPublicKey;
-import javacard.security.KeyAgreement;
-import javacard.security.KeyPair;
-import javacard.security.RandomData;
+import javacard.security.*;
import javacardx.apdu.ExtendedLength;
/**
@@ -55,10 +51,11 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
public static final byte INS_ECDH_DIRECT = (byte) 0x71;
public static final byte INS_ECDSA = (byte) 0x72;
public static final byte INS_CLEANUP = (byte) 0x73;
- public static final byte INS_SUPPORT = (byte) 0x74;
+ //public static final byte INS_SUPPORT = (byte) 0x74;
public static final byte INS_ALLOCATE_KA = (byte) 0x75;
-
-
+ public static final byte INS_ALLOCATE_SIG = (byte) 0x76;
+
+
// PARAMETERS for P1 and P2
public static final byte KEYPAIR_LOCAL = (byte) 0x01;
public static final byte KEYPAIR_REMOTE = (byte) 0x02;
@@ -72,10 +69,9 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
public static final short SW_KEYPAIR_NULL = (short) 0x0ee3;
public static final short SW_KA_NULL = (short) 0x0ee4;
public static final short SW_SIGNATURE_NULL = (short) 0x0ee5;
- public static final short SW_OBJECT_NULL = (short) 0x0ee6;
- public static final short SW_KA_UNSUPPORTED = (short) 0x0ee7;
+ public static final short SW_OBJECT_NULL = (short) 0x0ee6;
+
-
// Class javacard.security.KeyAgreement
// javacard.security.KeyAgreement Fields:
public static final byte KeyAgreement_ALG_EC_SVDP_DH = 1;
@@ -86,8 +82,14 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
public static final byte KeyAgreement_ALG_EC_SVDP_DHC_PLAIN = 4;
public static final byte KeyAgreement_ALG_EC_PACE_GM = 5;
public static final byte KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY = 6;
- public static final byte KeyAgreement_ALG_DH_PLAIN = 7;
+ // Class javacard.security.Signature
+ // javacard.security.Signature Fields:
+ public static final byte Signature_ALG_ECDSA_SHA = 17;
+ public static final byte Signature_ALG_ECDSA_SHA_256 = 33;
+ public static final byte Signature_ALG_ECDSA_SHA_384 = 34;
+ public static final byte Signature_ALG_ECDSA_SHA_224 = 37;
+ public static final byte Signature_ALG_ECDSA_SHA_512 = 38;
private static final short ARRAY_LENGTH = (short) 0xff;
private static final short APDU_MAX_LENGTH = (short) 1024;
@@ -98,13 +100,9 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
// PERSISTENT ARRAY IN EEPROM
private byte[] dataArray = null; // unused
-
private RandomData randomData = null;
private ECKeyTester keyTester = null;
- private short ecdhSW;
- private short ecdhcSW;
- private short ecdsaSW;
private ECKeyGenerator keyGenerator = null;
private KeyPair localKeypair = null;
private KeyPair remoteKeypair = null;
@@ -133,11 +131,6 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
keyGenerator = new ECKeyGenerator();
keyTester = new ECKeyTester();
- ecdhSW = keyTester.allocateECDH(KeyAgreement.ALG_EC_SVDP_DH);
- ecdhcSW = keyTester.allocateECDHC(KeyAgreement.ALG_EC_SVDP_DHC);
- //ecdhSW = keyTester.allocateECDH((byte) 3);
- //ecdhcSW = keyTester.allocateECDHC((byte) 4);
- ecdsaSW = keyTester.allocateECDSA();
}
register();
}
@@ -163,9 +156,12 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
short length = 0;
switch (ins) {
- case INS_ALLOCATE_KA:
+ case INS_ALLOCATE_KA:
length = insAllocateKA(apdu);
break;
+ case INS_ALLOCATE_SIG:
+ length = insAllocateSig(apdu);
+ break;
case INS_ALLOCATE:
length = insAllocate(apdu);
break;
@@ -196,9 +192,6 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
case INS_CLEANUP:
length = insCleanup(apdu);
break;
- case INS_SUPPORT:
- length = insSupport(apdu);
- break;
default:
// The INS code is not supported by the dispatcher
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
@@ -208,9 +201,9 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
apdu.setOutgoingAndSend((short) 0, length);
} else ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}
-
+
/**
- * Allocates KeyAgreement object. returns allocate SW
+ * Allocates KeyAgreement object, returns allocate SW.
*
* @param apdu DATA = byte KeyAgreementType
* @return length of response
@@ -218,35 +211,25 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
private short insAllocateKA(APDU apdu) {
short cdata = apdu.getOffsetCdata();
byte kaType = apduArray[cdata];
-/*
- short sw = SW_KA_UNSUPPORTED;
- switch (kaType) {
- case KeyAgreement_ALG_EC_SVDP_DH: // no break
- case KeyAgreement_ALG_EC_SVDP_DH_PLAIN:
- case KeyAgreement_ALG_EC_PACE_GM:
- case KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY:
- sw = keyTester.allocateECDH(kaType);
- break;
- case KeyAgreement_ALG_EC_SVDP_DHC:
- case KeyAgreement_ALG_EC_SVDP_DHC_PLAIN:
- sw = keyTester.allocateECDHC(kaType);
- break;
- default:
- sw = SW_KA_UNSUPPORTED;
- break;
- }
-*/
- // Allocate given type into both DH and DHC objects
- short sw = keyTester.allocateECDH(kaType);
- short offset = 0;
- Util.setShort(apdu.getBuffer(), offset, sw);
- offset += 2;
-
- //sw = keyTester.allocateECDHC(kaType);
- Util.setShort(apdu.getBuffer(), offset, sw);
- offset += 2;
- return offset;
- }
+ short sw = keyTester.allocateKA(kaType);
+ Util.setShort(apdu.getBuffer(), (short) 0, sw);
+ return 2;
+ }
+
+ /**
+ * Allocates a Signature object, returns allocate SW.
+ *
+ * @param apdu DATA = byte SignatureType
+ * @return length of response
+ */
+ private short insAllocateSig(APDU apdu) {
+ short cdata = apdu.getOffsetCdata();
+ byte sigType = apduArray[cdata];
+ short sw = keyTester.allocateSig(sigType);
+ Util.setShort(apdu.getBuffer(), (short) 0, sw);
+ return 2;
+ }
+
/**
* Allocates local and remote keyPairs.
* returns allocate SWs
@@ -422,13 +405,15 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
}
/**
+ * Performs ECDH, directly between the privkey specified in P1(local/remote) and the raw data
*
* @param apdu P1 = byte privkey (KEYPAIR_*)
- * @return P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
+ * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
* DATA = short corruption (EC_Consts.CORRUPTION_* | ...)
* byte type (EC_Consts.KA_* | ...)
* short length
* byte[] pubkey
+ * @return length of response
*/
private short insECDH_direct(APDU apdu) {
byte privkey = apduArray[ISO7816.OFFSET_P1];
@@ -447,7 +432,8 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
*
* @param apdu P1 = byte keyPair (KEYPAIR_*)
* P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
- * DATA = short dataLength (00 = random data generated, !00 = data length)
+ * DATA = byte sigType
+ * short dataLength (00 = random data generated, !00 = data length)
* byte[] data
* @return length of response
*/
@@ -455,13 +441,14 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
byte keyPair = apduArray[ISO7816.OFFSET_P1];
byte export = apduArray[ISO7816.OFFSET_P2];
short cdata = apdu.getOffsetCdata();
+ byte sigType = apduArray[cdata];
short len = 0;
if ((keyPair & KEYPAIR_LOCAL) != 0) {
- len += ecdsa(localKeypair, export, apduArray, cdata, apdu.getBuffer(), (short) 0);
+ len += ecdsa(localKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), (short) 0);
}
if ((keyPair & KEYPAIR_REMOTE) != 0) {
- len += ecdsa(remoteKeypair, export, apduArray, cdata, apdu.getBuffer(), len);
+ len += ecdsa(remoteKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), len);
}
return len;
@@ -480,19 +467,6 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
}
/**
- * Returns data about card support for various EC related tasks collected on applet
- * install.
- *
- * @param apdu no data
- * @return length of response
- */
- private short insSupport(APDU apdu) {
- byte[] apdubuf = apdu.getBuffer();
-
- return support(apdubuf, (short) 0);
- }
-
- /**
* @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...)
* @param keyLength key length to set
* @param keyClass key class to allocate
@@ -623,7 +597,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
* @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
* @param export whether to export ECDH secret
* @param corruption whether to invalidate the pubkey before ECDH
- * @param type KeyAgreement type to test (EC_Consts.KA_* || ...)
+ * @param type KeyAgreement type to test
* @param outBuffer buffer to write sw to, and export ECDH secret {@code if(export == EXPORT_TRUE)}
* @param outOffset output offset in buffer
* @return length of data written to the buffer
@@ -635,23 +609,14 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair;
short secretLength = 0;
- switch (type) {
- case EC_Consts.KA_ECDH:
- secretLength = keyTester.testECDH(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption);
- break;
- case EC_Consts.KA_ECDHC:
- secretLength = keyTester.testECDHC(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption);
- break;
- case EC_Consts.KA_BOTH:
- secretLength = keyTester.testBOTH(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption);
- break;
- case EC_Consts.KA_ANY:
- secretLength = keyTester.testANY(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption);
- break;
- default:
- ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
+ if (keyTester.getKaType() == type) {
+ secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption);
+ } else {
+ short allocateSW = keyTester.allocateKA(type);
+ if (allocateSW == ISO7816.SW_NO_ERROR) {
+ secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption);
+ }
}
-
Util.setShort(outBuffer, outOffset, keyTester.getSW());
length += 2;
@@ -671,21 +636,13 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair;
short secretLength = 0;
- switch (type) {
- case EC_Consts.KA_ECDH:
- secretLength = keyTester.testECDH_direct(priv, apduArray, keyOffset, keyLength, outBuffer, outOffset, corruption);
- break;
- case EC_Consts.KA_ECDHC:
- secretLength = keyTester.testECDHC_direct(priv, apduArray, keyOffset, keyLength, outBuffer, outOffset, corruption);
- break;
- case EC_Consts.KA_BOTH:
- secretLength = keyTester.testBOTH_direct(priv, apduArray, keyOffset, keyLength, outBuffer, outOffset, corruption);
- break;
- case EC_Consts.KA_ANY:
- secretLength = keyTester.testANY_direct(priv, apduArray, keyOffset, keyLength, outBuffer, outOffset, corruption);
- break;
- default:
- ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
+ if (keyTester.getKaType() == type) {
+ secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, corruption);
+ } else {
+ short allocateSW = keyTester.allocateKA(type);
+ if (allocateSW == ISO7816.SW_NO_ERROR) {
+ secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, corruption);
+ }
}
Util.setShort(outBuffer, outOffset, keyTester.getSW());
@@ -702,6 +659,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
/**
* @param sign keyPair to use for signing and verification
+ * @param sigType Signature type to use
* @param export whether to export ECDSA signature
* @param inBuffer buffer to read dataLength and data to sign from
* @param inOffset input offset in buffer
@@ -709,7 +667,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
* @param outOffset output offset in buffer
* @return length of data written to the buffer
*/
- private short ecdsa(KeyPair sign, byte export, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) {
+ private short ecdsa(KeyPair sign, byte sigType, byte export, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) {
short length = 0;
short dataLength = Util.getShort(inBuffer, inOffset);
@@ -721,7 +679,15 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
Util.arrayCopyNonAtomic(inBuffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength);
}
- short signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
+ short signatureLength = 0;
+ if (keyTester.getSigType() == sigType) {
+ signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
+ } else {
+ short allocateSW = keyTester.allocateSig(sigType);
+ if (allocateSW == ISO7816.SW_NO_ERROR) {
+ signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
+ }
+ }
Util.setShort(outBuffer, outOffset, keyTester.getSW());
length += 2;
@@ -753,30 +719,4 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
Util.setShort(buffer, offset, sw);
return 2;
}
-
- /**
- * @param buffer buffer to write sw to
- * @param offset output offset in buffer
- * @return length of data written to the buffer
- */
- private short support(byte[] buffer, short offset) {
-
- if (keyTester.hasECDH()) {
- Util.setShort(buffer, offset, ecdhSW);
- } else {
- Util.setShort(buffer, offset, ISO7816.SW_FUNC_NOT_SUPPORTED);
- }
- if (keyTester.hasECDHC()) {
- Util.setShort(buffer, (short) (offset + 2), ecdhcSW);
- } else {
- Util.setShort(buffer, (short) (offset + 2), ISO7816.SW_FUNC_NOT_SUPPORTED);
- }
- if (keyTester.hasECDSA()) {
- Util.setShort(buffer, (short) (offset + 4), ecdsaSW);
- } else {
- Util.setShort(buffer, (short) (offset + 4), ISO7816.SW_FUNC_NOT_SUPPORTED);
- }
-
- return 6;
- }
}
diff --git a/src/cz/crcs/ectester/applet/EC_Consts.java b/src/cz/crcs/ectester/applet/EC_Consts.java
index 04cd55e..4581fd6 100644
--- a/src/cz/crcs/ectester/applet/EC_Consts.java
+++ b/src/cz/crcs/ectester/applet/EC_Consts.java
@@ -59,13 +59,6 @@ public class EC_Consts {
public static final byte KEY_PRIVATE = 0x02;
public static final byte KEY_BOTH = KEY_PUBLIC | KEY_PRIVATE;
-
- // Key Agreement test identifiers
- public static final byte KA_ECDH = 0x01;
- public static final byte KA_ECDHC = 0x02;
- public static final byte KA_BOTH = KA_ECDH | KA_ECDHC;
- public static final byte KA_ANY = 0x04;
-
public static RandomData randomData = null;
// secp112r1
@@ -1009,7 +1002,7 @@ public class EC_Consts {
public static final byte CURVE_default = (byte) 0;
public static final byte CURVE_external = (byte) 0xff;
- // SECP recommended curves over FP
+ // SECG recommended curves over FP
public static final byte CURVE_secp112r1 = (byte) 1;
public static final byte CURVE_secp128r1 = (byte) 2;
public static final byte CURVE_secp160r1 = (byte) 3;
@@ -1021,7 +1014,7 @@ public class EC_Consts {
public static final byte FP_CURVES = (byte) 8;
- // SECP recommended curves over F2M
+ // SECG recommended curves over F2M
public static final byte CURVE_sect163r1 = (byte) 9;
public static final byte CURVE_sect233r1 = (byte) 10;
public static final byte CURVE_sect283r1 = (byte) 11;
@@ -1033,6 +1026,25 @@ public class EC_Consts {
public static final short[] FP_SIZES = new short[]{112, 128, 160, 192, 224, 256, 384, 521};
public static final short[] F2M_SIZES = new short[]{163, 233, 283, 409, 571};
+ public static final byte[] KA_TYPES = new byte[]{
+ ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH,
+ //ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_KDF, //duplicate
+ ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC,
+ //ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC_KDF, //duplicate
+ ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_PLAIN,
+ ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN,
+ ECTesterApplet.KeyAgreement_ALG_EC_PACE_GM,
+ ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY
+ };
+
+ public static final byte[] SIG_TYPES = new byte[]{
+ ECTesterApplet.Signature_ALG_ECDSA_SHA,
+ ECTesterApplet.Signature_ALG_ECDSA_SHA_224,
+ ECTesterApplet.Signature_ALG_ECDSA_SHA_256,
+ ECTesterApplet.Signature_ALG_ECDSA_SHA_384,
+ ECTesterApplet.Signature_ALG_ECDSA_SHA_512
+ };
+
public static byte getCurve(short keyLength, byte keyClass) {
if (keyClass == KeyPair.ALG_EC_FP) {
switch (keyLength) {
diff --git a/src/cz/crcs/ectester/common/cli/Argument.java b/src/cz/crcs/ectester/common/cli/Argument.java
new file mode 100644
index 0000000..e9b6688
--- /dev/null
+++ b/src/cz/crcs/ectester/common/cli/Argument.java
@@ -0,0 +1,29 @@
+package cz.crcs.ectester.common.cli;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class Argument {
+ private String name;
+ private String desc;
+ private boolean required;
+
+ public Argument(String name, String desc, boolean isRequired) {
+ this.name = name;
+ this.desc = desc;
+ this.required = isRequired;
+ }
+
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public boolean isRequired() {
+ return required;
+ }
+}
diff --git a/src/cz/crcs/ectester/common/cli/CLITools.java b/src/cz/crcs/ectester/common/cli/CLITools.java
new file mode 100644
index 0000000..91f121f
--- /dev/null
+++ b/src/cz/crcs/ectester/common/cli/CLITools.java
@@ -0,0 +1,140 @@
+package cz.crcs.ectester.common.cli;
+
+import cz.crcs.ectester.common.ec.EC_Category;
+import cz.crcs.ectester.common.ec.EC_Data;
+import cz.crcs.ectester.data.EC_Store;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CLITools {
+
+ /**
+ * Print help.
+ */
+ public static void help(String prog, String header, Options options, String footer, boolean usage) {
+ HelpFormatter help = new HelpFormatter();
+ help.setOptionComparator(null);
+ help.printHelp(prog, header, options, footer, usage);
+ }
+
+ private static void help(HelpFormatter help, PrintWriter pw, CommandLineParser cli, Options opts, int depth) {
+ if (opts.getOptions().size() > 0) {
+ help.printOptions(pw, HelpFormatter.DEFAULT_WIDTH, opts, HelpFormatter.DEFAULT_LEFT_PAD + depth, HelpFormatter.DEFAULT_DESC_PAD);
+ }
+ if (cli instanceof TreeParser) {
+ TreeParser tp = (TreeParser) cli;
+ for (Argument arg : tp.getArgs()) {
+ String argname = arg.isRequired() ? "<" + arg.getName() + ">" : "[" + arg.getName() + "]";
+ help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + (depth + 1) + "s" + argname + " " + arg.getDesc(), " "));
+ }
+ tp.getParsers().forEach((key, value) -> {
+ pw.println();
+ help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + depth + "s" + key + ":", " "));
+ CLITools.help(help, pw, value.getParser(), value.getOptions(), depth + 1);
+ });
+ }
+ }
+
+ private static void usage(HelpFormatter help, PrintWriter pw, CommandLineParser cli, Options opts) {
+ StringWriter sw = new StringWriter();
+ PrintWriter upw = new PrintWriter(sw);
+ help.printUsage(upw, HelpFormatter.DEFAULT_WIDTH, "", opts);
+ if (cli instanceof TreeParser) {
+ upw.print(" ");
+ TreeParser tp = (TreeParser) cli;
+ String[] keys = tp.getParsers().keySet().toArray(new String[tp.getParsers().size()]);
+ if (keys.length > 0 && !tp.isRequired()) {
+ upw.print("[ ");
+ }
+
+ for (int i = 0; i < keys.length; ++i) {
+ String key = keys[i];
+ ParserOptions value = tp.getParsers().get(key);
+ upw.print("(" + key);
+ usage(help, upw, value.getParser(), value.getOptions());
+ upw.print(")");
+ if (i != keys.length - 1) {
+ upw.print(" | ");
+ }
+ }
+
+ if (keys.length > 0 && !tp.isRequired()) {
+ upw.print(" ]");
+ }
+
+ Argument[] args = tp.getArgs().toArray(new Argument[tp.getArgs().size()]);
+ if (args.length > 0) {
+ String[] argss = new String[tp.getArgs().size()];
+ for (int i = 0; i < args.length; ++i) {
+ Argument arg = args[i];
+ argss[i] = arg.isRequired() ? "<" + arg.getName() + ">" : "[" + arg.getName() + "]";
+ }
+ upw.print(" " + String.join(" ", argss));
+ }
+ }
+ pw.println(sw.toString().replaceAll("usage:( )?", "").replace("\n", ""));
+ }
+
+ /**
+ * Print tree help.
+ */
+ public static void help(String prog, String header, Options baseOpts, TreeParser baseParser, String footer, boolean printUsage) {
+ HelpFormatter help = new HelpFormatter();
+ help.setOptionComparator(null);
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, header);
+ if (printUsage) {
+ StringWriter uw = new StringWriter();
+ PrintWriter upw = new PrintWriter(uw);
+ usage(help, upw, baseParser, baseOpts);
+ pw.print("usage: " + prog);
+ help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, uw.toString());
+ upw.close();
+ pw.println();
+ }
+ help(help, pw, baseParser, baseOpts, 1);
+ help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, footer);
+ System.out.println(sw.toString());
+ }
+
+ /**
+ * Print version info.
+ */
+ public static void version(String description, String license) {
+ System.out.println(description);
+ System.out.println(license);
+ }
+
+ /**
+ * List categories and named curves.
+ */
+ public static void listNamed(EC_Store dataStore, String named) {
+ Map<String, EC_Category> categories = dataStore.getCategories();
+ if (named == null) {
+ // print all categories, briefly
+ for (EC_Category cat : categories.values()) {
+ System.out.println(cat);
+ }
+ } else if (categories.containsKey(named)) {
+ // print given category
+ System.out.println(categories.get(named));
+ } else {
+ // print given object
+ EC_Data object = dataStore.getObject(EC_Data.class, named);
+ if (object != null) {
+ System.out.println(object);
+ } else {
+ System.err.println("Named object " + named + " not found!");
+ }
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/common/cli/ParserOptions.java b/src/cz/crcs/ectester/common/cli/ParserOptions.java
new file mode 100644
index 0000000..ee2097e
--- /dev/null
+++ b/src/cz/crcs/ectester/common/cli/ParserOptions.java
@@ -0,0 +1,38 @@
+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<Argument> arguments;
+
+ public ParserOptions(CommandLineParser parser, Options options) {
+ this.parser = parser;
+ this.options = options;
+ }
+
+ public ParserOptions(CommandLineParser parser, Options options, List<Argument> arguments) {
+ this(parser, options);
+ this.arguments = arguments;
+ }
+
+ public CommandLineParser getParser() {
+ return parser;
+ }
+
+ public Options getOptions() {
+ return options;
+ }
+
+ public List<Argument> getArguments() {
+ return Collections.unmodifiableList(arguments);
+ }
+}
diff --git a/src/cz/crcs/ectester/common/cli/TreeCommandLine.java b/src/cz/crcs/ectester/common/cli/TreeCommandLine.java
new file mode 100644
index 0000000..6a044d2
--- /dev/null
+++ b/src/cz/crcs/ectester/common/cli/TreeCommandLine.java
@@ -0,0 +1,178 @@
+package cz.crcs.ectester.common.cli;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.function.BiFunction;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class TreeCommandLine extends CommandLine {
+ private String name = "";
+ private TreeCommandLine next;
+ private CommandLine cli;
+
+ public TreeCommandLine(CommandLine cli, TreeCommandLine next) {
+ this.cli = cli;
+ this.next = next;
+ }
+
+ public TreeCommandLine(String name, CommandLine cli, TreeCommandLine next) {
+ this(cli, next);
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getNextName() {
+ if (next != null) {
+ return next.getName();
+ }
+ return null;
+ }
+
+ public TreeCommandLine getNext() {
+ return next;
+ }
+
+ public boolean isNext(String next) {
+ return Objects.equals(getNextName(), next);
+ }
+
+ public CommandLine getThis() {
+ return cli;
+ }
+
+ public int getDepth() {
+ if (next == null) {
+ return 0;
+ }
+ return next.getDepth() + 1;
+ }
+
+ private <T> T getOption(String opt, BiFunction<CommandLine, String, T> getter, T defaultValue) {
+ if (opt.contains(".")) {
+ String[] parts = opt.split("\\.", 2);
+ if (next != null && parts[0].equals(next.getName())) {
+ T result = getter.apply(next, parts[1]);
+ if (result != null)
+ return result;
+ return defaultValue;
+ }
+ return defaultValue;
+ }
+ return getter.apply(cli, opt);
+ }
+
+ @Override
+ public boolean hasOption(String opt) {
+ return getOption(opt, CommandLine::hasOption, false);
+ }
+
+ @Override
+ public boolean hasOption(char opt) {
+ return cli.hasOption(opt);
+ }
+
+ @Override
+ public Object getParsedOptionValue(String opt) throws ParseException {
+ if (opt.contains(".")) {
+ String[] parts = opt.split("\\.", 2);
+ if (next != null && parts[0].equals(next.getName())) {
+ return next.getParsedOptionValue(parts[1]);
+ }
+ return null;
+ }
+ return cli.getParsedOptionValue(opt);
+ }
+
+ @Override
+ public Object getOptionObject(char opt) {
+ return cli.getOptionObject(opt);
+ }
+
+ @Override
+ public String getOptionValue(String opt) {
+ return getOption(opt, CommandLine::getOptionValue, null);
+ }
+
+ @Override
+ public String getOptionValue(char opt) {
+ return cli.getOptionValue(opt);
+ }
+
+ @Override
+ public String[] getOptionValues(String opt) {
+ return getOption(opt, CommandLine::getOptionValues, null);
+ }
+
+ @Override
+ public String[] getOptionValues(char opt) {
+ return cli.getOptionValues(opt);
+ }
+
+ @Override
+ public String getOptionValue(String opt, String defaultValue) {
+ return getOption(opt, CommandLine::getOptionValue, defaultValue);
+ }
+
+ @Override
+ public String getOptionValue(char opt, String defaultValue) {
+ return cli.getOptionValue(opt, defaultValue);
+ }
+
+ @Override
+ public Properties getOptionProperties(String opt) {
+ return getOption(opt, CommandLine::getOptionProperties, new Properties());
+ }
+
+ @Override
+ public Iterator<Option> iterator() {
+ return cli.iterator();
+ }
+
+ @Override
+ public Option[] getOptions() {
+ return cli.getOptions();
+ }
+
+ public boolean hasArg(int index) {
+ return getArg(index) != null;
+ }
+
+ public String getArg(int index) {
+ if (next != null) {
+ return next.getArg(index);
+ }
+ String[] args = cli.getArgs();
+ if (index >= args.length) {
+ return null;
+ }
+ if (index < 0 && -index > args.length) {
+ return null;
+ }
+ return index < 0 ? args[args.length + index] : args[index];
+ }
+
+ @Override
+ public String[] getArgs() {
+ return cli.getArgs();
+ }
+
+ @Override
+ public List<String> getArgList() {
+ return cli.getArgList();
+ }
+}
diff --git a/src/cz/crcs/ectester/common/cli/TreeParser.java b/src/cz/crcs/ectester/common/cli/TreeParser.java
new file mode 100644
index 0000000..f1a1980
--- /dev/null
+++ b/src/cz/crcs/ectester/common/cli/TreeParser.java
@@ -0,0 +1,128 @@
+package cz.crcs.ectester.common.cli;
+
+import org.apache.commons.cli.*;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class TreeParser implements CommandLineParser {
+ private Map<String, ParserOptions> parsers;
+ private boolean required;
+ private List<Argument> args = Collections.emptyList();
+
+ public TreeParser(Map<String, ParserOptions> parsers, boolean required) {
+ this.parsers = parsers;
+ this.required = required;
+ }
+
+ public TreeParser(Map<String, ParserOptions> parsers, boolean required, List<Argument> args) {
+ this(parsers, required);
+ this.args = args;
+ }
+
+ public Map<String, ParserOptions> getParsers() {
+ return Collections.unmodifiableMap(parsers);
+ }
+
+ public boolean isRequired() {
+ return required;
+ }
+
+ public List<Argument> getArgs() {
+ return Collections.unmodifiableList(args);
+ }
+
+ @Override
+ public TreeCommandLine parse(Options options, String[] arguments) throws ParseException {
+ return this.parse(options, arguments, null);
+ }
+
+ public TreeCommandLine parse(Options options, String[] arguments, Properties properties) throws ParseException {
+ return this.parse(options, arguments, properties, false);
+ }
+
+ @Override
+ public TreeCommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException {
+ return this.parse(options, arguments, null, stopAtNonOption);
+ }
+
+ public TreeCommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption) throws ParseException {
+ DefaultParser thisParser = new DefaultParser();
+ CommandLine cli = thisParser.parse(options, arguments, properties, true);
+
+ CommandLine subCli = null;
+ String[] cliArgs = cli.getArgs();
+ String sub = null;
+ if (cliArgs.length != 0) {
+ sub = cliArgs[0];
+
+ List<String> matches = new LinkedList<>();
+ String finalSub = sub;
+ for (Map.Entry<String, ParserOptions> entry : parsers.entrySet()) {
+ if (entry.getKey().equalsIgnoreCase(finalSub)) {
+ matches.clear();
+ matches.add(finalSub);
+ break;
+ } else if (entry.getKey().startsWith(finalSub)) {
+ matches.add(entry.getKey());
+ }
+ }
+
+ if (matches.size() == 1) {
+ sub = matches.get(0);
+ ParserOptions subparser = parsers.get(sub);
+ String[] remainingArgs = new String[cliArgs.length - 1];
+ System.arraycopy(cliArgs, 1, remainingArgs, 0, cliArgs.length - 1);
+ subCli = subparser.getParser().parse(subparser.getOptions(), remainingArgs, true);
+ } else if (matches.size() > 1) {
+ throw new AmbiguousOptionException(sub, matches);
+ }
+ } else {
+ if (required) {
+ throw new MissingOptionException(new ArrayList(parsers.keySet()));
+ }
+ }
+
+ int maxArgs = args.size();
+ long requiredArgs = args.stream().filter(Argument::isRequired).count();
+ String reqArgs = String.join(" ", args.stream().filter(Argument::isRequired).map(Argument::getName).collect(Collectors.toList()));
+
+ if (subCli instanceof TreeCommandLine) {
+ TreeCommandLine subTreeCli = (TreeCommandLine) subCli;
+
+ TreeCommandLine lastCli = subTreeCli;
+ while (lastCli.getNext() != null) {
+ lastCli = lastCli.getNext();
+ }
+
+ if (lastCli.getArgs().length < requiredArgs) {
+ throw new MissingArgumentException("Not enough arguments: " + reqArgs);
+ } else if (lastCli.getArgs().length > maxArgs) {
+ throw new MissingArgumentException("Too many arguments.");
+ }
+
+ subTreeCli.setName(sub);
+ return new TreeCommandLine(cli, subTreeCli);
+ } else if (subCli != null) {
+ if (subCli.getArgs().length < requiredArgs) {
+ throw new MissingArgumentException("Not enough arguments: " + reqArgs);
+ } else if (subCli.getArgs().length > maxArgs) {
+ throw new MissingArgumentException("Too many arguments.");
+ }
+
+ TreeCommandLine subTreeCli = new TreeCommandLine(sub, subCli, null);
+ return new TreeCommandLine(cli, subTreeCli);
+ } else {
+ if (cliArgs.length < requiredArgs) {
+ throw new MissingArgumentException("Not enough arguments: " + reqArgs);
+ } else if (cliArgs.length > maxArgs) {
+ throw new MissingArgumentException("Too many arguments.");
+ }
+
+ return new TreeCommandLine(cli, null);
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/ec/EC_Category.java b/src/cz/crcs/ectester/common/ec/EC_Category.java
index 41cbad8..32a788d 100644
--- a/src/cz/crcs/ectester/reader/ec/EC_Category.java
+++ b/src/cz/crcs/ectester/common/ec/EC_Category.java
@@ -1,4 +1,4 @@
-package cz.crcs.ectester.reader.ec;
+package cz.crcs.ectester.common.ec;
import java.util.Collections;
import java.util.Map;
diff --git a/src/cz/crcs/ectester/common/ec/EC_Curve.java b/src/cz/crcs/ectester/common/ec/EC_Curve.java
new file mode 100644
index 0000000..173fd29
--- /dev/null
+++ b/src/cz/crcs/ectester/common/ec/EC_Curve.java
@@ -0,0 +1,132 @@
+package cz.crcs.ectester.common.ec;
+
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.util.ByteUtil;
+import javacard.security.KeyPair;
+
+import java.math.BigInteger;
+import java.security.spec.*;
+
+/**
+ * An Elliptic curve, contains parameters Fp/F2M, A, B, G, R, (K)?.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Curve extends EC_Params {
+ private short bits;
+ private byte field;
+ private String desc;
+
+ /**
+ * @param bits
+ * @param field KeyPair.ALG_EC_FP or KeyPair.ALG_EC_F2M
+ */
+ public EC_Curve(short bits, byte field) {
+ super(field == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M);
+ this.bits = bits;
+ this.field = field;
+ }
+
+ public EC_Curve(String id, short bits, byte field) {
+ this(bits, field);
+ this.id = id;
+ }
+
+ public EC_Curve(String id, short bits, byte field, String desc) {
+ this(id, bits, field);
+ this.desc = desc;
+ }
+
+ public short getBits() {
+ return bits;
+ }
+
+ public byte getField() {
+ return field;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ @Override
+ public String toString() {
+ return "<" + getId() + "> " + (field == KeyPair.ALG_EC_FP ? "Prime" : "Binary") + " field Elliptic curve (" + String.valueOf(bits) + "b)" + (desc == null ? "" : ": " + desc);
+ }
+
+ public ECParameterSpec toSpec() {
+ ECField field;
+ if (this.field == KeyPair.ALG_EC_FP) {
+ field = new ECFieldFp(new BigInteger(1, getData(0)));
+ } else {
+ byte[][] fieldData = getParam(EC_Consts.PARAMETER_F2M);
+ int m = ByteUtil.getShort(fieldData[0], 0);
+ int e1 = ByteUtil.getShort(fieldData[1], 0);
+ int e2 = ByteUtil.getShort(fieldData[2], 0);
+ int e3 = ByteUtil.getShort(fieldData[3], 0);
+ int[] powers = new int[]{e1, e2, e3};
+ field = new ECFieldF2m(m, powers);
+ }
+
+ BigInteger a = new BigInteger(1, getParam(EC_Consts.PARAMETER_A)[0]);
+ BigInteger b = new BigInteger(1, getParam(EC_Consts.PARAMETER_B)[0]);
+
+ EllipticCurve curve = new EllipticCurve(field, a, b);
+
+ byte[][] G = getParam(EC_Consts.PARAMETER_G);
+ BigInteger gx = new BigInteger(1, G[0]);
+ BigInteger gy = new BigInteger(1, G[1]);
+ ECPoint generator = new ECPoint(gx, gy);
+
+ BigInteger n = new BigInteger(1, getParam(EC_Consts.PARAMETER_R)[0]);
+
+ int h = ByteUtil.getShort(getParam(EC_Consts.PARAMETER_K)[0], 0);
+
+ return new ECParameterSpec(curve, generator, n, h);
+ }
+
+ public static EC_Curve fromSpec(ECParameterSpec spec) {
+ EllipticCurve curve = spec.getCurve();
+ ECField field = curve.getField();
+
+ short bits = (short) field.getFieldSize();
+ byte[][] params;
+ int paramIndex = 0;
+ byte fieldType;
+ if (field instanceof ECFieldFp) {
+ ECFieldFp primeField = (ECFieldFp) field;
+ params = new byte[7][];
+ params[paramIndex++] = primeField.getP().toByteArray();
+ fieldType = KeyPair.ALG_EC_FP;
+ } else if (field instanceof ECFieldF2m) {
+ ECFieldF2m binaryField = (ECFieldF2m) field;
+ params = new byte[10][];
+ params[paramIndex] = new byte[2];
+ ByteUtil.setShort(params[paramIndex++], 0, (short) binaryField.getM());
+ int[] powers = binaryField.getMidTermsOfReductionPolynomial();
+ for (int i = 0; i < 3; ++i) {
+ params[paramIndex] = new byte[2];
+ ByteUtil.setShort(params[paramIndex++], 0, (short) powers[i]);
+ }
+ fieldType = KeyPair.ALG_EC_F2M;
+ } else {
+ throw new IllegalArgumentException("ECParameterSpec with an unknown field.");
+ }
+
+ ECPoint generator = spec.getGenerator();
+
+ params[paramIndex++] = curve.getA().toByteArray();
+ params[paramIndex++] = curve.getB().toByteArray();
+
+ params[paramIndex++] = generator.getAffineX().toByteArray();
+ params[paramIndex++] = generator.getAffineY().toByteArray();
+
+ params[paramIndex++] = spec.getOrder().toByteArray();
+ params[paramIndex] = new byte[2];
+ ByteUtil.setShort(params[paramIndex], 0, (short) spec.getCofactor());
+
+ EC_Curve result = new EC_Curve(bits, fieldType);
+ result.readByteArray(params);
+ return result;
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/ec/EC_Data.java b/src/cz/crcs/ectester/common/ec/EC_Data.java
index 0ceddef..c048ef7 100644
--- a/src/cz/crcs/ectester/reader/ec/EC_Data.java
+++ b/src/cz/crcs/ectester/common/ec/EC_Data.java
@@ -1,6 +1,6 @@
-package cz.crcs.ectester.reader.ec;
+package cz.crcs.ectester.common.ec;
-import cz.crcs.ectester.reader.Util;
+import cz.crcs.ectester.common.util.ByteUtil;
import java.io.*;
import java.util.*;
@@ -8,9 +8,10 @@ import java.util.regex.Pattern;
/**
* A list of byte arrays for holding EC data.
- *
+ * <p>
* The data can be read from a byte array via <code>readBytes()</code>, from a CSV via <code>readCSV()</code>.
* The data can be exported to a byte array via <code>flatten()</code> or to a string array via <code>expand()</code>.
+ *
* @author Jan Jancar johny@neuromancer.sk
*/
public abstract class EC_Data {
@@ -55,19 +56,19 @@ public abstract class EC_Data {
return data;
}
- public boolean hasData() {
- return data != null;
+ public byte[] getData(int index) {
+ return data[index];
}
- public byte[] getParam(int index) {
- return data[index];
+ public boolean hasData() {
+ return data != null;
}
public byte[] flatten() {
ByteArrayOutputStream out = new ByteArrayOutputStream();
for (byte[] param : data) {
byte[] length = new byte[2];
- Util.setShort(length, 0, (short) param.length);
+ ByteUtil.setShort(length, 0, (short) param.length);
out.write(length, 0, 2);
out.write(param, 0, param.length);
@@ -79,7 +80,7 @@ public abstract class EC_Data {
public String[] expand() {
List<String> out = new ArrayList<>(count);
for (byte[] param : data) {
- out.add(Util.bytesToHex(param, false));
+ out.add(ByteUtil.bytesToHex(param, false));
}
return out.toArray(new String[out.size()]);
@@ -97,9 +98,9 @@ public abstract class EC_Data {
private static byte[] parse(String param) {
byte[] data;
if (param.startsWith("0x") || param.startsWith("0X")) {
- data = Util.hexToBytes(param.substring(2));
+ data = ByteUtil.hexToBytes(param.substring(2));
} else {
- data = Util.hexToBytes(param);
+ data = ByteUtil.hexToBytes(param);
}
if (data == null)
return new byte[0];
@@ -141,12 +142,16 @@ public abstract class EC_Data {
}
public boolean readBytes(byte[] bytes) {
+ if (bytes == null) {
+ return false;
+ }
+
int offset = 0;
for (int i = 0; i < count; i++) {
if (bytes.length - offset < 2) {
return false;
}
- short paramLength = Util.getShort(bytes, offset);
+ short paramLength = ByteUtil.getShort(bytes, offset);
offset += 2;
if (bytes.length < offset + paramLength) {
return false;
@@ -158,6 +163,18 @@ public abstract class EC_Data {
return true;
}
+ public boolean readByteArray(byte[][] bytes) {
+ if (bytes == null || count != bytes.length) {
+ return false;
+ }
+
+ for (int i = 0; i < count; ++i) {
+ data[i] = new byte[bytes[i].length];
+ System.arraycopy(bytes[i], 0, data[i], 0, bytes[i].length);
+ }
+ return true;
+ }
+
public void writeCSV(OutputStream out) throws IOException {
Writer w = new OutputStreamWriter(out);
w.write(String.join(",", expand()));
diff --git a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java b/src/cz/crcs/ectester/common/ec/EC_KAResult.java
index 4a67bbe..8a5fcb4 100644
--- a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java
+++ b/src/cz/crcs/ectester/common/ec/EC_KAResult.java
@@ -1,6 +1,6 @@
-package cz.crcs.ectester.reader.ec;
+package cz.crcs.ectester.common.ec;
-import cz.crcs.ectester.reader.Util;
+import cz.crcs.ectester.common.util.CardUtil;
/**
* A result of EC based Key agreement operation.
@@ -8,15 +8,14 @@ import cz.crcs.ectester.reader.Util;
* @author Jan Jancar johny@neuromancer.sk
*/
public class EC_KAResult extends EC_Data {
-
- private byte ka;
+ private String ka;
private String curve;
private String oneKey;
private String otherKey;
private String desc;
- public EC_KAResult(byte ka, String curve, String oneKey, String otherKey) {
+ public EC_KAResult(String ka, String curve, String oneKey, String otherKey) {
super(1);
this.ka = ka;
this.curve = curve;
@@ -24,20 +23,24 @@ public class EC_KAResult extends EC_Data {
this.otherKey = otherKey;
}
- public EC_KAResult(String id, byte ka, String curve, String oneKey, String otherKey) {
+ public EC_KAResult(String id, String ka, String curve, String oneKey, String otherKey) {
this(ka, curve, oneKey, otherKey);
this.id = id;
}
- public EC_KAResult(String id, byte ka, String curve, String oneKey, String otherKey, String desc) {
+ public EC_KAResult(String id, String ka, String curve, String oneKey, String otherKey, String desc) {
this(id, ka, curve, oneKey, otherKey);
this.desc = desc;
}
- public byte getKA() {
+ public String getKA() {
return ka;
}
+ public byte getJavaCardKA() {
+ return CardUtil.getKA(ka);
+ }
+
public String getCurve() {
return curve;
}
@@ -56,8 +59,7 @@ public class EC_KAResult extends EC_Data {
@Override
public String toString() {
- String algo = Util.getKA(ka);
- return "<" + getId() + "> " + algo + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc);
+ return "<" + getId() + "> " + ka + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc);
}
}
diff --git a/src/cz/crcs/ectester/reader/ec/EC_Key.java b/src/cz/crcs/ectester/common/ec/EC_Key.java
index 5077d5b..a34b0e7 100644
--- a/src/cz/crcs/ectester/reader/ec/EC_Key.java
+++ b/src/cz/crcs/ectester/common/ec/EC_Key.java
@@ -1,4 +1,4 @@
-package cz.crcs.ectester.reader.ec;
+package cz.crcs.ectester.common.ec;
import cz.crcs.ectester.applet.EC_Consts;
diff --git a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java b/src/cz/crcs/ectester/common/ec/EC_Keypair.java
index 2643346..53632cd 100644
--- a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java
+++ b/src/cz/crcs/ectester/common/ec/EC_Keypair.java
@@ -1,4 +1,4 @@
-package cz.crcs.ectester.reader.ec;
+package cz.crcs.ectester.common.ec;
import cz.crcs.ectester.applet.EC_Consts;
diff --git a/src/cz/crcs/ectester/reader/ec/EC_Params.java b/src/cz/crcs/ectester/common/ec/EC_Params.java
index 6fb164b..1c066e7 100644
--- a/src/cz/crcs/ectester/reader/ec/EC_Params.java
+++ b/src/cz/crcs/ectester/common/ec/EC_Params.java
@@ -1,7 +1,7 @@
-package cz.crcs.ectester.reader.ec;
+package cz.crcs.ectester.common.ec;
import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.reader.Util;
+import cz.crcs.ectester.common.util.ByteUtil;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
@@ -44,6 +44,49 @@ public class EC_Params extends EC_Data {
return params;
}
+ public byte[][] getParam(short param) {
+ if (!hasParam(param)) {
+ return null;
+ }
+ if (Integer.bitCount(param) != 1) {
+ return null;
+ }
+ short paramMask = EC_Consts.PARAMETER_FP;
+ byte[][] result = null;
+ int i = 0;
+ while (paramMask <= EC_Consts.PARAMETER_S) {
+ short masked = (short) (this.params & param & paramMask);
+ short shallow = (short) (this.params & paramMask);
+ if (masked != 0) {
+ if (masked == EC_Consts.PARAMETER_F2M) {
+ result = new byte[4][];
+ result[0] = data[i].clone();
+ result[1] = data[i+1].clone();
+ result[2] = data[i+2].clone();
+ result[3] = data[i+3].clone();
+ break;
+ }
+ if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) {
+ result = new byte[2][];
+ result[0] = data[i].clone();
+ result[1] = data[i+1].clone();
+ break;
+ }
+ result = new byte[1][];
+ result[0] = data[i].clone();
+ }
+ if (shallow == EC_Consts.PARAMETER_F2M) {
+ i += 4;
+ } else if (shallow == EC_Consts.PARAMETER_G || shallow == EC_Consts.PARAMETER_W) {
+ i += 2;
+ } else if (shallow != 0) {
+ i++;
+ }
+ paramMask = (short) (paramMask << 1);
+ }
+ return result;
+ }
+
public boolean hasParam(short param) {
return (params & param) != 0;
}
@@ -82,12 +125,12 @@ public class EC_Params extends EC_Data {
byte[] param = data[i];
if (masked == EC_Consts.PARAMETER_F2M) {
//add m, e_1, e_2, e_3
- param = Util.concatenate(param, data[i + 1]);
- if (!Util.allValue(data[i + 2], (byte) 0)) {
- param = Util.concatenate(param, data[i + 2]);
+ param = ByteUtil.concatenate(param, data[i + 1]);
+ if (!ByteUtil.allValue(data[i + 2], (byte) 0)) {
+ param = ByteUtil.concatenate(param, data[i + 2]);
}
- if (!Util.allValue(data[i + 3], (byte) 0)) {
- param = Util.concatenate(param, data[i + 3]);
+ if (!ByteUtil.allValue(data[i + 3], (byte) 0)) {
+ param = ByteUtil.concatenate(param, data[i + 3]);
}
if (!(param.length == 4 || param.length == 8))
throw new RuntimeException("PARAMETER_F2M length is not 8.(should be)");
@@ -95,14 +138,14 @@ public class EC_Params extends EC_Data {
if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) {
//read another param (the y coord) and put into X962 format.
byte[] y = data[i + 1];
- param = Util.concatenate(new byte[]{4}, param, y); //<- ugly but works!
+ param = ByteUtil.concatenate(new byte[]{4}, param, y); //<- ugly but works!
}
if (param.length == 0)
throw new RuntimeException("Empty parameter read?");
//write length
byte[] length = new byte[2];
- Util.setShort(length, 0, (short) param.length);
+ ByteUtil.setShort(length, 0, (short) param.length);
out.write(length, 0, 2);
//write data
out.write(param, 0, param.length);
@@ -132,15 +175,15 @@ public class EC_Params extends EC_Data {
byte[] param = data[index];
if (masked == EC_Consts.PARAMETER_F2M) {
for (int i = 0; i < 4; ++i) {
- out.add(Util.bytesToHex(data[index + i], false));
+ out.add(ByteUtil.bytesToHex(data[index + i], false));
}
index += 4;
} else if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) {
- out.add(Util.bytesToHex(param, false));
- out.add(Util.bytesToHex(data[index + 1], false));
+ out.add(ByteUtil.bytesToHex(param, false));
+ out.add(ByteUtil.bytesToHex(data[index + 1], false));
index += 2;
} else {
- out.add(Util.bytesToHex(param, false));
+ out.add(ByteUtil.bytesToHex(param, false));
index++;
}
}
diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
new file mode 100644
index 0000000..29eb671
--- /dev/null
+++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
@@ -0,0 +1,82 @@
+package cz.crcs.ectester.common.output;
+
+import cz.crcs.ectester.common.test.*;
+
+import java.io.PrintStream;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class BaseTextTestWriter implements TestWriter {
+ private PrintStream output;
+
+ public static int BASE_WIDTH = 90;
+
+ public BaseTextTestWriter(PrintStream output) {
+ this.output = output;
+ }
+
+ @Override
+ public void begin(TestSuite suite) {
+ output.println("═══ Running test suite: " + suite.getName() + " ═══");
+ output.println("═══ " + suite.getDescription());
+ output.print(deviceString(suite));
+ }
+
+ protected abstract String testableString(Testable t);
+
+ protected abstract String deviceString(TestSuite suite);
+
+ private String testString(Test t, String prefix) {
+ if (!t.hasRun()) {
+ return null;
+ }
+ boolean compound = t instanceof CompoundTest;
+
+ StringBuilder out = new StringBuilder();
+ out.append(t.ok() ? " OK " : "NOK ");
+ out.append(compound ? "┳ " : "━ ");
+ int width = BASE_WIDTH - (prefix.length() + out.length());
+ 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(" ┃ ");
+
+ if (compound) {
+ CompoundTest test = (CompoundTest) t;
+ out.append(test.getResultCause());
+ out.append(System.lineSeparator());
+ Test[] tests = test.getTests();
+ for (int i = 0; i < tests.length; ++i) {
+ if (i == tests.length - 1) {
+ out.append(prefix).append(" ┗ ");
+ out.append(testString(tests[i], prefix + " "));
+ } else {
+ out.append(prefix).append(" ┣ ");
+ out.append(testString(tests[i], prefix + " ┃ "));
+ }
+
+ if (i != tests.length - 1) {
+ out.append(System.lineSeparator());
+ }
+ }
+ } else {
+ SimpleTest test = (SimpleTest) t;
+ out.append(testableString(test.getTestable()));
+ }
+ return out.toString();
+ }
+
+ @Override
+ public void outputTest(Test t) {
+ if (!t.hasRun())
+ return;
+ output.println(testString(t, ""));
+ 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
new file mode 100644
index 0000000..f3e9411
--- /dev/null
+++ b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java
@@ -0,0 +1,103 @@
+package cz.crcs.ectester.common.output;
+
+import cz.crcs.ectester.common.test.*;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.OutputStream;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class BaseXMLTestWriter implements TestWriter {
+ private OutputStream output;
+ private DocumentBuilder db;
+ protected Document doc;
+ private Node root;
+
+ public BaseXMLTestWriter(OutputStream output) throws ParserConfigurationException {
+ this.output = output;
+ this.db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ }
+
+ @Override
+ public void begin(TestSuite suite) {
+ doc = db.newDocument();
+ Element rootElem = doc.createElement("testSuite");
+ rootElem.setAttribute("name", suite.getName());
+ rootElem.setAttribute("desc", suite.getDescription());
+
+ root = rootElem;
+ doc.appendChild(root);
+ root.appendChild(deviceElement(suite));
+ }
+
+ protected abstract Element testableElement(Testable t);
+
+ protected abstract Element deviceElement(TestSuite suite);
+
+ 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()) {
+ testElem.appendChild(testElement(innerTest));
+ }
+ } else {
+ SimpleTest test = (SimpleTest) t;
+ testElem = testableElement(test.getTestable());
+ }
+
+ Element description = doc.createElement("desc");
+ 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);
+ testElem.appendChild(result);
+
+ return testElem;
+ }
+
+ @Override
+ public void outputTest(Test t) {
+ if (!t.hasRun())
+ return;
+ root.appendChild(testElement(t));
+ }
+
+ @Override
+ public void end() {
+ try {
+ DOMSource domSource = new DOMSource(doc);
+ StreamResult result = new StreamResult(output);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+ transformer.transform(domSource, result);
+ } catch (TransformerException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java
new file mode 100644
index 0000000..0769e83
--- /dev/null
+++ b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java
@@ -0,0 +1,91 @@
+package cz.crcs.ectester.common.output;
+
+import cz.crcs.ectester.common.test.*;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class BaseYAMLTestWriter implements TestWriter {
+ private PrintStream output;
+ private Map<String, Object> testRun;
+ private Map<String, String> testSuite;
+ protected List<Object> tests;
+
+ public BaseYAMLTestWriter(PrintStream output) {
+ this.output = output;
+ }
+
+ @Override
+ public void begin(TestSuite suite) {
+ output.println("---");
+ testRun = new HashMap<>();
+ testSuite = new HashMap<>();
+ tests = new LinkedList<>();
+ testSuite.put("name", suite.getName());
+ testSuite.put("desc", suite.getDescription());
+
+ testRun.put("suite", testSuite);
+ testRun.put("device", deviceObject(suite));
+ testRun.put("tests", tests);
+ }
+
+ abstract protected Map<String, Object> testableObject(Testable t);
+
+ abstract protected Map<String, Object> deviceObject(TestSuite suite);
+
+ private Map<String, Object> testObject(Test t) {
+ Map<String, Object> testObj;
+ if (t instanceof CompoundTest) {
+ CompoundTest test = (CompoundTest) t;
+ testObj = new HashMap<>();
+ testObj.put("type", "compound");
+ List<Map<String, Object>> innerTests = new LinkedList<>();
+ for (Test innerTest : test.getTests()) {
+ innerTests.add(testObject(innerTest));
+ }
+ testObj.put("tests", innerTests);
+ } else {
+ SimpleTest test = (SimpleTest) t;
+ testObj = testableObject(test.getTestable());
+ }
+
+ testObj.put("desc", t.getDescription());
+ Map<String, Object> result = new HashMap<>();
+ result.put("ok", t.ok());
+ result.put("value", t.getResultValue().name());
+ result.put("cause", t.getResultCause());
+ testObj.put("result", result);
+
+ return testObj;
+ }
+
+ @Override
+ public void outputTest(Test t) {
+ if (!t.hasRun())
+ return;
+ tests.add(testObject(t));
+ }
+
+ @Override
+ public void end() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ options.setPrettyFlow(true);
+ Yaml yaml = new Yaml(options);
+
+ Map<String, Object> result = new HashMap<>();
+ result.put("testRun", testRun);
+ String out = yaml.dump(result);
+
+ output.println(out);
+ output.println("---");
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/output/OutputLogger.java b/src/cz/crcs/ectester/common/output/OutputLogger.java
index bf47a1f..09b8f73 100644
--- a/src/cz/crcs/ectester/reader/output/OutputLogger.java
+++ b/src/cz/crcs/ectester/common/output/OutputLogger.java
@@ -1,4 +1,4 @@
-package cz.crcs.ectester.reader.output;
+package cz.crcs.ectester.common.output;
import java.io.*;
import java.util.LinkedList;
diff --git a/src/cz/crcs/ectester/reader/output/TeeOutputStream.java b/src/cz/crcs/ectester/common/output/TeeOutputStream.java
index 2a1af99..2401fce 100644
--- a/src/cz/crcs/ectester/reader/output/TeeOutputStream.java
+++ b/src/cz/crcs/ectester/common/output/TeeOutputStream.java
@@ -1,4 +1,4 @@
-package cz.crcs.ectester.reader.output;
+package cz.crcs.ectester.common.output;
import java.io.IOException;
import java.io.OutputStream;
diff --git a/src/cz/crcs/ectester/reader/output/TestWriter.java b/src/cz/crcs/ectester/common/output/TestWriter.java
index 74c76fb..0ecfd5a 100644
--- a/src/cz/crcs/ectester/reader/output/TestWriter.java
+++ b/src/cz/crcs/ectester/common/output/TestWriter.java
@@ -1,7 +1,7 @@
-package cz.crcs.ectester.reader.output;
+package cz.crcs.ectester.common.output;
-import cz.crcs.ectester.reader.test.Test;
-import cz.crcs.ectester.reader.test.TestSuite;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.test.TestSuite;
/**
* @author Jan Jancar johny@neuromancer.sk
diff --git a/src/cz/crcs/ectester/common/test/BaseTestable.java b/src/cz/crcs/ectester/common/test/BaseTestable.java
new file mode 100644
index 0000000..a4b9a00
--- /dev/null
+++ b/src/cz/crcs/ectester/common/test/BaseTestable.java
@@ -0,0 +1,32 @@
+package cz.crcs.ectester.common.test;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class BaseTestable implements Testable {
+ protected boolean hasRun;
+ protected boolean ok;
+ protected boolean error;
+
+ @Override
+ public boolean hasRun() {
+ return hasRun;
+ }
+
+ @Override
+ public boolean ok() {
+ return ok;
+ }
+
+ @Override
+ public boolean error() {
+ return error;
+ }
+
+ @Override
+ public void reset() {
+ hasRun = false;
+ ok = false;
+ error = false;
+ }
+}
diff --git a/src/cz/crcs/ectester/common/test/CompoundTest.java b/src/cz/crcs/ectester/common/test/CompoundTest.java
new file mode 100644
index 0000000..10ecf9c
--- /dev/null
+++ b/src/cz/crcs/ectester/common/test/CompoundTest.java
@@ -0,0 +1,111 @@
+package cz.crcs.ectester.common.test;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * A compound test that runs many Tests and has a Result dependent on all/some of their Results.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CompoundTest extends Test {
+ private Function<Test[], Result> callback;
+ private Test[] tests;
+ private String description;
+
+ private CompoundTest(Function<Test[], Result> callback, Test... tests) {
+ this.callback = callback;
+ this.tests = Arrays.stream(tests).filter(Objects::nonNull).toArray(Test[]::new);
+ }
+
+ private CompoundTest(Function<Test[], Result> callback, String descripiton, Test... tests) {
+ this(callback, tests);
+ this.description = descripiton;
+ }
+
+ public static CompoundTest function(Function<Test[], Result> callback, Test... tests) {
+ return new CompoundTest(callback, tests);
+ }
+
+ public static CompoundTest function(Function<Test[], Result> callback, String description, Test... tests) {
+ return new CompoundTest(callback, description, tests);
+ }
+
+ public static CompoundTest all(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.");
+ }, all);
+ }
+
+ public static CompoundTest all(Result.ExpectedValue what, String description, Test... all) {
+ CompoundTest result = CompoundTest.all(what, all);
+ 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.");
+ }, any);
+ }
+
+ public static CompoundTest any(Result.ExpectedValue what, String description, Test... any) {
+ CompoundTest result = CompoundTest.any(what, any);
+ result.setDescription(description);
+ return result;
+ }
+
+ public static CompoundTest mask(Result.ExpectedValue[] results, Test... masked) {
+ return new CompoundTest((tests) -> {
+ for (int i = 0; i < results.length; ++i) {
+ if (!Result.Value.fromExpected(results[i], tests[i].ok()).ok()) {
+ return new Result(Result.Value.FAILURE, "Some sub-tests did not match the result mask.");
+ }
+ }
+ return new Result(Result.Value.SUCCESS, "All sub-tests matched the expected mask.");
+ }, masked);
+ }
+
+ public static CompoundTest mask(Result.ExpectedValue[] results, String description, Test... masked) {
+ CompoundTest result = CompoundTest.mask(results, masked);
+ result.setDescription(description);
+ return result;
+ }
+
+ public Test[] getTests() {
+ return tests;
+ }
+
+ @Override
+ public void run() throws TestException {
+ if (hasRun)
+ return;
+
+ for (Test test : tests) {
+ test.run();
+ }
+
+ result = callback.apply(tests);
+ this.hasRun = true;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/Result.java b/src/cz/crcs/ectester/common/test/Result.java
index 82f0f32..11fcb4d 100644
--- a/src/cz/crcs/ectester/reader/test/Result.java
+++ b/src/cz/crcs/ectester/common/test/Result.java
@@ -1,6 +1,8 @@
-package cz.crcs.ectester.reader.test;
+package cz.crcs.ectester.common.test;
/**
+ * A Result of a Test. Has a Value and an optional String cause.
+ *
* @author Jan Jancar johny@neuromancer.sk
*/
public class Result {
@@ -44,7 +46,7 @@ public class Result {
}
/**
- *
+ * A result value of a Test.
*/
public enum Value {
SUCCESS(true),
@@ -84,7 +86,7 @@ public class Result {
}
/**
- *
+ * A possible expected value result of a Test.
*/
public enum ExpectedValue {
SUCCESS,
diff --git a/src/cz/crcs/ectester/common/test/SimpleTest.java b/src/cz/crcs/ectester/common/test/SimpleTest.java
new file mode 100644
index 0000000..f68320a
--- /dev/null
+++ b/src/cz/crcs/ectester/common/test/SimpleTest.java
@@ -0,0 +1,19 @@
+package cz.crcs.ectester.common.test;
+
+/**
+ * @param <T>
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class SimpleTest<T extends BaseTestable> extends Test {
+ protected T testable;
+ protected TestCallback<T> callback;
+
+ public SimpleTest(T testable, TestCallback<T> callback) {
+ this.testable = testable;
+ this.callback = callback;
+ }
+
+ public T getTestable() {
+ return testable;
+ }
+}
diff --git a/src/cz/crcs/ectester/common/test/Test.java b/src/cz/crcs/ectester/common/test/Test.java
new file mode 100644
index 0000000..3d0baf6
--- /dev/null
+++ b/src/cz/crcs/ectester/common/test/Test.java
@@ -0,0 +1,66 @@
+package cz.crcs.ectester.common.test;
+
+import static cz.crcs.ectester.common.test.Result.Value;
+
+/**
+ * An abstract test that can be run and has a Result.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class Test implements Testable {
+ protected boolean hasRun;
+ 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) {
+ return true;
+ }
+ return result.ok();
+ }
+
+ @Override
+ public boolean error() {
+ if (!hasRun) {
+ return false;
+ }
+ return result.compareTo(Value.ERROR);
+ }
+
+ @Override
+ public boolean hasRun() {
+ return hasRun;
+ }
+
+ @Override
+ public void reset() {
+ hasRun = false;
+ result = null;
+ }
+
+ public abstract String getDescription();
+
+ @Override
+ public abstract void run() throws TestException;
+
+}
diff --git a/src/cz/crcs/ectester/common/test/TestCallback.java b/src/cz/crcs/ectester/common/test/TestCallback.java
new file mode 100644
index 0000000..ce6000b
--- /dev/null
+++ b/src/cz/crcs/ectester/common/test/TestCallback.java
@@ -0,0 +1,12 @@
+package cz.crcs.ectester.common.test;
+
+import java.util.function.Function;
+
+/**
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ * @param <T>
+ */
+public abstract class TestCallback<T extends Testable> implements Function<T, Result> {
+
+}
diff --git a/src/cz/crcs/ectester/common/test/TestException.java b/src/cz/crcs/ectester/common/test/TestException.java
new file mode 100644
index 0000000..008e9f6
--- /dev/null
+++ b/src/cz/crcs/ectester/common/test/TestException.java
@@ -0,0 +1,13 @@
+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
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class TestException extends Exception {
+ 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
new file mode 100644
index 0000000..f4f30ee
--- /dev/null
+++ b/src/cz/crcs/ectester/common/test/TestSuite.java
@@ -0,0 +1,56 @@
+package cz.crcs.ectester.common.test;
+
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.data.EC_Store;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class TestSuite {
+ protected String name;
+ protected String description;
+ protected TestWriter writer;
+
+ public TestSuite(TestWriter writer, String name, String description) {
+ this.writer = writer;
+ this.name = name;
+ this.description = description;
+ }
+
+ public void run() throws TestException {
+ writer.begin(this);
+ try {
+ runTests();
+ } catch (Exception e) {
+ throw new TestException(e);
+ }
+ writer.end();
+ }
+
+ protected Test runTest(Test t) throws TestException {
+ t.run();
+ return t;
+ }
+
+ protected Test doTest(Test t) throws TestException {
+ t.run();
+ writer.outputTest(t);
+ return t;
+ }
+
+ protected abstract void runTests() throws Exception;
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+}
diff --git a/src/cz/crcs/ectester/common/test/Testable.java b/src/cz/crcs/ectester/common/test/Testable.java
new file mode 100644
index 0000000..33c9485
--- /dev/null
+++ b/src/cz/crcs/ectester/common/test/Testable.java
@@ -0,0 +1,33 @@
+package cz.crcs.ectester.common.test;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public interface Testable {
+ /**
+ * @return Whether this Testable was OK.
+ */
+ boolean ok();
+
+ /**
+ * @return Whether an error happened.
+ */
+ boolean error();
+
+ /**
+ * @return Whether this runnable was run.
+ */
+ boolean hasRun();
+
+ /**
+ *
+ */
+ void reset();
+
+ /**
+ * Run this Runnable.
+ *
+ * @throws TestException If an unexpected exception/error is encountered.
+ */
+ void run() throws TestException;
+}
diff --git a/src/cz/crcs/ectester/common/util/ByteUtil.java b/src/cz/crcs/ectester/common/util/ByteUtil.java
new file mode 100644
index 0000000..90c6eaa
--- /dev/null
+++ b/src/cz/crcs/ectester/common/util/ByteUtil.java
@@ -0,0 +1,128 @@
+package cz.crcs.ectester.common.util;
+
+/**
+ * Utility class, some byte/hex manipulation, convenient byte[] methods.
+ *
+ * @author Petr Svenda petr@svenda.com
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class ByteUtil {
+ public static short getShort(byte[] array, int offset) {
+ return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF));
+ }
+
+ public static void setShort(byte[] array, int offset, short value) {
+ array[offset + 1] = (byte) (value & 0xFF);
+ array[offset] = (byte) ((value >> 8) & 0xFF);
+ }
+
+ public static int diffBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) {
+ for (int i = 0; i < length; ++i) {
+ byte a = one[i + oneOffset];
+ byte b = other[i + otherOffset];
+ if (a != b) {
+ return i;
+ }
+ }
+ return length;
+ }
+
+ public static boolean compareBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) {
+ return diffBytes(one, oneOffset, other, otherOffset, length) == length;
+ }
+
+ public static boolean allValue(byte[] array, byte value) {
+ for (byte a : array) {
+ if (a != value)
+ return false;
+ }
+ return true;
+ }
+
+ public static byte[] hexToBytes(String hex) {
+ return hexToBytes(hex, true);
+ }
+
+ public static byte[] hexToBytes(String hex, boolean bigEndian) {
+ hex = hex.replace(" ", "");
+ int len = hex.length();
+ StringBuilder sb = new StringBuilder();
+
+ if (len % 2 == 1) {
+ sb.append("0");
+ ++len;
+ }
+
+ if (bigEndian) {
+ sb.append(hex);
+ } else {
+ for (int i = 0; i < len / 2; ++i) {
+ if (sb.length() >= 2) {
+ sb.insert(sb.length() - 2, hex.substring(2 * i, 2 * i + 2));
+ } else {
+ sb.append(hex.substring(2 * i, 2 * i + 2));
+ }
+
+ }
+ }
+
+ String data = sb.toString();
+ byte[] result = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ result[i / 2] = (byte) ((Character.digit(data.charAt(i), 16) << 4)
+ + (Character.digit(data.charAt(i + 1), 16)));
+ }
+ return result;
+ }
+
+ public static String byteToHex(byte data) {
+ return String.format("%02x", data);
+ }
+
+ public static String bytesToHex(byte[] data) {
+ return bytesToHex(data, true);
+ }
+
+ public static String bytesToHex(byte[] data, boolean addSpace) {
+ if (data == null) {
+ return "";
+ }
+ return bytesToHex(data, 0, data.length, addSpace);
+ }
+
+ public static String bytesToHex(byte[] data, int offset, int len) {
+ return bytesToHex(data, offset, len, true);
+ }
+
+ public static String bytesToHex(byte[] data, int offset, int len, boolean addSpace) {
+ if (data == null) {
+ return "";
+ }
+ StringBuilder buf = new StringBuilder();
+ for (int i = offset; i < (offset + len); i++) {
+ buf.append(byteToHex(data[i]));
+ if (addSpace && i != (offset + len - 1)) {
+ buf.append(" ");
+ }
+ }
+ return (buf.toString());
+ }
+
+ public static byte[] concatenate(byte[]... arrays) {
+ int len = 0;
+ for (byte[] array : arrays) {
+ if (array == null)
+ continue;
+ len += array.length;
+ }
+ byte[] out = new byte[len];
+ int offset = 0;
+ for (byte[] array : arrays) {
+ if (array == null || array.length == 0)
+ continue;
+ System.arraycopy(array, 0, out, offset, array.length);
+ offset += array.length;
+ }
+ return out;
+ }
+}
diff --git a/src/cz/crcs/ectester/common/util/CardUtil.java b/src/cz/crcs/ectester/common/util/CardUtil.java
new file mode 100644
index 0000000..8285d8b
--- /dev/null
+++ b/src/cz/crcs/ectester/common/util/CardUtil.java
@@ -0,0 +1,272 @@
+package cz.crcs.ectester.common.util;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import javacard.framework.ISO7816;
+import javacard.security.CryptoException;
+
+import static cz.crcs.ectester.applet.ECTesterApplet.*;
+
+/**
+ * @author Petr Svenda petr@svenda.com
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardUtil {
+ public static byte getKA(String name) {
+ switch (name) {
+ case "DH":
+ case "ECDH":
+ return ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH;
+ case "DHC":
+ case "ECDHC":
+ return ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC;
+ default:
+ return ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH;
+ }
+ }
+
+ public static String getSWSource(short sw) {
+ switch (sw) {
+ case ISO7816.SW_NO_ERROR:
+ case ISO7816.SW_APPLET_SELECT_FAILED:
+ case ISO7816.SW_BYTES_REMAINING_00:
+ case ISO7816.SW_CLA_NOT_SUPPORTED:
+ case ISO7816.SW_COMMAND_NOT_ALLOWED:
+ case ISO7816.SW_CONDITIONS_NOT_SATISFIED:
+ case ISO7816.SW_CORRECT_LENGTH_00:
+ case ISO7816.SW_DATA_INVALID:
+ case ISO7816.SW_FILE_FULL:
+ case ISO7816.SW_FILE_INVALID:
+ case ISO7816.SW_FILE_NOT_FOUND:
+ case ISO7816.SW_FUNC_NOT_SUPPORTED:
+ case ISO7816.SW_INCORRECT_P1P2:
+ case ISO7816.SW_INS_NOT_SUPPORTED:
+ case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED:
+ case ISO7816.SW_RECORD_NOT_FOUND:
+ case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED:
+ case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED:
+ case ISO7816.SW_UNKNOWN:
+ case ISO7816.SW_WARNING_STATE_UNCHANGED:
+ case ISO7816.SW_WRONG_DATA:
+ case ISO7816.SW_WRONG_LENGTH:
+ case ISO7816.SW_WRONG_P1P2:
+ return "ISO";
+ case CryptoException.ILLEGAL_VALUE:
+ case CryptoException.UNINITIALIZED_KEY:
+ case CryptoException.NO_SUCH_ALGORITHM:
+ case CryptoException.INVALID_INIT:
+ case CryptoException.ILLEGAL_USE:
+ return "CryptoException";
+ case ECTesterApplet.SW_SIG_VERIFY_FAIL:
+ case ECTesterApplet.SW_DH_DHC_MISMATCH:
+ case ECTesterApplet.SW_KEYPAIR_NULL:
+ case ECTesterApplet.SW_KA_NULL:
+ case ECTesterApplet.SW_SIGNATURE_NULL:
+ case ECTesterApplet.SW_OBJECT_NULL:
+ return "ECTesterApplet";
+ default:
+ return "?";
+ }
+ }
+
+ public static String getSW(short sw) {
+ switch (sw) {
+ case ISO7816.SW_APPLET_SELECT_FAILED:
+ return "APPLET_SELECT_FAILED";
+ case ISO7816.SW_BYTES_REMAINING_00:
+ return "BYTES_REMAINING";
+ case ISO7816.SW_CLA_NOT_SUPPORTED:
+ return "CLA_NOT_SUPPORTED";
+ case ISO7816.SW_COMMAND_NOT_ALLOWED:
+ return "COMMAND_NOT_ALLOWED";
+ case ISO7816.SW_CONDITIONS_NOT_SATISFIED:
+ return "CONDITIONS_NOT_SATISFIED";
+ case ISO7816.SW_CORRECT_LENGTH_00:
+ return "CORRECT_LENGTH";
+ case ISO7816.SW_DATA_INVALID:
+ return "DATA_INVALID";
+ case ISO7816.SW_FILE_FULL:
+ return "FILE_FULL";
+ case ISO7816.SW_FILE_INVALID:
+ return "FILE_INVALID";
+ case ISO7816.SW_FILE_NOT_FOUND:
+ return "FILE_NOT_FOUND";
+ case ISO7816.SW_FUNC_NOT_SUPPORTED:
+ return "FUNC_NOT_SUPPORTED";
+ case ISO7816.SW_INCORRECT_P1P2:
+ return "INCORRECT_P1P2";
+ case ISO7816.SW_INS_NOT_SUPPORTED:
+ return "INS_NOT_SUPPORTED";
+ case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED:
+ return "LOGICAL_CHANNEL_NOT_SUPPORTED";
+ case ISO7816.SW_RECORD_NOT_FOUND:
+ return "RECORD_NOT_FOUND";
+ case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED:
+ return "SECURE_MESSAGING_NOT_SUPPORTED";
+ case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED:
+ return "SECURITY_STATUS_NOT_SATISFIED";
+ case ISO7816.SW_UNKNOWN:
+ return "UNKNOWN";
+ case ISO7816.SW_WARNING_STATE_UNCHANGED:
+ return "WARNING_STATE_UNCHANGED";
+ case ISO7816.SW_WRONG_DATA:
+ return "WRONG_DATA";
+ case ISO7816.SW_WRONG_LENGTH:
+ return "WRONG_LENGTH";
+ case ISO7816.SW_WRONG_P1P2:
+ return "WRONG_P1P2";
+ case CryptoException.ILLEGAL_VALUE:
+ return "ILLEGAL_VALUE";
+ case CryptoException.UNINITIALIZED_KEY:
+ return "UNINITIALIZED_KEY";
+ case CryptoException.NO_SUCH_ALGORITHM:
+ return "NO_SUCH_ALG";
+ case CryptoException.INVALID_INIT:
+ return "INVALID_INIT";
+ case CryptoException.ILLEGAL_USE:
+ return "ILLEGAL_USE";
+ case ECTesterApplet.SW_SIG_VERIFY_FAIL:
+ return "SIG_VERIFY_FAIL";
+ case ECTesterApplet.SW_DH_DHC_MISMATCH:
+ return "DH_DHC_MISMATCH";
+ case ECTesterApplet.SW_KEYPAIR_NULL:
+ return "KEYPAIR_NULL";
+ case ECTesterApplet.SW_KA_NULL:
+ return "KA_NULL";
+ case ECTesterApplet.SW_SIGNATURE_NULL:
+ return "SIGNATURE_NULL";
+ case ECTesterApplet.SW_OBJECT_NULL:
+ return "OBJECT_NULL";
+ default:
+ return "unknown";
+ }
+ }
+
+ public static String getSWString(short sw) {
+ if (sw == ISO7816.SW_NO_ERROR) {
+ return "OK (0x9000)";
+ } else {
+ String str = getSW(sw);
+ return String.format("fail (%s, 0x%04x)", str, sw);
+ }
+ }
+
+ public static String getCorruption(short corruptionType) {
+ switch (corruptionType) {
+ case EC_Consts.CORRUPTION_NONE:
+ return "NONE";
+ case EC_Consts.CORRUPTION_FIXED:
+ return "FIXED";
+ case EC_Consts.CORRUPTION_ONE:
+ return "ONE";
+ case EC_Consts.CORRUPTION_ZERO:
+ return "ZERO";
+ case EC_Consts.CORRUPTION_ONEBYTERANDOM:
+ return "ONE_BYTE_RANDOM";
+ case EC_Consts.CORRUPTION_FULLRANDOM:
+ return "FULL_RANDOM";
+ case EC_Consts.CORRUPTION_INCREMENT:
+ return "INCREMENT";
+ case EC_Consts.CORRUPTION_INFINITY:
+ return "INFINITY";
+ case EC_Consts.CORRUPTION_COMPRESS:
+ return "COMPRESSED";
+ case EC_Consts.CORRUPTION_MAX:
+ return "MAX";
+ default:
+ return "unknown";
+ }
+ }
+
+ public static String getKATypeString(byte kaType) {
+ switch (kaType) {
+ case KeyAgreement_ALG_EC_SVDP_DH:
+ return "ALG_EC_SVDP_DH";
+ case KeyAgreement_ALG_EC_SVDP_DH_PLAIN:
+ return "ALG_EC_SVDP_DH_PLAIN";
+ case KeyAgreement_ALG_EC_PACE_GM:
+ return "ALG_EC_PACE_GM";
+ case KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY:
+ return "ALG_EC_SVDP_DH_PLAIN_XY";
+ case KeyAgreement_ALG_EC_SVDP_DHC:
+ return "ALG_EC_SVDP_DHC";
+ case KeyAgreement_ALG_EC_SVDP_DHC_PLAIN:
+ return "ALG_EC_SVDP_DHC_PLAIN";
+ default:
+ return "unknown";
+ }
+ }
+
+ public static byte getKAType(String kaTypeString) {
+ switch (kaTypeString) {
+ case "ALG_EC_SVDP_DH":
+ return KeyAgreement_ALG_EC_SVDP_DH;
+ case "ALG_EC_SVDP_DH_PLAIN":
+ return KeyAgreement_ALG_EC_SVDP_DH_PLAIN;
+ case "ALG_EC_PACE_GM":
+ return KeyAgreement_ALG_EC_PACE_GM;
+ case "ALG_EC_SVDP_DH_PLAIN_XY":
+ return KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY;
+ case "ALG_EC_SVDP_DHC":
+ return KeyAgreement_ALG_EC_SVDP_DHC;
+ case "ALG_EC_SVDP_DHC_PLAIN":
+ return KeyAgreement_ALG_EC_SVDP_DHC_PLAIN;
+ default:
+ return 0;
+ }
+ }
+
+ public static byte parseKAType(String kaTypeString) {
+ byte kaType;
+ try {
+ kaType = Byte.parseByte(kaTypeString);
+ } catch (NumberFormatException nfex) {
+ kaType = getKAType(kaTypeString);
+ }
+ return kaType;
+ }
+
+ public static String getSigTypeString(byte sigType) {
+ switch (sigType) {
+ case Signature_ALG_ECDSA_SHA:
+ return "ALG_ECDSA_SHA";
+ case Signature_ALG_ECDSA_SHA_224:
+ return "ALG_ECDSA_SHA_224";
+ case Signature_ALG_ECDSA_SHA_256:
+ return "ALG_ECDSA_SHA_256";
+ case Signature_ALG_ECDSA_SHA_384:
+ return "ALG_ECDSA_SHA_384";
+ case Signature_ALG_ECDSA_SHA_512:
+ return "ALG_ECDSA_SHA_512";
+ default:
+ return "unknown";
+ }
+ }
+
+ public static byte getSigType(String sigTypeString) {
+ switch (sigTypeString) {
+ case "ALG_ECDSA_SHA":
+ return Signature_ALG_ECDSA_SHA;
+ case "ALG_ECDSA_SHA_224":
+ return Signature_ALG_ECDSA_SHA_224;
+ case "ALG_ECDSA_SHA_256":
+ return Signature_ALG_ECDSA_SHA_256;
+ case "ALG_ECDSA_SHA_384":
+ return Signature_ALG_ECDSA_SHA_384;
+ case "ALG_ECDSA_SHA_512":
+ return Signature_ALG_ECDSA_SHA_512;
+ default:
+ return 0;
+ }
+ }
+
+ public static byte parseSigType(String sigTypeString) {
+ byte sigType;
+ try {
+ sigType = Byte.parseByte(sigTypeString);
+ } catch (NumberFormatException nfex) {
+ sigType = getSigType(sigTypeString);
+ }
+ return sigType;
+ }
+}
diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java
new file mode 100644
index 0000000..973b813
--- /dev/null
+++ b/src/cz/crcs/ectester/common/util/ECUtil.java
@@ -0,0 +1,172 @@
+package cz.crcs.ectester.common.util;
+
+import java.math.BigInteger;
+import java.security.spec.*;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class ECUtil {
+
+ public static byte[] toByteArray(BigInteger what, int bits) {
+ byte[] raw = what.toByteArray();
+ int bytes = (bits + 7) / 8;
+ if (raw.length < bytes) {
+ byte[] result = new byte[bytes];
+ System.arraycopy(raw, 0, result, bytes - raw.length, raw.length);
+ return result;
+ }
+ if (bytes < raw.length) {
+ byte[] result = new byte[bytes];
+ System.arraycopy(raw, raw.length - bytes, result, 0, bytes);
+ return result;
+ }
+ return raw;
+ }
+
+ public static byte[] toX962Compressed(ECPoint point, int bits) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte marker = (byte) (0x02 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
+ return ByteUtil.concatenate(new byte[]{marker}, x);
+ }
+
+ public static byte[] toX962Compressed(ECPoint point, EllipticCurve curve) {
+ return toX962Compressed(point, curve.getField().getFieldSize());
+ }
+
+ public static byte[] toX962Compressed(ECPoint point, ECParameterSpec spec) {
+ return toX962Compressed(point, spec.getCurve());
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point, int bits) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte[] y = toByteArray(point.getAffineY(), bits);
+ return ByteUtil.concatenate(new byte[]{0x04}, x, y);
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point, EllipticCurve curve) {
+ return toX962Uncompressed(point, curve.getField().getFieldSize());
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point, ECParameterSpec spec) {
+ return toX962Uncompressed(point, spec.getCurve());
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, int bits) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte[] y = toByteArray(point.getAffineY(), bits);
+ byte marker = (byte) (0x06 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
+ return ByteUtil.concatenate(new byte[]{marker}, x, y);
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, EllipticCurve curve) {
+ return toX962Hybrid(point, curve.getField().getFieldSize());
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, ECParameterSpec spec) {
+ return toX962Hybrid(point, spec.getCurve());
+ }
+
+ private static boolean isResidue(BigInteger a, BigInteger p) {
+ BigInteger exponent = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
+ BigInteger result = a.modPow(exponent, p);
+ return result.intValueExact() == 1;
+ }
+
+ private static BigInteger modSqrt(BigInteger a, BigInteger p) {
+ BigInteger q = p.subtract(BigInteger.ONE);
+ int s = 0;
+ while (q.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
+ q = q.divide(BigInteger.valueOf(2));
+ s++;
+ }
+
+ BigInteger z = BigInteger.ONE;
+ do {
+ z = z.add(BigInteger.ONE);
+ } while (isResidue(z, p));
+
+ BigInteger m = BigInteger.valueOf(s);
+ BigInteger c = z.modPow(q, p);
+ BigInteger t = a.modPow(q, p);
+ BigInteger rExponent = q.add(BigInteger.ONE).divide(BigInteger.valueOf(2));
+ BigInteger r = a.modPow(rExponent, p);
+
+ while (!t.equals(BigInteger.ONE)) {
+ int i = 0;
+ BigInteger exponent;
+ do {
+ exponent = BigInteger.valueOf(2).pow(++i);
+ } while (!t.modPow(exponent, p).equals(BigInteger.ONE));
+
+ BigInteger twoExponent = m.subtract(BigInteger.valueOf(i + 1));
+ BigInteger b = c.modPow(BigInteger.valueOf(2).modPow(twoExponent, p), p);
+ m = BigInteger.valueOf(i);
+ c = b.modPow(BigInteger.valueOf(2), p);
+ t = t.multiply(c).mod(p);
+ r = r.multiply(b).mod(p);
+ }
+ return r;
+ }
+
+ public static ECPoint fromX962(byte[] data, EllipticCurve curve) {
+ if (data == null) {
+ return null;
+ }
+ if (data[0] == 0x04 || data[0] == 0x06 || data[0] == 0x07) {
+ int len = (data.length - 1) / 2;
+ byte[] xbytes = new byte[len];
+ System.arraycopy(data, 1, xbytes, 0, len);
+ byte[] ybytes = new byte[len];
+ System.arraycopy(data, 1 + len, ybytes, 0, len);
+ return new ECPoint(new BigInteger(1, xbytes), new BigInteger(1, ybytes));
+ } else if (data[0] == 0x02 || data[0] == 0x03) {
+ if (curve == null) {
+ throw new IllegalArgumentException();
+ }
+ byte[] xbytes = new byte[data.length - 1];
+ System.arraycopy(data, 1, xbytes, 0, data.length - 1);
+ BigInteger x = new BigInteger(1, xbytes);
+ BigInteger a = curve.getA();
+ BigInteger b = curve.getB();
+
+ ECField field = curve.getField();
+ if (field instanceof ECFieldFp) {
+ BigInteger p = ((ECFieldFp) field).getP();
+ BigInteger alpha = x.modPow(BigInteger.valueOf(3), p);
+ alpha = alpha.add(x.multiply(a));
+ alpha = alpha.add(b);
+
+ BigInteger beta = modSqrt(alpha, p);
+ if (beta.getLowestSetBit() == 0) {
+ // rightmost bit is one
+ if (data[0] == 0x02) {
+ beta = beta.negate();
+ }
+ } else {
+ // rightmost bit is zero
+ if (data[0] == 0x03) {
+ beta = beta.negate();
+ }
+ }
+
+ return new ECPoint(x, beta);
+ } else if (field instanceof ECFieldF2m) {
+ //TODO
+ throw new UnsupportedOperationException();
+ }
+ return null;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/data/EC_Store.java b/src/cz/crcs/ectester/data/EC_Store.java
index 9b1f5bb..e4ba40c 100644
--- a/src/cz/crcs/ectester/data/EC_Store.java
+++ b/src/cz/crcs/ectester/data/EC_Store.java
@@ -1,7 +1,6 @@
package cz.crcs.ectester.data;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.reader.ec.*;
+import cz.crcs.ectester.common.ec.*;
import javacard.security.KeyPair;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -30,12 +29,11 @@ import java.util.TreeMap;
* @author Jan Jancar johny@neuromancer.sk
*/
public class EC_Store {
-
private DocumentBuilder db;
-
private Map<String, EC_Category> categories;
+ private static EC_Store instance;
- public EC_Store() throws IOException {
+ private EC_Store() {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
@@ -84,7 +82,7 @@ public class EC_Store {
});
parse();
- } catch (ParserConfigurationException | SAXException e) {
+ } catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
@@ -217,25 +215,7 @@ public class EC_Store {
descs = descc.item(0).getTextContent();
}
- byte kab = EC_Consts.KA_ANY;
- switch (ka.getTextContent()) {
- case "DH":
- case "ECDH":
- kab = EC_Consts.KA_ECDH;
- break;
- case "DHC":
- case "ECDHC":
- kab = EC_Consts.KA_ECDHC;
- break;
- case "ANY":
- kab = EC_Consts.KA_ANY;
- break;
- case "BOTH":
- kab = EC_Consts.KA_BOTH;
- break;
- }
-
- EC_KAResult kaResult = new EC_KAResult(id.getTextContent(), kab, curve.getTextContent(), onekey.getTextContent(), otherkey.getTextContent(), descs);
+ EC_KAResult kaResult = new EC_KAResult(id.getTextContent(), ka.getTextContent(), curve.getTextContent(), onekey.getTextContent(), otherkey.getTextContent(), descs);
InputStream csv = parseDataElement(dir, elem);
if (!kaResult.readCSV(csv)) {
@@ -339,4 +319,11 @@ public class EC_Store {
return getObject(objClass, query.substring(0, split), query.substring(split + 1));
}
+ public static EC_Store getInstance() {
+ if (instance == null) {
+ instance = new EC_Store();
+ }
+ return instance;
+ }
+
}
diff --git a/src/cz/crcs/ectester/data/categories.xml b/src/cz/crcs/ectester/data/categories.xml
index 750fa8c..f123b6a 100644
--- a/src/cz/crcs/ectester/data/categories.xml
+++ b/src/cz/crcs/ectester/data/categories.xml
@@ -47,8 +47,18 @@
<desc></desc>
</category>
<category>
+ <name>twist</name>
+ <directory>twist</directory>
+ <desc></desc>
+ </category>
+ <category>
<name>test</name>
<directory>test</directory>
<desc>Test vectors</desc>
</category>
+ <category>
+ <name>x962</name>
+ <directory>x962</directory>
+ <desc>ANSI X9.62 example curves.</desc>
+ </category>
</categories> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/nist/b163.csv b/src/cz/crcs/ectester/data/nist/b163.csv
index 9259308..85b777b 100644
--- a/src/cz/crcs/ectester/data/nist/b163.csv
+++ b/src/cz/crcs/ectester/data/nist/b163.csv
@@ -1 +1 @@
-00a3,0007,0006,0003,000000000000000000000000000000000000000001,020a601907b8c953ca1481eb10512f78744a3205fd,03f0eba16286a2d57ea0991168d4994637e8343e36,00d51fbc6c71a0094fa2cdd545b11c5c0c797324f1,040000000000000000000292fe77e70c12a4234c33,2 \ No newline at end of file
+0x00a3,0x0007,0x0006,0x0003,0x000000000000000000000000000000000000000001,0x020a601907b8c953ca1481eb10512f78744a3205fd,0x03f0eba16286a2d57ea0991168d4994637e8343e36,0x00d51fbc6c71a0094fa2cdd545b11c5c0c797324f1,0x040000000000000000000292fe77e70c12a4234c33,0x2
diff --git a/src/cz/crcs/ectester/data/nist/b233.csv b/src/cz/crcs/ectester/data/nist/b233.csv
index 79f0e85..a9c2711 100644
--- a/src/cz/crcs/ectester/data/nist/b233.csv
+++ b/src/cz/crcs/ectester/data/nist/b233.csv
@@ -1 +1 @@
-00e9,004a,0000,0000,000000000000000000000000000000000000000000000000000000000001,0066647ede6c332c7f8c0923bb58213b333b20e9ce4281fe115f7d8f90ad,00fac9dfcbac8313bb2139f1bb755fef65bc391f8b36f8f8eb7371fd558b,01006a08a41903350678e58528bebf8a0beff867a7ca36716f7e01f81052,1000000000000000000000000000013e974e72f8a6922031d2603cfe0d7,2 \ No newline at end of file
+0x00e9,0x004a,0x0000,0x0000,0x000000000000000000000000000000000000000000000000000000000001,0x0066647ede6c332c7f8c0923bb58213b333b20e9ce4281fe115f7d8f90ad,0x00fac9dfcbac8313bb2139f1bb755fef65bc391f8b36f8f8eb7371fd558b,0x01006a08a41903350678e58528bebf8a0beff867a7ca36716f7e01f81052,0x1000000000000000000000000000013e974e72f8a6922031d2603cfe0d7,0x2
diff --git a/src/cz/crcs/ectester/data/nist/b283.csv b/src/cz/crcs/ectester/data/nist/b283.csv
index 88506b3..06cc151 100644
--- a/src/cz/crcs/ectester/data/nist/b283.csv
+++ b/src/cz/crcs/ectester/data/nist/b283.csv
@@ -1 +1 @@
-011b,000c,0007,0005,00000000000000000000000000000000000000000000000000000000000000000000001,27b680ac8b8596da5a4af8a19a0303fca97fd7645309fa2a581485af6263e313b79a2f5,5f939258db7dd90e1934f8c70b0dfec2eed25b8557eac9c80e2e198f8cdbecd86b12053,3676854fe24141cb98fe6d4b20d02b4516ff702350eddb0826779c813f0df45be8112f4,3ffffffffffffffffffffffffffffffffffef90399660fc938a90165b042a7cefadb307,2 \ No newline at end of file
+0x011b,0x000c,0x0007,0x0005,0x00000000000000000000000000000000000000000000000000000000000000000000001,0x27b680ac8b8596da5a4af8a19a0303fca97fd7645309fa2a581485af6263e313b79a2f5,0x5f939258db7dd90e1934f8c70b0dfec2eed25b8557eac9c80e2e198f8cdbecd86b12053,0x3676854fe24141cb98fe6d4b20d02b4516ff702350eddb0826779c813f0df45be8112f4,0x3ffffffffffffffffffffffffffffffffffef90399660fc938a90165b042a7cefadb307,0x2
diff --git a/src/cz/crcs/ectester/data/nist/b409.csv b/src/cz/crcs/ectester/data/nist/b409.csv
index ed5ef5b..66523a7 100644
--- a/src/cz/crcs/ectester/data/nist/b409.csv
+++ b/src/cz/crcs/ectester/data/nist/b409.csv
@@ -1,9 +1 @@
-0199,0057,0000,0000,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,021a5c2c8ee9feb5c4b9a753b7b476b7fd6422ef1f3dd674761fa99d6ac27c8a9a197b272822f6cd57a55aa4f50ae317b13545f,15d4860d088ddb3496b0c6064756260441cde4af1771d4db01ffe5b34e59703dc255a868a1180515603aeab60794e54bb7996a7,061b1cfab6be5f32bbfa78324ed106a7636b9c5a7bd198d0158aa4f5488d08f38514f1fdf4b4f40d2181b3681c364ba0273c706,10000000000000000000000000000000000000000000000000001e2aad6a612f33307be5fa47c3c9e052f838164cd37d9a21173,2
-
-
-
-
-
-
-
-
+0x0199,0x0057,0x0000,0x0000,0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x021a5c2c8ee9feb5c4b9a753b7b476b7fd6422ef1f3dd674761fa99d6ac27c8a9a197b272822f6cd57a55aa4f50ae317b13545f,0x15d4860d088ddb3496b0c6064756260441cde4af1771d4db01ffe5b34e59703dc255a868a1180515603aeab60794e54bb7996a7,0x061b1cfab6be5f32bbfa78324ed106a7636b9c5a7bd198d0158aa4f5488d08f38514f1fdf4b4f40d2181b3681c364ba0273c706,0x10000000000000000000000000000000000000000000000000001e2aad6a612f33307be5fa47c3c9e052f838164cd37d9a21173,0x2
diff --git a/src/cz/crcs/ectester/data/nist/b571.csv b/src/cz/crcs/ectester/data/nist/b571.csv
index c0bef32..7d824c4 100644
--- a/src/cz/crcs/ectester/data/nist/b571.csv
+++ b/src/cz/crcs/ectester/data/nist/b571.csv
@@ -1 +1 @@
-023b,000a,0005,0002,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,2f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a,303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19,37bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b,3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47,2 \ No newline at end of file
+0x023b,0x000a,0x0005,0x0002,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x2f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a,0x303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19,0x37bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b,0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47,0x2
diff --git a/src/cz/crcs/ectester/data/nist/k163.csv b/src/cz/crcs/ectester/data/nist/k163.csv
index 21c2f5f..e35fbda 100644
--- a/src/cz/crcs/ectester/data/nist/k163.csv
+++ b/src/cz/crcs/ectester/data/nist/k163.csv
@@ -1 +1 @@
-00a3,0007,0006,0003,000000000000000000000000000000000000000001,000000000000000000000000000000000000000001,02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8,0289070fb05d38ff58321f2e800536d538ccdaa3d9,04000000000000000000020108a2e0cc0d99f8a5ef,2 \ No newline at end of file
+0x00a3,0x0007,0x0006,0x0003,0x000000000000000000000000000000000000000001,0x000000000000000000000000000000000000000001,0x02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8,0x0289070fb05d38ff58321f2e800536d538ccdaa3d9,0x04000000000000000000020108a2e0cc0d99f8a5ef,0x2
diff --git a/src/cz/crcs/ectester/data/nist/k233.csv b/src/cz/crcs/ectester/data/nist/k233.csv
index 45e3c49..a429d81 100644
--- a/src/cz/crcs/ectester/data/nist/k233.csv
+++ b/src/cz/crcs/ectester/data/nist/k233.csv
@@ -1 +1 @@
-00e9,004a,0000,0000,000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000001,017232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126,01db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3,8000000000000000000000000000069d5bb915bcd46efb1ad5f173abdf,4 \ No newline at end of file
+0x00e9,0x004a,0x0000,0x0000,0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001,0x017232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126,0x01db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3,0x8000000000000000000000000000069d5bb915bcd46efb1ad5f173abdf,0x4
diff --git a/src/cz/crcs/ectester/data/nist/k283.csv b/src/cz/crcs/ectester/data/nist/k283.csv
index b0e2800..32dcc3e 100644
--- a/src/cz/crcs/ectester/data/nist/k283.csv
+++ b/src/cz/crcs/ectester/data/nist/k283.csv
@@ -1 +1 @@
-011b,000c,0007,0005,00000000000000000000000000000000000000000000000000000000000000000000000,00000000000000000000000000000000000000000000000000000000000000000000001,503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836,1ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259,1ffffffffffffffffffffffffffffffffffe9ae2ed07577265dff7f94451e061e163c61,4 \ No newline at end of file
+0x011b,0x000c,0x0007,0x0005,0x00000000000000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000000000000000000000000000000000000000000000000001,0x503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836,0x1ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259,0x1ffffffffffffffffffffffffffffffffffe9ae2ed07577265dff7f94451e061e163c61,0x4
diff --git a/src/cz/crcs/ectester/data/nist/k409.csv b/src/cz/crcs/ectester/data/nist/k409.csv
index fc44b82..119754a 100644
--- a/src/cz/crcs/ectester/data/nist/k409.csv
+++ b/src/cz/crcs/ectester/data/nist/k409.csv
@@ -1 +1 @@
-0199,0057,0000,0000,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,060f05f658f49c1ad3ab1890f7184210efd0987e307c84c27accfb8f9f67cc2c460189eb5aaaa62ee222eb1b35540cfe9023746,1e369050b7c4e42acba1dacbf04299c3460782f918ea427e6325165e9ea10e3da5f6c42e9c55215aa9ca27a5863ec48d8e0286b,7ffffffffffffffffffffffffffffffffffffffffffffffffffe5f83b2d4ea20400ec4557d5ed3e3e7ca5b4b5c83b8e01e5fcf,4 \ No newline at end of file
+0x0199,0x0057,0x0000,0x0000,0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x060f05f658f49c1ad3ab1890f7184210efd0987e307c84c27accfb8f9f67cc2c460189eb5aaaa62ee222eb1b35540cfe9023746,0x1e369050b7c4e42acba1dacbf04299c3460782f918ea427e6325165e9ea10e3da5f6c42e9c55215aa9ca27a5863ec48d8e0286b,0x7ffffffffffffffffffffffffffffffffffffffffffffffffffe5f83b2d4ea20400ec4557d5ed3e3e7ca5b4b5c83b8e01e5fcf,0x4
diff --git a/src/cz/crcs/ectester/data/nist/k571.csv b/src/cz/crcs/ectester/data/nist/k571.csv
index 5660f6a..7fb1431 100644
--- a/src/cz/crcs/ectester/data/nist/k571.csv
+++ b/src/cz/crcs/ectester/data/nist/k571.csv
@@ -1 +1 @@
-023b,000a,0005,0002,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,26eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972,349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3,20000000000000000000000000000000000000000000000000000000000000000000000131850e1f19a63e4b391a8db917f4138b630d84be5d639381e91deb45cfe778f637c1001,4 \ No newline at end of file
+0x023b,0x000a,0x0005,0x0002,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x26eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972,0x349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3,0x20000000000000000000000000000000000000000000000000000000000000000000000131850e1f19a63e4b391a8db917f4138b630d84be5d639381e91deb45cfe778f637c1001,0x4
diff --git a/src/cz/crcs/ectester/data/secg/sect163k1.csv b/src/cz/crcs/ectester/data/secg/sect163k1.csv
index 21c2f5f..e35fbda 100644
--- a/src/cz/crcs/ectester/data/secg/sect163k1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect163k1.csv
@@ -1 +1 @@
-00a3,0007,0006,0003,000000000000000000000000000000000000000001,000000000000000000000000000000000000000001,02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8,0289070fb05d38ff58321f2e800536d538ccdaa3d9,04000000000000000000020108a2e0cc0d99f8a5ef,2 \ No newline at end of file
+0x00a3,0x0007,0x0006,0x0003,0x000000000000000000000000000000000000000001,0x000000000000000000000000000000000000000001,0x02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8,0x0289070fb05d38ff58321f2e800536d538ccdaa3d9,0x04000000000000000000020108a2e0cc0d99f8a5ef,0x2
diff --git a/src/cz/crcs/ectester/data/secg/sect163r1.csv b/src/cz/crcs/ectester/data/secg/sect163r1.csv
index a537e6f..fa7a328 100644
--- a/src/cz/crcs/ectester/data/secg/sect163r1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect163r1.csv
@@ -1 +1 @@
-00a3,0007,0006,0003,07b6882caaefa84f9554ff8428bd88e246d2782ae2,0713612dcddcb40aab946bda29ca91f73af958afd9,0369979697ab43897789566789567f787a7876a654,00435edb42efafb2989d51fefce3c80988f41ff883,03ffffffffffffffffffff48aab689c29ca710279b,2 \ No newline at end of file
+0x00a3,0x0007,0x0006,0x0003,0x07b6882caaefa84f9554ff8428bd88e246d2782ae2,0x0713612dcddcb40aab946bda29ca91f73af958afd9,0x0369979697ab43897789566789567f787a7876a654,0x00435edb42efafb2989d51fefce3c80988f41ff883,0x03ffffffffffffffffffff48aab689c29ca710279b,0x2
diff --git a/src/cz/crcs/ectester/data/secg/sect163r2.csv b/src/cz/crcs/ectester/data/secg/sect163r2.csv
index 9259308..85b777b 100644
--- a/src/cz/crcs/ectester/data/secg/sect163r2.csv
+++ b/src/cz/crcs/ectester/data/secg/sect163r2.csv
@@ -1 +1 @@
-00a3,0007,0006,0003,000000000000000000000000000000000000000001,020a601907b8c953ca1481eb10512f78744a3205fd,03f0eba16286a2d57ea0991168d4994637e8343e36,00d51fbc6c71a0094fa2cdd545b11c5c0c797324f1,040000000000000000000292fe77e70c12a4234c33,2 \ No newline at end of file
+0x00a3,0x0007,0x0006,0x0003,0x000000000000000000000000000000000000000001,0x020a601907b8c953ca1481eb10512f78744a3205fd,0x03f0eba16286a2d57ea0991168d4994637e8343e36,0x00d51fbc6c71a0094fa2cdd545b11c5c0c797324f1,0x040000000000000000000292fe77e70c12a4234c33,0x2
diff --git a/src/cz/crcs/ectester/data/secg/sect233k1.csv b/src/cz/crcs/ectester/data/secg/sect233k1.csv
index 45e3c49..a429d81 100644
--- a/src/cz/crcs/ectester/data/secg/sect233k1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect233k1.csv
@@ -1 +1 @@
-00e9,004a,0000,0000,000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000001,017232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126,01db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3,8000000000000000000000000000069d5bb915bcd46efb1ad5f173abdf,4 \ No newline at end of file
+0x00e9,0x004a,0x0000,0x0000,0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001,0x017232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126,0x01db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3,0x8000000000000000000000000000069d5bb915bcd46efb1ad5f173abdf,0x4
diff --git a/src/cz/crcs/ectester/data/secg/sect233r1.csv b/src/cz/crcs/ectester/data/secg/sect233r1.csv
index 8f27bc2..faba42b 100644
--- a/src/cz/crcs/ectester/data/secg/sect233r1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect233r1.csv
@@ -1 +1 @@
-00e9,004a,0000,0000,000000000000000000000000000000000000000000000000000000000001,0066647ede6c332c7f8c0923bb58213b333b20e9ce4281fe115f7d8f90ad,00fac9dfcbac8313bb2139f1bb755fef65bc391f8b36f8f8eb7371fd558b,01006a08a41903350678e58528bebf8a0beff867a7ca36716f7e01f81052,01000000000000000000000000000013e974e72f8a6922031d2603cfe0d7,2 \ No newline at end of file
+0x00e9,0x004a,0x0000,0x0000,0x000000000000000000000000000000000000000000000000000000000001,0x0066647ede6c332c7f8c0923bb58213b333b20e9ce4281fe115f7d8f90ad,0x00fac9dfcbac8313bb2139f1bb755fef65bc391f8b36f8f8eb7371fd558b,0x01006a08a41903350678e58528bebf8a0beff867a7ca36716f7e01f81052,0x01000000000000000000000000000013e974e72f8a6922031d2603cfe0d7,0x2
diff --git a/src/cz/crcs/ectester/data/secg/sect239k1.csv b/src/cz/crcs/ectester/data/secg/sect239k1.csv
index 187316f..8b2e58a 100644
--- a/src/cz/crcs/ectester/data/secg/sect239k1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect239k1.csv
@@ -1 +1 @@
-00ef,009e,0000,0000,000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000001,29a0b6a887a983e9730988a68727a8b2d126c44cc2cc7b2a6555193035dc,76310804f12e549bdb011c103089e73510acb275fc312a5dc6b76553f0ca,2000000000000000000000000000005a79fec67cb6e91f1c1da800e478a5,4 \ No newline at end of file
+0x00ef,0x009e,0x0000,0x0000,0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001,0x29a0b6a887a983e9730988a68727a8b2d126c44cc2cc7b2a6555193035dc,0x76310804f12e549bdb011c103089e73510acb275fc312a5dc6b76553f0ca,0x2000000000000000000000000000005a79fec67cb6e91f1c1da800e478a5,0x4
diff --git a/src/cz/crcs/ectester/data/secg/sect283k1.csv b/src/cz/crcs/ectester/data/secg/sect283k1.csv
index fde7306..9a3a8f6 100644
--- a/src/cz/crcs/ectester/data/secg/sect283k1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect283k1.csv
@@ -1 +1 @@
-011b,000c,0007,0005,000000000000000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000000000000000001,0503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836,01ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259,01ffffffffffffffffffffffffffffffffffe9ae2ed07577265dff7f94451e061e163c61,4
+0x011b,0x000c,0x0007,0x0005,0x000000000000000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000000000000000001,0x0503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836,0x01ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259,0x01ffffffffffffffffffffffffffffffffffe9ae2ed07577265dff7f94451e061e163c61,0x4
diff --git a/src/cz/crcs/ectester/data/secg/sect283r1.csv b/src/cz/crcs/ectester/data/secg/sect283r1.csv
index ff75b55..68c17f6 100644
--- a/src/cz/crcs/ectester/data/secg/sect283r1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect283r1.csv
@@ -1 +1 @@
-011b,000c,0007,0005,000000000000000000000000000000000000000000000000000000000000000000000001,027b680ac8b8596da5a4af8a19a0303fca97fd7645309fa2a581485af6263e313b79a2f5,05f939258db7dd90e1934f8c70b0dfec2eed25b8557eac9c80e2e198f8cdbecd86b12053,03676854fe24141cb98fe6d4b20d02b4516ff702350eddb0826779c813f0df45be8112f4,03ffffffffffffffffffffffffffffffffffef90399660fc938a90165b042a7cefadb307,2 \ No newline at end of file
+0x011b,0x000c,0x0007,0x0005,0x000000000000000000000000000000000000000000000000000000000000000000000001,0x027b680ac8b8596da5a4af8a19a0303fca97fd7645309fa2a581485af6263e313b79a2f5,0x05f939258db7dd90e1934f8c70b0dfec2eed25b8557eac9c80e2e198f8cdbecd86b12053,0x03676854fe24141cb98fe6d4b20d02b4516ff702350eddb0826779c813f0df45be8112f4,0x03ffffffffffffffffffffffffffffffffffef90399660fc938a90165b042a7cefadb307,0x2
diff --git a/src/cz/crcs/ectester/data/secg/sect409k1.csv b/src/cz/crcs/ectester/data/secg/sect409k1.csv
index 4c88afb..e39e076 100644
--- a/src/cz/crcs/ectester/data/secg/sect409k1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect409k1.csv
@@ -1 +1 @@
-0199,0057,0000,0000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0060f05f658f49c1ad3ab1890f7184210efd0987e307c84c27accfb8f9f67cc2c460189eb5aaaa62ee222eb1b35540cfe9023746,01e369050b7c4e42acba1dacbf04299c3460782f918ea427e6325165e9ea10e3da5f6c42e9c55215aa9ca27a5863ec48d8e0286b,7ffffffffffffffffffffffffffffffffffffffffffffffffffe5f83b2d4ea20400ec4557d5ed3e3e7ca5b4b5c83b8e01e5fcf,4 \ No newline at end of file
+0x0199,0x0057,0x0000,0x0000,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x0060f05f658f49c1ad3ab1890f7184210efd0987e307c84c27accfb8f9f67cc2c460189eb5aaaa62ee222eb1b35540cfe9023746,0x01e369050b7c4e42acba1dacbf04299c3460782f918ea427e6325165e9ea10e3da5f6c42e9c55215aa9ca27a5863ec48d8e0286b,0x7ffffffffffffffffffffffffffffffffffffffffffffffffffe5f83b2d4ea20400ec4557d5ed3e3e7ca5b4b5c83b8e01e5fcf,0x4
diff --git a/src/cz/crcs/ectester/data/secg/sect409r1.csv b/src/cz/crcs/ectester/data/secg/sect409r1.csv
index b3d72d6..727fb25 100644
--- a/src/cz/crcs/ectester/data/secg/sect409r1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect409r1.csv
@@ -1 +1 @@
-0199,0057,0000,0000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0021a5c2c8ee9feb5c4b9a753b7b476b7fd6422ef1f3dd674761fa99d6ac27c8a9a197b272822f6cd57a55aa4f50ae317b13545f,015d4860d088ddb3496b0c6064756260441cde4af1771d4db01ffe5b34e59703dc255a868a1180515603aeab60794e54bb7996a7,0061b1cfab6be5f32bbfa78324ed106a7636b9c5a7bd198d0158aa4f5488d08f38514f1fdf4b4f40d2181b3681c364ba0273c706,010000000000000000000000000000000000000000000000000001e2aad6a612f33307be5fa47c3c9e052f838164cd37d9a21173,2 \ No newline at end of file
+0x0199,0x0057,0x0000,0x0000,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x0021a5c2c8ee9feb5c4b9a753b7b476b7fd6422ef1f3dd674761fa99d6ac27c8a9a197b272822f6cd57a55aa4f50ae317b13545f,0x015d4860d088ddb3496b0c6064756260441cde4af1771d4db01ffe5b34e59703dc255a868a1180515603aeab60794e54bb7996a7,0x0061b1cfab6be5f32bbfa78324ed106a7636b9c5a7bd198d0158aa4f5488d08f38514f1fdf4b4f40d2181b3681c364ba0273c706,0x010000000000000000000000000000000000000000000000000001e2aad6a612f33307be5fa47c3c9e052f838164cd37d9a21173,0x2
diff --git a/src/cz/crcs/ectester/data/secg/sect571k1.csv b/src/cz/crcs/ectester/data/secg/sect571k1.csv
index 72488e5..0c94778 100644
--- a/src/cz/crcs/ectester/data/secg/sect571k1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect571k1.csv
@@ -1 +1 @@
-023b,000a,0005,0002,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,026eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972,0349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3,020000000000000000000000000000000000000000000000000000000000000000000000131850e1f19a63e4b391a8db917f4138b630d84be5d639381e91deb45cfe778f637c1001,4 \ No newline at end of file
+0x023b,0x000a,0x0005,0x0002,0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x026eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972,0x0349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3,0x020000000000000000000000000000000000000000000000000000000000000000000000131850e1f19a63e4b391a8db917f4138b630d84be5d639381e91deb45cfe778f637c1001,0x4
diff --git a/src/cz/crcs/ectester/data/secg/sect571r1.csv b/src/cz/crcs/ectester/data/secg/sect571r1.csv
index 4bba9a0..739cbb0 100644
--- a/src/cz/crcs/ectester/data/secg/sect571r1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect571r1.csv
@@ -1 +1 @@
-023b,000a,0005,0002,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,02f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a,0303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19,037bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b,03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47,2 \ No newline at end of file
+0x023b,0x000a,0x0005,0x0002,0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x02f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a,0x0303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19,0x037bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b,0x03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47,0x2
diff --git a/src/cz/crcs/ectester/data/twist/keys.xml b/src/cz/crcs/ectester/data/twist/keys.xml
new file mode 100644
index 0000000..1acbc31
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/keys.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE keys [
+ <!ENTITY k163 SYSTEM "twist/nist/k163.xml">
+ <!ENTITY k233 SYSTEM "twist/nist/k233.xml">
+ <!ENTITY k283 SYSTEM "twist/nist/k283.xml">
+ <!ENTITY b163 SYSTEM "twist/nist/b163.xml">
+ <!ENTITY b233 SYSTEM "twist/nist/b233.xml">
+ <!ENTITY b283 SYSTEM "twist/nist/b283.xml">
+
+ <!ENTITY secp112r1 SYSTEM "twist/secg/secp112r1.xml">
+ <!ENTITY secp112r2 SYSTEM "twist/secg/secp112r2.xml">
+ <!ENTITY secp128r1 SYSTEM "twist/secg/secp128r1.xml">
+ <!ENTITY secp128r2 SYSTEM "twist/secg/secp128r2.xml">
+ <!ENTITY secp160k1 SYSTEM "twist/secg/secp160k1.xml">
+ <!ENTITY secp160r1 SYSTEM "twist/secg/secp160r1.xml">
+ <!ENTITY secp160r2 SYSTEM "twist/secg/secp160r2.xml">
+ <!ENTITY secp192k1 SYSTEM "twist/secg/secp192k1.xml">
+ <!ENTITY secp192r1 SYSTEM "twist/secg/secp192r1.xml">
+ <!ENTITY secp224r1 SYSTEM "twist/secg/secp224r1.xml">
+ <!ENTITY secp256k1 SYSTEM "twist/secg/secp256k1.xml">
+ <!ENTITY secp256r1 SYSTEM "twist/secg/secp256r1.xml">
+ <!ENTITY secp384r1 SYSTEM "twist/secg/secp384r1.xml">
+ <!ENTITY secp521r1 SYSTEM "twist/secg/secp521r1.xml">
+ ]>
+<keys xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd"
+ category="twist"
+ desc="">
+ &k163;
+ &k233;
+ &k283;
+ &b163;
+ &b233;
+ &b283;
+
+ &secp112r1;
+ &secp112r2;
+ &secp128r1;
+ &secp128r2;
+ &secp160k1;
+ &secp160r1;
+ &secp160r2;
+ &secp192k1;
+ &secp192r1;
+ &secp224r1;
+ &secp256k1;
+ &secp256r1;
+ &secp384r1;
+ &secp521r1;
+</keys> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/twist/nist/b163.xml b/src/cz/crcs/ectester/data/twist/nist/b163.xml
new file mode 100644
index 0000000..03690ac
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/b163.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>b163/0</id>
+ <inline>0x000000000000000000000000000000000000000000,0x02c25b85badf8927593d21c366da89c03969f34da5</inline>
+ <curve>nist/B-163</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>b163/1</id>
+ <inline>0x03a98eb9fc1007f0a2b0e8de7da23cc6a7f7dd76b1,0x019971752926a2aca5407bffbf2a73f3f884b97127</inline>
+ <curve>nist/B-163</curve>
+ <desc>twist order = 0x1f</desc>
+</pubkey>
+<pubkey>
+ <id>b163/2</id>
+ <inline>0x023ae22e69bac70ca24078fdf63753eaf6cb89e857,0x03674a33443dc657c24685eb761ab7efbb63a8adbc</inline>
+ <curve>nist/B-163</curve>
+ <desc>twist order = 0x38b</desc>
+</pubkey>
+<pubkey>
+ <id>b163/3</id>
+ <inline>0x04feb095cf083a783cac4107305889efa9f401cc27,0x0403abb00aa4712e4b9120391d59745e9fbad39db3</inline>
+ <curve>nist/B-163</curve>
+ <desc>twist order = 0x1208485</desc>
+</pubkey>
+<pubkey>
+ <id>b163/4</id>
+ <inline>0x00a72a640e05acc0e6c6956ab5be24240b92623add,0x031dfc8af709b3db0a05126f17a7b4d703de503475</inline>
+ <curve>nist/B-163</curve>
+ <desc>twist order = 0xb78fc77</desc>
+</pubkey>
+<pubkey>
+ <id>b163/5</id>
+ <inline>0x031b5fc734d73023a06e4fe1b7921811221c6d1b2a,0x05432357b4a42a7b8f51b04dfab95a5ecf03547500</inline>
+ <curve>nist/B-163</curve>
+ <desc>twist order = 0x5c4bf9b1205a07afbe718429</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/nist/b233.xml b/src/cz/crcs/ectester/data/twist/nist/b233.xml
new file mode 100644
index 0000000..7a0b579
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/b233.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>b233/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000000000000000,0x0187f85627b97874e747ee31e06d71caaeea52f21253e5f946d061da9138</inline>
+ <curve>nist/B-233</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>b233/1</id>
+ <inline>0x01143eef5ed49cf4b4c552259589988a019e98418c012194a255e9186870,0x01f8070b0ef657563e5d584ce23fc58ef70265d4178d78717c6acebb8c78</inline>
+ <curve>nist/B-233</curve>
+ <desc>twist order = 0x5</desc>
+</pubkey>
+<pubkey>
+ <id>b233/2</id>
+ <inline>0x01c8185b4f7d07a7eca7deb9f2adcd3c9402461f8679cbc9618ad1d82be3,0x002d17d4fa7eafbf4f6238b94ddc95f6a56384a4028f50e7de1838c21c8c</inline>
+ <curve>nist/B-233</curve>
+ <desc>twist order = 0x11b</desc>
+</pubkey>
+<pubkey>
+ <id>b233/3</id>
+ <inline>0x01af53fdcb81b561803cb01ba4d384fa3ef7633b1c0dfb35f0e437ffc201,0x012a092d0b600cc59c2234ae65261513eee7a085428b2b42e96253b1143e</inline>
+ <curve>nist/B-233</curve>
+ <desc>twist order = 0x21d</desc>
+</pubkey>
+<pubkey>
+ <id>b233/4</id>
+ <inline>0x01f4b2e29d7a3796e3aa4a6b3ff40805d322292acefd80149ff954d75e04,0x00df2f3258674f799c4dcc8cef118abb4c00abf0c1f10144b47af7a6f41b</inline>
+ <curve>nist/B-233</curve>
+ <desc>twist order = 0x22dba0b9</desc>
+</pubkey>
+<pubkey>
+ <id>b233/5</id>
+ <inline>0x01b6b9ce48a1428cb554a76a3f659d8b443ebee6b5619c88100bf3f83bb1,0x00dcafc85dfc3758e99736abe5ed2c4f03cbed5a3b478c9e233b976f7258</inline>
+ <curve>nist/B-233</curve>
+ <desc>twist order = 0x2a7504c0fda95a2311</desc>
+</pubkey>
+<pubkey>
+ <id>b233/6</id>
+ <inline>0x015cc90c0fdc2fc5fefddf1e9890627f87250b74fbaacd77feb761085d59,0x00059ccb49d156720dd3bcd75438225df9f9e84e7ffc0fc0dda02a647613</inline>
+ <curve>nist/B-233</curve>
+ <desc>twist order = 0x1e53fa33649df4ef97d6b29ded5a7</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/nist/b283.xml b/src/cz/crcs/ectester/data/twist/nist/b283.xml
new file mode 100644
index 0000000..7f57585
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/b283.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>b283/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000000000000000000000000000,0x072bcc9c5792b1ebe81983089fb6f835a2fd220a304424ca17c082ae17442aede9b9b3f6</inline>
+ <curve>nist/B-283</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>b283/1</id>
+ <inline>0x0297e6d1f2b857a79f5dc85c2f1259d5d801c61a4d0a4312a04f65f09a887a7b93cf7ae1,0x051963c38ac61f05fef93707abcfbda7bc0f39eacddb2bdd3077f19c0e65c8be66ecb30e</inline>
+ <curve>nist/B-283</curve>
+ <desc>twist order = 0x7</desc>
+</pubkey>
+<pubkey>
+ <id>b283/2</id>
+ <inline>0x022b522e9e120300e74563dee496f8feb64209b858abd5da50f31c92ae4a1eee751c92d6,0x012647d0d771016622e899c2a54afad773907e42e15d45e1db3e4fb0ae6a6df2934dba63</inline>
+ <curve>nist/B-283</curve>
+ <desc>twist order = 0x13</desc>
+</pubkey>
+<pubkey>
+ <id>b283/3</id>
+ <inline>0x02597a5336d18d9effde2820bed7352dccc8824abc81cde80914ea3cd072da55e9f91368,0x04a6d2c92a1ee699cda25dafa88191ef34218e9ea5c996d37e9ce507c318e7649b3b02d9</inline>
+ <curve>nist/B-283</curve>
+ <desc>twist order = 0x1623ab619</desc>
+</pubkey>
+<pubkey>
+ <id>b283/4</id>
+ <inline>0x01b011689cef74d9b2be4e8fb548eeabe31a678f560fc7b893c330b3939da9451a0cff78,0x022fd9ba4762f742a18e299f035a837b0525d7030e6b061eaa9242237d0767e7c28b608d</inline>
+ <curve>nist/B-283</curve>
+ <desc>twist order = 0x2a4aa67aaaf5413fb</desc>
+</pubkey>
+<pubkey>
+ <id>b283/5</id>
+ <inline>0x06ac85dce72aa795b5b90d43849dec9d4ee0ffc4d41f87fe8d48de2ac3cf84dfc5c20263,0x008e5147dba15ff3cb287457b3f41d32ca6c074df014f85033368d982c1670907d6afa05</inline>
+ <curve>nist/B-283</curve>
+ <desc>twist order = 0x25a8cdb1f2e470f3ac1ba7</desc>
+</pubkey>
+<pubkey>
+ <id>b283/6</id>
+ <inline>0x0132803a996ebd53ffa3553fc994b583cdb9514e4476c79336acf72f82ac36add519e655,0x004d30604436960af06b2eab63027ca8f59ca105f505afcd3413e1e72f5fb9c0f29d3a20</inline>
+ <curve>nist/B-283</curve>
+ <desc>twist order = 0x606749a9c147da03ad3f37</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/nist/k163.xml b/src/cz/crcs/ectester/data/twist/nist/k163.xml
new file mode 100644
index 0000000..31040c0
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/k163.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>k163/0</id>
+ <inline>0x000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000001</inline>
+ <curve>nist/K-163</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>k163/1</id>
+ <inline>0x04410857858628f16bd3ef77fce6732525d6d75f6c,0x00c51e38c5eb613ff4c8b594d754a218f30e8b1c39</inline>
+ <curve>nist/K-163</curve>
+ <desc>twist order = 0x28d</desc>
+</pubkey>
+<pubkey>
+ <id>k163/2</id>
+ <inline>0x004c291913c2e75103b38481fbda3830850ee4c026,0x0403ff8ccadf20f12e10e40b8eed4872d4c128aaa2</inline>
+ <curve>nist/K-163</curve>
+ <desc>twist order = 0x1979</desc>
+</pubkey>
+<pubkey>
+ <id>k163/3</id>
+ <inline>0x03868f9f75e8d0056c6e1aabed4a3df1437a56b386,0x07473bb4e85044c95af468d5374da860c4e563159c</inline>
+ <curve>nist/K-163</curve>
+ <desc>twist order = 0x7926bec180108d</desc>
+</pubkey>
+<pubkey>
+ <id>k163/4</id>
+ <inline>0x0162deb07d5848fc45fd580549a6f17fecea1b7497,0x0297440c5cfd9e8fe781004db92f9f106b9d33235f</inline>
+ <curve>nist/K-163</curve>
+ <desc>twist order = 0x10a6989de57d15c65ba229</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/nist/k233.xml b/src/cz/crcs/ectester/data/twist/nist/k233.xml
new file mode 100644
index 0000000..6354ff9
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/k233.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>k233/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001</inline>
+ <curve>nist/K-233</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>k233/1</id>
+ <inline>0x01f5c35c89f8294442218a24a7e62ce3dac66c3ee5e9d2b70aaf51f520b2,0x001328eb45743dd96c4deaaa299b5394abfec9852e73a1e051a745fa95d8</inline>
+ <curve>nist/K-233</curve>
+ <desc>twist order = 0x1686d</desc>
+</pubkey>
+<pubkey>
+ <id>k233/2</id>
+ <inline>0x00959e63a797bf3b2ea48d328ea3a9985da6bc95f296d1fc5e8cf17c257c,0x0070034f2e503a97be8766dd6db086870eea2e3fcb02260e9fcc0df8704c</inline>
+ <curve>nist/K-233</curve>
+ <desc>twist order = 0x6d8a417</desc>
+</pubkey>
+<pubkey>
+ <id>k233/3</id>
+ <inline>0x00103cf39b9ffa6da7ef9f19f601daf698148663f6e0ae3b4ae2dca53782,0x013c1241644b61fb8c811287c2277c863eb0c31287e30d57d99169b1f509</inline>
+ <curve>nist/K-233</curve>
+ <desc>twist order = 0x7c02977</desc>
+</pubkey>
+<pubkey>
+ <id>k233/4</id>
+ <inline>0x003d84c97077988af52d6d825080c0c79276fc168e092260d67b5d4ca3a3,0x01d3fa5b63a25a8f08828117edb78a1ab31724ecfc74d4fc2c4b7ea00703</inline>
+ <curve>nist/K-233</curve>
+ <desc>twist order = 0x46403a035013f70d</desc>
+</pubkey>
+<pubkey>
+ <id>k233/5</id>
+ <inline>0x01a053f3903f7b9e7e5c8784b01e43fd427b7264781b1e6c7a8755065a38,0x01ed5e24cd66d3d42b4a869aee65bff9506a8cdbc9f3c3c86543ba14db12</inline>
+ <curve>nist/K-233</curve>
+ <desc>twist order = 0xc7cb3894752e561e6abf871db</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/nist/k283.xml b/src/cz/crcs/ectester/data/twist/nist/k283.xml
new file mode 100644
index 0000000..48a2dd9
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/k283.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>k283/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000000000000000001</inline>
+ <curve>nist/K-283</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>k283/1</id>
+ <inline>0x02707778aaa47f7a075be036522a6c2998ce118bf7e6314f342ba399dbc3572750791e4d,0x0568810a78107353690d1429cb7f4f408650cbf112d096907f563971baafad1b36436ec2</inline>
+ <curve>nist/K-283</curve>
+ <desc>twist order = 0x400000000000000000000000000000000002ca3a25f1511b3440100d775c3f3c3d3873f</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/nist/p192.xml b/src/cz/crcs/ectester/data/twist/nist/p192.xml
new file mode 100644
index 0000000..d1fdf49
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/p192.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>p192/0</id>
+ <inline>0x489ba2a146ac0e7bb9f008fb780005e48d3588893c7ebca9,0x7caac0b203223010fb59940946a12e35d227fcb3ee6c9afc</inline>
+ <curve>nist/P-192</curve>
+ <desc>twist order = 0x17</desc>
+</pubkey>
+<pubkey>
+ <id>p192/1</id>
+ <inline>0xfaebaecd2737a6c22b5023d236ad48ab9acacb2cac075379,0x43810e9a10dabc2f835af837ac83fc4f0225773f3a84103f</inline>
+ <curve>nist/P-192</curve>
+ <desc>twist order = 0x231acce82af76d32ca5d526f</desc>
+</pubkey>
+<pubkey>
+ <id>p192/2</id>
+ <inline>0x7af6e161dcb8cd7852d5102ab42974af5179706d4616cce0,0xa3177747f0de49227575d2afc449187ab546e9ab827fcac9</inline>
+ <curve>nist/P-192</curve>
+ <desc>twist order = 0x512b1bfde874086edba50007</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/nist/p224.xml b/src/cz/crcs/ectester/data/twist/nist/p224.xml
new file mode 100644
index 0000000..3ae34ff
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/p224.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>p224/0</id>
+ <inline>0x90427f4a141f94c26f98d40060292350fcace2356961ef27dda08d7b,0x58877d4992c377c33459aa0caeb0526881326f201beb519fc11aadc8</inline>
+ <curve>nist/P-224</curve>
+ <desc>twist order = 0x3</desc>
+</pubkey>
+<pubkey>
+ <id>p224/1</id>
+ <inline>0x7f87c1db4213f1032c251a514e324f4360390476e0f7cd025547df58,0x2498f43e46af6fa0ad6480cfd61fb40caa78e349db0766a8760ff021</inline>
+ <curve>nist/P-224</curve>
+ <desc>twist order = 0xb</desc>
+</pubkey>
+<pubkey>
+ <id>p224/2</id>
+ <inline>0x2a2d61174fd561e9da2f279b96f7a69ae50a78d87f09674f465c9184,0xc9c7232ca8a50587181d8c96204c1eec6e976bcbd58e3c7181dbb2a7</inline>
+ <curve>nist/P-224</curve>
+ <desc>twist order = 0x2f</desc>
+</pubkey>
+<pubkey>
+ <id>p224/3</id>
+ <inline>0x15da8f68bfe51bc75f0cd892f7400c3d5ce5a9c6da126171527767cc,0x0cee3612475887d31963b62c69580191d1158df3f0c0305765175c9c</inline>
+ <curve>nist/P-224</curve>
+ <desc>twist order = 0x2e0273</desc>
+</pubkey>
+<pubkey>
+ <id>p224/4</id>
+ <inline>0xbd813fcdea2281a452733516e4e2625fac96573c41f3b37c56d0d1d7,0x351de92e6b06928fec37ee0ffd03606fecc5022edc1a72453c433ef4</inline>
+ <curve>nist/P-224</curve>
+ <desc>twist order = 0x268160f</desc>
+</pubkey>
+<pubkey>
+ <id>p224/5</id>
+ <inline>0x2a379d972d016116067b5bf2c23937b6182b4dc6bf8aa0625eb58b9f,0xb9ec1e372728d3334a762e5d64faca1e0cd47f46c3e5402ff14cb140</inline>
+ <curve>nist/P-224</curve>
+ <desc>twist order = 0xf3bac7aa52cf</desc>
+</pubkey>
+<pubkey>
+ <id>p224/6</id>
+ <inline>0xc5e229bfc9f4e0992ecf51a3c354e6aac1a4673056bee9a673beae5a,0x73a2e7d530b13c281d460ea2d2c3bddb49a8eb3446b9308ec64d5a70</inline>
+ <curve>nist/P-224</curve>
+ <desc>twist order = 0x22340ff0f7eba57b33ac73e28a14d1</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/nist/p256.xml b/src/cz/crcs/ectester/data/twist/nist/p256.xml
new file mode 100644
index 0000000..2e1c55e
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/p256.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>p256/0</id>
+ <inline>0x92787586fc8a5d065a2a754e229a66ea3c845c8d5f7120792ee3aacee88ca01c,0xee95a42047d9eae3bb007aa7aed3a87ee6986df813f6c76d8f19866a1b1f9c20</inline>
+ <curve>nist/P-256</curve>
+ <desc>twist order = 0x3</desc>
+</pubkey>
+<pubkey>
+ <id>p256/1</id>
+ <inline>0x40d27c77cf9fb36e49a850b1ae7357c9ab3f1d917d52ba3edb648bd33354d3da,0xd30662382d8440919f4decbc58c6d9ca8745d39cdd71c26063fd2fa8bcbb69f7</inline>
+ <curve>nist/P-256</curve>
+ <desc>twist order = 0x5</desc>
+</pubkey>
+<pubkey>
+ <id>p256/2</id>
+ <inline>0x33961ae81d08958d1dbc42bdadb05e7cb7bdda383b1c49e18c3a2f5908c833a2,0xc4a96d4f905a1d7e32d4c82d6e79f1ef7047d09bf1d1518be2c65d13815306fe</inline>
+ <curve>nist/P-256</curve>
+ <desc>twist order = 0xd</desc>
+</pubkey>
+<pubkey>
+ <id>p256/3</id>
+ <inline>0x21fa3bf4b7d23dea73a1751d3b02dd8724a2a5a0ae9b28fdd98b8ef18bb610f5,0x7d933ab51ac8bc7e5d3c5a44d9875c64a080eba393c6492e4e5ce2367f133dd1</inline>
+ <curve>nist/P-256</curve>
+ <desc>twist order = 0xb3</desc>
+</pubkey>
+<pubkey>
+ <id>p256/4</id>
+ <inline>0x3819da45c7b025be543fd40ec49b2613891c12f2ae2daf014396c70270eff92c,0xbec84d62254dbc67864ced51966d4f419ad5b1ec9ee1d72cce291a8a034518da</inline>
+ <curve>nist/P-256</curve>
+ <desc>twist order = 0x1e0a75640070a738557cc30f68bd56eaea65c94f98411d17ac4e16ece1a47</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/nist/p384.xml b/src/cz/crcs/ectester/data/twist/nist/p384.xml
new file mode 100644
index 0000000..8e0d2b6
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/p384.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>p384/0</id>
+ <inline>0x77e3431a4d6b9d63985798eb41188f9af7eb6c0f38745d360bf82b5c2c162cb8393adf2dbc4d5531c49322d9c7b4c9cd,0x2b38ea158d3c980e9b3618cfe42599dd9d78e630ac83c66673949121ca6c8997fbf5e08c060076f3fa60d6dec8ac8624</inline>
+ <curve>nist/P-384</curve>
+ <desc>twist order = 0x1000000000000000000000000000000000000000000000000389cb27e0bc8d21ea7e5f24bb74f58851313e697333ad68d</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/nist/p521.xml b/src/cz/crcs/ectester/data/twist/nist/p521.xml
new file mode 100644
index 0000000..1564c80
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/nist/p521.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>p521/0</id>
+ <inline>0x01a0c6f0e5b2c6948218fb8d1e913d750ace27674e59ec0a45f8f5883518c65c401af5a2275b7c2c74e717f5b64c48056f1440de1d48ef0825086f12db4f862e4467,0x00c93c77edf1cac8bab534a28c49446113a22833e05658b69f73658d7867b43c94f58d52e17b726e3f6d0b5847d91980509250210c4e1c73eeec72e185529c1450b0</inline>
+ <curve>nist/P-521</curve>
+ <desc>twist order = 0x5</desc>
+</pubkey>
+<pubkey>
+ <id>p521/1</id>
+ <inline>0x00e84fb16849133c2e4c24e7efc4df752ed9f01204aa692342bc619a8a9ccdd1b058996f3896790d0ee1b7c480cb117cc0b9272c116c6f544b99dca9d441976c69c0,0x00e6d2c8adb57c81db0bead3d225ee900c81e049d0e36bf20bf421f5620449b1638f2b1998f3e1ffbee369a74bc4833d01f45b46388755ba16abf67c5f7f53ac9110</inline>
+ <curve>nist/P-521</curve>
+ <desc>twist order = 0x7</desc>
+</pubkey>
+<pubkey>
+ <id>p521/2</id>
+ <inline>0x0161cb810a7d7f9092d518ed483208f202cf5a984e98ff50f94b13e04bf94be942c91a007cff215d55bf124912b8620312bc94e813d7956e3821b45da439f0b0e8e7,0x005194f315423bcacf38ea558ff344daedf9a51a81b0a9ef27f1d687c8d1b6952b60b6486fc2c3d394749fb00e4921a5cfced55c1fe821e8b80279f6cec89ba1ac1f</inline>
+ <curve>nist/P-521</curve>
+ <desc>twist order = 0x4277ffb</desc>
+</pubkey>
+<pubkey>
+ <id>p521/3</id>
+ <inline>0x01c133c394ad86829a9252e4d5e266c3d2830eb9b899e2cb16b815a5c7050c3bc53c415296339d33427087bdef04c0ae2d8f7d63d4a41176bd76d3c07cbd1ecfd1ee,0x01fee0c7535c40e01f2c12ee2a6ae1e54cafc147c3b491602da1f278b46c6ae3c04705b3bb3c72af70aaf3d4c684411ede8694d7a21b3734ce43ecc2b4a1ee2efee7</inline>
+ <curve>nist/P-521</curve>
+ <desc>twist order = 0x25e6d2cd</desc>
+</pubkey>
+<pubkey>
+ <id>p521/4</id>
+ <inline>0x01232e18498e6cafe2572ec0b511376cf0d4844ec3b94472fb53346d7d9611726065cc922b3d2132117c99bce0ff8bc7f51bb30c6909a53b7c8a88e81807c31a1999,0x0112ada376c25bdc96440e0e2bf936377b287e885a08e6e1b5aa54f9b269cce4ed6ca6e6e44bd6d8e092e4864b278951648e897682096488e2a36036e989b1af7b24</inline>
+ <curve>nist/P-521</curve>
+ <desc>twist order = 0x17c8b8fa594c0fc63a5c0043ab498c1762d92f18fdfe2fea8f074695615d886d81bf930a0ac77d01bf9dd8c1a1ae121dab4e860c5dc18e265de3</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp112r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp112r1.xml
new file mode 100644
index 0000000..bea215a
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp112r1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp112r1/0</id>
+ <inline>0x873a74a2da300cab1c8761d8f67b,0x46e03cbcc61d00aa9fe5a8077494</inline>
+ <curve>secg/secp112r1</curve>
+ <desc>twist order = 0x8a5</desc>
+</pubkey>
+<pubkey>
+ <id>secp112r1/1</id>
+ <inline>0x218f000fe41ffd98b55fc9b756c7,0x62a1bd48c034935e4367f392fbaa</inline>
+ <curve>secg/secp112r1</curve>
+ <desc>twist order = 0x1835</desc>
+</pubkey>
+<pubkey>
+ <id>secp112r1/2</id>
+ <inline>0xadf84193c633787f17ff7c789296,0x19b5613c0ee78be5954a104fad0b</inline>
+ <curve>secg/secp112r1</curve>
+ <desc>twist order = 0x11167</desc>
+</pubkey>
+<pubkey>
+ <id>secp112r1/3</id>
+ <inline>0x4b3b746903493367fd076f6e73bb,0x030545f11165bac7cbf381c48879</inline>
+ <curve>secg/secp112r1</curve>
+ <desc>twist order = 0x44015</desc>
+</pubkey>
+<pubkey>
+ <id>secp112r1/4</id>
+ <inline>0x51132c4c92342942c8027b71890e,0x43beab4961a59cf10d1b30531f5a</inline>
+ <curve>secg/secp112r1</curve>
+ <desc>twist order = 0x3b273570eb27b9</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp112r2.xml b/src/cz/crcs/ectester/data/twist/secg/secp112r2.xml
new file mode 100644
index 0000000..f1d0fee
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp112r2.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp112r2/0</id>
+ <inline>0x48edb7418c08127bdd779ac7e5f7,0x0000000000000000000000000000</inline>
+ <curve>secg/secp112r2</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>secp112r2/1</id>
+ <inline>0x4a1cb7539a8401269dbff6acf404,0xc21acfb8b7b32712febd4e61633f</inline>
+ <curve>secg/secp112r2</curve>
+ <desc>twist order = 0x17</desc>
+</pubkey>
+<pubkey>
+ <id>secp112r2/2</id>
+ <inline>0xc8faf44b8d4853737ccf82806b75,0xcce630f92e9c95bf26e0f4a070fe</inline>
+ <curve>secg/secp112r2</curve>
+ <desc>twist order = 0xd3</desc>
+</pubkey>
+<pubkey>
+ <id>secp112r2/3</id>
+ <inline>0x14590ab5b3753e82b3d0b57ce706,0x233b3204fdedbaf31c5dceb86285</inline>
+ <curve>secg/secp112r2</curve>
+ <desc>twist order = 0x35e63</desc>
+</pubkey>
+<pubkey>
+ <id>secp112r2/4</id>
+ <inline>0x8ae76a4a40729732096d3c5207e5,0x629a89669d42e3871f1820cb97a5</inline>
+ <curve>secg/secp112r2</curve>
+ <desc>twist order = 0x73c27</desc>
+</pubkey>
+<pubkey>
+ <id>secp112r2/5</id>
+ <inline>0xa86117a59016f257c4397d388a65,0x67ead9fb333257074be723a5f46b</inline>
+ <curve>secg/secp112r2</curve>
+ <desc>twist order = 0x1e6727ac61bb6633</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp128r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp128r1.xml
new file mode 100644
index 0000000..e9bf07b
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp128r1.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp128r1/0</id>
+ <inline>0x7ad6f2458364dc3bc253564a0f55f047,0x24ca1c658f7572c87528e6b9db2b6a76</inline>
+ <curve>secg/secp128r1</curve>
+ <desc>twist order = 0x29</desc>
+</pubkey>
+<pubkey>
+ <id>secp128r1/1</id>
+ <inline>0xd831601d766cc45f62eb7cf7937ee642,0xf9e0a4e6fec14da13d27d248a190d230</inline>
+ <curve>secg/secp128r1</curve>
+ <desc>twist order = 0xc0034f</desc>
+</pubkey>
+<pubkey>
+ <id>secp128r1/2</id>
+ <inline>0x8867a9a49ff8c47c6d10d32783cd69b0,0xc2d9ae698d287ecdadce470328485477</inline>
+ <curve>secg/secp128r1</curve>
+ <desc>twist order = 0x56a1f8d</desc>
+</pubkey>
+<pubkey>
+ <id>secp128r1/3</id>
+ <inline>0xeb842468d2d732452a3044e8558fbf60,0x35022342302a1fc4f2bbd4ddca43892d</inline>
+ <curve>secg/secp128r1</curve>
+ <desc>twist order = 0x18996f4e0882951e9d1</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp128r2.xml b/src/cz/crcs/ectester/data/twist/secg/secp128r2.xml
new file mode 100644
index 0000000..fdd9028
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp128r2.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp128r2/0</id>
+ <inline>0x64a89794638df343c17a48c6e926de14,0x00000000000000000000000000000000</inline>
+ <curve>secg/secp128r2</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>secp128r2/1</id>
+ <inline>0xd2d9721cd218b8d0a9dc8101e053a834,0x8111cc843d9d6090ec34cfe2ea360eb6</inline>
+ <curve>secg/secp128r2</curve>
+ <desc>twist order = 0x3cb</desc>
+</pubkey>
+<pubkey>
+ <id>secp128r2/2</id>
+ <inline>0x88ba57155e8f2050626d2a02a34b4efd,0x8f97d0b54e869e605b7fb7ae97819d1d</inline>
+ <curve>secg/secp128r2</curve>
+ <desc>twist order = 0x10df9252a726c184278bf55634b577</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp160k1.xml b/src/cz/crcs/ectester/data/twist/secg/secp160k1.xml
new file mode 100644
index 0000000..8d1cc53
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp160k1.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp160k1/0</id>
+ <inline>0x0000000000000000000000000000000000000000,0xc1fd26fdc8681a7ba7f699610a62c328cde65ba0</inline>
+ <curve>secg/secp160k1</curve>
+ <desc>twist order = 0x3</desc>
+</pubkey>
+<pubkey>
+ <id>secp160k1/1</id>
+ <inline>0x261f4b383910221b95b8064ffd1667c136652295,0x84bb1bf6e9d6beebcb0b3525e99df9124bb14e40</inline>
+ <curve>secg/secp160k1</curve>
+ <desc>twist order = 0x7</desc>
+</pubkey>
+<pubkey>
+ <id>secp160k1/2</id>
+ <inline>0x5ad5c6cd4067ee20b4984eb2132c9742d15d15e2,0x2de572e579ea7b539f0234a6a2f875966dc4b249</inline>
+ <curve>secg/secp160k1</curve>
+ <desc>twist order = 0xd</desc>
+</pubkey>
+<pubkey>
+ <id>secp160k1/3</id>
+ <inline>0x12a1d4d6314698fa80a153de7849173ba3840012,0x34dec5c8c38ec56f7cdf8f1e44f54606a49e5213</inline>
+ <curve>secg/secp160k1</curve>
+ <desc>twist order = 0x5fc5</desc>
+</pubkey>
+<pubkey>
+ <id>secp160k1/4</id>
+ <inline>0x836557a9441a4591e3b35c4b86c4b4a964887b4c,0xd5491a1f264c3f115223731855ce2ed837c15bf0</inline>
+ <curve>secg/secp160k1</curve>
+ <desc>twist order = 0x25807</desc>
+</pubkey>
+<pubkey>
+ <id>secp160k1/5</id>
+ <inline>0x1c959049e8e689783335f711f7a928d4200890c2,0xd0846962412aa16de740be64dadca13bb0c50758</inline>
+ <curve>secg/secp160k1</curve>
+ <desc>twist order = 0x271c756a728aed5671cf8cb4b33771</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp160r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp160r1.xml
new file mode 100644
index 0000000..dece980
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp160r1.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp160r1/0</id>
+ <inline>0xdfe49462b5a10a4cf944801e93a444d4951c54f4,0x9ef1de44c53a4814eb31f616175922327cd2e112</inline>
+ <curve>secg/secp160r1</curve>
+ <desc>twist order = 0x20b</desc>
+</pubkey>
+<pubkey>
+ <id>secp160r1/1</id>
+ <inline>0x5cf0cd60ea345232884895f01b4e1760927f5d94,0x0bb00af378e1f0f69589a2da5b8fd6b2669b5402</inline>
+ <curve>secg/secp160r1</curve>
+ <desc>twist order = 0x2c29d39e9</desc>
+</pubkey>
+<pubkey>
+ <id>secp160r1/2</id>
+ <inline>0xeb8957704438337bbddb0d6ce1e28b635d5db134,0x631bad39571cfea33639a76c774e46fecaadc9b1</inline>
+ <curve>secg/secp160r1</curve>
+ <desc>twist order = 0x2d65dd7cc36e3baf234efd9dea9ae3</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp160r2.xml b/src/cz/crcs/ectester/data/twist/secg/secp160r2.xml
new file mode 100644
index 0000000..bdb8a03
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp160r2.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp160r2/0</id>
+ <inline>0x33581bd94e113c8b34fec9c60b9031675b9c8b68,0x987cd809e044f8ab7f3757bbd06ecc01550f3868</inline>
+ <curve>secg/secp160r2</curve>
+ <desc>twist order = 0xa3</desc>
+</pubkey>
+<pubkey>
+ <id>secp160r2/1</id>
+ <inline>0x8318469fc335f235b8d8fc4fbcd61282b9521fb7,0xcf52bc6053b4cea8117431dcb68db2110dd87e63</inline>
+ <curve>secg/secp160r2</curve>
+ <desc>twist order = 0x1c9</desc>
+</pubkey>
+<pubkey>
+ <id>secp160r2/2</id>
+ <inline>0x615ace506803fd5f06a323ce45319a3ca5aadcf0,0xbb4f76d2db8189c07a10487fb32b206a38ba2e89</inline>
+ <curve>secg/secp160r2</curve>
+ <desc>twist order = 0x355</desc>
+</pubkey>
+<pubkey>
+ <id>secp160r2/3</id>
+ <inline>0x3178dfd1f5c334184521d055a043a2349f35f67e,0x98c2395fd272532476f2c6d5ddb2c9a579b84699</inline>
+ <curve>secg/secp160r2</curve>
+ <desc>twist order = 0x78d</desc>
+</pubkey>
+<pubkey>
+ <id>secp160r2/4</id>
+ <inline>0x0e17d26c2ebf81b5e1c695438abe9eb3edd96f6b,0x2502f5d59f731f0cca5b8449fde15b713f82f36c</inline>
+ <curve>secg/secp160r2</curve>
+ <desc>twist order = 0x8f3af9a6f25d7b73940da6f6ebd3137</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp192k1.xml b/src/cz/crcs/ectester/data/twist/secg/secp192k1.xml
new file mode 100644
index 0000000..457a414
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp192k1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp192k1/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000,0x50f36a853090dc8aaeab4e45e31a9476899ac91c98622974</inline>
+ <curve>secg/secp192k1</curve>
+ <desc>twist order = 0x3</desc>
+</pubkey>
+<pubkey>
+ <id>secp192k1/1</id>
+ <inline>0xc1ee9eeacca70968c68149d7ea884f4d2081c7f135a3c0db,0xcd1fcc8fa5650d5b63c2e4e3529845200fe959e2bf7aa743</inline>
+ <curve>secg/secp192k1</curve>
+ <desc>twist order = 0x175</desc>
+</pubkey>
+<pubkey>
+ <id>secp192k1/2</id>
+ <inline>0xa5e8d7e243f29335b7f9067cc2a99334e5504dab66de2b61,0xe488e628f21a0d13439c912ad6dd6a4c017deb6d1bd9ac91</inline>
+ <curve>secg/secp192k1</curve>
+ <desc>twist order = 0xdc3f</desc>
+</pubkey>
+<pubkey>
+ <id>secp192k1/3</id>
+ <inline>0xc3ad3754b5199729816ba49f459caa03c63e8580f66c03a9,0xce4bc350ed04ecb8634147d9a9cd1cf6d06268fdc6a11fdd</inline>
+ <curve>secg/secp192k1</curve>
+ <desc>twist order = 0x24e7164b</desc>
+</pubkey>
+<pubkey>
+ <id>secp192k1/4</id>
+ <inline>0x14fc875f81ce7d409013996fa7d8d75dab7b750f41e7aeee,0xb16e153045429ab589746734c0fb13ad11a81ef95e41cdad</inline>
+ <curve>secg/secp192k1</curve>
+ <desc>twist order = 0x1d83dac42196d3629c6baf0247e0157a469</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp192r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp192r1.xml
new file mode 100644
index 0000000..16ba7db
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp192r1.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp192r1/0</id>
+ <inline>0x23142b001b0b474409a0d4c8815e7ade529ae9eff7c5b95b,0xa1629eaae43dab352219bf25ff6e12f4936864615eb89078</inline>
+ <curve>secg/secp192r1</curve>
+ <desc>twist order = 0x17</desc>
+</pubkey>
+<pubkey>
+ <id>secp192r1/1</id>
+ <inline>0xc0a1f79357e0d708a855fe30e2fc032486e3b26d8fe1a5c0,0x51d01bb8aadd9b41863ece85c2b600a0107f812d4460e9d9</inline>
+ <curve>secg/secp192r1</curve>
+ <desc>twist order = 0x231acce82af76d32ca5d526f</desc>
+</pubkey>
+<pubkey>
+ <id>secp192r1/2</id>
+ <inline>0x45cc2ab6dba52cbfd5860d0e61a3decfee82e0b1c64bd094,0xbf8b1707363dc155b16233478b0555b1815a295338522b80</inline>
+ <curve>secg/secp192r1</curve>
+ <desc>twist order = 0x512b1bfde874086edba50007</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp224r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp224r1.xml
new file mode 100644
index 0000000..ee6782e
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp224r1.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp224r1/0</id>
+ <inline>0x5d60f43a069cfe3a7c365b782bd8ef722e29efed9f8e782d98da9523,0xc790eaae79a6ea2fbe7bcd6c430c54362a834b3a6628008347264d89</inline>
+ <curve>secg/secp224r1</curve>
+ <desc>twist order = 0x3</desc>
+</pubkey>
+<pubkey>
+ <id>secp224r1/1</id>
+ <inline>0xcd1095d23b17e6cfbd1c59476bd60751bb743a42ab8673414cfaf3e7,0x89b8deb522b178eb7a8ad262ce9e99a472797448d598ce64a2116b03</inline>
+ <curve>secg/secp224r1</curve>
+ <desc>twist order = 0xb</desc>
+</pubkey>
+<pubkey>
+ <id>secp224r1/2</id>
+ <inline>0xe442f9e86c386800f2ae5982f3be77c833663e8b673121fed69282f4,0x2a94e1cd72999b32a6b1fc71328b63bb4857f045a4acda509991145b</inline>
+ <curve>secg/secp224r1</curve>
+ <desc>twist order = 0x2f</desc>
+</pubkey>
+<pubkey>
+ <id>secp224r1/3</id>
+ <inline>0x25c4b228af197210904546d9f6dda2385b9a0a0cbe2211af65341cb9,0x3f5c565a48b1b8d05adbc9ca94ade61e0e45cc9e9f1248c963d5784c</inline>
+ <curve>secg/secp224r1</curve>
+ <desc>twist order = 0x2e0273</desc>
+</pubkey>
+<pubkey>
+ <id>secp224r1/4</id>
+ <inline>0x5e7b261f83fa2b59e6bf4c7c9edf8e9c6ad418f4e9b3f9cec09f66d9,0x59033a890a85f95fc514abfa27e01bb010c3699f9430057b7235c1fd</inline>
+ <curve>secg/secp224r1</curve>
+ <desc>twist order = 0x268160f</desc>
+</pubkey>
+<pubkey>
+ <id>secp224r1/5</id>
+ <inline>0x8d9a10823de47bc73a12ae57fe97a34373ae59f16d61a3b82a46f68e,0x622fd6f6069294c902a82d3583d88816675e44fcafa47a0a433990a6</inline>
+ <curve>secg/secp224r1</curve>
+ <desc>twist order = 0xf3bac7aa52cf</desc>
+</pubkey>
+<pubkey>
+ <id>secp224r1/6</id>
+ <inline>0x99bfcc79f6c38a9b3d773506f827eccde507531d2886af8770f69f43,0x0e4e90ae87d71816c2bef3d55f0dfe7b54c16f9aadd8ea3b56e9663b</inline>
+ <curve>secg/secp224r1</curve>
+ <desc>twist order = 0x22340ff0f7eba57b33ac73e28a14d1</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp256k1.xml b/src/cz/crcs/ectester/data/twist/secg/secp256k1.xml
new file mode 100644
index 0000000..467641e
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp256k1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp256k1/0</id>
+ <inline>0x1f5f34663a612761136c07de53d91039f82644aa7706e90b37ac2dc5154d79ed,0xb32d76a9b3c7a9fac50c6da11a9953d11b262206cf26f33a9feb20a6bb1bb70c</inline>
+ <curve>secg/secp256k1</curve>
+ <desc>twist order = 0x3</desc>
+</pubkey>
+<pubkey>
+ <id>secp256k1/1</id>
+ <inline>0x9537931b68257bb2ef5782a3df24719668c70029522ba296c076996231e5c790,0x236617decf9b2f14223d798de8de3bca791fe36603a312e572048e89609379d4</inline>
+ <curve>secg/secp256k1</curve>
+ <desc>twist order = 0xd</desc>
+</pubkey>
+<pubkey>
+ <id>secp256k1/2</id>
+ <inline>0xaa45c03ebb0dd5ef1eb604802b97cef9694d5b9f37b253a475be99927dc28d55,0xb6762cffb2eacc3504b6c2e25908c4b9af12a62450fab97690c137a1102d64d4</inline>
+ <curve>secg/secp256k1</curve>
+ <desc>twist order = 0xcf7</desc>
+</pubkey>
+<pubkey>
+ <id>secp256k1/3</id>
+ <inline>0x4c5029ee7f3f340b328d6db4e6195a21a43ddc42152137922e7ed27a2723ff87,0x2309f5db4cb59337fabd8ca6b1b8866fd3a96429c4aec311e315983bf3b6864f</inline>
+ <curve>secg/secp256k1</curve>
+ <desc>twist order = 0x586f</desc>
+</pubkey>
+<pubkey>
+ <id>secp256k1/4</id>
+ <inline>0x4234a6acce09563862bc78f46c93dbb9e8ca3579ec58d08f273911178ae88e25,0x5d3e9733e02e6b94f297d8d5905265d1ddfeacb2633f0db3fd255d0177d2de46</inline>
+ <curve>secg/secp256k1</curve>
+ <desc>twist order = 0x99ee564ea5d84f508913936a761b0d5d792a426a7779817ae2f5b67</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp256r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp256r1.xml
new file mode 100644
index 0000000..b385548
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp256r1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp256r1/0</id>
+ <inline>0xd43dd5ce6c8e557e282bdc3535609e72bc46c1f91c166c63fc298b5a2ef64ea5,0x53cdb347774d9feef822754c289a8a7aab6e4bf5168a5155b0c25016f6ff47ad</inline>
+ <curve>secg/secp256r1</curve>
+ <desc>twist order = 0x3</desc>
+</pubkey>
+<pubkey>
+ <id>secp256r1/1</id>
+ <inline>0x44b4e6293d9efcb1b655b7f90b81dabceb5925a258780aa22381292af84e4615,0x39efc0650cd2289cb1d6c2bd2bd7139f4f4c97e43f536c47b7782e5e5b627428</inline>
+ <curve>secg/secp256r1</curve>
+ <desc>twist order = 0x5</desc>
+</pubkey>
+<pubkey>
+ <id>secp256r1/2</id>
+ <inline>0x588e38eb7a4adf969daea9e2beabe2616ac8c0a7a52d920f10ed1d2f81986b6e,0x3b728114a2421a73d047338f60a324ee1b25d81f8f207ba762765b45576d009d</inline>
+ <curve>secg/secp256r1</curve>
+ <desc>twist order = 0xd</desc>
+</pubkey>
+<pubkey>
+ <id>secp256r1/3</id>
+ <inline>0x0d8e8d6f9b9bec935475145bde3b80b76884b57d136afe327d80e13677a915f5,0x6bc1fc461c4dcec55a6ceadb7950aaffb5621ea428b13e7091b1d7a90642b270</inline>
+ <curve>secg/secp256r1</curve>
+ <desc>twist order = 0xb3</desc>
+</pubkey>
+<pubkey>
+ <id>secp256r1/4</id>
+ <inline>0x84cdc23c802dd6ae90ae1257884709fc522206adf114b8f0ea715e0dc77d2bad,0x92a4b98b60c8204cbdf947839663229d2fd36184504ff0e308eaa1761c138d7a</inline>
+ <curve>secg/secp256r1</curve>
+ <desc>twist order = 0x1e0a75640070a738557cc30f68bd56eaea65c94f98411d17ac4e16ece1a47</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp384r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp384r1.xml
new file mode 100644
index 0000000..2ddbe9b
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp384r1.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp384r1/0</id>
+ <inline>0xe623940e96d6ce70b3a3185b1b49560532daafbc36f8fcc9167500b186682ac19c1bc959c0b9ae6e2f620449358c9367,0x97c91ddd90946df34ee5c540a04175d45a5ebad666439b8384ec64cd95b2f0a438bedfc36ca80a7d7e9a38a7c26925bf</inline>
+ <curve>secg/secp384r1</curve>
+ <desc>twist order = 0x1000000000000000000000000000000000000000000000000389cb27e0bc8d21ea7e5f24bb74f58851313e697333ad68d</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/secp521r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp521r1.xml
new file mode 100644
index 0000000..105efa3
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/secp521r1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>secp521r1/0</id>
+ <inline>0x0099cfe88fe446b8eaeefc4094833b1ab0853c7bc4d906aef04d9f57be2de53e3678551217b736cd26d1b217dcb806c747f17e29bee7490161f86726d59f2129c16b,0x0079651e0bf51bd1bd86a1f520c528705862589c5b78843d523be3e980e93ef3ddf3366175a1567b88d54689e6bfcafee863ad3d93411d54ca3db6ad2ce27eae309d</inline>
+ <curve>secg/secp521r1</curve>
+ <desc>twist order = 0x5</desc>
+</pubkey>
+<pubkey>
+ <id>secp521r1/1</id>
+ <inline>0x0140ba8e264bfcbc2dae3e498236fdb502cdbcd053476d148143bb0a38f72d4bb4d0c53b971cd36ba19f0a35cfb6af2f82c1a9bc5978873e0edf753282e11fdfd045,0x0041833aebb70b75c471c35ca5cdbbdfb8c64dd10f2e977e254f081e2566e8010e80d69ff11cf3140561586e917070d2a0443d3f3eba20688f0e48e4132d0eb0a5b4</inline>
+ <curve>secg/secp521r1</curve>
+ <desc>twist order = 0x7</desc>
+</pubkey>
+<pubkey>
+ <id>secp521r1/2</id>
+ <inline>0x00925139c9b4c7788add3ec38be6c9799dcd4794f9f3e708bd66130b2d21abc953035a3bd6cbae7fc2cc02b0be12cd0b0fbfe0d190844bb3e346899f6c03908bb73b,0x006a86cb7307e9901bcf819e1cf2deecc0e2a35b0cb06998ec1e354267294a17f872179cad4f80e79ad06fd4200cbf142d18779a8e4633824265a0cae30aacd38418</inline>
+ <curve>secg/secp521r1</curve>
+ <desc>twist order = 0x4277ffb</desc>
+</pubkey>
+<pubkey>
+ <id>secp521r1/3</id>
+ <inline>0x013dec992b39d75718ca8ea86f481bec0d4717e18b86f0716e807374317bf4bd93cd036f6969d2d85e19f2b9a375c0c5cc3a46af11048671bb9c8aac21bd8a02bb9d,0x01f629b94eadd014680a318a29a743585e7b8a9a315accccf7dcd8b2f6d012f301eeb2477fb8c822b07f09cc2089c3be07896502cbf1e86f72635718dd2ae3004c65</inline>
+ <curve>secg/secp521r1</curve>
+ <desc>twist order = 0x25e6d2cd</desc>
+</pubkey>
+<pubkey>
+ <id>secp521r1/4</id>
+ <inline>0x013189c93b04b69426269fbadbee6379a6752ca1cbbe972ca1f14edbb4fefdc437bd96912266a83fb0482b6a291d74326a1d2b6a170f0cd24896e93323049fea281d,0x01a05a94d5e7481d42d3af74994f6f7bfacd231123cd6abcd31e3e99c571a84d032aeee65aa3fff8cda497aa77900910a897188f87fc4d502162349ec1d2345a307e</inline>
+ <curve>secg/secp521r1</curve>
+ <desc>twist order = 0x17c8b8fa594c0fc63a5c0043ab498c1762d92f18fdfe2fea8f074695615d886d81bf930a0ac77d01bf9dd8c1a1ae121dab4e860c5dc18e265de3</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/sect163k1.xml b/src/cz/crcs/ectester/data/twist/secg/sect163k1.xml
new file mode 100644
index 0000000..754e8e6
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/sect163k1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>sect163k1/0</id>
+ <inline>0x000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000001</inline>
+ <curve>secg/sect163k1</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>sect163k1/1</id>
+ <inline>0x05f78762dcf07272474326134cd9afb8ec82b6b9af,0x05ae3cb5265210c388e0fb9787c7dc7c40ef03acae</inline>
+ <curve>secg/sect163k1</curve>
+ <desc>twist order = 0x28d</desc>
+</pubkey>
+<pubkey>
+ <id>sect163k1/2</id>
+ <inline>0x01626b92c13b6eaf8a07353707e3ee25b69d56b403,0x0066a86e6fd8c5fa73245eef10159b5b428efface3</inline>
+ <curve>secg/sect163k1</curve>
+ <desc>twist order = 0x1979</desc>
+</pubkey>
+<pubkey>
+ <id>sect163k1/3</id>
+ <inline>0x072da789cdf1e91288880d47aade6d19206a3eef8b,0x006405496db1049f579e035d9047f554152d215933</inline>
+ <curve>secg/sect163k1</curve>
+ <desc>twist order = 0x7926bec180108d</desc>
+</pubkey>
+<pubkey>
+ <id>sect163k1/4</id>
+ <inline>0x059f4674675ce9134f7c6095e57f0f2da73b303ab0,0x03cdd4b8e4efa8c96ed4b2b349f6e1b47bc33f145c</inline>
+ <curve>secg/sect163k1</curve>
+ <desc>twist order = 0x10a6989de57d15c65ba229</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/sect163r1.xml b/src/cz/crcs/ectester/data/twist/secg/sect163r1.xml
new file mode 100644
index 0000000..dd7d798
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/sect163r1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>sect163r1/0</id>
+ <inline>0x000000000000000000000000000000000000000000,0x009917a2556e1856bc7ea9a472cd01bfb889b95835</inline>
+ <curve>secg/sect163r1</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>sect163r1/1</id>
+ <inline>0x06deb836183f1f185aa782845b7e30b87aac87cc86,0x02a07ec119c487e132b464ea54e7f2264103fbf6f3</inline>
+ <curve>secg/sect163r1</curve>
+ <desc>twist order = 0x7</desc>
+</pubkey>
+<pubkey>
+ <id>sect163r1/2</id>
+ <inline>0x01dbb909b594a1b8db65b2de7cffe586d10ea658c8,0x031e430590c0ca5707f54a0463dbd329ca9088d1f2</inline>
+ <curve>secg/sect163r1</curve>
+ <desc>twist order = 0x923</desc>
+</pubkey>
+<pubkey>
+ <id>sect163r1/3</id>
+ <inline>0x029d7e51e1b8552d0fe88a48bcfb1913b4d0adac52,0x073688d2e575b20328f70560be4ba53b575498d23d</inline>
+ <curve>secg/sect163r1</curve>
+ <desc>twist order = 0xcd4110cf690bd</desc>
+</pubkey>
+<pubkey>
+ <id>sect163r1/4</id>
+ <inline>0x010175375db66e9ce0060fc3785804ebe2d96b8a3a,0x04d4cc08f4975602d69520023bb0505fe701339146</inline>
+ <curve>secg/sect163r1</curve>
+ <desc>twist order = 0x9fc0d375facf703681f32693</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/sect163r2.xml b/src/cz/crcs/ectester/data/twist/secg/sect163r2.xml
new file mode 100644
index 0000000..421887d
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/sect163r2.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>sect163r2/0</id>
+ <inline>0x000000000000000000000000000000000000000000,0x02c25b85badf8927593d21c366da89c03969f34da5</inline>
+ <curve>secg/sect163r2</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>sect163r2/1</id>
+ <inline>0x0176fb3d1e1035f04de3297dafb0033baeee694e97,0x0602840f8148fc8afc1f695df529e4dd48337243a4</inline>
+ <curve>secg/sect163r2</curve>
+ <desc>twist order = 0x1f</desc>
+</pubkey>
+<pubkey>
+ <id>sect163r2/2</id>
+ <inline>0x017d5799f3c55c7f0941240a0030cd1f6a4077e627,0x02a19d01c1bd140363e68414e8f35a9fdf8a5345ea</inline>
+ <curve>secg/sect163r2</curve>
+ <desc>twist order = 0x38b</desc>
+</pubkey>
+<pubkey>
+ <id>sect163r2/3</id>
+ <inline>0x01aff9f7655201dc4800b811f5c983d4ca9933b947,0x07bdfdfc15dc948a4dc91d8565a69659c6c88bf5f3</inline>
+ <curve>secg/sect163r2</curve>
+ <desc>twist order = 0x1208485</desc>
+</pubkey>
+<pubkey>
+ <id>sect163r2/4</id>
+ <inline>0x0332053427eaa5d8f365c5306fb301be9627647e81,0x0696da25692ba254884fb945caa12fe68c05a0416c</inline>
+ <curve>secg/sect163r2</curve>
+ <desc>twist order = 0xb78fc77</desc>
+</pubkey>
+<pubkey>
+ <id>sect163r2/5</id>
+ <inline>0x02556ec8322e21c3de7444a6fcdfff37629d657018,0x0324ab964dd8012423c2607dd9094393b60c725c10</inline>
+ <curve>secg/sect163r2</curve>
+ <desc>twist order = 0x5c4bf9b1205a07afbe718429</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/sect233k1.xml b/src/cz/crcs/ectester/data/twist/secg/sect233k1.xml
new file mode 100644
index 0000000..cf8524c
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/sect233k1.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>sect233k1/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001</inline>
+ <curve>secg/sect233k1</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>sect233k1/1</id>
+ <inline>0x014cdc219c9370a243ae5a9456fe5e3a421c7363727f3e4018c497e30705,0x01a88dbabe626a8941b5394278f7de54d63edfa7e70c15a815aa75bc5072</inline>
+ <curve>secg/sect233k1</curve>
+ <desc>twist order = 0x1686d</desc>
+</pubkey>
+<pubkey>
+ <id>sect233k1/2</id>
+ <inline>0x00bba31978663bc010dc6620c8241e44417b1a56212b82d4d63751d234cf,0x01b3cda86c83bb59b8e3f3ba2d025adc35abd11acb19ba561491c34fd9c7</inline>
+ <curve>secg/sect233k1</curve>
+ <desc>twist order = 0x6d8a417</desc>
+</pubkey>
+<pubkey>
+ <id>sect233k1/3</id>
+ <inline>0x01512cc87e6cd2a418857736c96688476b641b9d3a838eb4f9207751e021,0x01dc01ca001b69c64322a5d5c2cf81a9ae0ed04d8d10e8b06ccbcf9ef911</inline>
+ <curve>secg/sect233k1</curve>
+ <desc>twist order = 0x7c02977</desc>
+</pubkey>
+<pubkey>
+ <id>sect233k1/4</id>
+ <inline>0x01c61af41b217ec78ffb3572df845fe33c8efecb2d05f2033c2824784e5b,0x0138f83ba05a3957721d5db5a5bd247ab02a4f6a3e1c2163027116996730</inline>
+ <curve>secg/sect233k1</curve>
+ <desc>twist order = 0x46403a035013f70d</desc>
+</pubkey>
+<pubkey>
+ <id>sect233k1/5</id>
+ <inline>0x00e9f2cc9d6665352aa77575f3f7bd42642c924388b8c741134eeda9ccb7,0x01e74c2549cce5d6587a11dfd625e099f2519691653c80dbe335aa61c789</inline>
+ <curve>secg/sect233k1</curve>
+ <desc>twist order = 0xc7cb3894752e561e6abf871db</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/sect233r1.xml b/src/cz/crcs/ectester/data/twist/secg/sect233r1.xml
new file mode 100644
index 0000000..45eecf4
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/sect233r1.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>sect233r1/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000000000000000,0x0187f85627b97874e747ee31e06d71caaeea52f21253e5f946d061da9138</inline>
+ <curve>secg/sect233r1</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>sect233r1/1</id>
+ <inline>0x00c5f754b03ae354c9cce8386a31436157eaa590a9cfb892dc40d56f66cf,0x01294608d589c250bed15f0e63887c961fa149c68881c1ec242e441ad1a3</inline>
+ <curve>secg/sect233r1</curve>
+ <desc>twist order = 0x5</desc>
+</pubkey>
+<pubkey>
+ <id>sect233r1/2</id>
+ <inline>0x0024806b9e973c082da34fadd43d94d6966e16b147450db7ddd6e5a3f4e2,0x0083fb9fa68aba9805c0a747897fd1bf12defaa7d8efee174060ac0ef3b0</inline>
+ <curve>secg/sect233r1</curve>
+ <desc>twist order = 0x11b</desc>
+</pubkey>
+<pubkey>
+ <id>sect233r1/3</id>
+ <inline>0x004bde91214e1b76dbe01fe34c68135178639f0453632209fd9da04d22fc,0x0030256812c97f8763815acc7fd00ca87d86cde0517ad2afc92b21c593d7</inline>
+ <curve>secg/sect233r1</curve>
+ <desc>twist order = 0x21d</desc>
+</pubkey>
+<pubkey>
+ <id>sect233r1/4</id>
+ <inline>0x00ca85e22408b271206c05630370c75c7c678392eb5ed54903ed3196eb5e,0x00c3e55b408782683364c3ea0191e4aaadc888f95c5d4a0e0e06e979f77c</inline>
+ <curve>secg/sect233r1</curve>
+ <desc>twist order = 0x22dba0b9</desc>
+</pubkey>
+<pubkey>
+ <id>sect233r1/5</id>
+ <inline>0x0159c22cd6ea5fe56041b75f3b21594ae94161363576338717d9b393ed85,0x00ec9f09736dbd80af6efd0f16419fd24982f9d5de455414057a6b57ac0c</inline>
+ <curve>secg/sect233r1</curve>
+ <desc>twist order = 0x2a7504c0fda95a2311</desc>
+</pubkey>
+<pubkey>
+ <id>sect233r1/6</id>
+ <inline>0x00fe6311a7ee2de94e57f9e632e184a8f9cc21d6a5865a820b6dd62371c3,0x0002dfd2fbdb68965f56f478b7a345950a5ef1e7a7f570962d389efc4612</inline>
+ <curve>secg/sect233r1</curve>
+ <desc>twist order = 0x1e53fa33649df4ef97d6b29ded5a7</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/sect239k1.xml b/src/cz/crcs/ectester/data/twist/secg/sect239k1.xml
new file mode 100644
index 0000000..bc17d4f
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/sect239k1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>sect239k1/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001</inline>
+ <curve>secg/sect239k1</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>sect239k1/1</id>
+ <inline>0x027dc44bed0f67a40050ce79eea889f65a856864c1ece7ae4b2d05887b3b,0x330b3b1520d30c012146cd13e3af3d32ee02f0eaebacac36611bda4b9483</inline>
+ <curve>secg/sect239k1</curve>
+ <desc>twist order = 0x10771acb9</desc>
+</pubkey>
+<pubkey>
+ <id>sect239k1/2</id>
+ <inline>0x2253fa673642a0046615d33a2853062d60e5959144bd608385ad7f4a6686,0x728f3a8f45ff239c5f1ab44cec36278be6312571486cde0a4205a3afb20f</inline>
+ <curve>secg/sect239k1</curve>
+ <desc>twist order = 0x3eaaf7f039f</desc>
+</pubkey>
+<pubkey>
+ <id>sect239k1/3</id>
+ <inline>0x38b81ec85fcdcea4a29a8b0326fcf122eee852754476b8490bbb5362efeb,0x2b8e9442ffb0eb8be55636cf7f12bc5402a985e8f7ea89ff0233ddb76a1c</inline>
+ <curve>secg/sect239k1</curve>
+ <desc>twist order = 0x1e3607543aabf52e8d8f7</desc>
+</pubkey>
+<pubkey>
+ <id>sect239k1/4</id>
+ <inline>0x5dbc5cbd7a0c046aeabff4b2abb49fb58763ea2c7e4ca9507ed3d54f9af2,0x0a389cf9dc455db54fc3de75a361b408e2cb679cfb2e1fbed312ff09c048</inline>
+ <curve>secg/sect239k1</curve>
+ <desc>twist order = 0x868c9487ea27642c47f97</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/sect283k1.xml b/src/cz/crcs/ectester/data/twist/secg/sect283k1.xml
new file mode 100644
index 0000000..65ecb63
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/sect283k1.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>sect283k1/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000000000000000001</inline>
+ <curve>secg/sect283k1</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>sect283k1/1</id>
+ <inline>0x01f5a4ad35352d19e37108222909b2a7002516cdf68afb899e9fca4056f77e889d15a7d0,0x04464034359d8bbf2e34f3d0a863d50ea325b804d8882dbf7a36c56d3f782451320799aa</inline>
+ <curve>secg/sect283k1</curve>
+ <desc>twist order = 0x400000000000000000000000000000000002ca3a25f1511b3440100d775c3f3c3d3873f</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/twist/secg/sect283r1.xml b/src/cz/crcs/ectester/data/twist/secg/sect283r1.xml
new file mode 100644
index 0000000..e2913a0
--- /dev/null
+++ b/src/cz/crcs/ectester/data/twist/secg/sect283r1.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<pubkey>
+ <id>sect283r1/0</id>
+ <inline>0x000000000000000000000000000000000000000000000000000000000000000000000000,0x072bcc9c5792b1ebe81983089fb6f835a2fd220a304424ca17c082ae17442aede9b9b3f6</inline>
+ <curve>secg/sect283r1</curve>
+ <desc>twist order = 0x2</desc>
+</pubkey>
+<pubkey>
+ <id>sect283r1/1</id>
+ <inline>0x0297e6d1f2b857a79f5dc85c2f1259d5d801c61a4d0a4312a04f65f09a887a7b93cf7ae1,0x051963c38ac61f05fef93707abcfbda7bc0f39eacddb2bdd3077f19c0e65c8be66ecb30e</inline>
+ <curve>secg/sect283r1</curve>
+ <desc>twist order = 0x7</desc>
+</pubkey>
+<pubkey>
+ <id>sect283r1/2</id>
+ <inline>0x06909a8eacbed1942bc0a6d606ad1ce284dd223d8ce569dba8525c5a5f799f137112c7ad,0x02e4300b6ce278700db70764e810c1a8d4645b57db3d3974027a1a106598ceba86a61ab5</inline>
+ <curve>secg/sect283r1</curve>
+ <desc>twist order = 0x13</desc>
+</pubkey>
+<pubkey>
+ <id>sect283r1/3</id>
+ <inline>0x01287256c9848e3bd11dddf8f34ecca845b535e84adfdf0154f0e7c4ae1a9f0e6719b9b2,0x0119bf5a2c413f730a1576f577873a6f0a603fd571084d584df0a12601b80fe9b607401f</inline>
+ <curve>secg/sect283r1</curve>
+ <desc>twist order = 0x1623ab619</desc>
+</pubkey>
+<pubkey>
+ <id>sect283r1/4</id>
+ <inline>0x0598a8e3f2a3e06680ab11b84a01d59adee54f329dfc2b65f8a517c2a5f03b8f1aedb021,0x02943952200eb1ab69c2ac5811d32ea4a528af7cc917d2f2883ca5ca55e464f673f5c2f0</inline>
+ <curve>secg/sect283r1</curve>
+ <desc>twist order = 0x2a4aa67aaaf5413fb</desc>
+</pubkey>
+<pubkey>
+ <id>sect283r1/5</id>
+ <inline>0x02e22724a4462bbca361607163bb9ab9926e8fe6859adb397e5eeb8d0972de359e37eebc,0x05b15d8c245bfd0c2ed3930a5742f747e12f4fe0e018ab32fc790711bfdb060514cf8400</inline>
+ <curve>secg/sect283r1</curve>
+ <desc>twist order = 0x25a8cdb1f2e470f3ac1ba7</desc>
+</pubkey>
+<pubkey>
+ <id>sect283r1/6</id>
+ <inline>0x032a8c3ac7583c8f599fe6cba343b26f66fe13906c96e11db396ad939d43b55260e5fcef,0x046a4cbc0d05bf6ebad4b5f2bfa6f1a486519ff332ebc49136067916f188af2f5bce0782</inline>
+ <curve>secg/sect283r1</curve>
+ <desc>twist order = 0x606749a9c147da03ad3f37</desc>
+</pubkey>
diff --git a/src/cz/crcs/ectester/data/wrong/wrongt163.csv b/src/cz/crcs/ectester/data/wrong/wrongt163.csv
index 91fd70b..88b142e 100644
--- a/src/cz/crcs/ectester/data/wrong/wrongt163.csv
+++ b/src/cz/crcs/ectester/data/wrong/wrongt163.csv
@@ -1 +1 @@
-00a3,0002,0000,0000,55e202b98d7e864b2c9c560dc8f8b4047743a84ad,4cf310ee7a37cb2bacafa5e5a5ffcc8464a51162d,58ae9952e3b62978ccc1bfd060564b2620d154049,5ed1e3aa306f09a955feff97757bc4e599c64bb9f,2aaaaaaaaaaaaaaaaaaaaaaaaaabc02b61ca4c651,3 \ No newline at end of file
+0x00a3,0x0002,0x0000,0x0000,0x55e202b98d7e864b2c9c560dc8f8b4047743a84ad,0x4cf310ee7a37cb2bacafa5e5a5ffcc8464a51162d,0x58ae9952e3b62978ccc1bfd060564b2620d154049,0x5ed1e3aa306f09a955feff97757bc4e599c64bb9f,0x2aaaaaaaaaaaaaaaaaaaaaaaaaabc02b61ca4c651,0x3
diff --git a/src/cz/crcs/ectester/data/wrong/wrongt233.csv b/src/cz/crcs/ectester/data/wrong/wrongt233.csv
index 7e704b0..291cdfe 100644
--- a/src/cz/crcs/ectester/data/wrong/wrongt233.csv
+++ b/src/cz/crcs/ectester/data/wrong/wrongt233.csv
@@ -1 +1 @@
-00e9,0001,0000,0000,14228234ca1e8900adcfef49a037d560c8e2c2ed4227d4a2cda8703079d,18f33f0e925e6af86764a84dae2e09eeb0ce218e21ad9638eeb9d2e2600,182a21d656972aeca534df8f8e8c5aa0f553cde1e025a75610f10ae9db5,118732c490d8788716e9ac581c37c140116d12e2e9abd56262a1a255472,c59f46db5ba025578d418f86dc556bec9d212b740ab595b83abd008ec0,2 \ No newline at end of file
+0x00e9,0x0001,0x0000,0x0000,0x14228234ca1e8900adcfef49a037d560c8e2c2ed4227d4a2cda8703079d,0x18f33f0e925e6af86764a84dae2e09eeb0ce218e21ad9638eeb9d2e2600,0x182a21d656972aeca534df8f8e8c5aa0f553cde1e025a75610f10ae9db5,0x118732c490d8788716e9ac581c37c140116d12e2e9abd56262a1a255472,0xc59f46db5ba025578d418f86dc556bec9d212b740ab595b83abd008ec0,0x2
diff --git a/src/cz/crcs/ectester/data/wrong/wrongt239.csv b/src/cz/crcs/ectester/data/wrong/wrongt239.csv
index 51098b6..bef2e14 100644
--- a/src/cz/crcs/ectester/data/wrong/wrongt239.csv
+++ b/src/cz/crcs/ectester/data/wrong/wrongt239.csv
@@ -1 +1 @@
-00ef,0001,0000,0000,513e8b6997328b69d60decd7fa034c1b3bd862717164e7785eb06dcc5b88,63510c1cc1053a916b68f258e9d3f7c2ba054e4af05f3e4d61b3de772d2a,509d82beb7ef27b5b7421ac1e93ccffea76c4f0874991cf3facf0eab9ef6,42a9207ae1cc90d3d29c42a87f754321ccbeaed2e18957ce5a9b01f56812,28759505089d94226a73eefded3f7bf2f81673517715cb032daeddbb68f7,2 \ No newline at end of file
+0x00ef,0x0001,0x0000,0x0000,0x513e8b6997328b69d60decd7fa034c1b3bd862717164e7785eb06dcc5b88,0x63510c1cc1053a916b68f258e9d3f7c2ba054e4af05f3e4d61b3de772d2a,0x509d82beb7ef27b5b7421ac1e93ccffea76c4f0874991cf3facf0eab9ef6,0x42a9207ae1cc90d3d29c42a87f754321ccbeaed2e18957ce5a9b01f56812,0x28759505089d94226a73eefded3f7bf2f81673517715cb032daeddbb68f7,0x2
diff --git a/src/cz/crcs/ectester/data/wrong/wrongt283.csv b/src/cz/crcs/ectester/data/wrong/wrongt283.csv
index 0d412de..736fe15 100644
--- a/src/cz/crcs/ectester/data/wrong/wrongt283.csv
+++ b/src/cz/crcs/ectester/data/wrong/wrongt283.csv
@@ -1 +1 @@
-011b,0002,0000,0000,7e2a42c7f5af962ff0f58711703462947d0a4eb3555b123aa33088a9c566424f0126157,6f317d6314dd7069b6be8cfb5fd0c563b9dbb2f9b8ca2618dd8cd4e7d1a368452aa3c34,5beb9f0130f758148a16a5c65b9228836af1c7afbab4afeffed328ed04ec1bf015f9c16,68996bd05c007c329738a29893a6215c99fbfa460e143090d588d9b157c99843e91c976,2552bf070faa392ab3b7fa07e443e5a45dc9bb3e1a6fe44d1440fdde6752c90899d4197,3
+0x011b,0x0002,0x0000,0x0000,0x7e2a42c7f5af962ff0f58711703462947d0a4eb3555b123aa33088a9c566424f0126157,0x6f317d6314dd7069b6be8cfb5fd0c563b9dbb2f9b8ca2618dd8cd4e7d1a368452aa3c34,0x5beb9f0130f758148a16a5c65b9228836af1c7afbab4afeffed328ed04ec1bf015f9c16,0x68996bd05c007c329738a29893a6215c99fbfa460e143090d588d9b157c99843e91c976,0x2552bf070faa392ab3b7fa07e443e5a45dc9bb3e1a6fe44d1440fdde6752c90899d4197,0x3
diff --git a/src/cz/crcs/ectester/data/wrong/wrongt409.csv b/src/cz/crcs/ectester/data/wrong/wrongt409.csv
index 97c8f95..fe7e040 100644
--- a/src/cz/crcs/ectester/data/wrong/wrongt409.csv
+++ b/src/cz/crcs/ectester/data/wrong/wrongt409.csv
@@ -1 +1 @@
-0199,0002,0000,0000,1cc6efad1333dd213e812bdc9909754ff20c102fb9c9a2a7fdbd23ca7d414bec401bc45532980dff9cc869b4622c7f5b65e2afb,1cfc909e058af6762da1c2d85ec911d4e393dcd4539aa6c6d755b3dfdf9c4c338c84b984f533479d2f2bb5169b4fae6a25159f6,1ef44edd1100313984d059e3ecae6c866d83bfb9931e616abafcb9f1461ec264509260b4c62a09f1f03595c404e530d467dc14c,1055f15e3b4272c3bf6ecaeb59204470b96111eb38eb395066b26fbae646ab57b7ae6cda5722a98b01aade1bcf3b6db950d2957,c3b9b6e10f6ed3a458388e94c4d567e1a2272bb996892a919e65a8da15c0907ac735eb2f9a7cee28ac90193dabd2408e232839,2
+0x0199,0x0002,0x0000,0x0000,0x1cc6efad1333dd213e812bdc9909754ff20c102fb9c9a2a7fdbd23ca7d414bec401bc45532980dff9cc869b4622c7f5b65e2afb,0x1cfc909e058af6762da1c2d85ec911d4e393dcd4539aa6c6d755b3dfdf9c4c338c84b984f533479d2f2bb5169b4fae6a25159f6,0x1ef44edd1100313984d059e3ecae6c866d83bfb9931e616abafcb9f1461ec264509260b4c62a09f1f03595c404e530d467dc14c,0x1055f15e3b4272c3bf6ecaeb59204470b96111eb38eb395066b26fbae646ab57b7ae6cda5722a98b01aade1bcf3b6db950d2957,0xc3b9b6e10f6ed3a458388e94c4d567e1a2272bb996892a919e65a8da15c0907ac735eb2f9a7cee28ac90193dabd2408e232839,0x2
diff --git a/src/cz/crcs/ectester/data/wrong/wrongt571.csv b/src/cz/crcs/ectester/data/wrong/wrongt571.csv
index 9e61a8a..2fcd0df 100644
--- a/src/cz/crcs/ectester/data/wrong/wrongt571.csv
+++ b/src/cz/crcs/ectester/data/wrong/wrongt571.csv
@@ -1 +1 @@
-023b,0002,0000,0000,4d3b833ae38b91e89061c4fae9e38264f2e88b4969778aa935eeec50fd1d66a994589e835aeb590566f0adafba2c40c1866865e62cae00f1d235038139d8d25b32d842a7a8b03b0,736974cc00c08dfbd1d23a6bea984c1c1af6ceae0a8b48ecd84b8a4fedbb46d61ab94efa8f53e50b6aa0c0599c2121af733dc36c07ccb7762d210bef02aa8611fe464d369f8a923,4f3bb81214f966e73a2f64423738ab7cd642b871ce7fb0e5f302a3a658aafd68e25d38c432d5e48334a2c03f472defa43ca0933fd13c98138bab6d7ca228ab860c79cd9114d4549,6355104090026816f380b1b406e84f93e12cbaa9f23adcef1eab09bd0418f7906195b102daed369ba72b9370e24a12c7676263c20bf7c7f3018c7a84ee80f586cc8fb16dd526110,397cad72a3fefe82d79a96e18009f5f9b661a9fa2ee53a5eb9f4016d2deaf249e2969b9af649fa363f4c2d5ec837792d932748f7344a16f8ab4be63341812d1c4f52a7b3fa65757,2
+0x023b,0x0002,0x0000,0x0000,0x4d3b833ae38b91e89061c4fae9e38264f2e88b4969778aa935eeec50fd1d66a994589e835aeb590566f0adafba2c40c1866865e62cae00f1d235038139d8d25b32d842a7a8b03b0,0x736974cc00c08dfbd1d23a6bea984c1c1af6ceae0a8b48ecd84b8a4fedbb46d61ab94efa8f53e50b6aa0c0599c2121af733dc36c07ccb7762d210bef02aa8611fe464d369f8a923,0x4f3bb81214f966e73a2f64423738ab7cd642b871ce7fb0e5f302a3a658aafd68e25d38c432d5e48334a2c03f472defa43ca0933fd13c98138bab6d7ca228ab860c79cd9114d4549,0x6355104090026816f380b1b406e84f93e12cbaa9f23adcef1eab09bd0418f7906195b102daed369ba72b9370e24a12c7676263c20bf7c7f3018c7a84ee80f586cc8fb16dd526110,0x397cad72a3fefe82d79a96e18009f5f9b661a9fa2ee53a5eb9f4016d2deaf249e2969b9af649fa363f4c2d5ec837792d932748f7344a16f8ab4be63341812d1c4f52a7b3fa65757,0x2
diff --git a/src/cz/crcs/ectester/data/x962/curves.xml b/src/cz/crcs/ectester/data/x962/curves.xml
new file mode 100644
index 0000000..eee64ad
--- /dev/null
+++ b/src/cz/crcs/ectester/data/x962/curves.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd">
+ <curve>
+ <id>prime192v1</id>
+ <bits>192</bits>
+ <field>prime</field>
+ <file>prime192v1.csv</file>
+ </curve>
+ <curve>
+ <id>prime192v2</id>
+ <bits>192</bits>
+ <field>prime</field>
+ <file>prime192v2.csv</file>
+ </curve>
+ <curve>
+ <id>prime192v3</id>
+ <bits>192</bits>
+ <field>prime</field>
+ <file>prime192v3.csv</file>
+ </curve>
+
+ <curve>
+ <id>prime239v1</id>
+ <bits>239</bits>
+ <field>prime</field>
+ <file>prime239v1.csv</file>
+ </curve>
+ <curve>
+ <id>prime239v2</id>
+ <bits>239</bits>
+ <field>prime</field>
+ <file>prime239v2.csv</file>
+ </curve>
+ <curve>
+ <id>prime239v3</id>
+ <bits>239</bits>
+ <field>prime</field>
+ <file>prime239v3.csv</file>
+ </curve>
+
+ <curve>
+ <id>prime256v1</id>
+ <bits>256</bits>
+ <field>prime</field>
+ <file>prime256v1.csv</file>
+ </curve>
+</curves> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/x962/prime192v1.csv b/src/cz/crcs/ectester/data/x962/prime192v1.csv
new file mode 100644
index 0000000..07f9154
--- /dev/null
+++ b/src/cz/crcs/ectester/data/x962/prime192v1.csv
@@ -0,0 +1 @@
+0xfffffffffffffffffffffffffffffffeffffffffffffffff,0xfffffffffffffffffffffffffffffffefffffffffffffffc,0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1,0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012,0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811,0xffffffffffffffffffffffff99def836146bc9b1b4d22831,0x1 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/x962/prime192v2.csv b/src/cz/crcs/ectester/data/x962/prime192v2.csv
new file mode 100644
index 0000000..ee6f1a2
--- /dev/null
+++ b/src/cz/crcs/ectester/data/x962/prime192v2.csv
@@ -0,0 +1 @@
+0xfffffffffffffffffffffffffffffffeffffffffffffffff,0xfffffffffffffffffffffffffffffffefffffffffffffffc,0xcc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953,0xeea2bae7e1497842f2de7769cfe9c989c072ad696f48034a,0x6574d11d69b6ec7a672bb82a083df2f2b0847de970b2de15,0xfffffffffffffffffffffffe5fb1a724dc80418648d8dd31,0x1 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/x962/prime192v3.csv b/src/cz/crcs/ectester/data/x962/prime192v3.csv
new file mode 100644
index 0000000..f80fd5b
--- /dev/null
+++ b/src/cz/crcs/ectester/data/x962/prime192v3.csv
@@ -0,0 +1 @@
+0xfffffffffffffffffffffffffffffffeffffffffffffffff,0xfffffffffffffffffffffffffffffffefffffffffffffffc,0x22123dc2395a05caa7423daeccc94760a7d462256bd56916,0x7d29778100c65a1da1783716588dce2b8b4aee8e228f1896,0x38a90f22637337334b49dcb66a6dc8f9978aca7648a943b0,0xffffffffffffffffffffffff7a62d031c83f4294f640ec13,0x1 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/x962/prime239v1.csv b/src/cz/crcs/ectester/data/x962/prime239v1.csv
new file mode 100644
index 0000000..c9d704b
--- /dev/null
+++ b/src/cz/crcs/ectester/data/x962/prime239v1.csv
@@ -0,0 +1 @@
+0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,0x6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a,0x0ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf,0x7debe8e4e90a5dae6e4054ca530ba04654b36818ce226b39fccb7b02f1ae,0x7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b,0x1 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/x962/prime239v2.csv b/src/cz/crcs/ectester/data/x962/prime239v2.csv
new file mode 100644
index 0000000..100e60b
--- /dev/null
+++ b/src/cz/crcs/ectester/data/x962/prime239v2.csv
@@ -0,0 +1 @@
+0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,0x617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c,0x38af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7,0x5b0125e4dbea0ec7206da0fc01d9b081329fb555de6ef460237dff8be4ba,0x7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063,0x1 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/x962/prime239v3.csv b/src/cz/crcs/ectester/data/x962/prime239v3.csv
new file mode 100644
index 0000000..ce8b38a
--- /dev/null
+++ b/src/cz/crcs/ectester/data/x962/prime239v3.csv
@@ -0,0 +1 @@
+0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,0x255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e,0x6768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a,0x1607e6898f390c06bc1d552bad226f3b6fcfe48b6e818499af18e3ed6cf3,0x7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551,0x1 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/x962/prime256v1.csv b/src/cz/crcs/ectester/data/x962/prime256v1.csv
new file mode 100644
index 0000000..c5a2440
--- /dev/null
+++ b/src/cz/crcs/ectester/data/x962/prime256v1.csv
@@ -0,0 +1 @@
+0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff,0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc,0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b,0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551,0x1 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java
index e11bcb3..1e42c52 100644
--- a/src/cz/crcs/ectester/reader/CardMngr.java
+++ b/src/cz/crcs/ectester/reader/CardMngr.java
@@ -2,11 +2,12 @@ package cz.crcs.ectester.reader;
import com.licel.jcardsim.io.CAD;
import com.licel.jcardsim.io.JavaxSmartCardInterface;
+import cz.crcs.ectester.common.util.ByteUtil;
import javacard.framework.AID;
+import javacard.framework.ISO7816;
import javax.smartcardio.*;
-import java.util.List;
-import java.util.Scanner;
+import java.util.*;
/**
* @author Petr Svenda petr@svenda.com
@@ -79,7 +80,7 @@ public class CardMngr {
//reset the card
if (verbose)
- System.out.println(Util.bytesToHex(card.getATR().getBytes()));
+ System.out.println(ByteUtil.bytesToHex(card.getATR().getBytes()));
cardFound = true;
}
@@ -108,7 +109,7 @@ public class CardMngr {
try {
card = terminal.connect("*");
ATR atr = card.getATR();
- System.out.println(terminalIndex + " : " + terminal.getName() + " - " + Util.bytesToHex(atr.getBytes()));
+ System.out.println(terminalIndex + " : " + terminal.getName() + " - " + ByteUtil.bytesToHex(atr.getBytes()));
terminalIndex++;
} catch (CardException ex) {
ex.printStackTrace(System.out);
@@ -164,50 +165,138 @@ public class CardMngr {
}
}
- public byte[] getCPLCData() throws Exception {
- byte[] data;
+ // Functions for CPLC taken and modified from https://github.com/martinpaljak/GlobalPlatformPro
+ private static final byte CLA_GP = (byte) 0x80;
+ private static final byte ISO7816_INS_GET_DATA = (byte) 0xCA;
+ private static final byte[] FETCH_GP_CPLC_APDU = {CLA_GP, ISO7816_INS_GET_DATA, (byte) 0x9F, (byte) 0x7F, (byte) 0x00};
+ private static final byte[] FETCH_ISO_CPLC_APDU = {ISO7816.CLA_ISO7816, ISO7816_INS_GET_DATA, (byte) 0x9F, (byte) 0x7F, (byte) 0x00};
+ private static final byte[] FETCH_GP_CARDDATA_APDU = {CLA_GP, ISO7816_INS_GET_DATA, (byte) 0x00, (byte) 0x66, (byte) 0x00};
- // TODO: Modify to obtain CPLC data
- byte apdu[] = new byte[HEADER_LENGTH];
- apdu[OFFSET_CLA] = (byte) 0x00;
- apdu[OFFSET_INS] = (byte) 0x00;
- apdu[OFFSET_P1] = (byte) 0x00;
- apdu[OFFSET_P2] = (byte) 0x00;
- apdu[OFFSET_LC] = (byte) 0x00;
+ public byte[] fetchCPLC() throws CardException {
+ // Try CPLC via GP
+ ResponseAPDU resp = send(FETCH_GP_CPLC_APDU);
+ // If GP CLA fails, try with ISO
+ if (resp.getSW() == (ISO7816.SW_CLA_NOT_SUPPORTED & 0xffff)) {
+ resp = send(FETCH_ISO_CPLC_APDU);
+ }
+ if (resp.getSW() == (ISO7816.SW_NO_ERROR & 0xffff)) {
+ return resp.getData();
+ }
+ return null;
+ }
- ResponseAPDU resp = send(apdu);
- if (resp.getSW() != 0x9000) { // 0x9000 is "OK"
- System.err.println("Fail to obtain card's response data");
- data = null;
- } else {
- byte temp[] = resp.getBytes();
- data = new byte[temp.length - 2];
- System.arraycopy(temp, 0, data, 0, temp.length - 2);
- // Last two bytes are status word (also obtainable by resp.getSW())
- // Take a look at ISO7816_status_words.txt for common codes
+ public static final class CPLC {
+ public enum Field {
+ ICFabricator,
+ ICType,
+ OperatingSystemID,
+ OperatingSystemReleaseDate,
+ OperatingSystemReleaseLevel,
+ ICFabricationDate,
+ ICSerialNumber,
+ ICBatchIdentifier,
+ ICModuleFabricator,
+ ICModulePackagingDate,
+ ICCManufacturer,
+ ICEmbeddingDate,
+ ICPrePersonalizer,
+ ICPrePersonalizationEquipmentDate,
+ ICPrePersonalizationEquipmentID,
+ ICPersonalizer,
+ ICPersonalizationDate,
+ ICPersonalizationEquipmentID
}
- return data;
- }
+ private Map<Field, byte[]> values = new TreeMap<>();
- public void probeCardCommands() throws Exception {
- // TODO: modify to probe for instruction
- for (int i = 0; i <= 0; i++) {
- byte apdu[] = new byte[HEADER_LENGTH];
- apdu[OFFSET_CLA] = (byte) 0x00;
- apdu[OFFSET_INS] = (byte) 0x00;
- apdu[OFFSET_P1] = (byte) 0x00;
- apdu[OFFSET_P2] = (byte) 0x00;
- apdu[OFFSET_LC] = (byte) 0x00;
+ public CPLC(byte[] data) {
+ if (data == null) {
+ return;
+ }
+ if (data.length < 3 || data[2] != 0x2A) {
+ throw new IllegalArgumentException("CPLC must be 0x2A bytes long");
+ }
+ //offset = TLVUtils.skipTag(data, offset, (short)0x9F7F);
+ short offset = 3;
+ values.put(Field.ICFabricator, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICType, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.OperatingSystemID, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.OperatingSystemReleaseDate, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.OperatingSystemReleaseLevel, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICFabricationDate, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICSerialNumber, Arrays.copyOfRange(data, offset, offset + 4));
+ offset += 4;
+ values.put(Field.ICBatchIdentifier, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICModuleFabricator, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICModulePackagingDate, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICCManufacturer, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICEmbeddingDate, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICPrePersonalizer, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICPrePersonalizationEquipmentDate, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICPrePersonalizationEquipmentID, Arrays.copyOfRange(data, offset, offset + 4));
+ offset += 4;
+ values.put(Field.ICPersonalizer, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICPersonalizationDate, Arrays.copyOfRange(data, offset, offset + 2));
+ offset += 2;
+ values.put(Field.ICPersonalizationEquipmentID, Arrays.copyOfRange(data, offset, offset + 4));
+ offset += 4;
+ }
- ResponseAPDU resp = send(apdu);
+ public Map<Field, byte[]> values() {
+ return values;
+ }
+ }
- if (verbose)
- System.out.println("Response: " + Integer.toHexString(resp.getSW()));
+ public CPLC getCPLC() throws CardException {
+ byte[] data = fetchCPLC();
+ return new CPLC(data);
+ }
- if (resp.getSW() != 0x6D00) { // Note: 0x6D00 is SW_INS_NOT_SUPPORTED
- // something?
- }
+ public static String mapCPLCField(CPLC.Field field, byte[] value) {
+ switch (field) {
+ case ICFabricator:
+ String id = ByteUtil.bytesToHex(value, false);
+ String fabricatorName = "unknown";
+ if (id.equals("3060")) {
+ fabricatorName = "Renesas";
+ }
+ if (id.equals("4090")) {
+ fabricatorName = "Infineon";
+ }
+ if (id.equals("4180")) {
+ fabricatorName = "Atmel";
+ }
+ if (id.equals("4250")) {
+ fabricatorName = "Samsung";
+ }
+ if (id.equals("4790")) {
+ fabricatorName = "NXP";
+ }
+ return id + " (" + fabricatorName + ")";
+ default:
+ return ByteUtil.bytesToHex(value, false);
+ }
+ }
+
+ public ATR getATR() {
+ if (simulate) {
+ return new ATR(simulator.getATR());
+ } else {
+ return card.getATR();
}
}
@@ -226,7 +315,7 @@ public class CardMngr {
System.out.println(">>>>");
System.out.println(apdu);
- System.out.println(Util.bytesToHex(apdu.getBytes()));
+ System.out.println(ByteUtil.bytesToHex(apdu.getBytes()));
}
long elapsed = -System.nanoTime();
@@ -237,7 +326,7 @@ public class CardMngr {
if (verbose) {
System.out.println(responseAPDU);
- System.out.println(Util.bytesToHex(responseAPDU.getBytes()));
+ System.out.println(ByteUtil.bytesToHex(responseAPDU.getBytes()));
}
if (responseAPDU.getSW1() == (byte) 0x61) {
@@ -247,7 +336,7 @@ public class CardMngr {
responseAPDU = channel.transmit(apduToSend);
if (verbose)
- System.out.println(Util.bytesToHex(responseAPDU.getBytes()));
+ System.out.println(ByteUtil.bytesToHex(responseAPDU.getBytes()));
}
if (verbose) {
@@ -276,7 +365,7 @@ public class CardMngr {
if (verbose) {
System.out.println(">>>>");
System.out.println(apdu);
- System.out.println(Util.bytesToHex(apdu.getBytes()));
+ System.out.println(ByteUtil.bytesToHex(apdu.getBytes()));
}
ResponseAPDU response = simulator.transmitCommand(apdu);
@@ -284,7 +373,7 @@ public class CardMngr {
if (verbose) {
System.out.println(response);
- System.out.println(Util.bytesToHex(responseBytes));
+ System.out.println(ByteUtil.bytesToHex(responseBytes));
System.out.println("<<<<");
}
diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTesterReader.java
index 550e070..5e3a3fe 100644
--- a/src/cz/crcs/ectester/reader/ECTester.java
+++ b/src/cz/crcs/ectester/reader/ECTesterReader.java
@@ -23,12 +23,19 @@ package cz.crcs.ectester.reader;
import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.cli.CLITools;
+import cz.crcs.ectester.common.ec.EC_Params;
+import cz.crcs.ectester.common.output.OutputLogger;
+import cz.crcs.ectester.common.output.TestWriter;
+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.data.EC_Store;
import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.ec.EC_Category;
-import cz.crcs.ectester.reader.ec.EC_Data;
-import cz.crcs.ectester.reader.ec.EC_Params;
-import cz.crcs.ectester.reader.output.*;
+import cz.crcs.ectester.reader.output.ResponseWriter;
+import cz.crcs.ectester.reader.output.TextTestWriter;
+import cz.crcs.ectester.reader.output.XMLTestWriter;
+import cz.crcs.ectester.reader.output.YAMLTestWriter;
import cz.crcs.ectester.reader.response.Response;
import cz.crcs.ectester.reader.test.*;
import javacard.security.KeyPair;
@@ -38,9 +45,13 @@ import javax.smartcardio.CardException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.nio.file.Files;
-import java.util.*;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Scanner;
import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH;
+import static cz.crcs.ectester.applet.ECTesterApplet.Signature_ALG_ECDSA_SHA;
/**
* Reader part of ECTester, a tool for testing Elliptic curve support on javacards.
@@ -49,18 +60,15 @@ import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH
* @author Jan Jancar johny@neuromancer.sk
* @version v0.1.0
*/
-public class ECTester {
-
+public class ECTesterReader {
private CardMngr cardManager;
private OutputLogger logger;
- private TestWriter testWriter;
private ResponseWriter respWriter;
- private EC_Store dataStore;
private Config cfg;
private Options opts = new Options();
private static final String VERSION = "v0.1.0";
- private static final String DESCRIPTION = "ECTester " + VERSION + ", a javacard Elliptic Curve Cryptograhy support tester/utility.";
+ 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 <petr@svenda.com>";
private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n";
private static final String CLI_FOOTER = "\n" + LICENSE;
@@ -76,11 +84,10 @@ public class ECTester {
//if help, print and quit
if (cli.hasOption("help")) {
- help();
+ CLITools.help("ECTesterReader.jar", CLI_HEADER, opts, CLI_FOOTER, true);
return;
} else if (cli.hasOption("version")) {
- System.out.println(DESCRIPTION);
- System.out.println(LICENSE);
+ CLITools.version(DESCRIPTION, LICENSE);
return;
}
cfg = new Config();
@@ -90,10 +97,9 @@ public class ECTester {
return;
}
- dataStore = new EC_Store();
//if list, print and quit
if (cli.hasOption("list-named")) {
- list();
+ CLITools.listNamed(EC_Store.getInstance(), cli.getOptionValue("list-named"));
return;
}
@@ -116,22 +122,7 @@ public class ECTester {
// Setup logger, testWriter and respWriter
logger = new OutputLogger(true, cfg.log);
- if (cfg.format == null) {
- testWriter = new TextTestWriter(logger.getPrintStream());
- } else {
- switch (cfg.format) {
- case "text":
- testWriter = new TextTestWriter(logger.getPrintStream());
- break;
- case "xml":
- testWriter = new XMLTestWriter(logger.getOutputStream());
- break;
- case "yaml":
- case "yml":
- testWriter = new YAMLTestWriter(logger.getPrintStream());
- break;
- }
- }
+
respWriter = new ResponseWriter(logger.getPrintStream());
//do action
@@ -187,9 +178,10 @@ public class ECTester {
System.err.println("File " + fnfe.getMessage() + " not found.");
} catch (ParseException | IOException ex) {
System.err.println(ex.getMessage());
- } catch (CardException ex) {
+ } catch (CardException | TestException ex) {
if (logger != null)
logger.println(ex.getMessage());
+ ex.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} finally {
@@ -213,8 +205,7 @@ public class ECTester {
* -e / --export
* -g / --generate [amount]
* -t / --test [test_suite]
- * -dh / --ecdh [count]
- * -dhc / --ecdhc [count]
+ * -dh / --ecdh [count]]
* -dsa / --ecdsa [count]
* -ln / --list-named [obj]
*
@@ -248,6 +239,7 @@ public class ECTester {
* -s / --simulate
* -y / --yes
* -ka/ --ka-type <type>
+ * -sig/--sig-type <type>
*/
OptionGroup actions = new OptionGroup();
actions.setRequired(true);
@@ -256,9 +248,8 @@ public class ECTester {
actions.addOption(Option.builder("ln").longOpt("list-named").desc("Print the list of supported named curves and keys.").hasArg().argName("what").optionalArg(true).build());
actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build());
actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build());
- actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- wrong:\n- composite:\n- test-vectors:").hasArg().argName("test_suite").optionalArg(true).build());
- actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do ECDH, [count] times.").hasArg().argName("count").optionalArg(true).build());
- actions.addOption(Option.builder("dhc").longOpt("ecdhc").desc("Do ECDHC, [count] times.").hasArg().argName("count").optionalArg(true).build());
+ actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- twist:\n- wrong:\n- composite:\n- test-vectors:").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());
opts.addOptionGroup(actions);
@@ -303,45 +294,13 @@ public class ECTester {
opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build());
opts.addOption(Option.builder("ka").longOpt("ka-type").desc("Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants.").hasArg().argName("type").optionalArg(true).build());
+ opts.addOption(Option.builder("sig").longOpt("sig-type").desc("Set Signature object [type], corresponds to JC.Signature constants.").hasArg().argName("type").optionalArg(true).build());
CommandLineParser parser = new DefaultParser();
return parser.parse(opts, args);
}
/**
- * Prints help.
- */
- private void help() {
- HelpFormatter help = new HelpFormatter();
- help.setOptionComparator(null);
- help.printHelp("ECTester.jar", CLI_HEADER, opts, CLI_FOOTER, true);
- }
-
- /**
- * List categories and named curves.
- */
- private void list() {
- Map<String, EC_Category> categories = dataStore.getCategories();
- if (cfg.listNamed == null) {
- // print all categories, briefly
- for (EC_Category cat : categories.values()) {
- System.out.println(cat);
- }
- } else if (categories.containsKey(cfg.listNamed)) {
- // print given category
- System.out.println(categories.get(cfg.listNamed));
- } else {
- // print given object
- EC_Data object = dataStore.getObject(EC_Data.class, cfg.listNamed);
- if (object != null) {
- System.out.println(object);
- } else {
- System.err.println("Named object " + cfg.listNamed + " not found!");
- }
- }
- }
-
- /**
* Exports default card/simulation EC domain parameters to output file.
*
* @throws CardException if APDU transmission fails
@@ -386,8 +345,9 @@ public class ECTester {
private void generate() throws CardException, IOException {
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send();
- Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass);
+ Response allocate = new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send();
+ respWriter.outputResponse(allocate);
+ Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass);
FileWriter keysFile = new FileWriter(cfg.output);
keysFile.write("index;time;pubW;privS\n");
@@ -417,8 +377,8 @@ public class ECTester {
}
respWriter.outputResponse(response);
- String pub = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
- String priv = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
+ String pub = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
+ String priv = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
String line = String.format("%d;%d;%s;%s\n", generated, elapsed / 1000000, pub, priv);
keysFile.write(line);
keysFile.flush();
@@ -436,20 +396,38 @@ public class ECTester {
* @throws CardException if APDU transmission fails
* @throws IOException if an IO error occurs when writing to key file.
*/
- private void test() throws IOException, CardException {
- TestSuite suite;
+ private void test() throws IOException, TestException, ParserConfigurationException {
+ TestWriter writer = null;
+ if (cfg.format == null) {
+ writer = new TextTestWriter(logger.getPrintStream());
+ } else {
+ switch (cfg.format) {
+ case "text":
+ writer = new TextTestWriter(logger.getPrintStream());
+ break;
+ case "xml":
+ writer = new XMLTestWriter(logger.getOutputStream());
+ break;
+ case "yaml":
+ case "yml":
+ writer = new YAMLTestWriter(logger.getPrintStream());
+ break;
+ }
+ }
+
+ CardTestSuite suite;
switch (cfg.testSuite) {
case "default":
- suite = new DefaultSuite(dataStore, cfg);
+ suite = new CardDefaultSuite(writer, cfg, cardManager);
break;
case "test-vectors":
- suite = new TestVectorSuite(dataStore, cfg);
+ suite = new CardTestVectorSuite(writer, cfg, cardManager);
break;
default:
- // These tests are dangerous, prompt before them.
+ // These run are dangerous, prompt before them.
System.out.println("The test you selected (" + cfg.testSuite + ") is potentially dangerous.");
- System.out.println("Some of these tests have caused temporary DoS of some cards.");
+ System.out.println("Some of these run have caused temporary DoS of some cards.");
if (!cfg.yes) {
System.out.print("Do you want to proceed? (y/n): ");
Scanner in = new Scanner(System.in);
@@ -459,17 +437,18 @@ public class ECTester {
}
in.close();
}
-
-
switch (cfg.testSuite) {
case "wrong":
- suite = new WrongCurvesSuite(dataStore, cfg);
+ suite = new CardWrongCurvesSuite(writer, cfg, cardManager);
break;
case "composite":
- suite = new CompositeCurvesSuite(dataStore, cfg);
+ suite = new CardCompositeCurvesSuite(writer, cfg, cardManager);
break;
case "invalid":
- suite = new InvalidCurvesSuite(dataStore, cfg);
+ suite = new CardInvalidCurvesSuite(writer, cfg, cardManager);
+ break;
+ case "twist":
+ suite = new CardTwistTestSuite(writer, cfg, cardManager);
break;
default:
System.err.println("Unknown test suite.");
@@ -478,9 +457,7 @@ public class ECTester {
break;
}
- TestRunner runner = new TestRunner(suite, testWriter);
- suite.setup(cardManager);
- runner.run();
+ suite.run();
}
/**
@@ -492,9 +469,9 @@ public class ECTester {
private void ecdh() throws IOException, CardException {
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
List<Response> prepare = new LinkedList<>();
- prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.kaType).send()); // Prepare KeyAgreement or required type
+ prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.ECKAType).send()); // Prepare KeyAgreement or required type
prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass).send());
- Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass);
+ Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass);
if (curve != null)
prepare.add(curve.send());
@@ -508,21 +485,26 @@ public class ECTester {
List<Command> generate = new LinkedList<>();
generate.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH));
if (cfg.anyPublicKey || cfg.anyPrivateKey || cfg.anyKey) {
- generate.add(Command.prepareKey(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_REMOTE));
+ generate.add(Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_REMOTE));
}
FileWriter out = null;
if (cfg.output != null) {
out = new FileWriter(cfg.output);
- out.write("index;time;secret\n");
+ out.write("index;time;pubW;privS;secret\n");
}
int retry = 0;
int done = 0;
- while (done < cfg.ECDHCount) {
+ while (done < cfg.ECKACount) {
List<Response> ecdh = Command.sendAll(generate);
- Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, cfg.ECDHKA).send();
+ Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send();
+ ecdh.add(export);
+ byte pubkey_bytes[] = export.getParameter(pubkey, EC_Consts.PARAMETER_W);
+ byte privkey_bytes[] = export.getParameter(privkey, EC_Consts.PARAMETER_S);
+
+ Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, cfg.ECKAType).send();
ecdh.add(perform);
for (Response r : ecdh) {
respWriter.outputResponse(r);
@@ -539,7 +521,7 @@ public class ECTester {
}
if (out != null) {
- out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSecret(), false)));
+ out.write(String.format("%d;%d;%s;%s;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(perform.getSecret(), false)));
}
++done;
@@ -571,15 +553,16 @@ public class ECTester {
Command generate;
if (cfg.anyKeypart) {
- generate = Command.prepareKey(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL);
+ generate = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL);
} else {
generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL);
}
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
List<Response> prepare = new LinkedList<>();
+ prepare.add(new Command.AllocateSignature(cardManager, cfg.ECDSAType).send());
prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send());
- Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass);
+ Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass);
if (curve != null)
prepare.add(curve.send());
@@ -599,7 +582,7 @@ public class ECTester {
List<Response> ecdsa = new LinkedList<>();
ecdsa.add(generate.send());
- Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, data).send();
+ Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data).send();
ecdsa.add(perform);
for (Response r : ecdsa) {
respWriter.outputResponse(r);
@@ -616,7 +599,7 @@ public class ECTester {
}
if (out != null) {
- out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSignature(), false)));
+ out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(perform.getSignature(), false)));
}
++done;
@@ -629,18 +612,18 @@ public class ECTester {
}
public static void main(String[] args) {
- ECTester app = new ECTester();
+ ECTesterReader app = new ECTesterReader();
app.run(args);
}
public static class Config {
//Options
- public int bits;
+ public short bits;
public boolean all;
public boolean primeField = false;
public boolean binaryField = false;
- public byte kaType = KeyAgreement_ALG_EC_SVDP_DH;
+
public String namedCurve;
public String curveFile;
@@ -674,9 +657,10 @@ public class ECTester {
public String listNamed;
public String testSuite;
public int generateAmount;
- public int ECDHCount;
- public byte ECDHKA;
+ public int ECKACount;
+ public byte ECKAType = KeyAgreement_ALG_EC_SVDP_DH;
public int ECDSACount;
+ public byte ECDSAType = Signature_ALG_ECDSA_SHA;
/**
* Reads and validates options, also sets defaults.
@@ -685,11 +669,11 @@ public class ECTester {
* @return whether the options are valid.
*/
boolean readOptions(CommandLine cli) {
- bits = Integer.parseInt(cli.getOptionValue("bit-size", "0"));
+ bits = Short.parseShort(cli.getOptionValue("bit-size", "0"));
all = cli.hasOption("all");
primeField = cli.hasOption("fp");
binaryField = cli.hasOption("f2m");
- kaType = Byte.parseByte(cli.getOptionValue("ka-type", "1"));
+
namedCurve = cli.getOptionValue("named-curve");
customCurve = cli.hasOption("custom");
@@ -770,7 +754,6 @@ public class ECTester {
System.err.println("You have to specify curve bit-size with -b");
return false;
}
-
} else if (cli.hasOption("generate")) {
if (primeField == binaryField) {
System.err.print("Need to specify field with -fp or -f2m. (not both)");
@@ -801,13 +784,12 @@ public class ECTester {
}
testSuite = cli.getOptionValue("test", "default").toLowerCase();
- String[] tests = new String[]{"default", "composite", "invalid", "test-vectors", "wrong"};
+ String[] tests = new String[]{"default", "composite", "invalid", "test-vectors", "wrong", "twist"};
if (!Arrays.asList(tests).contains(testSuite)) {
System.err.println("Unknown test suite " + testSuite + ". Should be one of: " + Arrays.toString(tests));
return false;
}
-
- } else if (cli.hasOption("ecdh") || cli.hasOption("ecdhc")) {
+ } else if (cli.hasOption("ecdh")) {
if (primeField == binaryField) {
System.err.print("Need to specify field with -fp or -f2m. (not both)");
return false;
@@ -817,18 +799,13 @@ public class ECTester {
return false;
}
- if (cli.hasOption("ecdh")) {
- ECDHCount = Integer.parseInt(cli.getOptionValue("ecdh", "1"));
- ECDHKA = EC_Consts.KA_ECDH;
- } else if (cli.hasOption("ecdhc")) {
- ECDHCount = Integer.parseInt(cli.getOptionValue("ecdhc", "1"));
- ECDHKA = EC_Consts.KA_ECDHC;
- }
- if (ECDHCount <= 0) {
+ ECKACount = Integer.parseInt(cli.getOptionValue("ecdh", "1"));
+ if (ECKACount <= 0) {
System.err.println("ECDH count cannot be <= 0.");
return false;
}
+ ECKAType = CardUtil.parseKAType(cli.getOptionValue("ka-type", "1"));
} else if (cli.hasOption("ecdsa")) {
if (primeField == binaryField) {
System.err.print("Need to specify field with -fp or -f2m. (but not both)");
@@ -849,6 +826,8 @@ public class ECTester {
System.err.println("ECDSA count cannot be <= 0.");
return false;
}
+
+ ECDSAType = CardUtil.parseSigType(cli.getOptionValue("sig-type", "17"));
}
return true;
}
diff --git a/src/cz/crcs/ectester/reader/Util.java b/src/cz/crcs/ectester/reader/Util.java
deleted file mode 100644
index 4e1154b..0000000
--- a/src/cz/crcs/ectester/reader/Util.java
+++ /dev/null
@@ -1,379 +0,0 @@
-package cz.crcs.ectester.reader;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_PACE_GM;
-import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH;
-import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC;
-import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN;
-import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_PLAIN;
-import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY;
-import cz.crcs.ectester.applet.EC_Consts;
-import javacard.framework.ISO7816;
-import javacard.security.CryptoException;
-
-/**
- * Utility class, some byte/hex manipulation, convenient byte[] methods.
- *
- * @author Petr Svenda petr@svenda.com
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class Util {
-
- public static short getShort(byte[] array, int offset) {
- return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF));
- }
-
- public static void setShort(byte[] array, int offset, short value) {
- array[offset + 1] = (byte) (value & 0xFF);
- array[offset] = (byte) ((value >> 8) & 0xFF);
- }
-
- public static int diffBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) {
- for (int i = 0; i < length; ++i) {
- byte a = one[i + oneOffset];
- byte b = other[i + otherOffset];
- if (a != b) {
- return i;
- }
- }
- return length;
- }
-
- public static boolean compareBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) {
- return diffBytes(one, oneOffset, other, otherOffset, length) == length;
- }
-
- public static boolean allValue(byte[] array, byte value) {
- for (byte a : array) {
- if (a != value)
- return false;
- }
- return true;
- }
-
- public static byte[] hexToBytes(String hex) {
- return hexToBytes(hex, true);
- }
-
- public static byte[] hexToBytes(String hex, boolean bigEndian) {
- hex = hex.replace(" ", "");
- int len = hex.length();
- StringBuilder sb = new StringBuilder();
-
- if (len % 2 == 1) {
- sb.append("0");
- ++len;
- }
-
- if (bigEndian) {
- sb.append(hex);
- } else {
- for (int i = 0; i < len / 2; ++i) {
- if (sb.length() >= 2) {
- sb.insert(sb.length() - 2, hex.substring(2 * i, 2 * i + 2));
- } else {
- sb.append(hex.substring(2 * i, 2 * i + 2));
- }
-
- }
- }
-
- String data = sb.toString();
- byte[] result = new byte[len / 2];
- for (int i = 0; i < len; i += 2) {
- result[i / 2] = (byte) ((Character.digit(data.charAt(i), 16) << 4)
- + (Character.digit(data.charAt(i + 1), 16)));
- }
- return result;
- }
-
- public static String byteToHex(byte data) {
- return String.format("%02x", data);
- }
-
- public static String bytesToHex(byte[] data) {
- return bytesToHex(data, true);
- }
-
- public static String bytesToHex(byte[] data, boolean addSpace) {
- return bytesToHex(data, 0, data.length, addSpace);
- }
-
- public static String bytesToHex(byte[] data, int offset, int len) {
- return bytesToHex(data, offset, len, true);
- }
-
- public static String bytesToHex(byte[] data, int offset, int len, boolean addSpace) {
- StringBuilder buf = new StringBuilder();
- for (int i = offset; i < (offset + len); i++) {
- buf.append(byteToHex(data[i]));
- if (addSpace && i != (offset + len - 1)) {
- buf.append(" ");
- }
- }
- return (buf.toString());
- }
-
- public static byte[] concatenate(byte[]... arrays) {
- int len = 0;
- for (byte[] array : arrays) {
- if (array == null)
- continue;
- len += array.length;
- }
- byte[] out = new byte[len];
- int offset = 0;
- for (byte[] array : arrays) {
- if (array == null || array.length == 0)
- continue;
- System.arraycopy(array, 0, out, offset, array.length);
- offset += array.length;
- }
- return out;
- }
-
- public static String getSWSource(short sw) {
- switch (sw) {
- case ISO7816.SW_NO_ERROR:
- case ISO7816.SW_APPLET_SELECT_FAILED:
- case ISO7816.SW_BYTES_REMAINING_00:
- case ISO7816.SW_CLA_NOT_SUPPORTED:
- case ISO7816.SW_COMMAND_NOT_ALLOWED:
- case ISO7816.SW_CONDITIONS_NOT_SATISFIED:
- case ISO7816.SW_CORRECT_LENGTH_00:
- case ISO7816.SW_DATA_INVALID:
- case ISO7816.SW_FILE_FULL:
- case ISO7816.SW_FILE_INVALID:
- case ISO7816.SW_FILE_NOT_FOUND:
- case ISO7816.SW_FUNC_NOT_SUPPORTED:
- case ISO7816.SW_INCORRECT_P1P2:
- case ISO7816.SW_INS_NOT_SUPPORTED:
- case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED:
- case ISO7816.SW_RECORD_NOT_FOUND:
- case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED:
- case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED:
- case ISO7816.SW_UNKNOWN:
- case ISO7816.SW_WARNING_STATE_UNCHANGED:
- case ISO7816.SW_WRONG_DATA:
- case ISO7816.SW_WRONG_LENGTH:
- case ISO7816.SW_WRONG_P1P2:
- return "ISO";
- case CryptoException.ILLEGAL_VALUE:
- case CryptoException.UNINITIALIZED_KEY:
- case CryptoException.NO_SUCH_ALGORITHM:
- case CryptoException.INVALID_INIT:
- case CryptoException.ILLEGAL_USE:
- return "CryptoException";
- case ECTesterApplet.SW_SIG_VERIFY_FAIL:
- case ECTesterApplet.SW_DH_DHC_MISMATCH:
- case ECTesterApplet.SW_KEYPAIR_NULL:
- case ECTesterApplet.SW_KA_NULL:
- case ECTesterApplet.SW_SIGNATURE_NULL:
- case ECTesterApplet.SW_OBJECT_NULL:
- return "ECTesterApplet";
- default:
- return "?";
- }
- }
-
- public static String getSW(short sw) {
- String str;
- switch (sw) {
- case ISO7816.SW_APPLET_SELECT_FAILED:
- str = "APPLET_SELECT_FAILED";
- break;
- case ISO7816.SW_BYTES_REMAINING_00:
- str = "BYTES_REMAINING";
- break;
- case ISO7816.SW_CLA_NOT_SUPPORTED:
- str = "CLA_NOT_SUPPORTED";
- break;
- case ISO7816.SW_COMMAND_NOT_ALLOWED:
- str = "COMMAND_NOT_ALLOWED";
- break;
- case ISO7816.SW_CONDITIONS_NOT_SATISFIED:
- str = "CONDITIONS_NOT_SATISFIED";
- break;
- case ISO7816.SW_CORRECT_LENGTH_00:
- str = "CORRECT_LENGTH";
- break;
- case ISO7816.SW_DATA_INVALID:
- str = "DATA_INVALID";
- break;
- case ISO7816.SW_FILE_FULL:
- str = "FILE_FULL";
- break;
- case ISO7816.SW_FILE_INVALID:
- str = "FILE_INVALID";
- break;
- case ISO7816.SW_FILE_NOT_FOUND:
- str = "FILE_NOT_FOUND";
- break;
- case ISO7816.SW_FUNC_NOT_SUPPORTED:
- str = "FUNC_NOT_SUPPORTED";
- break;
- case ISO7816.SW_INCORRECT_P1P2:
- str = "INCORRECT_P1P2";
- break;
- case ISO7816.SW_INS_NOT_SUPPORTED:
- str = "INS_NOT_SUPPORTED";
- break;
- case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED:
- str = "LOGICAL_CHANNEL_NOT_SUPPORTED";
- break;
- case ISO7816.SW_RECORD_NOT_FOUND:
- str = "RECORD_NOT_FOUND";
- break;
- case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED:
- str = "SECURE_MESSAGING_NOT_SUPPORTED";
- break;
- case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED:
- str = "SECURITY_STATUS_NOT_SATISFIED";
- break;
- case ISO7816.SW_UNKNOWN:
- str = "UNKNOWN";
- break;
- case ISO7816.SW_WARNING_STATE_UNCHANGED:
- str = "WARNING_STATE_UNCHANGED";
- break;
- case ISO7816.SW_WRONG_DATA:
- str = "WRONG_DATA";
- break;
- case ISO7816.SW_WRONG_LENGTH:
- str = "WRONG_LENGTH";
- break;
- case ISO7816.SW_WRONG_P1P2:
- str = "WRONG_P1P2";
- break;
- case CryptoException.ILLEGAL_VALUE:
- str = "ILLEGAL_VALUE";
- break;
- case CryptoException.UNINITIALIZED_KEY:
- str = "UNINITIALIZED_KEY";
- break;
- case CryptoException.NO_SUCH_ALGORITHM:
- str = "NO_SUCH_ALG";
- break;
- case CryptoException.INVALID_INIT:
- str = "INVALID_INIT";
- break;
- case CryptoException.ILLEGAL_USE:
- str = "ILLEGAL_USE";
- break;
- case ECTesterApplet.SW_SIG_VERIFY_FAIL:
- str = "SIG_VERIFY_FAIL";
- break;
- case ECTesterApplet.SW_DH_DHC_MISMATCH:
- str = "DH_DHC_MISMATCH";
- break;
- case ECTesterApplet.SW_KEYPAIR_NULL:
- str = "KEYPAIR_NULL";
- break;
- case ECTesterApplet.SW_KA_NULL:
- str = "KA_NULL";
- break;
- case ECTesterApplet.SW_SIGNATURE_NULL:
- str = "SIGNATURE_NULL";
- break;
- case ECTesterApplet.SW_OBJECT_NULL:
- str = "OBJECT_NULL";
- break;
- default:
- str = "unknown";
- break;
- }
- return str;
- }
-
- public static String getSWString(short sw) {
- if (sw == ISO7816.SW_NO_ERROR) {
- return "OK (0x9000)";
- } else {
- String str = getSW(sw);
- return String.format("fail (%s, 0x%04x)", str, sw);
- }
- }
-
- public static String getCorruption(short corruptionType) {
- String corrupt;
- switch (corruptionType) {
- case EC_Consts.CORRUPTION_NONE:
- corrupt = "NONE";
- break;
- case EC_Consts.CORRUPTION_FIXED:
- corrupt = "FIXED";
- break;
- case EC_Consts.CORRUPTION_ONE:
- corrupt = "ONE";
- break;
- case EC_Consts.CORRUPTION_ZERO:
- corrupt = "ZERO";
- break;
- case EC_Consts.CORRUPTION_ONEBYTERANDOM:
- corrupt = "ONE_BYTE_RANDOM";
- break;
- case EC_Consts.CORRUPTION_FULLRANDOM:
- corrupt = "FULL_RANDOM";
- break;
- case EC_Consts.CORRUPTION_INCREMENT:
- corrupt = "INCREMENT";
- break;
- case EC_Consts.CORRUPTION_INFINITY:
- corrupt = "INFINITY";
- break;
- case EC_Consts.CORRUPTION_COMPRESS:
- corrupt = "COMPRESSED";
- break;
- case EC_Consts.CORRUPTION_MAX:
- corrupt = "MAX";
- break;
- default:
- corrupt = "unknown";
- break;
- }
- return corrupt;
- }
-
- public static String getKA(byte ka) {
- String algo = "";
- if ((ka & EC_Consts.KA_ECDH) != 0 || ka == EC_Consts.KA_ANY) {
- algo += "ECDH";
- }
- if (ka == EC_Consts.KA_BOTH) {
- algo += "+";
- } else if (ka == EC_Consts.KA_ANY) {
- algo += "/";
- }
- if ((ka & EC_Consts.KA_ECDHC) != 0 || ka == EC_Consts.KA_ANY) {
- algo += "ECDHC";
- }
- return algo;
- }
-
- public static String getKATypeString(byte kaType) {
- String kaTypeString = "unknown";
- switch (kaType) {
- case KeyAgreement_ALG_EC_SVDP_DH:
- kaTypeString = "ALG_EC_SVDP_DH";
- break;
- case KeyAgreement_ALG_EC_SVDP_DH_PLAIN:
- kaTypeString = "ALG_EC_SVDP_DH_PLAIN";
- break;
- case KeyAgreement_ALG_EC_PACE_GM:
- kaTypeString = "ALG_EC_PACE_GM";
- break;
- case KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY:
- kaTypeString = "ALG_EC_SVDP_DH_PLAIN_XY";
- break;
- case KeyAgreement_ALG_EC_SVDP_DHC:
- kaTypeString = "ALG_EC_SVDP_DHC";
- break;
- case KeyAgreement_ALG_EC_SVDP_DHC_PLAIN:
- kaTypeString = "ALG_EC_SVDP_DHC_PLAIN";
- break;
- default:
- kaTypeString = "unknown";
- }
- return kaTypeString;
- }
-}
diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java
index 3c11456..5a6906c 100644
--- a/src/cz/crcs/ectester/reader/command/Command.java
+++ b/src/cz/crcs/ectester/reader/command/Command.java
@@ -2,15 +2,15 @@ package cz.crcs.ectester.reader.command;
import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.util.ByteUtil;
import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
+import cz.crcs.ectester.reader.ECTesterReader;
import cz.crcs.ectester.reader.response.Response;
-import cz.crcs.ectester.reader.Util;
-import cz.crcs.ectester.reader.ec.EC_Curve;
-import cz.crcs.ectester.reader.ec.EC_Key;
-import cz.crcs.ectester.reader.ec.EC_Keypair;
-import cz.crcs.ectester.reader.ec.EC_Params;
+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;
@@ -54,7 +54,7 @@ public abstract class Command {
* @return a Command to send in order to prepare the curve on the keypairs.
* @throws IOException if curve file cannot be found/opened
*/
- public static Command prepareCurve(CardMngr cardManager, EC_Store dataStore, ECTester.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException {
+ public static Command prepareCurve(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException {
if (cfg.customCurve) {
// Set custom curve (one of the SECG curves embedded applet-side)
@@ -109,7 +109,7 @@ public abstract class Command {
* @return a CommandAPDU setting params loaded on the keyPair/s
* @throws IOException if any of the key files cannot be found/opened
*/
- public static Command prepareKey(CardMngr cardManager, EC_Store dataStore, ECTester.Config cfg, byte keyPair) throws IOException {
+ public static Command prepareKey(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair) throws IOException {
short params = EC_Consts.PARAMETERS_NONE;
byte[] data = null;
@@ -174,7 +174,7 @@ public abstract class Command {
if (privkey == null) {
throw new IOException("Couldn't read the private key file correctly.");
}
- data = Util.concatenate(data, privkey);
+ data = ByteUtil.concatenate(data, privkey);
}
return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, params, data);
}
@@ -203,7 +203,7 @@ public abstract class Command {
this.keyClass = keyClass;
byte[] data = new byte[]{0, 0, keyClass};
- Util.setShort(data, 0, keyLength);
+ ByteUtil.setShort(data, 0, keyLength);
this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE, keyPair, 0x00, data);
}
@@ -214,13 +214,19 @@ public abstract class Command {
elapsed += System.nanoTime();
return new Response.Allocate(response, elapsed, keyPair, keyLength, keyClass);
}
+
+ @Override
+ public String toString() {
+ return "Allocate";
+ }
}
-
- public static class AllocateKeyAgreement extends Command {
+ /**
+ *
+ */
+ public static class AllocateKeyAgreement extends Command {
private byte kaType;
-
/**
* Creates the INS_ALLOCATE_KA instruction.
*
@@ -241,7 +247,45 @@ public abstract class Command {
elapsed += System.nanoTime();
return new Response.AllocateKeyAgreement(response, elapsed, kaType);
}
- }
+
+ @Override
+ public String toString() {
+ return "AllocateKeyAgreement";
+ }
+ }
+
+ /**
+ *
+ */
+ public static class AllocateSignature extends Command {
+ private byte sigType;
+
+ /**
+ * Creates the INS_ALLOCATE_SIG instruction.
+ *
+ * @param cardManager cardManager to send APDU through
+ * @param sigType which type of Signature to use
+ */
+ public AllocateSignature(CardMngr cardManager, byte sigType) {
+ super(cardManager);
+ 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.AllocateSignature send() throws CardException {
+ long elapsed = -System.nanoTime();
+ ResponseAPDU response = cardManager.send(cmd);
+ elapsed += System.nanoTime();
+ return new Response.AllocateSignature(response, elapsed, sigType);
+ }
+
+ @Override
+ public String toString() {
+ return "AllocateSignature";
+ }
+ }
/**
*
@@ -267,6 +311,11 @@ public abstract class Command {
elapsed += System.nanoTime();
return new Response.Clear(response, elapsed, keyPair);
}
+
+ @Override
+ public String toString() {
+ return "Clear";
+ }
}
/**
@@ -296,7 +345,7 @@ public abstract class Command {
int len = external != null ? 2 + external.length : 2;
byte[] data = new byte[len];
- Util.setShort(data, 0, params);
+ ByteUtil.setShort(data, 0, params);
if (external != null) {
System.arraycopy(external, 0, data, 2, external.length);
}
@@ -311,6 +360,11 @@ public abstract class Command {
elapsed += System.nanoTime();
return new Response.Set(response, elapsed, keyPair, curve, params);
}
+
+ @Override
+ public String toString() {
+ return "Set";
+ }
}
/**
@@ -337,7 +391,7 @@ public abstract class Command {
this.corruption = corruption;
byte[] data = new byte[3];
- Util.setShort(data, 0, params);
+ ByteUtil.setShort(data, 0, params);
data[2] = corruption;
this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CORRUPT, keyPair, key, data);
@@ -350,6 +404,11 @@ public abstract class Command {
elapsed += System.nanoTime();
return new Response.Corrupt(response, elapsed, keyPair, key, params, corruption);
}
+
+ @Override
+ public String toString() {
+ return "Corrupt";
+ }
}
/**
@@ -378,6 +437,11 @@ public abstract class Command {
elapsed += System.nanoTime();
return new Response.Generate(response, elapsed, keyPair);
}
+
+ @Override
+ public String toString() {
+ return "Generate";
+ }
}
/**
@@ -403,7 +467,7 @@ public abstract class Command {
this.params = params;
byte[] data = new byte[2];
- Util.setShort(data, 0, params);
+ ByteUtil.setShort(data, 0, params);
this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_EXPORT, keyPair, key, data);
}
@@ -415,6 +479,11 @@ public abstract class Command {
elapsed += System.nanoTime();
return new Response.Export(response, elapsed, keyPair, key, params);
}
+
+ @Override
+ public String toString() {
+ return "Export";
+ }
}
/**
@@ -446,7 +515,7 @@ public abstract class Command {
this.type = type;
byte[] data = new byte[]{export, 0,0, type};
- Util.setShort(data, 1, corruption);
+ ByteUtil.setShort(data, 1, corruption);
this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDH, pubkey, privkey, data);
}
@@ -458,6 +527,11 @@ public abstract class Command {
elapsed += System.nanoTime();
return new Response.ECDH(response, elapsed, pubkey, privkey, export, corruption, type);
}
+
+ @Override
+ public String toString() {
+ return "ECDH";
+ }
}
/**
@@ -477,7 +551,7 @@ public abstract class Command {
* @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
* @param export whether to export ECDH secret
* @param corruption whether to invalidate the pubkey before ECDH (EC_Consts.CORRUPTION_* | ...)
- * @param type ECDH algorithm type (EC_Consts.KA_* | ...)
+ * @param type EC KeyAgreement type
* @param pubkey pubkey data to do ECDH with.
*/
public ECDH_direct(CardMngr cardManager, byte privkey, byte export, short corruption, byte type, byte[] pubkey) {
@@ -489,7 +563,7 @@ public abstract class Command {
this.pubkey = pubkey;
byte[] data = new byte[3 + pubkey.length];
- Util.setShort(data, 0, corruption);
+ ByteUtil.setShort(data, 0, corruption);
data[2] = type;
System.arraycopy(pubkey, 0, data, 3, pubkey.length);
@@ -503,10 +577,16 @@ public abstract class Command {
elapsed += System.nanoTime();
return new Response.ECDH(response, elapsed, ECTesterApplet.KEYPAIR_REMOTE, privkey, export, corruption, type);
}
+
+ @Override
+ public String toString() {
+ return "ECDH_direct";
+ }
}
public static class ECDSA extends Command {
private byte keyPair;
+ private byte sigType;
private byte export;
private byte[] raw;
@@ -515,20 +595,23 @@ public abstract class Command {
*
* @param cardManager cardManager to send APDU through
* @param keyPair keyPair to use for signing and verification (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
+ * @param sigType Signature type to use
* @param export whether to export ECDSA signature
* @param raw data to sign, can be null, in which case random data is signed.
*/
- public ECDSA(CardMngr cardManager, byte keyPair, byte export, byte[] raw) {
+ public ECDSA(CardMngr cardManager, byte keyPair, byte sigType, byte export, byte[] raw) {
super(cardManager);
this.keyPair = keyPair;
+ this.sigType = sigType;
this.export = export;
this.raw = raw;
int len = raw != null ? raw.length : 0;
- byte[] data = new byte[2 + len];
- Util.setShort(data, 0, (short) len);
+ byte[] data = new byte[3 + len];
+ data[0] = sigType;
+ ByteUtil.setShort(data, 1, (short) len);
if (raw != null) {
- System.arraycopy(raw, 0, data, 2, len);
+ System.arraycopy(raw, 0, data, 3, len);
}
this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDSA, keyPair, export, data);
@@ -539,7 +622,12 @@ public abstract class Command {
long elapsed = -System.nanoTime();
ResponseAPDU response = cardManager.send(cmd);
elapsed += System.nanoTime();
- return new Response.ECDSA(response, elapsed, keyPair, export, raw);
+ return new Response.ECDSA(response, elapsed, keyPair, sigType, export, raw);
+ }
+
+ @Override
+ public String toString() {
+ return "ECDSA";
}
}
@@ -564,28 +652,10 @@ public abstract class Command {
elapsed += System.nanoTime();
return new Response.Cleanup(response, elapsed);
}
- }
-
- /**
- *
- */
- public static class Support extends Command {
-
- /**
- * @param cardManager cardManager to send APDU through
- */
- public Support(CardMngr cardManager) {
- super(cardManager);
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SUPPORT, 0, 0);
- }
@Override
- public Response.Support send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.Support(response, elapsed);
+ public String toString() {
+ return "Cleanup";
}
}
}
diff --git a/src/cz/crcs/ectester/reader/ec/EC_Curve.java b/src/cz/crcs/ectester/reader/ec/EC_Curve.java
deleted file mode 100644
index cb4a2df..0000000
--- a/src/cz/crcs/ectester/reader/ec/EC_Curve.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package cz.crcs.ectester.reader.ec;
-
-import cz.crcs.ectester.applet.EC_Consts;
-import javacard.security.KeyPair;
-
-/**
- * An Elliptic curve, contains parameters Fp/F2M, A, B, G, R, (K)?.
- *
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class EC_Curve extends EC_Params {
- private short bits;
- private byte field;
- private String desc;
-
- /**
- * @param bits
- * @param field KeyPair.ALG_EC_FP or KeyPair.ALG_EC_F2M
- */
- public EC_Curve(short bits, byte field) {
- super(field == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M);
- this.bits = bits;
- this.field = field;
- }
-
- public EC_Curve(String id, short bits, byte field) {
- this(bits, field);
- this.id = id;
- }
-
- public EC_Curve(String id, short bits, byte field, String desc) {
- this(id, bits, field);
- this.desc = desc;
- }
-
- public short getBits() {
- return bits;
- }
-
- public byte getField() {
- return field;
- }
-
- public String getDesc() {
- return desc;
- }
-
- @Override
- public String toString() {
- return "<" + getId() + "> " + (field == KeyPair.ALG_EC_FP ? "Prime" : "Binary") + " field Elliptic curve (" + String.valueOf(bits) + "b)" + (desc == null ? "" : ": " + desc);
- }
-}
diff --git a/src/cz/crcs/ectester/reader/output/ResponseWriter.java b/src/cz/crcs/ectester/reader/output/ResponseWriter.java
index c357233..85bf79a 100644
--- a/src/cz/crcs/ectester/reader/output/ResponseWriter.java
+++ b/src/cz/crcs/ectester/reader/output/ResponseWriter.java
@@ -1,6 +1,6 @@
package cz.crcs.ectester.reader.output;
-import cz.crcs.ectester.reader.Util;
+import cz.crcs.ectester.common.util.CardUtil;
import cz.crcs.ectester.reader.response.Response;
import java.io.PrintStream;
@@ -20,20 +20,24 @@ public class ResponseWriter {
for (int j = 0; j < r.getNumSW(); ++j) {
short sw = r.getSW(j);
if (sw != 0) {
- suffix.append(" ").append(Util.getSWString(sw));
+ suffix.append(" ").append(CardUtil.getSWString(sw));
}
}
if (suffix.length() == 0) {
- suffix.append(" [").append(Util.getSW(r.getNaturalSW())).append("]");
+ suffix.append(" [").append(CardUtil.getSW(r.getNaturalSW())).append(String.format(" 0x%04x", r.getNaturalSW())).append("]");
}
return String.format("%4d ms ┃ %s", r.getDuration() / 1000000, suffix);
}
- public void outputResponse(Response r) {
+ public String responseString(Response r) {
String out = "";
out += String.format("%-70s", r.getDescription()) + " ┃ ";
out += responseSuffix(r);
- output.println(out);
+ return out;
+ }
+
+ public void outputResponse(Response r) {
+ output.println(responseString(r));
output.flush();
}
}
diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java
index bcebcd5..eb52937 100644
--- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java
@@ -1,85 +1,57 @@
package cz.crcs.ectester.reader.output;
-import cz.crcs.ectester.reader.test.Test;
-import cz.crcs.ectester.reader.test.TestSuite;
+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.common.util.ByteUtil;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.test.CardTestSuite;
+import cz.crcs.ectester.reader.test.CommandTestable;
+import javax.smartcardio.CardException;
import java.io.PrintStream;
+import java.util.Map;
/**
* @author Jan Jancar johny@neuromancer.sk
*/
-public class TextTestWriter implements TestWriter {
- private PrintStream output;
- private ResponseWriter respWriter;
-
- public static int BASE_WIDTH = 76;
+public class TextTestWriter extends BaseTextTestWriter {
+ private ResponseWriter writer;
public TextTestWriter(PrintStream output) {
- this.output = output;
- this.respWriter = new ResponseWriter(output);
+ super(output);
+ this.writer = new ResponseWriter(output);
}
@Override
- public void begin(TestSuite suite) {
- output.println("=== Running test suite: " + suite.getName() + " ===");
- output.println("=== " + suite.getDescription());
- }
-
- private String testString(Test t, int offset) {
- if (!t.hasRun()) {
- return null;
+ protected String testableString(Testable t) {
+ if (t instanceof CommandTestable) {
+ CommandTestable cmd = (CommandTestable) t;
+ return writer.responseSuffix(cmd.getResponse());
}
+ return "";
+ }
- StringBuilder out = new StringBuilder();
- if (t instanceof Test.Simple) {
- Test.Simple test = (Test.Simple) t;
- out.append(test.ok() ? "OK " : "NOK ");
- out.append("━ ");
- int width = BASE_WIDTH - (offset + out.length());
- String widthSpec = "%-" + String.valueOf(width) + "s";
- out.append(String.format(widthSpec, t.getDescription()));
- out.append(" ┃ ");
- out.append(String.format("%-9s", test.getResultValue().name()));
- out.append(" ┃ ");
- out.append(respWriter.responseSuffix(test.getResponse()));
- } else {
- Test.Compound test = (Test.Compound) t;
- out.append(test.ok() ? "OK " : "NOK ");
- out.append("┳ ");
- int width = BASE_WIDTH - (offset + out.length());
- String widthSpec = "%-" + String.valueOf(width) + "s";
- out.append(String.format(widthSpec, t.getDescription()));
- out.append(" ┃ ");
- out.append(String.format("%-9s", test.getResultValue().name()));
- out.append(" ┃ ");
- out.append(test.getResultCause());
- out.append(System.lineSeparator());
- Test[] tests = test.getTests();
- for (int i = 0; i < tests.length; ++i) {
- if (i == tests.length - 1) {
- out.append(" ┗ ");
- } else {
- out.append(" ┣ ");
- }
- out.append(testString(tests[i], offset + 6));
- if (i != tests.length - 1) {
- out.append(System.lineSeparator());
+ @Override
+ protected String deviceString(TestSuite suite) {
+ if (suite instanceof CardTestSuite) {
+ CardTestSuite cardSuite = (CardTestSuite) suite;
+ StringBuilder sb = new StringBuilder();
+ sb.append("═══ Card ATR: ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator());
+ try {
+ CardMngr.CPLC cplc = cardSuite.getCard().getCPLC();
+ if (!cplc.values().isEmpty()) {
+ sb.append("═══ Card CPLC data:").append(System.lineSeparator());
+ for (Map.Entry<CardMngr.CPLC.Field, byte[]> entry : cplc.values().entrySet()) {
+ CardMngr.CPLC.Field field = entry.getKey();
+ byte[] value = entry.getValue();
+ sb.append("═══ ").append(field.name()).append(": ").append(CardMngr.mapCPLCField(field, value));
+ }
}
+ } catch (CardException ignored) {
}
+ return sb.toString();
}
-
- return out.toString();
- }
-
- @Override
- public void outputTest(Test t) {
- if (!t.hasRun())
- return;
- output.println(testString(t, 0));
- output.flush();
- }
-
- @Override
- public void end() {
+ return "";
}
}
diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
index beb758c..d3674e8 100644
--- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
@@ -1,55 +1,34 @@
package cz.crcs.ectester.reader.output;
-import cz.crcs.ectester.reader.Util;
+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.reader.CardMngr;
import cz.crcs.ectester.reader.command.Command;
import cz.crcs.ectester.reader.response.Response;
-import cz.crcs.ectester.reader.test.Test;
-import cz.crcs.ectester.reader.test.TestSuite;
-import org.w3c.dom.Document;
+import cz.crcs.ectester.reader.test.CardTestSuite;
+import cz.crcs.ectester.reader.test.CommandTestable;
import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
+import javax.smartcardio.CardException;
import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
import java.io.OutputStream;
+import java.util.Map;
/**
* @author Jan Jancar johny@neuromancer.sk
*/
-public class XMLTestWriter implements TestWriter {
- private OutputStream output;
- private DocumentBuilder db;
- private Document doc;
- private Node root;
-
+public class XMLTestWriter extends BaseXMLTestWriter {
public XMLTestWriter(OutputStream output) throws ParserConfigurationException {
- this.output = output;
- this.db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
- }
-
- @Override
- public void begin(TestSuite suite) {
- doc = db.newDocument();
- Element rootElem = doc.createElement("testSuite");
- rootElem.setAttribute("name", suite.getName());
- rootElem.setAttribute("desc", suite.getDescription());
-
- root = rootElem;
- doc.appendChild(root);
+ super(output);
}
private Element commandElement(Command c) {
Element commandElem = doc.createElement("command");
Element apdu = doc.createElement("apdu");
- apdu.setTextContent(Util.bytesToHex(c.getAPDU().getBytes()));
+ apdu.setTextContent(ByteUtil.bytesToHex(c.getAPDU().getBytes()));
commandElem.appendChild(apdu);
return commandElem;
@@ -60,7 +39,7 @@ public class XMLTestWriter implements TestWriter {
responseElem.setAttribute("successful", r.successful() ? "true" : "false");
Element apdu = doc.createElement("apdu");
- apdu.setTextContent(Util.bytesToHex(r.getAPDU().getBytes()));
+ apdu.setTextContent(ByteUtil.bytesToHex(r.getAPDU().getBytes()));
responseElem.appendChild(apdu);
Element naturalSW = doc.createElement("natural-sw");
@@ -86,60 +65,50 @@ public class XMLTestWriter implements TestWriter {
return responseElem;
}
- private Element testElement(Test t) {
- Element testElem = doc.createElement("test");
+ @Override
+ protected Element testableElement(Testable t) {
+ if (t instanceof CommandTestable) {
+ CommandTestable cmd = (CommandTestable) t;
+ Element result = doc.createElement("test");
+ result.setAttribute("type", "command");
+ result.appendChild(commandElement(cmd.getCommand()));
+ result.appendChild(responseElement(cmd.getResponse()));
+ return result;
+ }
+ return null;
+ }
- if (t instanceof Test.Simple) {
- Test.Simple test = (Test.Simple) t;
- testElem.setAttribute("type", "simple");
- testElem.appendChild(commandElement(test.getCommand()));
- testElem.appendChild(responseElement(test.getResponse()));
- } else if (t instanceof Test.Compound) {
- Test.Compound test = (Test.Compound) t;
- testElem.setAttribute("type", "compound");
- for (Test innerTest : test.getTests()) {
- testElem.appendChild(testElement(innerTest));
+ private Element cplcElement(CardMngr card) {
+ Element result = doc.createElement("cplc");
+ try {
+ CardMngr.CPLC cplc = card.getCPLC();
+ if (!cplc.values().isEmpty()) {
+ for (Map.Entry<CardMngr.CPLC.Field, byte[]> entry : cplc.values().entrySet()) {
+ CardMngr.CPLC.Field field = entry.getKey();
+ byte[] value = entry.getValue();
+ Element keyVal = doc.createElement(field.name());
+ keyVal.setTextContent(ByteUtil.bytesToHex(value, false));
+ result.appendChild(keyVal);
+ }
}
+ } catch (CardException ignored) {
}
-
- Element description = doc.createElement("desc");
- 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);
- testElem.appendChild(result);
-
- return testElem;
+ return result;
}
@Override
- public void outputTest(Test t) {
- if (!t.hasRun())
- return;
- root.appendChild(testElement(t));
- }
+ protected Element deviceElement(TestSuite suite) {
+ if (suite instanceof CardTestSuite) {
+ CardTestSuite cardSuite = (CardTestSuite) suite;
+ Element result = doc.createElement("device");
+ result.setAttribute("type", "card");
+ result.appendChild(cplcElement(cardSuite.getCard()));
- @Override
- public void end() {
- try {
- DOMSource domSource = new DOMSource(doc);
- StreamResult result = new StreamResult(output);
- TransformerFactory tf = TransformerFactory.newInstance();
- Transformer transformer = tf.newTransformer();
- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
- transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
- transformer.transform(domSource, result);
- } catch (TransformerException e) {
- e.printStackTrace();
+ Element atr = doc.createElement("ATR");
+ atr.setTextContent(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false));
+ result.appendChild(atr);
+ return result;
}
+ return null;
}
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
index 3b2b72d..199f2c0 100644
--- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
@@ -1,13 +1,16 @@
package cz.crcs.ectester.reader.output;
-import cz.crcs.ectester.reader.Util;
+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.reader.CardMngr;
import cz.crcs.ectester.reader.command.Command;
import cz.crcs.ectester.reader.response.Response;
-import cz.crcs.ectester.reader.test.Test;
-import cz.crcs.ectester.reader.test.TestSuite;
-import org.yaml.snakeyaml.DumperOptions;
-import org.yaml.snakeyaml.Yaml;
+import cz.crcs.ectester.reader.test.CardTestSuite;
+import cz.crcs.ectester.reader.test.CommandTestable;
+import javax.smartcardio.CardException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.LinkedList;
@@ -17,39 +20,21 @@ import java.util.Map;
/**
* @author Jan Jancar johny@neuromancer.sk
*/
-public class YAMLTestWriter implements TestWriter {
- private PrintStream output;
- private Map<String, Object> testRun;
- private Map<String, String> testSuite;
- private List<Object> tests;
-
+public class YAMLTestWriter extends BaseYAMLTestWriter {
public YAMLTestWriter(PrintStream output) {
- this.output = output;
- }
-
- @Override
- public void begin(TestSuite suite) {
- output.println("---");
- testRun = new HashMap<>();
- testSuite = new HashMap<>();
- tests = new LinkedList<>();
- testSuite.put("name", suite.getName());
- testSuite.put("desc", suite.getDescription());
-
- testRun.put("suite", testSuite);
- testRun.put("tests", tests);
+ super(output);
}
private Map<String, Object> commandObject(Command c) {
Map<String, Object> commandObj = new HashMap<>();
- commandObj.put("apdu", Util.bytesToHex(c.getAPDU().getBytes()));
+ commandObj.put("apdu", ByteUtil.bytesToHex(c.getAPDU().getBytes()));
return commandObj;
}
private Map<String, Object> responseObject(Response r) {
Map<String, Object> responseObj = new HashMap<>();
responseObj.put("successful", r.successful());
- responseObj.put("apdu", Util.bytesToHex(r.getAPDU().getBytes()));
+ responseObj.put("apdu", ByteUtil.bytesToHex(r.getAPDU().getBytes()));
responseObj.put("natural_sw", Short.toUnsignedInt(r.getNaturalSW()));
List<Integer> sws = new LinkedList<>();
for (int i = 0; i < r.getNumSW(); ++i) {
@@ -61,53 +46,45 @@ public class YAMLTestWriter implements TestWriter {
return responseObj;
}
- private Map<String, Object> testObject(Test t) {
- Map<String, Object> testObj = new HashMap<>();
-
- if (t instanceof Test.Simple) {
- Test.Simple test = (Test.Simple) t;
- testObj.put("type", "simple");
- testObj.put("command", commandObject(test.getCommand()));
- testObj.put("response", responseObject(test.getResponse()));
- } else if (t instanceof Test.Compound) {
- Test.Compound test = (Test.Compound) t;
- testObj.put("type", "compound");
- List<Map<String, Object>> tests = new LinkedList<>();
- for (Test innerTest : test.getTests()) {
- tests.add(testObject(innerTest));
- }
- testObj.put("tests", tests);
+ @Override
+ protected Map<String, Object> testableObject(Testable t) {
+ if (t instanceof CommandTestable) {
+ CommandTestable cmd = (CommandTestable) t;
+ Map<String, Object> result = new HashMap<>();
+ result.put("type", "command");
+ result.put("command", commandObject(cmd.getCommand()));
+ result.put("response", responseObject(cmd.getResponse()));
+ return result;
}
-
- testObj.put("desc", t.getDescription());
- Map<String, Object> result = new HashMap<>();
- result.put("ok", t.ok());
- result.put("value", t.getResultValue().name());
- result.put("cause", t.getResultCause());
- testObj.put("result", result);
-
- return testObj;
+ return null;
}
- @Override
- public void outputTest(Test t) {
- if (!t.hasRun())
- return;
- tests.add(testObject(t));
+ private Map<String, Object> cplcObject(CardMngr card) {
+ Map<String, Object> result = new HashMap<>();
+ try {
+ CardMngr.CPLC cplc = card.getCPLC();
+ if (!cplc.values().isEmpty()) {
+ for (Map.Entry<CardMngr.CPLC.Field, byte[]> entry : cplc.values().entrySet()) {
+ CardMngr.CPLC.Field field = entry.getKey();
+ byte[] value = entry.getValue();
+ result.put(field.name(), ByteUtil.bytesToHex(value, false));
+ }
+ }
+ } catch (CardException ignored) {
+ }
+ return result;
}
@Override
- public void end() {
- DumperOptions options = new DumperOptions();
- options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
- options.setPrettyFlow(true);
- Yaml yaml = new Yaml(options);
-
- Map<String, Object> result = new HashMap<>();
- result.put("testRun", testRun);
- String out = yaml.dump(result);
-
- output.println(out);
- output.println("---");
+ protected Map<String, Object> deviceObject(TestSuite suite) {
+ if (suite instanceof CardTestSuite) {
+ CardTestSuite cardSuite = (CardTestSuite) suite;
+ Map<String, Object> result = new HashMap<>();
+ result.put("type", "card");
+ result.put("cplc", cplcObject(cardSuite.getCard()));
+ result.put("ATR", ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false));
+ return result;
+ }
+ return null;
}
}
diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java
index 4abfd14..cbed3b2 100644
--- a/src/cz/crcs/ectester/reader/response/Response.java
+++ b/src/cz/crcs/ectester/reader/response/Response.java
@@ -2,8 +2,8 @@ package cz.crcs.ectester.reader.response;
import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.reader.Util;
-import cz.crcs.ectester.reader.ec.EC_Data;
+import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.common.util.CardUtil;
import javacard.framework.ISO7816;
import javacard.security.KeyPair;
@@ -13,7 +13,6 @@ import javax.smartcardio.ResponseAPDU;
* @author Jan Jancar johny@neuromancer.sk
*/
public abstract class Response {
-
private ResponseAPDU resp;
private long time;
private short[] sws;
@@ -37,7 +36,7 @@ public abstract class Response {
//parse SWs in response
for (int i = 0; i < numSW; ++i) {
if (getLength() >= (offset + 2)) {
- short sw = Util.getShort(data, offset);
+ short sw = ByteUtil.getShort(data, offset);
offset += 2;
sws[i] = sw;
if (sw != ISO7816.SW_NO_ERROR) {
@@ -63,7 +62,7 @@ public abstract class Response {
error = true;
break;
}
- short paramLength = Util.getShort(data, offset);
+ short paramLength = ByteUtil.getShort(data, offset);
offset += 2;
if (data.length < offset + paramLength) {
error = true;
@@ -88,6 +87,10 @@ public abstract class Response {
return (short) resp.getSW();
}
+ public short[] getSWs() {
+ return sws;
+ }
+
public short getSW(int index) {
return sws[index];
}
@@ -130,24 +133,44 @@ public abstract class Response {
*
*/
public static class AllocateKeyAgreement extends Response {
- byte kaType;
+ private byte kaType;
public AllocateKeyAgreement(ResponseAPDU response, long time, byte kaType) {
super(response, time);
this.kaType = kaType;
- parse(2, 0);
+ parse(1, 0);
}
@Override
public String getDescription() {
- return String.format("Allocated KeyAgreement(%s) object", Util.getKATypeString(this.kaType));
+ return String.format("Allocated KeyAgreement(%s) object", CardUtil.getKATypeString(this.kaType));
}
+ }
+
+ /**
+ *
+ */
+ public static class AllocateSignature extends Response {
+ private byte sigType;
+
+ public AllocateSignature(ResponseAPDU response, long time, byte sigType) {
+ super(response, time);
+ this.sigType = sigType;
+ parse(1, 0);
+ }
+
+ @Override
+ public String getDescription() {
+ return String.format("Allocated Signature(%s) object", CardUtil.getSigTypeString(this.sigType));
+ }
}
+ /**
+ *
+ */
public static class Allocate extends Response {
-
private byte keyPair;
private short keyLength;
private byte keyClass;
@@ -181,7 +204,6 @@ public abstract class Response {
*
*/
public static class Clear extends Response {
-
private byte keyPair;
public Clear(ResponseAPDU response, long time, byte keyPair) {
@@ -210,7 +232,6 @@ public abstract class Response {
*
*/
public static class Set extends Response {
-
private byte keyPair;
private byte curve;
private short parameters;
@@ -268,7 +289,6 @@ public abstract class Response {
*
*/
public static class Corrupt extends Response {
-
private byte keyPair;
private byte key;
private short params;
@@ -290,7 +310,7 @@ public abstract class Response {
@Override
public String getDescription() {
- String corrupt = Util.getCorruption(corruption);
+ String corrupt = CardUtil.getCorruption(corruption);
String pair;
if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
@@ -306,7 +326,6 @@ public abstract class Response {
*
*/
public static class Generate extends Response {
-
private byte keyPair;
public Generate(ResponseAPDU response, long time, byte keyPair) {
@@ -336,7 +355,6 @@ public abstract class Response {
*
*/
public static class Export extends Response {
-
private byte keyPair;
private byte key;
private short parameters;
@@ -445,7 +463,6 @@ public abstract class Response {
*
*/
public static class ECDH extends Response {
-
private byte pubkey;
private byte privkey;
private byte export;
@@ -477,7 +494,7 @@ public abstract class Response {
@Override
public String getDescription() {
- String algo = Util.getKA(type);
+ String algo = CardUtil.getKATypeString(type);
String pub = pubkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
@@ -486,7 +503,7 @@ public abstract class Response {
if (corruption == EC_Consts.CORRUPTION_NONE) {
validity = "unchanged";
} else {
- validity = Util.getCorruption(corruption);
+ validity = CardUtil.getCorruption(corruption);
}
return String.format("%s of %s pubkey and %s privkey(%s point)", algo, pub, priv, validity);
}
@@ -496,14 +513,15 @@ public abstract class Response {
*
*/
public static class ECDSA extends Response {
-
private byte keyPair;
+ private byte sigType;
private byte export;
private byte[] raw;
- public ECDSA(ResponseAPDU response, long time, byte keyPair, byte export, byte[] raw) {
+ public ECDSA(ResponseAPDU response, long time, byte keyPair, byte sigType, byte export, byte[] raw) {
super(response, time);
this.keyPair = keyPair;
+ this.sigType = sigType;
this.export = export;
this.raw = raw;
@@ -520,9 +538,10 @@ public abstract class Response {
@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("ECDSA with %s keypair(%s data)", key, data);
+ return String.format("%s with %s keypair(%s data)", algo, key, data);
}
}
@@ -543,21 +562,4 @@ public abstract class Response {
}
}
-
- /**
- *
- */
- public static class Support extends Response {
-
- public Support(ResponseAPDU response, long time) {
- super(response, time);
-
- parse(3, 0);
- }
-
- @Override
- public String getDescription() {
- return "Support of ECDH, ECDHC, ECDSA allocation";
- }
- }
}
diff --git a/src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java
new file mode 100644
index 0000000..a53806c
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java
@@ -0,0 +1,51 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+import javacard.security.KeyPair;
+
+import java.util.Map;
+
+import static cz.crcs.ectester.common.test.Result.ExpectedValue;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardCompositeCurvesSuite extends CardTestSuite {
+
+ public CardCompositeCurvesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "composite", "The composite suite run ECDH over curves with composite order. This should generally fail, as using such a curve is unsafe.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ /* Do the default run with the public keys set to provided smallorder keys
+ * over composite order curves. Essentially small subgroup attacks.
+ * These should fail, the curves aren't safe so that if the computation with
+ * a small order public key succeeds the private key modulo the public key order
+ * is revealed.
+ */
+ Map<String, EC_Key> keys = EC_Store.getInstance().getObjects(EC_Key.class, "composite");
+ for (EC_Key key : keys.values()) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve());
+ if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
+ continue;
+ }
+ if ((curve.getBits() == cfg.bits || cfg.all)) {
+ doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ doTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY));
+ doTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY));
+ Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH, key.flatten());
+ doTest(CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key."));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
new file mode 100644
index 0000000..c3bd9c8
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
@@ -0,0 +1,94 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.util.CardUtil;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+import javacard.security.KeyPair;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static cz.crcs.ectester.common.test.Result.ExpectedValue;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardDefaultSuite extends CardTestSuite {
+
+ public CardDefaultSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "default", "The default test suite run basic support of ECDH and ECDSA.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ if (cfg.primeField) {
+ runDefault(KeyPair.ALG_EC_FP);
+ }
+ if (cfg.binaryField) {
+ runDefault(KeyPair.ALG_EC_F2M);
+ }
+ }
+
+ private void runDefault(byte field) throws Exception {
+ short[] keySizes = field == KeyPair.ALG_EC_FP ? EC_Consts.FP_SIZES : EC_Consts.F2M_SIZES;
+ for (short keyLength : keySizes) {
+ String description = "Tests of " + keyLength + "b " + (field == KeyPair.ALG_EC_FP ? "ALG_EC_FP" : "ALG_EC_F2M") + " support.";
+
+ List<Test> supportTests = new LinkedList<>();
+ Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, field), ExpectedValue.SUCCESS));
+ if (!key.ok()) {
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, description + " None.", key));
+ continue;
+ }
+ supportTests.add(key);
+
+ Test genDefault = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
+ Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.getCurve(keyLength, field), EC_Consts.PARAMETERS_DOMAIN_FP, null), ExpectedValue.SUCCESS));
+ Test genCustom = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
+ supportTests.add(genDefault);
+ supportTests.add(setCustom);
+ supportTests.add(genCustom);
+
+ for (byte kaType : EC_Consts.KA_TYPES) {
+ Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), ExpectedValue.SUCCESS));
+ if (allocate.ok()) {
+ Command ecdh = new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, kaType);
+ Test ka = runTest(CommandTest.expect(ecdh, ExpectedValue.SUCCESS));
+ Test kaCompressed = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_COMPRESS, kaType), ExpectedValue.SUCCESS));
+ Test perfTest = null;
+ if (ka.ok()) {
+ perfTest = runTest(PerformanceTest.repeat(ecdh, 10));
+ }
+ Test compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, "Test of the " + CardUtil.getKATypeString(kaType) + " KeyAgreement.", allocate, ka, kaCompressed, perfTest));
+ supportTests.add(compound);
+ } else {
+ runTest(allocate);
+ supportTests.add(allocate);
+ }
+ }
+ for (byte sigType : EC_Consts.SIG_TYPES) {
+ Test allocate = runTest(CommandTest.expect(new Command.AllocateSignature(this.card, sigType), ExpectedValue.SUCCESS));
+ if (allocate.ok()) {
+ Command ecdsa = new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, ECTesterApplet.EXPORT_FALSE, null);
+ Test expect = runTest(CommandTest.expect(ecdsa, ExpectedValue.SUCCESS));
+ Test perfTest = null;
+ if (expect.ok()) {
+ perfTest = runTest(PerformanceTest.repeat(ecdsa, 10));
+ }
+ Test compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, "Test of the " + CardUtil.getSigTypeString(sigType) + " signature.", allocate, expect, perfTest));
+ supportTests.add(compound);
+ } else {
+ supportTests.add(allocate);
+ }
+ }
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, description + " Some.", supportTests.toArray(new Test[0])));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java
new file mode 100644
index 0000000..8424d45
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java
@@ -0,0 +1,67 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+import javacard.security.KeyPair;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static cz.crcs.ectester.common.test.Result.ExpectedValue;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardInvalidCurvesSuite extends CardTestSuite {
+
+ public CardInvalidCurvesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "invalid", "The invalid curve suite tests whether the card rejects points outside of the curve during ECDH.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ /* Set original curves (secg/nist/brainpool). Generate local.
+ * Try ECDH with invalid public keys of increasing (or decreasing) order.
+ */
+ Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "invalid");
+ Map<EC_Curve, List<EC_Key.Public>> curves = new HashMap<>();
+ for (EC_Key.Public key : pubkeys.values()) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve());
+ if (curve.getBits() != cfg.bits && !cfg.all) {
+ continue;
+ }
+ if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
+ continue;
+ }
+ List<EC_Key.Public> keys = curves.getOrDefault(curve, new LinkedList<>());
+ keys.add(key);
+ curves.putIfAbsent(curve, keys);
+ }
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curves.entrySet()) {
+ EC_Curve curve = e.getKey();
+ List<EC_Key.Public> keys = e.getValue();
+
+ doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ doTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
+ doTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS));
+ List<Test> ecdhTests = new LinkedList<>();
+ for (EC_Key.Public pub : keys) {
+ Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
+ ecdhTests.add(CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve.", "Card incorrectly accepted point on invalid curve."));
+ }
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), ecdhTests.toArray(new Test[0])));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTestSuite.java
new file mode 100644
index 0000000..0eccd16
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardTestSuite.java
@@ -0,0 +1,24 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.TestSuite;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class CardTestSuite extends TestSuite {
+ ECTesterReader.Config cfg;
+ CardMngr card;
+
+ CardTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager, String name, String description) {
+ super(writer, name, description);
+ this.card = cardManager;
+ this.cfg = cfg;
+ }
+
+ public CardMngr getCard() {
+ return card;
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
new file mode 100644
index 0000000..73c6621
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
@@ -0,0 +1,83 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.*;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.*;
+import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+import cz.crcs.ectester.reader.response.Response;
+import javacard.security.KeyPair;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static cz.crcs.ectester.common.test.Result.ExpectedValue;
+import static cz.crcs.ectester.common.test.Result.Value;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardTestVectorSuite extends CardTestSuite {
+
+ public CardTestVectorSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "test", "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ /* Set original curves (secg/nist/brainpool). Set keypairs from test vectors.
+ * Do ECDH both ways, export and verify that the result is correct.
+ */
+ Map<String, EC_KAResult> results = EC_Store.getInstance().getObjects(EC_KAResult.class, "test");
+ for (EC_KAResult result : results.values()) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, result.getCurve());
+ if (curve.getBits() != cfg.bits && !cfg.all) {
+ continue;
+ }
+ if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
+ continue;
+ }
+ EC_Params onekey = EC_Store.getInstance().getObject(EC_Keypair.class, result.getOneKey());
+ if (onekey == null) {
+ onekey = EC_Store.getInstance().getObject(EC_Key.Private.class, result.getOneKey());
+ }
+ EC_Params otherkey = EC_Store.getInstance().getObject(EC_Keypair.class, result.getOtherKey());
+ if (otherkey == null) {
+ otherkey = EC_Store.getInstance().getObject(EC_Key.Public.class, result.getOtherKey());
+ }
+ if (onekey == null || otherkey == null) {
+ throw new IOException("Test vector keys couldn't be located.");
+ }
+ List<Test> testVector = new LinkedList<>();
+
+ testVector.add(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
+ testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS));
+ testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS));
+ testVector.add(CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getJavaCardKA()), new TestCallback<CommandTestable>() {
+ @Override
+ public Result apply(CommandTestable testable) {
+ Response.ECDH dh = (Response.ECDH) testable.getResponse();
+ if (!dh.successful())
+ return new Result(Value.FAILURE, "ECDH was unsuccessful.");
+ if (!dh.hasSecret())
+ return new Result(Value.FAILURE, "ECDH response did not contain the derived secret.");
+ if (!ByteUtil.compareBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength())) {
+ int firstDiff = ByteUtil.diffBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength());
+ return new Result(Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + String.valueOf(firstDiff) + ".");
+ }
+ return new Result(Value.SUCCESS);
+ }
+ }));
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0])));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java
new file mode 100644
index 0000000..c43b234
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java
@@ -0,0 +1,62 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+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.data.EC_Store;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+import javacard.security.KeyPair;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardTwistTestSuite extends CardTestSuite {
+ public CardTwistTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "twist", "The twist test suite tests whether the card correctly rejects points on the quadratic twist of the curve during ECDH.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "twist");
+ Map<EC_Curve, List<EC_Key.Public>> curves = new HashMap<>();
+ for (EC_Key.Public key : pubkeys.values()) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve());
+ if (curve.getBits() != cfg.bits && !cfg.all) {
+ continue;
+ }
+ if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
+ continue;
+ }
+ List<EC_Key.Public> keys = curves.getOrDefault(curve, new LinkedList<>());
+ keys.add(key);
+ curves.putIfAbsent(curve, keys);
+ }
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curves.entrySet()) {
+ EC_Curve curve = e.getKey();
+ List<EC_Key.Public> keys = e.getValue();
+
+ doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
+ doTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS));
+ doTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS));
+ List<Test> ecdhTests = new LinkedList<>();
+ for (EC_Key.Public pub : keys) {
+ Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
+ ecdhTests.add(CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on twist.", "Card incorrectly accepted point on twist."));
+ }
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), ecdhTests.toArray(new Test[0])));
+ new Command.Cleanup(this.card).send();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java
new file mode 100644
index 0000000..cac8fab
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java
@@ -0,0 +1,58 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.applet.ECTesterApplet;
+import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.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.data.EC_Store;
+import cz.crcs.ectester.reader.CardMngr;
+import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
+import javacard.security.KeyPair;
+
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardWrongCurvesSuite extends CardTestSuite {
+
+ public CardWrongCurvesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
+ super(writer, cfg, cardManager, "wrong", "The wrong curve suite run whether the card rejects domain parameters which are not curves.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ /* Just do the default run on the wrong curves.
+ * These should generally fail, the curves aren't curves.
+ */
+ Map<String, EC_Curve> curves = EC_Store.getInstance().getObjects(EC_Curve.class, "wrong");
+ for (Map.Entry<String, EC_Curve> e : curves.entrySet()) {
+ EC_Curve curve = e.getValue();
+ if (curve.getBits() != cfg.bits && !cfg.all) {
+ continue;
+ }
+ if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
+ continue;
+ }
+ Test key = doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
+ if (!key.ok()) {
+ continue;
+ }
+ Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS));
+ Test generate = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS));
+ doTest(CompoundTest.any(Result.ExpectedValue.FAILURE, "Set wrong curve and generate keypairs, should fail." ,set, generate));
+
+ for (byte kaType : EC_Consts.KA_TYPES) {
+ Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), Result.ExpectedValue.SUCCESS));
+ if (allocate.ok()) {
+ Test ka = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, kaType), Result.ExpectedValue.FAILURE));
+ doTest(CompoundTest.any(Result.ExpectedValue.FAILURE, "Allocate and perform KA, should fail.", allocate, ka));
+ }
+ }
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CommandTest.java b/src/cz/crcs/ectester/reader/test/CommandTest.java
new file mode 100644
index 0000000..a08d820
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CommandTest.java
@@ -0,0 +1,76 @@
+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.
+ */
+public class CommandTest extends SimpleTest<CommandTestable> {
+ private CommandTest(CommandTestable command, TestCallback<CommandTestable> callback) {
+ super(command, callback);
+ }
+
+ public static CommandTest function(CommandTestable command, TestCallback<CommandTestable> callback) {
+ return new CommandTest(command, callback);
+ }
+
+ public static CommandTest function(Command command, TestCallback<CommandTestable> callback) {
+ return function(new CommandTestable(command), callback);
+ }
+
+ public static CommandTest expect(CommandTestable command, Result.ExpectedValue expected, String ok, String nok) {
+ return new CommandTest(command, new TestCallback<CommandTestable>() {
+ @Override
+ public Result apply(CommandTestable commandTestable) {
+ Response resp = commandTestable.getResponse();
+ Result.Value resultValue = Result.Value.fromExpected(expected, resp.successful(), resp.error());
+ return new Result(resultValue, resultValue.ok() ? ok : nok);
+ }
+ });
+ }
+
+ public static CommandTest expect(Command command, Result.ExpectedValue expectedValue, String ok, String nok) {
+ return expect(new CommandTestable(command), expectedValue, ok, nok);
+ }
+
+ public static CommandTest expect(CommandTestable command, Result.ExpectedValue expected) {
+ return expect(command, expected, null, null);
+ }
+
+ public static CommandTest expect(Command command, Result.ExpectedValue expectedValue) {
+ return expect(command, expectedValue, null, null);
+ }
+
+ public Command getCommand() {
+ return testable.getCommand();
+ }
+
+ public Response getResponse() {
+ 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();
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CommandTestable.java b/src/cz/crcs/ectester/reader/test/CommandTestable.java
new file mode 100644
index 0000000..3bb55bf
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/CommandTestable.java
@@ -0,0 +1,44 @@
+package cz.crcs.ectester.reader.test;
+
+import cz.crcs.ectester.common.test.BaseTestable;
+import cz.crcs.ectester.common.test.TestException;
+import cz.crcs.ectester.reader.command.Command;
+import cz.crcs.ectester.reader.response.Response;
+
+import javax.smartcardio.CardException;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CommandTestable extends BaseTestable {
+ private Command command;
+ private Response response;
+
+ public CommandTestable(Command command) {
+ this.command = command;
+ }
+
+ public Command getCommand() {
+ return command;
+ }
+
+ public Response getResponse() {
+ return response;
+ }
+
+ @Override
+ public void run() throws TestException {
+ try {
+ response = command.send();
+ } catch (CardException e) {
+ throw new TestException(e);
+ }
+
+ hasRun = true;
+ if (response.error()) {
+ error = true;
+ } else if (response.successful()) {
+ ok = true;
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java
deleted file mode 100644
index 8e7ca31..0000000
--- a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.ec.EC_Curve;
-import cz.crcs.ectester.reader.ec.EC_Key;
-import javacard.security.KeyPair;
-
-import java.util.Map;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CompositeCurvesSuite extends TestSuite {
-
- public CompositeCurvesSuite(EC_Store dataStore, ECTester.Config cfg) {
- super(dataStore, cfg, "composite", "The composite suite tests ECDH over curves with composite order. This should generally fail, as using such a curve is unsafe.");
- }
-
- @Override
- public void setup(CardMngr cardManager) {
- /* Do the default tests with the public keys set to provided smallorder keys
- * over composite order curves. Essentially small subgroup attacks.
- * These should fail, the curves aren't safe so that if the computation with
- * a small order public key succeeds the private key modulo the public key order
- * is revealed.
- */
- Map<String, EC_Key> keys = dataStore.getObjects(EC_Key.class, "composite");
- for (EC_Key key : keys.values()) {
- EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve());
- if (cfg.namedCurve != null && !(key.getCurve().startsWith(cfg.namedCurve) || key.getCurve().equals(cfg.namedCurve))) {
- continue;
- }
- if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
- continue;
- }
- if ((curve.getBits() == cfg.bits || cfg.all)) {
- tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY));
- tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY));
- Command ecdhCommand = new Command.ECDH_direct(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH, key.flatten());
- tests.add(new Test.Simple(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key."));
- tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY));
- }
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/DefaultSuite.java b/src/cz/crcs/ectester/reader/test/DefaultSuite.java
deleted file mode 100644
index 736b7c5..0000000
--- a/src/cz/crcs/ectester/reader/test/DefaultSuite.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import cz.crcs.ectester.reader.command.Command;
-import javacard.security.KeyPair;
-
-import java.io.IOException;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class DefaultSuite extends TestSuite {
-
- public DefaultSuite(EC_Store dataStore, ECTester.Config cfg) {
- super(dataStore, cfg, "default", "The default test suite tests basic support of ECDH and ECDSA.");
- }
-
- @Override
- public void setup(CardMngr cardManager) throws IOException {
- tests.add(new Test.Simple(new Command.Support(cardManager), ExpectedValue.ANY));
- if (cfg.namedCurve != null) {
- String desc = "Default tests over the " + cfg.namedCurve + " curve category.";
- if (cfg.primeField) {
- tests.addAll(defaultCategoryTests(cardManager, cfg.namedCurve, KeyPair.ALG_EC_FP, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, desc));
- }
- if (cfg.binaryField) {
- tests.addAll(defaultCategoryTests(cardManager, cfg.namedCurve, KeyPair.ALG_EC_F2M, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, desc));
- }
- } else {
- if (cfg.all) {
- if (cfg.primeField) {
- //iterate over prime curve sizes used: EC_Consts.FP_SIZES
- for (short keyLength : EC_Consts.FP_SIZES) {
- defaultTests(cardManager, keyLength, KeyPair.ALG_EC_FP);
- }
- }
- if (cfg.binaryField) {
- //iterate over binary curve sizes used: EC_Consts.F2M_SIZES
- for (short keyLength : EC_Consts.F2M_SIZES) {
- defaultTests(cardManager, keyLength, KeyPair.ALG_EC_F2M);
- }
- }
- } else {
- if (cfg.primeField) {
- defaultTests(cardManager, (short) cfg.bits, KeyPair.ALG_EC_FP);
- }
-
- if (cfg.binaryField) {
- defaultTests(cardManager, (short) cfg.bits, KeyPair.ALG_EC_F2M);
- }
- }
- }
- }
-
- private void defaultTests(CardMngr cardManager, short keyLength, byte keyType) throws IOException {
- tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType), ExpectedValue.SUCCESS));
- Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType);
- if (curve != null)
- tests.add(new Test.Simple(curve, ExpectedValue.SUCCESS));
- tests.add(defaultCurveTests(cardManager, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, "Default tests."));
- tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY));
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java b/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java
deleted file mode 100644
index f61b695..0000000
--- a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.ec.EC_Curve;
-import cz.crcs.ectester.reader.ec.EC_Key;
-import javacard.security.KeyPair;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class InvalidCurvesSuite extends TestSuite {
-
- public InvalidCurvesSuite(EC_Store dataStore, ECTester.Config cfg) {
- super(dataStore, cfg, "invalid", "The invalid curve suite tests whether the card rejects points outside of the curve during ECDH.");
- }
-
- @Override
- public void setup(CardMngr cardManager) throws IOException {
- /* Set original curves (secg/nist/brainpool). Generate local.
- * Try ECDH with invalid public keys of increasing (or decreasing) order.
- */
- Map<String, EC_Key.Public> pubkeys = dataStore.getObjects(EC_Key.Public.class, "invalid");
- Map<EC_Curve, List<EC_Key.Public>> curves = new HashMap<>();
- for (EC_Key.Public key : pubkeys.values()) {
- EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve());
- if (cfg.namedCurve != null && !(key.getCurve().startsWith(cfg.namedCurve) || key.getCurve().equals(cfg.namedCurve))) {
- continue;
- }
- if (curve.getBits() != cfg.bits && !cfg.all) {
- continue;
- }
- if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
- continue;
- }
- List<EC_Key.Public> keys = curves.getOrDefault(curve, new LinkedList<>());
- keys.add(key);
- curves.putIfAbsent(curve, keys);
- }
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curves.entrySet()) {
- EC_Curve curve = e.getKey();
- List<EC_Key.Public> keys = e.getValue();
-
- tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
- tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS));
- List<Test> ecdhTests = new LinkedList<>();
- for (EC_Key.Public pub : keys) {
- Command ecdhCommand = new Command.ECDH_direct(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ANY, pub.flatten());
- ecdhTests.add(new Test.Simple(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve." , "Card incorrectly accepted point on invalid curve."));
- }
- tests.add(Test.Compound.all(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), ecdhTests.toArray(new Test[0])));
- tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY));
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/PerformanceTest.java b/src/cz/crcs/ectester/reader/test/PerformanceTest.java
new file mode 100644
index 0000000..4a27bad
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/test/PerformanceTest.java
@@ -0,0 +1,103 @@
+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 java.util.Arrays;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class PerformanceTest extends SimpleTest<CommandTestable> {
+ private long[] times;
+ private long mean;
+ private long median;
+ private long mode;
+ private int count;
+
+ private PerformanceTest(CommandTestable testable, int count) {
+ super(testable, new TestCallback<CommandTestable>() {
+ @Override
+ public Result apply(CommandTestable testable) {
+ return new Result(Result.Value.SUCCESS);
+ }
+ });
+ this.count = count;
+ }
+
+ public static PerformanceTest repeat(Command cmd, int count) {
+ return new PerformanceTest(new CommandTestable(cmd), count);
+ }
+
+ @Override
+ public String getDescription() {
+ return String.format("Mean = %d ns, Median = %d ns, Mode = %d ns", mean, median, mode);
+ }
+
+ @Override
+ public void run() throws TestException {
+ if (hasRun)
+ return;
+
+ times = new long[count];
+ for (int i = 0; i < count; ++i) {
+ testable.run();
+ times[i] = testable.getResponse().getDuration();
+ testable.reset();
+ }
+
+ mean = Arrays.stream(times).sum() / count;
+
+ long[] sorted = times.clone();
+ Arrays.sort(sorted);
+ if (count % 2 == 0) {
+ median = (sorted[(count / 2) - 1] + sorted[count / 2]) / 2;
+ } else {
+ median = sorted[count / 2];
+ }
+
+ long max_occurences = 0;
+ int i = 0;
+ while (i < count) {
+ long current_value = sorted[i];
+ long current_occurences = 0;
+ while (i < count && sorted[i] == current_value) {
+ i++;
+ current_occurences++;
+ }
+ if (current_occurences > max_occurences) {
+ max_occurences = current_occurences;
+ mode = current_value;
+ }
+ }
+ hasRun = true;
+ result = callback.apply(testable);
+ }
+
+ public long getCount() {
+ return count;
+ }
+
+ public Command getCommand() {
+ return testable.getCommand();
+ }
+
+ public long[] getTimes() {
+ return times;
+ }
+
+ public long getMean() {
+ return mean;
+ }
+
+ public long getMedian() {
+ return median;
+ }
+
+ public long getMode() {
+ return mode;
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/test/Test.java b/src/cz/crcs/ectester/reader/test/Test.java
deleted file mode 100644
index 022ad56..0000000
--- a/src/cz/crcs/ectester/reader/test/Test.java
+++ /dev/null
@@ -1,217 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-
-import javax.smartcardio.CardException;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-import static cz.crcs.ectester.reader.test.Result.Value;
-
-/**
- * An abstract test that can be run and has a Result.
- *
- * @author Jan Jancar johny@neuromancer.sk
- */
-public abstract class Test {
- boolean hasRun = false;
- 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) {
- return true;
- }
- return result.ok();
- }
-
- public abstract String getDescription();
-
- public boolean hasRun() {
- return hasRun;
- }
-
- public abstract void run() throws CardException;
-
- /**
- * A simple test that runs one Command to get and evaluate one Response
- * to get a Result and compare it with the expected one.
- */
- public static class Simple extends Test {
- private BiFunction<Command, Response, Result> callback;
- private Command command;
- private Response response;
-
- public Simple(Command command, BiFunction<Command, Response, Result> callback) {
- this.command = command;
- this.callback = callback;
- }
-
- public Simple(Command command, ExpectedValue expected, String ok, String nok) {
- this(command, (cmd, resp) -> {
- Value resultValue = Value.fromExpected(expected, resp.successful(), resp.error());
- return new Result(resultValue, resultValue.ok() ? ok : nok);
- });
- }
-
- public Simple(Command command, ExpectedValue expected) {
- this(command, expected, null, null);
- }
-
- public Command getCommand() {
- return command;
- }
-
- public Response getResponse() {
- return response;
- }
-
- @Override
- public void run() throws CardException {
- if (hasRun)
- return;
-
- response = command.send();
- if (callback != null) {
- result = callback.apply(command, response);
- } else {
- if (response.successful()) {
- result = new Result(Value.SUCCESS);
- } else {
- result = new Result(Value.FAILURE);
- }
- }
- hasRun = true;
- }
-
- @Override
- public String getDescription() {
- return response.getDescription();
- }
- }
-
- /**
- * A compound test that runs many Tests and has a Result dependent on all/some of their Results.
- */
- public static class Compound extends Test {
- private Function<Test[], Result> callback;
- private Test[] tests;
- private String description;
-
- private Compound(Function<Test[], Result> callback, Test... tests) {
- this.callback = callback;
- this.tests = tests;
- }
-
- private Compound(Function<Test[], Result> callback, String descripiton, Test... tests) {
- this(callback, tests);
- this.description = descripiton;
- }
-
- public static Compound function(Function<Test[], Result> callback, Test... tests) {
- return new Compound(callback, tests);
- }
-
- public static Compound function(Function<Test[], Result> callback, String description, Test... tests) {
- return new Compound(callback, description, tests);
- }
-
- public static Compound all(ExpectedValue what, Test... all) {
- return new Compound((tests) -> {
- for (Test test : tests) {
- if (!Value.fromExpected(what, test.ok()).ok()) {
- return new Result(Value.FAILURE, "At least one of the sub-tests did not have the expected result.");
- }
- }
- return new Result(Value.SUCCESS, "All sub-tests had the expected result.");
- }, all);
- }
-
- public static Compound all(ExpectedValue what, String description, Test... all) {
- Compound result = Compound.all(what, all);
- result.setDescription(description);
- return result;
- }
-
- public static Compound any(ExpectedValue what, Test... any) {
- return new Compound((tests) -> {
- for (Test test : tests) {
- if (Value.fromExpected(what, test.ok()).ok()) {
- return new Result(Value.SUCCESS, "At least one of the sub-tests did have the expected result.");
- }
- }
- return new Result(Value.FAILURE, "None of the sub-tests had the expected result.");
- }, any);
- }
-
- public static Compound any(ExpectedValue what, String description, Test... any) {
- Compound result = Compound.any(what, any);
- result.setDescription(description);
- return result;
- }
-
- public static Compound mask(ExpectedValue[] results, Test... masked) {
- return new Compound((tests) -> {
- for (int i = 0; i < results.length; ++i) {
- if (!Value.fromExpected(results[i], tests[i].ok()).ok()) {
- return new Result(Value.FAILURE, "At least one of the sub-tests did not match the result mask.");
- }
- }
- return new Result(Value.SUCCESS, "All sub-tests matched the expected mask.");
- }, masked);
- }
-
- public static Compound mask(ExpectedValue[] results, String description, Test... masked) {
- Compound result = Compound.mask(results, masked);
- result.setDescription(description);
- return result;
- }
-
- public Test[] getTests() {
- return tests;
- }
-
- @Override
- public void run() throws CardException {
- if (hasRun)
- return;
-
- for (Test test : tests) {
- test.run();
- }
- result = callback.apply(tests);
- this.hasRun = true;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- @Override
- public String getDescription() {
- return description;
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/TestRunner.java b/src/cz/crcs/ectester/reader/test/TestRunner.java
deleted file mode 100644
index baab6a8..0000000
--- a/src/cz/crcs/ectester/reader/test/TestRunner.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.reader.output.TestWriter;
-
-import javax.smartcardio.CardException;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class TestRunner {
- private TestSuite suite;
- private TestWriter writer;
-
- public TestRunner(TestSuite suite, TestWriter writer) {
- this.suite = suite;
- this.writer = writer;
- }
-
- public void run() throws CardException {
- writer.begin(suite);
- for (Test t : suite.getTests()) {
- if (!t.hasRun()) {
- t.run();
- writer.outputTest(t);
- }
- }
- writer.end();
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/TestSuite.java b/src/cz/crcs/ectester/reader/test/TestSuite.java
deleted file mode 100644
index f13317c..0000000
--- a/src/cz/crcs/ectester/reader/test/TestSuite.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.ec.EC_Curve;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-import static cz.crcs.ectester.reader.test.Result.Value;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public abstract class TestSuite {
- EC_Store dataStore;
- ECTester.Config cfg;
- String name;
- String description;
- List<Test> tests = new LinkedList<>();
-
- TestSuite(EC_Store dataStore, ECTester.Config cfg, String name, String description) {
- this.dataStore = dataStore;
- this.cfg = cfg;
- this.name = name;
- this.description = description;
- }
-
- public abstract void setup(CardMngr cardManager) throws IOException;
-
- public List<Test> getTests() {
- return Collections.unmodifiableList(tests);
- }
-
- public String getName() {
- return name;
- }
-
- public String getDescription() {
- return description;
- }
-
- /**
- * @param cardManager cardManager to send APDU through
- * @param generateExpected expected result of the Generate command
- * @param ecdhExpected expected result of the ordinary ECDH command
- * @param ecdhCompressExpected expected result of ECDH with a compressed point
- * @param ecdsaExpected expected result of the ordinary ECDSA command
- * @param description compound test description
- * @return test to run
- */
- Test defaultCurveTests(CardMngr cardManager, ExpectedValue generateExpected, ExpectedValue ecdhExpected, ExpectedValue ecdhCompressExpected, ExpectedValue ecdsaExpected, String description) {
- List<Test> tests = new LinkedList<>();
-
- tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), generateExpected));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH), ecdhExpected));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_COMPRESS, EC_Consts.KA_ECDH), ecdhExpected));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ONE, EC_Consts.KA_ECDH), ExpectedValue.FAILURE));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ZERO, EC_Consts.KA_ECDH), ExpectedValue.FAILURE));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_MAX, EC_Consts.KA_ECDH), ExpectedValue.FAILURE));
- tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_FULLRANDOM, EC_Consts.KA_ECDH), ExpectedValue.FAILURE));
- tests.add(new Test.Simple(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, null), ecdsaExpected));
-
- return Test.Compound.function((testArray) -> {
- Function<ExpectedValue, String> shouldHave = (expected) -> {
- switch (expected) {
- case SUCCESS:
- return "succeeded";
- case FAILURE:
- return "failed";
- case ANY:
- default:
- return "";
- }
- };
-
- for (int i = 0; i < testArray.length; ++i) {
- Test t = testArray[i];
- if (!t.ok()) {
- if (i == 0) { // generate
- return new Result(Value.FAILURE, "The generation of a key should have " + shouldHave.apply(generateExpected) + ", but it did not.");
- } else if (i == 2) { // ecdh compress
- return new Result(Value.FAILURE, "The ECDH should have " + shouldHave.apply(ecdhExpected) + ", but it did not.");
- } else if (i == 1) { // ecdh normal
- return new Result(Value.FAILURE, "The ECDH of a compressed point should have " + shouldHave.apply(ecdhCompressExpected) + ", but it did not.");
- } else if (i <= 6) { // ecdh wrong, should fail
- return new Result(Value.FAILURE, "The ECDH of a corrupted point should have failed, but it did not.");
- } else { // ecdsa
- return new Result(Value.FAILURE, "The ECDSA should have " + shouldHave.apply(ecdsaExpected) + ", but it did not.");
- }
- }
- }
- return new Result(Value.SUCCESS);
- }, description, tests.toArray(new Test[0]));
- }
-
- /**
- * @param cardManager cardManager to send APDU through
- * @param category category to test
- * @param field field to test (KeyPair.ALG_EC_FP || KeyPair.ALG_EC_F2M)
- * @param setExpected expected result of the Set (curve) command
- * @param generateExpected expected result of the Generate command
- * @param ecdhExpected expected result of the ordinary ECDH command
- * @param ecdhCompressedExpected expected result of the ECDH command with a compressed point.
- * @param ecdsaExpected expected result of the ordinary ECDSA command
- * @param description compound test description
- * @return tests to run
- */
- List<Test> defaultCategoryTests(CardMngr cardManager, String category, byte field, ExpectedValue setExpected, ExpectedValue generateExpected, ExpectedValue ecdhExpected, ExpectedValue ecdhCompressedExpected, ExpectedValue ecdsaExpected, String description) {
- List<Test> tests = new LinkedList<>();
- Map<String, EC_Curve> curves = dataStore.getObjects(EC_Curve.class, category);
- if (curves == null)
- return tests;
- for (Map.Entry<String, EC_Curve> entry : curves.entrySet()) {
- EC_Curve curve = entry.getValue();
- if (curve.getField() == field && (curve.getBits() == cfg.bits || cfg.all)) {
- tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), field), ExpectedValue.SUCCESS));
- tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), setExpected));
- tests.add(defaultCurveTests(cardManager, generateExpected, ecdhExpected, ecdhCompressedExpected, ecdsaExpected, description));
- tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY));
- }
- }
-
- return tests;
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java
deleted file mode 100644
index ff46feb..0000000
--- a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import cz.crcs.ectester.reader.Util;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.ec.*;
-import cz.crcs.ectester.reader.response.Response;
-import javacard.security.KeyPair;
-
-import java.io.IOException;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-import static cz.crcs.ectester.reader.test.Result.Value;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class TestVectorSuite extends TestSuite {
-
- public TestVectorSuite(EC_Store dataStore, ECTester.Config cfg) {
- super(dataStore, cfg, "test", "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness.");
- }
-
- @Override
- public void setup(CardMngr cardManager) throws IOException {
- /* Set original curves (secg/nist/brainpool). Set keypairs from test vectors.
- * Do ECDH both ways, export and verify that the result is correct.
- */
- Map<String, EC_KAResult> results = dataStore.getObjects(EC_KAResult.class, "test");
- for (EC_KAResult result : results.values()) {
- EC_Curve curve = dataStore.getObject(EC_Curve.class, result.getCurve());
- if (cfg.namedCurve != null && !(result.getCurve().startsWith(cfg.namedCurve) || result.getCurve().equals(cfg.namedCurve))) {
- continue;
- }
- if (curve.getBits() != cfg.bits && !cfg.all) {
- continue;
- }
- if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) {
- continue;
- }
- EC_Params onekey = dataStore.getObject(EC_Keypair.class, result.getOneKey());
- if (onekey == null) {
- onekey = dataStore.getObject(EC_Key.Private.class, result.getOneKey());
- }
- EC_Params otherkey = dataStore.getObject(EC_Keypair.class, result.getOtherKey());
- if (otherkey == null) {
- otherkey = dataStore.getObject(EC_Key.Public.class, result.getOtherKey());
- }
- if (onekey == null || otherkey == null) {
- throw new IOException("Test vector keys couldn't be located.");
- }
- List<Test> testVector = new LinkedList<>();
-
- testVector.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
- //tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
- testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS));
- testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS));
- testVector.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getKA()), (command, response) -> {
- Response.ECDH dh = (Response.ECDH) response;
- if (!dh.successful())
- return new Result(Value.FAILURE, "ECDH was unsuccessful.");
- if (!dh.hasSecret())
- return new Result(Value.FAILURE, "ECDH response did not contain the derived secret.");
- if (!Util.compareBytes(dh.getSecret(), 0, result.getParam(0), 0, dh.secretLength())) {
- int firstDiff = Util.diffBytes(dh.getSecret(), 0, result.getParam(0), 0, dh.secretLength());
- return new Result(Value.FAILURE, "ECDH derived secret does not match the test, first difference was at byte " + String.valueOf(firstDiff) + ".");
- }
- return new Result(Value.SUCCESS);
- }));
- tests.add(Test.Compound.all(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0])));
- tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY));
-
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java
deleted file mode 100644
index e9389b4..0000000
--- a/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTester;
-import javacard.security.KeyPair;
-
-import java.io.IOException;
-
-import static cz.crcs.ectester.reader.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class WrongCurvesSuite extends TestSuite {
-
- public WrongCurvesSuite(EC_Store dataStore, ECTester.Config cfg) {
- super(dataStore, cfg, "wrong", "The wrong curve suite tests whether the card rejects domain parameters which are not curves.");
- }
-
- @Override
- public void setup(CardMngr cardManager) throws IOException {
- /* Just do the default tests on the wrong curves.
- * These should generally fail, the curves aren't curves.
- */
- String desc = "Default tests over wrong curve params.";
- if (cfg.primeField) {
- tests.addAll(defaultCategoryTests(cardManager, cfg.testSuite, KeyPair.ALG_EC_FP, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, desc));
- }
- if (cfg.binaryField) {
- tests.addAll(defaultCategoryTests(cardManager, cfg.testSuite, KeyPair.ALG_EC_F2M, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, desc));
- }
- }
-}
diff --git a/src/cz/crcs/ectester/scripts/ectester.bat b/src/cz/crcs/ectester/scripts/ectester.bat
deleted file mode 100644
index e20b855..0000000
--- a/src/cz/crcs/ectester/scripts/ectester.bat
+++ /dev/null
@@ -1,34 +0,0 @@
-@ECHO OFF
-SETLOCAL enabledelayedexpansion
-
-SET n=0
-:loop
-IF NOT "%1"=="" (
- IF "%1"=="--dangerous" (
- SET dangerous=1
- ) ELSE (
- SET positional[!n!]=%1
- SET /A n+=1
- )
- SHIFT
- GOTO :loop
-)
-
-IF NOT "%n%"=="1" (
- ECHO "One argument expected:"
- ECHO " ./ectester.bar [--dangerous] CARD_NAME"
-)
-
-SET card=!positional[%%0]!
-
-SET tests="default test-vectors"
-java -jar ECTester.jar -t default -a --format yaml -l %card%.default
-java -jar ECTester.jar -t test-vectors -a --format yaml -l %card%.test-vectors
-IF "%dangerous%"=="1" (
- SET tests=%tests% "invalid wrong composite"
- java -jar ECTester.jar -t invalid -a --format yaml -l %card%.invalid
- java -jar ECTester.jar -t wrong -a --format yaml -l %card%.wrong
- java -jar ECTester.jar -t composite -a --format yaml -l %card%.composite
-)
-
-zip %card%.zip %tests%
diff --git a/src/cz/crcs/ectester/scripts/ectester.sh b/src/cz/crcs/ectester/scripts/ectester.sh
deleted file mode 100755
index 8040096..0000000
--- a/src/cz/crcs/ectester/scripts/ectester.sh
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash
-
-dangerous="0"
-
-positional=()
-while [[ $# -gt 0 ]]
-do
-
-key="$1"
-case $key in
- --dangerous)
- dangerous=1
- shift
- ;;
- *)
- positional+=("$1")
- shift
- ;;
-esac
-done
-set -- "${positional[@]}"
-
-if [[ $# -lt 1 ]]; then
- echo "At least one argument expected:" >&2
- echo " ./ectester.sh [--dangerous] CARD_NAME [ECTester args]" >&2
- exit 1
-fi
-
-card="$1"
-shift
-
-declare -a tests=("default" "test-vectors")
-if [[ "$dangerous" == "1" ]]; then
- tests+=("invalid" "wrong" "composite")
-fi
-
-declare -a files=()
-for i in $(seq 0 $((${#tests[@]} - 1))); do
- test="${tests[$i]}"
- java -jar ECTester.jar -t ${test} -a --format yaml -l ${card}.${test} $@
- files+=(${card}.$test)
-done
-
-if command -v tar 2>&1 >/dev/null; then
- tar -czvf ${card}.tar.gz ${files[*]}
-elif command -v zip 2>&1 >/dev/null; then
- zip ${card}.zip ${files[*]}
-fi
diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
new file mode 100644
index 0000000..f5361c3
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -0,0 +1,525 @@
+package cz.crcs.ectester.standalone;
+
+import cz.crcs.ectester.common.cli.*;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.TestException;
+import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
+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.*;
+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 org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+import javax.crypto.KeyAgreement;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.security.*;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
+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
+ */
+public class ECTesterStandalone {
+ private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib()};
+ private Config cfg;
+
+ private Options opts = new Options();
+ private TreeParser optParser;
+ private TreeCommandLine cli;
+ private static final String VERSION = "v0.1.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 <petr@svenda.com>";
+ private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n";
+ private static final String CLI_FOOTER = "\n" + LICENSE;
+
+ private void run(String[] args) {
+ try {
+ cli = parseArgs(args);
+
+ if (cli.hasOption("version")) {
+ CLITools.version(DESCRIPTION, LICENSE);
+ return;
+ } else if (cli.hasOption("help") || cli.getNext() == null) {
+ CLITools.help("ECTesterStandalone.jar", CLI_HEADER, opts, optParser, CLI_FOOTER, true);
+ return;
+ }
+
+ for (ECLibrary lib : libs) {
+ lib.initialize();
+ }
+
+ cfg = new Config(libs);
+ if (!cfg.readOptions(cli)) {
+ return;
+ }
+
+ if (cli.isNext("list-libs")) {
+ listLibraries();
+ } else if (cli.isNext("list-data")) {
+ CLITools.listNamed(EC_Store.getInstance(), cli.getNext().getArg(0));
+ } else if (cli.isNext("ecdh")) {
+ ecdh();
+ } else if (cli.isNext("ecdsa")) {
+ ecdsa();
+ } else if (cli.isNext("generate")) {
+ generate();
+ } else if (cli.isNext("test")) {
+ test();
+ } else if (cli.isNext("export")) {
+ export();
+ }
+
+ } catch (ParseException | ParserConfigurationException | IOException ex) {
+ System.err.println(ex.getMessage());
+ } catch (InvalidAlgorithmParameterException | InvalidParameterException e) {
+ System.err.println("Invalid algorithm parameter: " + e.getMessage());
+ } catch (NoSuchAlgorithmException nsaex) {
+ System.err.println("Algorithm not supported by the selected library: " + nsaex.getMessage());
+ nsaex.printStackTrace();
+ } catch (InvalidKeyException | SignatureException | TestException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private TreeCommandLine parseArgs(String[] args) throws ParseException {
+ Map<String, ParserOptions> actions = new TreeMap<>();
+
+ Option namedCurve = Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: <cat/id>").hasArg().argName("cat/id").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(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());
+ testOpts.addOption(Option.builder("f").longOpt("format").desc("Set the output format, one of text,yaml,xml.").hasArg().argName("format").optionalArg(false).build());
+ List<Argument> testArgs = new LinkedList<>();
+ testArgs.add(new Argument("test_suite", "The test suite to run.", true));
+ ParserOptions test = new ParserOptions(new DefaultParser(), testOpts, testArgs);
+ actions.put("test", test);
+
+ Options ecdhOpts = new Options();
+ ecdhOpts.addOption(bits);
+ ecdhOpts.addOption(namedCurve);
+ 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);
+ actions.put("ecdh", ecdh);
+
+ Options ecdsaOpts = new Options();
+ ecdsaOpts.addOption(bits);
+ ecdsaOpts.addOption(namedCurve);
+ 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);
+ actions.put("ecdsa", ecdsa);
+
+ Options generateOpts = new Options();
+ generateOpts.addOption(bits);
+ generateOpts.addOption(namedCurve);
+ 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);
+ 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);
+ actions.put("export", export);
+
+ Options listDataOpts = new Options();
+ List<Argument> listDataArgs = new LinkedList<>();
+ listDataArgs.add(new Argument("what", "what to list.", false));
+ ParserOptions listData = new ParserOptions(new TreeParser(Collections.emptyMap(), false, listDataArgs), listDataOpts);
+ actions.put("list-data", listData);
+
+ Options listLibsOpts = new Options();
+ ParserOptions listLibs = new ParserOptions(new DefaultParser(), listLibsOpts);
+ actions.put("list-libs", listLibs);
+
+ List<Argument> baseArgs = new LinkedList<>();
+ baseArgs.add(new Argument("lib", "What library to use.", false));
+ optParser = new TreeParser(actions, false, baseArgs);
+
+ opts.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build());
+ opts.addOption(Option.builder("h").longOpt("help").desc("Print help.").build());
+
+ return optParser.parse(opts, args);
+ }
+
+ /**
+ *
+ */
+ private void listLibraries() {
+ for (ECLibrary lib : libs) {
+ if (lib.isInitialized() && (cfg.selected == null || lib == cfg.selected)) {
+ System.out.println("\t- " + lib.name());
+ Set<KeyPairGeneratorIdent> kpgs = lib.getKPGs();
+ if (!kpgs.isEmpty()) {
+ System.out.println("\t\t- KeyPairGenerators: " + String.join(",", kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.toList())));
+ }
+ Set<KeyAgreementIdent> eckas = lib.getKAs();
+ if (!eckas.isEmpty()) {
+ System.out.println("\t\t- KeyAgreements: " + String.join(",", eckas.stream().map(KeyAgreementIdent::getName).collect(Collectors.toList())));
+ }
+ Set<SignatureIdent> sigs = lib.getSigs();
+ if (!sigs.isEmpty()) {
+ System.out.println("\t\t- Signatures: " + String.join(",", sigs.stream().map(SignatureIdent::getName).collect(Collectors.toList())));
+ }
+ Set<String> curves = lib.getCurves();
+ if (!curves.isEmpty()) {
+ System.out.println("\t\t- Curves: " + String.join(",", curves));
+ }
+ System.out.println();
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private void ecdh() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
+ ProviderECLibrary lib = cfg.selected;
+
+ String algo = cli.getOptionValue("ecdh.type", "ECDH");
+ KeyAgreementIdent kaIdent = lib.getKAs().stream()
+ .filter((ident) -> ident.contains(algo))
+ .findFirst()
+ .orElse(null);
+
+ KeyPairGeneratorIdent kpIdent = lib.getKPGs().stream()
+ .filter((ident) -> ident.contains(algo))
+ .findFirst()
+ .orElse(lib.getKPGs().stream()
+ .filter((ident) -> ident.contains("ECDH"))
+ .findFirst()
+ .orElse(lib.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst()
+ .orElse(null)));
+
+
+ if (kaIdent == null || kpIdent == null) {
+ throw new NoSuchAlgorithmException(algo);
+ } else {
+ KeyAgreement ka = kaIdent.getInstance(lib.getProvider());
+ KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
+ AlgorithmParameterSpec spec = null;
+ if (cli.hasOption("ecdh.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("ecdh.bits"));
+ kpg.initialize(bits);
+ } else if (cli.hasOption("ecdh.named-curve")) {
+ String curveName = cli.getOptionValue("ecdh.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();
+ kpg.initialize(spec);
+ }//TODO: allow ECGenNamedSpec
+
+ System.out.println("index;nanotime;pubW;privS;secret");
+
+ int amount = Integer.parseInt(cli.getOptionValue("ecdh.amount", "1"));
+ for (int i = 0; i < amount; ++i) {
+ KeyPair one = kpg.genKeyPair();
+ KeyPair other = kpg.genKeyPair();
+
+ ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
+ ECPublicKey pubkey = (ECPublicKey) other.getPublic();
+
+ long elapsed = -System.nanoTime();
+ if (spec != null) {
+ ka.init(privkey, spec);
+ } else {
+ ka.init(privkey);
+ }
+ ka.doPhase(pubkey, true);
+ elapsed += System.nanoTime();
+ byte[] result = ka.generateSecret();
+ ka = kaIdent.getInstance(lib.getProvider());
+
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
+ String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
+ String dh = ByteUtil.bytesToHex(result, false);
+ System.out.println(String.format("%d;%d;%s;%s;%s", i, elapsed, pub, priv, dh));
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private void ecdsa() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException, SignatureException {
+ byte[] data;
+ String dataString;
+ if (cli.hasOption("ecdsa.file")) {
+ String fileName = cli.getOptionValue("ecdsa.file");
+ File in = new File(fileName);
+ long len = in.length();
+ if (len == 0) {
+ throw new FileNotFoundException(fileName);
+ }
+ data = Files.readAllBytes(in.toPath());
+ dataString = "";
+ } else {
+ SecureRandom random = new SecureRandom();
+ data = new byte[32];
+ random.nextBytes(data);
+ dataString = ByteUtil.bytesToHex(data, false);
+ }
+
+ ProviderECLibrary lib = cfg.selected;
+
+ String algo = cli.getOptionValue("ecdsa.type", "ECDSA");
+ SignatureIdent sigIdent = lib.getSigs().stream()
+ .filter((ident) -> ident.contains(algo))
+ .findFirst()
+ .orElse(null);
+
+ KeyPairGeneratorIdent kpIdent = lib.getKPGs().stream()
+ .filter((ident) -> ident.contains(algo))
+ .findFirst()
+ .orElse(lib.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst()
+ .orElse(null));
+
+ if (sigIdent == null || kpIdent == null) {
+ throw new NoSuchAlgorithmException(algo);
+ } else {
+ Signature sig = sigIdent.getInstance(lib.getProvider());
+ KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
+ if (cli.hasOption("ecdsa.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("ecdsa.bits"));
+ kpg.initialize(bits);
+ } else if (cli.hasOption("ecdsa.named-curve")) {
+ String curveName = cli.getOptionValue("ecdsa.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
+ }
+ kpg.initialize(curve.toSpec());
+ }
+
+ System.out.println("index;data;signtime;verifytime;pubW;privS;signature;verified");
+
+ int amount = Integer.parseInt(cli.getOptionValue("ecdsa.amount", "1"));
+ for (int i = 0; i < amount; ++i) {
+ KeyPair one = kpg.genKeyPair();
+
+ ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
+ ECPublicKey pubkey = (ECPublicKey) one.getPublic();
+
+ sig.initSign(privkey);
+ sig.update(data);
+
+ long signTime = -System.nanoTime();
+ byte[] signature = sig.sign();
+ signTime += System.nanoTime();
+
+ sig.initVerify(pubkey);
+ sig.update(data);
+
+ long verifyTime = -System.nanoTime();
+ boolean verified = sig.verify(signature);
+ verifyTime += System.nanoTime();
+
+
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
+ String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
+ String sign = ByteUtil.bytesToHex(signature, false);
+ System.out.println(String.format("%d;%s;%d;%d;%s;%s;%s;%d", i, dataString, signTime, verifyTime, pub, priv, sign, verified ? 1 : 0));
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private void generate() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ ProviderECLibrary lib = cfg.selected;
+ KeyPairGeneratorIdent ident = null;
+ String algo = cli.getOptionValue("generate.type", "EC");
+ for (KeyPairGeneratorIdent kpIdent : lib.getKPGs()) {
+ if (kpIdent.contains(algo)) {
+ ident = kpIdent;
+ break;
+ }
+ }
+ if (ident == null) {
+ throw new NoSuchAlgorithmException(algo);
+ } else {
+ KeyPairGenerator kpg = ident.getInstance(lib.getProvider());
+ if (cli.hasOption("generate.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("generate.bits"));
+ kpg.initialize(bits);
+ } else if (cli.hasOption("generate.named-curve")) {
+ String curveName = cli.getOptionValue("generate.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
+ }
+ kpg.initialize(curve.toSpec());
+ }
+ System.out.println("index;nanotime;pubW;privS");
+
+ int amount = Integer.parseInt(cli.getOptionValue("generate.amount", "1"));
+ for (int i = 0; i < amount; ++i) {
+ long elapsed = -System.nanoTime();
+ KeyPair kp = kpg.genKeyPair();
+ elapsed += System.nanoTime();
+ ECPublicKey publicKey = (ECPublicKey) kp.getPublic();
+ ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
+
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(publicKey.getW(), publicKey.getParams()), false);
+ String priv = ByteUtil.bytesToHex(privateKey.getS().toByteArray(), false);
+ System.out.println(String.format("%d;%d;%s;%s", i, elapsed, pub, priv));
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private void test() throws NoSuchAlgorithmException, TestException, ParserConfigurationException {
+ TestWriter writer;
+ switch (cli.getOptionValue("test.format", "text").toLowerCase()) {
+ case "yaml":
+ case "yml":
+ writer = new YAMLTestWriter(System.out);
+ break;
+ case "xml":
+ writer = new XMLTestWriter(System.out);
+ break;
+ case "text":
+ default:
+ writer = new TextTestWriter(System.out);
+ break;
+ }
+
+ StandaloneTestSuite suite = new StandaloneDefaultSuite(writer, cfg, cli);
+ suite.run();
+ }
+
+ /**
+ *
+ */
+ private void export() throws NoSuchAlgorithmException, IOException {
+ ProviderECLibrary lib = (ProviderECLibrary) cfg.selected;
+ KeyPairGeneratorIdent ident = null;
+ String algo = cli.getOptionValue("export.type", "EC");
+ for (KeyPairGeneratorIdent kpIdent : lib.getKPGs()) {
+ if (kpIdent.contains(algo)) {
+ ident = kpIdent;
+ break;
+ }
+ }
+ if (ident == null) {
+ throw new NoSuchAlgorithmException(algo);
+ } else {
+ KeyPairGenerator kpg = ident.getInstance(lib.getProvider());
+ if (cli.hasOption("export.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("export.bits"));
+ kpg.initialize(bits);
+ }
+ KeyPair kp = kpg.genKeyPair();
+ ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
+ ECParameterSpec params = privateKey.getParams();
+ System.out.println(params);
+ EC_Curve curve = EC_Curve.fromSpec(params);
+ curve.writeCSV(System.out);
+ }
+ }
+
+ public static void main(String[] args) {
+ ECTesterStandalone app = new ECTesterStandalone();
+ app.run(args);
+ }
+
+
+ /**
+ *
+ */
+ public static class Config {
+ private ProviderECLibrary[] libs;
+ public ProviderECLibrary selected = null;
+
+ public Config(ProviderECLibrary[] libs) {
+ this.libs = libs;
+ }
+
+ boolean readOptions(TreeCommandLine cli) {
+ 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.");
+ return false;
+ }
+
+ 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.");
+ return false;
+ }
+ }
+
+ String libraryName = cli.getArg(-1);
+ if (libraryName != null) {
+ List<ProviderECLibrary> matchedLibs = new LinkedList<>();
+ for (ProviderECLibrary lib : libs) {
+ if (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 (cli.hasOption("test.format")) {
+ String fmt = cli.getOptionValue("test.format");
+ String formats[] = new String[]{"text", "xml", "yaml", "yml"};
+ if (!Arrays.asList(formats).contains(fmt.toLowerCase())) {
+ System.err.println("Invalid format specified.");
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/consts/Ident.java b/src/cz/crcs/ectester/standalone/consts/Ident.java
new file mode 100644
index 0000000..40a44ac
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/consts/Ident.java
@@ -0,0 +1,80 @@
+package cz.crcs.ectester.standalone.consts;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.BiFunction;
+
+public abstract class Ident {
+ Set<String> idents;
+ String name;
+
+ public Ident(String name, String... aliases) {
+ this.name = name;
+ this.idents = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
+ this.idents.add(name);
+ this.idents.addAll(Arrays.asList(aliases));
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Set<String> getIdents() {
+ return Collections.unmodifiableSet(idents);
+ }
+
+ public boolean contains(String other) {
+ return name.equals(other) || idents.contains(other);
+ }
+
+ <T> T getInstance(BiFunction<String, Provider, T> getter, Provider provider) throws NoSuchAlgorithmException {
+ T instance = null;
+ try {
+ instance = getter.apply(name, provider);
+ } catch (Exception ignored) {
+ }
+
+ if (instance == null) {
+ for (String alias : idents) {
+ try {
+ instance = getter.apply(alias, provider);
+ if (instance != null) {
+ break;
+ }
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ if (instance == null) {
+ throw new NoSuchAlgorithmException(name);
+ }
+ return instance;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof Ident)) {
+ return false;
+ }
+ Ident other = (Ident) obj;
+ return idents.equals(other.getIdents());
+ }
+
+ @Override
+ public int hashCode() {
+ return idents.hashCode() + 37;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + String.join("|", idents) + ")";
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
new file mode 100644
index 0000000..0e4d311
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
@@ -0,0 +1,68 @@
+package cz.crcs.ectester.standalone.consts;
+
+import javax.crypto.KeyAgreement;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class KeyAgreementIdent extends Ident {
+ private static final List<KeyAgreementIdent> ALL = new LinkedList<>();
+
+ static {
+ //https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
+ // Basic ECDH and ECDHC (plain/raw)
+ 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"));
+ // 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"));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA224CKDF", "1.3.132.1.15.0"));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA256CKDF", "1.3.132.1.15.1"));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA384CKDF", "1.3.132.1.15.2"));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA512CKDF", "1.3.132.1.15.3"));
+ // ECVKO - Disable for now as it needs diferent params(too different from DH)
+ //ALL.add(new KeyAgreementIdent("ECVKO", "ECGOST3410", "1.2.643.2.2.19", "GOST-3410-2001", "1.2.643.2.2.96"));
+ //ALL.add(new KeyAgreementIdent("ECVKO256", "ECGOST3410-2012-256", "1.2.643.7.1.1.6.1", "1.2.643.7.1.1.1.1"));
+ //ALL.add(new KeyAgreementIdent("ECVKO512", "ECGOST3410-2012-512", "1.2.643.7.1.1.6.2", "1.2.643.7.1.1.1.2"));
+ }
+
+ public static KeyAgreementIdent get(String ident) {
+ for (KeyAgreementIdent ka : ALL) {
+ if (ka.getIdents().contains(ident)) {
+ return ka;
+ }
+ }
+ return null;
+ }
+
+ private KeyAgreementIdent(String name, String... aliases) {
+ super(name, aliases);
+ }
+
+ public KeyAgreement getInstance(Provider provider) throws NoSuchAlgorithmException {
+ KeyAgreement instance = getInstance((algorithm, provider1) -> {
+ try {
+ return KeyAgreement.getInstance(algorithm, provider1);
+ } catch (NoSuchAlgorithmException e) {
+ return null;
+ }
+ }, provider);
+ instance.getProvider();
+ return instance;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java b/src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java
new file mode 100644
index 0000000..8e67967
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java
@@ -0,0 +1,50 @@
+package cz.crcs.ectester.standalone.consts;
+
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.LinkedList;
+import java.util.List;
+
+public class KeyPairGeneratorIdent extends Ident {
+ private static final List<KeyPairGeneratorIdent> ALL = new LinkedList<>();
+
+ static {
+ ALL.add(new KeyPairGeneratorIdent("EC"));
+ ALL.add(new KeyPairGeneratorIdent("ECDH"));
+ ALL.add(new KeyPairGeneratorIdent("ECDSA"));
+ ALL.add(new KeyPairGeneratorIdent("ECDHC"));
+ ALL.add(new KeyPairGeneratorIdent("ECMQV"));
+ ALL.add(new KeyPairGeneratorIdent("ECGOST3410"));
+ ALL.add(new KeyPairGeneratorIdent("ECGOST3410-2012"));
+ // ECKCDSA? Botan provides.
+ ALL.add(new KeyPairGeneratorIdent("ECKCDSA"));
+ // ECGDSA? Botan provides.
+ ALL.add(new KeyPairGeneratorIdent("ECGDSA"));
+ }
+
+ public static KeyPairGeneratorIdent get(String ident) {
+ for (KeyPairGeneratorIdent kg : ALL) {
+ if (kg.getIdents().contains(ident)) {
+ return kg;
+ }
+ }
+ return null;
+ }
+
+ public KeyPairGeneratorIdent(String name, String... aliases) {
+ super(name, aliases);
+ }
+
+ public KeyPairGenerator getInstance(Provider provider) throws NoSuchAlgorithmException {
+ KeyPairGenerator instance = getInstance((algorithm, provider1) -> {
+ try {
+ return KeyPairGenerator.getInstance(algorithm, provider1);
+ } catch (NoSuchAlgorithmException e) {
+ return null;
+ }
+ }, provider);
+ instance.getProvider();
+ return instance;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
new file mode 100644
index 0000000..42ff050
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
@@ -0,0 +1,109 @@
+package cz.crcs.ectester.standalone.consts;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Signature;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class SignatureIdent extends Ident {
+ private static final List<SignatureIdent> ALL = new LinkedList<>();
+
+ static {
+ //https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
+ // ECDSA
+ ALL.add(new SignatureIdent("ECDSA", "SHA1withECDSA", "ECDSAwithSHA1", "1.2.840.10045.4.1", "1.3.36.3.3.2.1"));
+ ALL.add(new SignatureIdent("NONEwithECDSA"));
+ ALL.add(new SignatureIdent("SHA224withECDSA", "SHA224/ECDSA", "1.2.840.10045.4.3.1"));
+ ALL.add(new SignatureIdent("SHA256withECDSA", "SHA256/ECDSA", "1.2.840.10045.4.3.2"));
+ ALL.add(new SignatureIdent("SHA384withECDSA", "SHA384/ECDSA", "1.2.840.10045.4.3.3"));
+ ALL.add(new SignatureIdent("SHA512withECDSA", "SHA512/ECDSA", "1.2.840.10045.4.3.4"));
+ ALL.add(new SignatureIdent("SHA3-224withECDSA", "SHA3-224/ECDSA", "2.16.840.1.101.3.4.3.9"));
+ ALL.add(new SignatureIdent("SHA3-256withECDSA", "SHA3-256/ECDSA", "2.16.840.1.101.3.4.3.10"));
+ ALL.add(new SignatureIdent("SHA3-384withECDSA", "SHA3-384/ECDSA", "2.16.840.1.101.3.4.3.11"));
+ ALL.add(new SignatureIdent("SHA3-512withECDSA", "SHA3-512/ECDSA", "2.16.840.1.101.3.4.3.12"));
+ ALL.add(new SignatureIdent("RIPEMD160withECDSA", "RIPEMD160/ECDSA", "1.3.36.3.3.2.2"));
+ // ECNR
+ ALL.add(new SignatureIdent("SHA1withECNR"));
+ ALL.add(new SignatureIdent("SHA224withECNR"));
+ ALL.add(new SignatureIdent("SHA256withECNR"));
+ ALL.add(new SignatureIdent("SHA512withECNR"));
+ // CVC-ECDSA
+ ALL.add(new SignatureIdent("SHA1withCVC-ECDSA", "SHA1/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.1"));
+ ALL.add(new SignatureIdent("SHA224withCVC-ECDSA", "SHA224/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.2"));
+ ALL.add(new SignatureIdent("SHA256withCVC-ECDSA", "SHA256/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.3"));
+ ALL.add(new SignatureIdent("SHA384withCVC-ECDSA", "SHA384/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.4"));
+ ALL.add(new SignatureIdent("SHA512withCVC-ECDSA", "SHA512/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.5"));
+ // PLAIN-ECDSA
+ ALL.add(new SignatureIdent("SHA1withPLAIN-ECDSA", "SHA1/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.1"));
+ ALL.add(new SignatureIdent("SHA224withPLAIN-ECDSA", "SHA224/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.2"));
+ ALL.add(new SignatureIdent("SHA256withPLAIN-ECDSA", "SHA256/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.3"));
+ ALL.add(new SignatureIdent("SHA384withPLAIN-ECDSA", "SHA384/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.4"));
+ ALL.add(new SignatureIdent("SHA512withPLAIN-ECDSA", "SHA512/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.5"));
+ ALL.add(new SignatureIdent("RIPEMD160withPLAIN-ECDSA", "RIPEMD160/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.6"));
+ // ECGOST
+ ALL.add(new SignatureIdent("ECGOST3410", "ECGOST-3410", "GOST-3410-2001"));
+ ALL.add(new SignatureIdent("GOST3411withECGOST3410", "GOST3411/ECGOST3410", "1.2.643.2.2.3"));
+ ALL.add(new SignatureIdent("ECGOST3410-2012-256", "GOST-3410-2012-256"));
+ ALL.add(new SignatureIdent("GOST3411-2012-256withECGOST3410-2012-256", "GOST3411-2012-256/ECGOST3410-2012-2560", "1.2.643.7.1.1.3.2"));
+ ALL.add(new SignatureIdent("ECGOST3410-2012-512", "GOST-3410-2012-512"));
+ ALL.add(new SignatureIdent("GOST3411-2012-512withECGOST3410-2012-512", "GOST3411-2012-512/ECGOST3410-2012-5120", "1.2.643.7.1.1.3.3"));
+ ALL.add(new SignatureIdent("SM3withSM2"));
+ // ECDDSA
+ ALL.add(new SignatureIdent("ECDDSA", "DETECDSA", "ECDETDSA"));
+ ALL.add(new SignatureIdent("SHA1withECDDSA", "SHA1withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA224withECDDSA", "SHA224withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA256withECDDSA", "SHA256withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA384withECDDSA", "SHA384withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA512withECDDSA", "SHA512withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA3-224withECDDSA", "SHA3-224withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA3-256withECDDSA", "SHA3-256withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA3-384withECDDSA", "SHA3-384withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA3-512withECDDSA", "SHA3-512withDETECDSA"));
+ // ECKCDSA? Botan provides.
+ ALL.add(new SignatureIdent("ECKCDSA","SHA1withECKCDSA", "1.2.410.200004.1.100.4.3"));
+ ALL.add(new SignatureIdent("NONEwithECKCDSA"));
+ ALL.add(new SignatureIdent("RIPEMD160withECKCDSA"));
+ ALL.add(new SignatureIdent("SHA224withECKCDSA", "1.2.410.200004.1.100.4.4"));
+ ALL.add(new SignatureIdent("SHA256withECKCDSA", "1.2.410.200004.1.100.4.5"));
+ ALL.add(new SignatureIdent("SHA384withECKCDSA"));
+ ALL.add(new SignatureIdent("SHA512withECKCDSA"));
+ // ECGDSA? Botan provides.
+ ALL.add(new SignatureIdent("ECGDSA", "SHA1withECGDSA", "1.3.36.3.3.2.5.4.2"));
+ ALL.add(new SignatureIdent("NONEwithECGDSA"));
+ ALL.add(new SignatureIdent("RIPEMD160withECGDSA", "1.3.36.3.3.2.5.4.1"));
+ ALL.add(new SignatureIdent("SHA224withECGDSA", "1.3.36.3.3.2.5.4.3"));
+ ALL.add(new SignatureIdent("SHA224withECGDSA", "1.3.36.3.3.2.5.4.4"));
+ ALL.add(new SignatureIdent("SHA384withECGDSA", "1.3.36.3.3.2.5.4.5"));
+ ALL.add(new SignatureIdent("SHA512withECGDSA", "1.3.36.3.3.2.5.4.6"));
+
+ }
+
+ public static SignatureIdent get(String ident) {
+ for (SignatureIdent sig : ALL) {
+ if (sig.getIdents().contains(ident)) {
+ return sig;
+ }
+ }
+ return null;
+ }
+
+ private SignatureIdent(String name, String... aliases) {
+ super(name, aliases);
+ }
+
+ public Signature getInstance(Provider provider) throws NoSuchAlgorithmException {
+ Signature instance = getInstance((algorithm, provider1) -> {
+ try {
+ return Signature.getInstance(algorithm, provider1);
+ } catch (NoSuchAlgorithmException e) {
+ return null;
+ }
+ }, provider);
+ instance.getProvider();
+ return instance;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/BotanLib.java b/src/cz/crcs/ectester/standalone/libs/BotanLib.java
new file mode 100644
index 0000000..cd28791
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/BotanLib.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 BotanLib extends NativeECLibrary {
+
+ public BotanLib() {
+ super("botan_provider", "botan-2");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java b/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java
new file mode 100644
index 0000000..c6600f9
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java
@@ -0,0 +1,28 @@
+package cz.crcs.ectester.standalone.libs;
+
+import org.bouncycastle.jce.ECNamedCurveTable;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import java.util.Enumeration;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class BouncyCastleLib extends ProviderECLibrary {
+
+ public BouncyCastleLib() {
+ super(new BouncyCastleProvider());
+ }
+
+ @Override
+ public Set<String> getCurves() {
+ Set<String> result = new TreeSet<>();
+ Enumeration names = ECNamedCurveTable.getNames();
+ while (names.hasMoreElements()) {
+ result.add((String) names.nextElement());
+ }
+ return result;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/ECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ECLibrary.java
new file mode 100644
index 0000000..0f81978
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/ECLibrary.java
@@ -0,0 +1,26 @@
+package cz.crcs.ectester.standalone.libs;
+
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public interface ECLibrary {
+ boolean initialize();
+
+ boolean isInitialized();
+
+ Set<String> getCurves();
+
+ Set<KeyAgreementIdent> getKAs();
+
+ Set<SignatureIdent> getSigs();
+
+ Set<KeyPairGeneratorIdent> getKPGs();
+
+ String name();
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
new file mode 100644
index 0000000..0a420a1
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
@@ -0,0 +1,119 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.security.Provider;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeECLibrary extends ProviderECLibrary {
+ private String resource;
+ private String[] requriements;
+
+ public static String LIB_RESOURCE_DIR = "/cz/crcs/ectester/standalone/libs/jni/";
+
+ public NativeECLibrary(String resource, String... requirements) {
+ this.resource = resource;
+ this.requriements = requirements;
+ }
+
+ @Override
+ public boolean initialize() {
+ try {
+ /* Determine what OS are we running on and use appropriate suffix and path. */
+ String suffix;
+ Path appData;
+ if (System.getProperty("os.name").startsWith("Windows")) {
+ suffix = "dll";
+ appData = Paths.get(System.getenv("AppData"));
+ } else {
+ suffix = "so";
+ if (System.getProperty("os.name").startsWith("Linux")) {
+ String dataHome = System.getenv("XDG_DATA_HOME");
+ if (dataHome != null) {
+ appData = Paths.get(dataHome);
+ } else {
+ appData = Paths.get(System.getProperty("user.home"), ".local", "share");
+ }
+ } else {
+ appData = Paths.get(System.getProperty("user.home"), ".local", "share");
+ }
+ }
+ Path libDir = appData.resolve("ECTesterStandalone");
+ File libDirFile = libDir.toFile();
+ Path libPath = libDir.resolve(resource + "." + suffix);
+ File libFile = libPath.toFile();
+
+ URL jarURL = NativeECLibrary.class.getResource(LIB_RESOURCE_DIR + resource + "." + suffix);
+ if (jarURL == null) {
+ return false;
+ }
+ URLConnection jarConnection = jarURL.openConnection();
+
+ /* Only write the file if it does not exist,
+ * or if the existing one is older than the
+ * one in the JAR.
+ */
+ boolean write = false;
+ if (libDirFile.isDirectory() && libFile.isFile()) {
+ long jarModified = jarConnection.getLastModified();
+
+ long libModified = Files.getLastModifiedTime(libPath).toMillis();
+ if (jarModified > libModified) {
+ write = true;
+ }
+ } else {
+ libDir.toFile().mkdirs();
+ libFile.createNewFile();
+ write = true;
+ }
+
+ if (write) {
+ Files.copy(jarConnection.getInputStream(), libPath, StandardCopyOption.REPLACE_EXISTING);
+ }
+ jarConnection.getInputStream().close();
+
+ /*
+ * Need to hack in /usr/local/lib to path.
+ * See: https://stackoverflow.com/questions/5419039/is-djava-library-path-equivalent-to-system-setpropertyjava-library-path/24988095#24988095
+ */
+ String path = System.getProperty("java.library.path");
+ if (suffix.equals("so")) {
+ String newPath = path + ":/usr/local/lib";
+ System.setProperty("java.library.path", newPath);
+ Field fieldSysPath;
+ try {
+ fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" );
+ fieldSysPath.setAccessible( true );
+ fieldSysPath.set( null, null );
+ } catch (NoSuchFieldException | IllegalAccessException ignored) {
+ }
+ }
+
+ for (String requirement : requriements) {
+ System.loadLibrary(requirement);
+ }
+
+ if (suffix.equals("so")) {
+ System.setProperty("java.library.path", path);
+ }
+
+ System.load(libPath.toString());
+
+ provider = createProvider();
+ return super.initialize();
+ } catch (IOException | UnsatisfiedLinkError ignored) {
+ }
+ return false;
+ }
+
+ abstract Provider createProvider();
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java
new file mode 100644
index 0000000..9108eaf
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java
@@ -0,0 +1,93 @@
+package cz.crcs.ectester.standalone.libs;
+
+import cz.crcs.ectester.standalone.consts.Ident;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+
+import java.security.Provider;
+import java.security.Security;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Function;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class ProviderECLibrary implements ECLibrary {
+ Provider provider;
+ private boolean initialized = false;
+
+ public ProviderECLibrary() {
+
+ }
+
+ public ProviderECLibrary(Provider provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public boolean initialize() {
+ try {
+ int result = Security.addProvider(provider);
+ if (result == -1) {
+ provider = Security.getProvider(provider.getName());
+ }
+ initialized = true;
+ } catch (NullPointerException | SecurityException ignored) {
+ initialized = false;
+ }
+ return initialized;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return initialized;
+ }
+
+ private <T extends Ident> Set<T> getIdents(String type, Function<String, T> getter) {
+ Set<T> results = new HashSet<>();
+ if (!initialized) {
+ return results;
+ }
+
+ for (Provider.Service service : provider.getServices()) {
+ if (service.getType().equals(type)) {
+ T id = getter.apply(service.getAlgorithm());
+ if (id != null) {
+ results.add(id);
+ }
+ }
+ }
+ return results;
+ }
+
+ @Override
+ public Set<KeyAgreementIdent> getKAs() {
+ return getIdents("KeyAgreement", KeyAgreementIdent::get);
+ }
+
+ @Override
+ public Set<SignatureIdent> getSigs() {
+ return getIdents("Signature", SignatureIdent::get);
+ }
+
+ @Override
+ public Set<KeyPairGeneratorIdent> getKPGs() {
+ return getIdents("KeyPairGenerator", KeyPairGeneratorIdent::get);
+ }
+
+ @Override
+ public String name() {
+ return provider.getInfo();
+ }
+
+ public Provider getProvider() {
+ return provider;
+ }
+
+ @Override
+ public String toString() {
+ return name();
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/SunECLib.java b/src/cz/crcs/ectester/standalone/libs/SunECLib.java
new file mode 100644
index 0000000..3aec842
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/SunECLib.java
@@ -0,0 +1,28 @@
+package cz.crcs.ectester.standalone.libs;
+
+import sun.security.ec.SunEC;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class SunECLib extends ProviderECLibrary {
+
+ public SunECLib() {
+ super(new SunEC());
+ }
+
+ @Override
+ public Set<String> getCurves() {
+ String curves = provider.get("AlgorithmParameters.EC SupportedCurves").toString();
+ String[] split = curves.split("\\|");
+ Set<String> result = new TreeSet<>();
+ for (String curve : split) {
+ String body = curve.split(",")[0].substring(1);
+ result.add(body);
+ }
+ return result;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java
new file mode 100644
index 0000000..57b273a
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.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 TomcryptLib extends NativeECLibrary {
+
+ public TomcryptLib() {
+ super("tomcrypt_provider", "tommath", "tomcrypt");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
new file mode 100644
index 0000000..3530499
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
@@ -0,0 +1,70 @@
+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))..)
+endif
+
+ifneq ($(JAVA_HOME),)
+JNI_INCLUDEDIR ?= $(JAVA_HOME)/include
+endif
+
+ifeq ($(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
+endif
+
+JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM)
+
+LOCAL_INCLUDES = /usr/local/include
+LOCAL_LIBS = /usr/local/lib
+
+CC?=gcc
+CXX?=g++
+
+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
+
+c_utils.o: c_utils.c
+ $(CC) $(CFLAGS) -c $<
+
+cpp_utils.o: cpp_utils.cpp
+ $(CXX) $(CXXFLAGS) -c $<
+
+
+tomcrypt_provider.so: tomcrypt.o c_utils.o
+ $(CC) -fPIC -g -shared -o $@ $^ -L. -ltommath -ltomcrypt
+
+tomcrypt.o: tomcrypt.c
+ $(CC) -DLTM_DESC $(CFLAGS) -c $<
+
+
+botan_provider.so: botan.o cpp_utils.o
+ $(CXX) -fPIC -g -shared -o $@ $^ -L. -L"$(LOCAL_LIBS)" -lbotan-2 -fstack-protector -m64 -pthread
+
+botan.o: botan.cpp
+ $(CXX) -I"$(LOCAL_INCLUDES)/botan-2" $(CFLAGS) -c $<
+
+clean:
+ rm -rf *.o
+ rm -rf *.so
+
+.PHONY: all clean \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
new file mode 100644
index 0000000..22e5329
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
@@ -0,0 +1,68 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import org.bouncycastle.util.Arrays;
+
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeECPrivateKey implements ECPrivateKey {
+ private String algorithm;
+ private String format;
+
+ public NativeECPrivateKey(String algorithm, String format) {
+ this.algorithm = algorithm;
+ this.format = format;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+
+ private static class Raw extends NativeECPrivateKey {
+ private byte[] keyData;
+ private ECParameterSpec params;
+
+ public Raw(byte[] keyData, ECParameterSpec params) {
+ super("EC", "raw");
+ this.keyData = keyData;
+ this.params = params;
+ }
+
+ @Override
+ public BigInteger getS() {
+ return new BigInteger(1, keyData);
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return Arrays.clone(keyData);
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return params;
+ }
+ }
+
+ public static class TomCrypt extends Raw {
+ public TomCrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ public static class Botan extends Raw {
+ public Botan(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
new file mode 100644
index 0000000..8fc4747
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
@@ -0,0 +1,69 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.util.ECUtil;
+import org.bouncycastle.util.Arrays;
+
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeECPublicKey implements ECPublicKey {
+ private String algorithm;
+ private String format;
+
+ public NativeECPublicKey(String algorithm, String format) {
+ this.algorithm = algorithm;
+ this.format = format;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+
+ private static class ANSIX962 extends NativeECPublicKey {
+ private byte[] keyData;
+ private ECParameterSpec params;
+
+ public ANSIX962(byte[] keyData, ECParameterSpec params) {
+ super("EC", "ANSI X9.62");
+ this.keyData = keyData;
+ this.params = params;
+ }
+
+ @Override
+ public ECPoint getW() {
+ return ECUtil.fromX962(keyData, params.getCurve());
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return Arrays.clone(keyData);
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return params;
+ }
+ }
+
+ public static class TomCrypt extends ANSIX962 {
+ public TomCrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ public static class Botan extends ANSIX962 {
+ public Botan(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
new file mode 100644
index 0000000..37c9add
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
@@ -0,0 +1,137 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.util.ECUtil;
+
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import java.security.*;
+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 abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
+ private ECPrivateKey privateKey;
+ private ECPublicKey publicKey;
+ private ECParameterSpec params;
+
+ @Override
+ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException {
+ if (!(key instanceof ECPrivateKey)) {
+ throw new InvalidKeyException
+ ("Key must be instance of ECPrivateKey");
+ }
+ privateKey = (ECPrivateKey) key;
+ this.params = privateKey.getParams();
+ }
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (!(params instanceof ECParameterSpec)) {
+ throw new InvalidAlgorithmParameterException();
+ }
+ engineInit(key, random);
+ this.params = (ECParameterSpec) params;
+ }
+
+ @Override
+ protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException {
+ if (privateKey == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+ if (publicKey != null) {
+ throw new IllegalStateException("Phase already executed");
+ }
+ if (!lastPhase) {
+ throw new IllegalStateException
+ ("Only two party agreement supported, lastPhase must be true");
+ }
+ if (!(key instanceof ECPublicKey)) {
+ throw new InvalidKeyException
+ ("Key must be an instance of ECPublicKey");
+ }
+ publicKey = (ECPublicKey) key;
+ return null;
+ }
+
+ @Override
+ protected byte[] engineGenerateSecret() throws IllegalStateException {
+ byte[] pubkey = ECUtil.toX962Uncompressed(publicKey.getW(), params.getCurve());
+ byte[] privkey = ECUtil.toByteArray(privateKey.getS(), params.getCurve().getField().getFieldSize());
+ return generateSecret(pubkey, privkey, params);
+ }
+
+ @Override
+ protected int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException {
+ byte[] secret = engineGenerateSecret();
+ if (sharedSecret.length < offset + secret.length) {
+ throw new ShortBufferException();
+ }
+ System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+ return secret.length;
+ }
+
+ @Override
+ protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ abstract byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+
+ public static class TomCrypt extends NativeKeyAgreementSpi {
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+ }
+
+ public abstract static class Botan extends NativeKeyAgreementSpi {
+ private String type;
+ public Botan(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+ }
+
+ public static class BotanECDH extends Botan {
+ public BotanECDH() {
+ super("ECDH");
+ }
+ }
+
+ public static class BotanECDHwithSHA1KDF extends Botan {
+ public BotanECDHwithSHA1KDF() {
+ super("ECDHwithSHA1KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA224KDF extends Botan {
+ public BotanECDHwithSHA224KDF() {
+ super("ECDHwithSHA224KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA256KDF extends Botan {
+ public BotanECDHwithSHA256KDF() {
+ super("ECDHwithSHA256KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA384KDF extends Botan {
+ public BotanECDHwithSHA384KDF() {
+ super("ECDHwithSHA384KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA512KDF extends Botan {
+ public BotanECDHwithSHA512KDF() {
+ super("ECDHwithSHA512KDF");
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
new file mode 100644
index 0000000..9461251
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
@@ -0,0 +1,123 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
+ private int keysize;
+ private SecureRandom random;
+ private AlgorithmParameterSpec params;
+ private boolean useKeysize;
+ private boolean useParams;
+
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ if (!keysizeSupported(keysize)) {
+ throw new InvalidParameterException("Keysize " + keysize + " not supported.");
+ }
+ this.keysize = keysize;
+ this.random = random;
+ this.useKeysize = true;
+ this.useParams = false;
+ }
+
+ @Override
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException {
+ if (!paramsSupported(params)) {
+ throw new InvalidAlgorithmParameterException("not supported.");
+ }
+ this.params = params;
+ this.random = random;
+ this.useParams = true;
+ this.useKeysize = false;
+ }
+
+ @Override
+ public KeyPair generateKeyPair() {
+ if (useKeysize) {
+ return generate(keysize, random);
+ } else if (useParams) {
+ return generate(params, random);
+ }
+ return null;
+ }
+
+ abstract boolean keysizeSupported(int keysize);
+
+ abstract boolean paramsSupported(AlgorithmParameterSpec params);
+
+ abstract KeyPair generate(int keysize, SecureRandom random);
+
+ abstract KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+
+ public static class TomCrypt extends NativeKeyPairGeneratorSpi {
+
+ public TomCrypt() {
+ 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 abstract class Botan extends NativeKeyPairGeneratorSpi {
+ private String type;
+
+ public Botan(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 BotanECDH extends Botan {
+
+ public BotanECDH() {
+ super("ECDH");
+ }
+ }
+
+ public static class BotanECDSA extends Botan {
+
+ public BotanECDSA() {
+ super("ECDSA");
+ }
+ }
+
+ public static class BotanECKCDSA extends Botan {
+
+ public BotanECKCDSA() {
+ super("ECKCDSA");
+ }
+ }
+
+ public static class BotanECGDSA extends Botan {
+
+ public BotanECGDSA() {
+ super("ECGDSA");
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
new file mode 100644
index 0000000..a0689d6
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
@@ -0,0 +1,42 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeProvider extends Provider {
+
+ public NativeProvider(String name, double version, String info) {
+ super(name, version, info);
+
+ AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
+ setup();
+ return null;
+ });
+ }
+
+ abstract void setup();
+
+ public static class TomCrypt extends NativeProvider {
+
+ public TomCrypt(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ public static class Botan extends NativeProvider {
+
+ public Botan(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
new file mode 100644
index 0000000..b212697
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
@@ -0,0 +1,227 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.util.ECUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.security.*;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeSignatureSpi extends SignatureSpi {
+ private ECPublicKey verifyKey;
+ private ECPrivateKey signKey;
+ private ECParameterSpec params;
+
+ private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ @Override
+ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
+ if (!(publicKey instanceof ECPublicKey)) {
+ throw new InvalidKeyException
+ ("Key must be an instance of ECPublicKey");
+ }
+ verifyKey = (ECPublicKey) publicKey;
+ params = verifyKey.getParams();
+ buffer.reset();
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
+ if (!(privateKey instanceof ECPrivateKey)) {
+ throw new InvalidKeyException
+ ("Key must be an instance of ECPrivateKey");
+ }
+ signKey = (ECPrivateKey) privateKey;
+ params = signKey.getParams();
+ buffer.reset();
+ }
+
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ buffer.write(b);
+ }
+
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
+ buffer.write(b, off, len);
+ }
+
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+ return sign(buffer.toByteArray(), ECUtil.toByteArray(signKey.getS(), params.getCurve().getField().getFieldSize()), params);
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ return verify(sigBytes, buffer.toByteArray(), ECUtil.toX962Uncompressed(verifyKey.getW(), params), params);
+ }
+
+ @Override
+ @Deprecated
+ protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
+ throw new UnsupportedOperationException("setParameter() not supported");
+ }
+
+ @Override
+ @Deprecated
+ protected Object engineGetParameter(String param) throws InvalidParameterException {
+ throw new UnsupportedOperationException("getParameter() not supported");
+ }
+
+ abstract byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ abstract boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+
+ public static class TomCryptRaw extends NativeSignatureSpi {
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public abstract static class Botan extends NativeSignatureSpi {
+ private String type;
+
+ public Botan(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class BotanECDSAwithNONE extends Botan {
+
+ public BotanECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA1 extends Botan {
+
+ public BotanECDSAwithSHA1() {
+ super("SHA1withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA224 extends Botan {
+
+ public BotanECDSAwithSHA224() {
+ super("SHA224withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA256 extends Botan {
+
+ public BotanECDSAwithSHA256() {
+ super("SHA256withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA384 extends Botan {
+
+ public BotanECDSAwithSHA384() {
+ super("SHA384withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA512 extends Botan {
+
+ public BotanECDSAwithSHA512() {
+ super("SHA512withECDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithNONE extends Botan {
+
+ public BotanECKCDSAwithNONE() {
+ super("NONEwithECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA1 extends Botan {
+
+ public BotanECKCDSAwithSHA1() {
+ super("SHA1withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA224 extends Botan {
+
+ public BotanECKCDSAwithSHA224() {
+ super("SHA224withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA256 extends Botan {
+
+ public BotanECKCDSAwithSHA256() {
+ super("SHA256withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA384 extends Botan {
+
+ public BotanECKCDSAwithSHA384() {
+ super("SHA384withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA512 extends Botan {
+
+ public BotanECKCDSAwithSHA512() {
+ super("SHA512withECKCDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithNONE extends Botan {
+
+ public BotanECGDSAwithNONE() {
+ super("NONEwithECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA1 extends Botan {
+
+ public BotanECGDSAwithSHA1() {
+ super("SHA1withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA224 extends Botan {
+
+ public BotanECGDSAwithSHA224() {
+ super("SHA224withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA256 extends Botan {
+
+ public BotanECGDSAwithSHA256() {
+ super("SHA256withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA384 extends Botan {
+
+ public BotanECGDSAwithSHA384() {
+ super("SHA384withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA512 extends Botan {
+
+ public BotanECGDSAwithSHA512() {
+ super("SHA512withECGDSA");
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp
new file mode 100644
index 0000000..8e666d6
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp
@@ -0,0 +1,631 @@
+#include "native.h"
+#include <string>
+#include <botan/botan.h>
+#include <botan/ec_group.h>
+#include <botan/ecc_key.h>
+#include <botan/ecdsa.h>
+#include <botan/eckcdsa.h>
+#include <botan/ecgdsa.h>
+#include <botan/ecdh.h>
+#include <botan/pubkey.h>
+#include "cpp_utils.hpp"
+
+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");
+ provider_class = (jclass) env->NewGlobalRef(local_provider_class);
+
+ jmethodID init = env->GetMethodID(local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ const char* info_str = Botan::version_cstr();
+ const char* v_str = Botan::short_version_cstr();
+ std::string name_str = Botan::short_version_string();
+ name_str.insert(0, "Botan ");
+
+ jstring name = env->NewStringUTF(name_str.c_str());
+ double version = strtod(v_str, NULL);
+ jstring info = env->NewStringUTF(info_str);
+
+ 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;");
+
+ 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);
+
+ 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);
+
+ 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 hash_set_class = env->FindClass("java/util/TreeSet");
+
+ jmethodID hash_set_ctr = env->GetMethodID(hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = env->GetMethodID(hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = env->NewObject(hash_set_class, hash_set_ctr);
+
+ const std::set<std::string>& 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);
+ }
+
+ 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;
+ }
+
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = env->CallObjectMethod(params, get_curve);
+
+ jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = env->CallObjectMethod(curve, get_field);
+
+ if (env->IsInstanceOf(field, fp_field_class)) {
+ return JNI_TRUE;
+ }
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ const std::set<std::string>& curves = Botan::EC_Group::known_named_groups();
+ 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);
+ if (curves.find(str_name) != curves.end()) {
+ return JNI_TRUE;
+ }
+ }
+ return JNI_FALSE;
+}
+
+static jobject biginteger_from_bigint(JNIEnv *env, const Botan::BigInt& bigint) {
+ std::vector<uint8_t> bigint_data = Botan::BigInt::encode(bigint);
+ jbyteArray bigint_array = env->NewByteArray(bigint_data.size());
+ jbyte * bigint_bytes = env->GetByteArrayElements(bigint_array, NULL);
+ std::copy(bigint_data.begin(), bigint_data.end(), bigint_bytes);
+ env->ReleaseByteArrayElements(bigint_array, bigint_bytes, JNI_COMMIT);
+
+ jmethodID biginteger_init = env->GetMethodID(biginteger_class, "<init>", "(I[B)V");
+ return env->NewObject(biginteger_class, biginteger_init, (jint) 1, bigint_array);
+}
+
+static Botan::BigInt bigint_from_biginteger(JNIEnv *env, jobject biginteger) {
+ jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B");
+ jbyteArray byte_array = (jbyteArray) env->CallObjectMethod(biginteger, to_byte_array);
+ jsize byte_length = env->GetArrayLength(byte_array);
+ jbyte *byte_data = env->GetByteArrayElements(byte_array, NULL);
+ Botan::BigInt result((unsigned uint8_t*) byte_data, byte_length);
+ env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT);
+ return result;
+}
+
+static Botan::EC_Group 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);
+
+ jmethodID get_bits = env->GetMethodID(fp_field_class, "getFieldSize", "()I");
+ jint bits = env->CallIntMethod(field, get_bits);
+ jint bytes = (bits + 7) / 8;
+
+ jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = env->CallObjectMethod(elliptic_curve, get_a);
+
+ jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = env->CallObjectMethod(elliptic_curve, get_b);
+
+ jmethodID get_p = env->GetMethodID(fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = env->CallObjectMethod(field, get_p);
+
+ 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);
+
+ jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = env->CallIntMethod(params, get_h);
+
+ Botan::BigInt pi = bigint_from_biginteger(env, p);
+ Botan::BigInt ai = bigint_from_biginteger(env, a);
+ Botan::BigInt bi = bigint_from_biginteger(env, b);
+ Botan::CurveGFp curve(pi, ai, bi);
+
+ Botan::BigInt gxi = bigint_from_biginteger(env, gx);
+ Botan::BigInt gyi = bigint_from_biginteger(env, gy);
+ Botan::PointGFp generator(curve, gxi, gyi);
+
+ Botan::BigInt ni = bigint_from_biginteger(env, n);
+ Botan::BigInt hi(h);
+
+ return Botan::EC_Group(curve, generator, 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 curve_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+ return Botan::EC_Group(curve_name);
+ }
+ return Botan::EC_Group();
+}
+
+static jobject params_from_group(JNIEnv *env, Botan::EC_Group group) {
+ const Botan::CurveGFp& curve = group.get_curve();
+ jobject p = biginteger_from_bigint(env, curve.get_p());
+
+ jmethodID fp_field_init = env->GetMethodID(fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject fp_field = env->NewObject(fp_field_class, fp_field_init, p);
+
+ jobject a = biginteger_from_bigint(env, curve.get_a());
+ jobject b = biginteger_from_bigint(env, curve.get_b());
+
+ jmethodID elliptic_curve_init = env->GetMethodID(elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = env->NewObject(elliptic_curve_class, elliptic_curve_init, fp_field, a, b);
+
+ const Botan::PointGFp& generator = group.get_base_point();
+ jobject gx = biginteger_from_bigint(env, generator.get_affine_x());
+ jobject gy = biginteger_from_bigint(env, generator.get_affine_y());
+
+ jmethodID point_init = env->GetMethodID(point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = env->NewObject(point_class, point_init, gx, gy);
+
+ const Botan::BigInt& order = group.get_order();
+ jobject n = biginteger_from_bigint(env, order);
+
+ const Botan::BigInt& cofactor = group.get_cofactor();
+ jint h = (jint) cofactor.to_u32bit();
+
+ jmethodID ec_parameter_spec_init = env->GetMethodID(ec_parameter_spec_class, "<init>", "(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, n, h);
+}
+
+static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group group) {
+ Botan::AutoSeeded_RNG rng;
+
+ jclass botan_kpg_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_kpg_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char* type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ std::unique_ptr<Botan::EC_PrivateKey> skey;
+ try {
+ if (type_str == "ECDH") {
+ skey = std::make_unique<Botan::ECDH_PrivateKey>(rng, group);
+ } else if (type_str == "ECDSA") {
+ skey = std::make_unique<Botan::ECDSA_PrivateKey>(rng, group);
+ } else if (type_str == "ECKCDSA") {
+ skey = std::make_unique<Botan::ECKCDSA_PrivateKey>(rng, group);
+ } else if (type_str == "ECGDSA") {
+ skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, group);
+ }
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+
+ jobject ec_param_spec = params_from_group(env, group);
+
+ const Botan::PointGFp& pub_point = skey->public_point();
+ std::vector<uint8_t> pub_data = Botan::unlock(Botan::EC2OSP(pub_point, Botan::PointGFp::UNCOMPRESSED));
+
+ jbyteArray pub_bytearray = env->NewByteArray(pub_data.size());
+ jbyte *pub_bytes = env->GetByteArrayElements(pub_bytearray, NULL);
+ std::copy(pub_data.begin(), pub_data.end(), pub_bytes);
+ env->ReleaseByteArrayElements(pub_bytearray, pub_bytes, JNI_COMMIT);
+
+ jobject ec_pub_param_spec = env->NewLocalRef(ec_param_spec);
+ jmethodID ec_pub_init = env->GetMethodID(pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = env->NewObject(pubkey_class, ec_pub_init, pub_bytearray, ec_pub_param_spec);
+
+ const Botan::BigInt& priv_scalar = skey->private_value();
+ std::vector<uint8_t> priv_data = Botan::BigInt::encode(priv_scalar);
+
+ jbyteArray priv_bytearray = env->NewByteArray(priv_data.size());
+ jbyte *priv_bytes = env->GetByteArrayElements(priv_bytearray, NULL);
+ std::copy(priv_data.begin(), priv_data.end(), priv_bytes);
+ env->ReleaseByteArrayElements(priv_bytearray, priv_bytes, JNI_COMMIT);
+
+ jobject ec_priv_param_spec = env->NewLocalRef(ec_param_spec);
+ jmethodID ec_priv_init = env->GetMethodID(privkey_class, "<init>", "([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, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+
+ 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<std::string>& curves = Botan::EC_Group::known_named_groups();
+ for (auto it = curves.begin(); it != curves.end(); ++it) {
+ Botan::EC_Group curve_group = Botan::EC_Group(*it);
+ size_t curve_size = curve_group.get_curve().get_p().bits();
+ if (curve_size == keysize) {
+ //generate on this group. Even thou no default groups are present...
+ return generate_from_group(env, self, curve_group);
+ }
+ }
+
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ 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);
+
+ jsize privkey_length = env->GetArrayLength(privkey);
+ jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL);
+ Botan::BigInt privkey_scalar((unsigned uint8_t*) privkey_data, privkey_length);
+ env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
+
+ Botan::AutoSeeded_RNG rng;
+
+ Botan::ECDH_PrivateKey skey(rng, curve_group, privkey_scalar);
+
+ jsize pubkey_length = env->GetArrayLength(pubkey);
+ jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL);
+ Botan::PointGFp public_point = Botan::OS2ECP((uint8_t*) pubkey_data, pubkey_length, curve_group.get_curve());
+ env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT);
+
+ Botan::ECDH_PublicKey pkey(curve_group, public_point);
+ //TODO: do check_key here?
+
+ jclass botan_ka_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_ka_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ std::string kdf;
+ size_t key_len = 0;
+ if (type_str == "ECDH") {
+ kdf = "Raw";
+ //key len unused
+ } else if (type_str == "ECDHwithSHA1KDF") {
+ kdf = "KDF1(SHA-1)";
+ key_len = 20;
+ } else if (type_str == "ECDHwithSHA224KDF") {
+ kdf = "KDF1(SHA-224)";
+ key_len = 28;
+ } else if (type_str == "ECDHwithSHA256KDF") {
+ kdf = "KDF1(SHA-256)";
+ key_len = 32;
+ } else if (type_str == "ECDHwithSHA384KDF") {
+ kdf = "KDF1(SHA-384)";
+ key_len = 48;
+ } else if (type_str == "ECDHwithSHA512KDF") {
+ kdf = "KDF1(SHA-512)";
+ key_len = 64;
+ }
+
+ Botan::PK_Key_Agreement ka(skey, rng, kdf);
+
+ std::vector<uint8_t> derived;
+ try {
+ derived = Botan::unlock(ka.derive_key(key_len, pkey.public_value()).bits_of());
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+ jbyteArray result = env->NewByteArray(derived.size());
+ jbyte *result_data = env->GetByteArrayElements(result, NULL);
+ std::copy(derived.begin(), derived.end(), result_data);
+ env->ReleaseByteArrayElements(result, result_data, JNI_COMMIT);
+
+ 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);
+
+ jclass botan_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ jsize privkey_length = env->GetArrayLength(privkey);
+ jbyte *privkey_bytes = env->GetByteArrayElements(privkey, NULL);
+ Botan::BigInt privkey_scalar((uint8_t*) privkey_bytes, privkey_length);
+ env->ReleaseByteArrayElements(privkey, privkey_bytes, JNI_ABORT);
+
+ Botan::AutoSeeded_RNG rng;
+
+ std::unique_ptr<Botan::EC_PrivateKey> skey;
+ if (type_str.find("ECDSA") != std::string::npos) {
+ skey = std::make_unique<Botan::ECDSA_PrivateKey>(rng, curve_group, privkey_scalar);
+ } else if (type_str.find("ECKCDSA") != std::string::npos) {
+ skey = std::make_unique<Botan::ECKCDSA_PrivateKey>(rng, curve_group, privkey_scalar);
+ } else if (type_str.find("ECGDSA") != std::string::npos) {
+ skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, curve_group, privkey_scalar);
+ }
+
+ std::string kdf;
+ if (type_str.find("NONE") != std::string::npos) {
+ kdf = "Raw";
+ } else if (type_str.find("SHA1") != std::string::npos) {
+ kdf = "EMSA1(SHA-1)";
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ kdf = "EMSA1(SHA-224)";
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ kdf = "EMSA1(SHA-256)";
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ kdf = "EMSA1(SHA-384)";
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ kdf = "EMSA1(SHA-512)";
+ }
+
+ Botan::PK_Signer signer(*skey, rng, kdf, Botan::DER_SEQUENCE);
+
+ jsize data_length = env->GetArrayLength(data);
+ jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ std::vector<uint8_t> sig;
+ try {
+ sig = signer.sign_message((uint8_t*) data_bytes, data_length, rng);
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ return NULL;
+ }
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+
+ jbyteArray result = env->NewByteArray(sig.size());
+ jbyte *result_data = env->GetByteArrayElements(result, NULL);
+ std::copy(sig.begin(), sig.end(), result_data);
+ env->ReleaseByteArrayElements(result, result_data, JNI_COMMIT);
+
+ 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);
+
+ jclass botan_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ jsize pubkey_length = env->GetArrayLength(pubkey);
+ jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL);
+ Botan::PointGFp public_point = Botan::OS2ECP((uint8_t*) pubkey_data, pubkey_length, curve_group.get_curve());
+ env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT);
+
+ std::unique_ptr<Botan::EC_PublicKey> pkey;
+ if (type_str.find("ECDSA") != std::string::npos) {
+ pkey = std::make_unique<Botan::ECDSA_PublicKey>(curve_group, public_point);
+ } else if (type_str.find("ECKCDSA") != std::string::npos) {
+ pkey = std::make_unique<Botan::ECKCDSA_PublicKey>(curve_group, public_point);
+ } else if (type_str.find("ECGDSA") != std::string::npos) {
+ pkey = std::make_unique<Botan::ECGDSA_PublicKey>(curve_group, public_point);
+ }
+
+ std::string kdf;
+ if (type_str.find("NONE") != std::string::npos) {
+ kdf = "Raw";
+ } else if (type_str.find("SHA1") != std::string::npos) {
+ kdf = "EMSA1(SHA-1)";
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ kdf = "EMSA1(SHA-224)";
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ kdf = "EMSA1(SHA-256)";
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ kdf = "EMSA1(SHA-384)";
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ kdf = "EMSA1(SHA-512)";
+ }
+
+ Botan::PK_Verifier verifier(*pkey, kdf, Botan::DER_SEQUENCE);
+
+ jsize data_length = env->GetArrayLength(data);
+ jsize sig_length = env->GetArrayLength(signature);
+ jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ jbyte *sig_bytes = env->GetByteArrayElements(signature, NULL);
+
+ bool result;
+ try {
+ result = verifier.verify_message((uint8_t*)data_bytes, data_length, (uint8_t*)sig_bytes, sig_length);
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT);
+ return JNI_FALSE;
+ }
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT);
+ if (result) {
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
new file mode 100644
index 0000000..336f4a1
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
@@ -0,0 +1,66 @@
+#include "c_utils.h"
+#include <string.h>
+
+jclass ec_parameter_spec_class;
+jclass ecgen_parameter_spec_class;
+jclass pubkey_class;
+jclass privkey_class;
+jclass keypair_class;
+jclass elliptic_curve_class;
+jclass fp_field_class;
+jclass f2m_field_class;
+jclass point_class;
+jclass biginteger_class;
+jclass illegal_state_exception_class;
+
+void init_classes(JNIEnv *env, const char* lib_name) {
+ jclass local_ec_parameter_spec_class = (*env)->FindClass(env, "java/security/spec/ECParameterSpec");
+ ec_parameter_spec_class = (*env)->NewGlobalRef(env, local_ec_parameter_spec_class);
+
+ jclass local_ecgen_parameter_spec_class = (*env)->FindClass(env, "java/security/spec/ECGenParameterSpec");
+ ecgen_parameter_spec_class = (*env)->NewGlobalRef(env, local_ecgen_parameter_spec_class);
+
+ const char *pubkey_base = "cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$";
+ char pubkey_class_name[strlen(pubkey_base) + strlen(lib_name) + 1];
+ pubkey_class_name[0] = 0;
+ strcat(pubkey_class_name, pubkey_base);
+ strcat(pubkey_class_name, lib_name);
+
+ jclass local_pubkey_class = (*env)->FindClass(env, pubkey_class_name);
+ pubkey_class = (*env)->NewGlobalRef(env, local_pubkey_class);
+
+ const char *privkey_base = "cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$";
+ char privkey_class_name[strlen(privkey_base) + strlen(lib_name) + 1];
+ privkey_class_name[0] = 0;
+ strcat(privkey_class_name, privkey_base);
+ strcat(privkey_class_name, lib_name);
+
+ jclass local_privkey_class = (*env)->FindClass(env, privkey_class_name);
+ privkey_class = (*env)->NewGlobalRef(env, local_privkey_class);
+
+ jclass local_keypair_class = (*env)->FindClass(env, "java/security/KeyPair");
+ keypair_class = (*env)->NewGlobalRef(env, local_keypair_class);
+
+ jclass local_elliptic_curve_class = (*env)->FindClass(env, "java/security/spec/EllipticCurve");
+ elliptic_curve_class = (*env)->NewGlobalRef(env, local_elliptic_curve_class);
+
+ jclass local_fp_field_class = (*env)->FindClass(env, "java/security/spec/ECFieldFp");
+ fp_field_class = (*env)->NewGlobalRef(env, local_fp_field_class);
+
+ jclass local_f2m_field_class = (*env)->FindClass(env, "java/security/spec/ECFieldF2m");
+ f2m_field_class = (*env)->NewGlobalRef(env, local_f2m_field_class);
+
+ jclass local_biginteger_class = (*env)->FindClass(env, "java/math/BigInteger");
+ biginteger_class = (*env)->NewGlobalRef(env, local_biginteger_class);
+
+ jclass local_point_class = (*env)->FindClass(env, "java/security/spec/ECPoint");
+ point_class = (*env)->NewGlobalRef(env, local_point_class);
+
+ jclass local_illegal_state_exception_class = (*env)->FindClass(env, "java/lang/IllegalStateException");
+ illegal_state_exception_class = (*env)->NewGlobalRef(env, local_illegal_state_exception_class);
+}
+
+void throw_new(JNIEnv *env, const char *class, const char *message) {
+ jclass clazz = (*env)->FindClass(env, class);
+ (*env)->ThrowNew(env, clazz, message);
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
new file mode 100644
index 0000000..d925dfe
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "native.h"
+
+/**
+ * Classes that are accessed alot are cached here, manually.
+ */
+extern jclass ec_parameter_spec_class;
+extern jclass ecgen_parameter_spec_class;
+extern jclass pubkey_class;
+extern jclass privkey_class;
+extern jclass keypair_class;
+extern jclass elliptic_curve_class;
+extern jclass fp_field_class;
+extern jclass f2m_field_class;
+extern jclass point_class;
+extern jclass biginteger_class;
+extern jclass illegal_state_exception_class;
+
+/**
+ * Initialize the classes.
+ */
+void init_classes(JNIEnv *env, const char* lib_name);
+
+/**
+ * Throw a new exception of class with message.
+ */
+void throw_new(JNIEnv *env, const char *class, const char *message); \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp
new file mode 100644
index 0000000..cef4bfe
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp
@@ -0,0 +1,59 @@
+#include "cpp_utils.hpp"
+
+jclass ec_parameter_spec_class;
+jclass ecgen_parameter_spec_class;
+jclass pubkey_class;
+jclass privkey_class;
+jclass keypair_class;
+jclass elliptic_curve_class;
+jclass fp_field_class;
+jclass f2m_field_class;
+jclass point_class;
+jclass biginteger_class;
+jclass illegal_state_exception_class;
+
+void init_classes(JNIEnv *env, std::string lib_name) {
+ jclass local_ec_parameter_spec_class = env->FindClass("java/security/spec/ECParameterSpec");
+ ec_parameter_spec_class = (jclass) env->NewGlobalRef(local_ec_parameter_spec_class);
+
+ jclass local_ecgen_parameter_spec_class = env->FindClass("java/security/spec/ECGenParameterSpec");
+ ecgen_parameter_spec_class = (jclass) env->NewGlobalRef(local_ecgen_parameter_spec_class);
+
+ std::string pubkey_class_name("cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$");
+ pubkey_class_name += lib_name;
+
+ jclass local_pubkey_class = env->FindClass(pubkey_class_name.c_str());
+ pubkey_class = (jclass) env->NewGlobalRef(local_pubkey_class);
+
+ std::string privkey_class_name("cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$");
+ privkey_class_name += lib_name;
+
+ jclass local_privkey_class = env->FindClass(privkey_class_name.c_str());
+ privkey_class = (jclass) env->NewGlobalRef(local_privkey_class);
+
+ jclass local_keypair_class = env->FindClass("java/security/KeyPair");
+ keypair_class = (jclass) env->NewGlobalRef(local_keypair_class);
+
+ jclass local_elliptic_curve_class = env->FindClass("java/security/spec/EllipticCurve");
+ elliptic_curve_class = (jclass) env->NewGlobalRef(local_elliptic_curve_class);
+
+ jclass local_fp_field_class = env->FindClass("java/security/spec/ECFieldFp");
+ fp_field_class = (jclass) env->NewGlobalRef(local_fp_field_class);
+
+ jclass local_f2m_field_class = env->FindClass("java/security/spec/ECFieldF2m");
+ f2m_field_class = (jclass) env->NewGlobalRef(local_f2m_field_class);
+
+ jclass local_biginteger_class = env->FindClass("java/math/BigInteger");
+ biginteger_class = (jclass) env->NewGlobalRef(local_biginteger_class);
+
+ jclass local_point_class = env->FindClass("java/security/spec/ECPoint");
+ point_class = (jclass) env->NewGlobalRef(local_point_class);
+
+ jclass local_illegal_state_exception_class = env->FindClass("java/lang/IllegalStateException");
+ illegal_state_exception_class = (jclass) env->NewGlobalRef(local_illegal_state_exception_class);
+}
+
+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());
+} \ 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
new file mode 100644
index 0000000..bbca521
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "native.h"
+#include <string>
+
+/**
+ * Classes that are accessed alot are cached here, manually.
+ */
+extern jclass ec_parameter_spec_class;
+extern jclass ecgen_parameter_spec_class;
+extern jclass pubkey_class;
+extern jclass privkey_class;
+extern jclass keypair_class;
+extern jclass elliptic_curve_class;
+extern jclass fp_field_class;
+extern jclass f2m_field_class;
+extern jclass point_class;
+extern jclass biginteger_class;
+extern jclass illegal_state_exception_class;
+
+/**
+ * Initialize the classes.
+ */
+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
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h
new file mode 100644
index 0000000..d714b39
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h
@@ -0,0 +1,344 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class cz_crcs_ectester_standalone_libs_TomcryptLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_TomcryptLib
+#define _Included_cz_crcs_ectester_standalone_libs_TomcryptLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 1421746759512286392LL
+#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
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_VALUES 1L
+#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
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_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_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_BotanLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_BotanLib
+#define _Included_cz_crcs_ectester_standalone_libs_BotanLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * 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 *, jobject);
+
+/*
+ * 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 *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 1421746759512286392LL
+#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
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_VALUES 1L
+#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
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID -4298000515446427739LL
+/*
+ * 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 *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * 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 *, jobject, jint);
+
+/*
+ * 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 *, jobject, jobject);
+
+/*
+ * 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 *, jobject, jint, jobject);
+
+/*
+ * 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 *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * 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 *, jobject, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * 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 *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * 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 *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
new file mode 100644
index 0000000..29ee707
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
@@ -0,0 +1,450 @@
+#include "native.h"
+#include <stdio.h>
+#include <string.h>
+#include <tomcrypt.h>
+#include "c_utils.h"
+
+static prng_state ltc_prng;
+static jclass provider_class;
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider(JNIEnv *env, jobject this) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$TomCrypt");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, "libtomcrypt " SCRYPT);
+ double version = strtod(SCRYPT, NULL);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup(JNIEnv *env, jobject this) {
+ /* Initialize libtommath as the math lib. */
+ ltc_mp = ltm_desc;
+
+ 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$TomCrypt");
+ (*env)->CallObjectMethod(env, this, provider_put, ec, ec_value);
+
+ jstring ecdh = (*env)->NewStringUTF(env, "KeyAgreement.ECDH");
+ jstring ecdh_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$TomCrypt");
+ (*env)->CallObjectMethod(env, this, provider_put, ecdh, ecdh_value);
+
+ jstring ecdsa = (*env)->NewStringUTF(env, "Signature.NONEwithECDSA");
+ jstring ecdsa_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$TomCryptRaw");
+ (*env)->CallObjectMethod(env, this, provider_put, ecdsa, ecdsa_value);
+
+ int err;
+ /* register yarrow */
+ if (register_prng(&yarrow_desc) == -1) {
+ fprintf(stderr, "Error registering Yarrow\n");
+ return;
+ }
+ /* setup the PRNG */
+ if ((err = rng_make_prng(128, find_prng("yarrow"), &ltc_prng, NULL)) != CRYPT_OK) {
+ fprintf(stderr, "Error setting up PRNG, %s\n", error_to_string(err));
+ }
+
+ init_classes(env, "TomCrypt");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves(JNIEnv *env, jobject this) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()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);
+ const ltc_ecc_set_type * curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ jstring curve_name = (*env)->NewStringUTF(env, curve->name);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ curve++;
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported(JNIEnv *env, jobject this, jint keysize){
+ int key_bytes = (keysize + 7) / 8;
+ const ltc_ecc_set_type * curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (curve->size == key_bytes) {
+ return JNI_TRUE;
+ }
+ curve++;
+ }
+
+ return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_paramsSupported(JNIEnv *env, jobject this, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject 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, curve, get_field);
+
+ 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);
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, curve, get_a);
+
+ jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;");
+ jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong)3);
+
+ jmethodID biginteger_add = (*env)->GetMethodID(env, biginteger_class, "add", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;");
+ jobject a_3 = (*env)->CallObjectMethod(env, a, biginteger_add, three);
+
+ jmethodID biginteger_equals = (*env)->GetMethodID(env, biginteger_class, "equals", "(Ljava/lang/Object;)Z");
+ jboolean eq = (*env)->CallBooleanMethod(env, p, biginteger_equals, a_3);
+ return eq;
+ } else if ((*env)->IsInstanceOf(env, field, f2m_field_class)) {
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+ } 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);
+ const ltc_ecc_set_type * curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (strcasecmp(utf_name, curve->name) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ curve++;
+ }
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, const ltc_ecc_set_type *curve) {
+ jstring p_string = (*env)->NewStringUTF(env, curve->prime);
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(Ljava/lang/String;I)V");
+ jobject p = (*env)->NewObject(env, biginteger_class, biginteger_init, p_string, (jint) 16);
+
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p);
+
+ jmethodID biginteger_subtract = (*env)->GetMethodID(env, biginteger_class, "subtract", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;");
+ jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;");
+ jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong) 3);
+ jobject a = (*env)->CallObjectMethod(env, p, biginteger_subtract, three);
+
+ jstring b_string = (*env)->NewStringUTF(env, curve->B);
+ jobject b = (*env)->NewObject(env, biginteger_class, biginteger_init, b_string, (jint) 16);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(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, b);
+
+ jstring gx_string = (*env)->NewStringUTF(env, curve->Gx);
+ jstring gy_string = (*env)->NewStringUTF(env, curve->Gy);
+ jobject gx = (*env)->NewObject(env, biginteger_class, biginteger_init, gx_string, (jint) 16);
+ jobject gy = (*env)->NewObject(env, biginteger_class, biginteger_init, gy_string, (jint) 16);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx, gy);
+
+ jstring n_string = (*env)->NewStringUTF(env, curve->order);
+ jobject n = (*env)->NewObject(env, biginteger_class, biginteger_init, n_string, (jint) 16);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(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, (jint) 1);
+}
+
+static char *biginteger_to_hex(JNIEnv *env, jobject big, jint bytes) {
+ jmethodID to_string = (*env)->GetMethodID(env, biginteger_class, "toString", "(I)Ljava/lang/String;");
+ jstring big_string = (*env)->CallObjectMethod(env, big, to_string, (jint) 16);
+
+ jsize len = (*env)->GetStringUTFLength(env, big_string);
+ char raw_string[len];
+ (*env)->GetStringUTFRegion(env, big_string, 0, len, raw_string);
+
+ char *result = calloc(bytes, 2);
+ if (len >= bytes) {
+ return strncpy(result, raw_string, 2*bytes);
+ } else {
+ jsize diff = bytes - len;
+ for (jint i = 0; i < diff*2; ++i) {
+ result[i] = '0';
+ }
+ return strncpy(result + diff*2, raw_string, 2*bytes);
+ }
+}
+
+static ltc_ecc_set_type* 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_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ 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);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+
+ ltc_ecc_set_type *curve = calloc(sizeof(ltc_ecc_set_type), 1);
+ curve->size = bytes;
+ curve->name = "";
+ curve->prime = biginteger_to_hex(env, p, bytes);
+ curve->B = biginteger_to_hex(env, b, bytes);
+ curve->order = biginteger_to_hex(env, n, bytes);
+ curve->Gx = biginteger_to_hex(env, gx, bytes);
+ curve->Gy = biginteger_to_hex(env, gy, bytes);
+
+ return curve;
+}
+
+static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) {
+ ecc_key key;
+ int err;
+ if ((err = ecc_make_key_ex(&ltc_prng, find_prng("yarrow"), &key, curve)) != CRYPT_OK) {
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
+ return NULL;
+ }
+ unsigned long key_len = 2*curve->size + 1;
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ ecc_ansi_x963_export(&key, key_pub, &key_len);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, JNI_COMMIT);
+
+ 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, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_param_spec);
+
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, curve->size);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ ltc_mp.unsigned_write(key.k, key_priv);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, JNI_COMMIT);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([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, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+
+ ecc_free(&key);
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject this, jint keysize, jobject random){
+ int key_bytes = (keysize + 7) / 8;
+
+ const ltc_ecc_set_type *curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (curve->size == key_bytes) {
+ break;
+ }
+ curve++;
+ }
+
+ if (curve->size == 0) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+
+ return generate_from_curve(env, curve);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject this, jobject params, jobject random){
+ 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);
+ 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);
+ const ltc_ecc_set_type* curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (strcasecmp(utf_name, curve->name) == 0) {
+ break;
+ }
+ curve++;
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+
+ return generate_from_curve(env, curve);
+ } else {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+}
+
+static jboolean privkey_from_bytes(JNIEnv *env, jbyteArray privkey, const ltc_ecc_set_type *curve, ecc_key *out) {
+ jsize priv_size = (*env)->GetArrayLength(env, privkey);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL);
+
+ if (curve->size != priv_size) {
+ throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the private key size.");
+ (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+
+ out->type = PK_PRIVATE;
+ out->idx = -1;
+ out->dp = curve;
+ ltc_mp.init(&out->k);
+ ltc_mp.unsigned_read(out->k, priv_data, (unsigned long) curve->size);
+
+ (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT);
+ return JNI_TRUE;
+}
+
+static jboolean pubkey_from_bytes(JNIEnv *env, jbyteArray pubkey, const ltc_ecc_set_type *curve, ecc_key *out) {
+ jsize pub_size = (*env)->GetArrayLength(env, pubkey);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL);
+
+ if (curve->size != (pub_size - 1) / 2) {
+ throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the public key size.");
+ (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+
+ out->type = PK_PUBLIC;
+ out->idx = -1;
+ out->dp = curve;
+ ltc_init_multi(&out->pubkey.x, &out->pubkey.y, &out->pubkey.z, NULL);
+ ltc_mp.set_int(out->pubkey.z, 1);
+ ltc_mp.unsigned_read(out->pubkey.x, pub_data + 1, (unsigned long) curve->size);
+ ltc_mp.unsigned_read(out->pubkey.y, pub_data + 1 + curve->size, (unsigned long) curve->size);
+
+ (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT);
+
+ return JNI_TRUE;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params){
+ ltc_ecc_set_type *curve = create_curve(env, params);
+
+ ecc_key pub;
+ if (!pubkey_from_bytes(env, pubkey, curve, &pub)) {
+ free(curve);
+ return NULL;
+ }
+
+ ecc_key priv;
+ if (!privkey_from_bytes(env, privkey, curve, &priv)) {
+ free(curve);
+ return NULL;
+ }
+
+ unsigned char result[curve->size];
+ unsigned long output_len = curve->size;
+ 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);
+ return NULL;
+ }
+
+ jbyteArray output = (*env)->NewByteArray(env, curve->size);
+ jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL);
+ memcpy(output_data, result, curve->size);
+ (*env)->ReleaseByteArrayElements(env, output, output_data, JNI_COMMIT);
+
+ ltc_cleanup_multi(&pub.pubkey.x, &pub.pubkey.y, &pub.pubkey.z, &priv.k, NULL);
+ free(curve);
+ return output;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) {
+ ltc_ecc_set_type *curve = create_curve(env, params);
+
+ ecc_key priv;
+ if (!privkey_from_bytes(env, privkey, curve, &priv)) {
+ free(curve);
+ return NULL;
+ }
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ unsigned char result[curve->size*4];
+ unsigned long output_len = curve->size*4;
+ int err;
+ if ((err = ecc_sign_hash(data_data, data_size, result, &output_len, &ltc_prng, find_prng("yarrow"), &priv)) != CRYPT_OK) {
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
+ free(curve);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ return NULL;
+ }
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ jbyteArray output = (*env)->NewByteArray(env, output_len);
+ jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL);
+ memcpy(output_data, result, output_len);
+ (*env)->ReleaseByteArrayElements(env, output, output_data, JNI_COMMIT);
+
+ free(curve);
+ return output;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify(JNIEnv *env, jobject this, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ ltc_ecc_set_type *curve = create_curve(env, params);
+
+ ecc_key pub;
+ if (!pubkey_from_bytes(env, pubkey, curve, &pub)) {
+ free(curve);
+ return JNI_FALSE;
+ }
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ jsize sig_size = (*env)->GetArrayLength(env, signature);
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
+
+ int err;
+ 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);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+ free(curve);
+ return result;
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java
new file mode 100644
index 0000000..972af18
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java
@@ -0,0 +1,28 @@
+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 java.io.PrintStream;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class TextTestWriter extends BaseTextTestWriter {
+ public TextTestWriter(PrintStream output) {
+ super(output);
+ }
+
+ @Override
+ protected String testableString(Testable t) {
+ //TODO
+ return "";
+ }
+
+ @Override
+ protected String deviceString(TestSuite suite) {
+ //TODO
+ return "";
+ }
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java b/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java
new file mode 100644
index 0000000..d2b16d8
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java
@@ -0,0 +1,119 @@
+package cz.crcs.ectester.standalone.output;
+
+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.test.KeyAgreementTestable;
+import cz.crcs.ectester.standalone.test.KeyGeneratorTestable;
+import cz.crcs.ectester.standalone.test.SignatureTestable;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.OutputStream;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class XMLTestWriter extends BaseXMLTestWriter {
+
+ public XMLTestWriter(OutputStream output) throws ParserConfigurationException {
+ super(output);
+ }
+
+ private Element pkeyElement(PublicKey pkey) {
+ Element pubkey = doc.createElement("pubkey");
+ if (pkey == null) {
+ return pubkey;
+ }
+ pubkey.setAttribute("algorithm", pkey.getAlgorithm());
+ pubkey.setAttribute("format", pkey.getFormat());
+ pubkey.setTextContent(ByteUtil.bytesToHex(pkey.getEncoded()));
+ return pubkey;
+ }
+
+ private Element skeyElement(PrivateKey skey) {
+ Element privkey = doc.createElement("privkey");
+ if (skey == null) {
+ return privkey;
+ }
+ privkey.setAttribute("algorithm", skey.getAlgorithm());
+ privkey.setAttribute("format", skey.getFormat());
+ privkey.setTextContent(ByteUtil.bytesToHex(skey.getEncoded()));
+ return privkey;
+ }
+
+ private Element kaElement(KeyAgreementTestable kat) {
+ Element katElem = doc.createElement("key-agreement");
+ katElem.setAttribute("algo", kat.getKa().getAlgorithm());
+
+ Element secret = doc.createElement("secret");
+ secret.setTextContent(ByteUtil.bytesToHex(kat.getSecret()));
+ katElem.appendChild(secret);
+
+ PublicKey pkey = kat.getPublicKey();
+ Element pubkey = pkeyElement(pkey);
+ katElem.appendChild(pubkey);
+
+ PrivateKey skey = kat.getPrivateKey();
+ Element privkey = skeyElement(skey);
+ katElem.appendChild(privkey);
+
+ return katElem;
+ }
+
+ private Element kgtElement(KeyGeneratorTestable kgt) {
+ Element kgtElem = doc.createElement("key-pair-generator");
+ kgtElem.setAttribute("algo", kgt.getKpg().getAlgorithm());
+
+ Element keyPair = doc.createElement("key-pair");
+ if (kgt.getKeyPair() != null) {
+ PublicKey pkey = kgt.getKeyPair().getPublic();
+ Element pubkey = pkeyElement(pkey);
+ keyPair.appendChild(pubkey);
+
+ PrivateKey skey = kgt.getKeyPair().getPrivate();
+ Element privkey = skeyElement(skey);
+ keyPair.appendChild(privkey);
+ }
+
+ kgtElem.appendChild(keyPair);
+ return kgtElem;
+ }
+
+ private Element sigElement(SignatureTestable sig) {
+ Element sigElem = doc.createElement("signature");
+ sigElem.setAttribute("verified", sig.getVerified() ? "true" : "false");
+ sigElem.setAttribute("algo", sig.getSig().getAlgorithm());
+
+ Element raw = doc.createElement("raw");
+ raw.setTextContent(ByteUtil.bytesToHex(sig.getSignature()));
+ sigElem.appendChild(raw);
+
+ return sigElem;
+ }
+
+ @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));
+ }
+ return result;
+ }
+
+ @Override
+ protected Element deviceElement(TestSuite suite) {
+ //TODO
+ return null;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java b/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java
new file mode 100644
index 0000000..dfc6813
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java
@@ -0,0 +1,98 @@
+package cz.crcs.ectester.standalone.output;
+
+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.test.KeyAgreementTestable;
+import cz.crcs.ectester.standalone.test.KeyGeneratorTestable;
+import cz.crcs.ectester.standalone.test.SignatureTestable;
+
+import java.io.PrintStream;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class YAMLTestWriter extends BaseYAMLTestWriter {
+ public YAMLTestWriter(PrintStream output) {
+ super(output);
+ }
+
+ private Map<String, Object> keyObject(Key key) {
+ Map<String, Object> kObject = new HashMap<>();
+ if (key == null) {
+ return kObject;
+ }
+ kObject.put("algo", key.getAlgorithm());
+ kObject.put("format", key.getFormat());
+ kObject.put("raw", ByteUtil.bytesToHex(key.getEncoded()));
+ return kObject;
+ }
+
+ private Map<String, Object> kaObject(KeyAgreementTestable kat) {
+ Map<String, Object> katObject = new HashMap<>();
+ katObject.put("algo", kat.getKa().getAlgorithm());
+ katObject.put("secret", ByteUtil.bytesToHex(kat.getSecret()));
+
+ PublicKey pkey = kat.getPublicKey();
+ katObject.put("pubkey", keyObject(pkey));
+
+ PrivateKey skey = kat.getPrivateKey();
+ katObject.put("privkey", keyObject(skey));
+ return katObject;
+ }
+
+ private Map<String, Object> kgtObject(KeyGeneratorTestable kgt) {
+ Map<String, Object> kgtObject = new HashMap<>();
+ kgtObject.put("algo", kgt.getKpg().getAlgorithm());
+
+ Map<String, Object> keypair = new HashMap<>();
+ if (kgt.getKeyPair() != null) {
+ PublicKey pkey = kgt.getKeyPair().getPublic();
+ Map<String, Object> pubObject = keyObject(pkey);
+ keypair.put("pubkey", pubObject);
+
+ PrivateKey skey = kgt.getKeyPair().getPrivate();
+ Map<String, Object> privObject = keyObject(skey);
+ keypair.put("privkey", privObject);
+ }
+
+ kgtObject.put("keypair", keypair);
+ return kgtObject;
+ }
+
+ private Map<String, Object> sigObject(SignatureTestable sig) {
+ Map<String, Object> sigObject = new HashMap<>();
+ sigObject.put("algo", sig.getSig().getAlgorithm());
+ sigObject.put("verified", sig.getVerified());
+ sigObject.put("raw", ByteUtil.bytesToHex(sig.getSignature()));
+ return sigObject;
+ }
+
+ @Override
+ protected Map<String, Object> testableObject(Testable t) {
+ Map<String, Object> 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));
+ }
+ return result;
+ }
+
+ @Override
+ protected Map<String, Object> deviceObject(TestSuite suite) {
+ //TODO
+ return null;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java
new file mode 100644
index 0000000..5f697c4
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java
@@ -0,0 +1,57 @@
+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;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class KeyAgreementTest extends SimpleTest<KeyAgreementTestable> {
+ private KeyAgreementTest(KeyAgreementTestable ka, TestCallback<KeyAgreementTestable> callback) {
+ super(ka, callback);
+ }
+
+ public static KeyAgreementTest match(KeyAgreementTestable ka, byte[] expectedSecret) {
+ return new KeyAgreementTest(ka, new TestCallback<KeyAgreementTestable>() {
+ @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<KeyAgreementTestable>() {
+ @Override
+ public Result apply(KeyAgreementTestable keyAgreementTestable) {
+ return new Result(Result.Value.fromExpected(expected, keyAgreementTestable.ok(), keyAgreementTestable.error()));
+ }
+ });
+ }
+
+ public static KeyAgreementTest function(KeyAgreementTestable ka, TestCallback<KeyAgreementTestable> callback) {
+ return new KeyAgreementTest(ka, callback);
+ }
+
+ @Override
+ 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
new file mode 100644
index 0000000..de9356b
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java
@@ -0,0 +1,124 @@
+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;
+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() throws TestException {
+ 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 = 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 {
+ secret = ka.generateSecret();
+ } catch (IllegalStateException isex) {
+ ok = false;
+ hasRun = true;
+ return;
+ } catch (UnsupportedOperationException uoe) {
+ ok = false;
+ error = true;
+ hasRun = false;
+ return;
+ }
+
+ ok = true;
+ hasRun = true;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java
new file mode 100644
index 0000000..93273ca
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java
@@ -0,0 +1,42 @@
+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
+ */
+public class KeyGeneratorTest extends SimpleTest<KeyGeneratorTestable> {
+ private KeyGeneratorTest(KeyGeneratorTestable kg, TestCallback<KeyGeneratorTestable> callback) {
+ super(kg, callback);
+ }
+
+ public static KeyGeneratorTest expect(KeyGeneratorTestable kg, Result.ExpectedValue expected) {
+ return new KeyGeneratorTest(kg, new TestCallback<KeyGeneratorTestable>() {
+ @Override
+ public Result apply(KeyGeneratorTestable keyGenerationTestable) {
+ return new Result(Result.Value.fromExpected(expected, keyGenerationTestable.ok(), keyGenerationTestable.error()));
+ }
+ });
+ }
+
+ public static KeyGeneratorTest function(KeyGeneratorTestable ka, TestCallback<KeyGeneratorTestable> callback) {
+ return new KeyGeneratorTest(ka, callback);
+ }
+
+ @Override
+ 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
new file mode 100644
index 0000000..3fca168
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java
@@ -0,0 +1,56 @@
+package cz.crcs.ectester.standalone.test;
+
+import cz.crcs.ectester.common.test.BaseTestable;
+import cz.crcs.ectester.common.test.TestException;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.spec.ECParameterSpec;
+
+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() throws TestException {
+ 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();
+ hasRun = true;
+ ok = true;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/test/SignatureTest.java b/src/cz/crcs/ectester/standalone/test/SignatureTest.java
new file mode 100644
index 0000000..9746b91
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/test/SignatureTest.java
@@ -0,0 +1,42 @@
+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
+ */
+public class SignatureTest extends SimpleTest<SignatureTestable> {
+ private SignatureTest(SignatureTestable sig, TestCallback<SignatureTestable> callback) {
+ super(sig, callback);
+ }
+
+ public static SignatureTest expect(SignatureTestable kg, Result.ExpectedValue expected) {
+ return new SignatureTest(kg, new TestCallback<SignatureTestable>() {
+ @Override
+ public Result apply(SignatureTestable signatureTestable) {
+ return new Result(Result.Value.fromExpected(expected, signatureTestable.ok(), signatureTestable.error()));
+ }
+ });
+ }
+
+ public static SignatureTest function(SignatureTestable ka, TestCallback<SignatureTestable> callback) {
+ return new SignatureTest(ka, callback);
+ }
+
+ @Override
+ 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
new file mode 100644
index 0000000..e434337
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/test/SignatureTestable.java
@@ -0,0 +1,107 @@
+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;
+
+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() throws TestException {
+ if (kgt != null) {
+ signKey = (ECPrivateKey) kgt.getKeyPair().getPrivate();
+ verifyKey = (ECPublicKey) kgt.getKeyPair().getPublic();
+ }
+
+ try {
+ sig.initSign(signKey);
+ } catch (InvalidKeyException e) {
+ throw new TestException(e);
+ }
+
+ 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) {
+ throw new TestException(e);
+ }
+
+ 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;
+ hasRun = true;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java b/src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java
new file mode 100644
index 0000000..42d2e54
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java
@@ -0,0 +1,76 @@
+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 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
new file mode 100644
index 0000000..ad404c8
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/test/StandaloneTestSuite.java
@@ -0,0 +1,23 @@
+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.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @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;
+ }
+}
diff --git a/util/plot_dh.py b/util/plot_dh.py
new file mode 100755
index 0000000..2354688
--- /dev/null
+++ b/util/plot_dh.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Script for plotting ECTester ECDH results.
+#
+# Example usage:
+#
+# > java -jar ECTesterReader.jar -dh 10000 -b 192 -fp -o dh.csv
+# ...
+# > ./plot_dh.py dh.csv
+# ...
+#
+
+import numpy as np
+import matplotlib.pyplot as plt
+import matplotlib.ticker as ticker
+import argparse
+from operator import itemgetter
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Plot ECTester ECDH timing.")
+ parser.add_argument("-o", "--output", dest="output", type=argparse.FileType("wb"), help="Write image to [file], do not display.", metavar="file")
+ parser.add_argument("--skip-first", dest="skip_first", action="store_true", help="Skip first entry, as it's usually a large outlier.")
+ parser.add_argument("file", type=str, help="The file to plot(csv).")
+
+ opts = parser.parse_args()
+
+ with open(opts.file, "r") as f:
+ header = f.readline()
+ header_names = header.split(";")
+
+ hx = lambda x: int(x, 16)
+ data = np.genfromtxt(opts.file, delimiter=";", skip_header=1, converters={2: hx, 3: hx, 4: hx}, dtype=np.dtype([("index","u4"), ("time","u4"), ("pub", "O"), ("priv", "O"), ("secret","O")]))
+ if opts.skip_first:
+ data = data[1:]
+
+ if "nano" in header_names[1]:
+ unit = r"$\mu s$"
+ time_data = map(lambda x: x[1]/1000, data)
+ else:
+ unit = r"ms"
+ time_data = map(itemgetter(1), data)
+ priv_data = map(itemgetter(2), data)
+ pub_data = map(itemgetter(3), data)
+ secret_data = map(itemgetter(4), data)
+
+ plt.style.use("ggplot")
+ fig = plt.figure(tight_layout=True)
+ fig.suptitle(opts.file)
+
+ axe_hist = fig.add_subplot(1,1,1)
+ time_max = max(time_data)
+ time_avg = np.average(time_data)
+ time_median = np.median(time_data)
+ axe_hist.hist(time_data, bins=time_max/3, log=True)
+ axe_hist.axvline(x=time_avg, alpha=0.7, linestyle="dotted", color="red", label="avg = {}".format(time_avg))
+ axe_hist.axvline(x=time_median, alpha=0.7, linestyle="dotted", color="green", label="median = {}".format(time_median))
+ axe_hist.set_ylabel("count\n(log)")
+ axe_hist.set_xlabel("time ({})".format(unit))
+ axe_hist.xaxis.set_major_locator(ticker.MaxNLocator())
+ axe_hist.legend(loc="best")
+
+ fig.text(0.01, 0.02, "Data size: {}".format(len(time_data)), size="small")
+
+ if opts.output is None:
+ plt.show()
+ else:
+ fig.set_size_inches(12, 10)
+ plt.savefig(opts.output, dpi=400)
diff --git a/util/plot_gen.py b/util/plot_gen.py
new file mode 100755
index 0000000..12f7089
--- /dev/null
+++ b/util/plot_gen.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Script for plotting ECTester key generation results.
+#
+# Example usage:
+#
+# > java -jar ECTesterReader.jar -g 10000 -b 192 -fp -o gen.csv
+# ...
+# > ./plot_gen.py gen.csv
+# ...
+#
+
+import numpy as np
+import matplotlib.pyplot as plt
+import matplotlib.ticker as ticker
+from operator import itemgetter
+import argparse
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Plot results of ECTester key generation timing.")
+ parser.add_argument("-o", "--output", dest="output", type=argparse.FileType("wb"), help="Write image to [file], do not display.", metavar="file")
+ parser.add_argument("--pub", dest="pub", action="store_true", help="Show public key scatter plot.")
+ parser.add_argument("--priv", dest="priv", action="store_true", help="Show private key scatter plot.")
+ parser.add_argument("--hist", dest="hist", action="store_true", help="Show histogram.")
+ parser.add_argument("--skip-first", dest="skip_first", action="store_true", help="Skip first entry, as it's usually a large outlier.")
+ parser.add_argument("file", type=str, help="The file to plot(csv).")
+
+ opts = parser.parse_args()
+
+ with open(opts.file, "r") as f:
+ header = f.readline()
+ header_names = header.split(";")
+
+ plots = [opts.priv, opts.pub, opts.hist]
+ n_plots = sum(plots)
+ if n_plots == 0:
+ n_plots = 3
+ plots = [True, True, True]
+
+ hx = lambda x: int(x, 16)
+ data = np.genfromtxt(opts.file, delimiter=";", skip_header=1, converters={2: hx, 3: hx}, dtype=np.dtype([("index","u4"), ("time","u4"), ("pub", "O"), ("priv", "O")]))
+ if opts.skip_first:
+ data = data[1:]
+
+ if "nano" in header_names[1]:
+ unit = r"$\mu s$"
+ time_data = map(lambda x: x[1]/1000, data)
+ else:
+ unit = r"ms"
+ time_data = map(itemgetter(1), data)
+ priv_data = map(itemgetter(2), data)
+ pub_data = map(itemgetter(3), data)
+
+ plt.style.use("ggplot")
+ fig = plt.figure(tight_layout=True)
+ fig.suptitle(opts.file)
+
+ plot_i = 1
+ if plots[0]:
+ axe_private = fig.add_subplot(n_plots, 1, plot_i)
+ axe_private.scatter(time_data, priv_data, marker="x", s=10)
+ axe_private.set_ylabel("private key value\n(big endian)")
+ axe_private.set_xlabel("time ({})".format(unit))
+ plot_i += 1
+
+ if plots[1]:
+ axe_public = fig.add_subplot(n_plots, 1, plot_i)
+ axe_public.scatter(time_data, pub_data, marker="x", s=10)
+ axe_public.set_ylabel("public key value\n(big endian)")
+ axe_public.set_xlabel("time ({})".format(unit))
+ plot_i += 1
+
+ if plots[2]:
+ axe_hist = fig.add_subplot(n_plots, 1, plot_i)
+ time_max = max(time_data)
+ time_avg = np.average(time_data)
+ time_median = np.median(time_data)
+ axe_hist.hist(time_data, bins=time_max/3, log=True)
+ axe_hist.axvline(x=time_avg, alpha=0.7, linestyle="dotted", color="red", label="avg = {}".format(time_avg))
+ axe_hist.axvline(x=time_median, alpha=0.7, linestyle="dotted", color="green", label="median = {}".format(time_median))
+ axe_hist.set_ylabel("count\n(log)")
+ axe_hist.set_xlabel("time ({})".format(unit))
+ axe_hist.xaxis.set_major_locator(ticker.MaxNLocator())
+ axe_hist.legend(loc="best")
+
+ fig.text(0.01, 0.02, "Data size: {}".format(len(time_data)), size="small")
+
+ if opts.output is None:
+ plt.show()
+ else:
+ fig.set_size_inches(12, 10)
+ plt.savefig(opts.output, dpi=400)