Verification of Hashing password is not working - c#

I have asked a question of which I did get a lot of great feedback, along with a good answer. I assume that I am doing something wrong with my verification check of the 2 hashes. Perhaps the code in the loop is fine, but my code with understanding of bytes and base64 etc. is the problem?
Here is the original question.
Password Hashing - Why salt 60,000 times
Problem is these hashes do not match if (resultHash.Equals(hashPassword))
Code
public string BuildVerify()
{
string password = "";
string salt = "";
byte[] result;
using (var sha256 = SHA256.Create())
{
password = "hovercraft";
// step 1: you can use RNGCryptoServiceProvider for something worth using
var passwordHashing = new PasswordHashing();
salt = passwordHashing.CreateRandomSalt();
// step 2
string hash =
Convert.ToBase64String(sha256.ComputeHash(Encoding.UTF8.GetBytes(salt + password)));
// step 3
result = sha256.ComputeHash(Encoding.UTF8.GetBytes(salt + hash));
// step 4
for (int i = 0; i < 60000; i++)
{
result =
sha256.ComputeHash(Encoding.UTF8.GetBytes(salt + Convert.ToBase64String(result)));
}
}
// TESTING VERIFY this works ..
string SaltAndPwd = string.Concat(password, salt);
SHA256 sha2 = SHA256Managed.Create();
byte[] buff = sha2.ComputeHash(Encoding.Unicode.GetBytes(SaltAndPwd));
string resultHash = Convert.ToBase64String(buff);
string hashPassword = Convert.ToBase64String(result);
if (resultHash.Equals(hashPassword))
{
// perfect
}
return "";
}
public class PasswordHashing
{
public string CreateRandomSalt()
{
string password = "";
password = HashPassword.CreateSalt(8) + "=";
password = password.Replace("/", "c");
return password;
}
}
public static string CreateSalt(int size)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[size];
rng.GetBytes(buff);
return Convert.ToBase64String(buff);
}
Update - issue
Ok, I'm using the code from the answer, but obviously my assumptions are not correct as I cannot use my code to verify
// This should be stored in your DB for example along with the hash result
var newsalt = SOPasswordHasher.GetSalt();
// We calculate the hash then store the result. Next time you want to authenticate someone
// You'll have to reuse the same salt and recalculate the hash then compare
// the stored hash with the new one
var result = Convert.ToBase64String(SOPasswordHasher.Hash("hovercraft", newsalt));
string SaltAndPwd = string.Concat("hovercraft", newsalt);
SHA256 sha2 = SHA256Managed.Create();
byte[] buff = sha2.ComputeHash(Encoding.Unicode.GetBytes(SaltAndPwd));
string resultHash = Convert.ToBase64String(buff);
if (result.Equals(resultHash))
{
// perfect
}

Here's a reusable class that you can use (relying less on converting to base64):
class SOPasswordHasher
{
/// <summary>
/// Password Hasher
/// </summary>
/// <param name="password">The password you want to hash</param>
/// <param name="salt">byte array of (crypto-secure) random values</param>
/// <param name="iterations">Number of iterations. default is 60,000</param>
/// <returns>Byte array containing the hashed password</returns>
public static byte[] Hash(string password, byte[] salt, int iterations = 60000)
{
using (var sha256 = SHA256.Create())
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
// step 2
byte[] hash = sha256.ComputeHash(passwordBytes.Concat(salt).ToArray());
// step 3
byte[] result = sha256.ComputeHash(salt.Concat(hash).ToArray());
// step 4
for (int i = 0; i < iterations; i++)
{
result =
sha256.ComputeHash(salt.Concat(result).ToArray());
}
return result;
}
}
public static byte[] GetSalt(int size = 32)
{
byte[] salt = new byte[size];
using (var cryptoServiceProvider = new RNGCryptoServiceProvider())
{
cryptoServiceProvider.GetBytes(salt);
}
return salt;
}
}
and here's a usage example:
// This should be stored in your DB for example along with the hash result
var salt = SOPasswordHasher.GetSalt();
// We calculate the hash then store the result. Next time you want to authenticate someone
// You'll have to reuse the same salt and recalculate the hash then compare
// the stored hash with the new one
var result = Convert.ToBase64String(SOPasswordHasher.Hash("hovercraft", salt));
Important: I make no guarantee that this code is safe to use since I'm not a security expert. Bruce Schneier said it best: "Amateurs Produce Amateur Cryptography"

