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

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

thank you!!

@brbeaird
Copy link

brbeaird commented May 5, 2022

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

@OpenSpacesAndPlaces
Copy link

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

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
Author

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

@bpatton00
Copy link

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