java - 加密在唯一文件中附加字节的文件 - 异常 : Given final block not properly padded

标签 java encryption aes badpaddingexception

我正在尝试使用 AES 和 SHA-256 key 来加密文件。 当我生成 IV 时,我将其添加到加密文件的开头,然后添加其余部分。

当我恢复 IV 并进行比较时(过程之后和之后的 IV)它们是相同的。问题是当我尝试解密文件时:

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

我认为这可能是因为我没有正确读取以下字节,但我修改了代码,看起来没问题。

加密类:

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 个字节之后的字节?或者可能是因为我没有为 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), 因此它不会将最后一个加密 block 写入文件。相反,您应该只是 cos.close(); ,每个 javadoc (请注意,它为您处理 os.close()):

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.

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

此外,您还可以使用 (file,true) 构造 FileOutputStream,这意味着如果识别的文件已存在且非空(且不 protected ,因此会引发异常),您的新数据为 附加在末尾,但您的阅读方希望它位于开头。

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

关于java - 加密在唯一文件中附加字节的文件 - 异常 : Given final block not properly padded,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29535663/

相关文章:

java - 在xml文件中查找一个String并将其值赋给另一个String

java - 该方法不适用于参数

java - 如何从 Java 中的文件生成 PublicKey 对象

c# - AES 算法( key 长度)- AES key + 附加 PIN 码

java - 上下文单击不适用于 Marathon Java 驱动程序

java - 计时器的 run 方法中调用的方法返回一个我需要在上游使用的值

加密库和 block 大小

java - 如何在 jruby9.1.2.0 中使用 PGP 加密来加密文件?

python - 用于 AES 256 加密的(纯)Python 库是什么?

ios - AES 加密算法无法解密少数文档格式