Encrypt a file appending IVSBytes in unique file - Execption: Given final block not properly padded

谁说我不能喝 提交于 2019-12-05 10:53:28

问题


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.

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: Given final block not properly padded

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

Crypto class:

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;

}

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?

Used for generating the salt:

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

回答1:


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):

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.

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

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

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.

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.



来源:https://stackoverflow.com/questions/29535663/encrypt-a-file-appending-ivsbytes-in-unique-file-execption-given-final-block

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!