+ Assert.AreEqual (64, cms.ToArray ().Length, "Length");
+ }
+
+ private void WriteByte (PaddingMode mode, bool padded)
+ {
+ byte[] Key = new byte[16];
+ byte[] IV = new byte[16];
+ byte[] Buffer = new byte[64];
+
+ Rijndael alg = Rijndael.Create ();
+ alg.Mode = CipherMode.CBC;
+ alg.Padding = mode;
+
+ MemoryStream cms = new MemoryStream ();
+ ICryptoTransform ct = alg.CreateEncryptor (Key, IV);
+ CryptoStream cs = new CryptoStream (cms, ct, CryptoStreamMode.Write);
+ for (int i = 0; i < Buffer.Length; i++)
+ cs.WriteByte (Buffer[i]);
+ cs.Close ();
+
+ byte[] result = cms.ToArray ();
+ // if padded then add one block, if not then it's the original length
+ int len = padded ? 80: 64;
+ Assert.AreEqual (len, result.Length, mode.ToString () + ".Encrypted.Length");
+
+ cms = new MemoryStream ();
+ ct = alg.CreateDecryptor (Key, IV);
+ cs = new CryptoStream (cms, ct, CryptoStreamMode.Write);
+ for (int i = 0; i < result.Length; i++)
+ cs.WriteByte (result[i]);
+ cs.Close ();
+
+ byte[] plaintext = cms.ToArray ();
+ Assert.AreEqual (64, plaintext.Length, mode.ToString () + ".Decrypted.Length");
+
+ Assert.AreEqual (Buffer, plaintext, mode.ToString () + ".Date");
+ }
+
+ [Test]
+ public void WriteByte ()
+ {
+ WriteByte (PaddingMode.None, false);
+ WriteByte (PaddingMode.Zeros, false);
+ WriteByte (PaddingMode.PKCS7, true); // related to bug #81597
+#if NET_2_0
+ WriteByte (PaddingMode.ANSIX923, true);
+ WriteByte (PaddingMode.ISO10126, true);
+#endif
+ }
+
+ [Test]
+ public void ReadModeDispose_FinalBlock ()
+ {
+ using (SHA1 sha1 = SHA1.Create()) {
+ using (MemoryStream mem = new MemoryStream(new byte[] { 1, 2, 3 }, false))
+ using (CryptoStream cs = new CryptoStream(mem, sha1, CryptoStreamMode.Read))
+ {
+ }
+ byte b = sha1.Hash [0]; // This will throw if TransformFinalBlock not called in sha1
+ GC.KeepAlive (b); // just the warning...
+ }
+ }
+
+ [Test]
+ public void CustomDisposeCalled ()
+ {
+ using (MemoryStream mem = new MemoryStream(new byte[] { 1, 2, 3 }, false)) {
+ MyCryptoStream cs;
+ using (cs = new MyCryptoStream (mem, SHA1.Create()))
+ {
+ }
+ Assert.IsTrue (cs.DisposeCalled, "#1");
+ }
+ }
+
+ [Test]
+ public void ExplicitFlush ()
+ {
+ // Tests that explicitly calling Flush does not call Flush in the underlying stream
+ MyStream ms = new MyStream ();
+ using (CryptoStream cs = new CryptoStream (ms, SHA1.Create (), CryptoStreamMode.Read)) {
+ ms.FlushCounterEnabled = true;
+ cs.Flush ();
+ ms.FlushCounterEnabled = false;
+ }
+ Assert.IsTrue (ms.FlushCounter == 0);
+ }
+
+ [Test]
+ public void ImplicitFlush ()
+ {
+ // Tests that Dispose() calls Flush on the underlying stream
+ MyStream ms = new MyStream ();
+ ms.FlushCounterEnabled = true;
+ using (CryptoStream cs = new CryptoStream (ms, SHA1.Create (), CryptoStreamMode.Read)) {
+ }
+ Assert.IsTrue (ms.FlushCounter == 1);
+ }
+
+ [Test]
+ public void ImplicitFlushCascade ()
+ {
+ // Tests that Dispose() calls FlushFinalBlock() on the underlying stream
+ MyStream ms = new MyStream ();
+ ms.FlushCounterEnabled = true;
+ CryptoStream cs1 = new CryptoStream (ms, SHA1.Create (), CryptoStreamMode.Read);
+ using (CryptoStream cs = new CryptoStream (cs1, SHA1.Create (), CryptoStreamMode.Read)) {
+ }
+ Assert.IsTrue (ms.FlushCounter == 1);
+ }
+
+ [Test]
+ [ExpectedException (typeof (ArgumentException))]
+ public void Ctor_InvalidEnumValue ()
+ {
+ CryptoStream cs = new CryptoStream (Stream.Null, SHA1.Create (), (CryptoStreamMode) 0xff);
+ }
+
+ [Test]
+ public void OutputBlock_Smaller ()
+ {
+ // The OutputBlockSize is smaller than the InputBlockSize
+ using (CryptoStream cs = new CryptoStream(Stream.Null, new MyCryptAlgorithm(), CryptoStreamMode.Write)) {
+ byte[] buffer = new byte[512 * 1024];
+ cs.Write(buffer, 0, buffer.Length);
+ }
+ }
+
+ class MyCryptoStream : CryptoStream {
+ public bool DisposeCalled { get; private set;}
+
+ public MyCryptoStream(Stream stream, ICryptoTransform transform)
+ : base(stream, transform, CryptoStreamMode.Read)
+ {
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ DisposeCalled = true;
+ }
+ }
+
+ class ExpandTransform : ICryptoTransform {
+
+ public bool CanReuseTransform {
+ get { return true; }
+ }
+
+ public bool CanTransformMultipleBlocks {
+ get; private set;
+ }
+
+ public int InputBlockSize {
+ get { return 1; }
+ }
+
+ public int OutputBlockSize {
+ get; private set;
+ }
+
+ public ExpandTransform (bool canTranformMultipleBlocks, int outputBlockSize)
+ {
+ this.CanTransformMultipleBlocks = canTranformMultipleBlocks;
+ this.OutputBlockSize = outputBlockSize;
+ }
+
+ public void Dispose ()
+ {
+ }
+
+ public int TransformBlock (byte [] inputBuffer, int inputOffset, int inputCount, byte [] outputBuffer, int outputOffset)
+ {
+ var ret = 0;
+ for (var i = 0; i < inputCount; i++, inputOffset++) {
+ for (var j = 0; j < OutputBlockSize; j++, outputOffset++, ret++) {
+ outputBuffer [outputOffset] = inputBuffer [inputOffset];
+ }
+ }
+ return ret;
+ }
+
+ public byte [] TransformFinalBlock (byte [] inputBuffer, int inputOffset, int inputCount)
+ {
+ var outputBuffer = new byte [inputCount * OutputBlockSize];
+ TransformBlock (inputBuffer, inputOffset, inputCount, outputBuffer, 0);
+ return outputBuffer;
+ }
+ }
+
+ static string[] expand_values = {
+ "00-01-02-03-04-05-06-07",
+ "00-00-01-01-02-02-03-03-04-04-05-05-06-06-07-07",
+ "00-00-00-01-01-01-02-02-02-03-03-03-04-04-04-05-05-05-06-06-06-07-07-07",
+ "00-00-00-00-01-01-01-01-02-02-02-02-03-03-03-03-04-04-04-04-05-05-05-05-06-06-06-06-07-07-07-07",
+ "00-01-02-03-04-05-06-07",
+ "00-00-01-01-02-02-03-03-04-04-05-05-06-06-07-07",
+ "00-00-00-01-01-01-02-02-02-03-03-03-04-04-04-05-05-05-06-06-06-07-07-07",
+ "00-00-00-00-01-01-01-01-02-02-02-02-03-03-03-03-04-04-04-04-05-05-05-05-06-06-06-06-07-07-07-07"
+ };
+
+ [Test]
+ public void Expand ()
+ {
+ int n = 0;
+ foreach (var transformMultiple in new [] { false, true }) {
+ foreach (var outputBlockSize in new [] { 1, 2, 3, 4 }) {
+ var expantedStream = new MemoryStream ();
+ var inputData = new byte [] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
+
+ using (var stream = new CryptoStream (expantedStream, new ExpandTransform (transformMultiple, outputBlockSize), CryptoStreamMode.Write)) {
+ stream.Write (inputData, 0, inputData.Length);
+ }
+ expantedStream.Close ();
+
+ string value = BitConverter.ToString (expantedStream.ToArray ());
+ Assert.AreEqual (expand_values [n++], value);
+ }
+ }
+ }
+
+ class CompressTransform : ICryptoTransform {
+ public bool CanReuseTransform {
+ get { return true; }
+ }
+
+ public bool CanTransformMultipleBlocks {
+ get { return true; }
+ }
+
+ public int InputBlockSize {
+ get; private set;
+ }
+
+ public int OutputBlockSize {
+ get { return 1; }
+ }
+
+ public CompressTransform (int inputBlockSize)
+ {
+ this.InputBlockSize = inputBlockSize;
+ }
+
+ public void Dispose ()
+ {
+ }
+
+ private int bufferedCount = 0;
+
+ public int TransformBlock (byte [] inputBuffer, int inputOffset, int inputCount, byte [] outputBuffer, int outputOffset)
+ {
+ var ret = 0;
+ for (var i = 0; i < inputCount; i++, inputOffset++) {
+ if (++bufferedCount == InputBlockSize) {
+ outputBuffer [outputOffset++] = inputBuffer [inputOffset];
+ ret++;
+ bufferedCount = 0;
+ }
+ }
+ return ret;
+ }
+
+ public byte [] TransformFinalBlock (byte [] inputBuffer, int inputOffset, int inputCount)
+ {
+ var outputBuffer = new byte [inputCount * OutputBlockSize];
+ var ret = TransformBlock (inputBuffer, inputOffset, inputCount, outputBuffer, 0);
+ byte[] result = new byte [ret];
+ Array.Copy (outputBuffer, result, ret);
+ return result;
+ }
+ }
+
+ static string[] compress_values = {
+ "00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F-10-11-12-13-14-15-16-17-18-19-1A-1B-1C-1D-1E-1F",
+ "01-03-05-07-09-0B-0D-0F-11-13-15-17-19-1B-1D-1F",
+ "02-05-08-0B-0E-11-14-17-1A-1D",
+ "03-07-0B-0F-13-17-1B-1F",
+ };
+
+ [Test]
+ public void Compress ()
+ {
+ int n = 0;
+ foreach (var inputBlockSize in new [] { 1, 2, 3, 4 }) {
+ var inputData = new byte [] {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ };
+
+ using (var stream = new CryptoStream (new MemoryStream (inputData), new CompressTransform (inputBlockSize), CryptoStreamMode.Read)) {
+ var buffer = new byte [inputData.Length];
+ var ret = stream.Read (buffer, 0, buffer.Length);
+ string value = BitConverter.ToString (buffer, 0, ret);
+ Assert.AreEqual (compress_values [n++], value);
+ }
+ }
+ }
+
+ class MyCryptAlgorithm : ICryptoTransform {
+ public bool CanReuseTransform { get { return true; } }
+ public bool CanTransformMultipleBlocks { get { return false; } }
+ public int InputBlockSize { get { return 128 * 1024; } }
+ public int OutputBlockSize { get { return 64 * 1024; } }
+
+ public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+ {
+ return this.OutputBlockSize;
+ }
+
+ public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ return new byte[this.OutputBlockSize];
+ }
+
+ public void Dispose() {}
+ }
+
+ class MyStream : Stream {
+ public bool FlushCounterEnabled;
+ public int FlushCounter;
+
+ public override bool CanRead
+ {
+ get {
+ return true;
+ }
+ }
+
+ public override bool CanSeek
+ {
+ get {
+ return true;
+ }
+ }
+
+ public override bool CanWrite
+ {
+ get {
+ return true;
+ }
+ }
+
+ public override long Length
+ {
+ get {
+ return 0;
+ }
+ }
+
+ public override long Position
+ {
+ get {
+ return 0;
+ }
+ set {
+ }
+ }
+
+ public override void Flush ()
+ {
+ if (FlushCounterEnabled)
+ FlushCounter++;
+ }
+
+ public override int Read (byte[] buffer, int offset, int count)
+ {
+ return 0;
+ }
+
+ public override int ReadByte ()
+ {
+ return -1;
+ }
+
+ public override long Seek (long offset, SeekOrigin origin)
+ {
+ return 0;
+ }
+
+ public override void SetLength (long value)
+ {
+ }
+
+ public override void Write (byte[] buffer, int offset, int count)
+ {
+ }
+
+ public override void WriteByte (byte value)
+ {
+ }