加密在唯一文件中附加IVSBytes的文件 – 执行:给定最终块未正确填充

我正在尝试使用带有SHA-256密钥的AES加密文件。 当我生成IV时,我在加密文件的开始时预先加上它,然后追加其余的。

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

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

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

加密类:

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),因此它不会将最后一个加密块写入文件。 相反,你应该只是cos.close(); 每个javadoc (注意为你处理os.close()):

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

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

或者,因为您的明文适合一个缓冲区(并且您的读取方需要 )跳过CipherOutputStream和os.write (cipher.doFinal(bytes)); os.close(); os.write (cipher.doFinal(bytes)); os.close();

此外,您使用(file,true)构造FileOutputStream,这意味着如果标识的文件已经存在且非空(并且没有受到保护,因此它会引发exception),您的新数据在末尾附加 ,但您的读取方希望它是在开始。

并且:你没有显示是什么,但是如果它不包含比人类记忆更多的熵它可能不符合它的目的。 由于我们不能指望人类记住并输入足够的盐,通常的做法是将其包含在文件/ message / database /中。