加密文件在唯一文件中附加IVSBytes - 执行:给定最终块未正确填充 [英] Encrypt a file appending IVSBytes in unique file - Execption: Given final block not properly padded

查看:223
本文介绍了加密文件在唯一文件中附加IVSBytes - 执行:给定最终块未正确填充的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用带有SHA-256键的AES加密文件。
当我生成IVs时,我会在加密文件的起始时预先支付它,并附加其他文件。

I'm trying to encrypt a file using AES with a SHA-256 Key. When I generate the IVs I preppend it at the beggining of the encrypted file, and append the rest.

当我恢复IV并比较它四是过后的过程),他们是一样的。问题是当我尝试解密文件时:

When I recover the IV's and compare it (the IV's after and then of the proces) they are the same. The problem is when I try to decrypt the file:


javax.crypto.BadPaddingException:给定最终块未正确填充

javax.crypto.BadPaddingException: Given final block not properly padded

我认为这可能是因为我没有正确读取以下字节,但是我修改了代码,似乎OK。

I think it could be because i don't read properly the following bytes, but I revise the code and it seems Ok.

加密类:

private static String password;
private static String salt;
private static int pswdIterations = 65536  ;
private static int keySize = 256;
private byte[] ivBytes;

public void encryptOfFile(byte[] bytes, File out) throws Exception {  

    byte[] saltBytes = salt.getBytes("UTF-8");

    System.out.println("Salt bfre:" +salt);

    // Derive the key
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(
            password.toCharArray(),
            saltBytes,
            pswdIterations,
            keySize
            );

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

    //encrypt the message
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    AlgorithmParameters params = cipher.getParameters();
    ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();

    //First copy the IVBytes at the beginning  of the file
    System.out.println("IvBytes Bfore: "  + DatatypeConverter.printHexBinary(ivBytes));
    FileOutputStream os = new FileOutputStream(out, true);
    os.write(ivBytes);

    CipherOutputStream cos = new CipherOutputStream(os, cipher);
    cos.write(bytes);

    os.close();
    cos.close();

}

public byte[] decryptToBytes(File in) throws Exception {  
    byte[] saltBytes = salt.getBytes("UTF-8");
    System.out.println("Salt afetr:" +salt);

    // Derive the key
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(
            password.toCharArray(),
            saltBytes,
            pswdIterations,
            keySize
            );

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");


    //Get IVBytes of the first 16 bytes of the file
    System.out.println("File Size: "  + in.length());

    FileInputStream is = new FileInputStream(in);
    byte [] ivBytesRecovered = new byte [16];
    if (is.read(ivBytesRecovered) != ivBytesRecovered.length) {
        //is.close();
        throw new IllegalStateException("Too short file");
    }
    System.out.println("IvBytes After: "  + DatatypeConverter.printHexBinary(ivBytesRecovered));

    // Decrypt the message
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytesRecovered));        

    byte[] encBytes = new byte[(int) in.length()-16];
    is.read(encBytes);

    byte[] decryptedBytes = null;
    try {
        decryptedBytes = cipher.doFinal(encBytes);
    } catch (IllegalBlockSizeException | BadPaddingException e) {
        e.printStackTrace();
    }

    is.close();

    return decryptedBytes;

}

我收到了错误信息...也许是因为我前16位字节没有正确读取?或者也许是因为我不给字节[] encBytes给一个很好的大小?

I recived the error message... Maybe is because I'm no reading properly the bytes after the first 16? Or maybe is because I don't give a good size for the byte[] encBytes?

用于生成盐:

public String generateSalt() {
    SecureRandom random = new SecureRandom();
    byte bytes[] = new byte[20];
    random.nextBytes(bytes);
    String s = new String(bytes);
    return s;
}


推荐答案

您的问题是加密/写边在关闭cos(CipherOutputStream),
之前关闭os(FileOutputStream),所以它不会将最后一个加密块写入该文件。相反,你应该只是 cos.close(); 哪个 javadoc
(注意,为你处理os.close()):

Your problem is on the encrypt/write side; you close os (the FileOutputStream) before you close cos (the CipherOutputStream), so it doesn't write the last encrypted block to the file. Instead you should just cos.close(); which per javadoc (note that handles the os.close() for you):


此方法调用封装密码对象的doFinal方法,这会导致被封装密码缓冲的任何字节被处理。结果通过调用此输出流的flush方法来写出。

This method invokes the doFinal method of the encapsulated cipher object, which causes any bytes buffered by the encapsulated cipher to be processed. The result is written out by calling the flush method of this output stream.

此方法将封装的密码对象重置为初始状态,并调用底层输出的close方法

This method resets the encapsulated cipher object to its initial state and calls the close method of the underlying output stream.

或者由于您的明文适合于一个缓冲区(而您的阅读端需要),请跳过CipherOutputStream,只是 os.write(cipher.doFinal(bytes)); os.close();

Or since your plaintext fits in one buffer (and your read side requires that) skip the CipherOutputStream and just os.write (cipher.doFinal(bytes)); os.close();

另外,您使用(file,true)构造FileOutputStream 这意味着如果所识别的文件已经存在并且非空(并且不受保护,因此它会引发异常),您的新数据将在附加,但是您的阅读方面期望它处于开始。

Also, you construct the FileOutputStream with (file,true) which means if the identified file already exists and is nonempty (and not protected so it throws an exception) your new data is appended at the end, but your read side expects it to be at the beginning.

而且:你不显示 salt 是什么,但如果它不包含比人类记住的更多的熵它可能不服务于其目的。由于我们不能指望人类记住并输入足够的盐,通常的做法是将其包含在文件/消息/数据库/任何内容中。

And: you don't show what the salt is, but if it doesn't contain more entropy than a human can remember it probably isn't serving its purpose. Since we can't expect a human to remember and type in adequate salt, the usual practice is to include it in the file/message/database/whatever.

这篇关于加密文件在唯一文件中附加IVSBytes - 执行:给定最终块未正确填充的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