Przeglądaj źródła

Ref System.Memory for net462 and netstandard2.0 (#1417)

* Ref System.Memory for net462 and netstandard2.0.
Use System.Buffers.Binary.BinaryPrimitives instead of Renci.SshNet.Common.Pack

* Remove unnecessary `AsSpan()`

* Apply suggestions from code review

* that's what I get for being lazy

---------

Co-authored-by: Rob Hague <rob.hague00@gmail.com>
Co-authored-by: Robert Hague <rh@johnstreetcapital.com>
Scott Xu 1 rok temu
rodzic
commit
c552d0d60b

+ 3 - 1
src/Renci.SshNet/Common/DerData.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Buffers.Binary;
 using System.Collections.Generic;
 
 namespace Renci.SshNet.Common
@@ -198,7 +199,8 @@ namespace Renci.SshNet.Common
         /// <param name="data">UInt32 data to write.</param>
         public void Write(uint data)
         {
-            var bytes = Pack.UInt32ToBigEndian(data);
+            var bytes = new byte[sizeof(uint)];
+            BinaryPrimitives.WriteUInt32BigEndian(bytes, data);
             _data.Add(Integer);
             var length = GetLength(bytes.Length);
             WriteBytes(length);

+ 0 - 282
src/Renci.SshNet/Common/Pack.cs

@@ -1,282 +0,0 @@
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-using System;
-using System.Buffers.Binary;
-#endif
-
-namespace Renci.SshNet.Common
-{
-    /// <summary>
-    /// Provides convenience methods for conversion to and from both Big Endian and Little Endian.
-    /// </summary>
-    internal static class Pack
-    {
-        /// <summary>
-        /// Converts little endian bytes into number.
-        /// </summary>
-        /// <param name="buffer">The buffer.</param>
-        /// <returns>Converted <see cref="ushort" />.</returns>
-        internal static ushort LittleEndianToUInt16(byte[] buffer)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            return BinaryPrimitives.ReadUInt16LittleEndian(buffer);
-#else
-            ushort n = buffer[0];
-            n |= (ushort)(buffer[1] << 8);
-            return n;
-#endif
-        }
-
-        /// <summary>
-        /// Converts little endian bytes into number.
-        /// </summary>
-        /// <param name="buffer">The buffer.</param>
-        /// <returns>Converted <see cref="uint" />.</returns>
-        internal static uint LittleEndianToUInt32(byte[] buffer)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            return BinaryPrimitives.ReadUInt32LittleEndian(buffer);
-#else
-            uint n = buffer[0];
-            n |= (uint)buffer[1] << 8;
-            n |= (uint)buffer[2] << 16;
-            n |= (uint)buffer[3] << 24;
-            return n;
-#endif
-        }
-
-        /// <summary>
-        /// Converts little endian bytes into number.
-        /// </summary>
-        /// <param name="buffer">The buffer.</param>
-        /// <returns>Converted <see cref="ulong" />.</returns>
-        internal static ulong LittleEndianToUInt64(byte[] buffer)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            return BinaryPrimitives.ReadUInt64LittleEndian(buffer);
-#else
-            ulong n = buffer[0];
-            n |= (ulong)buffer[1] << 8;
-            n |= (ulong)buffer[2] << 16;
-            n |= (ulong)buffer[3] << 24;
-            n |= (ulong)buffer[4] << 32;
-            n |= (ulong)buffer[5] << 40;
-            n |= (ulong)buffer[6] << 48;
-            n |= (ulong)buffer[7] << 56;
-            return n;
-#endif
-        }
-
-        /// <summary>
-        /// Populates buffer with little endian number representation.
-        /// </summary>
-        /// <param name="value">The number to convert.</param>
-        internal static byte[] UInt16ToLittleEndian(ushort value)
-        {
-            var buffer = new byte[2];
-            UInt16ToLittleEndian(value, buffer);
-            return buffer;
-        }
-
-        /// <summary>
-        /// Populates buffer with little endian number representation.
-        /// </summary>
-        /// <param name="value">The number to convert.</param>
-        /// <param name="buffer">The buffer.</param>
-        private static void UInt16ToLittleEndian(ushort value, byte[] buffer)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            BinaryPrimitives.WriteUInt16LittleEndian(buffer, value);
-#else
-            buffer[0] = (byte)(value & 0x00FF);
-            buffer[1] = (byte)((value & 0xFF00) >> 8);
-#endif
-        }
-
-        /// <summary>
-        /// Populates buffer with little endian number representation.
-        /// </summary>
-        /// <param name="value">The number to convert.</param>
-        internal static byte[] UInt32ToLittleEndian(uint value)
-        {
-            var buffer = new byte[4];
-            UInt32ToLittleEndian(value, buffer);
-            return buffer;
-        }
-
-        /// <summary>
-        /// Populates buffer with little endian number representation.
-        /// </summary>
-        /// <param name="value">The number to convert.</param>
-        /// <param name="buffer">The buffer.</param>
-        private static void UInt32ToLittleEndian(uint value, byte[] buffer)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
-#else
-            buffer[0] = (byte)(value & 0x000000FF);
-            buffer[1] = (byte)((value & 0x0000FF00) >> 8);
-            buffer[2] = (byte)((value & 0x00FF0000) >> 16);
-            buffer[3] = (byte)((value & 0xFF000000) >> 24);
-#endif
-        }
-
-        /// <summary>
-        /// Populates buffer with little endian number representation.
-        /// </summary>
-        /// <param name="value">The number to convert.</param>
-        internal static byte[] UInt64ToLittleEndian(ulong value)
-        {
-            var buffer = new byte[8];
-            UInt64ToLittleEndian(value, buffer);
-            return buffer;
-        }
-
-        /// <summary>
-        /// Populates buffer with little endian number representation.
-        /// </summary>
-        /// <param name="value">The number to convert.</param>
-        /// <param name="buffer">The buffer.</param>
-        private static void UInt64ToLittleEndian(ulong value, byte[] buffer)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            BinaryPrimitives.WriteUInt64LittleEndian(buffer, value);
-#else
-            buffer[0] = (byte)(value & 0x00000000000000FF);
-            buffer[1] = (byte)((value & 0x000000000000FF00) >> 8);
-            buffer[2] = (byte)((value & 0x0000000000FF0000) >> 16);
-            buffer[3] = (byte)((value & 0x00000000FF000000) >> 24);
-            buffer[4] = (byte)((value & 0x000000FF00000000) >> 32);
-            buffer[5] = (byte)((value & 0x0000FF0000000000) >> 40);
-            buffer[6] = (byte)((value & 0x00FF000000000000) >> 48);
-            buffer[7] = (byte)((value & 0xFF00000000000000) >> 56);
-#endif
-        }
-
-        internal static byte[] UInt16ToBigEndian(ushort value)
-        {
-            var buffer = new byte[2];
-            UInt16ToBigEndian(value, buffer, offset: 0);
-            return buffer;
-        }
-
-        internal static void UInt16ToBigEndian(ushort value, byte[] buffer, int offset)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            BinaryPrimitives.WriteUInt16BigEndian(buffer.AsSpan(offset), value);
-#else
-            buffer[offset] = (byte)(value >> 8);
-            buffer[offset + 1] = (byte)(value & 0x00FF);
-#endif
-        }
-
-        internal static void UInt32ToBigEndian(uint value, byte[] buffer)
-        {
-            UInt32ToBigEndian(value, buffer, offset: 0);
-        }
-
-        internal static void UInt32ToBigEndian(uint value, byte[] buffer, int offset)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            BinaryPrimitives.WriteUInt32BigEndian(buffer.AsSpan(offset), value);
-#else
-            buffer[offset++] = (byte)((value & 0xFF000000) >> 24);
-            buffer[offset++] = (byte)((value & 0x00FF0000) >> 16);
-            buffer[offset++] = (byte)((value & 0x0000FF00) >> 8);
-            buffer[offset] = (byte)(value & 0x000000FF);
-#endif
-        }
-
-        internal static byte[] UInt32ToBigEndian(uint value)
-        {
-            var buffer = new byte[4];
-            UInt32ToBigEndian(value, buffer);
-            return buffer;
-        }
-
-        internal static byte[] UInt64ToBigEndian(ulong value)
-        {
-            var buffer = new byte[8];
-            UInt64ToBigEndian(value, buffer, offset: 0);
-            return buffer;
-        }
-
-        private static void UInt64ToBigEndian(ulong value, byte[] buffer, int offset)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            BinaryPrimitives.WriteUInt64BigEndian(buffer.AsSpan(offset), value);
-#else
-            buffer[offset++] = (byte)((value & 0xFF00000000000000) >> 56);
-            buffer[offset++] = (byte)((value & 0x00FF000000000000) >> 48);
-            buffer[offset++] = (byte)((value & 0x0000FF0000000000) >> 40);
-            buffer[offset++] = (byte)((value & 0x000000FF00000000) >> 32);
-            buffer[offset++] = (byte)((value & 0x00000000FF000000) >> 24);
-            buffer[offset++] = (byte)((value & 0x0000000000FF0000) >> 16);
-            buffer[offset++] = (byte)((value & 0x000000000000FF00) >> 8);
-            buffer[offset] = (byte)(value & 0x00000000000000FF);
-#endif
-        }
-
-        /// <summary>
-        /// Converts big endian bytes into number.
-        /// </summary>
-        /// <param name="buffer">The buffer.</param>
-        /// <returns>Converted <see cref="ushort" />.</returns>
-        internal static ushort BigEndianToUInt16(byte[] buffer)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            return BinaryPrimitives.ReadUInt16BigEndian(buffer);
-#else
-            return (ushort)(buffer[0] << 8 | buffer[1]);
-#endif
-        }
-
-        /// <summary>
-        /// Converts big endian bytes into number.
-        /// </summary>
-        /// <param name="buffer">The buffer.</param>
-        /// <param name="offset">The buffer offset.</param>
-        /// <returns>Converted <see cref="uint" />.</returns>
-        internal static uint BigEndianToUInt32(byte[] buffer, int offset)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            return BinaryPrimitives.ReadUInt32BigEndian(buffer.AsSpan(offset));
-#else
-            return (uint)buffer[offset + 0] << 24 |
-                   (uint)buffer[offset + 1] << 16 |
-                   (uint)buffer[offset + 2] << 8 |
-                   buffer[offset + 3];
-#endif
-        }
-
-        /// <summary>
-        /// Converts big endian bytes into number.
-        /// </summary>
-        /// <param name="buffer">The buffer.</param>
-        /// <returns>Converted <see cref="uint" />.</returns>
-        internal static uint BigEndianToUInt32(byte[] buffer)
-        {
-            return BigEndianToUInt32(buffer, offset: 0);
-        }
-
-        /// <summary>
-        /// Converts big endian bytes into number.
-        /// </summary>
-        /// <param name="buffer">The buffer.</param>
-        /// <returns>Converted <see cref="ulong" />.</returns>
-        internal static ulong BigEndianToUInt64(byte[] buffer)
-        {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
-            return BinaryPrimitives.ReadUInt64BigEndian(buffer);
-#else
-            return (ulong)buffer[0] << 56 |
-                   (ulong)buffer[1] << 48 |
-                   (ulong)buffer[2] << 40 |
-                   (ulong)buffer[3] << 32 |
-                   (ulong)buffer[4] << 24 |
-                   (ulong)buffer[5] << 16 |
-                   (ulong)buffer[6] << 8 |
-                   buffer[7];
-#endif
-        }
-    }
-}

