All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.crypto.fips.FipsDH Maven / Gradle / Ivy

Go to download

The FIPS 140-3 Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms certified to FIPS 140-3 level 1. This jar contains JCE provider and low-level API for the BC-FJA version 2.0.0, FIPS Certificate #4743. Please see certificate for certified platform details.

There is a newer version: 2.0.0
Show newest version
package org.bouncycastle.crypto.fips;

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

import org.bouncycastle.crypto.AsymmetricPrivateKey;
import org.bouncycastle.crypto.AsymmetricPublicKey;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.asymmetric.AsymmetricDHPrivateKey;
import org.bouncycastle.crypto.asymmetric.AsymmetricDHPublicKey;
import org.bouncycastle.crypto.asymmetric.AsymmetricKeyPair;
import org.bouncycastle.crypto.asymmetric.DHDomainParameters;
import org.bouncycastle.crypto.asymmetric.DHValidationParameters;
import org.bouncycastle.crypto.asymmetric.DSADomainParameters;
import org.bouncycastle.crypto.asymmetric.DSAValidationParameters;
import org.bouncycastle.crypto.internal.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.internal.PrimeCertaintyCalculator;
import org.bouncycastle.crypto.internal.params.DhKeyGenerationParameters;
import org.bouncycastle.crypto.internal.params.DhParameters;
import org.bouncycastle.crypto.internal.params.DhPrivateKeyParameters;
import org.bouncycastle.crypto.internal.params.DhPublicKeyParameters;
import org.bouncycastle.crypto.internal.params.DhuPrivateParameters;
import org.bouncycastle.crypto.internal.params.DhuPublicParameters;
import org.bouncycastle.crypto.internal.params.MqvPrivateParameters;
import org.bouncycastle.crypto.internal.params.MqvPublicParameters;
import org.bouncycastle.crypto.internal.test.ConsistencyTest;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;

/**
 * Source class for FIPS approved mode Diffie-Hellman implementations.
 */
public final class FipsDH
{
    private static final int MIN_FIPS_KEY_STRENGTH = 2048;       // 112 bits of security

    static final FipsEngineProvider AGREEMENT_PROVIDER;
    static final FipsEngineProvider MQV_PROVIDER;
    static final FipsEngineProvider DHU_PROVIDER;

    private enum Variations
    {
        DH,
        MQV,
        DHU
    }

    /**
     * Basic Diffie-Hellman key marker, can be used for creating general purpose Diffie-Hellman keys.
     */
    public static final FipsAlgorithm ALGORITHM = new FipsAlgorithm("DH");

    private static final FipsAlgorithm ALGORITHM_DH = new FipsAlgorithm("DH", Variations.DH);
    private static final FipsAlgorithm ALGORITHM_MQV = new FipsAlgorithm("DH", Variations.MQV);
    private static final FipsAlgorithm ALGORITHM_DHU = new FipsAlgorithm("DH", Variations.DHU);

    /**
     * Regular Diffie-Hellman algorithm marker.
     */
    public static final AgreementParameters DH = new AgreementParameters();
    /**
     * Regular MQV algorithm marker.
     */
    public static final MQVAgreementParametersBuilder MQV = new MQVAgreementParametersBuilder();

    /**
     * Unified Diffie-Hellman algorithm marker.
     */
    public static final DHUAgreementParametersBuilder DHU = new DHUAgreementParametersBuilder();
    
    static
    {
        AGREEMENT_PROVIDER = new AgreementProvider();
        MQV_PROVIDER = new MqvProvider();
        DHU_PROVIDER = new DhuProvider();

        // FSM_STATE:3.DH.0,"FF AGREEMENT KAT", "The module is performing FF Key Agreement verify KAT self-test"
        // FSM_TRANS:3.DH.0,"POWER ON SELF-TEST", "FF AGREEMENT KAT", "Invoke FF Diffie-Hellman/MQV  KAT self-test"
        AGREEMENT_PROVIDER.createEngine();
        MQV_PROVIDER.createEngine();
        DHU_PROVIDER.createEngine();
        // FSM_TRANS:3.DH.1,"FF AGREEMENT KAT", "POWER ON SELF-TEST", "FF Diffie-Hellman/MQV KAT self-test successful completion"

        // FSM_STATE:3.DH.1,"KAS CVL Primitive 'Z' computation KAT", "The module is performing KAS CVL Primitive 'Z' computation KAT verify KAT self-test"
        // FSM_TRANS:3.DH.2,"POWER ON SELF-TEST", "KAS CVL Primitive 'Z' computation KAT", "Invoke KAS CVL Primitive 'Z' computation KAT self-test"
        ffPrimitiveZTest();
        // FSM_TRANS:3.DH.3,"KAS CVL Primitive 'Z' computation KAT", "POWER ON SELF-TEST", "KAS CVL Primitive 'Z' computation KAT self-test successful completion"
    }

    private FipsDH()
    {

    }

    /**
     * Parameters for Diffie-Hellman key pair generation.
     */
    public static final class KeyGenParameters
        extends FipsParameters
    {
        private final DHDomainParameters domainParameters;

        /**
         * Constructor for the default algorithm ID.
         *
         * @param domainParameters Diffie-Hellman domain parameters any generated keys will be for.
         */
        public KeyGenParameters(DHDomainParameters domainParameters)
        {
            this(ALGORITHM, domainParameters);
        }

        /**
         * Base constructor for specifying an algorithm ID from a parameter set.
         *
         * @param parameters       the parameters containing the algorithm the generated keys are for.
         * @param domainParameters Diffie-Hellman domain parameters any generated keys will be for.
         */
        public KeyGenParameters(AgreementParameters parameters, DHDomainParameters domainParameters)
        {
            this(parameters.getAlgorithm(), domainParameters);
        }

        /**
         * Base constructor for specifying an algorithm ID from an MQV builder.
         *
         * @param builder        the parameters containing the algorithm the generated keys are for.
         * @param domainParameters Diffie-Hellman domain parameters any generated keys will be for.
         */
        public KeyGenParameters(MQVAgreementParametersBuilder builder, DHDomainParameters domainParameters)
        {
            this(builder.getAlgorithm(), domainParameters);
        }

        /**
         * Base constructor for specifying an algorithm ID from an Diffie-Hellman Unified builder.
         *
         * @param builder        the parameters containing the algorithm the generated keys are for.
         * @param domainParameters Diffie-Hellman domain parameters any generated keys will be for.
         */
        public KeyGenParameters(DHUAgreementParametersBuilder builder, DHDomainParameters domainParameters)
        {
            this(builder.getAlgorithm(), domainParameters);
        }

        /**
         * Base constructor for specifying an algorithm ID.
         *
         * @param algorithm        the particular algorithm generated keys are for.
         * @param domainParameters Diffie-Hellman domain parameters any generated keys will be for.
         */
        private KeyGenParameters(FipsAlgorithm algorithm, DHDomainParameters domainParameters)
        {
            super(algorithm);
            this.domainParameters = domainParameters;
        }

        /**
         * Return the Diffie-Hellman domain parameters for this object.
         *
         * @return the Diffie-Hellman domain parameter set.
         */
        public DHDomainParameters getDomainParameters()
        {
            return domainParameters;
        }
    }

