diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECKeyGenerator.java | 4 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/applet/ECTesterApplet.java | 6 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/common/test/CompoundTest.java | 2 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/common/test/TestSuite.java | 12 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/common/util/ByteUtil.java | 17 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/data/wrong/curves.xml | 13 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/command/Command.java | 8 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/response/Response.java | 4 | ||||
| -rw-r--r-- | src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java | 96 |
9 files changed, 149 insertions, 13 deletions
diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java index b026cfe..244bdba 100644 --- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java +++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java @@ -145,7 +145,7 @@ public class ECKeyGenerator { * @param offset * @return */ - public short corruptCurve(KeyPair keypair, short corruptParams, byte corruption, byte[] buffer, short offset) { + public short corruptCurve(KeyPair keypair, short corruptParams, short corruption, byte[] buffer, short offset) { return corruptCurve(keypair, EC_Consts.KEY_BOTH, corruptParams, corruption, buffer, offset); } @@ -158,7 +158,7 @@ public class ECKeyGenerator { * @param offset * @return */ - public short corruptCurve(KeyPair keypair, byte key, short corruptParams, byte corruption, byte[] buffer, short offset) { + public short corruptCurve(KeyPair keypair, byte key, short corruptParams, short corruption, byte[] buffer, short offset) { sw = ISO7816.SW_NO_ERROR; if (corruptParams == EC_Consts.PARAMETERS_NONE) { return sw; diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index 20e3f05..210b3e7 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -310,7 +310,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength { * @param apdu P1 = byte keyPair (KEYPAIR_* | ...) * P2 = byte key (EC_Consts.KEY_* | ...) * DATA = short params (EC_Consts.PARAMETER_* | ...) - * byte corruption (EC_Consts.CORRUPTION_* || ...) + * short corruption (EC_Consts.CORRUPTION_* || ...) * @return length of response */ private short insCorrupt(APDU apdu) { @@ -318,7 +318,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength { byte key = apduArray[ISO7816.OFFSET_P2]; short cdata = apdu.getOffsetCdata(); short params = Util.getShort(apduArray, cdata); - byte corruption = apduArray[(short) (cdata + 2)]; + short corruption = Util.getShort(apduArray, (short) (cdata + 2)); short len = 0; if ((keyPair & KEYPAIR_LOCAL) != 0) { @@ -544,7 +544,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength { * @param outOffset output offset in buffer * @return length of data written to the buffer */ - private short corrupt(KeyPair keyPair, byte key, short params, byte corruption, byte[] outBuffer, short outOffset) { + private short corrupt(KeyPair keyPair, byte key, short params, short corruption, byte[] outBuffer, short outOffset) { short sw = keyGenerator.corruptCurve(keyPair, key, params, corruption, ramArray, (short) 0); Util.setShort(outBuffer, outOffset, sw); return 2; diff --git a/src/cz/crcs/ectester/common/test/CompoundTest.java b/src/cz/crcs/ectester/common/test/CompoundTest.java index 10ecf9c..69122b0 100644 --- a/src/cz/crcs/ectester/common/test/CompoundTest.java +++ b/src/cz/crcs/ectester/common/test/CompoundTest.java @@ -12,7 +12,7 @@ import java.util.function.Function; public class CompoundTest extends Test { private Function<Test[], Result> callback; private Test[] tests; - private String description; + private String description = ""; private CompoundTest(Function<Test[], Result> callback, Test... tests) { this.callback = callback; diff --git a/src/cz/crcs/ectester/common/test/TestSuite.java b/src/cz/crcs/ectester/common/test/TestSuite.java index f4f30ee..5bcee85 100644 --- a/src/cz/crcs/ectester/common/test/TestSuite.java +++ b/src/cz/crcs/ectester/common/test/TestSuite.java @@ -32,11 +32,23 @@ public abstract class TestSuite { writer.end(); } + /** + * Run the given test and return it back. + * @param t The test to run. + * @return The test that was run. + * @throws TestException + */ protected Test runTest(Test t) throws TestException { t.run(); return t; } + /** + * Run the given test, output it and return it back. + * @param t The test to run. + * @return The test that was run. + * @throws TestException + */ protected Test doTest(Test t) throws TestException { t.run(); writer.outputTest(t); diff --git a/src/cz/crcs/ectester/common/util/ByteUtil.java b/src/cz/crcs/ectester/common/util/ByteUtil.java index 90c6eaa..ad9f1bf 100644 --- a/src/cz/crcs/ectester/common/util/ByteUtil.java +++ b/src/cz/crcs/ectester/common/util/ByteUtil.java @@ -39,6 +39,23 @@ public class ByteUtil { return true; } + public static byte[] shortToBytes(short value) { + byte[] result = new byte[2]; + setShort(result, 0, value); + return result; + } + + public static byte[] shortToBytes(short[] shorts) { + if (shorts == null) { + return null; + } + byte[] result = new byte[shorts.length * 2]; + for (int i = 0; i < shorts.length; ++i) { + setShort(result, 2 * i, shorts[i]); + } + return result; + } + public static byte[] hexToBytes(String hex) { return hexToBytes(hex, true); } diff --git a/src/cz/crcs/ectester/data/wrong/curves.xml b/src/cz/crcs/ectester/data/wrong/curves.xml index 396dc4e..2a51474 100644 --- a/src/cz/crcs/ectester/data/wrong/curves.xml +++ b/src/cz/crcs/ectester/data/wrong/curves.xml @@ -6,77 +6,90 @@ <bits>128</bits> <field>prime</field> <file>wrongp128.csv</file> + <desc>The field is not prime.</desc> </curve> <curve> <id>wrongp160</id> <bits>160</bits> <field>prime</field> <file>wrongp160.csv</file> + <desc>The field is not prime.</desc> </curve> <curve> <id>wrongp192</id> <bits>192</bits> <field>prime</field> <file>wrongp192.csv</file> + <desc>The field is not prime.</desc> </curve> <curve> <id>wrongp224</id> <bits>224</bits> <field>prime</field> <file>wrongp224.csv</file> + <desc>The field is not prime.</desc> </curve> <curve> <id>wrongp256</id> <bits>256</bits> <field>prime</field> <file>wrongp256.csv</file> + <desc>The field is not prime.</desc> </curve> <curve> <id>wrongp384</id> <bits>384</bits> <field>prime</field> <file>wrongp384.csv</file> + <desc>The field is not prime.</desc> </curve> <curve> <id>wrongp521</id> <bits>521</bits> <field>prime</field> <file>wrongp521.csv</file> + <desc>The field is not prime.</desc> </curve> <curve> <id>wrongt163</id> <bits>163</bits> <field>binary</field> <file>wrongt163.csv</file> + <desc>The field polynomial is not irreducible in F_2^163[x].</desc> </curve> <curve> <id>wrongt233</id> <bits>233</bits> <field>binary</field> <file>wrongt233.csv</file> + <desc>The field polynomial is not irreducible in F_2^233[x].</desc> </curve> <curve> <id>wrongt239</id> <bits>239</bits> <field>binary</field> <file>wrongt239.csv</file> + <desc>The field polynomial is not irreducible in F_2^239[x].</desc> </curve> <curve> <id>wrongt283</id> <bits>283</bits> <field>binary</field> <file>wrongt283.csv</file> + <desc>The field polynomial is not irreducible in F_2^283[x].</desc> </curve> <curve> <id>wrongt409</id> <bits>409</bits> <field>binary</field> <file>wrongt409.csv</file> + <desc>The field polynomial is not irreducible in F_2^409[x].</desc> </curve> <curve> <id>wrongt571</id> <bits>571</bits> <field>binary</field> <file>wrongt571.csv</file> + <desc>The field polynomial is not irreducible in F_2^571[x].</desc> </curve> </curves>
\ No newline at end of file diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index 5a6906c..eefbc27 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -374,7 +374,7 @@ public abstract class Command { private byte keyPair; private byte key; private short params; - private byte corruption; + private short corruption; /** * @param cardManager cardManager to send APDU through @@ -383,16 +383,16 @@ public abstract class Command { * @param params parameters to corrupt (EC_Consts.PARAMETER_* | ...) * @param corruption corruption type (EC_Consts.CORRUPTION_*) */ - public Corrupt(CardMngr cardManager, byte keyPair, byte key, short params, byte corruption) { + public Corrupt(CardMngr cardManager, byte keyPair, byte key, short params, short corruption) { super(cardManager); this.keyPair = keyPair; this.key = key; this.params = params; this.corruption = corruption; - byte[] data = new byte[3]; + byte[] data = new byte[4]; ByteUtil.setShort(data, 0, params); - data[2] = corruption; + ByteUtil.setShort(data, 2, corruption); this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CORRUPT, keyPair, key, data); } diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index cbed3b2..1ae59de 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -292,9 +292,9 @@ public abstract class Response { private byte keyPair; private byte key; private short params; - private byte corruption; + private short corruption; - public Corrupt(ResponseAPDU response, long time, byte keyPair, byte key, short params, byte corruption) { + public Corrupt(ResponseAPDU response, long time, byte keyPair, byte key, short params, short corruption) { super(response, time); this.keyPair = keyPair; this.key = key; diff --git a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java index cac8fab..1de0723 100644 --- a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java +++ b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java @@ -3,17 +3,24 @@ package cz.crcs.ectester.reader.test; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Params; import cz.crcs.ectester.common.output.TestWriter; import cz.crcs.ectester.common.test.CompoundTest; import cz.crcs.ectester.common.test.Result; import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.common.util.CardUtil; +import cz.crcs.ectester.common.util.ECUtil; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.command.Command; import javacard.security.KeyPair; +import java.math.BigInteger; import java.util.Map; +import java.util.Random; /** * @author Jan Jancar johny@neuromancer.sk @@ -44,7 +51,7 @@ public class CardWrongCurvesSuite extends CardTestSuite { } Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS)); Test generate = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS)); - doTest(CompoundTest.any(Result.ExpectedValue.FAILURE, "Set wrong curve and generate keypairs, should fail." ,set, generate)); + doTest(CompoundTest.any(Result.ExpectedValue.FAILURE, "Set wrong curve and generate keypairs, should fail.", set, generate)); for (byte kaType : EC_Consts.KA_TYPES) { Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), Result.ExpectedValue.SUCCESS)); @@ -54,5 +61,92 @@ public class CardWrongCurvesSuite extends CardTestSuite { } } } + /* + * Do some interesting tests with corrupting the custom curves. + * For prime field: + * - p = 0 + * - p = 1 + * - p is a square of a prime + * - p is a composite q * s with q, s primes + * - TODO: p divides discriminant + */ + Random r = new Random(); + for (short keyLength : EC_Consts.FP_SIZES) { + byte curve = EC_Consts.getCurve(keyLength, KeyPair.ALG_EC_FP); + Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP), Result.ExpectedValue.SUCCESS)); + if (!key.ok()) { + continue; + } + Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curve, EC_Consts.PARAMETERS_DOMAIN_FP, null), Result.ExpectedValue.SUCCESS)); + Test setup = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set)); + + Test prime0 = ecdhTest(new Command.Corrupt(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_FP, EC_Consts.CORRUPTION_ZERO), "Set p = 0.", "ECDH with p = 0."); + Test prime1 = ecdhTest(new Command.Corrupt(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_FP, EC_Consts.CORRUPTION_ONE), "Set p = 1.", "ECDH with p = 1."); + + short keyHalf = (short) (keyLength / 2); + BigInteger prime = new BigInteger(keyHalf, r); + BigInteger primePow = prime.pow(2); + byte[] primePowBytes = ECUtil.toByteArray(primePow, keyLength); + EC_Params primePowData = new EC_Params(EC_Consts.PARAMETER_FP, new byte[][]{primePowBytes}); + Test primePower = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, primePowData.getParams(), primePowData.flatten()), "Set p = square of a prime.", "ECDH with p = q^2."); + + BigInteger q = new BigInteger(keyHalf, r); + BigInteger s = new BigInteger(keyHalf, r); + BigInteger compositeValue = q.multiply(s); + byte[] compositeBytes = ECUtil.toByteArray(compositeValue, keyLength); + EC_Params compositeData = new EC_Params(EC_Consts.PARAMETER_FP, new byte[][]{compositeBytes}); + Test composite = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, compositeData.getParams(), compositeData.flatten()), "Set p = product of two primes.", "ECDH with p = q * s."); + + Test wrong = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted prime parameter.", prime0, prime1, primePower, composite)); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_FP), setup, wrong)); + } + + /* + * For binary field: + * - e1, e2 or e3 is larger than m. + * - e1 = e2 = e3 = 0 + */ + for (short keyLength : EC_Consts.F2M_SIZES) { + byte curve = EC_Consts.getCurve(keyLength, KeyPair.ALG_EC_F2M); + Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M), Result.ExpectedValue.SUCCESS)); + if (!key.ok()) { + continue; + } + Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curve, EC_Consts.PARAMETERS_DOMAIN_F2M, null), Result.ExpectedValue.SUCCESS)); + Test setup = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set)); + + Test coeff0 = ecdhTest(new Command.Corrupt(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_F2M, EC_Consts.CORRUPTION_ZERO), "Set e1 = e2 = e3 = 0.", "ECDH with wrong field polynomial: x^" + keyLength); + + short e1 = (short) (2 * keyLength); + short e2 = (short) (3 * keyLength); + short e3 = (short) (4 * keyLength); + byte[][] coeffBytes = new byte[][]{ + ByteUtil.shortToBytes(keyLength), + ByteUtil.shortToBytes(e1), + ByteUtil.shortToBytes(e2), + ByteUtil.shortToBytes(e3)}; + EC_Params coeffParams = new EC_Params(EC_Consts.PARAMETER_F2M, coeffBytes); + Test coeffLarger = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, coeffParams.getParams(), coeffParams.flatten()), "Set e1=" + e1 + ", e2=" + e2 + ", e3=" + e3, "ECDH with wrong field poly, powers larger than " + keyLength); + + Test wrong = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted field polynomial parameter.", coeff0, coeffLarger)); + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_F2M), setup, wrong)); + } + + /* + * TODO: tests for both Fp and F2m: + * - generator not on curve, + * - generator not on proper subgroup of curve(as specified by order/cofactor), + * - wrong order, + * - wrong cofactor. + */ + } + + private Test ecdhTest(Command setupCmd, String prepareDesc, String fullDesc) throws TestException { + Test setup = runTest(CommandTest.expect(setupCmd, Result.ExpectedValue.FAILURE)); + Test generate = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.FAILURE)); + Test preparePhase = runTest(CompoundTest.any(Result.ExpectedValue.SUCCESS, prepareDesc, setup, generate)); + Test allocateECDH = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.SUCCESS)); + Test ecdh = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE)); + return runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, fullDesc, preparePhase, allocateECDH, ecdh)); } } |
