aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhallacy <Dragoonmac@gmail.com>2019-01-31 00:24:53 -0800
committerPhallacy <Dragoonmac@gmail.com>2019-01-31 00:24:53 -0800
commit4519ce26e2250cb233836296d292ddb7b3cf6346 (patch)
tree6d3781ac47a3a76406750a90f4a76d87efeba007
parent49d9649b8eb7e9edc889c10a679e980486ee0018 (diff)
Upgrade crypto provider, retarget better framework
-rw-r--r--Emby.Server.Implementations/Cryptography/CryptographyProvider.cs171
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj2
-rw-r--r--Emby.Server.Implementations/Library/UserManager.cs31
-rw-r--r--MediaBrowser.Model/Cryptography/ICryptoProvider.cs8
-rw-r--r--MediaBrowser.Model/Cryptography/PasswordHash.cs93
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);
+ }
+ }
+
+}