package org.bouncycastle.tls.crypto.impl.jcajce;

import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;

import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPublicKeySpec;

import org.bouncycastle.jcajce.spec.DHDomainParameterSpec;
import org.bouncycastle.tls.crypto.DHGroup;

class DHUtil
{
    static AlgorithmParameterSpec createInitSpec(DHGroup dhGroup)
    {
        // NOTE: A BC-specific spec, so other providers probably won't see Q 
        return new DHDomainParameterSpec(dhGroup.getP(), dhGroup.getQ(), dhGroup.getG(), dhGroup.getL());
    }

    static KeySpec createPublicKeySpec(BigInteger y, DHParameterSpec dhSpec)
    {
        BigInteger P = dhSpec.getP(), G = dhSpec.getG();

        @SuppressWarnings("unused")
        BigInteger Q = getQ(dhSpec);

        // TODO Need a way to pass Q here (when available)
        return new DHPublicKeySpec(y, P, G);
    }

    static AlgorithmParameters getAlgorithmParameters(JcaTlsCrypto crypto, DHGroup dhGroup)
    {
        return getAlgorithmParameters(crypto, createInitSpec(dhGroup));
    }

    static AlgorithmParameters getAlgorithmParameters(JcaTlsCrypto crypto, AlgorithmParameterSpec initSpec)
    {
        try
        {
            AlgorithmParameters dhAlgParams = crypto.getHelper().createAlgorithmParameters("DiffieHellman");
            dhAlgParams.init(initSpec);

            DHParameterSpec dhSpec = dhAlgParams.getParameterSpec(DHParameterSpec.class);
            if (null != dhSpec)
            {
                return dhAlgParams;
            }
        }
        catch (Exception e)
        {
        }

        return null;
    }

    static DHParameterSpec getDHParameterSpec(JcaTlsCrypto crypto, DHGroup dhGroup)
    {
        return getDHParameterSpec(crypto, createInitSpec(dhGroup));
    }

    static DHParameterSpec getDHParameterSpec(JcaTlsCrypto crypto, AlgorithmParameterSpec initSpec)
    {
        try
        {
            AlgorithmParameters dhAlgParams = crypto.getHelper().createAlgorithmParameters("DiffieHellman");
            dhAlgParams.init(initSpec);

            DHParameterSpec dhSpec = dhAlgParams.getParameterSpec(DHParameterSpec.class);
            if (null != dhSpec)
            {
                return dhSpec;
            }
        }
        catch (Exception e)
        {
        }

        return null;
    }

    static BigInteger getQ(DHParameterSpec dhSpec)
    {
        return dhSpec instanceof DHDomainParameterSpec ? ((DHDomainParameterSpec)dhSpec).getQ() : null;
    }
}

@@ -246,51 +246,68 @@
 ec;%0A
+%0A
 import 
-javax.crypto.spec.DHPublicKey
+org.bouncycastle.jcajce.spec.DHDomainParameter
 Spec;%0A
-%0A
 impo
@@ -336,39 +336,41 @@
 ajce.spec.DH
-DomainParameter
+ExtendedPublicKey
 Spec;%0Aimport
@@ -781,190 +781,77 @@
     
-BigInteger P = dhSpec.getP(), G = dhSpec.getG();%0A%0A        @SuppressWarnings(%22unused%22)%0A        BigInteger Q = getQ(dhSpec);%0A%0A        // TODO Need a way to pass Q here (when available)
+// NOTE: A BC-specific spec, so other providers probably won't see Q 
 %0A   
@@ -868,16 +868,24 @@
 n new DH
+Extended
 PublicKe
@@ -897,12 +897,14 @@
 (y, 
-P, G
+dhSpec
 );%0A 

Use DHExtendedPublicKeySpec to preserve Q