Search code examples
pythonsalt-cryptographysha512hashlibpython-cryptography

How to convert C# password hashing with salt to python for windows


How to convert below code in Python so that it gives same value on Windows even when executed multiple times.
Basically, it hashing password using sha512 and salt with 1000 iterations.

Here is the code:

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

namespace CheckHashing
{
    class Program
    {
        protected static string CreateSHA512Hash(string Password, string Salt)
        {
            try
            {
                byte[] bytes_password = Encoding.UTF8.GetBytes(Password);
                byte[] bytes_salt = Encoding.UTF8.GetBytes(Salt);
                HashAlgorithm sha512hash = (HashAlgorithm)new SHA512CryptoServiceProvider();
                for (int index = 0; index < 1000; ++index)
                {
                    byte[] bytes_iteration = Encoding.UTF8.GetBytes(Convert.ToBase64String(bytes_password) + Convert.ToBase64String(bytes_salt));
                    bytes_password = sha512hash.ComputeHash(bytes_iteration);
                }
                return Convert.ToBase64String(bytes_password);
            }
            catch (Exception ex)
            {
                return "Exception"+ex.Message;
            }
        }
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            string hash_pwd = CreateSHA512Hash("Pass@21", "SALT(}");
            Console.WriteLine(hash_pwd);
            // Answer => HoCg9kKAl5WY0lWzvH7hdW+cTQGUfknALKDw49rvzUVUTt9X9fuggGpDIRfCdotR/kVU8m7gj2xzRzwIfDc5Xw==
        }


    }
}

Already tried below code which gives different values. Below output gives Invalid Password as error in the function.

import hashlib
from base64 import b64encode

password = "Pass@21"
salt = "SALT(}"

h = hashlib.pbkdf2_hmac('sha512', password.encode('utf-8'), salt.encode('utf-8'), 1000)


print(b64encode(h).decode())

# and below as well

hex_hash = hashlib.sha512(password.encode('utf-8') + salt.encode('utf-8')).digest()
for i in range(1000):
    hex_hash = hashlib.sha512(hex_hash + salt.encode('utf-8')).digest()

print(b64encode(hex_hash).decode())


from passlib.hash import sha512_crypt as sha512

sha512_passwd = sha512.hash(password, rounds=1000)
print(sha512_passwd)


Solution

  • They don't start out the same.

    If you add some prints to the C#

        protected static string CreateSHA512Hash(string Password, string Salt)
        {
            try
            {
                byte[] bytes_password = Encoding.UTF8.GetBytes(Password);
                byte[] bytes_salt = Encoding.UTF8.GetBytes(Salt);
                HashAlgorithm sha512hash = (HashAlgorithm)new SHA512CryptoServiceProvider();
                for (int index = 0; index < 1000; ++index)
                {
                    if (index < 10)
                        Console.WriteLine(Convert.ToBase64String(bytes_password));
    
                    byte[] bytes_iteration = Encoding.UTF8.GetBytes(Convert.ToBase64String(bytes_password) + Convert.ToBase64String(bytes_salt));
                    bytes_password = sha512hash.ComputeHash(bytes_iteration);
                }
                Console.WriteLine("...");
                return Convert.ToBase64String(bytes_password);
            }
            catch (Exception ex)
            {
                return "Exception" + ex.Message;
            }
        }
    

    Here's my python port of the same code, with the same debug prints, so you can compare the first 10 values.

    import hashlib
    from base64 import b64encode
    
    password = "Pass@21"
    salt = "SALT(}"
    
    bytes_password = password.encode('utf-8') 
    bytes_salt = salt.encode('utf-8')
    for i in range(1000):
        if i < 10:
            print(b64encode(bytes_password).decode())
            
        b64pw = b64encode(bytes_password).decode()
        b64sa = b64encode(bytes_salt).decode()
        bytes_iteration = (b64pw + b64sa).encode('utf-8')
        
        bytes_password = hashlib.sha512(bytes_iteration).digest()
    
    print('...')
    print(b64encode(bytes_password).decode())
    

    Your original code wasn't consistent on when it hex encoded and when it computed the hash, and it computed a hash prior to entering the loop.