package org.bouncycastle.crypto.generators;

import org.bouncycastle.crypto.params.DHParameters;

import java.math.BigInteger;
import java.security.SecureRandom;

public class DHParametersGenerator
{
    private int             size;
    private int             certainty;
    private SecureRandom    random;

    private static final BigInteger ONE = BigInteger.valueOf(1);
    private static final BigInteger TWO = BigInteger.valueOf(2);

    /**
     * Initialise the parameters generator.
     * 
     * @param size bit length for the prime p
     * @param certainty level of certainty for the prime number tests
     * @param random  a source of randomness
     */
    public void init(
        int             size,
        int             certainty,
        SecureRandom    random)
    {
        this.size = size;
        this.certainty = certainty;
        this.random = random;
    }

    /**
     * which generates the p and g values from the given parameters,
     * returning the DHParameters object.
     * <p>
     * Note: can take a while...
     */
    public DHParameters generateParameters()
    {
        //
        // find a safe prime p where p = 2*q + 1, where p and q are prime.
        //
        BigInteger[] safePrimes = DHParametersHelper.generateSafePrimes(size, certainty, random);

        BigInteger p = safePrimes[0];
        BigInteger q = safePrimes[1];

        BigInteger g;
        int qLength = size - 1;

        //
        // calculate the generator g - the advantage of using the 2q+1 
        // approach is that we know the prime factorisation of (p - 1)...
        //
        for (;;)
        {
            g = new BigInteger(qLength, random);

            if (g.modPow(TWO, p).equals(ONE))
            {
                continue;
            }

            if (g.modPow(q, p).equals(ONE))
            {
                continue;
            }

            break;
        }

        return new DHParameters(p, g, q, TWO, null);
    }
}

@@ -1405,41 +1405,57 @@
 ger 
-g;%0A        int qLength = size - 1
+pMinusTwo = p.subtract(TWO);%0A        BigInteger g
 ;%0A%0A 
@@ -1621,24 +1621,25 @@
      //%0A
+%0A
         
 for (;;)
@@ -1634,65 +1634,114 @@
     
-for (;;)%0A        %7B%0A            g = new BigInteger(qLength
+// Handbook of Applied Cryptography 4.86%0A        do%0A        %7B%0A            g = createInRange(TWO, pMinusTwo
 , ra
@@ -1747,25 +1747,24 @@
 andom);%0A
-%0A
         
     if (
@@ -1747,38 +1747,47 @@
 andom);%0A        
+%7D%0A
     
-if
+    while
  (g.modPow(TWO, 
@@ -1792,33 +1792,32 @@
 , p).equals(ONE)
-)
 %0A            %7B%0A 
@@ -1817,76 +1817,231 @@
     
-%7B%0A                continue;%0A            %7D%0A%0A            if (g
+%7C%7C g.modPow(q, p).equals(ONE));%0A%0A/*%0A        // RFC 2631 2.1.1 (and see Handbook of Applied Cryptography 4.81)%0A        do%0A        %7B%0A            BigInteger h = createInRange(TWO, pMinusTwo, random);%0A%0A            g = h
 .modPow(
 q, p
@@ -2028,37 +2028,67 @@
    g = h.modPow(
-q
+TWO
 , p)
+;%0A        %7D%0A        while (g
 .equals(ONE))%0A  
@@ -2084,16 +2084,21 @@
 ls(ONE))
+;%0A*/%0A
 %0A       
@@ -2102,38 +2102,221 @@
     
-    %7B%0A                continue
+return new DHParameters(p, g, q, TWO, null);%0A    %7D%0A%0A    private static BigInteger createInRange(%0A        BigInteger      min,%0A        BigInteger      max,%0A        SecureRandom    random)%0A    %7B%0A        BigInteger x
 ;%0A  
@@ -2317,30 +2317,36 @@
  x;%0A        
+do%0A
     
-%7D%0A
+    %7B
 %0A           
@@ -2350,13 +2350,51 @@
     
-break
+x = new BigInteger(max.bitLength(), random)
 ;%0A  
@@ -2401,25 +2401,24 @@
       %7D%0A
-%0A
         
 return n
@@ -2413,51 +2413,78 @@
     
-return new DHParameters(p, g, q, TWO, null)
+while (x.compareTo(min) %3C 0 %7C%7C x.compareTo(max) %3E 0);%0A        return x
 ;%0A  

Fix the selection of g per Handbook of Applied Cryptography 4.86 Add alternate selection method (commented out) per RFC 2631