diff options
| author | Phallacy <Dragoonmac@gmail.com> | 2019-01-31 00:24:53 -0800 |
|---|---|---|
| committer | Phallacy <Dragoonmac@gmail.com> | 2019-01-31 00:24:53 -0800 |
| commit | 4519ce26e2250cb233836296d292ddb7b3cf6346 (patch) | |
| tree | 6d3781ac47a3a76406750a90f4a76d87efeba007 | |
| parent | 49d9649b8eb7e9edc889c10a679e980486ee0018 (diff) | |
Upgrade crypto provider, retarget better framework
5 files changed, 248 insertions, 57 deletions
diff --git a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs index 09fdbc856..ca6ae2bb2 100644 --- a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs +++ b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs @@ -1,40 +1,131 @@ -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; -using MediaBrowser.Model.Cryptography; - -namespace Emby.Server.Implementations.Cryptography -{ - public class CryptographyProvider : ICryptoProvider - { - public Guid GetMD5(string str) - { - return new Guid(ComputeMD5(Encoding.Unicode.GetBytes(str))); - } - - public byte[] ComputeSHA1(byte[] bytes) - { - using (var provider = SHA1.Create()) - { - return provider.ComputeHash(bytes); - } - } - - public byte[] ComputeMD5(Stream str) - { - using (var provider = MD5.Create()) - { - return provider.ComputeHash(str); - } - } - - public byte[] ComputeMD5(byte[] bytes) - { - using (var provider = MD5.Create()) - { - return provider.ComputeHash(bytes); - } - } - } -} +using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+using MediaBrowser.Model.Cryptography;
+
+namespace Emby.Server.Implementations.Cryptography
+{
+ public class CryptographyProvider : ICryptoProvider
+ {
+ private List<string> SupportedHashMethods = new List<string>();
+ private string DefaultHashMethod = "SHA256";
+ private RandomNumberGenerator rng;
+ private int defaultiterations = 1000;
+ public CryptographyProvider()
+ {
+ //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
+ SupportedHashMethods = new List<string>
+ {
+ "MD5"
+ ,"System.Security.Cryptography.MD5"
+ ,"SHA"
+ ,"SHA1"
+ ,"System.Security.Cryptography.SHA1"
+ ,"SHA256"
+ ,"SHA-256"
+ ,"System.Security.Cryptography.SHA256"
+ ,"SHA384"
+ ,"SHA-384"
+ ,"System.Security.Cryptography.SHA384"
+ ,"SHA512"
+ ,"SHA-512"
+ ,"System.Security.Cryptography.SHA512"
+ };
+ rng = RandomNumberGenerator.Create();
+ }
+
+ public Guid GetMD5(string str)
+ {
+ return new Guid(ComputeMD5(Encoding.Unicode.GetBytes(str)));
+ }
+
+ public byte[] ComputeSHA1(byte[] bytes)
+ {
+ using (var provider = SHA1.Create())
+ {
+ return provider.ComputeHash(bytes);
+ }
+ }
+
+ public byte[] ComputeMD5(Stream str)
+ {
+ using (var provider = MD5.Create())
+ {
+ return provider.ComputeHash(str);
+ }
+ }
+
+ public byte[] ComputeMD5(byte[] bytes)
+ {
+ using (var provider = MD5.Create())
+ {
+ return provider.ComputeHash(bytes);
+ }
+ }
+
+ public IEnumerable<string> GetSupportedHashMethods()
+ {
+ return SupportedHashMethods;
+ }
+
+ private byte[] PBKDF2(string method, byte[] bytes, byte[] salt)
+ {
+ using (var r = new Rfc2898DeriveBytes(bytes, salt, defaultiterations, new HashAlgorithmName(method)))
+ {
+ return r.GetBytes(32);
+ }
+ }
+
+ public byte[] ComputeHash(string HashMethod, byte[] bytes)
+ {
+ return ComputeHash(HashMethod, bytes, new byte[0]);
+ }
+
+ public byte[] ComputeHashWithDefaultMethod(byte[] bytes)
+ {
+ return ComputeHash(DefaultHashMethod, bytes);
+ }
+
+ public byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt)
+ {
+ if (SupportedHashMethods.Contains(HashMethod))
+ {
+ if (salt.Length == 0)
+ {
+ using (var h = HashAlgorithm.Create(HashMethod))
+ {
+ return h.ComputeHash(bytes);
+ }
+ }
+ else
+ {
+ return PBKDF2(HashMethod, bytes, salt);
+ }
+ }
+ else
+ {
+ throw new CryptographicException(String.Format("Requested hash method is not supported: {0}", HashMethod));
+ }
+ }
+
+ public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt)
+ {
+ return PBKDF2(DefaultHashMethod, bytes, salt);
+ }
+
+ public byte[] ComputeHash(PasswordHash hash)
+ {
+ return ComputeHash(hash.Id, hash.HashBytes, hash.SaltBytes);
+ }
+
+ public byte[] GenerateSalt()
+ {
+ byte[] salt = new byte[8];
+ rng.GetBytes(salt);
+ return salt;
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 3aa617b02..df7963b02 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -35,7 +35,7 @@ </ItemGroup> <PropertyGroup> - <TargetFramework>netstandard2.0</TargetFramework> + <TargetFramework>netcoreapp2.1</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> </PropertyGroup> diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index 05fce4542..70639dad5 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Events; @@ -220,22 +221,20 @@ namespace Emby.Server.Implementations.Library } } - public bool IsValidUsername(string username) - { - // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.) - foreach (var currentChar in username) - { - if (!IsValidUsernameCharacter(currentChar)) - { - return false; - } - } - return true; - } - - private static bool IsValidUsernameCharacter(char i) - { - return !char.Equals(i, '<') && !char.Equals(i, '>'); + public bool IsValidUsername(string username)
+ {
+ //The old way was dumb, we should make it less dumb, lets do so.
+ //This is some regex that matches only on unicode "word" characters, as well as -, _ and @
+ //In theory this will cut out most if not all 'control' characters which should help minimize any weirdness
+ string UserNameRegex = "^[\\w-'._@]*$";
+ // Usernames can contain letters (a-z + whatever else unicode is cool with), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)
+ return Regex.IsMatch(username, UserNameRegex);
+ }
+
+ private static bool IsValidUsernameCharacter(char i)
+ {
+ string UserNameRegex = "^[\\w-'._@]*$";
+ return Regex.IsMatch(i.ToString(), UserNameRegex);
} public string MakeValidUsername(string username) diff --git a/MediaBrowser.Model/Cryptography/ICryptoProvider.cs b/MediaBrowser.Model/Cryptography/ICryptoProvider.cs index b027d2ad0..ec7e57fec 100644 --- a/MediaBrowser.Model/Cryptography/ICryptoProvider.cs +++ b/MediaBrowser.Model/Cryptography/ICryptoProvider.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Collections.Generic; namespace MediaBrowser.Model.Cryptography { @@ -9,5 +10,12 @@ namespace MediaBrowser.Model.Cryptography 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(); } } diff --git a/MediaBrowser.Model/Cryptography/PasswordHash.cs b/MediaBrowser.Model/Cryptography/PasswordHash.cs new file mode 100644 index 000000000..d37220ab2 --- /dev/null +++ b/MediaBrowser.Model/Cryptography/PasswordHash.cs @@ -0,0 +1,93 @@ +using System;
+using System.Collections.Generic;
+using System.Text;
+
+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>]]
+
+ public string Id;
+ public Dictionary<string, string> Parameters = new Dictionary<string, string>();
+ public string Salt;
+ public byte[] SaltBytes;
+ public string Hash;
+ public byte[] HashBytes;
+ public PasswordHash(string StorageString)
+ {
+ string[] a = StorageString.Split('$');
+ Id = a[1];
+ if (a[2].Contains("="))
+ {
+ foreach (string paramset in (a[2].Split(',')))
+ {
+ if (!String.IsNullOrEmpty(paramset))
+ {
+ string[] fields = paramset.Split('=');
+ Parameters.Add(fields[0], fields[1]);
+ }
+ }
+ if (a.Length == 4)
+ {
+ Salt = a[2];
+ SaltBytes = Convert.FromBase64CharArray(Salt.ToCharArray(), 0, Salt.Length);
+ Hash = a[3];
+ HashBytes = Convert.FromBase64CharArray(Hash.ToCharArray(), 0, Hash.Length);
+ }
+ else
+ {
+ Salt = string.Empty;
+ Hash = a[3];
+ HashBytes = Convert.FromBase64CharArray(Hash.ToCharArray(), 0, Hash.Length);
+ }
+ }
+ else
+ {
+ if (a.Length == 4)
+ {
+ Salt = a[2];
+ SaltBytes = Convert.FromBase64CharArray(Salt.ToCharArray(), 0, Salt.Length);
+ Hash = a[3];
+ HashBytes = Convert.FromBase64CharArray(Hash.ToCharArray(), 0, Hash.Length);
+ }
+ else
+ {
+ Salt = string.Empty;
+ Hash = a[2];
+ HashBytes = Convert.FromBase64CharArray(Hash.ToCharArray(), 0, Hash.Length);
+ }
+
+ }
+
+ } + + public PasswordHash(ICryptoProvider cryptoProvider2)
+ {
+ Id = "SHA256";
+ SaltBytes = cryptoProvider2.GenerateSalt();
+ Salt = Convert.ToBase64String(SaltBytes);
+ }
+ private string SerializeParameters()
+ {
+ string ReturnString = String.Empty;
+ foreach (var KVP in Parameters)
+ {
+ ReturnString += String.Format(",{0}={1}", KVP.Key, KVP.Value);
+ }
+ if (ReturnString[0] == ',')
+ {
+ ReturnString = ReturnString.Remove(0, 1);
+ }
+ return ReturnString;
+ }
+
+ public override string ToString()
+ {
+ return String.Format("${0}${1}${2}${3}", Id, SerializeParameters(), Salt, Hash);
+ }
+ }
+
+} |
