/*******************************************************************************
 *  Copyright 2017-2018 Centre for Development of Advanced Computing(C-DAC), Pune
 *  
 * 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
 * limitations under the License.
 *******************************************************************************/
package cdac.medinfo.sdk.dcm30_04.mediasecurityprofile.testcases;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConstants;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;


import cdac.medinfo.sdk.dcm30_04.enums.EnumLoggingLevel;
import cdac.medinfo.sdk.dcm30_04.services.basicdicommediasecurityprofile.BasicDICOMMediaSecurityProfile;
import cdac.medinfo.sdk.dcm30_04.services.basicdicommediasecurityprofile.EnumProfileAlgorithm;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConfig;
import cdac.medinfo.sdk.dcm30_04.utils.IPairedCollection;

/**
 * This class is to test Basic DICOM Media Security Profile.
 * The Basic DICOM Media Security Profile allows encapsulation of a DICOM File into a Secure DICOM File
 * such that the following aspects of security are addressed:
 * confidentiality,
 * integrity,
 * data origin authentication (optional).
 * This sample code defines process of encryption/decryption , digital signature and digesting for DICOM File.
 */
public class MediaSecurityProfile_DES 
{
	public static void main(String[] args)
	{
		try
		{
			DicomConfig objDicomConfig = DicomConfig.createInstance();

			//enable logging,specify the path of the directory where log files are created.
			//User can specify any directory in place of 'c:\DCM_Logs'.
			//If no directory is defined by user to create logs then it is created in User Temp DIR.
			objDicomConfig.enableLogging(EnumLoggingLevel.INFO, "C:\\DCM_Logs");


			/*
			 * Generate Secret Key using for DES algo.
			 */
			KeyGenerator  keyGen = KeyGenerator .getInstance("DES");
			SecretKey objSecretKey = keyGen.generateKey();

			/*
			 * Generate public and private key for digital signature.
			 */
			KeyPairGenerator objKeyPairGenerator = KeyPairGenerator.getInstance("RSA");
			KeyPair objKeyPair = objKeyPairGenerator.generateKeyPair();
			PublicKey objPublicKey = objKeyPair.getPublic();
			PrivateKey objPrivateKey = objKeyPair.getPrivate();

			MediaSecurityProfile_DES objTestMediaSecurityProfile_DES = new MediaSecurityProfile_DES();

			boolean bContinue = true;

			while(bContinue)
			{

				System.out.println("\n1. Encryption of File");
				System.out.println("2. Encryption of File-Set");
				
				System.out.println("3. Decryption of File");
				System.out.println("4. Decryption of File-Set");

				System.out.println("5. Digital Signature Generation for File");
				System.out.println("6. Digital Signature Generation for File-Set");
				
				System.out.println("7. Digital Signature Verification for File");
				System.out.println("8. Digital Signature Verification for File-Set");

				System.out.println("9. Digest Generation for File");
				System.out.println("10. Digest Generation for File-Set");
				
				System.out.println("11. Digest Verification for File");
				System.out.println("12. Digest Verification for File-Set");
				
				System.out.println("Default :: Exit\n\n");

				System.out.print("Enter your choice : ");

				InputStreamReader input = new InputStreamReader(System.in);
				BufferedReader reader = new BufferedReader(input);

				int iChoice = Integer.parseInt(reader.readLine());

				switch(iChoice)
				{
				case 1:
					objTestMediaSecurityProfile_DES.encryptDicomFile(EnumProfileAlgorithm.DES, objSecretKey.getEncoded(),null);
					break;
				case 2:
					objTestMediaSecurityProfile_DES.encryptDicomFileSet(EnumProfileAlgorithm.DES, objSecretKey.getEncoded(),null);
					break;
				case 3:
					objTestMediaSecurityProfile_DES.decryptDicomFile(EnumProfileAlgorithm.DES, objSecretKey.getEncoded(),null);
					break;
				case 4:
					objTestMediaSecurityProfile_DES.decryptDicomFileSet(EnumProfileAlgorithm.DES, objSecretKey.getEncoded(),null);
					break;
				case 5:
					objTestMediaSecurityProfile_DES.generateSignature(objPrivateKey);
					break;
				case 6:
					objTestMediaSecurityProfile_DES.generateSignatureForFileSet(objPrivateKey);
					break;
				case 7:
					objTestMediaSecurityProfile_DES.verifySignature(objPublicKey);
					break;
				case 8:
					objTestMediaSecurityProfile_DES.verifySignatureForFileSet(objPublicKey);
					break;
				case 9:
					objTestMediaSecurityProfile_DES.generateDigest();
					break;
				case 10:
					objTestMediaSecurityProfile_DES.generateDigestForFileSet();
					break;
				case 11:
					objTestMediaSecurityProfile_DES.verifyDigest();
					break;
				case 12:
					objTestMediaSecurityProfile_DES.verifyDigestForFileSet();
					break;
				default:
					bContinue = false;
				}
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/*
	 * Encrypts DICOM file according to the profile algorithm using key and initializing vector.
	 */
	private void encryptDicomFile(EnumProfileAlgorithm enumProfileAlgorithm,byte[] objKey,byte[] IVparam)
	{
		try
		{
			System.out.print("Enter DICOM file path which need to be encapsulated in secure DICOM file :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strDicomFilePath = reader.readLine();

			System.out.print("Enter file path where secure DICOM file will be stored :: ");
			String strSecureDicomFilePath = reader.readLine();

			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			/*
			 * this block of code is commented,it specifies process using streams instead of sending file name as parameters 
			 */
//			FileInputStream objFileInputStream = new FileInputStream(strDicomFilePath);
//			FileOutputStream objFileOutputStream = new FileOutputStream(strSecureDicomFilePath);
//			DicomFileStream objDicomStream = new DicomFileStream();
//			objDicomStream.setInputStream(objFileInputStream);
//			objDicomStream.setOutputStream(objFileOutputStream);
//			objAgent.encryptDICOMFile(objDicomStream, objDicomStream,enumProfileAlgorithm,objKey,null);
//			objDicomStream.close();

			objAgent.encryptDICOMFile(strDicomFilePath, strSecureDicomFilePath,enumProfileAlgorithm,objKey,null);

			System.out.println("File encrypted successfully");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/*
	 * Encrypts DICOM File Set according to the profile algorithm using key and initializing vector.
	 */
	private void encryptDicomFileSet(EnumProfileAlgorithm enumProfileAlgorithm,byte[] objKey,byte[] IVparam)
	{
		try
		{
			System.out.print("Enter directory path which contains DICOMDIR FileSet :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strDicomFilePath = reader.readLine();

			System.out.print("Enter directory path where secure DICOMDIR FileSet will be stored :: ");
			String strSecureDicomFilePath = reader.readLine();

			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			objAgent.encryptDICOMFileSet(strDicomFilePath, strSecureDicomFilePath,enumProfileAlgorithm,objKey,null);

			System.out.println("FileSet encrypted successfully");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/*
	 * Decrypts DICOM file according to the profile algorithm using key and initializing vector.
	 */
	private void decryptDicomFile(EnumProfileAlgorithm enumProfileAlgorithm,byte[] objKey,byte[] IVparam)
	{
		try
		{
			System.out.print("Enter secure DICOM file path which need to be decrypted in original DICOM file :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strSecureDicomFilePath = reader.readLine();

			System.out.print("Enter file path where decrypted original DICOM file will be stored :: ");
			String strOriginalDicomFilePath = reader.readLine();

			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			/*
			 * this block of code is commented,it specifies process using streams instead of sending file name as parameters 
			 */

//			FileInputStream objFileInputStream = new FileInputStream(strSecureDicomFilePath);
//			FileOutputStream objFileOutputStream = new FileOutputStream(strOriginalDicomFilePath);
//			DicomFileStream objDicomStream = new DicomFileStream();
//			objDicomStream.setInputStream(objFileInputStream);
//			objDicomStream.setOutputStream(objFileOutputStream);
//			objAgent.decryptSecureDICOMFile(objDicomStream, objDicomStream,enumProfileAlgorithm,objKey,null);
//			objDicomStream.close();

			objAgent.decryptSecureDICOMFile(strSecureDicomFilePath, strOriginalDicomFilePath,enumProfileAlgorithm,objKey,null);

			System.out.println("File decrypted successfully");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/*
	 * Decrypts DICOM File Set according to the profile algorithm using key and initializing vector.
	 */
	private void decryptDicomFileSet(EnumProfileAlgorithm enumProfileAlgorithm,byte[] objKey,byte[] IVparam)
	{
		try
		{
			System.out.print("Enter directory path which contains decrypted DICOMDIR File Set :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strSecureDicomFilePath = reader.readLine();

			System.out.print("Enter directory path where original DICOM File Set will be stored :: ");
			String strOriginalDicomFilePath = reader.readLine();

			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			objAgent.decryptDICOMFileSet(strSecureDicomFilePath, strOriginalDicomFilePath,enumProfileAlgorithm,objKey,null);

			System.out.println("FileSet decrypted successfully");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/*
	 * Generates signature for DICOM file using private key.
	 */
	private void generateSignature(PrivateKey objKey)
	{
		try
		{
			System.out.print("Enter secure DICOM file path for which signature need to be generated :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strSourceFilePath = reader.readLine();

			System.out.print("Enter file path where digital signature will be stored :: ");
			String strSignatureFilePath = reader.readLine();

			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			/*
			 * this block of code is commented,it specifies process using streams instead of sending file name as parameters 
			 */

//			FileInputStream objFileInputStream = new FileInputStream(strSourceFilePath);
//			FileOutputStream objFileOutputStream = new FileOutputStream(strSignatureFilePath);
//			DicomFileStream objDicomStream = new DicomFileStream();
//			objDicomStream.setInputStream(objFileInputStream);
//			objDicomStream.setOutputStream(objFileOutputStream);
//			objAgent.generateSignature(objDicomStream, objDicomStream, objKey);
//			objDicomStream.close();

			objAgent.generateSignature(strSourceFilePath, strSignatureFilePath, objKey);

			System.out.println("Signature generated successfully");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/*
	 * Generates signature for DICOM File Set using private key.
	 */
	private void generateSignatureForFileSet(PrivateKey objKey)
	{
		try
		{
			System.out.print("Enter directory path which contains DICOM images in DICOMDIR format for which signature need to be generated :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strSourceFilePath = reader.readLine();

			System.out.print("Enter directory path where digital signature will be stored :: ");
			String strSignatureFilePath = reader.readLine();

			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			objAgent.generateSignForFileSet(strSourceFilePath, strSignatureFilePath, objKey,"Signature");

			System.out.println("Signature for FileSet generated successfully");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/*
	 * Verifies signature for DICOM file using public key.
	 */
	private void verifySignature(PublicKey objKey)
	{
		try
		{
			System.out.print("Enter secure DICOM file path for which signature need to be verified :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strSourceFilePath = reader.readLine();

			System.out.print("Enter file path where digital signature is stored :: ");
			String strSignatureFilePath = reader.readLine();

			boolean isverfied = false;
			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			/*
			 * this block of code is commented,it specifies process using streams instead of sending file name as parameters 
			 */

//			FileInputStream objFileInputStream1 = new FileInputStream(strSourceFilePath);
//			FileInputStream objFileInputStream2 = new FileInputStream(strSignatureFilePath);
//			DicomFileStream objSourceDataStream = new DicomFileStream();
//			objSourceDataStream.setInputStream(objFileInputStream1);
//			DicomFileStream objSignatureStream = new DicomFileStream();
//			objSignatureStream.setInputStream(objFileInputStream2);
//			isverfied = objAgent.verifySignature(objSourceDataStream, objSignatureStream, objKey);
//			objSourceDataStream.close();
//			objSignatureStream.close();

			isverfied = objAgent.verifySignature(strSourceFilePath, strSignatureFilePath, objKey);

			System.out.println("Signature verification status :: " + isverfied);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/*
	 * Verifies signature for DICOM File Set using public key.
	 */
	private void verifySignatureForFileSet(PublicKey objKey)
	{
		try
		{
			System.out.print("Enter directory path which contains DICOM images in DICOMDIR format for which signature need to be verified :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strSourceFilePath = reader.readLine();

			System.out.print("Enter directory path where original digital signature are stored :: ");
			String strSignatureFilePath = reader.readLine();

			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			IPairedCollection<String,Boolean> objStatusList = objAgent.verifySignForFileSet(strSourceFilePath, strSignatureFilePath, objKey,"Signature");

			for(Boolean isVerified : objStatusList)
			{
				System.out.println("Status for File :: "+isVerified);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/*
	 * Generates digest for DICOM file.
	 */
	private void generateDigest()
	{
		try
		{
			System.out.print("Enter secure DICOM file path for which digest need to be generated :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strSourceFilePath = reader.readLine();

			System.out.print("Enter file path where digest will be stored :: ");
			String strDigestFilePath = reader.readLine();

			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			/*
			 * this block of code is commented,it specifies process using streams instead of sending file name as parameters 
			 */
//			FileInputStream objFileInputStream = new FileInputStream(strSourceFilePath);
//			FileOutputStream objFileOutputStream = new FileOutputStream(strDigestFilePath);
//			DicomFileStream objDicomStream = new DicomFileStream();
//			objDicomStream.setInputStream(objFileInputStream);
//			objDicomStream.setOutputStream(objFileOutputStream);
//			objAgent.generateDigest(objDicomStream, objDicomStream);
//			objDicomStream.close();

			objAgent.generateDigest(strSourceFilePath, strDigestFilePath);

			System.out.println("Digest generated successfully");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/*
	 * Generates digest for DICOM File Set.
	 */
	private void generateDigestForFileSet()
	{
		try
		{
			System.out.print("Enter directory path which contains DICOM images in DICOMDIR format for which digest need to be generated :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strSourceFilePath = reader.readLine();

			System.out.print("Enter directory path where digest will be stored :: ");
			String strDigestFilePath = reader.readLine();

			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			objAgent.generateDigestForFileSet(strSourceFilePath, strDigestFilePath,null);

			System.out.println("Digest for FileSet generated successfully");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/*
	 * Verifies digest for DICOM file.
	 */
	private void verifyDigest()
	{
		try
		{
			System.out.print("Enter secure DICOM file path for which digest need to be verified :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strSourceFilePath = reader.readLine();

			System.out.print("Enter file path where digest is stored :: ");
			String strDigestFilePath = reader.readLine();

			boolean isverfied = false;
			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			/*
			 * this block of code is commented,it specifies process using streams instead of sending file name as parameters 
			 */

//			FileInputStream objFileInputStream1 = new FileInputStream(strSourceFilePath);
//			FileInputStream objFileInputStream2 = new FileInputStream(strDigestFilePath);
//			DicomFileStream objSourceDataStream = new DicomFileStream();
//			objSourceDataStream.setInputStream(objFileInputStream1);
//			DicomFileStream objDigestStream = new DicomFileStream();
//			objDigestStream.setInputStream(objFileInputStream2);
//			isverfied = objAgent.verifyDigest(objSourceDataStream, objDigestStream);
//			objSourceDataStream.close();
//			objDigestStream.close();

			isverfied = objAgent.verifyDigest(strSourceFilePath, strDigestFilePath);

			System.out.println("Digest verification status :: " + isverfied);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	/*
	 * Verifies digest for DICOM File Set.
	 */
	private void verifyDigestForFileSet()
	{
		try
		{
			System.out.print("Enter directory path which contains DICOM images in DICOMDIR format for which digest need to be verified :: ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strSourceFilePath = reader.readLine();

			System.out.print("Enter directory path where digest is stored :: ");
			String strDigestFilePath = reader.readLine();

			BasicDICOMMediaSecurityProfile objAgent = new BasicDICOMMediaSecurityProfile();

			IPairedCollection<String,Boolean> objStatusList = objAgent.verifyDigestForFileSet(strSourceFilePath, strDigestFilePath,null);

			for(Boolean isVerified : objStatusList)
			{
				System.out.println("Status for File :: "+isVerified);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}
