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:
- Store
data1
inutfD1
as UTF-8 bytearray ->byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(data1);
- Write
utfD1
into streamencrypt
(encryptionStream
is the underlying stream for CryptoStream) ->encrypt.Write(utfD1, 0, utfD1.Length);
- Write
encryptionStream
intedata1
byte array ->byte[] edata1 = encryptionStream.ToArray();
- Write
edata1
intodecryptionStreamBacking
(because its the underlying stream ofdecrypt
) ->decrypt.Write(edata1, 0, edata1.Length);
decryptionStreamBacking
Decode UTF-8 byte array and store it indata2
->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);
}
}
}