blob: c6ecba22f375551419138412385affd45493cec6 [file] [log] [blame]
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);
}
}