MODIFICA: Per discussione nei commenti, vorrei chiarire che ciò accadrà lato server, dietro SSL. Non ho intenzione di esporre la password hash o lo schema di hashing al client.JavaScript: Come generare Rfc2898DeriveBytes come C#?
Supponiamo di disporre di un database di identità asp.net esistente con le tabelle predefinite (aspnet_Users, aspnet_Roles, ecc.). In base alla mia comprensione, l'algoritmo di hashing della password utilizza sha256 e memorizza il salt + (hashed password) come una stringa codificata in base64. MODIFICA: questa ipotesi non è corretta, vedere la risposta di seguito.
vorrei replicare la funzione della classe Microsoft.AspNet.Identity.Crypto VerifyHashedPassword funzione con una versione di JavaScript.
Diciamo che una password è welcome1 e la sua asp.net hash password è ADOEtXqGCnWCuuc5UOAVIvMVJWjANOA/LoVy0E4XCyUHIfJ7dfSY0Id + uJ20DTtG + A ==
Finora sono stato in grado di riprodurre le parti del metodo che ottenere il sale e la chiave secondaria memorizzata.
Qualora l'attuazione C# fa più o meno questo:
var salt = new byte[SaltSize];
Buffer.BlockCopy(hashedPasswordBytes, 1, salt, 0, SaltSize);
var storedSubkey = new byte[PBKDF2SubkeyLength];
Buffer.BlockCopy(hashedPasswordBytes, 1 + SaltSize, storedSubkey, 0, PBKDF2SubkeyLength);
Ho il seguente in JavaScript (non elegante, con uno sforzo):
var hashedPwd = "ADOEtXqGCnWCuuc5UOAVIvMVJWjANOA/LoVy0E4XCyUHIfJ7dfSY0Id+uJ20DTtG+A==";
var hashedPasswordBytes = new Buffer(hashedPwd, 'base64');
var saltbytes = [];
var storedSubKeyBytes = [];
for(var i=1;i<hashedPasswordBytes.length;i++)
{
if(i > 0 && i <= 16)
{
saltbytes.push(hashedPasswordBytes[i]);
}
if(i > 0 && i >16) {
storedSubKeyBytes.push(hashedPasswordBytes[i]);
}
}
Anche in questo caso, non è abbastanza, ma dopo aver eseguito questo snippet, saltbytes e storedSubKeyBytes corrispondono a byte per byte ciò che vedo nel debugger C# per salt e storedSubkey.
Infine, in C#, un'istanza di Rfc2898DeriveBytes viene utilizzato per generare una nuova sottochiave basato sul sale e la password fornita, in questo modo:
byte[] generatedSubkey;
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt, PBKDF2IterCount))
{
generatedSubkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
Questo è dove mi sono bloccato. Ho provato soluzioni di altri come this one, ho usato rispettivamente CryptoJS di Google e Node e le librerie di crittografia, e il mio output non genera mai nulla che assomigli alla versione di C#.
(Esempio:
var output = crypto.pbkdf2Sync(new Buffer('welcome1', 'utf16le'),
new Buffer(parsedSaltString), 1000, 32, 'sha256');
console.log(output.toString('base64'))
genera "LSJvaDM9u7pXRfIS7QDFnmBPvsaN2z7FMXURGHIuqdY =")
Molti degli indicatori che ho trovato on-line indicano problemi che coinvolgono l'inadeguatezza codificanti (NodeJS/UTF-8 vs .NET/UTF -16LE), quindi ho provato a codificare utilizzando il formato di codifica .NET predefinito, ma senza alcun risultato.
Oppure potrei sbagliarmi completamente su cosa presumo queste librerie stiano facendo. Ma ogni suggerimento nella giusta direzione sarebbe molto apprezzato.
Si sta tentando di generare un hash della password sul client e passare l'hash al server per la convalida? – trailmax
No, sto provando a generare il lato server hash in node.js. Essenzialmente, mantenendo lo stesso database, ma sostituendo il livello IIS/asp.net per il nodo. Non sono un esperto di sicurezza, ma sarei cauto nel tentare di fare qualsiasi operazione client con le password. – GojiraDeMonstah
Ah, che chiarisce le mie preoccupazioni. Lo menzionerei nella tua domanda. Spiacenti, non posso davvero aiutare con il lato JS delle cose qui ( – trailmax