AES使用相同的IV进行加密和解密 [英] AES use same IV for encryption and decryption

查看:87
本文介绍了AES使用相同的IV进行加密和解密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的代码存在一些问题,因此我没有使用相同的IV进行加密和解密.我知道为了正确地执行此操作,我必须在数据之前将IV写入我的输出文件,但是我正在努力实现这一点.有人可以帮我解决这个问题吗?

I'm having some issues with my code whereby I am not using the same IV for encryption and decryption. I know in order to do this correctly I have to write the IV to my output file before the data however I am struggling implementing this. Could anyone help me with this issue?

再次编辑代码以显示完整范围

public class TestFileEncryption {
    private static void mainCrypto(int cipherMode, File inputFile, File outputFile) throws Exception{
        //Let the user enter the key they wish to use
        Key secretKey = new SecretKeySpec(UITest.getStoreKey().getBytes(), UITest.getSendAlg()); //Generates a key based on the default keysize for the specified algorithm

        //Generate an Initialization Vector (IV)
        final int ALG_KEYLENGTH = UITest.getStoreKey().length(); //Change this as desired for the security level you want
        byte[] iv = new byte[ALG_KEYLENGTH]; //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(UITest.getSendAlg() + "/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() - ALG_KEYLENGTH];
        inputStream.read(iv);
        inputStream.read(inputBytes);
        byte[] outputBytes = cipherForEncryption.doFinal(inputBytes);
        FileOutputStream outputStream = new FileOutputStream(outputFile);
        outputStream.write(iv);
        outputStream.write(outputBytes);
        inputStream.close();
        outputStream.close();
    }

    public static void encrypt(File inputFile, File outputFile) throws Exception {
        mainCrypto(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 {
        mainCrypto(Cipher.DECRYPT_MODE, inputFile, outputFile); //ENC_MODE = Constant used to initialize cipher to encryption mode.
    }

    public static void main(String[] args) {}
}

推荐答案

只需扩展@Javier的答案即可.

Just extending answer of @Javier.

您似乎想对加密和解密使用相同的方法(取决于模式),但是在处理IV方面有所不同.

it looks like you'd like to use the same method for encryption and decrpytion (depending on the mode) however there's a difference in handling the IV.

您生成了一个随机IV,然后用(普通)输入的输入覆盖了它,最后将其写入到输出中(不管它是解密的).

You generated a random IV, then you overwrote it with the input of the (plain) input and at the end you wrote it to the output (regardless it's decryption).

因此,您必须区分模式是否为

So you have to distinguish if the mode is

  • 加密-生成IV,并将其写到密文之前的输出中
  • 解密-从输入读取IV,并将其用于解密,但不写入输出

类似的东西:

private void encrypt(File inputFile, File outputFile)  {
    //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()];
    byte[] iv = new byte[16]; // 16 for AES-CBC
    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(UITest.getSendAlg() + "/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));      
        inputStream.read(inputBytes);
        byte[] outputBytes = cipherForEncryption.doFinal(inputBytes);
        FileOutputStream outputStream = new FileOutputStream(outputFile);
        outputStream.write(iv);
        outputStream.write(outputBytes);
        outputStream.flush();
        inputStream.close();
        outputStream.close();
    }
}

private void decrypt(File inputFile, File outputFile) {
    //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()-16];
    byte[] iv = new byte[16]; // 16 for AES-CBC

    //Create a Cipher by specifying the following parameters: Alg name, Mode (CBC), Padding (PKC7/PKCS5)
    Cipher cipherForEncryption = Cipher.getInstance(UITest.getSendAlg() + "/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));      
    inputStream.read(iv);
    inputStream.read(inputBytes);
    byte[] outputBytes = cipherForEncryption.doFinal(inputBytes);
    FileOutputStream outputStream = new FileOutputStream(outputFile);
    outputStream.write(outputBytes);
    outputStream.flush();
    inputStream.close();
    outputStream.close();
}

为省去一些细节,也许您可​​以直接使用Java CipherOutputStream和CiptherInputStream,该实现将为您处理这些细节(如果您不关心确切的格式).

To leave out some detail, maybe you could directly use Java CipherOutputStream and CiptherInputStream and the implementation will handle these details for you (if you don't care about exact format).

接下来,您缺少的是一个身份验证标签,至少要确保明文的完整性,否则必须使用明文的哈希值.(称为经过身份验证的加密)

Next what are you missing is an authentication tag, at least hash of the plaintext assuring integrity of the ciphertext. (it's called authenticated encryption)

这篇关于AES使用相同的IV进行加密和解密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