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?

3
  • 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? Commented Sep 9, 2014 at 14:52
  • I really don't know - current DB (we are migrating from this DB actually) maintainer sent me just this link stackoverflow.com/questions/1137368/… - any ideas? Commented Sep 9, 2014 at 15:04
  • I have updated the question - I have provided working c# code that I need to port to node.js. Commented Sep 21, 2014 at 13:07

3 Answers 3

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');
}
Sign up to request clarification or add additional context in comments.

1 Comment

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.
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);

1 Comment

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"
1
+50

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

2 Comments

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?
I will give you bounty in few hours because you answer, although not complete, helped me to to find the solution. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.