6

First of all I read this Hashing a password using SHA256 and .NET/Node.js and it didn't help me.

I have to verify passwords hashes created in ASP.NET in node.js environment. I was told that passwords are generated using this algorithm: What is default hash algorithm that ASP.NET membership uses?.

I have example password hash and salt (first line is password and second line is salt):

"Password": "jj/rf7OxXM263rPgvLan4M6Is7o=",
"PasswordSalt": "/Eju9rmaJp03e3+z1v5s+A==",

I know that hash algorithm is SHA1 and I know that above hash is generated for input test123. However I can't reproduce hashing algorithm to get same hash for this input. What I tried:

Password = "jj/rf7OxXM263rPgvLan4M6Is7o="
PasswordSalt = "/Eju9rmaJp03e3+z1v5s+A=="
crypto = require("crypto")
sha1 = crypto.createHash("sha1")
PasswordSalt = new Buffer(PasswordSalt, 'base64').toString('utf8')
sha1.update(PasswordSalt+"test123", "utf8")
result = sha1.digest("base64")
console.log(Password)
console.log(result)

Result is:

jj/rf7OxXM263rPgvLan4M6Is7o=
xIjxRod4+HVYzlHZ9xomGGGY6d8=

I was able to get working C# algorithm:

using System.IO;
using System;
using System.Text;
using System.Security.Cryptography;

class Program
{

    static string EncodePassword(string pass, string salt)
    {
        byte[] bytes = Encoding.Unicode.GetBytes(pass);
        byte[] src = Convert.FromBase64String(salt);
        byte[] dst = new byte[src.Length + bytes.Length];
        Buffer.BlockCopy(src, 0, dst, 0, src.Length);
        Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
        HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
        byte[] inArray = algorithm.ComputeHash(dst);
        return Convert.ToBase64String(inArray);
    }

    static void Main()
    {
        string pass = "test123";
        string salt = "/Eju9rmaJp03e3+z1v5s+A==";
        string hash = Program.EncodePassword(pass,salt);
        Console.WriteLine(hash);
        // outputs jj/rf7OxXM263rPgvLan4M6Is7o=
    }
}

So now it is just a matter of porting this algorithm to node.js. The problem is that c# somehow magically operates on bytes and I don't know how to do it in node. Consider following code (it does not use any salt - it just creates base64 sha1 from password:

crypto = require("crypto")
pass = 'test123'
sha1 = crypto.createHash("sha1")
buf = new Buffer( pass, 'utf8')
sha1.update(buf)
result = sha1.digest("base64")
console.log(result)
// outputs cojt0Pw//L6ToM8G41aOKFIWh7w=

And in c#

 using System.Text;
 using System.Security.Cryptography;
 string pass = "test123";
 byte[] bytes = Encoding.Unicode.GetBytes(pass);
 HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
 byte[] inArray = algorithm.ComputeHash(bytes);
 string hash = Convert.ToBase64String(inArray);
 Console.WriteLine(hash);
 // outputs Oc/baVMs/zM28IqDqsQlJPQc1uk=

I need code in node.js that will return same value as code in c#. Any ideas?

Community
  • 1
  • 1
user606521
  • 14,486
  • 30
  • 113
  • 204
  • Are you sure this is how salts are being used in the .NET platform, it seems like a naïve way. Are you sure it's not an HMAC? Also, are you sure the bytes you're adding with +"test123" are what you want and not UTF-16 or whatever v8 is using under the hood? – Jim Keener Sep 09 '14 at 14:52
  • I really don't know - current DB (we are migrating from this DB actually) maintainer sent me just this link http://stackoverflow.com/questions/1137368/what-is-default-hash-algorithm-that-asp-net-membership-uses?answertab=active#tab-top - any ideas? – user606521 Sep 09 '14 at 15:04
  • I have updated the question - I have provided working c# code that I need to port to node.js. – user606521 Sep 21 '14 at 13:07

3 Answers3

9

I finally found the right answer here: https://gist.github.com/PalmerEk/1191651 (with little change from 'ucs2' to 'utf16le'):

function dotnet_membership_password_hash(pass, salt)
{
  var bytes = new Buffer(pass || '', 'utf16le');
  var src = new Buffer(salt || '', 'base64');
  var dst = new Buffer(src.length + bytes.length);
  src.copy(dst, 0, 0, src.length);
  bytes.copy(dst, src.length, 0, bytes.length);

  return crypto.createHash('sha1').update(dst).digest('base64');
}
user606521
  • 14,486
  • 30
  • 113
  • 204
  • 1
    Note that your code uses 'ucs2', and not 'utf16le' (or 'utf-16' or 'utf-16le' or 'utf16', I don't know which is correct). The former doesn't support supplementary code points, while the latter does. – Peter O. Sep 21 '14 at 22:03
  • Thank god, you save me! – yangsibai Oct 10 '14 at 12:34
5

there is a nodejs module which does all the magic for you. No function on stackoverflow worked in my case, but this module works:

https://www.npmjs.com/package/aspnet-identity-pw

  var passwordHasher = require('aspnet-identity-pw');

  var hashedPassword = passwordHasher.hashPassword('SomePassword');

  var isValid = passwordHasher.validatePassword('SomePassword', hashedPassword);
EscapeNetscape
  • 2,892
  • 1
  • 33
  • 32
  • It is returning False, I am generating some password in c# and validation that encrypted password using your code but it returns false, c3 generated password for "123456" => "JWvppSSfnzOQ+uMd+BORpT/8aQorC8y05Bjbo/8w/9b/eiG4WLzUFRQSSiKZqo3C" – Juned Ansari Sep 21 '18 at 13:02
1

Changing the encoding of the buffer to utf16le works for both examples you provided here.

This is confirmed by the following StackOverflow Answer.

This is further documented at the relevant .Net Framework documentation

Community
  • 1
  • 1
Appleman1234
  • 15,946
  • 45
  • 67
  • I still can't make it work - where exactly (and how) I should change encoding? I tried just changing 'utf8' to 'utf16le' but it still does not work. Could you provide some piece of code in node how to modify node.js code to get same results as from c# code? – user606521 Sep 21 '14 at 16:40
  • I will give you bounty in few hours because you answer, although not complete, helped me to to find the solution. Thanks. – user606521 Sep 22 '14 at 10:22