package org.bouncycastle.crypto.agreement.test; import java.math.BigInteger; import java.security.SecureRandom; import junit.framework.TestCase; import org.bouncycastle.crypto.CryptoException; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.agreement.jpake.JPAKEParticipant; import org.bouncycastle.crypto.agreement.jpake.JPAKEPrimeOrderGroup; import org.bouncycastle.crypto.agreement.jpake.JPAKEPrimeOrderGroups; import org.bouncycastle.crypto.agreement.jpake.JPAKERound1Payload; import org.bouncycastle.crypto.agreement.jpake.JPAKERound2Payload; import org.bouncycastle.crypto.agreement.jpake.JPAKERound3Payload; import org.bouncycastle.crypto.agreement.jpake.JPAKEUtil; import org.bouncycastle.crypto.digests.SHA256Digest; public class JPAKEParticipantTest extends TestCase { public void testConstruction() throws CryptoException { JPAKEPrimeOrderGroup group = JPAKEPrimeOrderGroups.SUN_JCE_1024; SecureRandom random = new SecureRandom(); Digest 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(); } catch (NullPointerException e) { // pass } // null password try { new JPAKEParticipant(participantId, null, group, digest, random); fail(); } catch (NullPointerException e) { // pass } // empty password try { new JPAKEParticipant(participantId, "".toCharArray(), group, digest, random); fail(); } catch (IllegalArgumentException e) { // pass } // null group try { new JPAKEParticipant(participantId, password, null, digest, random); fail(); } catch (NullPointerException e) { // pass } // null digest try { new JPAKEParticipant(participantId, password, group, null, random); fail(); } catch (NullPointerException e) { // pass } // null random try { new JPAKEParticipant(participantId, password, group, digest, null); fail(); } catch (NullPointerException e) { // pass } } public void testSuccessfulExchange() throws CryptoException { 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); assertEquals(aliceKeyingMaterial, bobKeyingMaterial); } public void testIncorrectPassword() throws CryptoException { 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(); } catch (CryptoException e) { // pass } try { bob.validateRound3PayloadReceived(aliceRound3Payload, bobKeyingMaterial); fail(); } catch (CryptoException e) { // pass } } /** * Tests that {@link JPAKEParticipant} throws appropriate {@link IllegalStateException}s * when the methods are called in the wrong order. */ public void testStateValidation() throws CryptoException { JPAKEParticipant alice = createAlice(); JPAKEParticipant bob = createBob(); // We're testing alice here. Bob is just used for help. // START ROUND 1 CHECKS assertEquals(JPAKEParticipant.STATE_INITIALIZED, alice.getState()); // create round 2 before round 1 try { alice.createRound2PayloadToSend(); fail(); } catch (IllegalStateException e) { // pass } JPAKERound1Payload aliceRound1Payload = alice.createRound1PayloadToSend(); assertEquals(JPAKEParticipant.STATE_ROUND_1_CREATED, alice.getState()); // create round 1 payload twice try { alice.createRound1PayloadToSend(); fail(); } catch (IllegalStateException e) { // pass } // create round 2 before validating round 1 try { alice.createRound2PayloadToSend(); fail(); } catch (IllegalStateException e) { // pass } // validate round 2 before validating round 1 try { alice.validateRound2PayloadReceived(null); fail(); } catch (IllegalStateException e) { // pass } JPAKERound1Payload bobRound1Payload = bob.createRound1PayloadToSend(); alice.validateRound1PayloadReceived(bobRound1Payload); assertEquals(JPAKEParticipant.STATE_ROUND_1_VALIDATED, alice.getState()); // validate round 1 payload twice try { alice.validateRound1PayloadReceived(bobRound1Payload); fail(); } catch (IllegalStateException e) { // pass } bob.validateRound1PayloadReceived(aliceRound1Payload); // START ROUND 2 CHECKS JPAKERound2Payload aliceRound2Payload = alice.createRound2PayloadToSend(); assertEquals(JPAKEParticipant.STATE_ROUND_2_CREATED, alice.getState()); // create round 2 payload twice try { alice.createRound2PayloadToSend(); fail(); } catch (IllegalStateException e) { // pass } // create key before validating round 2 try { alice.calculateKeyingMaterial(); fail(); } catch (IllegalStateException e) { // pass } // validate round 3 before validating round 2 try { alice.validateRound3PayloadReceived(null, null); fail(); } catch (IllegalStateException e) { // pass } JPAKERound2Payload bobRound2Payload = bob.createRound2PayloadToSend(); alice.validateRound2PayloadReceived(bobRound2Payload); assertEquals(JPAKEParticipant.STATE_ROUND_2_VALIDATED, alice.getState()); // validate round 2 payload twice try { alice.validateRound2PayloadReceived(bobRound2Payload); fail(); } catch (IllegalStateException e) { // pass } bob.validateRound2PayloadReceived(aliceRound2Payload); // create round 3 before calculating key try { alice.createRound3PayloadToSend(BigInteger.ONE); fail(); } catch (IllegalStateException e) { // pass } // START KEY CALCULATION CHECKS BigInteger aliceKeyingMaterial = alice.calculateKeyingMaterial(); assertEquals(JPAKEParticipant.STATE_KEY_CALCULATED, alice.getState()); // calculate key twice try { alice.calculateKeyingMaterial(); fail(); } catch (IllegalStateException e) { // pass } BigInteger bobKeyingMaterial = bob.calculateKeyingMaterial(); // START ROUND 3 CHECKS JPAKERound3Payload aliceRound3Payload = alice.createRound3PayloadToSend(aliceKeyingMaterial); assertEquals(JPAKEParticipant.STATE_ROUND_3_CREATED, alice.getState()); // create round 3 payload twice try { alice.createRound3PayloadToSend(aliceKeyingMaterial); fail(); } catch (IllegalStateException e) { // pass } JPAKERound3Payload bobRound3Payload = bob.createRound3PayloadToSend(bobKeyingMaterial); alice.validateRound3PayloadReceived(bobRound3Payload, aliceKeyingMaterial); assertEquals(JPAKEParticipant.STATE_ROUND_3_VALIDATED, alice.getState()); // validate round 3 payload twice try { alice.validateRound3PayloadReceived(bobRound3Payload, aliceKeyingMaterial); fail(); } catch (IllegalStateException e) { // pass } bob.validateRound3PayloadReceived(aliceRound3Payload, bobKeyingMaterial); } /** * Tests that {@link JPAKEParticipant#validateRound1PayloadReceived(JPAKERound1Payload)} * calls the appropriate validate methods in {@link JPAKEUtil}. * Note that {@link JPAKEUtilTest} tests the individual validate methods * called by {@link JPAKEParticipant} more extensively. */ public void testValidateRound1PayloadReceived() throws CryptoException { // 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(); } catch (CryptoException e) { // pass } // g^x4 == 1 try { createAlice().validateRound1PayloadReceived(new JPAKERound1Payload( bobRound1Payload.getParticipantId(), bobRound1Payload.getGx1(), BigInteger.ONE, bobRound1Payload.getKnowledgeProofForX1(), bobRound1Payload.getKnowledgeProofForX2())); fail(); } catch (CryptoException e) { // pass } // zero knowledge proof for x3 fails try { JPAKERound1Payload bobRound1Payload2 = createBob().createRound1PayloadToSend(); createAlice().validateRound1PayloadReceived(new JPAKERound1Payload( bobRound1Payload.getParticipantId(), bobRound1Payload.getGx1(), bobRound1Payload.getGx2(), bobRound1Payload2.getKnowledgeProofForX1(), bobRound1Payload.getKnowledgeProofForX2())); fail(); } catch (CryptoException e) { // pass } // zero knowledge proof for x4 fails try { JPAKERound1Payload bobRound1Payload2 = createBob().createRound1PayloadToSend(); createAlice().validateRound1PayloadReceived(new JPAKERound1Payload( bobRound1Payload.getParticipantId(), bobRound1Payload.getGx1(), bobRound1Payload.getGx2(), bobRound1Payload.getKnowledgeProofForX1(), bobRound1Payload2.getKnowledgeProofForX2())); fail(); } catch (CryptoException e) { // pass } } /** * Tests that {@link JPAKEParticipant#validateRound2PayloadReceived(JPAKERound2Payload)} * calls the appropriate validate methods in {@link JPAKEUtil}. * Note that {@link JPAKEUtilTest} tests the individual validate methods * called by {@link JPAKEParticipant} more extensively. */ public void testValidateRound2PayloadReceived() throws CryptoException { // We're testing alice here. Bob is just used for help. // should succeed ExchangeAfterRound2Creation exchange1 = runExchangeUntilRound2Creation(createAlice(), createBob()); exchange1.alice.validateRound2PayloadReceived(exchange1.bobRound2Payload); // alice verifies alice's payload ExchangeAfterRound2Creation exchange2 = runExchangeUntilRound2Creation(createAlice(), createBob()); try { exchange2.alice.validateRound2PayloadReceived(exchange2.aliceRound2Payload); fail(); } catch (CryptoException e) { // pass } // wrong z ExchangeAfterRound2Creation exchange3 = runExchangeUntilRound2Creation(createAlice(), createBob()); ExchangeAfterRound2Creation exchange4 = runExchangeUntilRound2Creation(createAlice(), createBob()); try { exchange3.alice.validateRound2PayloadReceived(exchange4.bobRound2Payload); fail(); } catch (CryptoException e) { // pass } } private static 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) throws CryptoException { 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); } }