    /**
     * Parameters for Diffie-Hellman based key agreement.
     */
    public static final class AgreementParameters
        extends FipsAgreementParameters
    {
        /**
         * Default constructor which specifies returning the raw secret on agreement calculation.
         */
        AgreementParameters()
        {
            this(null);
        }

        private AgreementParameters(FipsAlgorithm digestAlgorithm)
        {
            super(ALGORITHM, digestAlgorithm);
        }

        private AgreementParameters(FipsKDF.PRF prfAlgorithm, byte[] salt)
        {
            super(ALGORITHM, prfAlgorithm, salt);
        }

        private AgreementParameters(FipsAlgorithm agreementAlgorithm, FipsKDF.AgreementKDFParametersBuilder kdfType, byte[] iv, int outputSize)
        {
            super(agreementAlgorithm, kdfType, iv, outputSize);
        }

        /**
         * Add a digest algorithm to process the Z value with.
         *
         * @param digestAlgorithm digest algorithm to use.
         * @return a new parameter set, including the digest algorithm
         */
        public AgreementParameters withDigest(FipsAlgorithm digestAlgorithm)
        {
            return new AgreementParameters(digestAlgorithm);
        }

        /**
         * Add a PRF algorithm and salt to process the Z value with (as in SP 800-56C)
         *
         * @param prfAlgorithm PRF represent the MAC/HMAC algorithm to use.
         * @param salt         the salt to use to initialise the PRF
         * @return a new parameter set, including the digest algorithm
         */
        public AgreementParameters withPRF(FipsKDF.PRF prfAlgorithm, byte[] salt)
        {
            return new AgreementParameters(prfAlgorithm, salt);
        }

        /**
         * Add a KDF to process the Z value with. The outputSize parameter determines how many bytes
         * will be generated.
         *
         * @param kdfType            KDF algorithm type to use for parameter creation.
         * @param iv                 the iv parameter for KDF initialization.
         * @param outputSize         the size of the output to be generated from the KDF.
         * @return a new parameter set, the KDF definition.
         */
        public AgreementParameters withKDF(FipsKDF.AgreementKDFParametersBuilder kdfType, byte[] iv, int outputSize)
        {
            return new AgreementParameters(this.getAlgorithm(), kdfType, iv, outputSize);
        }
    }

    /**
     * Initial builder for MQV parameters.
     */
    public static final class MQVAgreementParametersBuilder
        extends FipsParameters
    {
        MQVAgreementParametersBuilder()
        {
            super(ALGORITHM_MQV);
        }

        /**
         * Constructor for DH MQV parameters from an ephemeral public/private key pair. This constructor
         * will result in an agreement which returns the raw calculated agreement value, or shared secret.
         *
         * @param ephemeralKeyPair       our ephemeral public/private key pair.
         * @param otherPartyEphemeralKey the other party's ephemeral public key.
         */
        public MQVAgreementParameters using(AsymmetricKeyPair ephemeralKeyPair, AsymmetricDHPublicKey otherPartyEphemeralKey)
        {
            return new MQVAgreementParameters((AsymmetricDHPublicKey)ephemeralKeyPair.getPublicKey(), (AsymmetricDHPrivateKey)ephemeralKeyPair.getPrivateKey(), otherPartyEphemeralKey, null);
        }

        /**
         * Constructor for DH MQV parameters which assumes later calculation of our ephemeral public key. This constructor
         * will result in an agreement which returns the raw calculated agreement value, or shared secret.
         *
         * @param ephemeralPrivateKey    our ephemeral private key.
         * @param otherPartyEphemeralKey the other party's ephemeral public key.
         */
        public MQVAgreementParameters using(AsymmetricDHPrivateKey ephemeralPrivateKey, AsymmetricDHPublicKey otherPartyEphemeralKey)
        {
            return new MQVAgreementParameters(null, ephemeralPrivateKey, otherPartyEphemeralKey, null);
        }

        /**
         * Constructor for DH MQV parameters which results in an agreement returning the raw value.
         *
         * @param ephemeralPublicKey     our ephemeral public key.
         * @param ephemeralPrivateKey    our ephemeral private key.
         * @param otherPartyEphemeralKey the other party's ephemeral public key.
         */
        public MQVAgreementParameters using(AsymmetricDHPublicKey ephemeralPublicKey, AsymmetricDHPrivateKey ephemeralPrivateKey, AsymmetricDHPublicKey otherPartyEphemeralKey)
        {
            return new MQVAgreementParameters(ephemeralPublicKey, ephemeralPrivateKey, otherPartyEphemeralKey, null);
        }
    }