Related

SHA 512 and or ARGON2ID Hashing + Salt For Dovecot in C#

I have tried to generate a salted hash using ARGON2ID and am running in to the same issues. The dovecot password generation utility generates the correct hash but I still cant seem to get things working using C#.
I am using the Konscious.Security.Cryptography.Argon2 Nuget Package at the moment..
Like I said still doesn't work even after playing with the length of the salt
I setup a new mail-server using postfix and dovecot. The password storage I am using is SSHA512 which means SHA512 with a salt. I need to create an ASP.NET page that allows the user to create and change their e-mail password in the DB. I could use the SQL route but I would like to do this in C# so I can use NHibernate which is my ORM.
I found a post online that creates the hash and salt using SQL.
INSERT INTO virtual_users
(id, domain_id, password , email)
VALUES
(NULL, '1', (SELECT REPLACE(TO_BASE64(CONCAT(UNHEX(SHA2(CONCAT('YourPasswordHere', v.salt), 512)), v.salt)), '\n', '') AS salted FROM (SELECT SHA2(RAND(), 512) AS salt) v), 'user#example.com');
UPDATE virtual_users
SET password = (
SELECT REPLACE(TO_BASE64(CONCAT(UNHEX(SHA2(CONCAT('YourPasswordHere', v.salt), 512)), v.salt)), '\n', '') AS salted
FROM (
SELECT SHA2(RAND(), 512) AS salt
) v
)
WHERE email = 'user#example.com';
Here is an explanation of what is going on. I am trying to do the following in C# and am not having any luck..
Generate a random (rather lengthy) salt
Append the salt to the password
Get the SHA512 Hash of #2
Convert the hash to binary
Append the salt to #4
Convert the whole thing to Base64
7 .Remove unwanted newlines added by MySQL's TO_BASE64() function
The result is a 256 byte long string so you may need to update your password field to VARCHAR(256).
Any instruction would be greatly appreciated.
Here is what I have so far but it doesn't seem to work
SH1512 Code:
//My Random Method
public byte[] GenerateRandomCryptographicBytes(int keyLength)
{
var randomBytes = new byte[keyLength];
var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomBytes);
return randomBytes;
}
//Hashing Method:
public PasswordHashResult HashWithSalt(string password, int saltLength, HashAlgorithm hashAlgo)
{
var rng = new Rng();
var saltBytes = rng.GenerateRandomCryptographicBytes(saltLength);
var passwordAsBytes = Encoding.UTF8.GetBytes(password);
var passwordWithSaltBytes = new List<byte>();
passwordWithSaltBytes.AddRange(passwordAsBytes);
passwordWithSaltBytes.AddRange(saltBytes);
var digestBytes = hashAlgo.ComputeHash(passwordWithSaltBytes.ToArray());
return new PasswordHashResult
{
Salt = Convert.ToBase64String(saltBytes),
PasswordHash = Convert.ToBase64String(digestBytes)
};
}
//Result Class:
public sealed class PasswordHashResult
{
public string PasswordHash { get; set; }
public string Salt { get; set; }
public string HashAndSalt { get; set; }
}
Argon2 Code:
public byte[] CreateHash(byte[] password, byte[] salt)
{
using var argon2 = new Argon2id(password);
argon2.Salt = salt;
argon2.DegreeOfParallelism = 8;
argon2.Iterations = 4;
argon2.MemorySize = 1024 * 128;
return argon2.GetBytes(32);
}
public static byte[] GenerateRandomCryptographicBytes()
{
var randomBytes = new byte[32];
var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomBytes);
return randomBytes;
}
var bytes = Encoding.UTF8.GetBytes(plainTextPassword);
var salt = PasswordService.GenerateRandomCryptographicBytes(); // Salt should be stored alongside hash.
var hash = passwordService.CreateHash(bytes, salt);
Here is what the Argon2id hash looks like.
{ARGON2ID}$argon2id$v=19$m=65536,t=3,p=1$UCLtz5ubAeKTzeIVo0pzPw$jDDq5JmNX9LRzmlzknJWsGYKJ0TLiEHG6MGt5jcp6XQ
Nothing Like What I Get returned from the code above.

