Scala密码AES解密不起作用-有条件地无法解密文件-填充错误

时间:2018-08-09 20:55:44

标签: scala encryption error-handling aes padding

Scala 2.11.8,有助于加密...这遵循this stackoverflow site中的原则,并给出一个错误(javax.crypto.BadPaddingException:给定最终块未正确填充)。我知道为什么会导致错误,但是在处理它时需要帮助。 注意:分别执行解密代码(即在不同的窗口,单独的spark-shell实例上)时发生错误。很少,当加密和解密都在同一实例中时发生错误。将salt和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%以上)(例如,如果在同一实例中执行上述操作,则大部分时间都可以使用)。如果解密是分别完成的,则通过在单独的window / process / thread / java实例中获取salt和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

0 个答案:

没有答案