| 
					
				 | 
			
			
				@@ -21,31 +21,34 @@ namespace Jellyfin.Common.Tests.Cryptography 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public static IEnumerable<object[]> Parse_Valid_TestData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             yield return new object[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 "$PBKDF2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 new PasswordHash("PBKDF2", Array.Empty<byte>()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Id + parameter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             yield return new object[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                "$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "$PBKDF2$iterations=1000", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 new PasswordHash( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     "PBKDF2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Array.Empty<byte>(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     Array.Empty<byte>(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     new Dictionary<string, string>() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { "iterations", "1000" } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { "iterations", "1000" }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Id + parameters 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             yield return new object[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                "$PBKDF2$iterations=1000,m=120$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "$PBKDF2$iterations=1000,m=120", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 new PasswordHash( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     "PBKDF2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Array.Empty<byte>(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     Array.Empty<byte>(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     new Dictionary<string, string>() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -54,13 +57,50 @@ namespace Jellyfin.Common.Tests.Cryptography 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Id + hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             yield return new object[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                "$PBKDF2$iterations=1000,m=120$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "$PBKDF2$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                new PasswordHash( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "PBKDF2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Array.Empty<byte>(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    new Dictionary<string, string>()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Id + salt + hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            yield return new object[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "$PBKDF2$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 new PasswordHash( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     "PBKDF2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     Convert.FromHexString("69F420"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    new Dictionary<string, string>()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Id + parameter + hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            yield return new object[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                new PasswordHash( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "PBKDF2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Array.Empty<byte>(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    new Dictionary<string, string>() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { "iterations", "1000" } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Id + parameters + hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            yield return new object[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "$PBKDF2$iterations=1000,m=120$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                new PasswordHash( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "PBKDF2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Array.Empty<byte>(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     new Dictionary<string, string>() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         { "iterations", "1000" }, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -68,13 +108,14 @@ namespace Jellyfin.Common.Tests.Cryptography 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Id + parameters + salt + hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             yield return new object[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                "$PBKDF2$iterations=1000,m=120", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "$PBKDF2$iterations=1000,m=120$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 new PasswordHash( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     "PBKDF2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    Array.Empty<byte>(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    Array.Empty<byte>(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Convert.FromHexString("69F420"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     new Dictionary<string, string>() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         { "iterations", "1000" }, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -101,6 +142,7 @@ namespace Jellyfin.Common.Tests.Cryptography 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$iterations=1000,m=120$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [InlineData("$PBKDF2$iterations=1000,m=120$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$iterations=1000,m=120")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public static void ToString_Roundtrip_Success(string passwordHash) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -125,11 +167,15 @@ namespace Jellyfin.Common.Tests.Cryptography 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("PBKDF2$")] // Doesn't start with $ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Empty segment 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$iterations=1000$$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Empty salt segment 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [InlineData("$PBKDF2$iterations=1000$69F420$")] // Empty hash segment 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$iterations=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid parmeter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$iterations=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$")] // Ends on $ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        [InlineData("$PBKDF2$iterations=$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$anotherone")] // Extra segment 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [InlineData("$PBKDF2$iterations=$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$")] // Extra segment 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [InlineData("$PBKDF2$iterations=$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D$anotherone")] // Extra segment 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [InlineData("$PBKDF2$iterations=$invalidstalt$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D")] // Invalid salt 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [InlineData("$PBKDF2$iterations=$69F420$invalid hash")] // Invalid hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [InlineData("$PBKDF2$69F420$")] // Empty hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public static void Parse_InvalidFormat_ThrowsFormatException(string passwordHash) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 |