else Console.WriteLine('Incorrect password');
}
The main difference is that the hash value for MD5 is 128 bits in length.
Salted Hash
With hashing, you simply store the hash value of a user's password in the database. However, if two users use identical passwords, the hash values for these two passwords will be also identical. Imagine a hacker seeing that the two hash values are identical; it would not be hard for him to guess that the two passwords must be the same. For example, users often like to use their own names or birth dates or common words found in the dictionary as passwords. So, hackers often like to use dictionary attacks to correctly guess users' passwords. To reduce the chance of dictionary attacks, you can add a 'salt' to the hashing process so that no two identical passwords can generate the same hash values. For instance, instead of hashing a user's password, you hash his password together with his other information, such as email address, birth date, last name, first name, and so on. The idea is to ensure that each user will have a unique password hash value. While the idea of using the user's information as a salt for the hashing process sounds good, it is quite easy for hackers to guess. A better approach is to randomly generate a number to be used as the salt and then hash it together with the user's password.
The following function, Salted_Hashing_SHA1()
, generates a random number using the RNGCryptoServiceProvider
class, which returns a list of randomly generated bytes (the salt). It then combines the salt with the original password and performs a hash on it.
static void Salted_Hashing_SHA1() {
//---Random Number Generator---
byte[] salt = new byte[8];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(salt);
//---ask the user to enter a password---
Console.Write('Please enter a password: ');
string password = Console.ReadLine();
//---add the salt to the password---
password += ASCIIEncoding.ASCII.GetString(salt);
//---hash the password---
byte[] data = ASCIIEncoding.ASCII.GetBytes(password);
SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
byte[] passwordHash;
passwordHash = sha.ComputeHash(data);
//---ask the user to enter the same password again---
Console.Write('Please enter password again: ');
password = Console.ReadLine();
Console.WriteLine(ASCIIEncoding.ASCII.GetString(salt));
//---adding the salt to the second password---
password += ASCIIEncoding.ASCII.GetString(salt);
//---hash the second password and compare it with the first---
data = ASCIIEncoding.ASCII.GetBytes(password);
if (ASCIIEncoding.ASCII.GetString(passwordHash) ==
ASCIIEncoding.ASCII.GetString(sha.ComputeHash(data)))
Console.WriteLine('Same password');
else Console.WriteLine('Incorrect password');
}
If you use salted hash for storing passwords, the salt used for each password should be stored separately from the main hash database so that hackers do not have a chance to obtain it easily.
Encryption and Decryption
Hashing is a one-way process, which means that once a value is hashed, you can't obtain its original value by reversing the process. This characteristic is particularly well suited for authentications as well as digitally signing a document.
In reality, there are many situations that require information to be performed in a two-way process. For example, to send a secret message to a recipient, you need to 'scramble' it so that only the recipient can see it. This process of scrambling is known as
Symmetric encryption is also sometimes known as
Despite the potential weakness of private key encryption, it is very easy to implement and, computationally, it does not take up too many resources.
For private key encryption (symmetric), the .NET Framework supports the DES, RC2, Rijndael, and TripleDES algorithms.
To see how symmetric encryption works, you will use the RijndaelManaged
class in the following SymmetricEncryption()
function. Three parameters are required — the string to be encrypted, the private key, and the initialization vector (IV). The IV is a random number used in the encryption process to ensure that no two strings will give the same cipher text (the encrypted text) after the encryption process. You will need the same IV later on when decrypting the cipher text.
To perform the actual encryption, you initialize an instance of the CryptoStream
class with a MemoryStream
object, the cryptographic transformation to perform on the stream, and the mode of the stream (Write
for encryption and Read
for decryption):
static string SymmetricEncryption(string str, byte[] key, byte[] IV) {
MemoryStream ms = new MemoryStream();
try {
//---creates a new instance of the RijndaelManaged class---
RijndaelManaged RMCrypto = new RijndaelManaged();
//---creates a new instance of the CryptoStream class---
CryptoStream cryptStream = new CryptoStream(
ms, RMCrypto.CreateEncryptor(key, IV), CryptoStreamMode.Write);
StreamWriter sWriter = new StreamWriter(cryptStream);
//---encrypting the string---
sWriter.Write(str);
sWriter.Close();
cryptStream.Close();
//---return the encrypted data as a string---
return System.Convert.ToBase64String(ms.ToArray());
} catch (Exception ex) {