import java.io.*;
import java.security.*;
import java.util.Calendar;


/*

AUTHOR DEVEN PURI
Roll no 03329023

 */
public class SignDigest {
    
    /**
     *@param filename: the file which is used as input for signing
     *@param keySize: The key size to be used in bits
     *@param msgSize: The message size in bytes
     */
    public void signAndVerify(String inFile, int keySize, int msgSize,
                                                         String algo, String hash) {
        try {
            /************************* BEGIN Generate a key pair ***************************/
            long startTime = Calendar.getInstance().getTimeInMillis();
            KeyPairGenerator keygen = KeyPairGenerator.getInstance(algo);
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG","SUN");
            
            keygen.initialize(keySize,random);

            KeyPair keypair = keygen.generateKeyPair();
            PrivateKey Kr = keypair.getPrivate();
            PublicKey Ku = keypair.getPublic();
            /************************* END Generate a key pair ***************************/
            
            long midTime = Calendar.getInstance().getTimeInMillis();

            /************* Create a Signature object and initialize it with private key **************/
            Signature Sign = Signature.getInstance(hash);
            Sign.initSign(Kr);

            /************************* Update and Sign the data ***************************/
            FileInputStream fis = new FileInputStream(inFile);
            BufferedInputStream bis = new BufferedInputStream(fis);
            byte buffer[] = new byte[64];
            int length;
            int totalLength = 0;
            while(bis.available() != 0 && totalLength<msgSize){
                    length = bis.read(buffer);
                    totalLength += length;
                    Sign.update(buffer,0,length);
            }
            bis.close();

           /*
             * Now, that all the data to be signed is read in,
             * and hash generated ( using update method )
             * generate a signature for it
             */
            byte[] realsign = Sign.sign();
            long endTime = Calendar.getInstance().getTimeInMillis();

            /*********** Print output on the console **********/
            System.out.println("\n\n\n************* "+hash+" ***************\n");
            System.out.println("Message Size:"+totalLength+" bytes       KeySize:"+keySize+" bits\n");
            System.out.println("********Key generation time = "+(midTime - startTime)+" ms\n");
            System.out.println("********Signing time = "+(endTime - midTime)+" ms\n");
            
            /*****************verify the sign**************************/
            startTime = Calendar.getInstance().getTimeInMillis();
            Sign.initVerify(Ku);
            
            fis = new FileInputStream(inFile);
            bis = new BufferedInputStream(fis);
            totalLength = 0;
            while(bis.available() != 0 && totalLength<msgSize){
                    length = bis.read(buffer);
                    totalLength += length;
                    Sign.update(buffer,0,length);
            }
            bis.close();
            
            boolean verified = Sign.verify(realsign);
            
            endTime = Calendar.getInstance().getTimeInMillis();
            
            //write result in output file
            System.out.println("********Time taken to verify: "+(endTime-startTime)+" ms\n");
            
        }catch(Exception e) {
            System.out.println("An Error has occured:"+e);
        }
    }
    
    
    public void makeDigest(String inFile, String algo, int msgSize) {
        try {
            long startTime = Calendar.getInstance().getTimeInMillis();
            
            MessageDigest objMsgDig = MessageDigest.getInstance(algo);
            
            FileInputStream fis = new FileInputStream(inFile);
            BufferedInputStream bis = new BufferedInputStream(fis);
            byte buffer[] = new byte[64];
            int length;
            int totalLength = 0;
            while(bis.available() != 0 && totalLength<msgSize){
                    length = bis.read(buffer);
                    totalLength += length;
                    objMsgDig.update(buffer,0,length);
            }
            bis.close();
            
            byte [] realdigest = objMsgDig.digest();
            
            long endTime = Calendar.getInstance().getTimeInMillis();

            //write output too the console
            System.out.println("\n\n\n************ "+algo+" *************\n");
            System.out.println("Message size: "+totalLength+" bytes\n");
            System.out.println("********Time taken to verify: "+(endTime-startTime)+" ms\n");
        }catch(Exception e) {
            System.out.println("An Error has occured:"+e);
        }
    }
    
    public static void main(String [] args) {
        if(args.length!=1) {
            System.out.println("Usage: DSASignGen <name_of_file_to_sign>");
            System.exit(0);
        }
        
        //make object
        SignDigest objSignDigest = new SignDigest();
        
        //make keysize, messageSize and algo arrays
        int arrKeySize[] = {512,1024};
        int arrMsgSize[] = {512, 1024, 2048, 4096};
        String arrSignAlgo[] = {"DSA", "SHA1withDSA", "RSA", "SHA1withRSA", "RSA", "MD5withRSA"};
        
        String inFile = args[0];
        
        //call the DSA/RSA algorithm in a loop
        boolean verified = false;
        for (int ai=0; ai<6; ai+=2) {
            for (int i=0; i<arrKeySize.length; i++) {
                for (int j=0; j<arrMsgSize.length; j++) {
                    //sign with DSA
                    objSignDigest.signAndVerify(inFile, arrKeySize[i], arrMsgSize[j], 
                                                    arrSignAlgo[ai],arrSignAlgo[ai+1]);
                }
            }
        }
        
        //For the message digests: MD5 and SHA-1
        String arrDigest[] = {"SHA-1","MD5"};
        for (int ai=0; ai<arrDigest.length; ai++) {
            for (int i=0; i<arrMsgSize.length; i++) {
                objSignDigest.makeDigest(inFile, arrDigest[ai], arrMsgSize[i]);
            }
        }
    }
    
    
    
}
