Skip to content

Instantly share code, notes, and snippets.

@PalmerEk
Last active June 28, 2025 03:43
Show Gist options
  • Select an option

  • Save PalmerEk/1191651 to your computer and use it in GitHub Desktop.

Select an option

Save PalmerEk/1191651 to your computer and use it in GitHub Desktop.
ASP.NET Membership password hash for Node.js
See updated reply by OpenSpacesAndPlaces
https://gist.github.com/PalmerEk/1191651?permalink_comment_id=4449026#gistcomment-4449026
/////////////////////////////////////////////////////////////
// ORIGINAL/OLD for posterity
/////////////////////////////////////////////////////////////
var crypto = require('crypto');
console.log(dotnet_membership_password_hash("welcome1", "qkI2wRPSW7Y4ArqWkfHm5g==")); // W25/z6MAywBax7DITuKgSmsXua4=
function dotnet_membership_password_hash(pass, salt)
{
var bytes = new Buffer(pass || '', 'ucs2');
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');
}
@chrisumbel
Copy link
Copy Markdown

if this works out well it warrants a blog post, brudda. this little function could solve one of the major stumbling blocks for people porting apps from ASP.Net to node.

@FrancoIbarra
Copy link
Copy Markdown

thank you!!

@brbeaird
Copy link
Copy Markdown

brbeaird commented May 5, 2022

I cannot express how useful this was. Thanks for sharing!

@OpenSpacesAndPlaces
Copy link
Copy Markdown

OpenSpacesAndPlaces commented Jan 25, 2023

@PalmerEk

The C# I'm trying to mirror has a longer salt:

   public static String GenerateSalt()
        {
            byte[] buf = new byte[64];
            (new RNGCryptoServiceProvider()).GetBytes(buf);
            return Convert.ToBase64String(buf);
        }

And the base alg is set as:
<machineKey compatibilityMode="Framework45" validationKey="**512ValdiationKey**" decryptionKey="**256Key**" validation="HMACSHA512" decryption="AES"/>

I've tried like:
crypto.createHmac('sha512', **512ValdiationKey**).update(dst).digest('base64');

Is there a different way this needs to be approached.

@OpenSpacesAndPlaces
Copy link
Copy Markdown

Should anyone else run into this - see:
https://referencesource.microsoft.com/#System.Web/Security/SQLMembershipProvider.cs,f37d42faca2b921e

