【问题标题】:JCE padding not being properly encrypted/decryptedJCE 填充未正确加密/解密
【发布时间】:2017-07-04 13:15:34
【问题描述】:

我正在开发一个程序,我将使用该程序使用 JCE 加密和解密文件。我的加密和解密在默认模式(ECB/PKCS5PADDING)下正常工作,但是当我尝试使用 CBC 并解密我的文件时,我得到一些文本是垃圾(或者当我尝试图像时它被损坏了。

谁能看到我做错了什么? (我的导入没有包含,如有需要可以添加)

public class encwork {
private static String keyString = "ykHySDZCWr16TVku"; //Encryption key
private static void bulkWork(int cipherMode, File inputFile, File outputFile) throws Exception{
    //Let the user enter the key they wish to use
    Key secretKey = new SecretKeySpec(keyString.getBytes(), "AES"); //Generates a key based on the default keysize for the specified algorithm

    //Generate an Initialization Vector (IV)
    final int ALG_KEYLENGTH = 128; //Change this as desired for the security level you want
    byte[] iv = new byte[ALG_KEYLENGTH / 8]; //Save the IV bytes or send it in plaintext with the encrypted data so you can decrypt the data later
    SecureRandom prng = new SecureRandom(); //Use SecureRandom to generate random bits. The size of the IV matches the blocksize of the cipher
    prng.nextBytes(iv); //Construct the appropriate IvParameterSpec object for the data to pass to Cipher's init() method

    //Create a Cipher by specifying the following parameters: Alg name, Mode (CBC), Padding (PKC7/PKCS5)
    Cipher cipherForEncryption = Cipher.getInstance("AES/CBC/PKCS5PADDING"); // Must specify the mode explicitly as most JCE providers default to ECB mode

    //Initialize the Cipher for Encryption
    cipherForEncryption.init(cipherMode, secretKey, new IvParameterSpec(iv));

    //Declare / Initialize the Data, Convert the Input to Bytes and encrypt or decrypt using doFinal.
    FileInputStream inputStream = new FileInputStream(inputFile);
    byte[] inputBytes = new byte[(int) inputFile.length()];
    inputStream.read(inputBytes);
    byte[] outputBytes = cipherForEncryption.doFinal(inputBytes);
    FileOutputStream outputStream = new FileOutputStream(outputFile);
    outputStream.write(outputBytes);
    inputStream.close();
    outputStream.close();
}

public static void main(String[] args) {
    File inputFile = new File("C:/Users/admin/Desktop/Crypto/In/test.txt"); 
    File encryptedFile = new File("C:/Users/admin/Desktop/Crypto/Enc/test.encrypted");
    File decryptedFile = new File("C:/Users/admin/Desktop/Crypto/Dec/testdec.txt");

    //Encryption
    try {
        encwork.encrypt(inputFile, encryptedFile); //Encrypt method
    } catch (Exception e) {
        e.printStackTrace(); //Will show what caused the error in the console if an error occurs
    }

    //Decryption
    try {
        encwork.decrypt(encryptedFile, decryptedFile); //Decrypt method
    } catch (Exception e) {
        e.printStackTrace(); //Will show what caused the error in the console if an error occurs
    }
}

public static void encrypt(File inputFile, File outputFile) throws Exception {
    bulkWork(Cipher.ENCRYPT_MODE, inputFile, outputFile); //ENC_MODE = Constant used to initialize cipher to encryption mode.
}

public static void decrypt(File inputFile, File outputFile) throws Exception {
    bulkWork(Cipher.DECRYPT_MODE, inputFile, outputFile); //ENC_MODE = Constant used to initialize cipher to encryption mode.
}}

【问题讨论】:

  • “有些文本是垃圾”是什么意思?也许是前 16 个字节?
  • @zaph 基本上我的测试文件只是一个文本文件,一遍又一遍地写着“这是一个测试”,但是当我解密文件时,第一行是“çQßs}@ L¤qMä]this是一个测试”。我认为这是一个填充问题,因为当我使用默认加密/解密 (ECB) 时我没有这个问题。
  • 填充是在加密数据的末尾,而不是开头。

标签: java encryption jce


【解决方案1】:

您没有使用相同的 IV 进行加密和解密。

从解密开始的评论中:“第一行是“çQßs}@L¤qMä]这是一个测试”,这意味着加密和解密的IV不一样。

这条评论说明了一切:

//保存 IV 字节或将其与加密数据一起以明文形式发送,以便您稍后解密数据

要么:

  1. 通过从加密中返回 IV 并在解密时传递它来保存 IV

  1. 使用 IV 为加密数据添加前缀,并在解密时将其拆分以用于解密。 (IV 不需要保密)

有关 IV 和 CBC 模式的更多信息,请参阅Cipher Block Chaining (CBC)

虽然 IV 影响整个加密数据,但 CBC 模式是自我纠正的,这意味着当解密时使用错误的 IV 时,只有第一个块是不正确的。

【讨论】:

  • 感谢您的建议。请原谅我的无知,因为我最近才开始使用 JCE,但是我需要更改我的代码以确保使用相同的 IV?
  • 请参阅答案中的 2. 以获得合理的标准方法。简而言之,只需在第一个加密数据之前将 IV 写入文件。解密时读取前 16 个字节并将其用作 IV,然后立即开始解密数据。
  • 这是否意味着在我的加密和解密函数中,我需要将我的密钥和 IV 作为输入以及输入和输出文件?
  • 对,写两个函数。最好写两个函数,条件越多越混乱,错误越多。由于 IV 不需要保密,并且每次加密都应该不同,因此最简单的方法是将其放在文件中加密数据的开头。
  • 老实说,我有点困惑,我不确定该怎么做。您是否可以帮助告诉我我应该在代码中的哪个位置进行更改,以确保我使用相同的 IV 进行加密和解密。
猜你喜欢
  • 2015-05-22
  • 1970-01-01
  • 2012-02-04
  • 1970-01-01
  • 2014-01-22
  • 2020-05-28
  • 2018-06-12
  • 1970-01-01
  • 2013-12-02
相关资源
最近更新 更多