/*
 * 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.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.KeyPairGenerator;
import java.security.KeyPair;
import java.security.Signature;
import java.security.SignatureException;

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

/**
 * Unit tests to test the varoius RSA based signatures.
 * 
 * The class generates RSA based signatures with the openSSL block functions and
 * compares the results with RSA based signatures generated by the BouncyCastle
 * implementation and vices versa.
 * 
 * Created on 01.10.2005
 * 
 * @author Werner Dittmann (werner@apache.org)
 * 
 */

public class OpenSSLTestSignatures extends TestCase {

    KeyPair keyPair = null;

    Signature sigJuiceSign = null;

    Signature sigBCSign = null;

    Signature sigJuiceVerify = null;

    Signature sigBCVerify = null;

    byte[] plainData = null;

    byte[] signatureDataJuice = null;

    byte[] signatureDataBC = null;

    public OpenSSLTestSignatures(String name) {
        super(name);
        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) {
        }

        try {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "BC");
            keyGen.initialize(1024);
            keyPair = keyGen.generateKeyPair();

        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void setUp() {
        plainData = new byte[128];
        for (int i = 0; i < plainData.length; i++) {
            plainData[i] = (byte) (i + 1);
        }
    }

    private void setSignatures(String sigName) {

        try {
            /*
             * initialize ciphers: use the openSSL implementation and the
             * standard BC implementation (as reference)
             */
            sigJuiceSign = Signature.getInstance(sigName, "JuiCE");
            assertNotNull("Signature not found" + sigName, sigJuiceSign);
            sigBCSign = Signature.getInstance(sigName, "BC");

            sigJuiceVerify = Signature.getInstance(sigName, "JuiCE");
            sigBCVerify = Signature.getInstance(sigName, "BC");


            /*
             * Check if cipher providers are correct, i.e the correct provider
             * was chosen.
             */
            assertEquals("Wrong class of openSSL provider", sigJuiceSign
                    .getProvider().getClass().getName(),
                    "org.apache.security.juice.provider.JuiCEProviderOpenSSL");

            assertEquals("Wrong class of BC provider", sigBCSign
                    .getProvider().getClass().getName(),
                    "org.bouncycastle.jce.provider.BouncyCastleProvider");
            /*
             * Initialize the Ciphers
             */
            try {
                sigJuiceSign.initSign(keyPair.getPrivate());
                sigBCSign.initSign(keyPair.getPrivate());
                
                sigJuiceVerify.initVerify(keyPair.getPublic());
                sigBCVerify.initVerify(keyPair.getPublic());
            } catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    void sign() {
        try {
            sigJuiceSign.update(plainData);
            signatureDataJuice = sigJuiceSign.sign();

            sigBCSign.update(plainData);
            signatureDataBC = sigBCSign.sign();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SignatureException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    void verify () {
        try {
            sigJuiceVerify.update(plainData);
            assertTrue("Verify Juice Signature with Juice failed", sigJuiceVerify.verify(signatureDataJuice));
            
            sigJuiceVerify.update(plainData);
            assertTrue("Verify BC Signature with Juice failed", sigJuiceVerify.verify(signatureDataBC));
            
            sigBCVerify.update(plainData);
            assertTrue("Verify Juice Signature with BC failed", sigBCVerify.verify(signatureDataJuice));
            
            sigBCVerify.update(plainData);
            assertTrue("Verify BC Signature with BC failed", sigBCVerify.verify(signatureDataBC));
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SignatureException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    void performTest() {
        sign();
        verify();
    }

    public void testMD5_RSA() {
        setSignatures("MD5withRSAEncryption");        
        performTest();
    }

    public void testSHA1_RSA() {
        setSignatures("SHA1withRSAEncryption");        
        performTest();
    }
    public void testRIPEMD160_RSA() {
        setSignatures("RIPEMD160withRSAEncryption");        
        performTest();
    }
    /**
     * JUnit suite <p/>
     * 
     * @return a junit test suite
     */
    public static Test suite() {
        return new TestSuite(OpenSSLTestSignatures.class);
    }

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

}
