0

我正在尝试使用 5-argupdate方法java.crypto.Cipher来加密/解密一堆以切片形式出现的输入数据。由于要加密的数据位于数组中的特定位置,并且我想用解密形式覆盖加密数据,因此使用 5-arg update(定义为update(src, srcOffset, length, dst, dstOffset))的原因。

但是,我遇到的问题是,在使用 AES/CBC/PKCS5PADDING 算法时,解密后输出为 32 字节的乱码。如果我从使用 5-arg 切换update到创建用于保存输出的专用数组,然后执行System.arraycopy,则输出是正确的。

这是一个简单的测试程序:

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class CryptoTest
{
  private class Slice
  {
    byte[] array;

    int offset;

    int size;
  }

  private Slice[] createSlices(int howMany, int whatSize)
  {
    Slice[] slices = new Slice[howMany];
    for (int i = 0; i < howMany; i++)
    {
        slices[i] = new Slice();
        slices[i].array = new byte[whatSize];
        slices[i].offset = 0;
        slices[i].size = 0;
    }

    return slices;
  }

  public void testWithOffsets() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, ShortBufferException,
                IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException
  {
    int num = 10;
    int size = 32784;
    Slice[] slices = createSlices(num, size);

    // Create the keys and parameters
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
    SecretKey key = keyGenerator.generateKey();

    SecretKey encryptionKey = new SecretKeySpec(key.getEncoded(), "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

    cipher.init(Cipher.ENCRYPT_MODE, encryptionKey);

    // save IV
    byte iv[] = cipher.getIV();

    // setup input data
    for (int i = 0; i < num; i++)
    {
        slices[i].offset = 16;
        slices[i].size = 32768;
    }
    slices[num - 1].size = 5424;

    // calculate a sum of input data, for comparisson later
    Long sum = 0L;
    for (int i = 0; i < num; i++)
        for (int j = slices[i].offset; j < slices[i].offset + slices[i].size; j++)
            sum = sum + slices[i].array[j];

    // encrypt
    int finalSize = 0;
    for (int i = 0; i < num; i++)
    {
        if (i == num - 1)
            finalSize = cipher.doFinal(slices[i].array, slices[i].offset, slices[i].size, slices[i].array, slices[i].offset);
        else
            finalSize = cipher.update(slices[i].array, slices[i].offset, slices[i].size, slices[i].array, slices[i].offset);
        System.err.println("Original size is " + slices[i].size + " final size is " + finalSize);
        slices[i].size = finalSize;
    }

    // decrypt
    SecretKey decryptionKey = new SecretKeySpec(key.getEncoded(), "AES");
    Cipher decipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

    IvParameterSpec ips = new IvParameterSpec(iv);
    decipher.init(Cipher.DECRYPT_MODE, decryptionKey, ips);

    for (int i = 0; i < num; i++)
    {
    /* ** */
        if (i == num - 1)
            finalSize = decipher.doFinal(slices[i].array, slices[i].offset, slices[i].size, slices[i].array, slices[i].offset);
        else
            finalSize = decipher.update(slices[i].array, slices[i].offset, slices[i].size, slices[i].array, slices[i].offset);
        System.err.println("Original size is " + slices[i].size + " final size is " + finalSize);
        slices[i].size = finalSize;
    }

    // sum of output data, should be the same as the input data
    Long newsum = 0L;
    for (int i = 0; i < num; i++)
        for (int j = slices[i].offset; j < slices[i].offset + slices[i].size; j++)
            newsum = newsum + slices[i].array[j];

    System.err.println("newsum " + newsum + " oldsum " + sum);
    assert newsum == sum;
  }

  public static void main(String[] args) throws Exception
  {
    CryptoTest ct = new CryptoTest();

    ct.testWithOffsets();
    ct.testWithoutOffsets();
  }
}

预期的输出是'newsum 0 oldsum 0',但我没有得到那个。如果我用以下标记替换循环的主体**,我会得到预期的输出:

        byte[] output = new byte[slices[i].array.length];

        if (i == num - 1)
            finalSize = decipher.doFinal(slices[i].array, 0, slices[i].size, output);
        else
            finalSize = decipher.update(slices[i].array, 0, slices[i].size, output);
        System.err.println("Original size is " + slices[i].size + " final size is " + finalSize);
        slices[i].size = finalSize;
        System.arraycopy(output, 0, slices[i].array, 0, finalSize);

因此,我的问题是我在这里做错了什么?我希望这两种形式都能正常工作。

4

0 回答 0