Home > Enterprise >  C# HASH Algorithm logic for retrieved entry from SQL Server database
C# HASH Algorithm logic for retrieved entry from SQL Server database

Time:04-25

I've been struggling with the logic on this one and how to get the HASH Algorithm to check that an entry retrieved from a SQL Server database matches an entry entered by a user.

The code below does work, what I can't get my head around is where the field retrieved from the SQL Server database should go in the code and how it can match with the entry entered by the user.

The code below does contain code for saving an amended HASH entry.

The entry in the SQL Server database is held as Varbinary

'0xD94C0F10760D83BC35C0786C674B5F8F'

Any help would be much appreciated.

    string[] passwordargs = new string[] { "turkey", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
        //If no file name is specified, write usage text.
        if (passwordargs.Length == 0)
        {
            Console.WriteLine(usageText);
        }
        else
        {
            string pwd1 = passwordargs[0];
            // Create a byte array to hold the random value.
            byte[] salt1 = new byte[8];
            using (RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider())
            {
                // Fill the array with a random value.
                rngCsp.GetBytes(salt1);
            }

            //data1 can be a string or contents of a file.
            string data1 = "Some test data";
            //The default iteration count is 1000 so the two methods use the same iteration count.
            int myIterations = 1000;
            try
            {
                Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1, salt1, myIterations);
                Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(pwd1, salt1);
                // Encrypt the data.
                Aes encAlg = Aes.Create();
                encAlg.Key = k1.GetBytes(16);
                MemoryStream encryptionStream = new MemoryStream();
                CryptoStream encrypt = new CryptoStream(encryptionStream, encAlg.CreateEncryptor(), CryptoStreamMode.Write);
                byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(data1);

                encrypt.Write(utfD1, 0, utfD1.Length);
                encrypt.FlushFinalBlock();
                encrypt.Close();
                byte[] edata1 = encryptionStream.ToArray();
                string encryptString = Convert.ToBase64String(edata1.ToArray());

                string queryStmt = "UPDATE [dbo].[Staff] SET [MEMWORD] = (@Content) WHERE STAFF_ID=7";

                using (SqlConnection _con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString))
                using (SqlCommand _cmd = new SqlCommand(queryStmt, _con))
                {
                    SqlParameter param = _cmd.Parameters.Add("@Content", SqlDbType.VarBinary);
                    param.Value = edata1;

                    _con.Open();
                    _cmd.ExecuteNonQuery();
                    _con.Close();
                }

                k1.Reset();

                // Try to decrypt, thus showing it can be round-tripped.
                Aes decAlg = Aes.Create();
                decAlg.Key = k2.GetBytes(16);
                decAlg.IV = encAlg.IV;
                MemoryStream decryptionStreamBacking = new MemoryStream();
                CryptoStream decrypt = new CryptoStream(decryptionStreamBacking, decAlg.CreateDecryptor(), CryptoStreamMode.Write);
                decrypt.Write(edata1, 0, edata1.Length);
                decrypt.Flush();
                decrypt.Close();
                k2.Reset();
                string data2 = new UTF8Encoding(false).GetString(decryptionStreamBacking.ToArray());

                if (!data1.Equals(data2))
                {
                    Console.WriteLine("Error: The two values are not equal.");
                }
                else
                {
                    Console.WriteLine("The two values are equal.");
                    Console.WriteLine("k1 iterations: {0}", k1.IterationCount);
                   

                    Console.WriteLine("k2 iterations: {0}", k2.IterationCount);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: {0}", e);
                string error = e.ToString();
            }
        }

CodePudding user response:

Do you mean by

The code below does work ...

if (!data1.Equals(data2)) is equal when you expect it to be equal?

In my understanding you set data1 = "Some test data" and that will not change until we reach the end.

