确定已发生解密

时间:2014-08-09 15:29:03

标签: java encryption cryptography aes

我正在开发基于AES-128位对称加密的基于GUI的加密器/解密器。 我的问题是如何确定没有发生解密并显示“解密失败”对话框。我编写的代码总是生成一个没有.enc扩展名的文件,无论它是否仍然是加密的

希望能从Stack Overflow的顶级程序员那里得到答案:)

请注意解密进程不会失败或抛出异常!这只是它生成一个仍未解密的文件的事实。我们必须停下来,这就是我的意思!

此处代码:(抱歉压痕不好!)

    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();
  }
}

2 个答案:

答案 0 :(得分:1)

如果不查看API调用,解密方法应该在发生错误时抛出异常。在异常处理程序中,您可以设置一个标志,以便显示错误消息。您还可以延迟解密文件创建,直到成功解密(或至少直到第一个块成功解密后)。如果解密然后沿着该行进一步失败,则可以删除(基本上是临时的)解密输出文件并显示错误消息。

[编辑]

我稍微误解了原帖,所以有些建议要检查解密失败(注意这些比AES更高级别,因此它可能仅适用于您的应用程序):

  • 在加密前为明文数据添加校验和
  • 将其他元数据(文件大小,用户,日期等)附加到明文,并在解密时检查这些元数据
  • 通常,解密时会出现填充异常 - 检查这些(以及任何其他赠品)
  • 使用PKI(公钥基础结构)功能,例如签名(这超出了本答案的范围,可能超出了您尝试解决的问题的范围)。

答案 1 :(得分:1)

我建议在加密前为您的数据添加常量而不是校验和,并在加密后验证它。

加密算法应该使用链接,这意味着要避免使用ECB(请参阅此处原因:http://bobnalice.wordpress.com/2009/01/28/friends-don%E2%80%99t-let-friends-use-ecb-mode-encryption)。

使用带链接的常量几乎与校验和一样好,而且更简单。