Bug in Cipher ?

I ve come across what I believe is a bug in the JRE. Posting to this forum to get input from someone else and double check I m not missing something before I submit a bug report.

In a nutshell, if I pass a bytebuffer which has a position >0 to the method

doFinal(clearBuffer, outBuffer);

for the output buffer, the encryption gets corrupted every 4K bytes, for one full padding of 16 bytes. (encryption is correct for the first 4096 bytes)

If I don t advance the position, the encryption works fine.

package test;

import java.nio.ByteBuffer;

import java.util.Random;

import javax.crypto.Cipher;

import javax.crypto.spec.SecretKeySpec;

publicclass EncryptionBug{

// set this buffer to at least 4096 bytes for the bug to appear

staticint BUFFER_LENGTH = 4111;

//set this offset to >0 for the bug to appear

staticint OUTPUT_OFFSET = 4;

publicstaticvoid main(String[] args){

byte[] encryptionKey =newbyte[16];

new Random().nextBytes(encryptionKey);

Cipher cipherEncrypt;

try{

SecretKeySpec skeySpec =new SecretKeySpec(encryptionKey,"AES");

cipherEncrypt = Cipher.getInstance("AES");

Cipher cipherDecrypt = Cipher.getInstance("AES");

cipherEncrypt.init(Cipher.ENCRYPT_MODE, skeySpec);

cipherDecrypt.init(Cipher.DECRYPT_MODE, skeySpec);

byte data[] =newbyte[BUFFER_LENGTH];

new Random().nextBytes(data);

ByteBuffer outBuffer = ByteBuffer.allocateDirect(65536);

ByteBuffer clearBuffer = outBuffer.duplicate();

clearBuffer.put(data);

clearBuffer.flip();

outBuffer.position(OUTPUT_OFFSET);

int length = cipherEncrypt.doFinal(clearBuffer, outBuffer);

byte[] encryptedBuffer =newbyte[length];

for (int i = 0; i < encryptedBuffer.length; i++){

encryptedBuffer[i] = outBuffer.get(OUTPUT_OFFSET + i);

}

byte encryptedDirect[] = cipherEncrypt.doFinal(data);

for (int i = 0; i < encryptedBuffer.length; i++){

if (encryptedDirect[i] != encryptedBuffer[i]){

System.out.println("********* corrupted index " + i +" "

+ encryptedBuffer[i] +" vs " + encryptedDirect[i]);

}

}

}catch (Exception ex){

ex.printStackTrace();

}

}

}

[4058 byte] By [Irwina] at [2007-11-27 10:33:57]
# 1

also not that this issue is only reproducible with direct byte buffers. With regular byte buffers, it works fine.

Irwina at 2007-7-28 18:25:49 > top of Java-index,Security,Cryptography...
# 2

I've done a bit of investigation on this and though more is required I don't think this is a Cipher problem. It seems that ByteBuffer clearBuffer = outBuffer.duplicate();

does not create a buffer with the capacity of the original and if I use ByteBuffer clearBuffer = ByteBuffer.allocateDirect(65536);

then everything works as expected.

It seems to me that the duplicate() method just allocates 4096 bytes.

I don't know enough about ByteBuffer and NIO to say whether or not this is expected behaviour - maybe ejp will know.

sabre150a at 2007-7-28 18:25:49 > top of Java-index,Security,Cryptography...
# 3

Having looked at the Javadoc for duplicate() I seepublic abstract ByteBuffer duplicate()

Creates a new byte buffer that [b]shares[/b] this buffer's content.

The content of the new buffer will be that of this buffer. Changes to this buffer's content will be visible in the new buffer, and vice versa; the two buffers' position, limit, and mark values will be independent.

The new buffer's capacity, limit, position, and mark values will be identical to those of this buffer. The new buffer will be direct if, and only if, this buffer is direct, and it will be read-only if, and only if, this buffer is read-only.

which indicates that the two buffers will have the same capacity and that they share the same backing array. This means that your outBuffer and your clearBuffer share the same byte array.

Your cipher is reading from one buffer and writing to the other which means it is overwriting the original data! At best this seems dangerous.

Based on this, I don't think you have found a bug in Cipher.

sabre150a at 2007-7-28 18:25:49 > top of Java-index,Security,Cryptography...
# 4

I think your statement is incorrect.

According to the javadoc, we can share the same buffer.

http://java.sun.com/j2se/1.5.0/docs/api/javax/crypto/Cipher.html#doFinal(java.nio.ByteBuffer,%20java.nio.ByteBuffer)

Note: this method should be copy-safe, which means the input and output buffers can reference the same byte array and no unprocessed input data is overwritten when the result is copied into the output buffer.

Additionally, the fact that using a non-direct byte array works perfectly fine when sharing the same array seems to concur this fact.

The issue seems related to direct byte arrays only, when advancing position.

So far it still looks like to me a bug in the JRE.

Comments welcome

Irwina at 2007-7-28 18:25:49 > top of Java-index,Security,Cryptography...
# 5

> I think your statement is incorrect.

> According to the javadoc, we can share the same

> buffer.

> http://java.sun.com/j2se/1.5.0/docs/api/javax/crypto/C

> ipher.html#doFinal(java.nio.ByteBuffer,%20java.nio.Byt

> eBuffer)

>

> Note: this method should be copy-safe, which means

> the input and output buffers can reference the same

> byte array and no unprocessed input data is

> overwritten when the result is copied into the output

> buffer.

>

Looks like you are right BUT the use of "should be copy-safe " is interesting. I would have expected "is copy-safe" or "shall be copy-safe".

Of course the question now is - is this a problem with Cipher or a problem with ByteBuffer?

sabre150a at 2007-7-28 18:25:49 > top of Java-index,Security,Cryptography...
# 6

I looked over the source code. I think the relevant portions are contained in javax.crypto.CipherSpi, particularly in the method named bufferCrypt. It looks pretty hairy, perfect for hiding a bug. Plus, the ByteBuffer stuff is new to 1.5. I note that, if one of the buffers is direct, a temporary array of size at most 4096 is created. Looks suspicious. You should consider submitting a bug report.

ghstarka at 2007-7-28 18:25:49 > top of Java-index,Security,Cryptography...
# 7

Thanks for looking. I submitted a bug report.

Irwina at 2007-7-28 18:25:49 > top of Java-index,Security,Cryptography...
# 8

> Thanks for looking. I submitted a bug report.

Could you post the BUG number when you receive it.

sabre150a at 2007-7-28 18:25:49 > top of Java-index,Security,Cryptography...
# 9

It s been assigned a reviewID for now.

I ll update this thread once I get further feedback from Sun.

Irwina at 2007-7-28 18:25:49 > top of Java-index,Security,Cryptography...
# 10

Official bug

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6582580

Irwina at 2007-7-28 18:25:49 > top of Java-index,Security,Cryptography...