And for data2 it's a little more work but break it down from top to bottom:

  1. Store data1 in utfD1 as UTF-8 bytearray -> byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(data1);
  2. Write utfD1 into stream encrypt (encryptionStream is the underlying stream for CryptoStream) -> encrypt.Write(utfD1, 0, utfD1.Length);
  3. Write encryptionStream int edata1 byte array -> byte[] edata1 = encryptionStream.ToArray();
  4. Write edata1 into decryptionStreamBacking (because its the underlying stream of decrypt) -> decrypt.Write(edata1, 0, edata1.Length);
  5. decryptionStreamBacking Decode UTF-8 byte array and store it in data2 ->
  6. string data2 = new UTF8Encoding(false).GetString(decryptionStreamBacking.ToArray());

So for me it looks like a fancy way to say string data2 = data1 and the database is a write only scenario. You only update one value in the database but you do not read anything from it.

CodePudding user response:

Thanks for all your help and suggestions, we have got the working code down to this now.

We had to change byte[] salt1 = new byte[8]; to byte[] salt1 = new byte[]{0, 1, 2, 3, 4, 5, 6, 7};

Otherwise the salt1 would be different every time and this would create a different encryption which would not allow the entered password to pair against what is save in the database.

Thank you for everyone's input.

 byte[] returned_Data;
 string[] passwordargs = new string[] { "turkey", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
 //If no file name is specified, write usage text.
 if (passwordargs.Length == 0)
 {
 Console.WriteLine(usageText);
 }
 else
 {
 string pwd1 = passwordargs[0];
 byte[] salt1 = new byte[]{0,1 ,2, 3,4, 5,6, 7};
 using (RNGCryptoServiceProvider rngCsp = new
RNGCryptoServiceProvider())
 {
 // Fill the array with a random value.
 rngCsp.GetBytes(salt1);
 }

 //data1 can be a string or contents of a file.
 string data1 = "Some test data";
 //The default iteration count is 1000 so the two methods use the same iteration count.
 int myIterations = 1000;
 try
 {
 Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1, salt1,myIterations);
 Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(pwd1, salt1);
 // Encrypt the data.
 Aes encAlg = Aes.Create();
  encAlg.Key = k1.GetBytes(16);
 MemoryStream encryptionStream = new MemoryStream();
 CryptoStream encrypt = new CryptoStream(encryptionStream,
 encAlg.CreateEncryptor(), CryptoStreamMode.Write);
 byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(
data1);

 encrypt.Write(utfD1, 0, utfD1.Length);
 encrypt.FlushFinalBlock();
 encrypt.Close();
 byte[] edata1 = encryptionStream.ToArray();
                
 string queryStmt = "UPDATE [dbo].[Staff] SET [PASSWORD] = (@Content) WHERE STAFF_ID=7";

 using (SqlConnection _con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Conn"].ConnectionString))
 using (SqlCommand _cmd = new SqlCommand(queryStmt, _con))
 {
 SqlParameter param = _cmd.Parameters.Add("@Content", SqlDbType.VarBinary);
 param.Value = edata1;

 _con.Open();
 _cmd.ExecuteNonQuery();
 _con.Close();
 }


 using (SqlConnection sqlconnection = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Conn"].ConnectionString))
 {
 sqlconnection.Open();

 string selectQuery = string.Format(@"Select [PASSWORD] From [dbo].[Staff] Where STAFF_ID={0}", 7);

 SqlCommand selectCommand = new SqlCommand(selectQuery, sqlconnection);
 SqlDataReader reader = selectCommand.ExecuteReader();
 if (reader.Read())
 {
 returned_Data = (byte[])reader[0];
 string strData = Encoding.UTF8.GetString(returned_Data);
 Console.WriteLine(strData);

  if(!edata1.SequenceEqual(returned_Data))
 {
 Console.WriteLine("Error: The two values are not equal.");
 }
 else
 {
 Console.WriteLine("The two values are equal.");
 Console.WriteLine("k1 iterations: {0}", k1.IterationCount);


Console.WriteLine("k2 iterations: {0}", k2.IterationCount);
                        }
                    }
                }
  • Related