    /**
     * Parameters for Diffie-Hellman based key agreement using MQV.
     */
    public static final class MQVAgreementParameters
        extends FipsAgreementParameters
    {
        private final AsymmetricDHPublicKey ephemeralPublicKey;
        private final AsymmetricDHPrivateKey ephemeralPrivateKey;
        private final AsymmetricDHPublicKey otherPartyEphemeralKey;

        private MQVAgreementParameters(AsymmetricDHPublicKey ephemeralPublicKey, AsymmetricDHPrivateKey ephemeralPrivateKey, AsymmetricDHPublicKey otherPartyEphemeralKey, FipsAlgorithm digestAlgorithm)
        {
            super(ALGORITHM_MQV, digestAlgorithm);

            this.ephemeralPublicKey = ephemeralPublicKey;
            this.ephemeralPrivateKey = ephemeralPrivateKey;
            this.otherPartyEphemeralKey = otherPartyEphemeralKey;
        }

        private MQVAgreementParameters(AsymmetricDHPublicKey ephemeralPublicKey, AsymmetricDHPrivateKey ephemeralPrivateKey, AsymmetricDHPublicKey otherPartyEphemeralKey, FipsKDF.PRF prfAlgorithm, byte[] salt)
        {
            super(ALGORITHM_MQV, prfAlgorithm, salt);

            this.ephemeralPublicKey = ephemeralPublicKey;
            this.ephemeralPrivateKey = ephemeralPrivateKey;
            this.otherPartyEphemeralKey = otherPartyEphemeralKey;
        }

        private MQVAgreementParameters(AsymmetricDHPublicKey ephemeralPublicKey, AsymmetricDHPrivateKey ephemeralPrivateKey, AsymmetricDHPublicKey otherPartyEphemeralKey, FipsKDF.AgreementKDFParametersBuilder kdfType, byte[] iv, int outputSize)
        {
            super(ALGORITHM_MQV, kdfType, iv, outputSize);

            this.ephemeralPublicKey = ephemeralPublicKey;
            this.ephemeralPrivateKey = ephemeralPrivateKey;
            this.otherPartyEphemeralKey = otherPartyEphemeralKey;
        }

        /**
         * Return our ephemeral public key, if present.
         *
         * @return our ephemeral public key, or null.
         */
        public AsymmetricDHPublicKey getEphemeralPublicKey()
        {
            return ephemeralPublicKey;
        }

        /**
         * Return our ephemeral private key.
         *
         * @return our ephemeral private key.
         */
        public AsymmetricDHPrivateKey getEphemeralPrivateKey()
        {
            return ephemeralPrivateKey;
        }

        /**
         * Return the other party's ephemeral public key.
         *
         * @return the other party's ephemeral public key.
         */
        public AsymmetricDHPublicKey getOtherPartyEphemeralKey()
        {
            return otherPartyEphemeralKey;
        }

        /**
         * Add a digest algorithm to process the Z value with.
         *
         * @param digestAlgorithm digest algorithm to use.
         * @return a new parameter set, including the digest algorithm
         */
        public MQVAgreementParameters withDigest(FipsAlgorithm digestAlgorithm)
        {
            return new MQVAgreementParameters(this.ephemeralPublicKey, this.ephemeralPrivateKey, this.otherPartyEphemeralKey, digestAlgorithm);
        }

        /**
         * Add a PRF algorithm and salt to process the Z value with (as in SP 800-56C)
         *
         * @param prfAlgorithm PRF represent the MAC/HMAC algorithm to use.
         * @param salt         the salt to use to initialise the PRF
         * @return a new parameter set, including the digest algorithm
         */
        public MQVAgreementParameters withPRF(FipsKDF.PRF prfAlgorithm, byte[] salt)
        {
            return new MQVAgreementParameters(this.ephemeralPublicKey, this.ephemeralPrivateKey, this.otherPartyEphemeralKey, prfAlgorithm, salt);
        }

        /**
         * Add a KDF to process the Z value with. The outputSize parameter determines how many bytes
         * will be generated.
         *
         * @param kdfType            KDF algorithm type to use for parameter creation.
         * @param iv                 the iv parameter for KDF initialization.
         * @param outputSize         the size of the output to be generated from the KDF.
         * @return a new parameter set, the KDF definition.
         */
        public MQVAgreementParameters withKDF(FipsKDF.AgreementKDFParametersBuilder kdfType, byte[] iv, int outputSize)
        {
            return new MQVAgreementParameters(this.ephemeralPublicKey, this.ephemeralPrivateKey, this.otherPartyEphemeralKey, kdfType, iv, outputSize);
        }
    }

    /**
     * Initial builder for DHU parameters.
     */
    public static final class DHUAgreementParametersBuilder
        extends FipsParameters
    {
        DHUAgreementParametersBuilder()
        {
            super(ALGORITHM_DHU);
        }

        /**
         * Constructor for DH DHU parameters from an ephemeral public/private key pair. This constructor
         * will result in an agreement which returns the raw calculated agreement value, or shared secret.
         *
         * @param ephemeralKeyPair       our ephemeral public/private key pair.
         * @param otherPartyEphemeralKey the other party's ephemeral public key.
         */
        public DHUAgreementParameters using(AsymmetricKeyPair ephemeralKeyPair, AsymmetricDHPublicKey otherPartyEphemeralKey)
        {
            return new DHUAgreementParameters((AsymmetricDHPublicKey)ephemeralKeyPair.getPublicKey(), (AsymmetricDHPrivateKey)ephemeralKeyPair.getPrivateKey(), otherPartyEphemeralKey, null);
        }

        /**
         * Constructor for DH DHU parameters which assumes later calculation of our ephemeral public key. This constructor
         * will result in an agreement which returns the raw calculated agreement value, or shared secret.
         *
         * @param ephemeralPrivateKey    our ephemeral private key.
         * @param otherPartyEphemeralKey the other party's ephemeral public key.
         */
        public DHUAgreementParameters using(AsymmetricDHPrivateKey ephemeralPrivateKey, AsymmetricDHPublicKey otherPartyEphemeralKey)
        {
            return new DHUAgreementParameters(null, ephemeralPrivateKey, otherPartyEphemeralKey, null);
        }

        /**
         * Constructor for DH DHU parameters which results in an agreement returning the raw value.
         *
         * @param ephemeralPublicKey     our ephemeral public key.
         * @param ephemeralPrivateKey    our ephemeral private key.
         * @param otherPartyEphemeralKey the other party's ephemeral public key.
         */
        public DHUAgreementParameters using(AsymmetricDHPublicKey ephemeralPublicKey, AsymmetricDHPrivateKey ephemeralPrivateKey, AsymmetricDHPublicKey otherPartyEphemeralKey)
        {
            return new DHUAgreementParameters(ephemeralPublicKey, ephemeralPrivateKey, otherPartyEphemeralKey, null);
        }
    }

    /**
     * Parameters for Diffie-Hellman based key agreement using DHU.
     */
    public static final class DHUAgreementParameters
        extends FipsAgreementParameters
    {
        private final AsymmetricDHPublicKey ephemeralPublicKey;
        private final AsymmetricDHPrivateKey ephemeralPrivateKey;
        private final AsymmetricDHPublicKey otherPartyEphemeralKey;

        private DHUAgreementParameters(AsymmetricDHPublicKey ephemeralPublicKey, AsymmetricDHPrivateKey ephemeralPrivateKey, AsymmetricDHPublicKey otherPartyEphemeralKey, FipsAlgorithm digestAlgorithm)
        {
            super(ALGORITHM_DHU, digestAlgorithm);

            this.ephemeralPublicKey = ephemeralPublicKey;
            this.ephemeralPrivateKey = ephemeralPrivateKey;
            this.otherPartyEphemeralKey = otherPartyEphemeralKey;
        }

        private DHUAgreementParameters(AsymmetricDHPublicKey ephemeralPublicKey, AsymmetricDHPrivateKey ephemeralPrivateKey, AsymmetricDHPublicKey otherPartyEphemeralKey, FipsKDF.PRF prfAlgorithm, byte[] salt)
        {
            super(ALGORITHM_DHU, prfAlgorithm, salt);

            this.ephemeralPublicKey = ephemeralPublicKey;
            this.ephemeralPrivateKey = ephemeralPrivateKey;
            this.otherPartyEphemeralKey = otherPartyEphemeralKey;
        }

        private DHUAgreementParameters(AsymmetricDHPublicKey ephemeralPublicKey, AsymmetricDHPrivateKey ephemeralPrivateKey, AsymmetricDHPublicKey otherPartyEphemeralKey, FipsKDF.AgreementKDFParametersBuilder kdfType, byte[] iv, int outputSize)
        {
            super(ALGORITHM_DHU, kdfType, iv, outputSize);

            this.ephemeralPublicKey = ephemeralPublicKey;
            this.ephemeralPrivateKey = ephemeralPrivateKey;
            this.otherPartyEphemeralKey = otherPartyEphemeralKey;
        }

        /**
         * Return our ephemeral public key, if present.
         *
         * @return our ephemeral public key, or null.
         */
        public AsymmetricDHPublicKey getEphemeralPublicKey()
        {
            return ephemeralPublicKey;
        }

        /**
         * Return our ephemeral private key.
         *
         * @return our ephemeral private key.
         */
        public AsymmetricDHPrivateKey getEphemeralPrivateKey()
        {
            return ephemeralPrivateKey;
        }

        /**
         * Return the other party's ephemeral public key.
         *
         * @return the other party's ephemeral public key.
         */
        public AsymmetricDHPublicKey getOtherPartyEphemeralKey()
        {
            return otherPartyEphemeralKey;
        }

        /**
         * Add a digest algorithm to process the Z value with.
         *
         * @param digestAlgorithm digest algorithm to use.
         * @return a new parameter set, including the digest algorithm
         */
        public DHUAgreementParameters withDigest(FipsAlgorithm digestAlgorithm)
        {
            return new DHUAgreementParameters(this.ephemeralPublicKey, this.ephemeralPrivateKey, this.otherPartyEphemeralKey, digestAlgorithm);
        }

        /**
         * Add a PRF algorithm and salt to process the Z value with (as in SP 800-56C)
         *
         * @param prfAlgorithm PRF represent the MAC/HMAC algorithm to use.
         * @param salt         the salt to use to initialise the PRF
         * @return a new parameter set, including the digest algorithm
         */
        public DHUAgreementParameters withPRF(FipsKDF.PRF prfAlgorithm, byte[] salt)
        {
            return new DHUAgreementParameters(this.ephemeralPublicKey, this.ephemeralPrivateKey, this.otherPartyEphemeralKey, prfAlgorithm, salt);
        }

        /**
         * Add a KDF to process the Z value with. The outputSize parameter determines how many bytes
         * will be generated.
         *
         * @param kdfType            KDF algorithm type to use for parameter creation.
         * @param iv                 the iv parameter for KDF initialization.
         * @param outputSize         the size of the output to be generated from the KDF.
         * @return a new parameter set, the KDF definition.
         */
        public DHUAgreementParameters withKDF(FipsKDF.AgreementKDFParametersBuilder kdfType, byte[] iv, int outputSize)
        {
            return new DHUAgreementParameters(this.ephemeralPublicKey, this.ephemeralPrivateKey, this.otherPartyEphemeralKey, kdfType, iv, outputSize);
        }
    }
    
    /**
     * Parameters for generating Diffie-Hellman domain parameters.
     */
    public static final class DomainGenParameters
        extends FipsParameters
    {
        private final int L;
        private final int N;
        private final int certainty;

        private final BigInteger p;
        private final BigInteger q;
        private final byte[] seed;
        private final int usageIndex;

        /**
         * Construct just from strength (L) with a default value for N (160 for 1024, 256 for greater)
         * and a default certainty.
         *
         * @param strength desired length of prime P in bits (the effective key size).
         */
        public DomainGenParameters(int strength)
        {
            this(strength, (strength > 1024) ? 256 : 160, PrimeCertaintyCalculator.getDefaultCertainty(strength));      // Valid N for 2048/3072 , N for 1024
        }

        /**
         * Construct just from strength (L) with a default value for N (160 for 1024, 256 for greater).
         *
         * @param strength  desired length of prime P in bits (the effective key size).
         * @param certainty certainty level for prime number generation.
         */
        public DomainGenParameters(int strength, int certainty)
        {
            this(strength, (strength > 1024) ? 256 : 160, certainty);            // Valid N for 2048/3072 , N for 1024
        }

        /**
         * Construct without a usage index, this will do a random construction of G.
         *
         * @param L         desired length of prime P in bits (the effective key size).
         * @param N         desired length of prime Q in bits.
         * @param certainty certainty level for prime number generation.
         */
        public DomainGenParameters(int L, int N, int certainty)
        {
            this(L, N, certainty, null, null, null, -1);
        }

        /**
         * Construct for a specific usage index - this has the effect of using verifiable canonical generation of G.
         *
         * @param L          desired length of prime P in bits (the effective key size).
         * @param N          desired length of prime Q in bits.
         * @param certainty  certainty level for prime number generation.
         * @param usageIndex a valid usage index.
         */
        public DomainGenParameters(int L, int N, int certainty, int usageIndex)
        {
            this(L, N, certainty, null, null, null, usageIndex);
        }

        /**
         * Construct from initial prime values, this will do a random construction of G.
         *
         * @param p the prime P.
         * @param q the prime Q.
         */
        public DomainGenParameters(BigInteger p, BigInteger q)
        {
            this(p.bitLength(), q.bitLength(), 0, p, q, null, -1);
        }

        /**
         * Construct for a specific usage index and initial prime values - this has the effect of using verifiable canonical generation of G.
         *
         * @param p          the prime P.
         * @param q          the prime Q.
         * @param seed       seed used in the generation of (p, q).
         * @param usageIndex a valid usage index.
         */
        public DomainGenParameters(BigInteger p, BigInteger q, byte[] seed, int usageIndex)
        {
            this(p.bitLength(), q.bitLength(), 0, p, q, Arrays.clone(seed), usageIndex);
        }

        private DomainGenParameters(int L, int N, int certainty, BigInteger p, BigInteger q, byte[] seed, int usageIndex)
        {
            super(ALGORITHM);

            if (CryptoServicesRegistrar.isInApprovedOnlyMode())
            {
                if (p == null && certainty < PrimeCertaintyCalculator.getDefaultCertainty(L))
                {
                    throw new FipsUnapprovedOperationError("Prime generation certainty " + certainty + " inadequate for parameters of " + L + " bits", this.getAlgorithm());
                }
            }

            if (usageIndex > 255)
            {
                throw new IllegalArgumentException("Usage index must be in range 0 to 255 (or -1 to ignore)");
            }

            this.L = L;
            this.N = N;
            this.certainty = certainty;
            this.p = p;
            this.q = q;
            this.seed = seed;
            this.usageIndex = usageIndex;
        }
    }

    /**
     * Generator class for Diffie-Hellman domain parameters.
     */
    public static final class DomainParametersGenerator
    {
        private final SecureRandom random;
        private final DomainGenParameters parameters;
        private final FipsDigestAlgorithm digestAlgorithm;

        /**
         * Default constructor using SHA-256 as the digest.
         *
         * @param parameters domain generation parameters.
         * @param random     a source of randomness for the parameter generation.
         */
        public DomainParametersGenerator(DomainGenParameters parameters, SecureRandom random)
        {
            this(FipsSHS.Algorithm.SHA256, parameters, random);
        }