private string [EncodePassword](https://referencesource.microsoft.com/System.Web/R/f37d42faca2b921e.html)(string pass, int passwordFormat, string salt)
        {
            if (passwordFormat == 0) // MembershipPasswordFormat.Clear
                return pass;
 
            byte[] bIn = [Encoding](https://referencesource.microsoft.com/mscorlib/A.html#3b6090c501893c25).[Unicode](https://referencesource.microsoft.com/mscorlib/A.html#3ab75dace56ae6d2).[GetBytes](https://referencesource.microsoft.com/mscorlib/A.html#83f2d2c6f22db1a9)(pass);
            byte[] bSalt = [Convert](https://referencesource.microsoft.com/mscorlib/A.html#fc990bd1275d43d6).[FromBase64String](https://referencesource.microsoft.com/mscorlib/A.html#08c34f52087ba624)(salt);
            byte[] bRet = null;
 
            if (passwordFormat == 1)
            { // MembershipPasswordFormat.Hashed
                [HashAlgorithm](https://referencesource.microsoft.com/mscorlib/A.html#e7c6be1ed86f474f) hm = [GetHashAlgorithm](https://referencesource.microsoft.com/System.Web/Security/SQLMembershipProvider.cs.html#0f16b82251e5f3d9)();
                if (hm is [KeyedHashAlgorithm](https://referencesource.microsoft.com/mscorlib/A.html#c68ffe2089d6c464)) {
                    [KeyedHashAlgorithm](https://referencesource.microsoft.com/mscorlib/A.html#c68ffe2089d6c464) kha = ([KeyedHashAlgorithm](https://referencesource.microsoft.com/mscorlib/A.html#c68ffe2089d6c464)) hm;
                    if (kha.[Key](https://referencesource.microsoft.com/mscorlib/A.html#922271ab9c7d178d).[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94) == bSalt.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94)) {
                        kha.[Key](https://referencesource.microsoft.com/mscorlib/A.html#922271ab9c7d178d) = bSalt;
                    } else if (kha.[Key](https://referencesource.microsoft.com/mscorlib/A.html#922271ab9c7d178d).[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94) < bSalt.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94)) {
                        byte[] bKey = new byte[kha.[Key](https://referencesource.microsoft.com/mscorlib/A.html#922271ab9c7d178d).[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94)];
                        [Buffer](https://referencesource.microsoft.com/mscorlib/A.html#570e88af5685d024).[BlockCopy](https://referencesource.microsoft.com/mscorlib/A.html#1fbec67d6ee92203)(bSalt, 0, bKey, 0, bKey.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94));
                        kha.[Key](https://referencesource.microsoft.com/mscorlib/A.html#922271ab9c7d178d) = bKey;
                    } else {
                        byte[] bKey = new byte[kha.[Key](https://referencesource.microsoft.com/mscorlib/A.html#922271ab9c7d178d).[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94)];
                        for (int iter = 0; iter < bKey.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94); ) {
                            int len = [Math](https://referencesource.microsoft.com/mscorlib/A.html#a4407e67b9a5afad).[Min](https://referencesource.microsoft.com/mscorlib/A.html#f441d55c88d635ad)(bSalt.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94), bKey.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94) - iter);
                            [Buffer](https://referencesource.microsoft.com/mscorlib/A.html#570e88af5685d024).[BlockCopy](https://referencesource.microsoft.com/mscorlib/A.html#1fbec67d6ee92203)(bSalt, 0, bKey, iter, len);
                            iter += len;
                        }
                        kha.[Key](https://referencesource.microsoft.com/mscorlib/A.html#922271ab9c7d178d) = bKey;
                    }
                    bRet = kha.[ComputeHash](https://referencesource.microsoft.com/mscorlib/A.html#a71a3cba2c656040)(bIn);
                }
                else {
                    byte[] bAll = new byte[bSalt.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94) + bIn.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94)];
                    [Buffer](https://referencesource.microsoft.com/mscorlib/A.html#570e88af5685d024).[BlockCopy](https://referencesource.microsoft.com/mscorlib/A.html#1fbec67d6ee92203)(bSalt, 0, bAll, 0, bSalt.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94));
                    [Buffer](https://referencesource.microsoft.com/mscorlib/A.html#570e88af5685d024).[BlockCopy](https://referencesource.microsoft.com/mscorlib/A.html#1fbec67d6ee92203)(bIn, 0, bAll, bSalt.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94), bIn.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94));
                    bRet = hm.[ComputeHash](https://referencesource.microsoft.com/mscorlib/A.html#a71a3cba2c656040)(bAll);
                }
            } else {
                byte[] bAll = new byte[bSalt.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94) + bIn.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94)];
                [Buffer](https://referencesource.microsoft.com/mscorlib/A.html#570e88af5685d024).[BlockCopy](https://referencesource.microsoft.com/mscorlib/A.html#1fbec67d6ee92203)(bSalt, 0, bAll, 0, bSalt.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94));
                [Buffer](https://referencesource.microsoft.com/mscorlib/A.html#570e88af5685d024).[BlockCopy](https://referencesource.microsoft.com/mscorlib/A.html#1fbec67d6ee92203)(bIn, 0, bAll, bSalt.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94), bIn.[Length](https://referencesource.microsoft.com/mscorlib/A.html#42e9b7616956cf94));
                bRet = [EncryptPassword](https://referencesource.microsoft.com/System.Web.ApplicationServices/A.html#a76e2e1b0e95333c)(bAll, [_LegacyPasswordCompatibilityMode](https://referencesource.microsoft.com/System.Web/Security/SQLMembershipProvider.cs.html#8d4dbd5be6f5073e));
            }
 
            return [Convert](https://referencesource.microsoft.com/mscorlib/A.html#fc990bd1275d43d6).[ToBase64String](https://referencesource.microsoft.com/mscorlib/A.html#f9e5bd7b69c5f334)(bRet);
        }
const dotnet_membership_password_hmachash = function (pass, salt, VALIDATION_KEY) {
    var key = null;
    var bIn = Buffer.from(pass, 'utf16le');
    var bSalt = Buffer.from(salt, 'base64');
    if (VALIDATION_KEY.length == bSalt.length) {
        key = bSalt;
    } else if (VALIDATION_KEY.length < bSalt.length) {

        var bKey = new Buffer(VALIDATION_KEY.length);

        bSalt.copy(bKey, 0, 0, bKey.Length);
        key = bKey;

    } else {
        var bKey = new Buffer(VALIDATION_KEY.length);

        for (var iter = 0; iter < bKey.length; )
        {
            var len = Math.min(bSalt.length, bKey.length - iter);
            bSalt.copy(bKey, iter, 0, len);
            iter += len;
        }

        key = bKey;
    }

    return crypto.createHmac('sha512', key).update(bIn).digest('base64');
};

@PalmerEk
Copy link
Copy Markdown
Author

Great job! So glad you were able to find the solution.

@bpatton00
Copy link
Copy Markdown

absolute life saver, was getting crushed by this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment