Stream Encryption Modeling with AES / CTR

I am writing an application server, and I decided to use AES128 / CTR / NoPadding to protect the connections, since it is considered quite safe without the need to expand bytes to the block boundary, and I thought this worked well for TCP, which is a logically seamless stream.

The problem is that Cipher.update () does not return an encrypted block until it has a full 16-byte block, because CTR is mainly based on a block cipher, simulating a stream cipher. I have to read the data from the tcp socket and process the messages as soon as they arrive, but I can’t get the last block because it is still building up and its size is less than 16 bytes. And I can’t just wait, because we don’t know when the next message will be sent. Of course, I could call Cipher.doFinal () to get the rest, but that would mean the end of the stream (connection), and the Cipher object would be reinitialized.

I thought it would be nice if there was a way to look at the transference. CTR is just XOR representing plain text using a key stream, so I should be able to receive encrypted data regardless of the rest of the bytes in the block. Will there be a good way around this problem? I am thinking of writing a wrapper that encrypts fake text with zeros to get the key stream in advance and XOR manually, but I wonder how other people solved this problem.

Update

I am developing an Android application and it turned out that this is a VM Dalvik problem. As Robert and Monnand noted below, Java SE does not have this problem, at least with the default provider. I think I will have to write a shell class or change the mode to CFB8 to get around this problem. (CTR8 doesn't work) Thanks for all the answers!

+7
source share
3 answers

I just tested AES in CTR mode using Oracle Java 1.7, and I cannot verify your observations:

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 

Perhaps you are using a third-party defect implementation because "AES128 / CTR / NoPadding" is not a known cipher on my system.

+6
source

I had exactly the same problem and today it is fixed.

The problem is with your provider, which is probably Bouncy Castle . When you call getInstance() , just provide the name of your algorithm (which in my case is "AES / CTR / NoPadding"). DO NOT specify a supplier.

Let the code itself explain:

As @Robert said, the following code works correctly:

 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 

However, if you specify the provider as "BC", this will be incorrect:

 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 

This can be seen as a Bouncy Castle bug or a kind of (strange but reasonable) feature.

+4
source

I didn’t have to solve this problem myself, but one way to solve this problem would be to create a key stream manually and manage XORing myself.

That is, you must switch from AES/CTR/NoPadding to AES/ECB/NoPadding and repeatedly encrypt the counter increment value when you need fresh data for XOR with encrypted text.

From the ideal, but I believe that it will work.

0
source

All Articles