简体   繁体   English

如何使用新的加密数据更新部分加密数据?

[英]How to update part of the encrypted data with newly encrypted data?

I need to encrypt an audio file while it is being generated. 在生成音频文件时,我需要对其进行加密。 I am encrypting header with dummy data(because I don't know the actual size of audio data) at the starting and encrypting the audio data on the fly. 我在开始时使用伪数据(因为我不知道音频数据的实际大小)对标头进行加密,并即时对音频数据进行加密。 My plan is to update the header at the end with actual data size of audio file. 我的计划是使用音频文件的实际数据大小在末尾更新标头。

But, When I tried to overwrite the encrypted header data with newly encrypted header data of same size by using same key and IV and try to decrypt later, I am getting junk data generated. 但是,当我尝试通过使用相同的密钥和IV用相同大小的新加密头数据覆盖加密头数据并稍后尝试解密时,我得到的是垃圾数据。

Why is this happening even though I am using same key and IV? 即使我使用相同的键和IV,为什么会发生这种情况? In the below code I tried to simulate what I am doing. 在下面的代码中,我尝试模拟自己在做什么。 Encrypted file of size 64 bytes generated and decrypted file of size 50 bytes generated. 生成大小为64字节的加密文件,并生成大小为50字节的解密文件。

Without updation: abcdabcdab0123456789012345678901234567890123456789 不更新:abcdabcdab0123456789012345678901234567890123456789

With header updation: ABCDABCDAB÷‹þ@óMCKLZƒÖ^Ô234567890123456789 带有标头更新:ABCDABCDAB÷‹þ@óMCKLZƒÖ^Ô234567890123456789

Expected output: ABCDABCDAB0123456789012345678901234567890123456789 预期输出:ABCDABCDAB0123456789012345678901234567890123456789

Is this the right approach to achieve partial update of already encrypted data? 这是实现已加密数据的部分更新的正确方法吗?

protected void Encrypt()
{

    byte[] numBytes = {'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', '0','1','2','3','4','5','6','7','8','9', '0','1','2','3','4','5','6','7','8','9'};
    byte[] smallCase = {'a','b','c','d','a','b','c','d','a','b','c','d','a','b','c','d'};
    byte[] capitalCase = {'A','B','C','D','A','B','C','D','A','B','C','D','A','B','C','D'};

    try {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA1And8BIT");
        KeySpec spec = new PBEKeySpec("junglebook".toCharArray(), "Salt".getBytes(), 65536, 256);
        SecretKey tmp = null;
        tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

        /* Encryption cipher initialization. */
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);

        AlgorithmParameters params = cipher.getParameters();
        byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();

        Log.d("Encryption" + "iv data :", iv.toString());

        /*Open two Cipher ouput streams to the same encrypted file*/
        FileOutputStream os = new FileOutputStream(sdCard.getAbsolutePath() + "/Notes/sample.encrypted");
        CipherOutputStream cos = new CipherOutputStream(os,cipher);

        FileOutputStream os1 = new FileOutputStream(sdCard.getAbsolutePath() + "/Notes/sample.encrypted");
        CipherOutputStream cos1 = new CipherOutputStream(os1,cipher);

        int offset = 0;
        Log.d("Encryption", "Writing cipher text to output file");
        //Write 16 bytes header data with smallCase array
        cos.write(smallCase, offset, 16);
        // write 40 bytes actual data
        cos.write(numBytes, offset, 40);

        FileOutputStream ivStream = new FileOutputStream(sdCard.getAbsolutePath() + "/Notes/iv.dat");
        if (ivStream != null) {
            Log.d("Encryption", "Writing iv data to output file");
            ivStream.write(iv);
        }
        cos.close();

        // Overwrite header data with capitalCase array data
        cos1.write(capitalCase, offset, 16);
        cos1.close();

        ivStream.close();

    }catch (Exception e) {
        e.printStackTrace();
    }
}

protected void Decrypt()
{
    byte[] dBytes = new byte[200];

    try {

        Log.d("Decryption", "Reading iv data ");
        File f1 = new File(sdCard.getAbsolutePath()+"/Notes/iv.dat");
        byte[] newivtext = new byte[(int)f1.length()];
        FileInputStream readivStream = new FileInputStream(sdCard.getAbsolutePath()+"/Notes/iv.dat");
        if(readivStream != null) {
            readivStream.read(newivtext);
        }

        // Generate the secret key from same password and salt used in encryption
        SecretKeyFactory dfactory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA1And8BIT");
        KeySpec dspec = new PBEKeySpec("junglebook".toCharArray(), "Salt".getBytes(), 65536, 256);
        SecretKey dtmp = dfactory.generateSecret(dspec);
        SecretKey dsecret = new SecretKeySpec(dtmp.getEncoded(), "AES");

        // Initialize dcipher
        Cipher dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        dcipher.init(Cipher.DECRYPT_MODE, dsecret, new IvParameterSpec(newivtext));

        FileInputStream inputStream = new FileInputStream(sdCard.getAbsolutePath()+"/Notes/sample.encrypted");
        CipherInputStream cis = new CipherInputStream(inputStream,dcipher);
        FileOutputStream os = new FileOutputStream(sdCard.getAbsolutePath() + "/Notes/sample.decrypted");

        int b = cis.read(dBytes);
        while(b != -1) {
            Log.d("Decryption","Bytes decrypted" + b);
            os.write(dBytes, 0, b);
            b = cis.read(dBytes);
        }
        cis.close();
        os.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

I suggest you update several things: 我建议您更新几件事:

  1. you are opening multiple outputstreams to the SAME file, which is very strange, the runtime should not allow you to do that. 您正在打开多个输出流到SAME文件,这很奇怪,运行时不应允许您这样做。 So - write only with a single output if you want any predictable results. 因此-如果您想要任何可预测的结果,请仅使用单个输出编写。

  2. You may read about the mode of operations see the CRT mode uses no padding and allows you to update only a portion of the ciphertext (assuming you use no authenticated encryption). 您可能会读到有关操作模式的信息,请参阅CRT模式不使用填充,并且只允许更新部分密文(假设您不使用经过身份验证的加密)。 So AES/CTR/NoPadding could solve your problem. 因此AES/CTR/NoPadding可以解决您的问题。 (and there should be no extra bytes if you do it correctly) (如果正确执行,则不应有多余的字节)

  3. you can update a portion of the file using the RandomAccessFile and overwrite portion of the ciphertext what is needed. 您可以使用RandomAccessFile更新文件的一部分,并覆盖所需的密文部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM