首页 > 解决方案 > Scala密码AES解密不起作用-有条件地无法解密文件-填充错误

问题描述

Scala 2.11.8,加密帮助...这遵循这个stackoverflow站点的原则并给出错误(javax.crypto.BadPaddingException:给定最终块未正确填充)。我知道为什么会导致错误,但是需要帮助来处理它。 注意:单独执行解密代码时会发生错误(即在不同的窗口,单独的 spark-shell 实例上)。 很少,当加密和解密都在同一个实例中时会发生错误......盐和IvSpec被复制到单独的实例 - 如最后所示(注意:我已经验证两个实例中的字节相同)...

import java.io.{BufferedWriter, File, FileWriter, FileInputStream, FileOutputStream, BufferedInputStream, BufferedOutputStream, DataInputStream, DataOutputStream}
import org.apache.commons.io.FileUtils;
import javax.crypto.{Cipher, SecretKey, SecretKeyFactory, CipherInputStream, CipherOutputStream}
import javax.crypto.spec.{IvParameterSpec, SecretKeySpec, PBEKeySpec}
import java.security.SecureRandom
import scala.util.Random
import scala.math.pow

val password = "Let us test this" 

val random = new SecureRandom();
val salt = Array.fill[Byte](16)(0)
random.nextBytes(salt)

val IvSpec1 = Array.fill[Byte](16)(0)
random.nextBytes(IvSpec1)
val IvSpec = new IvParameterSpec(IvSpec1)

def password_to_key(password: String, salt: Array[Byte]): SecretKeySpec = {
    val spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
    val f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    val key = f.generateSecret(spec).getEncoded()
    new SecretKeySpec(key, "AES")
}

val Key = password_to_key(password, salt)

val Algorithm = "AES/CBC/PKCS5Padding"
val cipher_encrypt = Cipher.getInstance(Algorithm)
cipher_encrypt.init(Cipher.ENCRYPT_MODE, Key, IvSpec)
val cipher_decrypt = Cipher.getInstance(Algorithm)
cipher_decrypt.init(Cipher.DECRYPT_MODE, Key, IvSpec)

def encrypt(file_in: String, file_out: String, cipher_encrypt:javax.crypto.Cipher )  {
    val in = new BufferedInputStream(new FileInputStream(file_in))
    val out = new BufferedOutputStream(new FileOutputStream(file_out))
    val out_encrypted = new CipherOutputStream(out, cipher_encrypt)

    val bufferSize = 1024 * pow(2,4).toInt
    val bb = new Array[Byte](bufferSize)
    var bb_read = in.read(bb, 0, bufferSize)
    while (bb_read > 0) {
        out_encrypted.write(bb, 0, bb_read)
        bb_read = in.read(bb, 0, bufferSize)
    }
    in.close()
    out_encrypted.close()
    out.close()
}

def decrypt(file_in: String, file_out: String, cipher_decrypt:javax.crypto.Cipher )  {
    val in = new BufferedInputStream(new FileInputStream(file_in))
    val in_decrypted = new CipherInputStream(in, cipher_decrypt)

    val out = new BufferedOutputStream(new FileOutputStream(file_out))
    val bufferSize = 1024 * pow(2,4).toInt
    val bb = new Array[Byte](bufferSize)
    var bb_read = in_decrypted.read(bb, 0, bufferSize)
    while (bb_read >0 )  {
        out.write(bb, 0, bb_read)
        bb_read = in_decrypted.read(bb, 0, bufferSize)
    } 
    in_decrypted.close()
    in.close()
    out.close()
} 

val file_in = "test.csv"
val file_encrypt = "test_encrypt.csv"
val file_decrypt = "test_decrypt.csv"
encrypt(file_in, file_encrypt, cipher_encrypt)
decrypt( file_encrypt, file_decrypt, cipher_decrypt)

// To write salt, IvSpec (to re-read it in a separate instance...)
val salt_loc = new File("salt.txt")
val IvSpec_loc = new File("IvSpec.txt")
val salt_w = new FileOutputStream(salt_loc)
salt_w.write(salt)
salt_w.close()
val IvSpec_w = new FileOutputStream(IvSpec_loc)
IvSpec_w.write(IvSpec1)
IvSpec_w.close()

//to re-read salt and IvSpec in a separate instance...
//Ignore that we do not need to re-read IvSpec 
val salt_loc = new File("salt.txt")
val IvSpec_loc = new File("IvSpec.txt")
val salt_r = new FileInputStream(salt_loc)
val salt = Stream.continually(salt_r.read).takeWhile(-1 !=).map(_.toByte).toArray
val IvSpec_r = new FileInputStream(IvSpec_loc)
val IvSpec1 = Stream.continually(IvSpec_r.read).takeWhile(-1 !=).map(_.toByte).toArray
val IvSpec = new IvParameterSpec(IvSpec1)

当解密代码在单独的java进程中执行时,这肯定会出错(错误与填充有关)。当加密和解密在同一个脚本中完成时,这在大多数情况下都有效(95%+)(例如,上面大部分时间都有效 - 如果在同一个实例中执行)。如果解密是单独完成的,通过在单独的窗口/进程/线程/java 实例中获取盐和 IvSpec,它会失败。

error is java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded
  at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:121)
  at javax.crypto.CipherInputStream.read(CipherInputStream.java:239)
  at javax.crypto.CipherInputStream.read(CipherInputStream.java:215)
  at decrypt3(<console>:81)
  ... 60 elided
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
  at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:991)
  at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
  at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
  at javax.crypto.Cipher.doFinal(Cipher.java:2047)
  at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:118)
  ... 63 more

标签: scalaencryptionerror-handlingaespadding

解决方案


推荐阅读