        /**
         * Base constructor.
         *
         * @param digestAlgorithm digest to use in prime calculations.
         * @param parameters      domain generation parameters.
         * @param random          a source of randomness for the parameter generation.
         */
        public DomainParametersGenerator(FipsDigestAlgorithm digestAlgorithm, DomainGenParameters parameters, SecureRandom random)
        {
            if (CryptoServicesRegistrar.isInApprovedOnlyMode())
            {
                int effSizeInBits = parameters.L;

                if (effSizeInBits != 2048 && effSizeInBits != 3072)
                {
                    throw new FipsUnapprovedOperationError("Attempt to create parameters with unapproved key size [" + effSizeInBits + "]", ALGORITHM);
                }

                Utils.validateRandom(random, Utils.getAsymmetricSecurityStrength(effSizeInBits), ALGORITHM, "Attempt to create parameters with unapproved RNG");
            }

            this.digestAlgorithm = digestAlgorithm;
            this.parameters = parameters;
            this.random = random;
        }

        /**
         * Generate a new set of Diffie-Hellman domain parameters.
         *
         * @return a new set of DHDomainParameters
         */
        public DHDomainParameters generateDomainParameters()
        {
            if (parameters.L < MIN_FIPS_KEY_STRENGTH)
            {
                if (CryptoServicesRegistrar.isInApprovedOnlyMode())
                {
                    throw new FipsUnapprovedOperationError("Requested DH parameter strength too small for approved mode: " + parameters.L);
                }

                DhParametersGenerator pGen = new DhParametersGenerator();

                pGen.init(parameters.L, parameters.certainty, random);

                DhParameters p = pGen.generateParameters();

                return new DHDomainParameters(p.getP(), p.getQ(), p.getG(), p.getJ(), null);
            }

            FipsDSA.DomainGenParameters params = new FipsDSA.DomainGenParameters(parameters.L, parameters.N, parameters.certainty, parameters.p, parameters.q, parameters.seed, parameters.usageIndex);
            FipsDSA.DomainParametersGenerator pGen = new FipsDSA.DomainParametersGenerator(digestAlgorithm, params, random);

            DSADomainParameters domainParameters = pGen.generateDomainParameters();
            DSAValidationParameters vParams = domainParameters.getValidationParameters();

            if (vParams != null)
            {
                return new DHDomainParameters(domainParameters.getP(), domainParameters.getQ(), domainParameters.getG(), null, new DHValidationParameters(vParams.getSeed(), vParams.getCounter(), vParams.getUsageIndex()));
            }
            else
            {
                return new DHDomainParameters(domainParameters.getP(), domainParameters.getQ(), domainParameters.getG());
            }
        }
    }

    /**
     * Key pair generator for Diffie-Hellman key pairs.
     */
    public static final class KeyPairGenerator
        extends FipsAsymmetricKeyPairGenerator
    {
        private final DhKeyPairGenerator engine = new DhKeyPairGenerator();
        private final DHDomainParameters domainParameters;
        private final DhKeyGenerationParameters param;

        /**
         * Construct a key pair generator for Diffie-Hellman keys,
         *
         * @param keyGenParameters domain parameters and algorithm for the generated key.
         * @param random           a source of randomness for calculating the private value.
         */
        public KeyPairGenerator(KeyGenParameters keyGenParameters, SecureRandom random)
        {
            super(keyGenParameters);

            if (CryptoServicesRegistrar.isInApprovedOnlyMode())
            {
                int sizeInBits = keyGenParameters.domainParameters.getP().bitLength();
                if (sizeInBits < MIN_FIPS_KEY_STRENGTH)
                {
                    throw new FipsUnapprovedOperationError("Attempt to create key of less than " + MIN_FIPS_KEY_STRENGTH + " bits", keyGenParameters.getAlgorithm());
                }

                Utils.validateKeyPairGenRandom(random, Utils.getAsymmetricSecurityStrength(sizeInBits), ALGORITHM);
            }

            this.param = new DhKeyGenerationParameters(random, getDomainParams(keyGenParameters.getDomainParameters()));
            this.domainParameters = keyGenParameters.getDomainParameters();
            this.engine.init(param);
        }

        /**
         * Generate a new Diffie-Hellman key pair.
         *
         * @return a new AsymmetricKeyPair containing a Diffie-Hellman key pair.
         */
        @Override
        public AsymmetricKeyPair generateKeyPair()
        {
            AsymmetricCipherKeyPair kp = engine.generateKeyPair();

            DhPublicKeyParameters pubKey = (DhPublicKeyParameters)kp.getPublic();
            DhPrivateKeyParameters prvKey = (DhPrivateKeyParameters)kp.getPrivate();

            FipsAlgorithm algorithm = (FipsAlgorithm)this.getParameters().getAlgorithm();


            // FSM_STATE:5.6, "DH PAIRWISE CONSISTENCY TEST", "The module is performing DH Pairwise Consistency self-test"
            // FSM_TRANS:5.DH.0,"CONDITIONAL TEST", "DH PAIRWISE CONSISTENCY TEST", "Invoke DH Pairwise Consistency test"
            validateKeyPair(algorithm, kp);
            // FSM_TRANS:5.DH.1,"DH PAIRWISE CONSISTENCY TEST", "CONDITIONAL TEST", "DH Pairwise Consistency test successful"
            // FSM_TRANS:5.DH.2,"DH PAIRWISE CONSISTENCY TEST", "SOFT ERROR", "DH Pairwise Consistency test failed"

            return new AsymmetricKeyPair(new AsymmetricDHPublicKey(algorithm, domainParameters, pubKey.getY()), new AsymmetricDHPrivateKey(algorithm, domainParameters, prvKey.getX()));
        }
    }

    /**
     * Factory for Agreement operators based on Diffie-Hellman
     */
    public static final class DHAgreementFactory
        extends FipsAgreementFactory
    {
        /**
         * Return an Agreement operator based on the regular Diffie-Hellman algorithm.
         *
         * @param key        the private key to initialize the Agreement with.
         * @param parameters the parameters for configuring the agreement.
         * @return a new Agreement operator for Diffie-Hellman.
         */
        @Override
        public FipsAgreement createAgreement(AsymmetricPrivateKey key, final AgreementParameters parameters)
        {
            AsymmetricDHPrivateKey dhKey = (AsymmetricDHPrivateKey)key;
            DhPrivateKeyParameters lwDhKey = getLwKey(dhKey);

            final DhBasicAgreement dh = AGREEMENT_PROVIDER.createEngine();

            dh.init(lwDhKey);

            return new FipsAgreement()
            {
                @Override
                public AgreementParameters getParameters()
                {
                    return parameters;
                }

                @Override
                public byte[] calculate(AsymmetricPublicKey key)
                {
                    AsymmetricDHPublicKey dhKey = (AsymmetricDHPublicKey)key;
                    DhPublicKeyParameters lwDhKey = new DhPublicKeyParameters(dhKey.getY(), getDomainParams(dhKey.getDomainParameters()));

                    int length = dh.getFieldSize();
                    BigInteger z = dh.calculateAgreement(lwDhKey);
                    byte[] zBytes = BigIntegers.asUnsignedByteArray(length, z);

                    return FipsKDF.processZBytes(zBytes, parameters);
                }
            };
        }
    }

