4

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.

3
  • 1
    Aren't there certain regulations you need to comply with? I'd expect storage of medical data to be regulated in most countries. Apr 24, 2012 at 9:06
  • 1
    I think you should remove your code from this question and write out your security-relevant protocols in English. You can post your code on Code Review for a code-level review. Apr 24, 2012 at 17:01
  • 2
    If you are in the US, you must look at HIPAA for guidance!
    – Rory Alsop
    Apr 24, 2012 at 18:21

1 Answer 1

3

Some criticisms of the cryptography: you should try to avoid generating crypto keys from passwords (or if you absolutely must, you should use PBKDF2 with a high iteration count, but understand that the resulting scheme will likely have poor security and may provide a false sense of security), and you need to apply a MAC to the encrypted data. I didn't follow some of the details of the crypto (e.g., the MediCare number bit). In general, rather than working out how to use crypto properly on your own, you'd probably be safer to just use GPG to encrypt the data.

But beyond the crypto --

I'm not certain that encrypting data so that only a single nurse can decrypt it is the right approach for medical settings. What if someone needs to access the medical data in an emergency, and the one nurse is not around? Perhaps instead of trying to limit access so severely, you may need a "break glass in case of emergency protocol" that allows any medical personnel to access the data -- combined with strong audit and scrutiny of the audit logs, to prevent misuse of the "break glass" feature.

Please be careful about storing medical data on a web service, to ensure that medical data is not inadvertently stored on the client side (where it might get leaked). Please make sure to send no-cache headers, so the client doesn't cache it; use SSL sitewide; and make sure not to make any confidential data available in a PDF or other format that will be downloaded to the client's machine.

Have you confirmed whether this system needs to be HIPAA compliant?

1
  • Thank you for the advice on the crypto. I wasnt sure where to look for good implementations of cryptography. I found this example on the web : codeproject.com/Articles/3118/… =
    – metraon
    Apr 24, 2012 at 15:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .