diff --git a/!uploader/ectester.cap b/!uploader/ectester.cap deleted file mode 100644 index b8839653..00000000 Binary files a/!uploader/ectester.cap and /dev/null differ diff --git a/!uploader/simpleECC_NXP_JCOP_CJ2A081.txt b/!uploader/simpleECC_NXP_JCOP_CJ2A081.txt deleted file mode 100644 index bec8ef71..00000000 --- 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 81395114..00000000 --- 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 eb6ab5f1..00000000 --- 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 acb4c4da..00000000 --- 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 09d967aa..00000000 --- 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 00000000..1953275d --- /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 3959c4d5..62681d6b 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 a8fc8514..21ecc94d 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 5096bd3b..6184b846 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 Print the list of supported named - curves and keys. -dsa,--ecdsa Sign data with ECDSA, [count] times. - -t,--test Test ECC support. - -dh,--ecdh Do ECDH, [count] times. + -t,--test Test ECC support. [test_suite]: + - default: + - invalid: + - wrong: + - composite: + - test-vectors: + -dh,--ecdh Do EC KeyAgreement (ECDH...), [count] + times. -e,--export Export the defaut curve parameters of the card(if any). - -g,--generate Generate [amount] of EC keys. + -V,--version Print version info. + -ln,--list-named Print the list of supported named + curves and keys. -h,--help Print help. - -dhc,--ecdhc Do ECDHC, [count] times. + -a,--all Test all curve sizes. -b,--bit-size Set curve size. + -fp,--prime-field Use a prime field. -f2m,--binary-field Use a binary field. + -c,--curve Use curve from file (field,a,b,gx,gy,r,k). -nc,--named-curve Use a named curve, from CurveDB: @@ -58,20 +70,25 @@ See `java -jar ECTester.jar -h` for more. -k,--key Use keyPair from file  (wx,wy,s). -nk,--named-key Use keyPair from KeyDB: + -i,--input Input from file , for ECDSA signing. -o,--output Output into file . -l,--log Log output into file [log_file]. -v,--verbose Turn on verbose logging. - --format Output format to use. + --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 Set KeyAgreement object [type], corresponds to JC.KeyAgreement - constants. + constants. + -sig,--sig-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 ] [-n ] [-b ] [-nc ]) | +(ecdsa [-t ] [-n ] [-b ] [-nc ] [-f ]) | +(export [-t ] [-b ]) | (generate [-nc ] [-n ] [-t +] [-b ]) | (list-data [what]) | (list-libs) | (test [-gt ] +[-kt ] [-st ] [-b ] [-nc ]) ] [lib] + + -V,--version Print version info. + -h,--help Print help. + [lib] What library to use. + + ecdh: + -t,--type Set KeyAgreement object [type]. + -n,--amount Do ECDH [amount] times. + -b,--bits What size of curve to use. + -nc,--named-curve Use a named curve, from CurveDB: + + ecdsa: + -t,--type Set Signature object [type]. + -n,--amount Do ECDSA [amount] times. + -b,--bits What size of curve to use. + -nc,--named-curve Use a named curve, from CurveDB: + -f,--file Input [file] to sign. + + export: + -t,--type Set KeyPair object [type]. + -b,--bits What size of curve to use. + + generate: + -nc,--named-curve Use a named curve, from CurveDB: + -n,--amount Generate [amount] of EC keys. + -t,--type Set KeyPairGenerator object [type]. + -b,--bits What size of curve to use. + + list-data: + [what] what to list. + + list-libs: + + test: + -gt,--kpg-type Set the KeyPairGenerator object [type]. + -kt,--ka-type Set the KeyAgreement object [type]. + -st,--sig-type Set the Signature object [type]. + -b,--bits What size of curve to use. + -nc,--named-curve Use a named curve, from CurveDB: + +``` \ No newline at end of file diff --git a/!uploader/GPPcScConnectionPlugin.dll b/applet/GPPcScConnectionPlugin.dll similarity index 100% rename from !uploader/GPPcScConnectionPlugin.dll rename to applet/GPPcScConnectionPlugin.dll diff --git a/!uploader/GPShell.exe b/applet/GPShell.exe similarity index 100% rename from !uploader/GPShell.exe rename to applet/GPShell.exe diff --git a/!uploader/GlobalPlatform.dll b/applet/GlobalPlatform.dll similarity index 100% rename from !uploader/GlobalPlatform.dll rename to applet/GlobalPlatform.dll diff --git a/!uploader/gp.exe b/applet/gp.exe similarity index 100% rename from !uploader/gp.exe rename to applet/gp.exe diff --git a/!uploader/gp.jar b/applet/gp.jar similarity index 100% rename from !uploader/gp.jar rename to applet/gp.jar diff --git a/!uploader/gppro_upload.bat b/applet/gppro_upload.bat similarity index 100% rename from !uploader/gppro_upload.bat rename to applet/gppro_upload.bat diff --git a/!uploader/gppro_upload.sh b/applet/gppro_upload.sh similarity index 100% rename from !uploader/gppro_upload.sh rename to applet/gppro_upload.sh diff --git a/!uploader/gppro_upload_emv.bat b/applet/gppro_upload_emv.bat similarity index 100% rename from !uploader/gppro_upload_emv.bat rename to applet/gppro_upload_emv.bat diff --git a/!uploader/gppro_upload_emv.sh b/applet/gppro_upload_emv.sh similarity index 100% rename from !uploader/gppro_upload_emv.sh rename to applet/gppro_upload_emv.sh diff --git a/!uploader/libeay32.dll b/applet/libeay32.dll similarity index 100% rename from !uploader/libeay32.dll rename to applet/libeay32.dll diff --git a/!uploader/openkms-gp.jar b/applet/openkms-gp.jar similarity index 100% rename from !uploader/openkms-gp.jar rename to applet/openkms-gp.jar diff --git a/!uploader/ssleay32.dll b/applet/ssleay32.dll similarity index 100% rename from !uploader/ssleay32.dll rename to applet/ssleay32.dll diff --git a/!uploader/zlib1.dll b/applet/zlib1.dll similarity index 100% rename from !uploader/zlib1.dll rename to applet/zlib1.dll diff --git a/build-applet.xml b/build-applet.xml new file mode 100644 index 00000000..9d7d4d6e --- /dev/null +++ b/build-applet.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.xml b/build-reader.xml similarity index 59% rename from build.xml rename to build-reader.xml index 3d778f38..11d61453 100644 --- a/build.xml +++ b/build-reader.xml @@ -7,9 +7,10 @@ - - Builds, tests, and runs the project ECTester. - + + Builds, tests, and runs the project ECTesterReader. + + - + + - - + + + diff --git a/build-standalone.xml b/build-standalone.xml new file mode 100644 index 00000000..dcfb1f36 --- /dev/null +++ b/build-standalone.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + Builds, tests, and runs the project ECTesterStandalone. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dist/README.TXT b/dist/README.TXT index 5d6fa172..64c76a6d 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 d1749dfb..4a80d49b 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 b68db399..849a62c3 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 00000000..4fac57b5 --- /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 21298dc6..c4f38dcf 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 793060c1..00000000 --- a/jcbuild.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/bcprov-jdk15on-1.58.jar b/lib/bcprov-jdk15on-1.58.jar new file mode 100644 index 00000000..dae02cbc Binary files /dev/null and b/lib/bcprov-jdk15on-1.58.jar differ diff --git a/nbproject/copylibstask.jar b/nbproject/copylibstask.jar index ad1d2ac6..45fdbe13 100644 Binary files a/nbproject/copylibstask.jar and b/nbproject/copylibstask.jar differ diff --git a/nbproject/dist-build.xml b/nbproject/dist-build.xml new file mode 100644 index 00000000..b980e2d7 --- /dev/null +++ b/nbproject/dist-build.xml @@ -0,0 +1,34 @@ + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nbproject/build-impl.xml b/nbproject/reader/build-impl.xml similarity index 99% rename from nbproject/build-impl.xml rename to nbproject/reader/build-impl.xml index 3b01c7f1..f7c43a29 100644 --- a/nbproject/build-impl.xml +++ b/nbproject/reader/build-impl.xml @@ -19,7 +19,7 @@ is divided into following sections: - cleanup --> - + @@ -51,7 +51,7 @@ is divided into following sections: - + diff --git a/manifest.mf b/nbproject/reader/manifest.mf similarity index 69% rename from manifest.mf rename to nbproject/reader/manifest.mf index 2cb1a50e..cbfea93d 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 similarity index 87% rename from nbproject/project.properties rename to nbproject/reader/project.properties index 152dc9c4..69db5235 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 similarity index 92% rename from nbproject/project.xml rename to nbproject/reader/project.xml index 6e5a48eb..aebe2175 100644 --- a/nbproject/project.xml +++ b/nbproject/reader/project.xml @@ -3,7 +3,7 @@ org.netbeans.modules.java.j2seproject - ECTester + ECTesterReader diff --git a/nbproject/standalone/build-impl.xml b/nbproject/standalone/build-impl.xml new file mode 100644 index 00000000..a1f91c2c --- /dev/null +++ b/nbproject/standalone/build-impl.xml @@ -0,0 +1,1413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/standalone/manifest.mf b/nbproject/standalone/manifest.mf new file mode 100644 index 00000000..02f1e3e0 --- /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 00000000..9fed4c25 --- /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 00000000..2f2fb3f6 --- /dev/null +++ b/nbproject/standalone/project.xml @@ -0,0 +1,15 @@ + + + org.netbeans.modules.java.j2seproject + + + ECTesterStandalone + + + + + + + + + diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java index 0c20333c..b026cfe5 100644 --- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java +++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java @@ -201,13 +201,13 @@ public short setParameter(KeyPair keypair, byte key, short param, byte[] data, s 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 0b3c1e0a..36515efa 100644 --- a/src/cz/crcs/ectester/applet/ECKeyTester.java +++ b/src/cz/crcs/ectester/applet/ECKeyTester.java @@ -3,7 +3,6 @@ import javacard.framework.CardRuntimeException; import javacard.framework.ISO7816; -import javacard.framework.ISOException; import javacard.security.*; /** @@ -13,77 +12,35 @@ * @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 @@ private short testKA_direct(KeyAgreement ka, KeyPair privatePair, byte[] pubkey, * @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 short testECDSA(ECPrivateKey signKey, ECPublicKey verifyKey, byte[] input 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 ecf97f2e..20e3f055 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 @@ protected ECTesterApplet(byte[] buffer, short offset, byte length) { 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 void process(APDU apdu) throws ISOException { 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 void process(APDU apdu) throws ISOException { 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 void process(APDU apdu) throws ISOException { 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 void process(APDU apdu) throws ISOException { 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 @@ private short insECDH(APDU apdu) { } /** + * 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 @@ private short insECDH_direct(APDU apdu) { * * @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 @@ private short insECDSA(APDU apdu) { 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; @@ -479,19 +466,6 @@ private short insCleanup(APDU apdu) { return cleanup(apdubuf, (short) 0); } - /** - * 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 @@ -623,7 +597,7 @@ private short export(KeyPair keyPair, byte key, short params, byte[] outBuffer, * @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 @@ private short ecdh(byte pubkey, byte privkey, byte export, short corruption, byt 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 @@ private short ecdh_direct(byte privkey, byte export, short corruption, byte type 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 @@ private short ecdh_direct(byte privkey, byte export, short corruption, byte type /** * @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 @@ private short ecdh_direct(byte privkey, byte export, short corruption, byte type * @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 @@ private short ecdsa(KeyPair sign, byte export, byte[] inBuffer, short inOffset, 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 @@ private short cleanup(byte[] buffer, short offset) { 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 04cd55ef..4581fd6e 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 00000000..e9b66885 --- /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 00000000..91f121f4 --- /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 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 00000000..ee2097e0 --- /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 arguments; + + public ParserOptions(CommandLineParser parser, Options options) { + this.parser = parser; + this.options = options; + } + + public ParserOptions(CommandLineParser parser, Options options, List arguments) { + this(parser, options); + this.arguments = arguments; + } + + public CommandLineParser getParser() { + return parser; + } + + public Options getOptions() { + return options; + } + + public List 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 00000000..6a044d2b --- /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 getOption(String opt, BiFunction 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