    /**
     * Factory for Unified Agreement operators based on Diffie-Hellman
     */
    public static final class DHUAgreementFactory
        extends FipsAgreementFactory
    {
        /**
         * Return an Agreement operator based on the regular Diffie-Hellman algorithm.
         *
         * @param key        the private key to initialize the Agreement with.
         * @param parameters the parameters for configuring the agreement.
         * @return a new Agreement operator for Diffie-Hellman.
         */
        @Override
        public FipsAgreement createAgreement(AsymmetricPrivateKey key, final DHUAgreementParameters parameters)
        {
            AsymmetricDHPrivateKey dhKey = (AsymmetricDHPrivateKey)key;
            DhuPrivateParameters lwDhKey = new DhuPrivateParameters(getLwKey(dhKey), getLwKey(parameters.ephemeralPrivateKey));
            
            final DhuBasicAgreement dh = DHU_PROVIDER.createEngine();

            dh.init(lwDhKey);

            return new FipsAgreement()
            {
                @Override
                public DHUAgreementParameters getParameters()
                {
                    return parameters;
                }

                @Override
                public byte[] calculate(AsymmetricPublicKey key)
                {
                    AsymmetricDHPublicKey dhKey = (AsymmetricDHPublicKey)key;
                    DhPublicKeyParameters lwDhKey = new DhPublicKeyParameters(dhKey.getY(), getDomainParams(dhKey.getDomainParameters()));

                    DhuPublicParameters dhuParams = new DhuPublicParameters(lwDhKey,
                            new DhPublicKeyParameters(parameters.otherPartyEphemeralKey.getY(), lwDhKey.getParameters()));

                    byte[] zBytes = dh.calculateAgreement(dhuParams);
           
                    return FipsKDF.processZBytes(zBytes, parameters);
                }
            };
        }
    }

    /**
     * Factory for Agreement operators based on MQV
     */
    public static final class MQVAgreementFactory
        extends FipsAgreementFactory
    {
        /**
         * Return an Agreement operator based on MQV using Diffie-Hellman keys.
         *
         * @param key        the private key to initialize the Agreement with.
         * @param parameters the parameters for configuring the agreement.
         * @return a new Agreement operator for MQV.
         */
        @Override
        public FipsAgreement createAgreement(AsymmetricPrivateKey key, final MQVAgreementParameters parameters)
        {
            AsymmetricDHPrivateKey dhKey = (AsymmetricDHPrivateKey)key;
            DhPrivateKeyParameters lwDHKey = getLwKey(dhKey);

            final MqvBasicAgreement mqv = MQV_PROVIDER.createEngine();

            mqv.init(new MqvPrivateParameters(lwDHKey, parameters.ephemeralPrivateKey == null ? lwDHKey : getLwKey(parameters.ephemeralPrivateKey)));

            return new FipsAgreement()
            {
                @Override
                public MQVAgreementParameters getParameters()
                {
                    return parameters;
                }

                @Override
                public byte[] calculate(AsymmetricPublicKey key)
                {
                    AsymmetricDHPublicKey dhKey = (AsymmetricDHPublicKey)key;
                    DhPublicKeyParameters lwDhKey = new DhPublicKeyParameters(dhKey.getY(), getDomainParams(dhKey.getDomainParameters()));

                    int length = mqv.getFieldSize();
                    AsymmetricDHPublicKey ephPublicKey = parameters.getOtherPartyEphemeralKey();
                    BigInteger z = mqv.calculateAgreement(new MqvPublicParameters(lwDhKey, new DhPublicKeyParameters(ephPublicKey.getY(), getDomainParams(ephPublicKey.getDomainParameters()))));
                    byte[] zBytes = BigIntegers.asUnsignedByteArray(length, z);

                    return FipsKDF.processZBytes(zBytes, parameters);
                }
            };
        }
    }

    private static void validateKeyPair(FipsAlgorithm algorithm, AsymmetricCipherKeyPair keyPair)
    {
        Variations variation = (algorithm == ALGORITHM) ? Variations.DH : (Variations)algorithm.basicVariation();

        switch (variation)
        {
        case DH:
            SelfTestExecutor.validate(algorithm, keyPair, new ConsistencyTest()
            {
                public boolean hasTestPassed(AsymmetricCipherKeyPair kp)
                    throws Exception
                {
                    DhBasicAgreement agreement = new DhBasicAgreement();

                    agreement.init(kp.getPrivate());

                    BigInteger agree1 = agreement.calculateAgreement(kp.getPublic());

                    AsymmetricCipherKeyPair testKP = getTestKeyPair(kp);

                    agreement.init(testKP.getPrivate());

                    BigInteger agree2 = agreement.calculateAgreement(testKP.getPublic());

                    agreement.init(kp.getPrivate());

                    BigInteger agree3 = agreement.calculateAgreement(testKP.getPublic());

                    agreement.init(testKP.getPrivate());

                    BigInteger agree4 = agreement.calculateAgreement(kp.getPublic());

                    return !agree1.equals(agree2) && !agree1.equals(agree3) && agree3.equals(agree4);
                }
            });
            break;
        case MQV:
            SelfTestExecutor.validate(algorithm, keyPair, new ConsistencyTest()
            {
                public boolean hasTestPassed(AsymmetricCipherKeyPair kp)
                    throws Exception
                {
                    MqvBasicAgreement agreement = new MqvBasicAgreement();

                    agreement.init(new MqvPrivateParameters((DhPrivateKeyParameters)kp.getPrivate(), (DhPrivateKeyParameters)kp.getPrivate()));

                    BigInteger agree1 = agreement.calculateAgreement(new MqvPublicParameters((DhPublicKeyParameters)kp.getPublic(), (DhPublicKeyParameters)kp.getPublic()));

                    AsymmetricCipherKeyPair testSKP = getTestKeyPair(kp);
                    AsymmetricCipherKeyPair testEKP = getTestKeyPair(kp);

                    agreement.init(new MqvPrivateParameters((DhPrivateKeyParameters)kp.getPrivate(), (DhPrivateKeyParameters)kp.getPrivate()));

                    BigInteger agree2 = agreement.calculateAgreement(new MqvPublicParameters((DhPublicKeyParameters)testSKP.getPublic(), (DhPublicKeyParameters)testEKP.getPublic()));

                    agreement.init(new MqvPrivateParameters((DhPrivateKeyParameters)testSKP.getPrivate(), (DhPrivateKeyParameters)testEKP.getPrivate()));

                    BigInteger agree3 = agreement.calculateAgreement(new MqvPublicParameters((DhPublicKeyParameters)kp.getPublic(), (DhPublicKeyParameters)kp.getPublic()));

                    return !agree1.equals(agree2) && agree2.equals(agree3);
                }
            });
            break;
        case DHU:
            SelfTestExecutor.validate(algorithm, keyPair, new ConsistencyTest()
            {
                public boolean hasTestPassed(AsymmetricCipherKeyPair kp)
                    throws Exception
                {
                    DhuBasicAgreement agreement = new DhuBasicAgreement();

                    agreement.init(new DhuPrivateParameters((DhPrivateKeyParameters)kp.getPrivate(), (DhPrivateKeyParameters)kp.getPrivate()));

                    byte[] agree1 = agreement.calculateAgreement(new DhuPublicParameters((DhPublicKeyParameters)kp.getPublic(), (DhPublicKeyParameters)kp.getPublic()));

                    AsymmetricCipherKeyPair testSKP = getTestKeyPair(kp);
                    AsymmetricCipherKeyPair testEKP = getTestKeyPair(kp);

                    agreement.init(new DhuPrivateParameters((DhPrivateKeyParameters)kp.getPrivate(), (DhPrivateKeyParameters)kp.getPrivate()));

                    byte[] agree2 = agreement.calculateAgreement(new DhuPublicParameters((DhPublicKeyParameters)testSKP.getPublic(), (DhPublicKeyParameters)testEKP.getPublic()));

                    agreement.init(new DhuPrivateParameters((DhPrivateKeyParameters)testSKP.getPrivate(), (DhPrivateKeyParameters)testEKP.getPrivate()));

                    byte[] agree3 = agreement.calculateAgreement(new DhuPublicParameters((DhPublicKeyParameters)kp.getPublic(), (DhPublicKeyParameters)kp.getPublic()));

                    return !Arrays.areEqual(agree1, agree2) && Arrays.areEqual(agree2, agree3);
                }
            });
            break;
        default:
            throw new IllegalStateException("Unhandled DH algorithm: " + algorithm.getName());
        }
    }

