Date: Wed, 13 Aug 1997 12:01:12 -0700
From: "J. Kelly Johnson" <kellyj@ricochet.net>
To: Marianne Mueller <java-security@web2.javasoft.com>
Subject: Buffering bug with CipherInputStream using decrypt Cipher?
This is a multi-part message in MIME format.
--------------59E7330339FCD48B11A4DA81
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
I am testing JCE with JDK1.1.3 and am having problems with
CipherInputStream in decrypt mode. My test program (CipherTest.java,
attached) simply:
1) Generates a DES key.
2) Initializes an encrypt Cipher (getInstance("DES/ECB/PKCS#5))
3) Reads a test file "input.clear" 100 bytes at a time and writes
it to an output file "input.encrypted" using CipherOutputStream
and the encrypt Cipher.
4) Initializes a decrypt Cipher (using the same DES key as used to
encrypt, of course).
5) Reads the newly created "input.encrypted" with a CipherInputStream
using the decrypt Cipher and a read loop with a 100 byte buffer,
writing the decrypted output to "input.decrypted".
The program seems to always create a complete and properly encrypted
"input.encrypted" file from the "input.clear" file (the file sizes
are equivalent to within a few bytes and the file can be at least
partially decrypted by the decrypt stage). However, when decrypting
the "input.encrypted" file to create the "input.decrypted" file with
the 100 byte buffer read-loop, short reads occur (less than 100
bytes are returned), and the next read skips the data that was
shorted in the previous read. The result is that the "input.decrypted"
file ends up containing in-order decrypted fragments of the original
file.
However, if you increase the buffer size of the decrypt read loop
such that the whole file can be read in one read, then all is
decrypted properly without any loss of data.
This appears to me to be a buffering bug in the implementation of
CipherInputStream using decryption Ciphers, or am I missing something
basic here? Please compile and run the attached small CipherTest.java
program (using a simple text "input.clear" file in the current
directory of at least 700 bytes in size) and see if you get the same
results.
Your help is much appreciated,
J. Kelly Johnson
AppletVisions, Inc. (Subsidiary of LSS)
--------------59E7330339FCD48B11A4DA81
Content-Type: text/plain; charset=us-ascii; name="CipherTest.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="CipherTest.java"
import java.io.*;
import java.security.*;
public class CipherTest {
public static void main(String args[]) {
/*****************************************************************/
/* */
/* Generate a DES key. */
/* */
/*****************************************************************/
Key des_key;
try {
Provider provider = Security.getProvider("SUN");
System.out.println("SUN Provider info: " + provider.getInfo());
KeyGenerator key_generator = KeyGenerator.getInstance("DES", "SUN");
System.out.println("KeyGenerator is " + key_generator);
SecureRandom random = new SecureRandom();
key_generator.initialize(random);
des_key = key_generator.generateKey();
}
catch (Exception e) {
System.out.println("Exception generating key: " + e);
return;
}
/*****************************************************************/
/* */
/* Initialize an encrypt Cipher. */
/* */
/*****************************************************************/
Cipher des_cipher;
try {
des_cipher = Cipher.getInstance("DES/ECB/PKCS#5");
des_cipher.initEncrypt(des_key);
}
catch (Exception e) {
System.out.println("Error initializing encrypt cipher: " + e);
return;
}
/*****************************************************************/
/* */
/* Write out an encrypted version of the test input file */
/* "input.clear" to "input.encrypted" using a */
/* CipherOutputStream. */
/* */
/*****************************************************************/
System.out.println("\nReading from \"input.clear\" and " +
"writing to \"input.encrypted\"...");
InputStream in;
OutputStream out;
byte [] buffer = new byte[100];
int bytes_read;
int total_bytes_read = 0;
try {
in = new FileInputStream("input.clear");
out = new CipherOutputStream(
new FileOutputStream("input.encrypt"), des_cipher);
while ((bytes_read = in.read(buffer)) != -1) {
out.write(buffer, 0, bytes_read);
System.out.println(" Bytes read/written: " + bytes_read);
total_bytes_read += bytes_read;
}
in.close();
out.close();
System.out.println("Total bytes read from \"input.clear\" " +
"and written to \"input.encrypted\" was " + total_bytes_read);
}
catch (Exception e) {
System.out.println("Error creating encrypted file: " + e);
return;
}
/*****************************************************************/
/* */
/* Initialize a decrypt Cipher. */
/* */
/*****************************************************************/
try {
des_cipher = Cipher.getInstance("DES/ECB/PKCS#5");
des_cipher.initDecrypt(des_key);
}
catch (Exception e) {
System.out.println("Error initializing decrypt cipher: " + e);
return;
}
/*****************************************************************/
/* */
/* Read in the encrypted file "input.encrypted" using a */
/* decrypting CipherInputStream and write out the decrypted */
/* result to "input.decrypted". */
/* */
/*****************************************************************/
System.out.println("\nReading from \"input.encrypted\" " +
"and writing to \"input.decrypted\"...");
buffer = new byte[100];
int total_bytes_written = 0;
try {
in = new CipherInputStream(
new FileInputStream("input.encrypt"), des_cipher);
out = new FileOutputStream("input.decrypt");
while ((bytes_read = in.read(buffer)) != -1) {
out.write(buffer, 0, bytes_read);
System.out.println(" Bytes read/written: " + bytes_read);
total_bytes_written += bytes_read;
}
in.close();
out.close();
System.out.println("Total bytes written to \"input.decrypt\" was " +
total_bytes_written + ".");
}
catch (Exception e) {
System.out.println("Error creating decrypted file: " + e);
}
}
}
--------------59E7330339FCD48B11A4DA81--