+ 26 - 27
src/Renci.SshNet/Common/SshDataStream.cs

@@ -56,20 +56,41 @@ namespace Renci.SshNet.Common
             }
         }
 
+#if NET462 || NETSTANDARD2_0
+        private int Read(Span<byte> buffer)
+        {
+            var sharedBuffer = System.Buffers.ArrayPool<byte>.Shared.Rent(buffer.Length);
+
+            var numRead = Read(sharedBuffer, 0, buffer.Length);
+
+            sharedBuffer.AsSpan(0, numRead).CopyTo(buffer);
+
+            System.Buffers.ArrayPool<byte>.Shared.Return(sharedBuffer);
+
+            return numRead;
+        }
+
+        private void Write(ReadOnlySpan<byte> buffer)
+        {
+            var sharedBuffer = System.Buffers.ArrayPool<byte>.Shared.Rent(buffer.Length);
+
+            buffer.CopyTo(sharedBuffer);
+
+            Write(sharedBuffer, 0, buffer.Length);
+
+            System.Buffers.ArrayPool<byte>.Shared.Return(sharedBuffer);
+        }
+#endif
+
         /// <summary>
         /// Writes an <see cref="uint"/> to the SSH data stream.
         /// </summary>
         /// <param name="value"><see cref="uint"/> data to write.</param>
         public void Write(uint value)
         {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
             Span<byte> bytes = stackalloc byte[4];
             System.Buffers.Binary.BinaryPrimitives.WriteUInt32BigEndian(bytes, value);
             Write(bytes);
-#else
-            var bytes = Pack.UInt32ToBigEndian(value);
-            Write(bytes, 0, bytes.Length);
-#endif
         }
 
         /// <summary>
@@ -78,14 +99,9 @@ namespace Renci.SshNet.Common
         /// <param name="value"><see cref="ulong"/> data to write.</param>
         public void Write(ulong value)
         {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
             Span<byte> bytes = stackalloc byte[8];
             System.Buffers.Binary.BinaryPrimitives.WriteUInt64BigEndian(bytes, value);
             Write(bytes);
-#else
-            var bytes = Pack.UInt64ToBigEndian(value);
-            Write(bytes, 0, bytes.Length);
-#endif
         }
 
         /// <summary>
@@ -208,14 +224,9 @@ namespace Renci.SshNet.Common
         /// </returns>
         public ushort ReadUInt16()
         {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
             Span<byte> bytes = stackalloc byte[2];
             ReadBytes(bytes);
             return System.Buffers.Binary.BinaryPrimitives.ReadUInt16BigEndian(bytes);
-#else
-            var data = ReadBytes(2);
-            return Pack.BigEndianToUInt16(data);
-#endif
         }
 
         /// <summary>
@@ -226,14 +237,9 @@ namespace Renci.SshNet.Common
         /// </returns>
         public uint ReadUInt32()
         {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
             Span<byte> span = stackalloc byte[4];
             ReadBytes(span);
             return System.Buffers.Binary.BinaryPrimitives.ReadUInt32BigEndian(span);
-#else
-            var data = ReadBytes(4);
-            return Pack.BigEndianToUInt32(data);
-#endif // NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
         }
 
         /// <summary>
@@ -244,14 +250,9 @@ namespace Renci.SshNet.Common
         /// </returns>
         public ulong ReadUInt64()
         {
-#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
             Span<byte> span = stackalloc byte[8];
             ReadBytes(span);
             return System.Buffers.Binary.BinaryPrimitives.ReadUInt64BigEndian(span);
-#else
-            var data = ReadBytes(8);
-            return Pack.BigEndianToUInt64(data);
-#endif // NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER
         }
 
         /// <summary>
@@ -316,7 +317,6 @@ namespace Renci.SshNet.Common
             return data;
         }
 
-#if NETSTANDARD2_1 || NET6_0_OR_GREATER
         /// <summary>
         /// Reads data into the specified <paramref name="buffer" />.
         /// </summary>
@@ -330,6 +330,5 @@ namespace Renci.SshNet.Common
                 throw new ArgumentOutOfRangeException(nameof(buffer), string.Format(CultureInfo.InvariantCulture, "The requested length ({0}) is greater than the actual number of bytes read ({1}).", buffer.Length, bytesRead));
             }
         }
-#endif // NETSTANDARD2_1 || NET6_0_OR_GREATER
     }
 }

+ 2 - 1
src/Renci.SshNet/Connection/Socks4Connector.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Buffers.Binary;
 using System.Net;
 using System.Net.Sockets;
 using System.Text;
@@ -90,7 +91,7 @@ namespace Renci.SshNet.Connection
             connectionRequest[index++] = 0x01; // establish a TCP/IP stream connection
 
             // Port number
-            Pack.UInt16ToBigEndian(port, connectionRequest, index);
+            BinaryPrimitives.WriteUInt16BigEndian(connectionRequest.AsSpan(index), port);
             index += 2;
 
             // Address

+ 2 - 1
src/Renci.SshNet/Connection/Socks5Connector.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Buffers.Binary;
 using System.Diagnostics;
 using System.Net;
 using System.Net.Sockets;
@@ -239,7 +240,7 @@ namespace Renci.SshNet.Connection
             index += addressBytes.Length;
 
             // Port number
-            Pack.UInt16ToBigEndian(port, connectionRequest, index);
+            BinaryPrimitives.WriteUInt16BigEndian(connectionRequest.AsSpan(index), port);
 
             return connectionRequest;
         }

+ 3 - 2
src/Renci.SshNet/ForwardedPortDynamic.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Buffers.Binary;
 using System.Globalization;
 using System.Linq;
 using System.Net;
@@ -479,7 +480,7 @@ namespace Renci.SshNet
                 return false;
             }
 
-            var port = Pack.BigEndianToUInt16(portBuffer);
+            var port = BinaryPrimitives.ReadUInt16BigEndian(portBuffer);
 
             var ipBuffer = new byte[4];
             if (SocketAbstraction.Read(socket, ipBuffer, 0, ipBuffer.Length, timeout) == 0)
@@ -602,7 +603,7 @@ namespace Renci.SshNet
                 return false;
             }
 
-            var port = Pack.BigEndianToUInt16(portBuffer);
+            var port = BinaryPrimitives.ReadUInt16BigEndian(portBuffer);
 
             RaiseRequestReceived(host, port);
 

+ 1 - 0
src/Renci.SshNet/Renci.SshNet.csproj

@@ -37,6 +37,7 @@
   <ItemGroup Condition=" '$(TargetFramework)' == 'net462' or '$(TargetFramework)' == 'netstandard2.0' ">
     <!-- Must be kept at version 1.0.0 or higher, see https://github.com/sshnet/SSH.NET/pull/1288 for details. -->
     <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="[1.0.0,)" />
+    <PackageReference Include="System.Memory" Version="4.5.5" />
   </ItemGroup>
 
   <ItemGroup>

+ 9 - 10
src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs

@@ -1,6 +1,5 @@
 using System;
-
-using Renci.SshNet.Common;
+using System.Buffers.Binary;
 
 namespace Renci.SshNet.Security.Cryptography.Ciphers
 {
@@ -358,8 +357,8 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
                 throw new ArgumentException("inputCount");
             }
 
-            var xl = Pack.BigEndianToUInt32(inputBuffer, inputOffset);
-            var xr = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4);
+            var xl = BinaryPrimitives.ReadUInt32BigEndian(inputBuffer.AsSpan(inputOffset));
+            var xr = BinaryPrimitives.ReadUInt32BigEndian(inputBuffer.AsSpan(inputOffset + 4));
 
             xl ^= _p[0];
 
@@ -371,8 +370,8 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 
             xr ^= _p[Rounds + 1];
 
-            Pack.UInt32ToBigEndian(xr, outputBuffer, outputOffset);
-            Pack.UInt32ToBigEndian(xl, outputBuffer, outputOffset + 4);
+            BinaryPrimitives.WriteUInt32BigEndian(outputBuffer.AsSpan(outputOffset), xr);
+            BinaryPrimitives.WriteUInt32BigEndian(outputBuffer.AsSpan(outputOffset + 4), xl);
 
             return BlockSize;
         }
@@ -395,8 +394,8 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
                 throw new ArgumentException("inputCount");
             }
 
-            var xl = Pack.BigEndianToUInt32(inputBuffer, inputOffset);
-            var xr = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4);
+            var xl = BinaryPrimitives.ReadUInt32BigEndian(inputBuffer.AsSpan(inputOffset));
+            var xr = BinaryPrimitives.ReadUInt32BigEndian(inputBuffer.AsSpan(inputOffset + 4));
 
             xl ^= _p[Rounds + 1];
 
@@ -408,8 +407,8 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
 
             xr ^= _p[0];
 
