如何将加密器重置为初始化时的状态?

3
为了保留密钥、初始向量和操作模式,并重置所有缓冲区等内容,调用doFinal()方法是正确的吗? 但是doFinal()会做额外的工作。我不需要之前的数据。
Cipher с=Cipher.getInstance("AES/CBC/PKCS7Padding");
с.init(Cipher.DECRYPT_MODE, key, iv);
....

void Decode(Cipher c)
{
   c.doFinal();//reset cipher !?
   //Start a new decoding session
   ....
}

创建一个新的Cipher对象,怎么样? - Artjom B.
当然是可能的,但使用一份副本会更方便。 - Mixer
不,如果您无法确定Cipher实例的状态,仅使用一个副本是一个非常糟糕的想法。Cipher实例并不会占用太多资源,而且您可能需要一个新的初始化向量,对吧? - Maarten Bodewes
我将解释为什么我需要它。 Decode函数对于解码同一文件的小片段是必要的。 加密数据与未加密的头部交错在一起。 即,在我的情况下,密码本没有改变,所有片段都相同。 我假设99%的情况下doFinal不会有任何作用。 由于缓存中的数据,Cipher只能在加密前一个片段时产生错误或异常。 也就是说,这种方法应该尽可能快地工作。 重要的是,从数据完整性的角度来看,可以使用此方法。你认为呢? - Mixer
2个回答

2

当然,你需要调用 Cipher.init()。

你只需要重新安排API,以便为您的方法提供正确的参数,以便它们可以调用init()

无论如何,您可能需要为每个单独的加密/解密使用一个新的初始化向量。


有时候你确实需要使用相同的IV(或在ECB模式下)加密/解密许多小数据块。Cipher.init()会有很多开销,因为每次调用都会检查SPI、基于密钥大小的出口限制、豁免等。 - jurez

0

好消息!您不需要做任何事情。在调用doFinal()之后,密码将重置为其初始状态。以下是演示:

public static void main(String[] args) throws Exception {

    Cipher aes = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    SecretKeySpec key = new SecretKeySpec("YELLOW SUBMARINE".getBytes(), "AES");
    IvParameterSpec iv = new IvParameterSpec(new byte[16]);

    aes.init(Cipher.DECRYPT_MODE, key, iv);

    byte[] cipherText = DatatypeConverter.parseHexBinary("60FA36707E45F499DBA0F25B922301A57192FEBE51B66D25BBFCC348138FD3F7");

    System.out.println(DatatypeConverter.printHexBinary(aes.doFinal(cipherText)));
    System.out.println(DatatypeConverter.printHexBinary(aes.doFinal(cipherText)));
}

我得到了输出:
10101010101010101010101010101010
10101010101010101010101010101010

请注意,Java Sun Crypto provider 将其称为 PKCS5PADDING 而不是 PKCS7。如果您使用不同的加密提供程序,请按其文档建议使用。请注意,我通过加密 16 个 0x10 字节来生成密码文本。我假设它不会填充,但实际上它确实填充了。

不是错误,但“doFinal”已经在问题中提到了。 - Maarten Bodewes
似乎 doFinal() 并没有真正重置任何东西,而 init() 则有。 - ed22
如果您的密文填满了最后一个加密块,您将获得另一个完整的填充块 ;) - ed22
尽管现在可能有效,但使用它并不是一个好主意,因为它没有文档记录。行为可能会随着不同版本的更改而改变,最终导致数据损坏。 - jurez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接