2
0
Phallacy 6 жил өмнө
parent
commit
2c26517172

+ 24 - 18
Emby.Server.Implementations/Cryptography/CryptographyProvider.cs

@@ -11,17 +11,21 @@ namespace Emby.Server.Implementations.Cryptography
 {
     public class CryptographyProvider : ICryptoProvider
     {
-        private HashSet<string> SupportedHashMethods;
+        private HashSet<string> _supportedHashMethods;
+
         public string DefaultHashMethod => "PBKDF2";
-        private RandomNumberGenerator rng;
-        private int defaultiterations = 1000;
+
+        private RandomNumberGenerator _randomNumberGenerator;
+
+        private int _defaultIterations = 1000;
+
         public CryptographyProvider()
         {
             //FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto
             //Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1
             //there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one
             //Please note the default method of PBKDF2 is not included, it cannot be used to generate hashes cleanly as it is actually a pbkdf with sha1
-            SupportedHashMethods = new HashSet<string>()
+            _supportedHashMethods = new HashSet<string>()
             {
                 "MD5"
                 ,"System.Security.Cryptography.MD5"
@@ -38,7 +42,7 @@ namespace Emby.Server.Implementations.Cryptography
                 ,"SHA-512"
                 ,"System.Security.Cryptography.SHA512"
             };
-            rng = RandomNumberGenerator.Create();
+            _randomNumberGenerator = RandomNumberGenerator.Create();
         }
 
         public Guid GetMD5(string str)
@@ -72,7 +76,7 @@ namespace Emby.Server.Implementations.Cryptography
 
         public IEnumerable<string> GetSupportedHashMethods()
         {
-            return SupportedHashMethods;
+            return _supportedHashMethods;
         }
 
         private byte[] PBKDF2(string method, byte[] bytes, byte[] salt, int iterations)
@@ -86,12 +90,13 @@ namespace Emby.Server.Implementations.Cryptography
                     return r.GetBytes(32);
                 }
             }
+
             throw new CryptographicException($"Cannot currently use PBKDF2 with requested hash method: {method}");
         }
 
-        public byte[] ComputeHash(string HashMethod, byte[] bytes)
+        public byte[] ComputeHash(string hashMethod, byte[] bytes)
         {
-            return ComputeHash(HashMethod, bytes, new byte[0]);
+            return ComputeHash(hashMethod, bytes, new byte[0]);
         }
 
         public byte[] ComputeHashWithDefaultMethod(byte[] bytes)
@@ -99,15 +104,15 @@ namespace Emby.Server.Implementations.Cryptography
             return ComputeHash(DefaultHashMethod, bytes);
         }
 
-        public byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt)
+        public byte[] ComputeHash(string hashMethod, byte[] bytes, byte[] salt)
         {
-            if(HashMethod == DefaultHashMethod)
+            if(hashMethod == DefaultHashMethod)
             {
-                return PBKDF2(HashMethod, bytes, salt, defaultiterations);
+                return PBKDF2(hashMethod, bytes, salt, _defaultIterations);
             }
-            else if (SupportedHashMethods.Contains(HashMethod))
+            else if (_supportedHashMethods.Contains(hashMethod))
             {
-                using (var h = HashAlgorithm.Create(HashMethod))
+                using (var h = HashAlgorithm.Create(hashMethod))
                 {
                     if (salt.Length == 0)
                     {
@@ -121,21 +126,21 @@ namespace Emby.Server.Implementations.Cryptography
             }
             else
             {
-                throw new CryptographicException($"Requested hash method is not supported: {HashMethod}");
+                throw new CryptographicException($"Requested hash method is not supported: {hashMethod}");
             }
         }
 
         public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt)
         {
-            return PBKDF2(DefaultHashMethod, bytes, salt, defaultiterations);
+            return PBKDF2(DefaultHashMethod, bytes, salt, _defaultIterations);
         }
         
         public byte[] ComputeHash(PasswordHash hash)
         {
-            int iterations = defaultiterations;
+            int iterations = _defaultIterations;
             if (!hash.Parameters.ContainsKey("iterations"))
             {
-                hash.Parameters.Add("iterations", defaultiterations.ToString(CultureInfo.InvariantCulture));
+                hash.Parameters.Add("iterations", _defaultIterations.ToString(CultureInfo.InvariantCulture));
             }
             else
             {
@@ -148,13 +153,14 @@ namespace Emby.Server.Implementations.Cryptography
                     throw new InvalidDataException($"Couldn't successfully parse iterations value from string: {hash.Parameters["iterations"]}", e);
                 }
             }
+
             return PBKDF2(hash.Id, hash.HashBytes, hash.SaltBytes, iterations);
         }
 
         public byte[] GenerateSalt()
         {
             byte[] salt = new byte[64];
-            rng.GetBytes(salt);
+            _randomNumberGenerator.GetBytes(salt);
             return salt;
         }
     }