    private static class AgreementProvider
        extends FipsEngineProvider
    {
        static final BigInteger expected = new BigInteger("8b2ba83764fc961a7aeb335d67aa206c1013be9127e2d37a43fa7fff45dd13d4699173a727f4fc88b66d5f53c8848667c090adb2879501d1f7fe53b430beb220b6cce85c5bff74c61b16dbc788ab1459eec1b6f03455862324210e72f7e1f01a55f464bbd996267d3693cdc61053d87a17cb93f6e5079188377db48774bc9232552440471218ec2834e0e29fcdba7e0b7caf9a8f679c4e4382f83f66f8a4dd61cc5d91d15440f10a0f76c3e3a495e7cc53993ba7fb3231310c79e2b587a10074030f158a560e85c89642da9c883f78947116d8ea0d94bfe77c6fb07a7fca8c524827f5779aa7f5428fec0d282f8aca22dd1d47ed61eb6584b5444c5344ab716e", 16);

        public DhBasicAgreement createEngine()
        {
            return SelfTestExecutor.validate(ALGORITHM_DH, new DhBasicAgreement(), new VariantKatTest()
            {
                @Override
                void evaluate(DhBasicAgreement engine)
                    throws Exception
                {
                    AsymmetricCipherKeyPair kp = getKATKeyPair();

                    AsymmetricCipherKeyPair testOther = getTestKeyPair(kp);

                    engine.init(kp.getPrivate());

                    if (!expected.equals(engine.calculateAgreement(testOther.getPublic())))
                    {
                        fail("KAT DH agreement not verified");
                    }
                }
            });
        }
    }

    private static class MqvProvider
        extends FipsEngineProvider
    {
        static final BigInteger expected = new BigInteger("52b800582b28e89d8ee581014ea4a1bc59cc3cc202562788ac40cbf9b1b11657019b556f112ecc9404b1de17630edcd0b8f9f4075e39624e94074b5060d3e699f726873b16e6ec49bdf689bcc275477da4170c7bbe93bfd5bc32a9556311d3f54d0e534118363deda2e3d25b6213b3d01f218c3f1d237967d128cd5a0f0caca8e287fd599d48ce297c8d92a4b7b2d95950a8ddb0e86e7b9bdc6abab91f758613762d185b2a5f516434f96c1bcba67f47bb780ade54dfa6a4f6a8d130aca76f9b28d77ef5eae1e254e5b61526b8c0fecf11b22e8630ebdd5e95f3902954526bd99eb8735263855b5f4d1ea32f6a0d2895ed292e9bb17a07ba1742a1619f4d95c9", 16);

        public MqvBasicAgreement createEngine()
        {
            return SelfTestExecutor.validate(ALGORITHM_MQV, new MqvBasicAgreement(), new VariantKatTest()
            {
                @Override
                void evaluate(MqvBasicAgreement engine)
                    throws Exception
                {
                    AsymmetricCipherKeyPair kp = getKATKeyPair();

                    AsymmetricCipherKeyPair testSKP = getTestKeyPair(kp);
                    AsymmetricCipherKeyPair testEKP = getTestKeyPair(kp);

                    engine.init(new MqvPrivateParameters((DhPrivateKeyParameters)kp.getPrivate(), (DhPrivateKeyParameters)kp.getPrivate()));

                    BigInteger calculated = engine.calculateAgreement(new MqvPublicParameters((DhPublicKeyParameters)testSKP.getPublic(), (DhPublicKeyParameters)testEKP.getPublic()));

                    if (!expected.equals(calculated))
                    {
                        fail("KAT DH MQV agreement not verified");
                    }
                }
            });
        }
    }

    private static class DhuProvider
        extends FipsEngineProvider
    {
        static final byte[] expected = Hex.decode("8b2ba83764fc961a7aeb335d67aa206c1013be9127e2d37a43fa7fff45dd13d4699173a727f4fc88b66d5f53c8848667c090adb2879501d1f7fe53b430beb220b6cce85c5bff74c61b16dbc788ab1459eec1b6f03455862324210e72f7e1f01a55f464bbd996267d3693cdc61053d87a17cb93f6e5079188377db48774bc9232552440471218ec2834e0e29fcdba7e0b7caf9a8f679c4e4382f83f66f8a4dd61cc5d91d15440f10a0f76c3e3a495e7cc53993ba7fb3231310c79e2b587a10074030f158a560e85c89642da9c883f78947116d8ea0d94bfe77c6fb07a7fca8c524827f5779aa7f5428fec0d282f8aca22dd1d47ed61eb6584b5444c5344ab716e8b2ba83764fc961a7aeb335d67aa206c1013be9127e2d37a43fa7fff45dd13d4699173a727f4fc88b66d5f53c8848667c090adb2879501d1f7fe53b430beb220b6cce85c5bff74c61b16dbc788ab1459eec1b6f03455862324210e72f7e1f01a55f464bbd996267d3693cdc61053d87a17cb93f6e5079188377db48774bc9232552440471218ec2834e0e29fcdba7e0b7caf9a8f679c4e4382f83f66f8a4dd61cc5d91d15440f10a0f76c3e3a495e7cc53993ba7fb3231310c79e2b587a10074030f158a560e85c89642da9c883f78947116d8ea0d94bfe77c6fb07a7fca8c524827f5779aa7f5428fec0d282f8aca22dd1d47ed61eb6584b5444c5344ab716e");

        public DhuBasicAgreement createEngine()
        {
            return SelfTestExecutor.validate(ALGORITHM_DHU, new DhuBasicAgreement(), new VariantKatTest()
            {
                @Override
                void evaluate(DhuBasicAgreement engine)
                    throws Exception
                {
                    AsymmetricCipherKeyPair kp = getKATKeyPair();

                    AsymmetricCipherKeyPair testSKP = getTestKeyPair(kp);
                    AsymmetricCipherKeyPair testEKP = getTestKeyPair(kp);

                    engine.init(new DhuPrivateParameters((DhPrivateKeyParameters)kp.getPrivate(), (DhPrivateKeyParameters)kp.getPrivate()));

                    byte[] calculated = engine.calculateAgreement(new DhuPublicParameters((DhPublicKeyParameters)testSKP.getPublic(), (DhPublicKeyParameters)testEKP.getPublic()));

                    if (!Arrays.areEqual(expected, calculated))
                    {
                        fail("KAT DH DHU agreement not verified");
                    }
                }
            });
        }
    }

    private static void ffPrimitiveZTest()
    {
        SelfTestExecutor.validate(ALGORITHM, new VariantInternalKatTest(ALGORITHM)
        {
            @Override
            void evaluate()
                throws Exception
            {
                AsymmetricCipherKeyPair kp = getKATKeyPair();

                DhPrivateKeyParameters priv = (DhPrivateKeyParameters)kp.getPrivate();
                DhPublicKeyParameters pub = (DhPublicKeyParameters)kp.getPublic();

                if (!pub.getY().equals(priv.getParameters().getG().modPow(priv.getX(), priv.getParameters().getP())))
                {
                    fail("FF primitive 'Z' computation failed");
                }
            }
        });
    }

    private static AsymmetricCipherKeyPair getKATKeyPair()
    {
        BigInteger q = new BigInteger("90EAF4D1AF0708B1B612FF35E0A2997EB9E9D263C9CE659528945C0D", 16);

        BigInteger p = new BigInteger(
            "C196BA05AC29E1F9C3C72D56DFFC6154" +
                "A033F1477AC88EC37F09BE6C5BB95F51C296DD20D1A28A06" +
                "7CCC4D4316A4BD1DCA55ED1066D438C35AEBAABF57E7DAE4" +
                "28782A95ECA1C143DB701FD48533A3C18F0FE23557EA7AE6" +
                "19ECACC7E0B51652A8776D02A425567DED36EABD90CA33A1" +
                "E8D988F0BBB92D02D1D20290113BB562CE1FC856EEB7CDD9" +
                "2D33EEA6F410859B179E7E789A8F75F645FAE2E136D252BF" +
                "FAFF89528945C1ABE705A38DBC2D364AADE99BE0D0AAD82E" +
                "5320121496DC65B3930E38047294FF877831A16D5228418D" +
                "E8AB275D7D75651CEFED65F78AFC3EA7FE4D79B35F62A040" +
                "2A1117599ADAC7B269A59F353CF450E6982D3B1702D9CA83", 16);

        BigInteger g = new BigInteger(
            "A59A749A11242C58C894E9E5A91804E8" +
                "FA0AC64B56288F8D47D51B1EDC4D65444FECA0111D78F35F" +
                "C9FDD4CB1F1B79A3BA9CBEE83A3F811012503C8117F98E50" +
                "48B089E387AF6949BF8784EBD9EF45876F2E6A5A495BE64B" +
                "6E770409494B7FEE1DBB1E4B2BC2A53D4F893D418B715959" +
                "2E4FFFDF6969E91D770DAEBD0B5CB14C00AD68EC7DC1E574" +
                "5EA55C706C4A1C5C88964E34D09DEB753AD418C1AD0F4FDF" +
                "D049A955E5D78491C0B7A2F1575A008CCD727AB376DB6E69" +
                "5515B05BD412F5B8C2F4C77EE10DA48ABD53F5DD498927EE" +
                "7B692BBBCDA2FB23A516C5B4533D73980B2A3B60E384ED20" +
                "0AE21B40D273651AD6060C13D97FD69AA13C5611A51B9085", 16);

        BigInteger x = new BigInteger(
            "80d54802e42ce811d122ce2657c303013fc33c2f08f8ff1a9c4ebfd1", 16);

        BigInteger y = new BigInteger(
            "76277e7f847626c252c76828a6142b75e92aaa69612c789686686f44" +
                "7d7361f58c54dac02f23a672157a239dedefaeadecdd94b8f581ec08" +
                "6d152517532c2a8465983f51a643491ddcc328792c9795674ba630b4" +
                "7f364670432d826e2733bc85a666c64e3607d599b125b79ff5a179c8" +
                "8ceee1972d3da80c77c7652b0dc2930f0bf81be1a782e27f35f82848" +
                "ea0e1f2d4ff6d0c6a739bbc61bdb646d1a189a10421a76c2942254ec" +
                "92e7f7d3bec0b6066eb70c9de6be50409e25f7d0e0b93fcc08a9f269" +
                "4253238c6889a909f22b636924e54f6b12392ddf5016633646476b74" +
                "257ffbb486723f1a3167c93f0e577c4e6d3734f4af38153c76850374" +
                "c067e6c7", 16);

        DhParameters dhParameters = new DhParameters(p, g, q);

        return new AsymmetricCipherKeyPair(new DhPublicKeyParameters(y, dhParameters), new DhPrivateKeyParameters(x, dhParameters));
    }

    private static AsymmetricCipherKeyPair getTestKeyPair(AsymmetricCipherKeyPair kp)
    {
        DhPrivateKeyParameters privKey = (DhPrivateKeyParameters)kp.getPrivate();
        DhParameters dhParams = privKey.getParameters();

        BigInteger testD = privKey.getX().multiply(BigInteger.valueOf(7)).mod(privKey.getX());

        if (testD.compareTo(BigInteger.valueOf(2)) < 0)
        {
            testD = new BigInteger("0102030405060708090a0b0c0d0e0f101112131415161718", 16);
        }

        DhPrivateKeyParameters testPriv = new DhPrivateKeyParameters(testD, dhParams);
        DhPublicKeyParameters testPub = new DhPublicKeyParameters(dhParams.getG().modPow(testD, dhParams.getP()), dhParams);

        return new AsymmetricCipherKeyPair(testPub, testPriv);
    }

    private static DhParameters getDomainParams(DHDomainParameters dhParameters)
    {
        return new DhParameters(dhParameters.getP(), dhParameters.getG(), dhParameters.getQ(), dhParameters.getM(), dhParameters.getL(), dhParameters.getJ());
    }

    private static DhPrivateKeyParameters getLwKey(final AsymmetricDHPrivateKey privKey)
    {
        return AccessController.doPrivileged(new PrivilegedAction()
        {
            public DhPrivateKeyParameters run()
            {
                return new DhPrivateKeyParameters(privKey.getX(), getDomainParams(privKey.getDomainParameters()));
            }
        });
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy