[Mono-bugs] [Bug 60573][Nor] New - CryptoStream output 1 block short after Flush

bugzilla-daemon@bugzilla.ximian.com bugzilla-daemon@bugzilla.ximian.com
Tue, 22 Jun 2004 13:27:04 -0400 (EDT)


Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

Changed by t7@pobox.com.

http://bugzilla.ximian.com/show_bug.cgi?id=60573

--- shadow/60573	2004-06-22 13:27:04.000000000 -0400
+++ shadow/60573.tmp.24951	2004-06-22 13:27:04.000000000 -0400
@@ -0,0 +1,215 @@
+Bug#: 60573
+Product: Mono: Class Libraries
+Version: unspecified
+OS: 
+OS Details: Other
+Status: NEW   
+Resolution: 
+Severity: 
+Priority: Normal
+Component: System.Security
+AssignedTo: mono-bugs@ximian.com                            
+ReportedBy: t7@pobox.com               
+QAContact: mono-bugs@ximian.com
+TargetMilestone: ---
+URL: 
+Cc: 
+Summary: CryptoStream output 1 block short after Flush
+
+Please fill in this template when reporting a bug, unless you know what you
+are doing.
+Description of Problem:
+When a CryptoStream is created from an encryptor and a multiple of the
+block size is written to it.  It outputs one block short after a Flush.
+
+System is Redhat Fedora Core 2 with kernel 2.6.5.  Mono beta3 release.
+
+Steps to reproduce the problem:
+1. Compile and run the test code included
+2. 
+3. 
+
+Actual Results:
+outputs
+CryptoStreamOutput: Write(buffer, offset=0, count=56)
+CryptoStreamOutput: Flush()
+
+Expected Results:
+should output
+CryptoStreamOutput: Write(buffer, offset=0, count=64)
+CryptoStreamOutput: Flush()
+
+
+How often does this happen? 
+Every time
+
+Additional Information:
+I think this is an implementation bug, but I'm new to the
+mono crypto API, so it could be a misunderstanding on my
+part.
+As you can see from the code, I instantiate a 3DES provided.
+This has a BlockSize of 64 by default.  I create the encryptor
+via CreateEncryptor() and the resulting ICryptoTransform has 
+an inpout/output block size of 8.
+So, when I write 64 bytes (a multiple of 8) to the crypto stream
+and do a flush, I'd expect 64 bytes out - but I only get 56
+(8 short).  In my actual application there is a network stream
+between the encryptor and decryptor, but I always get blocked
+waiting for the block that never comes.
+Note also, that the block is not lost. Pushing another 64 bytes into
+the stream causes the missing 8 bytes to come out, followed by another
+56 bytes corresponding to the second 64 bytes (again, 8 short after the Flush).
+
+Here is the code.  Not that the most part is just the impl of the
+DebugStream, which is just a pass-through stream to show what's
+happening.  Omitting it and just using the few lines of Main
+without the DebugStream will also reproduce the problem.
+
+Hope this helps.  Sorry if it isn't really a bug.
+
+
+using System;
+using System.IO;
+using System.Security.Cryptography;
+
+
+
+//
+// DebugStream is just a pass-through that displays the method call args
+//
+
+class DebugStream : Stream
+{
+  public DebugStream(Stream s, string name)
+  {
+    this.s = s;
+    this.name = name;
+  }
+
+  
+  public bool disp = true; // display?
+  public string name = "DebugStream";
+  
+
+  public override bool CanRead { get {return s.CanRead;} }
+  public override bool CanSeek { get {return s.CanSeek;} }
+  public override bool CanWrite { get {return s.CanWrite;} }
+  public override long Length { get {return s.Length;} }
+  public override long Position { get {return s.Position;} set
+{s.Position=value;} }
+  
+  public override void Close () { s.Close(); }
+
+  
+  public override void Flush () 
+  {
+    if (disp) Console.WriteLine(name+": Flush()"); 
+    s.Flush(); 
+  }
+
+  public override int Read (byte[] buffer, int offset, int count) 
+  {
+    if (disp) Console.Write(name+": Read(buffer, offset="+offset+",
+count="+count+")"); 
+    int res = s.Read(buffer, offset, count);
+    if (disp) Console.WriteLine(" -> "+res);
+    return res;
+  }
+
+  public override int ReadByte () 
+  {
+    if (disp) Console.Write(name+": ReadByte()");
+    int res = s.ReadByte(); 
+    if (disp) Console.WriteLine(" -> "+res);
+    return res;
+  }
+
+  public override long Seek (long offset, SeekOrigin origin) { return
+s.Seek(offset, origin); }
+
+  public override void SetLength (long value) { s.SetLength(value); }
+
+  public override void Write (byte[] buffer, int offset, int count) 
+  {
+    if (disp) Console.WriteLine(name+": Write(buffer, offset="+offset+",
+count="+count+")");
+    s.Write(buffer, offset, count); 
+  }
+
+  public override void WriteByte (byte value) 
+  { 
+    if (disp) Console.WriteLine(name+": WriteByte(value="+value+")");
+    s.WriteByte(value); 
+  }
+
+  public override IAsyncResult
+  BeginRead (byte [] buffer, int offset, int count, AsyncCallback cback,
+object state)
+  { 
+    if (disp) Console.WriteLine(name+": BeginRead(buffer, offset, count,
+cback, state)");
+    return s.BeginRead(buffer, offset, count, cback, state); 
+  }
+
+
+  public override IAsyncResult
+  BeginWrite (byte [] buffer, int offset, int count, AsyncCallback cback,
+object state)
+  {
+    if (disp) Console.WriteLine(name+": BeginWrite(buffer, offset, count,
+cback, state)");
+    return s.BeginWrite(buffer, offset, count, cback, state);
+  }
+  
+  public override int EndRead (IAsyncResult async_result)
+  { 
+    if (disp) Console.WriteLine(name+": EndRead(async_result)");
+    return s.EndRead(async_result); 
+  }
+
+  public override void EndWrite (IAsyncResult async_result)
+  {
+    if (disp) Console.WriteLine(name+": EndWrite(async_result)");
+    s.EndWrite(async_result);
+  }
+
+    
+  protected Stream s;
+  
+}
+
+
+
+
+
+public class CryptoTest
+{  
+
+  // 64 bytes
+  static public byte[] data =
+System.Text.Encoding.ASCII.GetBytes("0123456789012345678901234567890123456789012345678901234567890123");
+ 
+  public static void Main(string[] args)
+  {
+
+    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
+    tdes.GenerateKey();
+    tdes.GenerateIV();
+
+    // wrap a DebugStream around Stream.Null so we can see what calls
+CryptoStream makes to it's underlying Stream
+    DebugStream outDebugStream = new DebugStream(Stream.Null,
+"CryptoStreamOutput"); 
+
+    // feed that with a CryptoStream
+    CryptoStream encStream = new CryptoStream(outDebugStream,
+tdes.CreateEncryptor(), CryptoStreamMode.Write);
+
+    
+    // feed some data to the crypto stream
+    encStream.Write(data,0,64); // 64 bytes out
+    encStream.Flush();
+    
+  }
+
+}