Validating HMACSHA256 in C#

I'm pretty new to asp.net/c# and i'm trying to recreate the password validation in C#. I have this hash stored in the database:
U2zdbUmZXCeOLs0OuS9bhg==7hQ60TTq0ZiT/z+eu4bdzpmBcp5uYa70ZDxQPncEG0c=
The password for this hash is 1234567. This works because I can login with this password in the webapplication.
So if I understand correctly. The hash consists of a base64 encoded salt U2zdbUmZXCeOLs0OuS9bhg== and a password hashed with this salt: 7hQ60TTq0ZiT/z+eu4bdzpmBcp5uYa70ZDxQPncEG0c=
But if I use this example I found on the internet. I don't get the same hash result. I already tried playing with the encoding (resulting in different hashes), but no luck. hashAlgorithmType is set to HMACSHA256 in the web.config. What am I doing wrong?
using System;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
var base64Salt = "U2zdbUmZXCeOLs0OuS9bhg==";
var base64Hash = "7hQ60TTq0ZiT/z+eu4bdzpmBcp5uYa70ZDxQPncEG0c=";
// Decode the base64 salt to get the salt byte array
var saltBytes = Convert.FromBase64String(base64Salt);
// Provide the user's plain password
var plaintextPassword = "1234567";
// Salt the plaintext password, prepend to user's provided password, and then hash
try
{
var hmac256 = new HMACSHA256(saltBytes);
var hash = Convert.ToBase64String(hmac256.ComputeHash(Encoding.UTF8.GetBytes(plaintextPassword)));
Console.WriteLine(base64Salt+hash);
if (hash == base64Hash)
{
Console.WriteLine("Success! Both hashes match!");
}
else
{
Console.WriteLine("Passwords do not match.");
}
}
catch (Exception e)
{
Console.WriteLine("Error!", e.Message);
}
}
}
You need to know the right key used and how is the password concatenated with the salt.
Normally, the salt bytes are concatenated with the password bytes, like this:
var password = "1234567";
var passwordBytes = Encoding.UTF8.GetBytes(password);
var salt = "U2zdbUmZXCeOLs0OuS9bhg==";
var saltBytes = Convert.FromBase64String(salt);
var passwordBytesAndSaltBytes = new byte[passwordBytes.Length + saltBytes.Length];
for (int i = 0; i < passwordBytes.Length; i++)
{
passwordBytesAndSaltBytes[i] = passwordBytes[i];
}
for (int i = 0; i < saltBytes.Length; i++)
{
passwordBytesAndSaltBytes[passwordBytes.Length + i] = saltBytes[i];
}
but we don't know what were the rules used.
And the secret is well, kept secret, like this:
var secret = "this must be hidden";
var secretBytes = Encoding.UTF8.GetBytes(secret);
var hmac256 = new HMACSHA256(secretBytes);
var hash = Convert.ToBase64String(hmac256.ComputeHash(passwordBytesAndSaltBytes) );
Without seeing the code, unfortunately, I don't think you will be able to replicate it.
Finally got it to work! I found the answer in the source code of Umbraco (I'm using Umbraco as CMS). I thought it was using the default membershipprovider but it wasn't... Also worth mentioning that the salt was to short for the required key-length, so it was extended.
From the source code I made a working example:
using System;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
var bytes = Encoding.Unicode.GetBytes("1234567");
var saltBytes = Convert.FromBase64String("U2zdbUmZXCeOLs0OuS9bhg==");
byte[] inArray;
var hashAlgorithm = HashAlgorithm.Create("HMACSHA256");
var algorithm = hashAlgorithm as KeyedHashAlgorithm;
var keyedHashAlgorithm = algorithm;
if (keyedHashAlgorithm.Key.Length == saltBytes.Length)
{
//if the salt bytes is the required key length for the algorithm, use it as-is
keyedHashAlgorithm.Key = saltBytes;
Console.WriteLine("length is ok");
}
else if (keyedHashAlgorithm.Key.Length < saltBytes.Length)
{
//if the salt bytes is too long for the required key length for the algorithm, reduce it
var numArray2 = new byte[keyedHashAlgorithm.Key.Length];
Buffer.BlockCopy(saltBytes, 0, numArray2, 0, numArray2.Length);
keyedHashAlgorithm.Key = numArray2;
Console.WriteLine("salt byte too long");
}
else
{
//if the salt bytes is too short for the required key length for the algorithm, extend it
Console.WriteLine("salt byte to short");
var numArray2 = new byte[keyedHashAlgorithm.Key.Length];
var dstOffset = 0;
while (dstOffset < numArray2.Length)
{
var count = Math.Min(saltBytes.Length, numArray2.Length - dstOffset);
Buffer.BlockCopy(saltBytes, 0, numArray2, dstOffset, count);
dstOffset += count;
}
keyedHashAlgorithm.Key = numArray2;
}
inArray = keyedHashAlgorithm.ComputeHash(bytes);
var hash = Convert.ToBase64String(inArray);
Console.WriteLine(hash);
var base64Hash = "7hQ60TTq0ZiT/z+eu4bdzpmBcp5uYa70ZDxQPncEG0c=";
if (hash == base64Hash)
{
Console.WriteLine("Success! Both hashes match!");
}
else
{
Console.WriteLine("Passwords do not match.");
}
}
}

