blob: ad2c6aead6505ec1ec6a5558969d17b9e30ed88c [file] [log] [blame]
package org.bouncycastle.crypto.agreement.jpake;
import java.math.BigInteger;
/**
* A pre-computed prime order group for use during a J-PAKE exchange.
* <p>
* Typically a Schnorr group is used. In general, J-PAKE can use any prime order group
* that is suitable for public key cryptography, including elliptic curve cryptography.
* <p>
* See {@link JPAKEPrimeOrderGroups} for convenient standard groups.
* <p>
* NIST <a href="http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/DSA2_All.pdf">publishes</a>
* many groups that can be used for the desired level of security.
*/
public class JPAKEPrimeOrderGroup
{
private final BigInteger p;
private final BigInteger q;
private final BigInteger g;
/**
* Constructs a new {@link JPAKEPrimeOrderGroup}.
* <p>
* In general, you should use one of the pre-approved groups from
* {@link JPAKEPrimeOrderGroups}, rather than manually constructing one.
* <p>
* The following basic checks are performed:
* <ul>
* <li>p-1 must be evenly divisible by q</li>
* <li>g must be in [2, p-1]</li>
* <li>g^q mod p must equal 1</li>
* <li>p must be prime (within reasonably certainty)</li>
* <li>q must be prime (within reasonably certainty)</li>
* </ul>
* <p>
* The prime checks are performed using {@link BigInteger#isProbablePrime(int)},
* and are therefore subject to the same probability guarantees.
* <p>
* These checks prevent trivial mistakes.
* However, due to the small uncertainties if p and q are not prime,
* advanced attacks are not prevented.
* Use it at your own risk.
*
* @throws NullPointerException if any argument is null
* @throws IllegalArgumentException if any of the above validations fail
*/
public JPAKEPrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g)
{
/*
* Don't skip the checks on user-specified groups.
*/
this(p, q, g, false);
}
/**
* Internal package-private constructor used by the pre-approved
* groups in {@link JPAKEPrimeOrderGroups}.
* These pre-approved groups can avoid the expensive checks.
*/
JPAKEPrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g, boolean skipChecks)
{
JPAKEUtil.validateNotNull(p, "p");
JPAKEUtil.validateNotNull(q, "q");
JPAKEUtil.validateNotNull(g, "g");
if (!skipChecks)
{
if (!p.subtract(JPAKEUtil.ONE).mod(q).equals(JPAKEUtil.ZERO))
{
throw new IllegalArgumentException("p-1 must be evenly divisible by q");
}
if (g.compareTo(BigInteger.valueOf(2)) == -1 || g.compareTo(p.subtract(JPAKEUtil.ONE)) == 1)
{
throw new IllegalArgumentException("g must be in [2, p-1]");
}
if (!g.modPow(q, p).equals(JPAKEUtil.ONE))
{
throw new IllegalArgumentException("g^q mod p must equal 1");
}
/*
* Note that these checks do not guarantee that p and q are prime.
* We just have reasonable certainty that they are prime.
*/
if (!p.isProbablePrime(20))
{
throw new IllegalArgumentException("p must be prime");
}
if (!q.isProbablePrime(20))
{
throw new IllegalArgumentException("q must be prime");
}
}
this.p = p;
this.q = q;
this.g = g;
}
public BigInteger getP()
{
return p;
}
public BigInteger getQ()
{
return q;
}
public BigInteger getG()
{
return g;
}
}