Siddharth Kamaria
Siddharth Kamaria

Reputation: 2717

Determining that decryption has occurred

I am developing a GUI based encryptor/decryptor based on AES-128 bit symmetric encryption. My problem is that how to determine that decryption has not occurred and show a dialog box "Decryption Failed". The code I have written would always generate a file without a .enc extension regardless of the fact that it is still encrypted !

Hoping to get a answer as always from Stack Overflow's top notch programmers :)

Do note that the decryption process doesn't fail or throws exception ! It's just the fact that it generates a file that's still not decrypted. That we have to stop and that's what I meant !

Code here: (Sorry for bad indentation !)

    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.util.Arrays;

    import javax.crypto.Cipher;
    import javax.crypto.CipherInputStream;
    import javax.crypto.CipherOutputStream;
    import javax.crypto.spec.SecretKeySpec;
    import java.security.SecureRandom;
    import java.security.MessageDigest;

    public class FileEncryptor{

    private String algo;
    private String path;
    private String password;
    public FileEncryptor(String algo,String path, String password) {
        this.algo = algo; //setting algo
        this.path = path;//setting file path
        this.password = password;
    }

public void encrypt() throws Exception{
 SecureRandom padding = new SecureRandom();
 byte[] salt = new byte[16];
 padding.nextBytes(salt);
     //generating key
  byte k[] = password.getBytes();  
 MessageDigest sha = MessageDigest.getInstance("SHA-1");
 k = sha.digest(k);
 k = Arrays.copyOf(k, 16);  
     SecretKeySpec key = new SecretKeySpec(k,algo);  
     //creating and initialising cipher and cipher streams
     Cipher encrypt =  Cipher.getInstance(algo);  
     encrypt.init(Cipher.ENCRYPT_MODE, key);
     //opening streams
     FileOutputStream fos =new FileOutputStream(path+".enc");
     try(FileInputStream fis =new FileInputStream(path)){
        try(CipherOutputStream cout=new CipherOutputStream(fos, encrypt)){
            copy(fis,cout);
        }
     }
 }

 public void decrypt() throws Exception{
 SecureRandom padding = new SecureRandom();
 byte[] salt = new byte[16];
 padding.nextBytes(salt);
     //generating same key
  byte k[] = password.getBytes();  
 MessageDigest sha = MessageDigest.getInstance("SHA-1");
 k = sha.digest(k);
 k = Arrays.copyOf(k, 16); 
     SecretKeySpec key = new SecretKeySpec(k,algo);  
     //creating and initialising cipher and cipher streams
     Cipher decrypt =  Cipher.getInstance(algo);  
     decrypt.init(Cipher.DECRYPT_MODE, key);
     //opening streams
     FileInputStream fis = new FileInputStream(path);
     try(CipherInputStream cin=new CipherInputStream(fis, decrypt)){  
        try(FileOutputStream fos =new FileOutputStream(path.substring(0,path.lastIndexOf(".")))){
           copy(cin,fos);
       }
     }
  }

 private void copy(InputStream is,OutputStream os) throws Exception{
    byte buf[] = new byte[4096];  //4K buffer set
    int read = 0;
    while((read = is.read(buf)) != -1)  //reading
       os.write(buf,0,read);  //writing
 }

 public static void main (String[] args)throws Exception {
     System.out.println("Enter Password: ");
     new FileEncryptor("AES","sample.txt",new java.util.Scanner(System.in).nextLine()).encrypt();
     new FileEncryptor("AES","sample.txt.enc",new java.util.Scanner(System.in).nextLine()).decrypt();
  }
}

Upvotes: 1

Views: 609

Answers (2)

Jonathan Rosenne
Jonathan Rosenne

Reputation: 2227

I suggest appending a constant, rather than a checksum, to your data before encryption, and verifying it after encryption.

And the encryption algorithm should use chaining, that means avoid ECB (see here why: http://bobnalice.wordpress.com/2009/01/28/friends-don%E2%80%99t-let-friends-use-ecb-mode-encryption).

Using a constant with chaining, is nearly as good as a checksum and much simpler.

Upvotes: 1

roelofs
roelofs

Reputation: 2170

Without looking at the API calls, the decrypt methods should throw an exception if an error occurs. In your exception handler, you can set a flag that will allow you to display an error message. You can also delay the decrypted file creation till after successful decryption (or at least till after the first block has been successfully decrypted). If decryption then fails further along the line, you can delete the (essentially temporary) decrypted output file and display the error message.

[edit]

I slightly misunderstood the original post, so some suggestions to check for failed decryption (note that these are higher level than AES, so it might be specific to your application only):

  • Add a checksum to the plaintext data before encryption
  • Append other metadata (file size, user, date, etc) to the plaintext, and check for these when decrypting
  • Usually, a padding exception would occur on decryption - check for these (and any other giveaways)
  • Use PKI (public key infrastructure) functionality such as signatures (this is outside the scope of this answer, and possibly outside the scope of the problem you're trying to solve)

Upvotes: 1

Related Questions