-            Pack.UInt32ToBigEndian(xr, outputBuffer, outputOffset);
-            Pack.UInt32ToBigEndian(xl, outputBuffer, outputOffset + 4);
+            BinaryPrimitives.WriteUInt32BigEndian(outputBuffer.AsSpan(outputOffset), xr);
+            BinaryPrimitives.WriteUInt32BigEndian(outputBuffer.AsSpan(outputOffset + 4), xl);
 
             return BlockSize;
         }

+ 9 - 10
src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs

@@ -1,6 +1,5 @@
 using System;
-
-using Renci.SshNet.Common;
+using System.Buffers.Binary;
 
 namespace Renci.SshNet.Security.Cryptography.Ciphers
 {
@@ -65,15 +64,15 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
              * the array is in bytes, the increment is 8x8 bits = 64
              */
 
-            var l0 = Pack.BigEndianToUInt32(inputBuffer, inputOffset);
-            var r0 = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4);
+            var l0 = BinaryPrimitives.ReadUInt32BigEndian(inputBuffer.AsSpan(inputOffset));
+            var r0 = BinaryPrimitives.ReadUInt32BigEndian(inputBuffer.AsSpan(inputOffset + 4));
 
             var result = new uint[2];
             CastEncipher(l0, r0, result);
 
             // now stuff them into the destination block
-            Pack.UInt32ToBigEndian(result[0], outputBuffer, outputOffset);
-            Pack.UInt32ToBigEndian(result[1], outputBuffer, outputOffset + 4);
+            BinaryPrimitives.WriteUInt32BigEndian(outputBuffer.AsSpan(outputOffset), result[0]);
+            BinaryPrimitives.WriteUInt32BigEndian(outputBuffer.AsSpan(outputOffset + 4), result[1]);
 
             return BlockSize;
         }
@@ -94,15 +93,15 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
             // process the input block
             // batch the units up into a 32 bit chunk and go for it
             // the array is in bytes, the increment is 8x8 bits = 64
-            var l16 = Pack.BigEndianToUInt32(inputBuffer, inputOffset);
-            var r16 = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4);
+            var l16 = BinaryPrimitives.ReadUInt32BigEndian(inputBuffer.AsSpan(inputOffset));
+            var r16 = BinaryPrimitives.ReadUInt32BigEndian(inputBuffer.AsSpan(inputOffset + 4));
 
             var result = new uint[2];
             CastDecipher(l16, r16, result);
 
             // now stuff them into the destination block
-            Pack.UInt32ToBigEndian(result[0], outputBuffer, outputOffset);
-            Pack.UInt32ToBigEndian(result[1], outputBuffer, outputOffset + 4);
+            BinaryPrimitives.WriteUInt32BigEndian(outputBuffer.AsSpan(outputOffset), result[0]);
+            BinaryPrimitives.WriteUInt32BigEndian(outputBuffer.AsSpan(outputOffset + 4), result[1]);
 
             return BlockSize;
         }

+ 5 - 6
src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs

@@ -1,6 +1,5 @@
 using System;
-
-using Renci.SshNet.Common;
+using System.Buffers.Binary;
 
 namespace Renci.SshNet.Security.Cryptography.Ciphers
 {
@@ -406,8 +405,8 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
         /// <param name="outOff">The out off.</param>
         protected static void DesFunc(int[] wKey, byte[] input, int inOff, byte[] outBytes, int outOff)
         {
-            var left = Pack.BigEndianToUInt32(input, inOff);
-            var right = Pack.BigEndianToUInt32(input, inOff + 4);
+            var left = BinaryPrimitives.ReadUInt32BigEndian(input.AsSpan(inOff));
+            var right = BinaryPrimitives.ReadUInt32BigEndian(input.AsSpan(inOff + 4));
 
             var work = ((left >> 4) ^ right) & 0x0f0f0f0f;
             right ^= work;
@@ -473,8 +472,8 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
             left ^= work;
             right ^= work << 4;
 
-            Pack.UInt32ToBigEndian(right, outBytes, outOff);
-            Pack.UInt32ToBigEndian(left, outBytes, outOff + 4);
+            BinaryPrimitives.WriteUInt32BigEndian(outBytes.AsSpan(outOff), right);
+            BinaryPrimitives.WriteUInt32BigEndian(outBytes.AsSpan(outOff + 4), left);
         }
     }
 }

+ 4 - 3
src/Renci.SshNet/Session.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Buffers.Binary;
 using System.Diagnostics;
 using System.Globalization;
 using System.Linq;
@@ -1047,7 +1048,7 @@ namespace Renci.SshNet
                 var packetDataOffset = 4; // first four bytes are reserved for outbound packet sequence
 
                 // write outbound packet sequence to start of packet data
-                Pack.UInt32ToBigEndian(_outboundPacketSequence, packetData);
+                BinaryPrimitives.WriteUInt32BigEndian(packetData, _outboundPacketSequence);
 
                 if (_clientMac != null && !_clientEtm)
                 {
@@ -1250,7 +1251,7 @@ namespace Renci.SshNet
                     firstBlock = _serverCipher.Decrypt(firstBlock);
                 }
 
