CryptographyProvider.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Security.Cryptography;
  5. using System.Text;
  6. using MediaBrowser.Model.Cryptography;
  7. namespace Emby.Server.Implementations.Cryptography
  8. {
  9. public class CryptographyProvider : ICryptoProvider
  10. {
  11. private HashSet<string> SupportedHashMethods;
  12. public string DefaultHashMethod => "SHA256";
  13. private RandomNumberGenerator rng;
  14. private int defaultiterations = 1000;
  15. public CryptographyProvider()
  16. {
  17. //Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1
  18. //there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one
  19. SupportedHashMethods = new HashSet<string>()
  20. {
  21. "MD5"
  22. ,"System.Security.Cryptography.MD5"
  23. ,"SHA"
  24. ,"SHA1"
  25. ,"System.Security.Cryptography.SHA1"
  26. ,"SHA256"
  27. ,"SHA-256"
  28. ,"System.Security.Cryptography.SHA256"
  29. ,"SHA384"
  30. ,"SHA-384"
  31. ,"System.Security.Cryptography.SHA384"
  32. ,"SHA512"
  33. ,"SHA-512"
  34. ,"System.Security.Cryptography.SHA512"
  35. };
  36. rng = RandomNumberGenerator.Create();
  37. }
  38. public Guid GetMD5(string str)
  39. {
  40. return new Guid(ComputeMD5(Encoding.Unicode.GetBytes(str)));
  41. }
  42. public byte[] ComputeSHA1(byte[] bytes)
  43. {
  44. using (var provider = SHA1.Create())
  45. {
  46. return provider.ComputeHash(bytes);
  47. }
  48. }
  49. public byte[] ComputeMD5(Stream str)
  50. {
  51. using (var provider = MD5.Create())
  52. {
  53. return provider.ComputeHash(str);
  54. }
  55. }
  56. public byte[] ComputeMD5(byte[] bytes)
  57. {
  58. using (var provider = MD5.Create())
  59. {
  60. return provider.ComputeHash(bytes);
  61. }
  62. }
  63. public IEnumerable<string> GetSupportedHashMethods()
  64. {
  65. return SupportedHashMethods;
  66. }
  67. private byte[] PBKDF2(string method, byte[] bytes, byte[] salt, int iterations)
  68. {
  69. using (var r = new Rfc2898DeriveBytes(bytes, salt, iterations, new HashAlgorithmName(method)))
  70. {
  71. return r.GetBytes(32);
  72. }
  73. }
  74. public byte[] ComputeHash(string HashMethod, byte[] bytes)
  75. {
  76. return ComputeHash(HashMethod, bytes, new byte[0]);
  77. }
  78. public byte[] ComputeHashWithDefaultMethod(byte[] bytes)
  79. {
  80. return ComputeHash(DefaultHashMethod, bytes);
  81. }
  82. public byte[] ComputeHash(string HashMethod, byte[] bytes, byte[] salt)
  83. {
  84. if (SupportedHashMethods.Contains(HashMethod))
  85. {
  86. if (salt.Length == 0)
  87. {
  88. using (var h = HashAlgorithm.Create(HashMethod))
  89. {
  90. return h.ComputeHash(bytes);
  91. }
  92. }
  93. else
  94. {
  95. return PBKDF2(HashMethod, bytes, salt,defaultiterations);
  96. }
  97. }
  98. else
  99. {
  100. throw new CryptographicException(String.Format("Requested hash method is not supported: {0}", HashMethod));
  101. }
  102. }
  103. public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt)
  104. {
  105. return PBKDF2(DefaultHashMethod, bytes, salt, defaultiterations);
  106. }
  107. public byte[] ComputeHash(PasswordHash hash)
  108. {
  109. int iterations = defaultiterations;
  110. if (!hash.Parameters.ContainsKey("iterations"))
  111. {
  112. hash.Parameters.Add("iterations", defaultiterations.ToString());
  113. }
  114. else
  115. {
  116. try { iterations = int.Parse(hash.Parameters["iterations"]); }
  117. catch (Exception e) { iterations = defaultiterations; throw new Exception($"Couldn't successfully parse iterations value from string:{hash.Parameters["iterations"]}", e); }
  118. }
  119. return PBKDF2(hash.Id, hash.HashBytes, hash.SaltBytes,iterations);
  120. }
  121. public byte[] GenerateSalt()
  122. {
  123. byte[] salt = new byte[64];
  124. rng.GetBytes(salt);
  125. return salt;
  126. }
  127. }
  128. }