+ 16 - 23
Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs

@@ -19,18 +19,16 @@ namespace Emby.Server.Implementations.Library
         public string Name => "Default";
 
         public bool IsEnabled => true;
-
-
-        //This is dumb and an artifact of the backwards way auth providers were designed.
-        //This version of authenticate was never meant to be called, but needs to be here for interface compat
-        //Only the providers that don't provide local user support use this
+        
+        // This is dumb and an artifact of the backwards way auth providers were designed.
+        // This version of authenticate was never meant to be called, but needs to be here for interface compat
+        // Only the providers that don't provide local user support use this
         public Task<ProviderAuthenticationResult> Authenticate(string username, string password)
         {
             throw new NotImplementedException();
         }
-
-
-        //This is the verson that we need to use for local users. Because reasons.
+        
+        // This is the verson that we need to use for local users. Because reasons.
         public Task<ProviderAuthenticationResult> Authenticate(string username, string password, User resolvedUser)
         {
             bool success = false;
@@ -39,7 +37,7 @@ namespace Emby.Server.Implementations.Library
                 throw new Exception("Invalid username or password");
             }
 
-            //As long as jellyfin supports passwordless users, we need this little block here to accomodate
+            // As long as jellyfin supports passwordless users, we need this little block here to accomodate
             if (IsPasswordEmpty(resolvedUser, password))
             {
                 return Task.FromResult(new ProviderAuthenticationResult
@@ -70,7 +68,7 @@ namespace Emby.Server.Implementations.Library
                 if (CalculatedHashString == readyHash.Hash)
                 {
                     success = true;
-                    //throw new Exception("Invalid username or password");
+                    // throw new Exception("Invalid username or password");
                 }
             }
             else
@@ -78,7 +76,7 @@ namespace Emby.Server.Implementations.Library
                 throw new Exception(String.Format($"Requested crypto method not available in provider: {readyHash.Id}"));
             }
 
-            //var success = string.Equals(GetPasswordHash(resolvedUser), GetHashedString(resolvedUser, password), StringComparison.OrdinalIgnoreCase);
+            // var success = string.Equals(GetPasswordHash(resolvedUser), GetHashedString(resolvedUser, password), StringComparison.OrdinalIgnoreCase);
 
             if (!success)
             {
@@ -91,8 +89,8 @@ namespace Emby.Server.Implementations.Library
             });
         }
 
-        //This allows us to move passwords forward to the newformat without breaking. They are still insecure, unsalted, and dumb before a password change
-        //but at least they are in the new format.
+        // This allows us to move passwords forward to the newformat without breaking. They are still insecure, unsalted, and dumb before a password change
+        // but at least they are in the new format.
         private void ConvertPasswordFormat(User user)
         {
             if (string.IsNullOrEmpty(user.Password))
@@ -121,18 +119,13 @@ namespace Emby.Server.Implementations.Library
 
         private bool IsPasswordEmpty(User user, string password)
         {
-            if (string.IsNullOrEmpty(user.Password))
-            {
-                return string.IsNullOrEmpty(password);
-            }
-
-            return false;
+            return (string.IsNullOrEmpty(user.Password) && string.IsNullOrEmpty(password));
         }
 
         public Task ChangePassword(User user, string newPassword)
         {
             ConvertPasswordFormat(user);
-            //This is needed to support changing a no password user to a password user
+            // This is needed to support changing a no password user to a password user
             if (string.IsNullOrEmpty(user.Password))
             {
                 PasswordHash newPasswordHash = new PasswordHash(_cryptographyProvider);
@@ -184,7 +177,7 @@ namespace Emby.Server.Implementations.Library
         public string GetHashedString(User user, string str)
         {
             PasswordHash passwordHash;
-            if (String.IsNullOrEmpty(user.Password))
+            if (string.IsNullOrEmpty(user.Password))
             {
                 passwordHash = new PasswordHash(_cryptographyProvider);
             }
@@ -196,13 +189,13 @@ namespace Emby.Server.Implementations.Library
 
             if (passwordHash.SaltBytes != null)
             {
-                //the password is modern format with PBKDF and we should take advantage of that
+                // the password is modern format with PBKDF and we should take advantage of that
                 passwordHash.HashBytes = Encoding.UTF8.GetBytes(str);
                 return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash));
             }
             else
             {
-                //the password has no salt and should be called with the older method for safety
+                // the password has no salt and should be called with the older method for safety
                 return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash.Id, Encoding.UTF8.GetBytes(str)));
             }
         }

+ 1 - 1
Emby.Server.Implementations/Library/UserManager.cs

@@ -75,7 +75,7 @@ namespace Emby.Server.Implementations.Library
         private readonly Func<IDtoService> _dtoServiceFactory;
         private readonly IServerApplicationHost _appHost;
         private readonly IFileSystem _fileSystem;
-        
+
         private IAuthenticationProvider[] _authenticationProviders;
         private DefaultAuthenticationProvider _defaultAuthenticationProvider;
 

+ 21 - 21
MediaBrowser.Model/Cryptography/ICryptoProvider.cs

@@ -1,22 +1,22 @@
-using System;
-using System.IO;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Model.Cryptography
-{
-    public interface ICryptoProvider
-    {
-        Guid GetMD5(string str);
-        byte[] ComputeMD5(Stream str);
-        byte[] ComputeMD5(byte[] bytes);
-        byte[] ComputeSHA1(byte[] bytes);
-        IEnumerable<string> GetSupportedHashMethods();
-        byte[] ComputeHash(string HashMethod, byte[] bytes);
-        byte[] ComputeHashWithDefaultMethod(byte[] bytes);
-        byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt);
-        byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt);
-        byte[] ComputeHash(PasswordHash hash);
+using System;
+using System.IO;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.Cryptography
+{
+    public interface ICryptoProvider
+    {
+        Guid GetMD5(string str);
+        byte[] ComputeMD5(Stream str);
+        byte[] ComputeMD5(byte[] bytes);
+        byte[] ComputeSHA1(byte[] bytes);
+        IEnumerable<string> GetSupportedHashMethods();
+        byte[] ComputeHash(string HashMethod, byte[] bytes);
+        byte[] ComputeHashWithDefaultMethod(byte[] bytes);
+        byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt);
+        byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt);
+        byte[] ComputeHash(PasswordHash hash);
         byte[] GenerateSalt();
-        string DefaultHashMethod { get; }
-    }
-}
+        string DefaultHashMethod { get; }
+    }
+}

+ 53 - 39
MediaBrowser.Model/Cryptography/PasswordHash.cs

@@ -6,27 +6,40 @@ namespace MediaBrowser.Model.Cryptography
 {
     public class PasswordHash
     {
-        //Defined from this hash storage spec
-        //https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md
-        //$<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]
+        // Defined from this hash storage spec
+        // https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md
+        // $<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]
+        // with one slight amendment to ease the transition, we're writing out the bytes in hex
+        // rather than making them a BASE64 string with stripped padding
 
-        private string id;
-        private Dictionary<string, string> parameters = new Dictionary<string, string>();
-        private string salt;
-        private byte[] saltBytes;
-        private string hash;
-        private byte[] hashBytes;
-        public string Id { get => id; set => id = value; }
-        public Dictionary<string, string> Parameters { get => parameters; set => parameters = value; }
-        public string Salt { get => salt; set => salt = value; }
-        public byte[] SaltBytes { get => saltBytes; set => saltBytes = value; }
-        public string Hash { get => hash; set => hash = value; }
-        public byte[] HashBytes { get => hashBytes; set => hashBytes = value; }
+        private string _id;
+
+        private Dictionary<string, string> _parameters = new Dictionary<string, string>();
+
+        private string _salt;
+
+        private byte[] _saltBytes;
+
+        private string _hash;
+
+        private byte[] _hashBytes;
+
+        public string Id { get => _id; set => _id = value; }
+
+        public Dictionary<string, string> Parameters { get => _parameters; set => _parameters = value; }
+
+        public string Salt { get => _salt; set => _salt = value; }
+
+        public byte[] SaltBytes { get => _saltBytes; set => _saltBytes = value; }
+
+        public string Hash { get => _hash; set => _hash = value; }
+
+        public byte[] HashBytes { get => _hashBytes; set => _hashBytes = value; }
 
         public PasswordHash(string storageString)
         {
             string[] splitted = storageString.Split('$');
-            id = splitted[1];
+            _id = splitted[1];
             if (splitted[2].Contains("="))
             {
                 foreach (string paramset in (splitted[2].Split(',')))
@@ -36,7 +49,7 @@ namespace MediaBrowser.Model.Cryptography
                         string[] fields = paramset.Split('=');
                         if (fields.Length == 2)
                         {
-                            parameters.Add(fields[0], fields[1]);
+                            _parameters.Add(fields[0], fields[1]);
                         }
                         else
                         {
@@ -46,32 +59,32 @@ namespace MediaBrowser.Model.Cryptography
                 }
                 if (splitted.Length == 5)
                 {
-                    salt = splitted[3];
-                    saltBytes = ConvertFromByteString(salt);
-                    hash = splitted[4];
-                    hashBytes = ConvertFromByteString(hash);
+                    _salt = splitted[3];
+                    _saltBytes = ConvertFromByteString(_salt);
+                    _hash = splitted[4];
+                    _hashBytes = ConvertFromByteString(_hash);
                 }
                 else
                 {
-                    salt = string.Empty;
-                    hash = splitted[3];
-                    hashBytes = ConvertFromByteString(hash);
+                    _salt = string.Empty;
+                    _hash = splitted[3];
+                    _hashBytes = ConvertFromByteString(_hash);
                 }
             }
             else
             {
                 if (splitted.Length == 4)
                 {
-                    salt = splitted[2];
-                    saltBytes = ConvertFromByteString(salt);
-                    hash = splitted[3];
-                    hashBytes = ConvertFromByteString(hash);
+                    _salt = splitted[2];
+                    _saltBytes = ConvertFromByteString(_salt);
+                    _hash = splitted[3];
+                    _hashBytes = ConvertFromByteString(_hash);
                 }
                 else
                 {
-                    salt = string.Empty;
-                    hash = splitted[2];
-                    hashBytes = ConvertFromByteString(hash);
+                    _salt = string.Empty;
+                    _hash = splitted[2];
+                    _hashBytes = ConvertFromByteString(_hash);
                 }
 
             }
@@ -80,9 +93,9 @@ namespace MediaBrowser.Model.Cryptography
 
         public PasswordHash(ICryptoProvider cryptoProvider)
         {
-            id = cryptoProvider.DefaultHashMethod;
-            saltBytes = cryptoProvider.GenerateSalt();
-            salt = ConvertToByteString(SaltBytes);
+            _id = cryptoProvider.DefaultHashMethod;
+            _saltBytes = cryptoProvider.GenerateSalt();
+            _salt = ConvertToByteString(SaltBytes);
         }
 
         public static byte[] ConvertFromByteString(string byteString)
@@ -92,6 +105,7 @@ namespace MediaBrowser.Model.Cryptography
             {
                 Bytes.Add(Convert.ToByte(byteString.Substring(i, 2),16));
             }
+
             return Bytes.ToArray();
         }
 
@@ -103,7 +117,7 @@ namespace MediaBrowser.Model.Cryptography
         private string SerializeParameters()
         {
             string ReturnString = string.Empty;
-            foreach (var KVP in parameters)
+            foreach (var KVP in _parameters)
             {
                 ReturnString += $",{KVP.Key}={KVP.Value}";
             }
@@ -118,19 +132,19 @@ namespace MediaBrowser.Model.Cryptography
 
         public override string ToString()
         {
-            string outString = "$" +id;
+            string outString = "$" +_id;
             string paramstring = SerializeParameters();
             if (!string.IsNullOrEmpty(paramstring))
             {
                 outString += $"${paramstring}";
             }
 
-            if (!string.IsNullOrEmpty(salt))
+            if (!string.IsNullOrEmpty(_salt))
             {
-                outString += $"${salt}";
+                outString += $"${_salt}";
             }
 
-            outString += $"${hash}";
+            outString += $"${_hash}";
             return outString;
         }
     }