False alarm - my PasswordHash data was incorrect from the start. All is good now.
This post has it correct:
“value”: “$pbkdf2-sha1$i=1000,l=32${salt}${hash}”
For anyone else in the future in a similar situation - here’s a quick C# script I wrote that you can run to produce the string you’ll need to put in hash.value in your user import JSON payload:
public static void Main(string[] args)
{
var passwordhash_string_fromdb = "YOUR_PASSWORDHASH_BASE64_STRING";
var passwordhash_bytes = Convert.FromBase64String(passwordhash_string_fromdb);
var salt_bytes = new List<byte>();
var pw_bytes = new List<byte>();
// Break down passwordhash_string_fromdb into bytes representing salt and pw
// The first byte represents the version of Identity being used (0 == v2.0; 1 == v3.0)
// This script will not work if your password was not hashed using v2
// For v2, bytes 1-17 represent the salt and bytes 18-49 represent the password
// reference: https://github.com/aspnet/AspNetIdentity/blob/main/src/Microsoft.AspNet.Identity.Core/Crypto.cs
if (passwordhash_bytes[0] != 0)
{
Console.WriteLine("This script will not work for you because your password was hashed using something other than Identity v2");
return;
}
for (var i = 0; i < passwordhash_bytes.Length; i++)
{
if (i > 0 && i < 17)
salt_bytes.Add(passwordhash_bytes[i]);
else if (i >= 17 && i <= 49)
pw_bytes.Add(passwordhash_bytes[i]);
}
// Convert to byte array
var salt_bytearray = salt_bytes.ToArray();
// Convert to byte array
var pw_bytearray = pw_bytes.ToArray();
// Convert both back to base64 and Remove base 64 padding aka '='
var salt_b64_nopadding = Convert.ToBase64String(salt_bytearray).Replace('=',' ').Trim(' ');
var pw_b64_nopadding = Convert.ToBase64String(pw_bytearray).Replace('=',' ').Trim(' ');
// PHC string format
var pbkdf2string = ($"$pbkdf2-sha1$i=1000,l=32${salt_b64_nopadding}${pw_b64_nopadding}");
// pbkdf2string: copy this to hash.value in your json payload
Console.WriteLine(pbkdf2string);
}