From aadf165e48945fd6b934ae1808ca4ff43e44a47b Mon Sep 17 00:00:00 2001 From: Marius Thesing Date: Sun, 21 Jul 2024 16:28:57 +0200 Subject: [PATCH 1/2] Clean up Abstractions / use HashData - replace usages of GenerateRandom(byte[]) with GenerateRandom(int) - remove Create() functions and make use of static HashData methods on .NET 6+, see https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1850 - Remove unused ReflectionAbstraction --- .../Abstractions/CryptoAbstraction.cs | 49 +------------- .../Abstractions/ReflectionAbstraction.cs | 16 ----- src/Renci.SshNet/Common/BigInteger.cs | 3 +- src/Renci.SshNet/Common/HostKeyEventArgs.cs | 14 +++- src/Renci.SshNet/Messages/Message.cs | 6 +- .../Transport/KeyExchangeInitMessage.cs | 4 +- src/Renci.SshNet/PrivateKeyFile.cs | 65 ++++++++++++------- .../Security/Cryptography/Bcrypt.cs | 2 +- .../Cryptography/DsaDigitalSignature.cs | 3 +- ...yExchangeDiffieHellmanGroupExchangeSha1.cs | 10 ++- ...xchangeDiffieHellmanGroupExchangeSha256.cs | 8 ++- .../KeyExchangeDiffieHellmanGroupSha1.cs | 10 ++- .../KeyExchangeDiffieHellmanGroupSha256.cs | 8 ++- .../KeyExchangeDiffieHellmanGroupSha512.cs | 8 ++- .../Security/KeyExchangeECCurve25519.cs | 12 +++- .../Security/KeyExchangeECDH256.cs | 14 ++-- .../Security/KeyExchangeECDH384.cs | 14 ++-- .../Security/KeyExchangeECDH521.cs | 14 ++-- .../Classes/SessionTest_ConnectingBase.cs | 7 +- 19 files changed, 134 insertions(+), 133 deletions(-) delete mode 100644 src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs diff --git a/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs b/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs index 1567af3ef..a94e49a4e 100644 --- a/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs @@ -1,10 +1,10 @@ -using System; +using System.Security.Cryptography; namespace Renci.SshNet.Abstractions { internal static class CryptoAbstraction { - private static readonly System.Security.Cryptography.RandomNumberGenerator Randomizer = CreateRandomNumberGenerator(); + private static readonly RandomNumberGenerator Randomizer = RandomNumberGenerator.Create(); /// /// Generates a array of the specified length, and fills it with a @@ -14,51 +14,8 @@ internal static class CryptoAbstraction public static byte[] GenerateRandom(int length) { var random = new byte[length]; - GenerateRandom(random); + Randomizer.GetBytes(random); return random; } - - /// - /// Fills an array of bytes with a cryptographically strong random sequence of values. - /// - /// The array to fill with cryptographically strong random bytes. - /// is . - /// - /// The length of the byte array determines how many random bytes are produced. - /// - public static void GenerateRandom(byte[] data) - { - Randomizer.GetBytes(data); - } - - public static System.Security.Cryptography.RandomNumberGenerator CreateRandomNumberGenerator() - { - return System.Security.Cryptography.RandomNumberGenerator.Create(); - } - - public static System.Security.Cryptography.MD5 CreateMD5() - { - return System.Security.Cryptography.MD5.Create(); - } - - public static System.Security.Cryptography.SHA1 CreateSHA1() - { - return System.Security.Cryptography.SHA1.Create(); - } - - public static System.Security.Cryptography.SHA256 CreateSHA256() - { - return System.Security.Cryptography.SHA256.Create(); - } - - public static System.Security.Cryptography.SHA384 CreateSHA384() - { - return System.Security.Cryptography.SHA384.Create(); - } - - public static System.Security.Cryptography.SHA512 CreateSHA512() - { - return System.Security.Cryptography.SHA512.Create(); - } } } diff --git a/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs b/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs deleted file mode 100644 index d9e15a508..000000000 --- a/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Renci.SshNet.Abstractions -{ - internal static class ReflectionAbstraction - { - public static IEnumerable GetCustomAttributes(this Type type, bool inherit) - where T : Attribute - { - var attributes = type.GetCustomAttributes(typeof(T), inherit); - return attributes.Cast(); - } - } -} diff --git a/src/Renci.SshNet/Common/BigInteger.cs b/src/Renci.SshNet/Common/BigInteger.cs index c83ddbadc..57c3def90 100644 --- a/src/Renci.SshNet/Common/BigInteger.cs +++ b/src/Renci.SshNet/Common/BigInteger.cs @@ -179,8 +179,7 @@ public static BigInteger PositiveMod(BigInteger dividend, BigInteger divisor) /// A random number of the specified length. public static BigInteger Random(int bitLength) { - var bytesArray = new byte[(bitLength / 8) + (((bitLength % 8) > 0) ? 1 : 0)]; - CryptoAbstraction.GenerateRandom(bytesArray); + var bytesArray = CryptoAbstraction.GenerateRandom((bitLength / 8) + (((bitLength % 8) > 0) ? 1 : 0)); bytesArray[bytesArray.Length - 1] = (byte)(bytesArray[bytesArray.Length - 1] & 0x7F); // Ensure not a negative value return new BigInteger(bytesArray); } diff --git a/src/Renci.SshNet/Common/HostKeyEventArgs.cs b/src/Renci.SshNet/Common/HostKeyEventArgs.cs index acd38965a..20639646e 100644 --- a/src/Renci.SshNet/Common/HostKeyEventArgs.cs +++ b/src/Renci.SshNet/Common/HostKeyEventArgs.cs @@ -1,6 +1,6 @@ using System; +using System.Security.Cryptography; -using Renci.SshNet.Abstractions; using Renci.SshNet.Security; namespace Renci.SshNet.Common @@ -102,15 +102,23 @@ public HostKeyEventArgs(KeyHostAlgorithm host) _lazyFingerPrint = new Lazy(() => { - using var md5 = CryptoAbstraction.CreateMD5(); +#if NET6_0_OR_GREATER + return MD5.HashData(HostKey); +#else + using var md5 = MD5.Create(); return md5.ComputeHash(HostKey); +#endif }); _lazyFingerPrintSHA256 = new Lazy(() => { - using var sha256 = CryptoAbstraction.CreateSHA256(); +#if NET6_0_OR_GREATER + return Convert.ToBase64String(SHA256.HashData(HostKey)) +#else + using var sha256 = SHA256.Create(); return Convert.ToBase64String(sha256.ComputeHash(HostKey)) +#endif #if NET || NETSTANDARD2_1_OR_GREATER .Replace("=", string.Empty, StringComparison.Ordinal); #else diff --git a/src/Renci.SshNet/Messages/Message.cs b/src/Renci.SshNet/Messages/Message.cs index 07b747472..ea8f6a9b5 100644 --- a/src/Renci.SshNet/Messages/Message.cs +++ b/src/Renci.SshNet/Messages/Message.cs @@ -83,8 +83,7 @@ internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor, bool ex var paddingLength = GetPaddingLength(paddingMultiplier, excludePacketLengthFieldWhenPadding ? packetLength - 4 : packetLength); // add padding bytes - var paddingBytes = new byte[paddingLength]; - CryptoAbstraction.GenerateRandom(paddingBytes); + var paddingBytes = CryptoAbstraction.GenerateRandom(paddingLength); sshDataStream.Write(paddingBytes, 0, paddingLength); var packetDataLength = GetPacketDataLength(messageLength, paddingLength); @@ -128,8 +127,7 @@ internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor, bool ex WriteBytes(sshDataStream); // add padding bytes - var paddingBytes = new byte[paddingLength]; - CryptoAbstraction.GenerateRandom(paddingBytes); + var paddingBytes = CryptoAbstraction.GenerateRandom(paddingLength); sshDataStream.Write(paddingBytes, 0, paddingLength); return sshDataStream.ToArray(); diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs index 7bfce46dc..a0e7979ec 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs @@ -12,9 +12,7 @@ public class KeyExchangeInitMessage : Message, IKeyExchangedAllowed /// public KeyExchangeInitMessage() { - var cookie = new byte[16]; - CryptoAbstraction.GenerateRandom(cookie); - Cookie = cookie; + Cookie = CryptoAbstraction.GenerateRandom(16); } #region Message Properties diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 59e72cec6..94f90d800 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -7,7 +7,6 @@ using System.Text; using System.Text.RegularExpressions; -using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Security; using Renci.SshNet.Security.Cryptography; @@ -380,19 +379,27 @@ private static byte[] GetCipherKey(string passphrase, int length) { var cipherKey = new List(); - using (var md5 = CryptoAbstraction.CreateMD5()) - { - var passwordBytes = Encoding.UTF8.GetBytes(passphrase); +#if !NET6_0_OR_GREATER + using var md5 = MD5.Create(); +#endif + var passwordBytes = Encoding.UTF8.GetBytes(passphrase); - var hash = md5.ComputeHash(passwordBytes); - cipherKey.AddRange(hash); +#if NET6_0_OR_GREATER + var hash = MD5.HashData(passwordBytes); +#else + var hash = md5.ComputeHash(passwordBytes); +#endif + cipherKey.AddRange(hash); - while (cipherKey.Count < length) - { - hash = passwordBytes.Concat(hash); - hash = md5.ComputeHash(hash); - cipherKey.AddRange(hash); - } + while (cipherKey.Count < length) + { + hash = passwordBytes.Concat(hash); +#if NET6_0_OR_GREATER + hash = MD5.HashData(hash); +#else + hash = md5.ComputeHash(hash); +#endif + cipherKey.AddRange(hash); } return cipherKey.ToArray().Take(length); @@ -426,22 +433,30 @@ private static byte[] DecryptKey(CipherInfo cipherInfo, byte[] cipherData, strin var cipherKey = new List(); - using (var md5 = CryptoAbstraction.CreateMD5()) - { - var passwordBytes = Encoding.UTF8.GetBytes(passPhrase); +#if !NET6_0_OR_GREATER + using var md5 = MD5.Create(); +#endif + var passwordBytes = Encoding.UTF8.GetBytes(passPhrase); - // Use 8 bytes binary salt - var initVector = passwordBytes.Concat(binarySalt.Take(8)); + // Use 8 bytes binary salt + var initVector = passwordBytes.Concat(binarySalt.Take(8)); - var hash = md5.ComputeHash(initVector); - cipherKey.AddRange(hash); +#if NET6_0_OR_GREATER + var hash = MD5.HashData(initVector); +#else + var hash = md5.ComputeHash(initVector); +#endif + cipherKey.AddRange(hash); - while (cipherKey.Count < cipherInfo.KeySize / 8) - { - hash = hash.Concat(initVector); - hash = md5.ComputeHash(hash); - cipherKey.AddRange(hash); - } + while (cipherKey.Count < cipherInfo.KeySize / 8) + { + hash = hash.Concat(initVector); +#if NET6_0_OR_GREATER + hash = MD5.HashData(hash); +#else + hash = md5.ComputeHash(hash); +#endif + cipherKey.AddRange(hash); } var cipher = cipherInfo.Cipher(cipherKey.ToArray(), binarySalt); diff --git a/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs b/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs index 14f6169a5..40ab0695c 100644 --- a/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs +++ b/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs @@ -852,7 +852,7 @@ public void Hash(byte[] hpass, byte[] hsalt, byte[] output) /// public void Pbkdf(byte[] password, byte[] salt, int rounds, byte[] output) { - using (var sha512 = CryptoAbstraction.CreateSHA512()) + using (var sha512 = SHA512.Create()) { int nblocks = (output.Length + 31) / 32; byte[] hpass = sha512.ComputeHash(password); diff --git a/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs index a5aae17c0..8fdb6a8f7 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs @@ -1,7 +1,6 @@ using System; using System.Security.Cryptography; -using Renci.SshNet.Abstractions; using Renci.SshNet.Common; namespace Renci.SshNet.Security.Cryptography @@ -29,7 +28,7 @@ public DsaDigitalSignature(DsaKey key) _key = key; - _hash = CryptoAbstraction.CreateSHA1(); + _hash = SHA1.Create(); } /// diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs index 791e2c44b..95017bd6a 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs @@ -1,4 +1,4 @@ -using Renci.SshNet.Abstractions; +using System.Security.Cryptography; namespace Renci.SshNet.Security { @@ -35,10 +35,14 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { - using (var sha1 = CryptoAbstraction.CreateSHA1()) +#if NET6_0_OR_GREATER + return SHA1.HashData(hashData); +#else + using (var sha1 = SHA1.Create()) { - return sha1.ComputeHash(hashData, 0, hashData.Length); + return sha1.ComputeHash(hashData); } +#endif } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs index 2e286345c..a7ca60ac5 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs @@ -1,4 +1,4 @@ -using Renci.SshNet.Abstractions; +using System.Security.Cryptography; namespace Renci.SshNet.Security { @@ -35,10 +35,14 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { - using (var sha256 = CryptoAbstraction.CreateSHA256()) +#if NET6_0_OR_GREATER + return SHA256.HashData(hashData); +#else + using (var sha256 = SHA256.Create()) { return sha256.ComputeHash(hashData); } +#endif } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs index 4669eb8ae..c431ee8ab 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs @@ -1,4 +1,4 @@ -using Renci.SshNet.Abstractions; +using System.Security.Cryptography; namespace Renci.SshNet.Security { @@ -27,10 +27,14 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { - using (var sha1 = CryptoAbstraction.CreateSHA1()) +#if NET6_0_OR_GREATER + return SHA1.HashData(hashData); +#else + using (var sha1 = SHA1.Create()) { - return sha1.ComputeHash(hashData, 0, hashData.Length); + return sha1.ComputeHash(hashData); } +#endif } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs index ea29e6e2f..7f046b113 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs @@ -1,4 +1,4 @@ -using Renci.SshNet.Abstractions; +using System.Security.Cryptography; namespace Renci.SshNet.Security { @@ -27,10 +27,14 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { - using (var sha256 = CryptoAbstraction.CreateSHA256()) +#if NET6_0_OR_GREATER + return SHA256.HashData(hashData); +#else + using (var sha256 = SHA256.Create()) { return sha256.ComputeHash(hashData); } +#endif } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs index 60a8e5f7c..07145c0c7 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs @@ -1,4 +1,4 @@ -using Renci.SshNet.Abstractions; +using System.Security.Cryptography; namespace Renci.SshNet.Security { @@ -27,10 +27,14 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { - using (var sha512 = CryptoAbstraction.CreateSHA512()) +#if NET6_0_OR_GREATER + return SHA512.HashData(hashData); +#else + using (var sha512 = SHA512.Create()) { return sha512.ComputeHash(hashData); } +#endif } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs index c6c060bab..97e2026e3 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs @@ -1,4 +1,6 @@ -using Renci.SshNet.Abstractions; +using System.Security.Cryptography; + +using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Security.Chaos.NaCl; @@ -68,10 +70,14 @@ public override void Finish() /// protected override byte[] Hash(byte[] hashData) { - using (var sha256 = CryptoAbstraction.CreateSHA256()) +#if NET6_0_OR_GREATER + return SHA256.HashData(hashData); +#else + using (var sha256 = SHA256.Create()) { - return sha256.ComputeHash(hashData, 0, hashData.Length); + return sha256.ComputeHash(hashData); } +#endif } private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageEventArgs e) diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH256.cs b/src/Renci.SshNet/Security/KeyExchangeECDH256.cs index a519c1896..f15689743 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH256.cs @@ -1,7 +1,7 @@ -using Org.BouncyCastle.Asn1.Sec; -using Org.BouncyCastle.Asn1.X9; +using System.Security.Cryptography; -using Renci.SshNet.Abstractions; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X9; namespace Renci.SshNet.Security { @@ -46,10 +46,14 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { - using (var sha256 = CryptoAbstraction.CreateSHA256()) +#if NET6_0_OR_GREATER + return SHA256.HashData(hashData); +#else + using (var sha256 = SHA256.Create()) { - return sha256.ComputeHash(hashData, 0, hashData.Length); + return sha256.ComputeHash(hashData); } +#endif } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH384.cs b/src/Renci.SshNet/Security/KeyExchangeECDH384.cs index e91dcf965..016ad74f9 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH384.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH384.cs @@ -1,7 +1,7 @@ -using Org.BouncyCastle.Asn1.Sec; -using Org.BouncyCastle.Asn1.X9; +using System.Security.Cryptography; -using Renci.SshNet.Abstractions; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X9; namespace Renci.SshNet.Security { @@ -46,10 +46,14 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { - using (var sha384 = CryptoAbstraction.CreateSHA384()) +#if NET6_0_OR_GREATER + return SHA384.HashData(hashData); +#else + using (var sha384 = SHA384.Create()) { - return sha384.ComputeHash(hashData, 0, hashData.Length); + return sha384.ComputeHash(hashData); } +#endif } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH521.cs b/src/Renci.SshNet/Security/KeyExchangeECDH521.cs index 9ed146e96..dfc50b73a 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH521.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH521.cs @@ -1,7 +1,7 @@ -using Org.BouncyCastle.Asn1.Sec; -using Org.BouncyCastle.Asn1.X9; +using System.Security.Cryptography; -using Renci.SshNet.Abstractions; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X9; namespace Renci.SshNet.Security { @@ -46,10 +46,14 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { - using (var sha512 = CryptoAbstraction.CreateSHA512()) +#if NET6_0_OR_GREATER + return SHA512.HashData(hashData); +#else + using (var sha512 = SHA512.Create()) { - return sha512.ComputeHash(hashData, 0, hashData.Length); + return sha512.ComputeHash(hashData); } +#endif } } } diff --git a/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectingBase.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectingBase.cs index 05ce88754..45690d20e 100644 --- a/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectingBase.cs +++ b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectingBase.cs @@ -181,7 +181,12 @@ protected virtual void SetupData() { var serviceAcceptMessage = ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication) .Build(ServerOutboundPacketSequence); - var hash = Abstractions.CryptoAbstraction.CreateSHA256().ComputeHash(serviceAcceptMessage); + +#if NET6_0_OR_GREATER + var hash = SHA256.HashData(serviceAcceptMessage); +#else + var hash = SHA256.Create().ComputeHash(serviceAcceptMessage); +#endif var packet = new byte[serviceAcceptMessage.Length - 4 + hash.Length]; From 1fa45a3c1f43fbbb88c01093e35b5122dd7f0c07 Mon Sep 17 00:00:00 2001 From: Marius Thesing Date: Mon, 22 Jul 2024 18:41:00 +0200 Subject: [PATCH 2/2] Use Abstractions for HashData Co-authored-by: Robert Hague --- .../Abstractions/CryptoAbstraction.cs | 60 ++++++++++++++++ src/Renci.SshNet/Common/HostKeyEventArgs.cs | 20 +----- src/Renci.SshNet/PrivateKeyFile.cs | 68 ++++++++----------- ...yExchangeDiffieHellmanGroupExchangeSha1.cs | 11 +-- ...xchangeDiffieHellmanGroupExchangeSha256.cs | 11 +-- .../KeyExchangeDiffieHellmanGroupSha1.cs | 11 +-- .../KeyExchangeDiffieHellmanGroupSha256.cs | 11 +-- .../KeyExchangeDiffieHellmanGroupSha512.cs | 11 +-- .../Security/KeyExchangeECCurve25519.cs | 13 +--- .../Security/KeyExchangeECDH256.cs | 13 +--- .../Security/KeyExchangeECDH384.cs | 13 +--- .../Security/KeyExchangeECDH521.cs | 13 +--- .../Classes/SessionTest_ConnectingBase.cs | 7 +- 13 files changed, 114 insertions(+), 148 deletions(-) diff --git a/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs b/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs index a94e49a4e..46f4b429d 100644 --- a/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs @@ -17,5 +17,65 @@ public static byte[] GenerateRandom(int length) Randomizer.GetBytes(random); return random; } + + public static byte[] HashMD5(byte[] source) + { +#if NET + return MD5.HashData(source); +#else + using (var md5 = MD5.Create()) + { + return md5.ComputeHash(source); + } +#endif + } + + public static byte[] HashSHA1(byte[] source) + { +#if NET + return SHA1.HashData(source); +#else + using (var sha1 = SHA1.Create()) + { + return sha1.ComputeHash(source); + } +#endif + } + + public static byte[] HashSHA256(byte[] source) + { +#if NET + return SHA256.HashData(source); +#else + using (var sha256 = SHA256.Create()) + { + return sha256.ComputeHash(source); + } +#endif + } + + public static byte[] HashSHA384(byte[] source) + { +#if NET + return SHA384.HashData(source); +#else + using (var sha384 = SHA384.Create()) + { + return sha384.ComputeHash(source); + } +#endif + } + + public static byte[] HashSHA512(byte[] source) + { +#if NET + return SHA512.HashData(source); +#else + using (var sha512 = SHA512.Create()) + { + return sha512.ComputeHash(source); + } +#endif + } } } diff --git a/src/Renci.SshNet/Common/HostKeyEventArgs.cs b/src/Renci.SshNet/Common/HostKeyEventArgs.cs index 20639646e..e3365bec9 100644 --- a/src/Renci.SshNet/Common/HostKeyEventArgs.cs +++ b/src/Renci.SshNet/Common/HostKeyEventArgs.cs @@ -1,6 +1,6 @@ using System; -using System.Security.Cryptography; +using Renci.SshNet.Abstractions; using Renci.SshNet.Security; namespace Renci.SshNet.Common @@ -100,25 +100,11 @@ public HostKeyEventArgs(KeyHostAlgorithm host) HostKeyName = host.Name; KeyLength = host.Key.KeyLength; - _lazyFingerPrint = new Lazy(() => - { -#if NET6_0_OR_GREATER - return MD5.HashData(HostKey); -#else - using var md5 = MD5.Create(); - return md5.ComputeHash(HostKey); -#endif - }); + _lazyFingerPrint = new Lazy(() => CryptoAbstraction.HashMD5(HostKey)); _lazyFingerPrintSHA256 = new Lazy(() => { -#if NET6_0_OR_GREATER - return Convert.ToBase64String(SHA256.HashData(HostKey)) -#else - using var sha256 = SHA256.Create(); - - return Convert.ToBase64String(sha256.ComputeHash(HostKey)) -#endif + return Convert.ToBase64String(CryptoAbstraction.HashSHA256(HostKey)) #if NET || NETSTANDARD2_1_OR_GREATER .Replace("=", string.Empty, StringComparison.Ordinal); #else diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 94f90d800..b0ed8668f 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -379,28 +379,22 @@ private static byte[] GetCipherKey(string passphrase, int length) { var cipherKey = new List(); -#if !NET6_0_OR_GREATER - using var md5 = MD5.Create(); -#endif - var passwordBytes = Encoding.UTF8.GetBytes(passphrase); - -#if NET6_0_OR_GREATER - var hash = MD5.HashData(passwordBytes); -#else - var hash = md5.ComputeHash(passwordBytes); -#endif - cipherKey.AddRange(hash); - - while (cipherKey.Count < length) +#pragma warning disable CA1850 // Prefer static HashData method; We'll reuse the object on lower targets. + using (var md5 = MD5.Create()) { - hash = passwordBytes.Concat(hash); -#if NET6_0_OR_GREATER - hash = MD5.HashData(hash); -#else - hash = md5.ComputeHash(hash); -#endif + var passwordBytes = Encoding.UTF8.GetBytes(passphrase); + + var hash = md5.ComputeHash(passwordBytes); cipherKey.AddRange(hash); + + while (cipherKey.Count < length) + { + hash = passwordBytes.Concat(hash); + hash = md5.ComputeHash(hash); + cipherKey.AddRange(hash); + } } +#pragma warning restore CA1850 // Prefer static HashData method return cipherKey.ToArray().Take(length); } @@ -433,31 +427,25 @@ private static byte[] DecryptKey(CipherInfo cipherInfo, byte[] cipherData, strin var cipherKey = new List(); -#if !NET6_0_OR_GREATER - using var md5 = MD5.Create(); -#endif - var passwordBytes = Encoding.UTF8.GetBytes(passPhrase); - - // Use 8 bytes binary salt - var initVector = passwordBytes.Concat(binarySalt.Take(8)); +#pragma warning disable CA1850 // Prefer static HashData method; We'll reuse the object on lower targets. + using (var md5 = MD5.Create()) + { + var passwordBytes = Encoding.UTF8.GetBytes(passPhrase); -#if NET6_0_OR_GREATER - var hash = MD5.HashData(initVector); -#else - var hash = md5.ComputeHash(initVector); -#endif - cipherKey.AddRange(hash); + // Use 8 bytes binary salt + var initVector = passwordBytes.Concat(binarySalt.Take(8)); - while (cipherKey.Count < cipherInfo.KeySize / 8) - { - hash = hash.Concat(initVector); -#if NET6_0_OR_GREATER - hash = MD5.HashData(hash); -#else - hash = md5.ComputeHash(hash); -#endif + var hash = md5.ComputeHash(initVector); cipherKey.AddRange(hash); + + while (cipherKey.Count < cipherInfo.KeySize / 8) + { + hash = hash.Concat(initVector); + hash = md5.ComputeHash(hash); + cipherKey.AddRange(hash); + } } +#pragma warning restore CA1850 // Prefer static HashData method var cipher = cipherInfo.Cipher(cipherKey.ToArray(), binarySalt); diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs index 95017bd6a..5eb0e7c17 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs @@ -1,4 +1,4 @@ -using System.Security.Cryptography; +using Renci.SshNet.Abstractions; namespace Renci.SshNet.Security { @@ -35,14 +35,7 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { -#if NET6_0_OR_GREATER - return SHA1.HashData(hashData); -#else - using (var sha1 = SHA1.Create()) - { - return sha1.ComputeHash(hashData); - } -#endif + return CryptoAbstraction.HashSHA1(hashData); } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs index a7ca60ac5..62d466cc1 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs @@ -1,4 +1,4 @@ -using System.Security.Cryptography; +using Renci.SshNet.Abstractions; namespace Renci.SshNet.Security { @@ -35,14 +35,7 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { -#if NET6_0_OR_GREATER - return SHA256.HashData(hashData); -#else - using (var sha256 = SHA256.Create()) - { - return sha256.ComputeHash(hashData); - } -#endif + return CryptoAbstraction.HashSHA256(hashData); } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs index c431ee8ab..26d13a4d4 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs @@ -1,4 +1,4 @@ -using System.Security.Cryptography; +using Renci.SshNet.Abstractions; namespace Renci.SshNet.Security { @@ -27,14 +27,7 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { -#if NET6_0_OR_GREATER - return SHA1.HashData(hashData); -#else - using (var sha1 = SHA1.Create()) - { - return sha1.ComputeHash(hashData); - } -#endif + return CryptoAbstraction.HashSHA1(hashData); } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs index 7f046b113..3246a3d8e 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs @@ -1,4 +1,4 @@ -using System.Security.Cryptography; +using Renci.SshNet.Abstractions; namespace Renci.SshNet.Security { @@ -27,14 +27,7 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { -#if NET6_0_OR_GREATER - return SHA256.HashData(hashData); -#else - using (var sha256 = SHA256.Create()) - { - return sha256.ComputeHash(hashData); - } -#endif + return CryptoAbstraction.HashSHA256(hashData); } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs index 07145c0c7..b599e9d2e 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs @@ -1,4 +1,4 @@ -using System.Security.Cryptography; +using Renci.SshNet.Abstractions; namespace Renci.SshNet.Security { @@ -27,14 +27,7 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { -#if NET6_0_OR_GREATER - return SHA512.HashData(hashData); -#else - using (var sha512 = SHA512.Create()) - { - return sha512.ComputeHash(hashData); - } -#endif + return CryptoAbstraction.HashSHA512(hashData); } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs index 97e2026e3..987665afe 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs @@ -1,6 +1,4 @@ -using System.Security.Cryptography; - -using Renci.SshNet.Abstractions; +using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Security.Chaos.NaCl; @@ -70,14 +68,7 @@ public override void Finish() /// protected override byte[] Hash(byte[] hashData) { -#if NET6_0_OR_GREATER - return SHA256.HashData(hashData); -#else - using (var sha256 = SHA256.Create()) - { - return sha256.ComputeHash(hashData); - } -#endif + return CryptoAbstraction.HashSHA256(hashData); } private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageEventArgs e) diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH256.cs b/src/Renci.SshNet/Security/KeyExchangeECDH256.cs index f15689743..aabfba62f 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH256.cs @@ -1,8 +1,8 @@ -using System.Security.Cryptography; - using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.X9; +using Renci.SshNet.Abstractions; + namespace Renci.SshNet.Security { internal sealed class KeyExchangeECDH256 : KeyExchangeECDH @@ -46,14 +46,7 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { -#if NET6_0_OR_GREATER - return SHA256.HashData(hashData); -#else - using (var sha256 = SHA256.Create()) - { - return sha256.ComputeHash(hashData); - } -#endif + return CryptoAbstraction.HashSHA256(hashData); } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH384.cs b/src/Renci.SshNet/Security/KeyExchangeECDH384.cs index 016ad74f9..39fcf3bde 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH384.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH384.cs @@ -1,8 +1,8 @@ -using System.Security.Cryptography; - using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.X9; +using Renci.SshNet.Abstractions; + namespace Renci.SshNet.Security { internal sealed class KeyExchangeECDH384 : KeyExchangeECDH @@ -46,14 +46,7 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { -#if NET6_0_OR_GREATER - return SHA384.HashData(hashData); -#else - using (var sha384 = SHA384.Create()) - { - return sha384.ComputeHash(hashData); - } -#endif + return CryptoAbstraction.HashSHA384(hashData); } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH521.cs b/src/Renci.SshNet/Security/KeyExchangeECDH521.cs index dfc50b73a..17fa89e7f 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH521.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH521.cs @@ -1,8 +1,8 @@ -using System.Security.Cryptography; - using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.X9; +using Renci.SshNet.Abstractions; + namespace Renci.SshNet.Security { internal sealed class KeyExchangeECDH521 : KeyExchangeECDH @@ -46,14 +46,7 @@ protected override int HashSize /// protected override byte[] Hash(byte[] hashData) { -#if NET6_0_OR_GREATER - return SHA512.HashData(hashData); -#else - using (var sha512 = SHA512.Create()) - { - return sha512.ComputeHash(hashData); - } -#endif + return CryptoAbstraction.HashSHA512(hashData); } } } diff --git a/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectingBase.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectingBase.cs index 45690d20e..f2c2f3476 100644 --- a/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectingBase.cs +++ b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectingBase.cs @@ -9,6 +9,7 @@ using Moq; +using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Compression; using Renci.SshNet.Connection; @@ -182,11 +183,7 @@ protected virtual void SetupData() var serviceAcceptMessage = ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication) .Build(ServerOutboundPacketSequence); -#if NET6_0_OR_GREATER - var hash = SHA256.HashData(serviceAcceptMessage); -#else - var hash = SHA256.Create().ComputeHash(serviceAcceptMessage); -#endif + var hash = CryptoAbstraction.HashSHA256(serviceAcceptMessage); var packet = new byte[serviceAcceptMessage.Length - 4 + hash.Length];