From 23108457286979cd680f44c24b602a2b49c747e8 Mon Sep 17 00:00:00 2001 From: drieseng Date: Sat, 23 Apr 2016 20:34:22 +0200 Subject: [PATCH] Introduce abstraction for generating a strong random sequence, as UWP/WinRT does not come with RandomNumberGenerator. On UWP/WinRT, we'll use CryptographicBuffer.GenerateRandom(uint). We'll probably revisit this once CoreFX is more stable (after RC2). --- src/Renci.SshNet/Common/BigInteger.cs | 4 +- src/Renci.SshNet/Messages/Message.cs | 7 +- .../Transport/KeyExchangeInitMessage.cs | 5 +- .../Cryptography/HashAlgorithmFactory.cs | 97 ++++++++++++------- 4 files changed, 65 insertions(+), 48 deletions(-) diff --git a/src/Renci.SshNet/Common/BigInteger.cs b/src/Renci.SshNet/Common/BigInteger.cs index 981c280c..d1848d47 100644 --- a/src/Renci.SshNet/Common/BigInteger.cs +++ b/src/Renci.SshNet/Common/BigInteger.cs @@ -67,8 +67,6 @@ namespace Renci.SshNet.Common /// public struct BigInteger : IComparable, IFormattable, IComparable, IEquatable { - private static readonly RandomNumberGenerator _randomizer = HashAlgorithmFactory.CreateRandomNumberGenerator(); - private const ulong _BASE = 0x100000000; private const Int32 _DECIMALSIGNMASK = unchecked((Int32)0x80000000); private const int _BIAS = 1075; @@ -1968,7 +1966,7 @@ namespace Renci.SshNet.Common public static BigInteger Random(int bitLength) { var bytesArray = new byte[bitLength / 8 + (((bitLength % 8) > 0) ? 1 : 0)]; - _randomizer.GetBytes(bytesArray); + HashAlgorithmFactory.GenerateRandom(bytesArray); bytesArray[bytesArray.Length - 1] = (byte)(bytesArray[bytesArray.Length - 1] & 0x7F); // Ensure not a negative value #if TUNING return new BigInteger(bytesArray); diff --git a/src/Renci.SshNet/Messages/Message.cs b/src/Renci.SshNet/Messages/Message.cs index 21c8f466..68ad5560 100644 --- a/src/Renci.SshNet/Messages/Message.cs +++ b/src/Renci.SshNet/Messages/Message.cs @@ -1,6 +1,5 @@ using System.IO; using System.Linq; -using System.Security.Cryptography; using Renci.SshNet.Common; using System.Globalization; using Renci.SshNet.Abstractions; @@ -14,8 +13,6 @@ namespace Renci.SshNet.Messages /// public abstract class Message : SshData { - private static readonly RandomNumberGenerator Randomizer = HashAlgorithmFactory.CreateRandomNumberGenerator(); - /// /// Gets the index that represents zero in current data type. /// @@ -104,7 +101,7 @@ namespace Renci.SshNet.Messages // add padding bytes var paddingBytes = new byte[paddingLength]; - Randomizer.GetBytes(paddingBytes); + HashAlgorithmFactory.GenerateRandom(paddingBytes); sshDataStream.Write(paddingBytes, 0, paddingLength); var packetDataLength = GetPacketDataLength(messageLength, paddingLength); @@ -144,7 +141,7 @@ namespace Renci.SshNet.Messages // add padding bytes var paddingBytes = new byte[paddingLength]; - Randomizer.GetBytes(paddingBytes); + HashAlgorithmFactory.GenerateRandom(paddingBytes); sshDataStream.Write(paddingBytes, 0, paddingLength); } diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs index 0fe5cff1..293e1153 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs @@ -1,5 +1,4 @@ using System; -using System.Security.Cryptography; using Renci.SshNet.Security.Cryptography; namespace Renci.SshNet.Messages.Transport @@ -10,15 +9,13 @@ namespace Renci.SshNet.Messages.Transport [Message("SSH_MSG_KEXINIT", 20)] public class KeyExchangeInitMessage : Message, IKeyExchangedAllowed { - private static readonly RandomNumberGenerator Randomizer = HashAlgorithmFactory.CreateRandomNumberGenerator(); - /// /// Initializes a new instance of the class. /// public KeyExchangeInitMessage() { var cookie = new byte[16]; - Randomizer.GetBytes(cookie); + HashAlgorithmFactory.GenerateRandom(cookie); Cookie = cookie; } diff --git a/src/Renci.SshNet/Security/Cryptography/HashAlgorithmFactory.cs b/src/Renci.SshNet/Security/Cryptography/HashAlgorithmFactory.cs index 2dbd1e49..6ac6fc10 100644 --- a/src/Renci.SshNet/Security/Cryptography/HashAlgorithmFactory.cs +++ b/src/Renci.SshNet/Security/Cryptography/HashAlgorithmFactory.cs @@ -1,9 +1,33 @@ -using System.Security.Cryptography; +using System; +using System.Security.Cryptography; +using Renci.SshNet.Messages.Authentication; namespace Renci.SshNet.Security.Cryptography { internal static class HashAlgorithmFactory { +#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP + private static readonly RandomNumberGenerator _randomizer = HashAlgorithmFactory.CreateRandomNumberGenerator(); +#endif + + /// + /// Fills an array of bytes with a cryptographically strong random sequence of values. + /// + /// The array to fill with cryptographically strong random bytes. + /// + /// The length of the byte array determines how many random bytes are produced. + /// + public static void GenerateRandom(byte[] data) + { +#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP + _randomizer.GetBytes(data); +#else + var buffer = Windows.Security.Cryptography.CryptographicBuffer.GenerateRandom((uint) data.Length); + Windows.Security.Cryptography.CryptographicBuffer.CopyToByteArray(buffer, out data); +#endif + } + +#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP public static RandomNumberGenerator CreateRandomNumberGenerator() { #if FEATURE_RNG_CREATE @@ -11,9 +35,10 @@ namespace Renci.SshNet.Security.Cryptography #elif FEATURE_RNG_CSP return new RNGCryptoServiceProvider(); #else - #error Creation of RandomNumberGenerator is not implemented. +#error Creation of RandomNumberGenerator is not implemented. #endif } +#endif // FEATURE_RNG_CREATE || FEATURE_RNG_CSP #if FEATURE_HASH_MD5 public static System.Security.Cryptography.MD5 CreateMD5() @@ -21,9 +46,9 @@ namespace Renci.SshNet.Security.Cryptography return System.Security.Cryptography.MD5.Create(); } #else - public static Renci.Security.Cryptography.MD5 CreateMD5() + public static global::SshNet.Security.Cryptography.MD5 CreateMD5() { - return new Renci.Security.Cryptography.MD5(); + return new global::SshNet.Security.Cryptography.MD5(); } #endif // FEATURE_HASH_MD5 @@ -33,9 +58,9 @@ namespace Renci.SshNet.Security.Cryptography return new System.Security.Cryptography.SHA1Managed(); } #else - public static Renci.Security.Cryptography.SHA1 CreateSHA1() + public static global::SshNet.Security.Cryptography.SHA1 CreateSHA1() { - return new Renci.Security.Cryptography.SHA1(); + return new global::SshNet.Security.Cryptography.SHA1(); } #endif @@ -45,9 +70,9 @@ namespace Renci.SshNet.Security.Cryptography return new System.Security.Cryptography.SHA256Managed(); } #else - public static Renci.Security.Cryptography.SHA256 CreateSHA256() + public static global::SshNet.Security.Cryptography.SHA256 CreateSHA256() { - return new Renci.Security.Cryptography.SHA256(); + return new global::SshNet.Security.Cryptography.SHA256(); } #endif @@ -57,9 +82,9 @@ namespace Renci.SshNet.Security.Cryptography return new System.Security.Cryptography.SHA384Managed(); } #else - public static Renci.Security.Cryptography.SHA384 CreateSHA384() + public static global::SshNet.Security.Cryptography.SHA384 CreateSHA384() { - return new Renci.Security.Cryptography.SHA384(); + return new global::SshNet.Security.Cryptography.SHA384(); } #endif @@ -69,9 +94,9 @@ namespace Renci.SshNet.Security.Cryptography return new System.Security.Cryptography.SHA512Managed(); } #else - public static Renci.Security.Cryptography.SHA512 CreateSHA512() + public static global::SshNet.Security.Cryptography.SHA512 CreateSHA512() { - return new Renci.Security.Cryptography.SHA512(); + return new global::SshNet.Security.Cryptography.SHA512(); } #endif @@ -81,9 +106,9 @@ namespace Renci.SshNet.Security.Cryptography return new System.Security.Cryptography.RIPEMD160Managed(); } #else - public static Renci.Security.Cryptography.RIPEMD160 CreateRIPEMD160() + public static global::SshNet.Security.Cryptography.RIPEMD160 CreateRIPEMD160() { - return new Renci.Security.Cryptography.RIPEMD160(); + return new global::SshNet.Security.Cryptography.RIPEMD160(); } #endif // FEATURE_HASH_RIPEMD160 @@ -98,14 +123,14 @@ namespace Renci.SshNet.Security.Cryptography return new HMACMD5(key, hashSize); } #else - public static Renci.Security.Cryptography.HMACMD5 CreateHMACMD5(byte[] key) + public static global::SshNet.Security.Cryptography.HMACMD5 CreateHMACMD5(byte[] key) { - return new Renci.Security.Cryptography.HMACMD5(key); + return new global::SshNet.Security.Cryptography.HMACMD5(key); } - public static Renci.Security.Cryptography.HMACMD5 CreateHMACMD5(byte[] key, int hashSize) + public static global::SshNet.Security.Cryptography.HMACMD5 CreateHMACMD5(byte[] key, int hashSize) { - return new Renci.Security.Cryptography.HMACMD5(key, hashSize); + return new global::SshNet.Security.Cryptography.HMACMD5(key, hashSize); } #endif // FEATURE_HMAC_MD5 @@ -120,14 +145,14 @@ namespace Renci.SshNet.Security.Cryptography return new HMACSHA1(key, hashSize); } #else - public static Renci.Security.Cryptography.HMACSHA1 CreateHMACSHA1(byte[] key) + public static global::SshNet.Security.Cryptography.HMACSHA1 CreateHMACSHA1(byte[] key) { - return new Renci.Security.Cryptography.HMACSHA1(key); + return new global::SshNet.Security.Cryptography.HMACSHA1(key); } - public static Renci.Security.Cryptography.HMACSHA1 CreateHMACSHA1(byte[] key, int hashSize) + public static global::SshNet.Security.Cryptography.HMACSHA1 CreateHMACSHA1(byte[] key, int hashSize) { - return new Renci.Security.Cryptography.HMACSHA1(key, hashSize); + return new global::SshNet.Security.Cryptography.HMACSHA1(key, hashSize); } #endif // FEATURE_HMAC_SHA1 @@ -142,14 +167,14 @@ namespace Renci.SshNet.Security.Cryptography return new HMACSHA256(key, hashSize); } #else - public static Renci.Security.Cryptography.HMACSHA256 CreateHMACSHA256(byte[] key) + public static global::SshNet.Security.Cryptography.HMACSHA256 CreateHMACSHA256(byte[] key) { - return new Renci.Security.Cryptography.HMACSHA256(key); + return new global::SshNet.Security.Cryptography.HMACSHA256(key); } - public static Renci.Security.Cryptography.HMACSHA256 CreateHMACSHA256(byte[] key, int hashSize) + public static global::SshNet.Security.Cryptography.HMACSHA256 CreateHMACSHA256(byte[] key, int hashSize) { - return new Renci.Security.Cryptography.HMACSHA256(key, hashSize); + return new global::SshNet.Security.Cryptography.HMACSHA256(key, hashSize); } #endif // FEATURE_HMAC_SHA256 @@ -164,14 +189,14 @@ namespace Renci.SshNet.Security.Cryptography return new HMACSHA384(key, hashSize); } #else - public static Renci.Security.Cryptography.HMACSHA384 CreateHMACSHA384(byte[] key) + public static global::SshNet.Security.Cryptography.HMACSHA384 CreateHMACSHA384(byte[] key) { - return new Renci.Security.Cryptography.HMACSHA384(key); + return new global::SshNet.Security.Cryptography.HMACSHA384(key); } - public static Renci.Security.Cryptography.HMACSHA384 CreateHMACSHA384(byte[] key, int hashSize) + public static global::SshNet.Security.Cryptography.HMACSHA384 CreateHMACSHA384(byte[] key, int hashSize) { - return new Renci.Security.Cryptography.HMACSHA384(key, hashSize); + return new global::SshNet.Security.Cryptography.HMACSHA384(key, hashSize); } #endif // FEATURE_HMAC_SHA384 @@ -186,14 +211,14 @@ namespace Renci.SshNet.Security.Cryptography return new HMACSHA512(key, hashSize); } #else - public static Renci.Security.Cryptography.HMACSHA512 CreateHMACSHA512(byte[] key) + public static global::SshNet.Security.Cryptography.HMACSHA512 CreateHMACSHA512(byte[] key) { - return new Renci.Security.Cryptography.HMACSHA512(key); + return new global::SshNet.Security.Cryptography.HMACSHA512(key); } - public static Renci.Security.Cryptography.HMACSHA512 CreateHMACSHA512(byte[] key, int hashSize) + public static global::SshNet.Security.Cryptography.HMACSHA512 CreateHMACSHA512(byte[] key, int hashSize) { - return new Renci.Security.Cryptography.HMACSHA512(key, hashSize); + return new global::SshNet.Security.Cryptography.HMACSHA512(key, hashSize); } #endif // FEATURE_HMAC_SHA512 @@ -203,9 +228,9 @@ namespace Renci.SshNet.Security.Cryptography return new System.Security.Cryptography.HMACRIPEMD160(key); } #else - public static Renci.Security.Cryptography.HMACRIPEMD160 CreateHMACRIPEMD160(byte[] key) + public static global::SshNet.Security.Cryptography.HMACRIPEMD160 CreateHMACRIPEMD160(byte[] key) { - return new Renci.Security.Cryptography.HMACRIPEMD160(key); + return new global::SshNet.Security.Cryptography.HMACRIPEMD160(key); } #endif // FEATURE_HMAC_RIPEMD160 }