# Re: CipherOutputStream flush() bug

Gigi Ankeny (Gigi.Ankeny@Eng)
Fri, 16 Jan 1998 14:11:46 -0800 (PST)

- Messages sorted by: [ date ][ thread ][ subject ][ author ]
- Next message: Jan Luehe: "Re: Setting an IV"
- Previous message: Jonathan Knudsen: "CipherOutputStream flush() bug"
- Maybe in reply to: Jonathan Knudsen: "CipherOutputStream flush() bug"

    Date: Fri, 16 Jan 1998 14:11:46 -0800 (PST)

    From: Gigi Ankeny <Gigi.Ankeny@Eng>

    Subject: Re: CipherOutputStream flush() bug

    To: java-security@web1.javasoft.com, jonathan@oreilly.com

Hi Jonathan,

I believe this is not a bug.

CipherOutputStream.flush method is called when you want to tell
the Cipher class that you are done with this input. The flush method
in fact calls for doFinal method in the Cipher class. (Take a look at
the doc for Cipher class and see what doFinal's implications are.)
DoFinal method resets the Cipher class internal state and gets it ready
for a new input with the key and iv you initially set.

Note: in your program, you use CFB for CipherInputStream and
CipherOutputStream. This mode uses the last CipherBlock as the feedback
iv for each block encryption. Of course, it uses your JonathanSpec for
the first IV. When you call flush, the next byte being encrypted is
again using JonathanSpec instead of the cipherOutput. On the other end,
the CipherInputStream has no idea that you reset the Cipher and
it assumes normal CFB mode and continues update each byte.

A simple way to prove this is insert the following line
after the flush testing line( if (flush) out.flush();)
if (flush)
decrypterJonathan.init(Cipher.DECRYPT_MODE, key, specJonathan);

Try that and you will see the result is again correct.
Remember that each write is an update() and each flush and
close is a doFinal().
Let me know if I have not made it clear.

Thanks for your input.

Gigi

>
> I believe I've isolated a bug in CipherOutputStream's
> flush() method. Specifically, I'm trying to use DES/CFB8
> with cipher streams to transmit single bytes over a socket
> connection. When I call flush() on the CipherOutputStream,
> the data gets mangled somehow. There's a test class at
> the bottom of this message so you can reproduce the problem.
>
> Ciao,
> Jonathan
>
> ----------
>
> import java.io.*;
> import java.security.*;
>
> import javax.crypto.*;
> import javax.crypto.spec.DESParameterSpec;
>
> import oreilly.jonathan.crypto.*;
>
> public class FlushBug {
> public static void main(String[] args) throws Exception {
> testFlush(false);
> testFlush(true);
> }
>
> public static void testFlush(boolean flush) throws Exception {
> System.out.println("Flushing will " + (flush ? "" : "not") + " be done.");
> System.out.println("Creating a SecureRandom...please be patient.");
> SecureRandom sr = new SecureRandom();
>
> // Create new DES key.
> KeyGenerator kg = KeyGenerator.getInstance("DES");
> kg.init(sr);
> Key key = kg.generateKey();
>
> // Generate an IV.
> byte[] iv = new byte[8];
> sr.nextBytes(iv);
>
> // Create the listening side.
> Cipher decrypterJonathan = Cipher.getInstance("DES/CFB8/NoPadding");
> DESParameterSpec specJonathan = new DESParameterSpec(iv);
> decrypterJonathan.init(Cipher.DECRYPT_MODE, key, specJonathan);
> PipedInputStream pipedInJonathan = new PipedInputStream();
> InputStream inJonathan = new CipherInputStream(pipedInJonathan,
> decrypterJonathan);
>
> // Create the sending side.
> Cipher encrypterMichael = Cipher.getInstance("DES/CFB8/NoPadding");
> DESParameterSpec specMichael = new DESParameterSpec(iv);
> encrypterMichael.init(Cipher.ENCRYPT_MODE, key, specMichael);
> PipedOutputStream pipedOutMichael = new PipedOutputStream();
> OutputStream outMichael = new CipherOutputStream(pipedOutMichael,
> encrypterMichael);
>
> // Wire them up.
> pipedOutMichael.connect(pipedInJonathan);
>
> // Write from Michael to Jonathan.
> OutputStream out = outMichael;
> InputStream in = inJonathan;
> byte[] plaintext = "abcdef".getBytes();
> for (int i = 0; i < plaintext.length; i++) {
> out.write(plaintext[i]);
> if (flush) out.flush();
> int b = in.read();
> String original = new String(plaintext, i, 1);
> String result = new String(new byte[] { (byte)b });
> System.out.println(" " + original + " -> " + result);
> }
> }
> }
>
>

===============================================================

( Gigi Ankeny
( ( JavaSoft Security Group Engineer
------
( Java )= 408-8633135
------ gigi.ankeny@eng.sun.com
http://www-cs-students.stanford.edu/~gigi
================================================================

- Next message: Jan Luehe: "Re: Setting an IV"
- Previous message: Jonathan Knudsen: "CipherOutputStream flush() bug"
- Maybe in reply to: Jonathan Knudsen: "CipherOutputStream flush() bug"