我正在尝试使用 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);
因此,我的问题是我在这里做错了什么?我希望这两种形式都能正常工作。