diff --git a/crypto/test/src/crypto/test/JPAKEParticipantTest.cs b/crypto/test/src/crypto/test/JPAKEParticipantTest.cs
new file mode 100644
index 000000000..7c01bf237
--- /dev/null
+++ b/crypto/test/src/crypto/test/JPAKEParticipantTest.cs
@@ -0,0 +1,566 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Agreement.Jpake;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+ [TestFixture]
+ public class JPAKEParticipantTest
+ : SimpleTest
+ {
+ public override void PerformTest()
+ {
+ TestConstruction();
+ TestSuccessfulExchange();
+ TestIncorrectPassword();
+ TestStateValidation();
+ TestValidateRound1PayloadReceived();
+ TestValidateRound2PayloadReceived();
+ }
+
+ public override string Name
+ {
+ get { return "JPAKEParticipant"; }
+ }
+
+ public static void Main(
+ string[] args)
+ {
+ RunTest(new JPAKEParticipantTest());
+ }
+
+ [Test]
+ public void TestFunction()
+ {
+ string resultText = Perform().ToString();
+
+ Assert.AreEqual(Name + ": Okay", resultText);
+ }
+
+ public void TestConstruction()
+ {
+ JPAKEPrimeOrderGroup group = JPAKEPrimeOrderGroups.SUN_JCE_1024;
+ SecureRandom random = new SecureRandom();
+ IDigest digest = new Sha256Digest();
+ string participantId = "participantId";
+ char[] password = "password".ToCharArray();
+
+ // should succeed
+ new JPAKEParticipant(participantId, password, group, digest, random);
+
+ // null participantId
+ try
+ {
+ new JPAKEParticipant(null, password, group, digest, random);
+
+ Fail("failed to throw exception on null participantId");
+ }
+ catch (NullReferenceException)
+ {
+ // expected
+ }
+
+ // null password
+ try
+ {
+ new JPAKEParticipant(participantId, null, group, digest, random);
+
+ Fail("failed to throw exception on null password");
+ }
+ catch (NullReferenceException)
+ {
+ // expected
+ }
+
+ // empty password
+ try
+ {
+ new JPAKEParticipant(participantId, "".ToCharArray(), group, digest, random);
+
+ Fail("failed to throw exception on empty password");
+ }
+ catch (ArgumentException)
+ {
+ // expected
+ }
+
+ // null group
+ try
+ {
+ new JPAKEParticipant(participantId, password, null, digest, random);
+
+ Fail("failed to throw exception on null group");
+ }
+ catch (NullReferenceException)
+ {
+ // expected
+ }
+
+ // null digest
+ try
+ {
+ new JPAKEParticipant(participantId, password, group, null, random);
+
+ Fail("failed to throw exception on null digest");
+ }
+ catch (NullReferenceException)
+ {
+ // expected
+ }
+
+ // null random
+ try
+ {
+ new JPAKEParticipant(participantId, password, group, digest, null);
+
+ Fail("failed to throw exception on null random");
+ }
+ catch (NullReferenceException)
+ {
+ // expected
+ }
+ }
+
+ public void TestSuccessfulExchange()
+ {
+ JPAKEParticipant alice = CreateAlice();
+ JPAKEParticipant bob = CreateBob();
+
+ ExchangeAfterRound2Creation exchange = RunExchangeUntilRound2Creation(alice, bob);
+
+ alice.ValidateRound2PayloadReceived(exchange.bobRound2Payload);
+ bob.ValidateRound2PayloadReceived(exchange.aliceRound2Payload);
+
+ BigInteger aliceKeyingMaterial = alice.CalculateKeyingMaterial();
+ BigInteger bobKeyingMaterial = bob.CalculateKeyingMaterial();
+
+ JPAKERound3Payload aliceRound3Payload = alice.CreateRound3PayloadToSend(aliceKeyingMaterial);
+ JPAKERound3Payload bobRound3Payload = bob.CreateRound3PayloadToSend(bobKeyingMaterial);
+
+ alice.ValidateRound3PayloadReceived(bobRound3Payload, aliceKeyingMaterial);
+ bob.ValidateRound3PayloadReceived(aliceRound3Payload, bobKeyingMaterial);
+
+ Assert.AreEqual(aliceKeyingMaterial, bobKeyingMaterial);
+ }
+
+ public void TestIncorrectPassword()
+ {
+ JPAKEParticipant alice = CreateAlice();
+ JPAKEParticipant bob = CreateBobWithWrongPassword();
+
+ ExchangeAfterRound2Creation exchange = RunExchangeUntilRound2Creation(alice, bob);
+
+ alice.ValidateRound2PayloadReceived(exchange.bobRound2Payload);
+ bob.ValidateRound2PayloadReceived(exchange.aliceRound2Payload);
+
+ BigInteger aliceKeyingMaterial = alice.CalculateKeyingMaterial();
+ BigInteger bobKeyingMaterial = bob.CalculateKeyingMaterial();
+
+ JPAKERound3Payload aliceRound3Payload = alice.CreateRound3PayloadToSend(aliceKeyingMaterial);
+ JPAKERound3Payload bobRound3Payload = bob.CreateRound3PayloadToSend(bobKeyingMaterial);
+
+ try
+ {
+ alice.ValidateRound3PayloadReceived(bobRound3Payload, aliceKeyingMaterial);
+
+ Fail("failed to throw exception on incorrect password");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ try
+ {
+ bob.ValidateRound3PayloadReceived(aliceRound3Payload, bobKeyingMaterial);
+
+ Fail("failed to throw exception on incorrect password");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+ }
+
+ public void TestStateValidation()
+ {
+ JPAKEParticipant alice = CreateAlice();
+ JPAKEParticipant bob = CreateBob();
+
+ // We're testing alice here. Bob is just used for help.
+
+ // START ROUND 1 CHECKS
+
+ Assert.AreEqual(JPAKEParticipant.STATE_INITIALIZED, alice.State);
+
+ // create round 2 before round 1
+ try
+ {
+ alice.CreateRound2PayloadToSend();
+
+ Fail("failed to throw on round 2 creation before 1");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ JPAKERound1Payload aliceRound1Payload = alice.CreateRound1PayloadToSend();
+ Assert.AreEqual(JPAKEParticipant.STATE_ROUND_1_CREATED, alice.State);
+
+ // create round 1 twice
+ try
+ {
+ alice.CreateRound1PayloadToSend();
+
+ Fail("failed to throw on round 1 creation twice");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ // create round 2 before validation round 1
+ try
+ {
+ alice.CreateRound2PayloadToSend();
+
+ Fail("failed to throw on round 2 creation before round 1 validation");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ // validate round 2 before validation round 1
+ try
+ {
+ alice.ValidateRound2PayloadReceived(null);
+
+ Fail("failed to throw on round 2 validation before round 1 validation");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ JPAKERound1Payload bobRound1Payload = bob.CreateRound1PayloadToSend();
+ alice.ValidateRound1PayloadReceived(bobRound1Payload);
+ Assert.AreEqual(JPAKEParticipant.STATE_ROUND_1_VALIDATED, alice.State);
+
+ // validate round 1 payload twice
+ try
+ {
+ alice.ValidateRound1PayloadReceived(bobRound1Payload);
+
+ Fail("failed to throw on round 1 validation twice");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ bob.ValidateRound1PayloadReceived(aliceRound1Payload);
+
+ // START ROUND 2 CHECKS
+
+ JPAKERound2Payload aliceRound2Payload = alice.CreateRound2PayloadToSend();
+ Assert.AreEqual(JPAKEParticipant.STATE_ROUND_2_CREATED, alice.State);
+
+ // create round 2 payload twice
+ try
+ {
+ alice.CreateRound2PayloadToSend();
+
+ Fail("failed to throw on round 2 creation twice");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ // create key before validation round 2
+ try
+ {
+ alice.CalculateKeyingMaterial();
+
+ Fail("failed to throw on calculating keying material before round 2 validation");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ // validate round 3 before validating round 2
+ try
+ {
+ alice.ValidateRound3PayloadReceived(null, null);
+
+ Fail("failed to throw on validating round 3 before 2");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ JPAKERound2Payload bobRound2Payload = bob.CreateRound2PayloadToSend();
+ alice.ValidateRound2PayloadReceived(bobRound2Payload);
+ Assert.AreEqual(JPAKEParticipant.STATE_ROUND_2_VALIDATED, alice.State);
+
+ // validate round 2 payload twice
+ try
+ {
+ alice.ValidateRound2PayloadReceived(bobRound2Payload);
+
+ Fail("failed to throw on validating round 2 twice");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ bob.ValidateRound2PayloadReceived(aliceRound2Payload);
+
+ // create round 3 before calculating key
+ try
+ {
+ alice.CreateRound3PayloadToSend(BigInteger.One);
+
+ Fail("failed to throw on creating round 3 before calculating key aterial");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ // START KEY CALCULATION CHECKS
+
+ BigInteger aliceKeyingMaterial = alice.CalculateKeyingMaterial();
+ Assert.AreEqual(JPAKEParticipant.STATE_KEY_CALCULATED, alice.State);
+
+ // calculate key twice
+ try
+ {
+ alice.CalculateKeyingMaterial();
+
+ Fail("failed to throw on calculating key twice");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ BigInteger bobKeyingMaterial = bob.CalculateKeyingMaterial();
+
+ // START ROUND 3 CHECKS
+
+ JPAKERound3Payload aliceRound3Payload = alice.CreateRound3PayloadToSend(aliceKeyingMaterial);
+ Assert.AreEqual(JPAKEParticipant.STATE_ROUND_3_CREATED, alice.State);
+
+ // create round 3 payload twice
+ try
+ {
+ alice.CreateRound3PayloadToSend(aliceKeyingMaterial);
+
+ Fail("failed to throw on creation round 3 twice");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ JPAKERound3Payload bobRound3Payload = bob.CreateRound3PayloadToSend(bobKeyingMaterial);
+ alice.ValidateRound3PayloadReceived(bobRound3Payload, aliceKeyingMaterial);
+ Assert.AreEqual(JPAKEParticipant.STATE_ROUND_3_VALIDATED, alice.State);
+
+ // validate round 3 payload twice
+ try
+ {
+ alice.ValidateRound3PayloadReceived(bobRound3Payload, aliceKeyingMaterial);
+
+ Fail("failed to throw on validation round 3 twice");
+ }
+ catch (InvalidOperationException)
+ {
+ // expected
+ }
+
+ bob.ValidateRound3PayloadReceived(aliceRound3Payload, bobKeyingMaterial);
+ }
+
+ public void TestValidateRound1PayloadReceived()
+ {
+ // We're testing alice here. Bob is just used for help.
+
+ JPAKERound1Payload bobRound1Payload = CreateBob().CreateRound1PayloadToSend();
+
+ // should succeed
+ CreateAlice().ValidateRound1PayloadReceived(bobRound1Payload);
+
+ // alice verifies alice's payload
+ try
+ {
+ JPAKEParticipant alice = CreateAlice();
+ alice.ValidateRound1PayloadReceived(alice.CreateRound1PayloadToSend());
+
+ Fail("failed to throw on participant validating own payload");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // g^x4 == 1
+ try
+ {
+ CreateAlice().ValidateRound1PayloadReceived(new JPAKERound1Payload(
+ bobRound1Payload.ParticipantId,
+ bobRound1Payload.Gx1,
+ BigInteger.One,
+ bobRound1Payload.KnowledgeProofForX1,
+ bobRound1Payload.KnowledgeProofForX2));
+
+ Fail("failed to throw on g^x4 == 1");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // zero knowledge proof for x3 fails
+ try
+ {
+ JPAKERound1Payload bobRound1Payload2 = CreateBob().CreateRound1PayloadToSend();
+ CreateAlice().ValidateRound1PayloadReceived(new JPAKERound1Payload(
+ bobRound1Payload.ParticipantId,
+ bobRound1Payload.Gx1,
+ bobRound1Payload.Gx2,
+ bobRound1Payload2.KnowledgeProofForX1,
+ bobRound1Payload.KnowledgeProofForX2));
+
+ Fail("failed to throw on incorrect zero knowledge proof for x3");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // zero knowledge proof for x4 fails
+ try
+ {
+ JPAKERound1Payload bobRound1Payload2 = CreateBob().CreateRound1PayloadToSend();
+ CreateAlice().ValidateRound1PayloadReceived(new JPAKERound1Payload(
+ bobRound1Payload.ParticipantId,
+ bobRound1Payload.Gx1,
+ bobRound1Payload.Gx2,
+ bobRound1Payload.KnowledgeProofForX1,
+ bobRound1Payload2.KnowledgeProofForX2));
+
+ Fail("failed to throw on incorrect zero knowledge proof for x4");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+ }
+
+ public void TestValidateRound2PayloadReceived()
+ {
+ // We're testing alice here. Bob is just used for help.
+
+ // should succeed
+ ExchangeAfterRound2Creation exchange1 = RunExchangeUntilRound2Creation(CreateAlice(), CreateBob());
+ exchange1.alice.ValidateRound2PayloadReceived(exchange1.bobRound2Payload);
+
+ // alice verified alice's payload
+ ExchangeAfterRound2Creation exchange2 = RunExchangeUntilRound2Creation(CreateAlice(), CreateBob());
+ try
+ {
+ exchange2.alice.ValidateRound2PayloadReceived(exchange2.aliceRound2Payload);
+
+ Fail("failed to throw on participant verifying own payload 2");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // wrong z
+ ExchangeAfterRound2Creation exchange3 = RunExchangeUntilRound2Creation(CreateAlice(), CreateBob());
+ ExchangeAfterRound2Creation exchange4 = RunExchangeUntilRound2Creation(CreateAlice(), CreateBob());
+ try
+ {
+ exchange3.alice.ValidateRound2PayloadReceived(exchange4.bobRound2Payload);
+
+ Fail("failed to throw on wrong z");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+ }
+
+ private class ExchangeAfterRound2Creation
+ {
+ public JPAKEParticipant alice;
+ public JPAKERound2Payload aliceRound2Payload;
+ public JPAKERound2Payload bobRound2Payload;
+
+ public ExchangeAfterRound2Creation(
+ JPAKEParticipant alice,
+ JPAKERound2Payload aliceRound2Payload,
+ JPAKERound2Payload bobRound2Payload)
+ {
+ this.alice = alice;
+ this.aliceRound2Payload = aliceRound2Payload;
+ this.bobRound2Payload = bobRound2Payload;
+ }
+ }
+
+ private ExchangeAfterRound2Creation RunExchangeUntilRound2Creation(JPAKEParticipant alice, JPAKEParticipant bob)
+ {
+ JPAKERound1Payload aliceRound1Payload = alice.CreateRound1PayloadToSend();
+ JPAKERound1Payload bobRound1Payload = bob.CreateRound1PayloadToSend();
+
+ alice.ValidateRound1PayloadReceived(bobRound1Payload);
+ bob.ValidateRound1PayloadReceived(aliceRound1Payload);
+
+ JPAKERound2Payload aliceRound2Payload = alice.CreateRound2PayloadToSend();
+ JPAKERound2Payload bobRound2Payload = bob.CreateRound2PayloadToSend();
+
+ return new ExchangeAfterRound2Creation(
+ alice,
+ aliceRound2Payload,
+ bobRound2Payload);
+ }
+
+ private JPAKEParticipant CreateAlice()
+ {
+ return CreateParticipant("alice", "password");
+ }
+
+ private JPAKEParticipant CreateBob()
+ {
+ return CreateParticipant("bob", "password");
+ }
+
+ private JPAKEParticipant CreateBobWithWrongPassword()
+ {
+ return CreateParticipant("bob", "wrong");
+ }
+
+ private JPAKEParticipant CreateParticipant(string participantId, string password)
+ {
+ return new JPAKEParticipant(
+ participantId,
+ password.ToCharArray(),
+ JPAKEPrimeOrderGroups.SUN_JCE_1024);
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/test/JPAKEPrimeOrderGroupTest.cs b/crypto/test/src/crypto/test/JPAKEPrimeOrderGroupTest.cs
new file mode 100644
index 000000000..d9749cb53
--- /dev/null
+++ b/crypto/test/src/crypto/test/JPAKEPrimeOrderGroupTest.cs
@@ -0,0 +1,117 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Agreement.Jpake;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+ [TestFixture]
+ public class JPAKEPrimeOrderGroupTest
+ : SimpleTest
+ {
+ public override void PerformTest()
+ {
+ TestConstruction();
+ }
+
+ public override string Name
+ {
+ get { return "JPAKEPrimeOrderGroup"; }
+ }
+
+ public static void Main(
+ string[] args)
+ {
+ RunTest(new JPAKEPrimeOrderGroupTest());
+ }
+
+ [Test]
+ public void TestFunction()
+ {
+ string resultText = Perform().ToString();
+
+ Assert.AreEqual(Name + ": Okay", resultText);
+ }
+
+ public void TestConstruction()
+ {
+ // p-1 not evenly divisible by q
+ try
+ {
+ new JPAKEPrimeOrderGroup(BigInteger.ValueOf(7), BigInteger.ValueOf(5), BigInteger.ValueOf(6));
+
+ Fail("failed to throw exception on p-1 not evenly divisible by q");
+ }
+ catch (ArgumentException)
+ {
+ // expected
+ }
+
+ // g < 2
+ try
+ {
+ new JPAKEPrimeOrderGroup(BigInteger.ValueOf(11), BigInteger.ValueOf(5), BigInteger.ValueOf(1));
+
+ Fail("failed to throw exception on g < 2");
+ }
+ catch (ArgumentException)
+ {
+ // expected
+ }
+
+ // g > p - 1
+ try
+ {
+ new JPAKEPrimeOrderGroup(BigInteger.ValueOf(11), BigInteger.ValueOf(5), BigInteger.ValueOf(11));
+
+ Fail("failed to throw exception on g > p - 1");
+ }
+ catch (ArgumentException)
+ {
+ // expected
+ }
+
+ //g^q mod p not equal 1
+ try
+ {
+ new JPAKEPrimeOrderGroup(BigInteger.ValueOf(11), BigInteger.ValueOf(5), BigInteger.ValueOf(6));
+
+ Fail("failed to throw exception on g^q mod p not equal 1");
+ }
+ catch (ArgumentException)
+ {
+ // expected
+ }
+
+ // p not prime
+ try
+ {
+ new JPAKEPrimeOrderGroup(BigInteger.ValueOf(15), BigInteger.ValueOf(2), BigInteger.ValueOf(4));
+
+ Fail("failed to throw exception on p not prime");
+ }
+ catch (ArgumentException)
+ {
+ // expected
+ }
+
+ // q not prime
+ try
+ {
+ new JPAKEPrimeOrderGroup(BigInteger.ValueOf(7), BigInteger.ValueOf(6), BigInteger.ValueOf(3));
+
+ Fail("failed to throw exception on q not prime");
+ }
+ catch (ArgumentException)
+ {
+ // expected
+ }
+
+ // should succeed
+ new JPAKEPrimeOrderGroup(BigInteger.ValueOf(7), BigInteger.ValueOf(3), BigInteger.ValueOf(4));
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/test/JPAKEUtilTest.cs b/crypto/test/src/crypto/test/JPAKEUtilTest.cs
new file mode 100644
index 000000000..7ac54aba0
--- /dev/null
+++ b/crypto/test/src/crypto/test/JPAKEUtilTest.cs
@@ -0,0 +1,306 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Agreement.Jpake;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+ [TestFixture]
+ public class JPAKEUtilTest
+ : SimpleTest
+ {
+ private static readonly BigInteger Ten = BigInteger.ValueOf(10);
+
+ public override void PerformTest()
+ {
+ TestValidateGx4();
+ TestValidateGa();
+ TestValidateParticipantIdsDiffer();
+ TestValidateParticipantsIdsEqual();
+ TestValidateMacTag();
+ TestValidateNotNull();
+ TestValidateZeroKnowledgeProof();
+ }
+
+ public override string Name
+ {
+ get { return "JPAKEUtil"; }
+ }
+
+ public static void Main(
+ string[] args)
+ {
+ RunTest(new JPAKEUtilTest());
+ }
+
+ [Test]
+ public void TestFunction()
+ {
+ string resultText = Perform().ToString();
+
+ Assert.AreEqual(Name + ": Okay", resultText);
+ }
+
+ public void TestValidateGx4()
+ {
+ JPAKEUtil.ValidateGx4(Ten);
+
+ try
+ {
+ JPAKEUtil.ValidateGx4(BigInteger.One);
+
+ Fail("exception not thrown for g^x4 equal to 1");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+ }
+
+ public void TestValidateGa()
+ {
+ JPAKEUtil.ValidateGa(Ten);
+
+ try
+ {
+ JPAKEUtil.ValidateGa(BigInteger.One);
+
+ Fail("exception not thrown for g^a equal to 1");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+ }
+
+ public void TestValidateParticipantIdsDiffer()
+ {
+ JPAKEUtil.ValidateParticipantIdsDiffer("a", "b");
+ JPAKEUtil.ValidateParticipantIdsDiffer("a", "A");
+
+ try
+ {
+ JPAKEUtil.ValidateParticipantIdsDiffer("a", "a");
+
+ Fail("validate participant ids differ not throwing exception for equal participant ids");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+ }
+
+ public void TestValidateParticipantsIdsEqual()
+ {
+ JPAKEUtil.ValidateParticipantIdsEqual("a", "a");
+
+ try
+ {
+ JPAKEUtil.ValidateParticipantIdsEqual("a", "b");
+
+ Fail("validate participant ids equal not throwing exception for different participant ids");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+ }
+
+ public void TestValidateMacTag()
+ {
+ JPAKEPrimeOrderGroup pg1 = JPAKEPrimeOrderGroups.SUN_JCE_1024;
+
+ SecureRandom random = new SecureRandom();
+ IDigest digest = new Sha256Digest();
+
+ BigInteger x1 = JPAKEUtil.GenerateX1(pg1.Q, random);
+ BigInteger x2 = JPAKEUtil.GenerateX2(pg1.Q, random);
+ BigInteger x3 = JPAKEUtil.GenerateX1(pg1.Q, random);
+ BigInteger x4 = JPAKEUtil.GenerateX2(pg1.Q, random);
+
+ BigInteger gx1 = JPAKEUtil.CalculateGx(pg1.P, pg1.G, x1);
+ BigInteger gx2 = JPAKEUtil.CalculateGx(pg1.P, pg1.G, x2);
+ BigInteger gx3 = JPAKEUtil.CalculateGx(pg1.P, pg1.G, x3);
+ BigInteger gx4 = JPAKEUtil.CalculateGx(pg1.P, pg1.G, x4);
+
+ BigInteger gB = JPAKEUtil.CalculateGA(pg1.P, gx3, gx1, gx2);
+
+ BigInteger s = JPAKEUtil.CalculateS("password".ToCharArray());
+
+ BigInteger xs = JPAKEUtil.CalculateX2s(pg1.Q, x4, s);
+
+ BigInteger B = JPAKEUtil.CalculateA(pg1.P, pg1.Q, gB, xs);
+
+ BigInteger keyingMaterial = JPAKEUtil.CalculateKeyingMaterial(pg1.P, pg1.Q, gx4, x2, s, B);
+
+ BigInteger macTag = JPAKEUtil.CalculateMacTag("participantId", "partnerParticipantId", gx1, gx2, gx3, gx4, keyingMaterial, digest);
+
+ // should succeed
+ JPAKEUtil.ValidateMacTag("partnerParticipantId", "participantId", gx3, gx4, gx1, gx2, keyingMaterial, digest, macTag);
+
+ // validating own macTag (as opposed to the other party's mactag)
+ try
+ {
+ JPAKEUtil.ValidateMacTag("participantId", "partnerParticipantId", gx1, gx2, gx3, gx4, keyingMaterial, digest, macTag);
+
+ Fail("failed to throw exception on validating own macTag (calculated partner macTag)");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // participant ids switched
+ try
+ {
+ JPAKEUtil.ValidateMacTag("participantId", "partnerParticipantId", gx3, gx4, gx1, gx2, keyingMaterial, digest, macTag);
+
+ Fail("failed to throw exception on validating own macTag (calculated partner macTag");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+ }
+
+ public void TestValidateNotNull()
+ {
+ JPAKEUtil.ValidateNotNull("a", "description");
+
+ try
+ {
+ JPAKEUtil.ValidateNotNull(null, "description");
+
+ Fail("failed to throw exception on null");
+ }
+ catch (NullReferenceException)
+ {
+ // expected
+ }
+ }
+
+ public void TestValidateZeroKnowledgeProof()
+ {
+ JPAKEPrimeOrderGroup pg1 = JPAKEPrimeOrderGroups.SUN_JCE_1024;
+
+ SecureRandom random = new SecureRandom();
+ IDigest digest1 = new Sha256Digest();
+
+ BigInteger x1 = JPAKEUtil.GenerateX1(pg1.Q, random);
+ BigInteger gx1 = JPAKEUtil.CalculateGx(pg1.P, pg1.G, x1);
+ string participantId1 = "participant1";
+
+ BigInteger[] zkp1 = JPAKEUtil.CalculateZeroKnowledgeProof(pg1.P, pg1.Q, pg1.G, gx1, x1, participantId1, digest1, random);
+
+ // should succeed
+ JPAKEUtil.ValidateZeroKnowledgeProof(pg1.P, pg1.Q, pg1.G, gx1, zkp1, participantId1, digest1);
+
+ // wrong group
+ JPAKEPrimeOrderGroup pg2 = JPAKEPrimeOrderGroups.NIST_3072;
+ try
+ {
+ JPAKEUtil.ValidateZeroKnowledgeProof(pg2.P, pg2.Q, pg2.G, gx1, zkp1, participantId1, digest1);
+
+ Fail("failed to throw exception on wrong prime order group");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // wrong digest
+ IDigest digest2 = new Sha1Digest();
+ try
+ {
+ JPAKEUtil.ValidateZeroKnowledgeProof(pg1.P, pg1.Q, pg1.G, gx1, zkp1, participantId1, digest2);
+
+ Fail("failed to throw exception on wrong digest");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // wrong participant
+ string participantId2 = "participant2";
+ try
+ {
+ JPAKEUtil.ValidateZeroKnowledgeProof(pg1.P, pg1.Q, pg1.G, gx1, zkp1, participantId2, digest1);
+
+ Fail("failed to throw exception on wrong participant");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // wrong gx
+ BigInteger x2 = JPAKEUtil.GenerateX2(pg1.Q, random);
+ BigInteger gx2 = JPAKEUtil.CalculateGx(pg1.P, pg1.G, x2);
+ try
+ {
+ JPAKEUtil.ValidateZeroKnowledgeProof(pg1.P, pg1.Q, pg1.G, gx2, zkp1, participantId1, digest1);
+
+ Fail("failed to throw exception on wrong gx");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // wrong zkp
+ BigInteger[] zkp2 = JPAKEUtil.CalculateZeroKnowledgeProof(pg1.P, pg1.Q, pg1.G, gx2, x2, participantId1, digest1, random);
+ try
+ {
+ JPAKEUtil.ValidateZeroKnowledgeProof(pg1.P, pg1.Q, pg1.G, gx1, zkp2, participantId1, digest1);
+
+ Fail("failed to throw exception on wrong zero knowledge proof");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // gx <= 0
+ try
+ {
+ JPAKEUtil.ValidateZeroKnowledgeProof(pg1.P, pg1.Q, pg1.G, BigInteger.Zero, zkp1, participantId1, digest1);
+
+ Fail("failed to throw exception on g^x <= 0");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // gx >= p
+ try
+ {
+ JPAKEUtil.ValidateZeroKnowledgeProof(pg1.P, pg1.Q, pg1.G, pg1.P, zkp1, participantId1, digest1);
+
+ Fail("failed to throw exception on g^x >= p");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+
+ // gx mod q == 1
+ try
+ {
+ JPAKEUtil.ValidateZeroKnowledgeProof(pg1.P, pg1.Q, pg1.G, pg1.Q.Add(BigInteger.One), zkp1, participantId1, digest1);
+
+ Fail("failed to throw exception on g^x mod q == 1");
+ }
+ catch (CryptoException)
+ {
+ // expected
+ }
+ }
+ }
+}
|