2
0
Эх сурвалжийг харах

Create output buffer after padding to ensure its length matches the padded length.
Fixes issue #2547.

Gert Driesen 11 жил өмнө
parent
commit
4dbbf7514f

+ 1 - 0
Renci.SshClient/Build/nuget/SSH.NET.nuspec

@@ -35,6 +35,7 @@
           * Signing key is missing from source download (issue #2455)
           * Forwarded Port channels can get stuck waiting (issue #1558)
           * NullReferenceException when SftpFileStream is finalized after dispose of session (issue #2013)
+          * BlockCipher.Encrypt fails if input message is not padded (issue #2547)
 
           2014.4.6-beta1
           ==============

+ 69 - 7
Renci.SshClient/Renci.SshNet.Tests/Classes/Security/Cryptography/BlockCipherTest.cs

@@ -1,15 +1,77 @@
-using Renci.SshNet.Security.Cryptography;
+using System;
+using System.Linq;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Renci.SshNet.Security.Cryptography;
+using Renci.SshNet.Security.Cryptography.Ciphers;
+using Renci.SshNet.Security.Cryptography.Ciphers.Paddings;
 using Renci.SshNet.Tests.Common;
 
-namespace Renci.SshNet.Tests
+namespace Renci.SshNet.Tests.Classes.Security.Cryptography
 {
-    /// <summary>
-    ///This is a test class for BlockCipherTest and is intended
-    ///to contain all BlockCipherTest Unit Tests
-    ///</summary>
-    [TestClass()]
+    [TestClass]
     public class BlockCipherTest  : TestBase
     {
+        [TestMethod]
+        public void EncryptShouldTakeIntoAccountPaddingForLengthOfOutputBufferPassedToEncryptBlock()
+        {
+            var input = new byte[] { 0x2c, 0x1a, 0x05, 0x00, 0x68 };
+            var output = new byte[] { 0x0a, 0x00, 0x03, 0x02, 0x06, 0x08, 0x07, 0x05 };
+            var key = new byte[] { 0x17, 0x78, 0x56, 0xe1, 0x3e, 0xbd, 0x3e, 0x50, 0x1d, 0x79, 0x3f, 0x0f, 0x55, 0x37, 0x45, 0x54 };
+            var blockCipher = new BlockCipherStub(key, 8, null, new PKCS5Padding())
+                {
+                    EncryptBlockDelegate = (inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset) =>
+                        {
+                            Assert.AreEqual(8, outputBuffer.Length);
+                            Buffer.BlockCopy(output, 0, outputBuffer, 0, output.Length);
+                            return inputBuffer.Length;
+                        }
+                };
+
+            var actual = blockCipher.Encrypt(input);
+
+            Assert.IsTrue(output.SequenceEqual(actual));
+        }
+
+        [TestMethod]
+        public void DecryptShouldTakeIntoAccountPaddingForLengthOfOutputBufferPassedToDecryptBlock()
+        {
+            var input = new byte[] { 0x2c, 0x1a, 0x05, 0x00, 0x68 };
+            var output = new byte[] { 0x0a, 0x00, 0x03, 0x02, 0x06, 0x08, 0x07, 0x05 };
+            var key = new byte[] { 0x17, 0x78, 0x56, 0xe1, 0x3e, 0xbd, 0x3e, 0x50, 0x1d, 0x79, 0x3f, 0x0f, 0x55, 0x37, 0x45, 0x54 };
+            var blockCipher = new BlockCipherStub(key, 8, null, new PKCS5Padding())
+                {
+                    DecryptBlockDelegate = (inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset) =>
+                        {
+                            Assert.AreEqual(8, outputBuffer.Length);
+                            Buffer.BlockCopy(output, 0, outputBuffer, 0, output.Length);
+                            return inputBuffer.Length;
+                        }
+                };
+
+            var actual = blockCipher.Decrypt(input);
+
+            Assert.IsTrue(output.SequenceEqual(actual));
+        }
+
+
+        private class BlockCipherStub : BlockCipher
+        {
+            public Func<byte[], int, int, byte[], int, int> EncryptBlockDelegate;
+            public Func<byte[], int, int, byte[], int, int> DecryptBlockDelegate;
+
+            public BlockCipherStub(byte[] key, byte blockSize, CipherMode mode, CipherPadding padding) : base(key, blockSize, mode, padding)
+            {
+            }
+
+            public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+            {
+                return EncryptBlockDelegate(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
+            }
+
+            public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+            {
+                return DecryptBlockDelegate(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
+            }
+        }
     }
 }

+ 2 - 3
Renci.SshClient/Renci.SshNet/Security/Cryptography/BlockCipher.cs

@@ -71,8 +71,6 @@ namespace Renci.SshNet.Security.Cryptography
         /// <returns>Encrypted data</returns>
         public override byte[] Encrypt(byte[] data)
         {
-            var output = new byte[data.Length];
-
             if (data.Length % _blockSize > 0)
             {
                 if (_padding == null)
@@ -82,9 +80,10 @@ namespace Renci.SshNet.Security.Cryptography
                 data = _padding.Pad(_blockSize, data);
             }
 
+            var output = new byte[data.Length];
             var writtenBytes = 0;
 
-            for (int i = 0; i < data.Length / _blockSize; i++)
+            for (var i = 0; i < data.Length / _blockSize; i++)
             {
                 if (_mode == null)
                 {