编辑:根据评论中的讨论,让我澄清一下这将发生在服务器端,在 SSL 后面。我不打算向客户端公开散列密码或散列方案。
假设我们有一个现有的 asp.net 身份数据库,其中包含默认表(aspnet_Users、aspnet_Roles 等)。根据我的理解,密码哈希算法使用 sha256 并将 salt +(哈希密码)存储为 base64 编码字符串。编辑:这个假设是不正确的,请参阅下面的答案。
我想用 JavaScript 版本复制 Microsoft.AspNet.Identity.Crypto 类的VerifyHashedPassword函数。
假设一个密码是welcome1,它的asp.net哈希密码是 ADOEtXqGCnWCuuc5UOAVIvMVJWjANOA/LoVy0E4XCyUHIfJ7dfSY0Id+uJ20DTtG+A==
到目前为止,我已经能够重现获取盐和存储的子密钥的方法部分。
C# 实现或多或少地这样做:
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);
我在 JavaScript 中有以下内容(无论如何都不优雅):
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]);
}
}
同样,它并不漂亮,但在运行此代码段后,saltbytes 和 storedSubKeyBytes 逐字节匹配我在 C# 调试器中看到的 salt 和 storedSubkey。
最后,在 C# 中,Rfc2898DeriveBytes 的一个实例用于根据所提供的盐和密码生成一个新的子密钥,如下所示:
byte[] generatedSubkey;
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt, PBKDF2IterCount))
{
generatedSubkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
这就是我卡住的地方。我已经尝试过其他的解决方案,例如这个,我分别使用了 Google 和 Node 的 CryptoJS 和加密库,我的输出从来没有生成任何类似于 C# 版本的东西。
(例子:
var output = crypto.pbkdf2Sync(new Buffer('welcome1', 'utf16le'),
new Buffer(parsedSaltString), 1000, 32, 'sha256');
console.log(output.toString('base64'))
生成“LSJvaDM9u7pXRfIS7QDFnmBPvsaN2z7FMXURGHIuqdY=")
我在网上找到的许多指针都表明存在编码不匹配的问题(NodeJS / UTF-8 与 .NET / UTF-16LE),因此我尝试使用默认的 .NET 编码格式进行编码,但无济于事。
或者我可能完全错误地认为这些库正在做什么。但是,任何指向正确方向的指针都将不胜感激。