diff options
34 files changed, 435 insertions, 170 deletions
diff --git a/!uploader/ectester.cap b/!uploader/ectester.cap Binary files differindex 6a16aa8..96d0c82 100644 --- a/!uploader/ectester.cap +++ b/!uploader/ectester.cap diff --git a/CURVES.md b/CURVES.md new file mode 100644 index 0000000..d1749df --- /dev/null +++ b/CURVES.md @@ -0,0 +1,15 @@ +# Curves + +## anomalous + +## Brainpool + +## invalid + +## NIST + +## nonprime + +## SECG + +## wrong diff --git a/FORMAT.md b/FORMAT.md new file mode 100644 index 0000000..a753c75 --- /dev/null +++ b/FORMAT.md @@ -0,0 +1,36 @@ +# Format +CSV based, little-endian hexadecimal values. + +## Curves +### Prime field +`p,a,b,gx,gy,n,h` + + +### Binary field +`m,e1,e2,e3,a,b,gx,gy,n,h` + +## Key material +### Keypair +`wx,wy,s` + +### Public key +`wx,wy` + +### Private key +`s` + +# Notation + - `p` - prime F_p + - `m` - binary field exponent F_2^m + - e1 - largest exponent of the field polynomial + - e2 - middle exponenet of the field polynomial, or `0000` if field poly is a trinomial + - e3 - smallest exponent (except zero) of the field polynomial, or `0000` if field poly is a trinomial + - `a` - a parameter in short Weierstrass curve equation + - `b` - b parameter in short Weierstrass curve equation + - `gx` - x coordinate of the curve base-point g + - `gy` - y coordinate of the curve base-point g + - `n` - the base-point order + - `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 @@ -16,7 +16,7 @@ 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 ECTester.jar -h` for more. ### Options @@ -61,6 +61,55 @@ See `java -jar ectester.jar -h` for more. of using a terminal. ``` +### Actions + +#### Export +`-e / --export` + +Exports the default curves (if any) that are preset on the card. +Use with `-o / --output [out_file]` to output the curve parameters to a file. +For format of this file see [FORMAT](FORMAT.md). + +#### Test +`-t / --test [test_suite]` + +Perform support and performance tests of ECC. + +For more info about the test suites see [TESTS](TESTS.md). + +#### Generate +`-g / --generate [amount]` + +Generates batches of EC keypairs and exports them. +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. + +#### ECDSA +`-dsa / --ecdsa [count]` + +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. + +#### List named curves +`-ln / --list-named []` + +Lists categories of curves, keys and keypairs embedded in ECTester's jar, along with some information about them. +These can be used as arguments to the `-n[c|k|pub|priv] / --named-[curve|key|public|private]` parameters. + +With the format: `category/name`. + +For example: +`secg/secp192r1` identifies the SECG 192 bit prime field curve known as `secp192r1`. + +For more info about the curves see [CURVES](CURVES.md). + ### Example diff --git a/TESTS.md b/TESTS.md new file mode 100644 index 0000000..710a04b --- /dev/null +++ b/TESTS.md @@ -0,0 +1,82 @@ +# Tests + + - `default` + - `test-vectors` + - `wrong` + - `nonprime` + - `invalid` + +**NOTE: The `wrong`, `nonprime` and `invalid` test suites caused temporary DoS of some cards. These test suites prompt you for +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. + +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. + +## Test-Vectors +Tests using known test vectors provided by NIST/SECG/Brainpool: + +[SECG - GEC2](http://read.pudn.com/downloads168/doc/772358/TestVectorsforSEC%201-gec2.pdf) + +[NIST - ECCDH](http://csrc.nist.gov/groups/STM/cavp/component-testing.html#ECCCDH) + +[Brainpool - RFC6931](https://tools.ietf.org/html/rfc6932#appendix-A.1) + +[Brainpool - RFC7027](https://tools.ietf.org/html/rfc7027#appendix-A) + +For example: +```bash +java -jar ECTester.jar -t test-vectors -nc nist -a -f2m +``` +tests all(`-a`), binary field(`-f2m`) NIST curves for which test-vectors are provided. Although this test suite is better for general testing: +```bash +java -jar ECTester.jar -t test-vectors -a +``` +## Wrong +Tests using the default tests on a category of wrong curves. These curves are not really curves as they have: + - non-prime field in the prime-field case + - reducible polynomial as the field polynomial in the binary case + +These tests should fail generally. They are equivalent with `java -jar ECTester.jar -nc wrong -t`, the default tests over the `wrong` category +of curves. + +For example: +```bash +java -jar ECTester.jar -t wrong -b 521 -fp +``` +tests a 521 bit(`-b`), prime-field(`-fp`) wrong curve. + +## Nonprime +Tests using curves that don't have a prime order/nearly prime order. +These tests should generally fail, a success here implies the card **WILL** use a non-secure curve if such curve is set +by the applet. Operations over such curves are susceptible to small-subgroup attacks. + +For example: +```bash +java -jar ECTester.jar -t nonprime -b 160 -fp +``` + +## Invalid +Tests using known named curves from several categories(SECG/NIST/Brainpool) against pregenerated *invalid* public keys. +These tests should definitely fail, a success here implies the card is susceptible to invalid curve attacks. + + +For example: +```bash +java -jar ECTester.jar -t invalid -nc nist -a -fp +``` +tests using all(`-a`), prime-field(`-fp`) NIST curves and pregenerated *invalid* public keys for these curves. + +**TODO: CURRENTLY NOT IMPLEMENTED**
\ No newline at end of file diff --git a/dist/ECTester.jar b/dist/ECTester.jar Binary files differindex ffe19d1..a256495 100644 --- a/dist/ECTester.jar +++ b/dist/ECTester.jar diff --git a/src/cz/crcs/ectester/applet/ECKeyTester.java b/src/cz/crcs/ectester/applet/ECKeyTester.java index 7ef6150..e22094b 100644 --- a/src/cz/crcs/ectester/applet/ECKeyTester.java +++ b/src/cz/crcs/ectester/applet/ECKeyTester.java @@ -148,6 +148,18 @@ public class ECKeyTester { return ecdsaSignature; } + public boolean hasECDH() { + return ecdhKeyAgreement != null; + } + + public boolean hasECDHC() { + return ecdhcKeyAgreement != null; + } + + public boolean hasECDSA() { + return ecdsaSignature != null; + } + public short getSW() { return sw; } diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index e17d102..f9fb5da 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -52,6 +52,7 @@ public class ECTesterApplet extends Applet { public static final byte INS_ECDH = (byte) 0x60; public static final byte INS_ECDSA = (byte) 0x61; public static final byte INS_CLEANUP = (byte) 0x62; + public static final byte INS_SUPPORT = (byte) 0x63; // PARAMETERS for P1 and P2 public static final byte KEYPAIR_LOCAL = (byte) 0x01; @@ -74,10 +75,13 @@ public class ECTesterApplet extends Applet { private RandomData randomData = null; - private KeyPair localKeypair = null; - private KeyPair remoteKeypair = 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; protected ECTesterApplet(byte[] buffer, short offset, byte length) { if (length > 9) { @@ -102,9 +106,9 @@ public class ECTesterApplet extends Applet { keyGenerator = new ECKeyGenerator(); keyTester = new ECKeyTester(); - keyTester.allocateECDH(); - keyTester.allocateECDHC(); - keyTester.allocateECDSA(); + ecdhSW = keyTester.allocateECDH(); + ecdhcSW = keyTester.allocateECDHC(); + ecdsaSW = keyTester.allocateECDSA(); } register(); } @@ -152,6 +156,9 @@ public class ECTesterApplet extends Applet { case INS_CLEANUP: insCleanup(apdu); break; + case INS_SUPPORT: + insSupport(apdu); + break; default: // The INS code is not supported by the dispatcher ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); @@ -375,6 +382,7 @@ public class ECTesterApplet extends Applet { /** * + * @param apdu */ private void insCleanup(APDU apdu) { apdu.setIncomingAndReceive(); @@ -386,6 +394,19 @@ public class ECTesterApplet extends Applet { } /** + * + * @param apdu + */ + private void insSupport(APDU apdu) { + apdu.setIncomingAndReceive(); + byte[] apdubuf = apdu.getBuffer(); + + short len = support(apdubuf, (short) 0); + + apdu.setOutgoingAndSend((short) 0, len); + } + + /** * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...) * @param keyLength key length to set * @param keyClass key class to allocate @@ -606,4 +627,19 @@ public class ECTesterApplet extends Applet { Util.setShort(buffer, offset, sw); return 2; } + + /** + * + * @param buffer + * @param offset + * @return + */ + private short support(byte[] buffer, short offset) { + + Util.setShort(buffer, offset, ecdhSW); + Util.setShort(buffer, (short) (offset+2), ecdhcSW); + Util.setShort(buffer, (short) (offset+4), ecdsaSW); + + return 6; + } } diff --git a/src/cz/crcs/ectester/data/anomalous/curves.xml b/src/cz/crcs/ectester/data/anomalous/curves.xml index c478657..b0b9b02 100644 --- a/src/cz/crcs/ectester/data/anomalous/curves.xml +++ b/src/cz/crcs/ectester/data/anomalous/curves.xml @@ -1,48 +1,32 @@ <?xml version="1.0" encoding="UTF-8" ?> <curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../schema.xsd"> - <!-- - <curve> - <id>anomalousp128</id> - <bits>128</bits> - <field>prime</field> - <file>anomalousp128.csv</file> - </curve> - <curve> - <id>anomalousp160</id> - <bits>160</bits> - <field>prime</field> - <file>anomalousp160.csv</file> - </curve> - <curve> - <id>anomalousp192</id> - <bits>192</bits> - <field>prime</field> - <file>anomalousp192.csv</file> - </curve> - <curve> - <id>anomalousp224</id> - <bits>224</bits> - <field>prime</field> - <file>anomalousp224.csv</file> - </curve> - <curve> - <id>anomalousp256</id> - <bits>256</bits> - <field>prime</field> - <file>anomalousp256.csv</file> - </curve> - <curve> - <id>anomalousp384</id> - <bits>384</bits> - <field>prime</field> - <file>anomalousp384.csv</file> - </curve> - <curve> - <id>anomalousp521</id> - <bits>521</bits> - <field>prime</field> - <file>anomalousp521.csv</file> - </curve> - --> -</curves>
\ No newline at end of file + <curve> + <id>miyaji128a1</id> + <bits>128</bits> + <field>prime</field> + <file>miyaji128a1.csv</file> + <desc>First curve in the "Proposed scheme A" section of Atsuko Miyaji's paper.</desc> + </curve> + <curve> + <id>miyaji128a2</id> + <bits>128</bits> + <field>prime</field> + <file>miyaji128a2.csv</file> + <desc>Second curve in the "Proposed scheme A" section of Atsuko Miyaji's paper.</desc> + </curve> + <curve> + <id>miyaji128b1</id> + <bits>128</bits> + <field>prime</field> + <file>miyaji128b1.csv</file> + <desc>First curve in the "Proposed scheme B" section of Atsuko Miyaji's paper.</desc> + </curve> + <curve> + <id>miyaji128b2</id> + <bits>128</bits> + <field>prime</field> + <file>miyaji128b2.csv</file> + <desc>Second curve in the "Proposed scheme B" section of Atsuko Miyaji's paper.</desc> + </curve> +</curves> diff --git a/src/cz/crcs/ectester/data/anomalous/miyaji128a1.csv b/src/cz/crcs/ectester/data/anomalous/miyaji128a1.csv new file mode 100644 index 0000000..b1a84a0 --- /dev/null +++ b/src/cz/crcs/ectester/data/anomalous/miyaji128a1.csv @@ -0,0 +1 @@ +80000000000001a86a91e9356e5fee11,1210cb7f8a3466b805b546960dd43f69,644a5a3e53a634ee06fa903172806914,55b40a8932013efa328cbe8abaf2f4ec,44375dc6a29cac1982fbf98c86da2707,80000000000001a86a91e9356e5fee11,1 diff --git a/src/cz/crcs/ectester/data/anomalous/miyaji128a2.csv b/src/cz/crcs/ectester/data/anomalous/miyaji128a2.csv new file mode 100644 index 0000000..70098c0 --- /dev/null +++ b/src/cz/crcs/ectester/data/anomalous/miyaji128a2.csv @@ -0,0 +1 @@ +fffffffffffffe1c2758f379fd46b0d9,5e2336fa13c5c6ce7add23893c0dfec7,7bf26de6e350dc183c58c09ad8237e00,1d8b7c787fdc92d299ec14e7916e5f7d,67621e61f115a2544364c1cd52e3cfa7,fffffffffffffe1c2758f379fd46b0d9,1 diff --git a/src/cz/crcs/ectester/data/anomalous/miyaji128b1.csv b/src/cz/crcs/ectester/data/anomalous/miyaji128b1.csv new file mode 100644 index 0000000..5c1f8b8 --- /dev/null +++ b/src/cz/crcs/ectester/data/anomalous/miyaji128b1.csv @@ -0,0 +1 @@ +800000000000037554ac874c19cdaedf,00000000000000000000000000000000,000000000000000000000000000000c0,635217788a2ff48664a09cb3cdf72b2e,5e69c2309032ef3cb1e41b1a245822be,800000000000037554ac874c19cdaedf,1 diff --git a/src/cz/crcs/ectester/data/anomalous/miyaji128b2.csv b/src/cz/crcs/ectester/data/anomalous/miyaji128b2.csv new file mode 100644 index 0000000..fdb77a0 --- /dev/null +++ b/src/cz/crcs/ectester/data/anomalous/miyaji128b2.csv @@ -0,0 +1 @@ +fffffffffffffe2a71fec762d2427ce7,00000000000000000000000000000000,000000000000000000000000000000c0,428e6765064e4a745b2aaae87ef7f0f7,3daee1541c98c3d51eec13a1f6177531,fffffffffffffe2a71fec762d2427ce7,1 diff --git a/src/cz/crcs/ectester/data/categories.xml b/src/cz/crcs/ectester/data/categories.xml index d0c9f39..100d962 100644 --- a/src/cz/crcs/ectester/data/categories.xml +++ b/src/cz/crcs/ectester/data/categories.xml @@ -22,9 +22,9 @@ <desc>SEC 2: Recommended Elliptic Curve Domain Parameters version 2.0 January 27, 2010</desc> </category> <category> - <name>smallpub</name> - <directory>smallpub</directory> - <desc>Non-prime order curves, with points of very small order pregenerated. Useful for testing in ECDH.</desc> + <name>nonprime</name> + <directory>nonprime</directory> + <desc>Non-prime order curves, with points of very small order pregenerated.</desc> </category> <category> <name>wrong</name> diff --git a/src/cz/crcs/ectester/data/smallpub/curves.xml b/src/cz/crcs/ectester/data/nonprime/curves.xml index 50c1d0c..e0eb78a 100644 --- a/src/cz/crcs/ectester/data/smallpub/curves.xml +++ b/src/cz/crcs/ectester/data/nonprime/curves.xml @@ -2,45 +2,45 @@ <curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../schema.xsd"> <curve> - <id>ecsp128</id> + <id>nonprime128</id> <bits>128</bits> <field>prime</field> - <file>ecsp128.csv</file> + <file>nonprime128.csv</file> </curve> <curve> - <id>ecsp160</id> + <id>nonprime160</id> <bits>160</bits> <field>prime</field> - <file>ecsp160.csv</file> + <file>nonprime160.csv</file> </curve> <curve> - <id>ecsp192</id> + <id>nonprime192</id> <bits>192</bits> <field>prime</field> - <file>ecsp192.csv</file> + <file>nonprime192.csv</file> </curve> <curve> - <id>ecsp224</id> + <id>nonprime224</id> <bits>224</bits> <field>prime</field> - <file>ecsp224.csv</file> + <file>nonprime224.csv</file> </curve> <curve> - <id>ecsp256</id> + <id>nonprime256</id> <bits>256</bits> <field>prime</field> - <file>ecsp256.csv</file> + <file>nonprime256.csv</file> </curve> <curve> - <id>ecsp384</id> + <id>nonprime384</id> <bits>384</bits> <field>prime</field> - <file>ecsp384.csv</file> + <file>nonprime384.csv</file> </curve> <curve> - <id>ecsp521</id> + <id>nonprime521</id> <bits>521</bits> <field>prime</field> - <file>ecsp521.csv</file> + <file>nonprime521.csv</file> </curve> </curves>
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/nonprime/keys.xml b/src/cz/crcs/ectester/data/nonprime/keys.xml new file mode 100644 index 0000000..c10ae65 --- /dev/null +++ b/src/cz/crcs/ectester/data/nonprime/keys.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8" ?> +<keys xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../schema.xsd" + category="nonprime" + desc="Points on the non-prime curves, very small point orders(3-5)."> + <pubkey> + <id>nonprime128-pub</id> + <file>nonprime128_pub.csv</file> + <curve>nonprime/nonprime128</curve> + <desc>order = 5</desc> + </pubkey> + <pubkey> + <id>nonprime160-pub</id> + <file>nonprime160_pub.csv</file> + <curve>nonprime/nonprime160</curve> + <desc>order = 3</desc> + </pubkey> + <pubkey> + <id>nonprime192-pub</id> + <file>nonprime192_pub.csv</file> + <curve>nonprime/nonprime192</curve> + <desc>order = 3</desc> + </pubkey> + <pubkey> + <id>nonprime224-pub</id> + <file>nonprime224_pub.csv</file> + <curve>nonprime/nonprime224</curve> + <desc>order = 5</desc> + </pubkey> + <pubkey> + <id>nonprime256-pub</id> + <file>nonprime256_pub.csv</file> + <curve>nonprime/nonprime256</curve> + <desc>order = 3</desc> + </pubkey> + <pubkey> + <id>nonprime384-pub</id> + <file>nonprime384_pub.csv</file> + <curve>nonprime/nonprime384</curve> + <desc>order = 3</desc> + </pubkey> + <pubkey> + <id>nonprime521-pub</id> + <file>nonprime521_pub.csv</file> + <curve>nonprime/nonprime521</curve> + <desc>order = 5</desc> + </pubkey> +</keys>
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp128.csv b/src/cz/crcs/ectester/data/nonprime/nonprime128.csv index f541010..f541010 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp128.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime128.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp128_pub.csv b/src/cz/crcs/ectester/data/nonprime/nonprime128_pub.csv index 78a8cb4..78a8cb4 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp128_pub.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime128_pub.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp160.csv b/src/cz/crcs/ectester/data/nonprime/nonprime160.csv index e556020..e556020 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp160.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime160.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp160_pub.csv b/src/cz/crcs/ectester/data/nonprime/nonprime160_pub.csv index 7b92733..7b92733 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp160_pub.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime160_pub.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp192.csv b/src/cz/crcs/ectester/data/nonprime/nonprime192.csv index bc55089..bc55089 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp192.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime192.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp192_pub.csv b/src/cz/crcs/ectester/data/nonprime/nonprime192_pub.csv index 5432c1d..5432c1d 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp192_pub.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime192_pub.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp224.csv b/src/cz/crcs/ectester/data/nonprime/nonprime224.csv index 09b9c01..09b9c01 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp224.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime224.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp224_pub.csv b/src/cz/crcs/ectester/data/nonprime/nonprime224_pub.csv index 319ca3a..319ca3a 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp224_pub.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime224_pub.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp256.csv b/src/cz/crcs/ectester/data/nonprime/nonprime256.csv index d5bf3c0..d5bf3c0 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp256.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime256.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp256_pub.csv b/src/cz/crcs/ectester/data/nonprime/nonprime256_pub.csv index d27ffdc..d27ffdc 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp256_pub.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime256_pub.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp384.csv b/src/cz/crcs/ectester/data/nonprime/nonprime384.csv index c58d74b..c58d74b 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp384.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime384.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp384_pub.csv b/src/cz/crcs/ectester/data/nonprime/nonprime384_pub.csv index 80f2cd6..80f2cd6 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp384_pub.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime384_pub.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp521.csv b/src/cz/crcs/ectester/data/nonprime/nonprime521.csv index f6835f1..f6835f1 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp521.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime521.csv diff --git a/src/cz/crcs/ectester/data/smallpub/ecsp521_pub.csv b/src/cz/crcs/ectester/data/nonprime/nonprime521_pub.csv index 5cceee6..5cceee6 100644 --- a/src/cz/crcs/ectester/data/smallpub/ecsp521_pub.csv +++ b/src/cz/crcs/ectester/data/nonprime/nonprime521_pub.csv diff --git a/src/cz/crcs/ectester/data/smallpub/keys.xml b/src/cz/crcs/ectester/data/smallpub/keys.xml deleted file mode 100644 index fbdf5e8..0000000 --- a/src/cz/crcs/ectester/data/smallpub/keys.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<keys xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../schema.xsd" - category="smallpub" - desc="Points on the Non-prime smallpub curves, very small point orders(3-5)."> - <pubkey> - <id>ecsp128-pub</id> - <file>ecsp128_pub.csv</file> - <curve>smallpub/ecsp128</curve> - <desc>order = 5</desc> - </pubkey> - <pubkey> - <id>ecsp160-pub</id> - <file>ecsp160_pub.csv</file> - <curve>smallpub/ecsp160</curve> - <desc>order = 3</desc> - </pubkey> - <pubkey> - <id>ecsp192-pub</id> - <file>ecsp192_pub.csv</file> - <curve>smallpub/ecsp192</curve> - <desc>order = 3</desc> - </pubkey> - <pubkey> - <id>ecsp224-pub</id> - <file>ecsp224_pub.csv</file> - <curve>smallpub/ecsp224</curve> - <desc>order = 5</desc> - </pubkey> - <pubkey> - <id>ecsp256-pub</id> - <file>ecsp256_pub.csv</file> - <curve>smallpub/ecsp256</curve> - <desc>order = 3</desc> - </pubkey> - <pubkey> - <id>ecsp384-pub</id> - <file>ecsp384_pub.csv</file> - <curve>smallpub/ecsp384</curve> - <desc>order = 3</desc> - </pubkey> - <pubkey> - <id>ecsp521-pub</id> - <file>ecsp521_pub.csv</file> - <curve>smallpub/ecsp521</curve> - <desc>order = 5</desc> - </pubkey> -</keys>
\ No newline at end of file diff --git a/src/cz/crcs/ectester/reader/Command.java b/src/cz/crcs/ectester/reader/Command.java index 92d9da1..24418be 100644 --- a/src/cz/crcs/ectester/reader/Command.java +++ b/src/cz/crcs/ectester/reader/Command.java @@ -49,7 +49,7 @@ public abstract class Command { * @param keyLength key length to set * @param keyClass key class to allocate */ - public Allocate(CardMngr cardManager, byte keyPair, short keyLength, byte keyClass) { + protected Allocate(CardMngr cardManager, byte keyPair, short keyLength, byte keyClass) { super(cardManager); this.keyPair = keyPair; this.keyLength = keyLength; @@ -79,7 +79,7 @@ public abstract class Command { * @param cardManager * @param keyPair which keyPair clear, local/remote (KEYPAIR_* || ...) */ - public Clear(CardMngr cardManager, byte keyPair) { + protected Clear(CardMngr cardManager, byte keyPair) { super(cardManager); this.keyPair = keyPair; @@ -113,7 +113,7 @@ public abstract class Command { * @param params parameters to set (EC_Consts.PARAMETER_* | ...) * @param external external curve data, can be null */ - public Set(CardMngr cardManager, byte keyPair, byte curve, short params, byte[] external) { + protected Set(CardMngr cardManager, byte keyPair, byte curve, short params, byte[] external) { super(cardManager); this.keyPair = keyPair; this.curve = curve; @@ -190,7 +190,7 @@ public abstract class Command { * @param cardManager * @param keyPair which keyPair to generate, local/remote (KEYPAIR_* || ...) */ - public Generate(CardMngr cardManager, byte keyPair) { + protected Generate(CardMngr cardManager, byte keyPair) { super(cardManager); this.keyPair = keyPair; @@ -222,7 +222,7 @@ public abstract class Command { * @param key key to export from (EC_Consts.KEY_* | ...) * @param params params to export (EC_Consts.PARAMETER_* | ...) */ - public Export(CardMngr cardManager, byte keyPair, byte key, short params) { + protected Export(CardMngr cardManager, byte keyPair, byte key, short params) { super(cardManager); this.keyPair = keyPair; this.key = key; @@ -263,7 +263,7 @@ public abstract class Command { * @param corruption whether to invalidate the pubkey before ECDH (EC_Consts.CORRUPTION_* || ...) * @param type */ - public ECDH(CardMngr cardManager, byte pubkey, byte privkey, byte export, byte corruption, byte type) { + protected ECDH(CardMngr cardManager, byte pubkey, byte privkey, byte export, byte corruption, byte type) { super(cardManager); this.pubkey = pubkey; this.privkey = privkey; @@ -298,7 +298,7 @@ public abstract class Command { * @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) { + protected ECDSA(CardMngr cardManager, byte keyPair, byte export, byte[] raw) { super(cardManager); this.keyPair = keyPair; this.export = export; @@ -342,5 +342,24 @@ public abstract class Command { return new Response.Cleanup(response, elapsed); } } + + /** + * + */ + public static class Support extends Command { + protected 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); + } + } } diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java index 9926d3e..716d4ea 100644 --- a/src/cz/crcs/ectester/reader/ECTester.java +++ b/src/cz/crcs/ectester/reader/ECTester.java @@ -80,7 +80,7 @@ public class ECTester { //Action-related options private String optListNamed; - private String optTestCase; + private String optTestSuite; private int optGenerateAmount; private int optECDHCount; private byte optECDHKA; @@ -205,7 +205,7 @@ public class ECTester { * -h / --help * -e / --export * -g / --generate [amount] - * -t / --test [test_case] + * -t / --test [test_suite] * -dh / --ecdh [count] * -dhc / --ecdhc [count] * -dsa / --ecdsa [count] @@ -245,7 +245,7 @@ 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_case>:\n- default:\n- invalid:\n- wrong:\n- nonprime:\n- smallpub:\n- test-vectors:").hasArg().argName("test_case").optionalArg(true).build()); + actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- wrong:\n- nonprime:\n- smallpub:\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("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build()); @@ -304,7 +304,7 @@ public class ECTester { optPrimeField = cli.hasOption("fp"); optBinaryField = cli.hasOption("f2m"); - optNamedCurve = cli.getOptionValue("named"); + optNamedCurve = cli.getOptionValue("named-curve"); optCustomCurve = cli.hasOption("custom"); optCurveFile = cli.getOptionValue("curve"); @@ -405,10 +405,10 @@ public class ECTester { optPrimeField = true; } - optTestCase = cli.getOptionValue("test", "default").toLowerCase(); - String[] tests = new String[]{"default", "nonprime", "invalid", "smallpub", "test-vectors", "wrong"}; + optTestSuite = cli.getOptionValue("test", "default").toLowerCase(); + String[] tests = new String[]{"default", "nonprime", "invalid", "test-vectors", "wrong"}; List<String> testsList = Arrays.asList(tests); - if (!testsList.contains(optTestCase)) { + if (!testsList.contains(optTestSuite)) { System.err.println("Unknown test case. Should be one of: " + Arrays.toString(tests)); return false; } @@ -527,6 +527,9 @@ public class ECTester { } else if (categories.containsKey(optListNamed)) { // print given category //TODO + } else { + // print given object + //TODO } } @@ -631,7 +634,8 @@ public class ECTester { private void test() throws IOException, CardException { List<Command> commands = new LinkedList<>(); - if (optTestCase.equals("default")) { + if (optTestSuite.equals("default")) { + commands.add(new Command.Support(cardManager)); if (optNamedCurve != null) { if (optPrimeField) { commands.addAll(testCurves(optNamedCurve, KeyPair.ALG_EC_FP)); @@ -675,7 +679,7 @@ public class ECTester { } } } - } else if (optTestCase.equals("test-vectors")) { + } else if (optTestSuite.equals("test-vectors")) { /* Set original curves (secg/nist/brainpool). Set keypairs from test vectors. * Do ECDH both ways, export and verify that the result is correct. * @@ -683,6 +687,12 @@ public class ECTester { 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 (optNamedCurve != null && !(result.getCurve().startsWith(optNamedCurve) || result.getCurve().equals(optNamedCurve))) { + continue; + } + if (curve.getBits() != optBits && !optAll) { + continue; + } EC_Params onekey = dataStore.getObject(EC_Keypair.class, result.getOneKey()); if (onekey == null) { onekey = dataStore.getObject(EC_Key.Private.class, result.getOneKey()); @@ -707,53 +717,56 @@ public class ECTester { } else { // These tests are dangerous, prompt before them. - System.out.println("The test you selected (" + optTestCase + ") is potentially dangerous."); + System.out.println("The test you selected (" + optTestSuite + ") is potentially dangerous."); System.out.println("Some of these tests have caused temporary DoS of some cards."); System.out.print("Do you want to proceed? (y/n):"); - String confirmation = System.console().readLine(); + Scanner in = new Scanner(System.in); + String confirmation = in.nextLine(); if (!Arrays.asList("yes", "y", "Y").contains(confirmation)) { return; } - if (optTestCase.equals("wrong") || optTestCase.equals("nonprime")) { - /* Just do the default tests on the wrong and non-prime curves. + if (optTestSuite.equals("wrong")) { + /* Just do the default tests on the wrong curves. * These should generally fail, the curves aren't safe. */ if (optPrimeField) { - commands.addAll(testCurves(optTestCase, KeyPair.ALG_EC_FP)); + commands.addAll(testCurves(optTestSuite, KeyPair.ALG_EC_FP)); } if (optBinaryField) { - commands.addAll(testCurves(optTestCase, KeyPair.ALG_EC_F2M)); + commands.addAll(testCurves(optTestSuite, KeyPair.ALG_EC_F2M)); } - } else if (optTestCase.equals("smallpub")) { - /* Do the default tests with the public keys set to provided smallpub keys. + } else if (optTestSuite.equals("nonprime")) { + /* Do the default tests with the public keys set to provided nonprime keys. * 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, "smallpub"); + Map<String, EC_Key> keys = dataStore.getObjects(EC_Key.class, "nonprime"); for (EC_Key key : keys.values()) { EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve()); if ((curve.getBits() == optBits || optAll)) { commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField())); commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL)); - commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, curve.getParams(), curve.flatten())); + commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten())); + commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, key.getParams(), key.flatten())); commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH)); commands.add(new Command.Cleanup(cardManager)); } } - } else if (optTestCase.equals("invalid")) { + } else if (optTestSuite.equals("invalid")) { /* Set original curves (secg/nist/brainpool). Generate local. * Try ECDH with invalid public keys of increasing (or decreasing) order. * */ //TODO + System.err.println("Currently not yet implemented."); } } List<Response> test = Command.sendAll(commands); - systemOutLogger.println(Response.toString(test)); + systemOutLogger.println(Response.toString(test, optTestSuite)); for (Response response : test) { if (response instanceof Response.ECDH) { @@ -1053,8 +1066,7 @@ public class ECTester { EC_Curve curve = entry.getValue(); if (curve.getField() == field && (curve.getBits() == optBits || optAll)) { commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), field)); - byte[] external = curve.flatten(); - commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), external)); + commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten())); commands.addAll(testCurve()); commands.add(new Command.Cleanup(cardManager)); } diff --git a/src/cz/crcs/ectester/reader/Response.java b/src/cz/crcs/ectester/reader/Response.java index 92d1b9f..4bb5b88 100644 --- a/src/cz/crcs/ectester/reader/Response.java +++ b/src/cz/crcs/ectester/reader/Response.java @@ -14,8 +14,7 @@ import java.util.List; public abstract class Response { private ResponseAPDU resp; private long time; - private short sw1 = 0; - private short sw2 = 0; + private short[] sws; private int numSW = 0; private byte[][] params; private boolean success = true; @@ -27,23 +26,20 @@ public abstract class Response { protected void parse(int numSW, int numParams) { this.numSW = numSW; + this.sws = new short[numSW]; byte[] data = resp.getData(); int offset = 0; //parse SWs in response - if (--numSW >= 0 && getLength() >= 2) { - sw1 = Util.getShort(data, offset); - offset += 2; - if (sw1 != ISO7816.SW_NO_ERROR) { - success = false; - } - } - if (--numSW >= 0 && getLength() >= 4) { - sw2 = Util.getShort(data, offset); - offset += 2; - if (sw2 != ISO7816.SW_NO_ERROR) { - success = false; + for (int i = 0; i < numSW; ++i) { + if (getLength() >= (offset + 2)) { + short sw = Util.getShort(data, offset); + offset += 2; + sws[i] = sw; + if (sw != ISO7816.SW_NO_ERROR) { + success = false; + } } } @@ -79,11 +75,15 @@ public abstract class Response { } public short getSW1() { - return sw1; + return sws[0]; } public short getSW2() { - return sw2; + return sws[1]; + } + + public short getSW(int index) { + return sws[index]; } public int getNumSW() { @@ -122,16 +122,16 @@ public abstract class Response { } public static String toString(List<Response> responses, String prefix) { + if (prefix != null) + prefix += " | "; StringBuilder out = new StringBuilder(); for (int i = 0; i < responses.size(); ++i) { Response r = responses.get(i); String message = r.toString(); - String suffix; - if (r.getNumSW() == 1) { - suffix = String.format("%s", Util.getSWString(r.getSW1())); - } else { - suffix = String.format("%s %s", Util.getSWString(r.getSW1()), Util.getSWString(r.getSW2())); + String suffix = ""; + for (int j = 0; j < r.getNumSW(); ++j) { + suffix += " " + Util.getSWString(r.getSW(j)); } if (prefix != null) @@ -153,7 +153,7 @@ public abstract class Response { private short keyLength; private byte keyClass; - public Allocate(ResponseAPDU response, long time, byte keyPair, short keyLength, byte keyClass) { + protected Allocate(ResponseAPDU response, long time, byte keyPair, short keyLength, byte keyClass) { super(response, time); this.keyPair = keyPair; this.keyLength = keyLength; @@ -181,7 +181,7 @@ public abstract class Response { public static class Clear extends Response { private byte keyPair; - public Clear(ResponseAPDU response, long time, byte keyPair) { + protected Clear(ResponseAPDU response, long time, byte keyPair) { super(response, time); this.keyPair = keyPair; @@ -323,7 +323,7 @@ public abstract class Response { private byte key; private short parameters; - public Export(ResponseAPDU response, long time, byte keyPair, byte key, short parameters) { + protected Export(ResponseAPDU response, long time, byte keyPair, byte key, short parameters) { super(response, time); this.keyPair = keyPair; this.key = key; @@ -527,6 +527,22 @@ public abstract class Response { return String.format("Requested JCSystem object deletion"); } + } + + /** + * + */ + public static class Support extends Response { + + protected Support(ResponseAPDU response, long time) { + super(response, time); + parse(3,0); + } + + @Override + public String toString() { + return "Support of ECDH, ECDHC, ECDSA"; + } } } |
