Following code snippet provides methods for strong Encryption/Decryption and hash implementation (as compare to last code)
(Tip: Not better for performance)
/// <summary>
/// Strong Encryption/Decryption methods and hash implementation
/// </summary>
internal class StrongSecurity {
private const int SHA1_HASH_SIZE = 160; // Size of hash without salt. Do not change this size.
private static string HASH_ALGORITHM = "SHA1";// can be "MD5"
private static int PASSWORD_ITERATIONS = 1;
private static int KEY_SIZE = 128;
/// <summary>
/// Decrypt Input Message
/// </summary>
/// <param name="strEncryptedMessage">Encrypted Message</param>
/// <param name="btSalt">Salt</param>
/// <param name="strKey">Key</param>
/// <param name="strHashAlgorithm">Hash Algorithm</param>
/// <returns>Decrypted Message</returns>
internal static string decryptMessage(string strEncryptedMessage, byte[] btSalt,string strKey) {
PasswordDeriveBytes password = null;
RijndaelManaged symmetricKey = null;
ICryptoTransform decryptor = null;
MemoryStream memoryStream = null;
CryptoStream cryptoStream = null;
try{
// Convert strings defining encryption key characteristics into byte arrays.
byte[] btIV = btSalt;
byte[] btEncryptedDataBytes = Convert.FromBase64String(strEncryptedMessage);
//Create password using salt and key
password = new PasswordDeriveBytes(
strKey,
btSalt,
HASH_ALGORITHM,
PASSWORD_ITERATIONS);
// Use the password to generate pseudo-random bytes for the encryption
// key. Specify the size of the key in bytes (instead of bits).
byte[] keyBytes = password.GetBytes(KEY_SIZE / 8);
symmetricKey = new RijndaelManaged();
// Set encryption mode to Cipher Block Chaining (CBC)
symmetricKey.Mode = CipherMode.CBC;
// Generate encryptor from the existing key bytes and IV
decryptor = symmetricKey.CreateDecryptor(
keyBytes,
btIV);
// Memory stream to hold encrypted data.
memoryStream = new MemoryStream(btEncryptedDataBytes);
// Define cryptographic stream
cryptoStream = new CryptoStream(memoryStream,
decryptor,
CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[btEncryptedDataBytes.Length];
// Start decrypting.
int decryptedByteCount = cryptoStream.Read(plainTextBytes,
0,
plainTextBytes.Length);
// Convert decrypted data into a string.
string plainText = Encoding.UTF8.GetString(plainTextBytes,
0,
decryptedByteCount);
// Return decrypted string.
return plainText;
}
finally{
password = null;
symmetricKey = null;
decryptor = null;
memoryStream.Close();
memoryStream = null;
cryptoStream.Close();
cryptoStream = null;
}
}
/// <summary>
/// Encrypts the Message
/// </summary>
/// <param name="strMessage">Message to Encrypt</param>
/// <param name="btSalt">Salt</param>
/// <param name="strKey">Key</param>
/// <param name="strHashAlgorithm">Hash Algorithm</param>
/// <returns>Encrypted Message</returns>
internal static string encryptMessage(string strMessage, byte[] btSalt, string strKey) {
PasswordDeriveBytes password = null;
RijndaelManaged symmetricKey = null;
ICryptoTransform encryptor = null;
MemoryStream memoryStream = null;
CryptoStream cryptoStream = null;
try{
// Convert strings into byte arrays.
byte[] btIV = btSalt;
byte[] btInputData = Encoding.UTF8.GetBytes(strMessage);
// Create password using salt,password phrase
password = new PasswordDeriveBytes(
strKey,
btSalt,
HASH_ALGORITHM,
PASSWORD_ITERATIONS);
// Use the password to generate pseudo-random bytes for the encryption
// key. Specify the size of the key in bytes (instead of bits).
byte[] keyBytes = password.GetBytes(KEY_SIZE / 8);
symmetricKey = new RijndaelManaged();
// Set encryption mode to Cipher Block Chaining (CBC)
symmetricKey.Mode = CipherMode.CBC;
// Generate encryptor from the existing key bytes and IV
encryptor = symmetricKey.CreateEncryptor(
keyBytes,
btIV);
// Memory stream to hold encrypted data.
memoryStream = new MemoryStream();
// Define cryptographic stream
cryptoStream = new CryptoStream(memoryStream,
encryptor,
CryptoStreamMode.Write);
// Start encrypting.
cryptoStream.Write(btInputData, 0, btInputData.Length);
// Finish encrypting.
cryptoStream.FlushFinalBlock();
// Convert our encrypted data from a memory stream into a byte array.
byte[] btEncryptedDataBytes = memoryStream.ToArray();
// Convert encrypted data into a base64-encoded string.
string strEncryptedData = Convert.ToBase64String(btEncryptedDataBytes);
// Return encrypted string.
return strEncryptedData;
}
finally{
password = null;
symmetricKey = null;
encryptor = null;
memoryStream.Close();
memoryStream = null;
cryptoStream.Close();
cryptoStream = null;
}
}
/// <summary>
/// Verifies Hash received from the client
/// </summary>
/// <param name="hashValue">Hash Value to Verify</param>
/// <param name="strKey">Server side Key to generate the hash</param>
/// <returns>If hash is correct then return the salt bytes else null</returns>
internal static byte[] VerifyHash(string strHashValue,string strKey) {
int intHashSizeInBits, intHashSizeInBytes;
// Convert base64-encoded hash value into a byte array.
byte[] btHashWithSalt = Convert.FromBase64String(strHashValue);
// Size of hash without salt.
intHashSizeInBits = SHA1_HASH_SIZE;
// Convert size of hash from bits to bytes.
intHashSizeInBytes = intHashSizeInBits / 8;
// Make sure that the specified hash value is long enough.
if (btHashWithSalt.Length < intHashSizeInBytes)
return null;
// Allocate array to hold original salt bytes retrieved from hash.
byte[] btSalt = new byte[btHashWithSalt.Length -
intHashSizeInBytes];
// Copy salt from the end of the hash to the new array.
for (int i=0; i < btSalt.Length; i++)
btSalt[i] = btHashWithSalt[intHashSizeInBytes + i];
// Compute a new hash string.
string strExpectedHashString =
computeHash(btSalt,strKey);
// If the computed hash matches the specified hash,
// the secrete key must be correct.
if (strHashValue == strExpectedHashString)
return btSalt;
else
return null;
}
/// <summary>
/// Computes hash of the key and salt
/// </summary>
/// <param name="btSalt">Salt</param>
/// <param name="strKey">Key</param>
/// <returns>Computed Hash</returns>
internal static string computeHash(byte [] btSalt, string strKey) {
// Convert plain text into a byte array.
byte[] plainTextBytes = Encoding.UTF8.GetBytes(strKey);
// Allocate array, which will hold plain text and salt.
byte[] plainTextWithSaltBytes =
new byte[plainTextBytes.Length + btSalt.Length];
// Copy plain text bytes into resulting array.
for (int i=0; i < plainTextBytes.Length; i++)
plainTextWithSaltBytes[i] = plainTextBytes[i];
// Append salt bytes to the resulting array.
for (int i=0; i < btSalt.Length; i++)
plainTextWithSaltBytes[plainTextBytes.Length + i] = btSalt[i];
// Specify hashing algorithm
HashAlgorithm hash = new SHA1Managed();
// Compute hash value of our plain text with appended salt.
byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);
// Create array which will hold hash and original salt bytes.
byte[] hashWithSaltBytes = new byte[hashBytes.Length +
btSalt.Length];
// Copy hash bytes into resulting array.
for (int i=0; i < hashBytes.Length; i++)
hashWithSaltBytes[i] = hashBytes[i];
// Append salt bytes to the result.
for (int i=0; i < btSalt.Length; i++)
hashWithSaltBytes[hashBytes.Length + i] = btSalt[i];
// Convert result into a base64-encoded string.
string hashValue = Convert.ToBase64String(hashWithSaltBytes);
// Return the result.
return hashValue;
}
}