Generating Hashed Passwords in C#

I don't know if this is the correct place to ask, but I am having an issue hashing passwords for MySql Backend. I am running mosquitto 1.4.3 broker and I have the mosquitto-auth-plugin working on the same server. But I want to move the auth-plugin to a new server. So I created a admin program in C# to add users and access controls however I cant seem to the get the correct hash code for the password.
Has anyone implemented this or is there some resoucres available to create the correct hash?
I have tried this Hash It Right
private const int SaltByteLength = 12;
private const int DerivedKeyLength = 24;
public string CreatePasswordHash(string password)
{
var salt = GenerateRandomSalt();
var iterationCount = GetIterationCount();
var hashValue = GenerateHashValue(password, salt, iterationCount);
var iterationCountBtyeArr = BitConverter.GetBytes(iterationCount);
var valueToSave = new byte[SaltByteLength + DerivedKeyLength + iterationCountBtyeArr.Length];
Buffer.BlockCopy(salt, 0, valueToSave, 0, SaltByteLength);
Buffer.BlockCopy(hashValue, 0, valueToSave, SaltByteLength, DerivedKeyLength);
Buffer.BlockCopy(iterationCountBtyeArr, 0, valueToSave, salt.Length + hashValue.Length, iterationCountBtyeArr.Length);
return Convert.ToBase64String(valueToSave);
}
private int GetIterationCount()
{
return 901;
}
private static byte[] GenerateRandomSalt()
{
var csprng = new RNGCryptoServiceProvider();
var salt = new byte[SaltByteLength];
csprng.GetBytes(salt);
return salt;
}
private static byte[] GenerateHashValue(string password, byte[] salt, int iterationCount)
{
byte[] hashValue;
var valueToHash = string.IsNullOrEmpty(password) ? string.Empty : password;
using (var pbkdf2 = new Rfc2898DeriveBytes(valueToHash, salt, iterationCount))
{
hashValue = pbkdf2.GetBytes(DerivedKeyLength);
}
return hashValue;
}
will this make it easier for you?
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
class Class1
{
static void Main(string[] args)
{
byte[] HashValue;
string MessageString = "This is the original message!";
//Create a new instance of the UnicodeEncoding class to
//convert the string into an array of Unicode bytes.
UnicodeEncoding UE = new UnicodeEncoding();
//Convert the string into an array of bytes.
byte[] MessageBytes = UE.GetBytes(MessageString);
//Create a new instance of the SHA1Managed class to create
//the hash value.
SHA1Managed SHhash = new SHA1Managed();
//Create the hash value from the array of bytes.
HashValue = SHhash.ComputeHash(MessageBytes);
//Display the hash value to the console.
foreach(byte b in HashValue)
{
Console.Write("{0} ", b);
}
}

RSA Encryption of large data in C#

This is my first post, so hope I haven't missed anything important. I'm doing a project in C# where I need to use public/private key encryption to encrypt a message and then send it over an SSL connection.
I chose to use the RSACryptoService, as according to the documentation, that was the only asymmetric encryption scheme used for encrypting data. The problem is that I am having a lot of problems with this. (I wanted to do symmetric encryption, but that is not what my teacher want me to do, and according to him it should be easy to just determine a block size and then it should do all the work for you.) Well, so far no luck and I've tried some different approaches, but now I'm back to basics and trying again, this is my current code:
public string[] GenerateKeysToStrings(string uniqueIdentifier)
{
string[] keys;
using (var rsa = new RSACryptoServiceProvider(4096))
{
try
{
string privateKey = rsa.ToXmlString(true);
string publicKey = rsa.ToXmlString(false);
this.pki.StoreKey(publicKey, uniqueIdentifier);
keys = new string[2];
keys[0] = privateKey;
keys[1] = publicKey;
}
finally
{
//// Clear the RSA key container, deleting generated keys.
rsa.PersistKeyInCsp = false;
}
}
return keys;
}
As you can see, I generate the keys and I mimmick a PKI by sending the public key to a simple class that stores it, and then the private key is written to a file
(Notice that I also have another method that does the same but stores it to an array instead, just because I wanted to test and simplify things as I get No such key exceptions and sometimes cryptographic exceptions when I do it the way shown in the example, so I wanted to simplify it by simply storing the rsa.ToXmlString string, as a string in an array, but no luck.)
Now I have an encrypt and decrypt method as follows:
public string Encrypt(string keyString, string message)
{
string encryptedMessage;
using (var rsa = new RSACryptoServiceProvider())
{
try
{
//// Load the key from the specified path
var encryptKey = new XmlDocument();
encryptKey.Load(#"C:\Test\PrivateKeyInfo.xml");
rsa.FromXmlString(encryptKey.OuterXml);
//// Conver the string message to a byte array for encryption
//// var encoder = new UTF8Encoding();
ASCIIEncoding byteConverter = new ASCIIEncoding();
byte[] dataToEncrypt = byteConverter.GetBytes(message);
byte[] encryptedData = rsa.Encrypt(dataToEncrypt, false);
//// Convert the byte array back to a string message
encryptedMessage = byteConverter.GetString(encryptedData);
}
finally
{
//// Clear the RSA key container, deleting generated keys.
rsa.PersistKeyInCsp = false;
}
}
return encryptedMessage;
}
Decryption:
public string Decrypt(string keyString, string message)
{
string decryptedText;
using (var rsa = new RSACryptoServiceProvider())
{
try
{
//// Loads the keyinfo into the rsa parameters from the keyfile
/*
var privateKey = new XmlDocument();
privateKey.Load(keyString);
*/
rsa.FromXmlString(keyString);
//// Convert the text from string to byte array for decryption
ASCIIEncoding byteConverter = new ASCIIEncoding();
var encryptedBytes = byteConverter.GetBytes(message);
//// Create an aux array to store all the encrypted bytes
byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, false);
decryptedText = byteConverter.GetString(decryptedBytes);
}
finally
{
//// Clear the RSA key container, deleting generated keys.
rsa.PersistKeyInCsp = false;
}
}
return decryptedText;
}
I know that this is a wall of text, but I hope you can help me out because I've been banging my head against the wall for so long now it's not funny :)
The problem is, how do I go about encrypting messages with RSA (or any other public/private key encryption)
Here is the Test client:
public static void Main(string[] args)
{
PublicKeyInfrastructure pki = new PublicKeyInfrastructure();
Cryptograph crypto = new Cryptograph();
string[] keys = crypto.GenerateKeysToStrings("simonlanghoff#gmail.com");
string plainText = "Hello play with me, please";
string publicKey = crypto.GetPublicKey("simonlanghoff#gmail.com");
string encryptedText = crypto.Encrypt(keys[0], plainText);
string decryptedText = crypto.Decrypt(keys[1], encryptedText);
}
As I mentioned, the string arrays are there because I wanted to eliminate bad parsing error from XML documents...
When I run the test client, if I use the private key to encrypt and public key to decrypt, I get a "Key does not exist exception" and if I do it the other way around, I get a bad data exception.
Please help me out guys, if you know of any good guide, or can tell me how to somewhat straightfoward implement public/private key encryption on string messages, please help me out.
I appreciate any help.
This is not how RSA encryption should be done.
RSA is all about math. What you encrypt is a number so it has to be of finite length and matching the RSA keypair length you're using. Further length limitations are imposed by the padding used (either PKCS#1 or OAEP).
If you want to encrypt large data with RSA you need to do it indirectly - i.e. use a symmetric key to encrypt the large data and encrypt this key using the RSA public key.
You can read about implementing this on my blog.
Okay, I've finally come up with a solution to the problem I stated in my original post. This is something I haven't thoroughly tested or anything, but something I figured out from a little trial and error process.
Here is the current code I have:
public static string Encrypt(string dataToEncrypt, RSAParameters publicKeyInfo)
{
//// Our bytearray to hold all of our data after the encryption
byte[] encryptedBytes = new byte[0];
using (var RSA = new RSACryptoServiceProvider())
{
try
{
//Create a new instance of RSACryptoServiceProvider.
UTF8Encoding encoder = new UTF8Encoding();
byte[] encryptThis = encoder.GetBytes(dataToEncrypt);
//// Importing the public key
RSA.ImportParameters(publicKeyInfo);
int blockSize = (RSA.KeySize / 8) - 32;
//// buffer to write byte sequence of the given block_size
byte[] buffer = new byte[blockSize];
byte[] encryptedBuffer = new byte[blockSize];
//// Initializing our encryptedBytes array to a suitable size, depending on the size of data to be encrypted
encryptedBytes = new byte[encryptThis.Length + blockSize - (encryptThis.Length % blockSize) + 32];
for (int i = 0; i < encryptThis.Length; i += blockSize)
{
//// If there is extra info to be parsed, but not enough to fill out a complete bytearray, fit array for last bit of data
if (2 * i > encryptThis.Length && ((encryptThis.Length - i) % blockSize != 0))
{
buffer = new byte[encryptThis.Length - i];
blockSize = encryptThis.Length - i;
}
//// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it
if (encryptThis.Length < blockSize)
{
buffer = new byte[encryptThis.Length];
blockSize = encryptThis.Length;
}
//// encrypt the specified size of data, then add to final array.
Buffer.BlockCopy(encryptThis, i, buffer, 0, blockSize);
encryptedBuffer = RSA.Encrypt(buffer, false);
encryptedBuffer.CopyTo(encryptedBytes, i);
}
}
catch (CryptographicException e)
{
Console.Write(e);
}
finally
{
//// Clear the RSA key container, deleting generated keys.
RSA.PersistKeyInCsp = false;
}
}
//// Convert the byteArray using Base64 and returns as an encrypted string
return Convert.ToBase64String(encryptedBytes);
}
/// <summary>
/// Decrypt this message using this key
/// </summary>
/// <param name="dataToDecrypt">
/// The data To decrypt.
/// </param>
/// <param name="privateKeyInfo">
/// The private Key Info.
/// </param>
/// <returns>
/// The decrypted data.
/// </returns>
public static string Decrypt(string dataToDecrypt, RSAParameters privateKeyInfo)
{
//// The bytearray to hold all of our data after decryption
byte[] decryptedBytes;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
try
{
byte[] bytesToDecrypt = Convert.FromBase64String(dataToDecrypt);
//// Import the private key info
RSA.ImportParameters(privateKeyInfo);
//// No need to subtract padding size when decrypting (OR do I?)
int blockSize = RSA.KeySize / 8;
//// buffer to write byte sequence of the given block_size
byte[] buffer = new byte[blockSize];
//// buffer containing decrypted information
byte[] decryptedBuffer = new byte[blockSize];
//// Initializes our array to make sure it can hold at least the amount needed to decrypt.
decryptedBytes = new byte[dataToDecrypt.Length];
for (int i = 0; i < bytesToDecrypt.Length; i += blockSize)
{
if (2 * i > bytesToDecrypt.Length && ((bytesToDecrypt.Length - i) % blockSize != 0))
{
buffer = new byte[bytesToDecrypt.Length - i];
blockSize = bytesToDecrypt.Length - i;
}
//// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it
if (bytesToDecrypt.Length < blockSize)
{
buffer = new byte[bytesToDecrypt.Length];
blockSize = bytesToDecrypt.Length;
}
Buffer.BlockCopy(bytesToDecrypt, i, buffer, 0, blockSize);
decryptedBuffer = RSA.Decrypt(buffer, false);
decryptedBuffer.CopyTo(decryptedBytes, i);
}
}
finally
{
//// Clear the RSA key container, deleting generated keys.
RSA.PersistKeyInCsp = false;
}
}
//// We encode each byte with UTF8 and then write to a string while trimming off the extra empty data created by the overhead.
var encoder = new UTF8Encoding();
return encoder.GetString(decryptedBytes).TrimEnd(new[] { '\0' });
}
As I said, I have not tested it much, other than sizes below, at and above the block-size, but it seems to be doing what it should. I am still a novice, so I would really like for you to scrutinize my code :)
Maybe I'm missing something, but it looks like your Encrypt() function doesn't make use of either the keyString parameter or the contents of encryptKey.

