import java.io.*; 
import java.security.*; 
import javax.crypto.*; 
import sun.misc.*;
import javax.swing.*;
import java.awt.*;



public class JCE_RSA
	{	
		
		public static void main(String args[]) throws Exception
			{ 	
				int MAX_RSA_INPUT_LENGTH=117; 
				int RSA_OUTPUT_LENGTH=128;
								
				Object[] option={"Encrypt","Decrypt"};
				String selectedAction;
				while(true)
					{	selectedAction = (String)JOptionPane.showInputDialog(null,"Select:","RSA",JOptionPane.QUESTION_MESSAGE,null,option,option[0]);
						if (selectedAction!=null) break;
					}
					
				JFrame progressBarFrame=new JFrame();
				progressBarFrame.setLayout(null);							
				progressBarFrame.setLocation(500,500);
				progressBarFrame.setSize(250,60);			
				progressBarFrame.setResizable(false);
				JProgressBar progressBar=new JProgressBar(0,100);
				progressBar.setBounds(0,0,250,30);
				progressBar.setValue(0);
				progressBar.setStringPainted(true);
				progressBar.setString("0 %");
				progressBarFrame.getContentPane().add(progressBar);
				progressBarFrame.setEnabled(false);	
						
				
				PublicKey RSAPublicKey=null;
				PrivateKey RSAPrivateKey=null;
				Security.addProvider(new com.sun.crypto.provider.SunJCE());
								
				try
					{ 	ObjectInputStream keyFile=new ObjectInputStream(new FileInputStream("RSAPublicKey.key")); 
						RSAPublicKey=(PublicKey)keyFile.readObject(); 
						keyFile.close();
						keyFile=new ObjectInputStream(new FileInputStream("RSAPrivateKey.key")); 
						RSAPrivateKey=(PrivateKey)keyFile.readObject(); 
						keyFile.close();
					}
				catch(FileNotFoundException fnfe) 
					{ 	
						KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
						kpg.initialize(1024);
						KeyPair kp = kpg.generateKeyPair();
						RSAPublicKey=kp.getPublic();
						RSAPrivateKey=kp.getPrivate();
							
						ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("RSAPublicKey.key")); 
						out.writeObject(RSAPublicKey); 
						out.close();
					
						out=new ObjectOutputStream(new FileOutputStream("RSAPrivateKey.key")); 
						out.writeObject(RSAPrivateKey); 
						out.close();
					} 
				
							
				Cipher RSACipher = Cipher.getInstance("RSA");
							
				if(selectedAction.equals("Encrypt")) 
					{	
						String plainFilename=null;
						FileDialog fileDialog=new FileDialog(new Frame(),"Select file to encrypt");
						while(true)
							{	fileDialog.setVisible(true);
								plainFilename=fileDialog.getDirectory()+fileDialog.getFile();
								if (plainFilename!=null) break;
							};
							
						File dataFile=new File(plainFilename);
						BufferedInputStream fileInput=new BufferedInputStream(new FileInputStream(dataFile));
						long fileSize=dataFile.length();
						
						byte[] data=null;
						byte[] dataEncoded=null;
						RSACipher.init(Cipher.ENCRYPT_MODE, RSAPublicKey);
						BufferedOutputStream fileOutput=new BufferedOutputStream(new FileOutputStream(new File(plainFilename+"_ENCRYPTED")));
						
						
						progressBarFrame.setTitle("Encryption Progress");
						progressBarFrame.setVisible(true);
						
						long computeTimeMSec=0;
						long startTimeMSec=0;
						
						long iteration=fileSize/MAX_RSA_INPUT_LENGTH;	
						int residualByte=(int)(fileSize-iteration*MAX_RSA_INPUT_LENGTH);
						long totalIteration;
						if (residualByte==0) totalIteration=iteration; else totalIteration=iteration+1;
																	
						if (iteration>0) data=new byte[MAX_RSA_INPUT_LENGTH];														
						for(int i=0;i<iteration;i++) 
							 {	for (int j=0;j<MAX_RSA_INPUT_LENGTH;j++) data[j]=(byte)fileInput.read();
							 	startTimeMSec=System.currentTimeMillis();
							 		dataEncoded=RSACipher.doFinal(data);
							 	computeTimeMSec=computeTimeMSec+System.currentTimeMillis()-startTimeMSec;
							 	fileOutput.write(dataEncoded);	
							 	progressBar.setValue((int)((((float)(i+1))/((float)totalIteration))*100));
							 	progressBar.setString(progressBar.getValue()+" %");						 			
							 }
						
						if (residualByte>0)
							{	data=new byte[residualByte];
								for (int j=0;j<residualByte;j++) data[j]=(byte)fileInput.read();
							 	startTimeMSec=System.currentTimeMillis();
							 		dataEncoded=RSACipher.doFinal(data);
							 	computeTimeMSec=computeTimeMSec+System.currentTimeMillis()-startTimeMSec;
							 	progressBar.setValue(100);
							 	progressBar.setString("100 %");	
							 	fileOutput.write(dataEncoded);		
							}
									
						fileOutput.close();	
						new JOptionPane().showMessageDialog(null,"FILE ENCRYPTED!\n"+"PUBLIC KEY SIZE: "+RSAPublicKey.getEncoded().length+"\nENCRYPTION TIME: "+((float)computeTimeMSec)/1000f+" sec");
						System.exit(0);
					} 

				else 
					{ 	
						String encryptedFilename=null;
						FileDialog fileDialog=new FileDialog(new Frame(),"Select file to decrypt");
						while(true)
							{	fileDialog.setVisible(true);
								encryptedFilename=fileDialog.getDirectory()+fileDialog.getFile();								
								if (encryptedFilename!=null) break;
							};
						
						File dataFile=new File(encryptedFilename);
						BufferedInputStream fileInput=new BufferedInputStream(new FileInputStream(dataFile));
						long fileSize=dataFile.length();
						
						byte[] data=null;
						byte[] dataDecoded=null;
						RSACipher.init(Cipher.DECRYPT_MODE, RSAPrivateKey);
						BufferedOutputStream fileOutput=new BufferedOutputStream(new FileOutputStream(new File("_"+encryptedFilename.substring(0,encryptedFilename.indexOf("_ENCRYPTED")))));
						
						progressBarFrame.setTitle("Decryption Progress");
						progressBarFrame.setVisible(true);
												
						long computeTimeMSec=0;
						long startTimeMSec=0;
						
						long iteration=fileSize/RSA_OUTPUT_LENGTH;	
						if (iteration==0) throw new Exception("ENCRYPTED FILE SIZE ERROR");
						data=new byte[RSA_OUTPUT_LENGTH];														
						for(int i=0;i<iteration;i++) 
							 {	for (int j=0;j<RSA_OUTPUT_LENGTH;j++) data[j]=(byte)fileInput.read();
							 	startTimeMSec=System.currentTimeMillis();
							 		dataDecoded=RSACipher.doFinal(data);
							 	computeTimeMSec=computeTimeMSec+System.currentTimeMillis()-startTimeMSec;
							 	progressBar.setValue((int)((((float)(i+1))/((float)iteration))*100));
							 	progressBar.setString(progressBar.getValue()+" %");
							 	fileOutput.write(dataDecoded);							 			
							 }
						fileOutput.close();	
						
						new JOptionPane().showMessageDialog(null,"FILE DECRYPTED!\n"+"PRIVATE KEY SIZE: "+RSAPrivateKey.getEncoded().length+"\nDECRYPTION TIME: "+((float)computeTimeMSec)/1000f+" sec");
						System.exit(0);							
						
						
					} 
						
								
				
			} 
						
	} 
