I am giving a free consultation for a non profit organisation that wants a simple system to manage multiple groups with a schedule component, etc. and also manage the medical informations of the kids. Its all in an Excel file but the problem is, it is not very convenient for the nurse. So, I am building this ASP.NET application and I hit a wall when attempting the encryption of sensitive data. I have writen this C# code following books and recommendations of this website. I am doing it right?
public partial class SymmetricEncryptionWithPassword : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
/// <summary>
/// Handles the OnClick event of the Encrypt control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void Encrypt_OnClick(object sender, EventArgs e)
{
// Initialize the algorithm from the values on the page.
SymmetricAlgorithm symmetricAlgorithm = new AesManaged();
byte[] generatedKey = null;
byte[] generatedIV = null;
TextBox salt = (TextBox)DetailsView1.FindControl("TextBox2");
TextBox ssn = (TextBox)DetailsView1.FindControl("TextBox1");
salt.Text = Convert.ToBase64String(GenerateSalt());
GetKeyAndIVFromPasswordAndSalt(this.password.Text, Convert.FromBase64String(salt.Text), symmetricAlgorithm, ref generatedKey, ref generatedIV);
symmetricAlgorithm.Key = generatedKey;
symmetricAlgorithm.IV = generatedIV;
ICryptoTransform encryptor = symmetricAlgorithm.CreateEncryptor(symmetricAlgorithm.Key, symmetricAlgorithm.IV);
// Create the streams used for encryption.
MemoryStream memoryStream = new MemoryStream();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
byte[] plainTextAsBytes = new UTF8Encoding(false).GetBytes(ssn.Text);
cryptoStream.Write(plainTextAsBytes, 0, plainTextAsBytes.Length);
}
symmetricAlgorithm.Clear();
byte[] encryptedData = memoryStream.ToArray();
ssn.Text = Convert.ToBase64String(encryptedData);
}
/// <summary>
/// Handles the OnClick event of the Decrypt control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void Decrypt_OnClick(object sender, EventArgs e)
{
// Initialize the algorithm from the values on the page.
SymmetricAlgorithm symmetricAlgorithm = new AesManaged();
byte[] generatedKey = null;
byte[] generatedIV = null;
TextBox txt = (TextBox)DetailsView1.FindControl("TextBox2");
TextBox txt1 = (TextBox)DetailsView1.FindControl("TextBox1");
GetKeyAndIVFromPasswordAndSalt(this.password.Text, Convert.FromBase64String(txt.Text), symmetricAlgorithm, ref generatedKey, ref generatedIV);
symmetricAlgorithm.Key = generatedKey;
symmetricAlgorithm.IV = generatedIV;
ICryptoTransform decryptor = symmetricAlgorithm.CreateDecryptor(symmetricAlgorithm.Key, symmetricAlgorithm.IV);
// Create the streams used for encryption.
MemoryStream memoryStream = new MemoryStream();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
{
byte[] encryptedDataAsBytes = Convert.FromBase64String(txt1.Text);
cryptoStream.Write(encryptedDataAsBytes, 0, encryptedDataAsBytes.Length);
}
symmetricAlgorithm.Clear();
byte[] decryptedData = memoryStream.ToArray();
txt1.Text = Encoding.UTF8.GetString(decryptedData);
}
/// <summary>
/// Generates a cryptographically secure block of data suitable for salting hashes.
/// </summary>
/// <returns>A cryptographically secure block of data suitable for salting hashes.</returns>
private static byte[] GenerateSalt()
{
const int MinSaltSize = 8;
const int MaxSaltSize = 16;
// Generate a random number to determine the salt size.
Random random = new Random();
int saltSize = random.Next(MinSaltSize, MaxSaltSize);
// Allocate a byte array, to hold the salt.
byte[] saltBytes = new byte[saltSize];
// Initialize the cryptographically secure random number generator.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
// Fill the salt with cryptographically strong byte values.
rng.GetNonZeroBytes(saltBytes);
return saltBytes;
}
/// <summary>
/// Generates a key and IV from password and salt.
/// </summary>
/// <param name="password">The password.</param>
/// <param name="salt">The salt used in generation.</param>
/// <param name="symmetricAlgorithm">The symmetric algorithm to generate the key and IV for.</param>
/// <param name="key">The generated key.</param>
/// <param name="iv">The generated IV.</param>
private static void GetKeyAndIVFromPasswordAndSalt(string password, byte[] salt, SymmetricAlgorithm symmetricAlgorithm, ref byte[] key, ref byte[] iv)
{
Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt);
key = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.KeySize / 8);
iv = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.BlockSize / 8);
}
}
The code works when I input data; it is encrypted in the database and the proper salt is stored with the values. When I want it decrypted in a text box, it works properly.
My idea is: the nurse enters data in the form, she encrypt it with a password a encrypted MediCare number and a salt value are generated by the server and then sended to the SQL server, the MediCare is encrypted in the table who looks like this.
Medicare_ID - int (Primary Key)
Medicar_Number - (varchar(MAX))
Medicare_SALT - (varchar(MAX))
The decryption password is not stored in the database, and I did this on purpose.
I am just not sure if I followed the best practice here. Can my information be easily decrypted if the physical server got stolen? They still need the password to decrypt the data, right? We sometimes need to get it decrypted in case of an emergency. Is my decryption method secure? Another concern is that I use 1and1 shared webhosting.
I have set up some more security measures e.g., SSL will be activated on the website so the informations are encrypted and prevent eye dropping.
I will ensure the connections strings and inputs are sanitized just in case but in theory only 1-2 managers or nurses will ever manipulate the data.
The website access is protected with a username and password with a login control that I borrowed from Visual studio 2010.