-                packetLength = Pack.BigEndianToUInt32(firstBlock);
+                packetLength = BinaryPrimitives.ReadUInt32BigEndian(firstBlock);
 
                 // Test packet minimum and maximum boundaries
                 if (packetLength < Math.Max((byte)16, blockSize) - 4 || packetLength > MaximumSshPacketSize - 4)
@@ -1275,7 +1276,7 @@ namespace Renci.SshNet
                 // byte[] for the purpose of calculating the client hash. Room for the server MAC is foreseen
                 // to read the packet including server MAC in a single pass (except for the initial block).
                 data = new byte[bytesToRead + blockSize + inboundPacketSequenceLength];
-                Pack.UInt32ToBigEndian(_inboundPacketSequence, data);
+                BinaryPrimitives.WriteUInt32BigEndian(data, _inboundPacketSequence);
                 Buffer.BlockCopy(firstBlock, 0, data, inboundPacketSequenceLength, firstBlock.Length);
 
                 if (bytesToRead > 0)

+ 0 - 187
test/Renci.SshNet.Tests/Classes/Common/PackTest.cs

@@ -1,187 +0,0 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-using Renci.SshNet.Common;
-
-namespace Renci.SshNet.Tests.Classes.Common
-{
-    [TestClass]
-    public class PackTest
-    {
-        [TestMethod]
-        public void BigEndianToUInt16()
-        {
-            Assert.AreEqual(0, Pack.BigEndianToUInt16(new byte[] { 0, 0 }));
-            Assert.AreEqual(1, Pack.BigEndianToUInt16(new byte[] { 0, 1 }));
-            Assert.AreEqual(256, Pack.BigEndianToUInt16(new byte[] { 1, 0 }));
-            Assert.AreEqual(257, Pack.BigEndianToUInt16(new byte[] { 1, 1 }));
-            Assert.AreEqual(1025, Pack.BigEndianToUInt16(new byte[] { 4, 1 }));
-            Assert.AreEqual(ushort.MaxValue, Pack.BigEndianToUInt16(new byte[] { 255, 255 }));
-        }
-
-        [TestMethod]
-        public void BigEndianToUInt32()
-        {
-            Assert.AreEqual(0U, Pack.BigEndianToUInt32(new byte[] { 0, 0, 0, 0 }));
-            Assert.AreEqual(1U, Pack.BigEndianToUInt32(new byte[] { 0, 0, 0, 1 }));
-            Assert.AreEqual(256U, Pack.BigEndianToUInt32(new byte[] { 0, 0, 1, 0 }));
-            Assert.AreEqual(257U, Pack.BigEndianToUInt32(new byte[] { 0, 0, 1, 1 }));
-            Assert.AreEqual(1025U, Pack.BigEndianToUInt32(new byte[] { 0, 0, 4, 1 }));
-            Assert.AreEqual(65536U, Pack.BigEndianToUInt32(new byte[] { 0, 1, 0, 0 }));
-            Assert.AreEqual(133124U, Pack.BigEndianToUInt32(new byte[] { 0, 2, 8, 4 }));
-            Assert.AreEqual(16777216U, Pack.BigEndianToUInt32(new byte[] { 1, 0, 0, 0 }));
-            Assert.AreEqual(uint.MaxValue, Pack.BigEndianToUInt32(new byte[] { 255, 255, 255, 255 }));
-        }
-
-        [TestMethod]
-        public void BigEndianToUInt64()
-        {
-            Assert.AreEqual(0UL, Pack.BigEndianToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }));
-            Assert.AreEqual(1UL, Pack.BigEndianToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }));
-            Assert.AreEqual(256UL, Pack.BigEndianToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }));
-            Assert.AreEqual(257UL, Pack.BigEndianToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }));
-            Assert.AreEqual(65536UL, Pack.BigEndianToUInt64(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }));
-            Assert.AreEqual(133124UL, Pack.BigEndianToUInt64(new byte[] { 0, 0, 0, 0, 0, 2, 8, 4 }));
-            Assert.AreEqual(16777216UL, Pack.BigEndianToUInt64(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }));
-            Assert.AreEqual(4294967296UL, Pack.BigEndianToUInt64(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }));
-            Assert.AreEqual(1099511627776UL, Pack.BigEndianToUInt64(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }));
-            Assert.AreEqual(1099511892096UL, Pack.BigEndianToUInt64(new byte[] { 0, 0, 1, 0, 0, 4, 8, 128 }));
-            Assert.AreEqual(1099511627776UL * 256, Pack.BigEndianToUInt64(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }));
-            Assert.AreEqual(1099511627776UL * 256 * 256, Pack.BigEndianToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }));
-            Assert.AreEqual(ulong.MaxValue, Pack.BigEndianToUInt64(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }));
-        }
-
-        [TestMethod]
-        public void LittleEndianToUInt16()
-        {
-            Assert.AreEqual((ushort)0, Pack.LittleEndianToUInt16(new byte[] { 0, 0 }));
-            Assert.AreEqual((ushort)1, Pack.LittleEndianToUInt16(new byte[] { 1, 0 }));
-            Assert.AreEqual((ushort)256, Pack.LittleEndianToUInt16(new byte[] { 0, 1 }));
-            Assert.AreEqual((ushort)257, Pack.LittleEndianToUInt16(new byte[] { 1, 1 }));
-            Assert.AreEqual((ushort)1025, Pack.LittleEndianToUInt16(new byte[] { 1, 4 }));
-            Assert.AreEqual(ushort.MaxValue, Pack.LittleEndianToUInt16(new byte[] { 255, 255 }));
-        }
-
-        [TestMethod]
-        public void LittleEndianToUInt32()
-        {
-            Assert.AreEqual(0U, Pack.LittleEndianToUInt32(new byte[] { 0, 0, 0, 0 }));
-            Assert.AreEqual(1U, Pack.LittleEndianToUInt32(new byte[] { 1, 0, 0, 0 }));
-            Assert.AreEqual(256U, Pack.LittleEndianToUInt32(new byte[] { 0, 1, 0, 0 }));
-            Assert.AreEqual(257U, Pack.LittleEndianToUInt32(new byte[] { 1, 1, 0, 0 }));
-            Assert.AreEqual(1025U, Pack.LittleEndianToUInt32(new byte[] { 1, 4, 0, 0 }));
-            Assert.AreEqual(65536U, Pack.LittleEndianToUInt32(new byte[] { 0, 0, 1, 0 }));
-            Assert.AreEqual(133124U, Pack.LittleEndianToUInt32(new byte[] { 4, 8, 2, 0 }));
-            Assert.AreEqual(16777216U, Pack.LittleEndianToUInt32(new byte[] { 0, 0, 0, 1 }));
-            Assert.AreEqual(uint.MaxValue, Pack.LittleEndianToUInt32(new byte[] { 255, 255, 255, 255 }));
-        }
-
-        [TestMethod]
-        public void LittleEndianToUInt64()
-        {
-            Assert.AreEqual(0UL, Pack.LittleEndianToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }));
-            Assert.AreEqual(1UL, Pack.LittleEndianToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }));
-            Assert.AreEqual(256UL, Pack.LittleEndianToUInt64(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }));
-            Assert.AreEqual(257UL, Pack.LittleEndianToUInt64(new byte[] { 1, 1, 0, 0, 0, 0, 0, 0 }));
-            Assert.AreEqual(65536UL, Pack.LittleEndianToUInt64(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }));
-            Assert.AreEqual(133124UL, Pack.LittleEndianToUInt64(new byte[] { 4, 8, 2, 0, 0, 0, 0, 0 }));
-            Assert.AreEqual(16777216UL, Pack.LittleEndianToUInt64(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }));
-            Assert.AreEqual(4294967296UL, Pack.LittleEndianToUInt64(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }));
-            Assert.AreEqual(1099511627776UL, Pack.LittleEndianToUInt64(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }));
-            Assert.AreEqual(1099511892096UL, Pack.LittleEndianToUInt64(new byte[] { 128, 8, 4, 0, 0, 1, 0, 0 }));
-            Assert.AreEqual(1099511627776UL * 256, Pack.LittleEndianToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }));
-            Assert.AreEqual(1099511627776UL * 256 * 256, Pack.LittleEndianToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }));
-            Assert.AreEqual(ulong.MaxValue, Pack.LittleEndianToUInt64(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }));
-        }
-
-        [TestMethod]
-        public void UInt16ToLittleEndian()
-        {
-            AssertEqual(new byte[] { 0, 0 }, Pack.UInt16ToLittleEndian(0));
-            AssertEqual(new byte[] { 1, 0 }, Pack.UInt16ToLittleEndian(1));
-            AssertEqual(new byte[] { 0, 1 }, Pack.UInt16ToLittleEndian(256));
-            AssertEqual(new byte[] { 1, 1 }, Pack.UInt16ToLittleEndian(257));
-            AssertEqual(new byte[] { 1, 4 }, Pack.UInt16ToLittleEndian(1025));
-            AssertEqual(new byte[] { 255, 255 }, Pack.UInt16ToLittleEndian(ushort.MaxValue));
-        }
-
-        [TestMethod]
-        public void UInt32ToLittleEndian()
-        {
-            AssertEqual(new byte[] { 0, 0, 0, 0 }, Pack.UInt32ToLittleEndian(0));
-            AssertEqual(new byte[] { 1, 0, 0, 0 }, Pack.UInt32ToLittleEndian(1));
-            AssertEqual(new byte[] { 0, 1, 0, 0 }, Pack.UInt32ToLittleEndian(256));
-            AssertEqual(new byte[] { 1, 1, 0, 0 }, Pack.UInt32ToLittleEndian(257));
-            AssertEqual(new byte[] { 1, 4, 0, 0 }, Pack.UInt32ToLittleEndian(1025));
-            AssertEqual(new byte[] { 0, 0, 1, 0 }, Pack.UInt32ToLittleEndian(65536));
-            AssertEqual(new byte[] { 4, 8, 2, 0 }, Pack.UInt32ToLittleEndian(133124));
-            AssertEqual(new byte[] { 0, 0, 0, 1 }, Pack.UInt32ToLittleEndian(16777216));
-            AssertEqual(new byte[] { 255, 255, 255, 255 }, Pack.UInt32ToLittleEndian(uint.MaxValue));
-        }
-
-        [TestMethod]
-        public void UInt64ToLittleEndian()
-        {
-            AssertEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, Pack.UInt64ToLittleEndian(0UL));
-            AssertEqual(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, Pack.UInt64ToLittleEndian(1UL));
-            AssertEqual(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, Pack.UInt64ToLittleEndian(256UL));
-            AssertEqual(new byte[] { 1, 1, 0, 0, 0, 0, 0, 0 }, Pack.UInt64ToLittleEndian(257UL));
-            AssertEqual(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, Pack.UInt64ToLittleEndian(65536UL));
-            AssertEqual(new byte[] { 4, 8, 2, 0, 0, 0, 0, 0 }, Pack.UInt64ToLittleEndian(133124UL));
-            AssertEqual(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, Pack.UInt64ToLittleEndian(16777216UL));
-            AssertEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, Pack.UInt64ToLittleEndian(4294967296UL));
-            AssertEqual(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, Pack.UInt64ToLittleEndian(1099511627776UL));
-            AssertEqual(new byte[] { 128, 8, 4, 0, 0, 1, 0, 0 }, Pack.UInt64ToLittleEndian(1099511892096UL));
-            AssertEqual(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, Pack.UInt64ToLittleEndian(1099511627776UL * 256));
-            AssertEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, Pack.UInt64ToLittleEndian(1099511627776UL * 256 * 256));
-            AssertEqual(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, Pack.UInt64ToLittleEndian(ulong.MaxValue));
-        }
-
-        [TestMethod]
-        public void UInt16ToBigEndian()
-        {
-            AssertEqual(new byte[] { 0, 0 }, Pack.UInt16ToBigEndian(0));
-            AssertEqual(new byte[] { 0, 1 }, Pack.UInt16ToBigEndian(1));
-            AssertEqual(new byte[] { 1, 0 }, Pack.UInt16ToBigEndian(256));
-            AssertEqual(new byte[] { 1, 1 }, Pack.UInt16ToBigEndian(257));
-            AssertEqual(new byte[] { 4, 1 }, Pack.UInt16ToBigEndian(1025));
-            AssertEqual(new byte[] { 255, 255 }, Pack.UInt16ToBigEndian(ushort.MaxValue));
-        }
-
-        [TestMethod]
-        public void UInt32ToBigEndian()
-        {
-            AssertEqual(new byte[] { 0, 0, 0, 0 }, Pack.UInt32ToBigEndian(0));
-            AssertEqual(new byte[] { 0, 0, 0, 1 }, Pack.UInt32ToBigEndian(1));
-            AssertEqual(new byte[] { 0, 0, 1, 0 }, Pack.UInt32ToBigEndian(256));
-            AssertEqual(new byte[] { 0, 0, 1, 1 }, Pack.UInt32ToBigEndian(257));
-            AssertEqual(new byte[] { 0, 0, 4, 1 }, Pack.UInt32ToBigEndian(1025));
-            AssertEqual(new byte[] { 0, 1, 0, 0 }, Pack.UInt32ToBigEndian(65536));
-            AssertEqual(new byte[] { 0, 2, 8, 4 }, Pack.UInt32ToBigEndian(133124));
-            AssertEqual(new byte[] { 1, 0, 0, 0 }, Pack.UInt32ToBigEndian(16777216));
-            AssertEqual(new byte[] { 255, 255, 255, 255 }, Pack.UInt32ToBigEndian(uint.MaxValue));
-        }
-
-        [TestMethod]
-        public void UInt64ToBigEndian()
-        {
-            AssertEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, Pack.UInt64ToBigEndian(0UL));
-            AssertEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, Pack.UInt64ToBigEndian(1UL));
-            AssertEqual(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, Pack.UInt64ToBigEndian(256UL));
-            AssertEqual(new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, Pack.UInt64ToBigEndian(257UL));
-            AssertEqual(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, Pack.UInt64ToBigEndian(65536UL));
-            AssertEqual(new byte[] { 0, 0, 0, 0, 0, 2, 8, 4 }, Pack.UInt64ToBigEndian(133124UL));
-            AssertEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, Pack.UInt64ToBigEndian(16777216UL));
-            AssertEqual(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, Pack.UInt64ToBigEndian(4294967296UL));
-            AssertEqual(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, Pack.UInt64ToBigEndian(1099511627776UL));
-            AssertEqual(new byte[] { 0, 0, 1, 0, 0, 4, 8, 128 }, Pack.UInt64ToBigEndian(1099511892096UL));
-            AssertEqual(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, Pack.UInt64ToBigEndian(1099511627776UL * 256));
-            AssertEqual(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, Pack.UInt64ToBigEndian(1099511627776UL * 256 * 256));
-            AssertEqual(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, Pack.UInt64ToBigEndian(ulong.MaxValue));
-        }
-
-        private static void AssertEqual(byte[] expected, byte[] actual)
-        {
-            Assert.IsTrue(expected.IsEqualTo(actual));
-        }
-    }
-}