InCorrect output using Rfc2898DeriveBytes for password hashing

I am certainly sure i am doing something wrong here. Using .net implementation of the algorithm i hash the password to store in database along with the salt used to hash. On validating the same password with the existing hash does not match.Here is my code
New Entry
byte[] SALT = GetRandomKey();
string password = Convert.ToBase64String((new Rfc2898DeriveBytes(txtPassword.Text, SALT)).GetBytes(20));
Session["test"] = password;
Session["salt"] = Convert.ToBase64String(SALT);
Validating
string HASHEDPASSWORD = Session["test"];
string SALT = Session["salt"];
string ouput = Convert.ToBase64String((new Rfc2898DeriveBytes(password, Encoding.Unicode.GetBytes(SALT))).GetBytes(20));
ltrResult.Text = HASHEDPASSWORD.Equals(ouput) ? "EQUAL" : "NOT EQUAL";
Get RandomKey method
byte[] GetRandomKey()
{
byte[] secretkey = new Byte[64];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(secretkey);
return secretkey;
}
Or Convert.FromBase64String instead of Encoding.Unicode.GetBytes.
You use Convert.ToBase64String when adding items, and Encoding.Unicode.GetBytes when retrieving it...
Use Encoding.Unicode.GetString when adding a new entry and your code should work, eg:
private static string GetString(byte[] bytes)
{
return Encoding.Unicode.GetString(bytes);
}
private static byte[] GetBytes(string value)
{
return Encoding.Unicode.GetBytes(value);
}
Adding
byte[] salt = GetRandomKey();
byte[] hash = new Rfc2898DeriveBytes(txtPassword.Text, salt)).GetBytes(20);
Session["test"] = GetString(hash);
Session["salt"] = GetString(salt);
Checking
byte[] hash = GetBytes(Session["test"]);
byte[] salt = GetBytes(Session["salt"]);
byte[] output = new Rfc2898DeriveBytes(password, salt).GetBytes(20);
ltrResult.Text = GetString(hash).Equals(GetString(output)) ? "EQUAL" : "NOT EQUAL";
You could store the salt as array of bytes in the session so that you don't get any differences of encoding when converting between strings and bytes:
byte[] SALT = GetRandomKey();
string password = Convert.ToBase64String((new Rfc2898DeriveBytes(txtPassword.Text, SALT)).GetBytes(20));
Session["test"] = password;
Session["salt"] = SALT;
and then to verify that a given password matches the hash you repeat the same procedure:
string HASHEDPASSWORD = Session["test"];
byte[] SALT = Session["salt"] as byte[];
string ouput = Convert.ToBase64String((new Rfc2898DeriveBytes(password, SALT)).GetBytes(20));
ltrResult.Text = HASHEDPASSWORD.Equals(ouput) ? "EQUAL" : "NOT EQUAL";

Categories