/*
 * Copyright 2002-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * imitations under the License.
 */

package test;

import java.math.BigInteger;
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;

import java.security.SecureRandom;

import javax.crypto.KeyAgreement;
import javax.crypto.spec.DHParameterSpec;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
 * Unit tests to test the Secure Random method.
 * 
 * Created on 15.02.2005
 * 
 * @author Werner Dittmann (werner@apache.org)
 * 
 */

public class OpenSSLTestDH extends TestCase {

    private BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
    private BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);

    private BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16);
    private BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16);

    private BigInteger  g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16);
    private BigInteger  p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16);

    static {
        try {
            Class c = Class
                    .forName("org.apache.security.juice.provider.JuiCEProviderOpenSSL");
            java.security.Security.addProvider((java.security.Provider) c
                    .newInstance());

            c = Class
                    .forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
            java.security.Security.addProvider((java.security.Provider) c
                    .newInstance());
        } catch (Throwable t) {
        }
    }

    public OpenSSLTestDH(String name) {
        super(name);
    }

    private void twoWay(DHParameterSpec spec) throws Exception {

        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC");
        keyGen.initialize(spec);

        //
        // a side
        //
        KeyPair aKeyPair = keyGen.generateKeyPair();

        KeyAgreement aKeyAgree = KeyAgreement.getInstance("DH", "BC");

        aKeyAgree.init(aKeyPair.getPrivate());

        //
        // b side
        //
        KeyPair bKeyPair = keyGen.generateKeyPair();

        KeyAgreement bKeyAgree = KeyAgreement.getInstance("DH", "JuiCE");

        bKeyAgree.init(bKeyPair.getPrivate());

        //
        // agreement
        //
        aKeyAgree.doPhase(bKeyPair.getPublic(), true);
        bKeyAgree.doPhase(aKeyPair.getPublic(), true);

        BigInteger k1 = new BigInteger(aKeyAgree.generateSecret());
        BigInteger k2 = new BigInteger(bKeyAgree.generateSecret());

        if (!k1.equals(k2)) {
            fail("2-way test failed");
        }
    }
    
    private void threeWay(DHParameterSpec spec) throws Exception {
        //
        // three party test
        //
        KeyPairGenerator aPairGen = KeyPairGenerator.getInstance("DH", "BC");
        aPairGen.initialize(spec);
        KeyPair aPair = aPairGen.generateKeyPair();

        KeyPairGenerator bPairGen = KeyPairGenerator.getInstance("DH", "BC");
        bPairGen.initialize(spec);
        KeyPair bPair = bPairGen.generateKeyPair();

        KeyPairGenerator cPairGen = KeyPairGenerator.getInstance("DH", "BC");
        cPairGen.initialize(spec);        
        KeyPair cPair = cPairGen.generateKeyPair();

        KeyAgreement aKeyAgree = KeyAgreement.getInstance("DH", "BC");
        aKeyAgree.init(aPair.getPrivate());

        KeyAgreement bKeyAgree = KeyAgreement.getInstance("DH", "JuiCE");
        bKeyAgree.init(bPair.getPrivate());

        KeyAgreement cKeyAgree = KeyAgreement.getInstance("DH", "JuiCE");
        cKeyAgree.init(cPair.getPrivate());

        Key ac = aKeyAgree.doPhase(cPair.getPublic(), false);

        Key ba = bKeyAgree.doPhase(aPair.getPublic(), false);

        Key cb = cKeyAgree.doPhase(bPair.getPublic(), false);

        aKeyAgree.doPhase(cb, true);

        bKeyAgree.doPhase(ac, true);

        cKeyAgree.doPhase(ba, true);

        BigInteger aShared = new BigInteger(aKeyAgree.generateSecret());
        BigInteger bShared = new BigInteger(bKeyAgree.generateSecret());
        BigInteger cShared = new BigInteger(cKeyAgree.generateSecret());

        if (!aShared.equals(bShared)) {
            fail("3-way test failed (a and b differ)");
        }

        if (!cShared.equals(bShared)) {
            fail("3-way test failed (c and b differ)");
        }
    }

    public void testThreeWay() throws Exception {
        
        DHParameterSpec   spec = new DHParameterSpec(p512, g512);
        threeWay(spec);
    }
    
    public void testTwoWay() throws Exception {
        
        DHParameterSpec   spec = new DHParameterSpec(p512, g512);
        twoWay(spec);
    }

    public void testJuiceParamGen() throws Exception {
        AlgorithmParameterGenerator a = AlgorithmParameterGenerator
                .getInstance("DH", "JuiCE");
        a.init(512, null);
        AlgorithmParameters params = a.generateParameters();
        
        DHParameterSpec dhP = (DHParameterSpec)params.getParameterSpec(DHParameterSpec.class);

        twoWay(dhP);
    }

    /**
     * JUnit suite <p/>
     * 
     * @return a junit test suite
     */
    public static Test suite() {
        return new TestSuite(OpenSSLTestDH.class);
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        junit.textui.TestRunner.run(suite());
    }

}
