2013-04-30 90 views
7

我正在编写应用程序服务器,并决定使用AES128/CTR/NoPadding来保护连接,因为它被认为是足够安全的,无需将字节扩展到块我认为这很适合TCP,这在逻辑上是无缝的流。使用AES/CTR模拟流密码

问题是Cipher.update()直到它有一个完整的16字节块才返回加密块,因为CTR虽然模拟流密码基本上基于块密码。我应该从tcp套接字读取数据,并在它们到达时立即处理消息,但我无法检索最近的数据块,因为它仍在建立,其大小小于16个字节。而且我不能等待,因为我们不知道何时会发送下一封邮件。当然,我可以调用Cipher.doFinal()来获得剩余,但这意味着流(连接)的结束和Cipher对象将被重新初始化。

我认为这将是很好,如果有一种方法来偷看carryover。 CTR只需将纯文本与密钥流进行XOR即可,因此无论块中的其余字节如何,我都能够获得加密数据。会不会有一个很好的解决方法来解决这个问题?我正在考虑编写一个封装器,用零来加密伪造的纯文本,以便事先获得密钥流并手动进行XOR,但我不知道其他人是如何解决这个问题的。

更新

我开发一个Android应用程序,它原来,这是Dalvik虚拟机的问题。正如Robert和Monnand在下面指出的那样,Java SE至少在缺省提供程序中没有这个问题。我想我必须编写一个包装类或将模式更改为CFB8以解决此问题。 (CTR8不起作用)感谢所有的回应!

+0

你能填充消息的长度是16的倍数吗?这将确保您始终以可解密的块结束。 – 2013-04-30 05:24:46

+0

@Chris:感谢您的建议,这可能是一种可能的解决方法。但是,如果可能的话,我想避免这种情况,因为在网络效率方面它不是最好的,尽管它可能可以忽略不计。 – 2013-04-30 05:27:25

+0

您可以简单地在由零组成的数组上调用它来获得密钥流。然后将其手动输入到消息中。 – CodesInChaos 2013-04-30 10:34:33

回答

6

我只是使用Oracle的Java 1.7测试AES的CTR模式,我无法核实你的意见:

Cipher c = Cipher.getInstance("AES/CTR/NoPadding"); 
KeyGenerator kg = KeyGenerator.getInstance("AES"); 
c.init(Cipher.ENCRYPT_MODE, kg.generateKey()); 
System.out.println(c.update(new byte[1]).length); // output: 1 
System.out.println(c.update(new byte[20]).length); // output: 20 

可能是你使用的缺陷第三方实现,因为“AES128/CTR/NoPadding”不是已知的密码在我的系统上。

+0

你说得对,这是Android Dalvik虚拟机的问题,而不是Java SE。 – 2013-05-01 06:13:19

0

我自己并没有必须解决这个问题,但是一种解决方法是手动生成密钥流并自己处理XOR。

也就是说,你会切换从AES/CTR/NoPaddingAES/ECB/NoPadding并多次加密您的incrementing counter value,当你需要新的数据XOR与密文。

远非理想,但我想它会起作用。

+2

感谢您的建议。我想我可以使用CTR数组来获得密钥流。 – 2013-05-01 06:17:00

4

我今天有完全相同的问题,现在就修好了。

问题是您的提供商,这可能是Bouncy Castle。当您拨打getInstance()时,只需提供算法的名称(在我的情况下为“AES/CTR/NoPadding”)。 请勿指定提供者。

让代码交待:

正如@Robert说,下面的代码工作正常:

Cipher c = Cipher.getInstance("AES/CTR/NoPadding"); 
KeyGenerator kg = KeyGenerator.getInstance("AES"); 
c.init(Cipher.ENCRYPT_MODE, kg.generateKey()); 
System.out.println(c.update(new byte[1]).length); // output: 1 
System.out.println(c.update(new byte[20]).length); // output: 20 

但是,如果您指定的供应商为“BC”来代替,这将是错误的:

Cipher c = Cipher.getInstance("AES/CTR/NoPadding", "BC"); 
KeyGenerator kg = KeyGenerator.getInstance("AES"); 
c.init(Cipher.ENCRYPT_MODE, kg.generateKey()); 
System.out.println(c.update(new byte[20]).length); // output: 16 
System.out.println(c.update(new byte[1]).length); // null pointer exception 

它可以被认为是Bouncy Castle的一个bug,或者是一种(奇怪但合理的)特征。

+1

在我的情况下,Android Dalvik是个问题,但是多谢指出一个自定义提供程序也有同样的问题。 – 2013-05-01 06:19:09

+0

谢谢你让我知道Android有同样的问题(功能?)。这很烦人,因为counter模式的好处是它可以在没有填充的情况下使用。 – monnand 2013-05-06 22:39:39

+0

我知道这个问题已经存在了一段时间......这个问题仍然存在于公元前现代资源中吗? – jww 2016-01-18 15:30:38