-1
 Cipher cipher = Cipher.getInstance("AES/CFB128/NoPadding");
 SecretKeySpec keySpec = new SecretKeySpec("1234567890123456".getBytes(), "AES");
 byte[] iv = "1234567890123456".getBytes();
 cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));
 Cipher decryptCipher = Cipher.getInstance("AES/CFB128/NoPadding");
 decryptCipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv));
 byte[] data = cipher.doFinal("1234567890123456".getBytes());

 for (byte b : data) {
    byte[] output = decryptCipher.update(new byte[]{b});
    System.out.println(new String(output));
 }

I use JCE to decrypt some data encrypt with AES_128_CFB, but I found decrycipher.update would return an empty array for the first 15 times. The decryptCipher's block size is 16. Should a CFB cipher work in stream mode? I retest this code in golang, and it works fine.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Wei Jian Guo
  • 123
  • 1
  • 10

1 Answers1

1

Just because the block cipher mode can work in principle with bit-precision streaming doesn't mean that an API implementing this mode must honor that. CFB-128 uses a segment size of 128 bit which means that it needs 16 bytes for one encryption which is coincidentally also the block size. It can create a part (same size as the segment size) of the key stream in advance, before the data to encrypt even arrives.

A possible way to explain this behavior is to look at how the code would change if the behavior changes from generating the key stream in advance or generating it after a full segment has arrived. One might be easier to implement or read over the other. Now, I'm not saying that the code that has this behavior is necessarily easier to read, but I'm saying that the class diagram of JCE is rather complicated and this was probably an easy way to implement CFB.

Another reason for doing this might be to limit the amount of time that the key stream is available in the process memory. For example, if the key stream is calculated in advance (which would mean that Cipher#update has the same output size as its input) we might come into the situation that a part of the key stream is available in memory and can be taken by another process on the same machine. If the key stream is not generated in advance, then it only exists when it is needed and therefore only a very short amount of time.
If we spin the thought further we see that if an attacker can access the key stream they can also access the sub keys of AES. If they can't do that they can certainly access the ciphertext and plaintext to calculate the key stream from that. Whether this is useful to them is another question, but generally it's not.

The only thing that must be accomplished in CFB mode is that the input and output have the same size and that can only be checked after calling Cipher#doFinal.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222