0

I have a need to take sensitive information collected from a WPF PasswordBox. After the user enters this data, it needs to be encrypted using a System.Security.Cryptography.Rijendael encryptor object.

Currently, this code that is being modified takes a "plaintext" string and encrypts it and using the following code:

using (var rijAlg = Rijndael.Create())
{
    var salt = ... //Generated Salt
    rijAlg.KeySize = CryptographyHelper.ENCRYPTION_KEYSIZE;
    rijAlg.Key = encryptionKey; //This is an encryption key safely derived elsewhere.
    rijAlg.IV = salt;

    var encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
    using (var msEncrypt = new MemoryStream())
    {
        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        {
            using (var swEncrypt = new StreamWriter(csEncrypt))
            {
                swEncrypt.Write(plainText); //Plain Text value.
            }
            encrypted = msEncrypt.ToArray();
        }
    }
}

The value plainText above is actually a value that is passed into this encryption method. At the end of the method, the encrypted value is passed into Convert.ToBase64String(...) and the data is converted to Base64 and return from the encryption method.

My question is, how can I modify the above code to take a SecureString object representing the value that needs to be encrypted, securely encrypt the associated value, clean up the associated data and return the encrypted data as a string, just as I am the plainText value? Keep in mind, I'll need to derive a follow-up Decrypt(...) method which I hope can return a SecureString object, but figuring that out can be another question.

RLH
  • 15,230
  • 22
  • 98
  • 182
  • you could possibly derive from Rijndael or SymmetricAlgorithm and overload the signature to allow a string to be passed in to Create? https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael(v=vs.110).aspx –  Nov 30 '17 at 21:50
  • @Programmer Not quite sure what you mean. I especially wouldn't like to pass any string data coming from my SecureString. Part of the purpose of using the SecureString object is to prevent the creation of a .Net string since it's insecure. – RLH Nov 30 '17 at 21:58
  • Now that I read more on SecureString, I understand more of your concern. This is where the stack is not in your favor and requires character-at-a-time unmangaged source, https://msdn.microsoft.com/en-us/library/system.security.securestring(v=vs.110).aspx. Curious how you resolve this! –  Nov 30 '17 at 22:14

1 Answers1

0

I don't have the full code with me because I did this a long time ago. The only way I found to securely convert a SecureString to a hashed password was using a Stream by reading by one character at a time. Supposedly, by reading by one character you ensure that a memory dump wouldn't reveal the password.

You can see this answer for a sample implementation of reading by one character. If I were you, I'd create a custom Stream class that performs the Read into the Write of the CryptoStream. You could also free the unmanaged pointer on the Dispose of the Stream.

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
  • `Supposedly, by reading by one character you ensure that a memory dump wouldn't reveal the password.` Well, you are revealing it, you're just making it more difficult to find because it's for a shorter period of time, and the whole string isn't all in memory at the same time, making getting at it...less practical. – Servy Nov 30 '17 at 22:08
  • @Servy well, yes, you need to decrypt it sooner or later. – Camilo Terevinto Nov 30 '17 at 22:09
  • This is getting close to what I need. I may just need to marshal it as an unmanaged object and just read the bytes into the stream. I wasn't sure if that was the best approach, assuming there was already a provided way to encrypt-and-serialize data from a SecureString. – RLH Nov 30 '17 at 22:10
  • @CamiloTerevinto No, if you're pulling it from the secure string a character at a time, then someone can look at those characters, one at a time, while they're in plain text, and get the result. – Servy Nov 30 '17 at 22:11
  • @Servy while it's a `SecureString`, it's encrypted. If you want to use it, you need to decrypt it. One character at a time is the best I could get, can you think of anything more secure? – Camilo Terevinto Nov 30 '17 at 22:13
  • @CamiloTerevinto I'm not saying what you're suggesting is wrong. It's as good as you can get it, but it's important to understand what you're actually doing. The code doesn't ensure that the data is always encrypted, and never stored in plain text, it just minimizes the time that it's stored in plain text in the hope that an attacker won't be willing to put in the time and effort it would take to find it. That may well be enough for people, they just need to understand that that is what they're doing so that they can make the correct risk assessment. – Servy Nov 30 '17 at 22:16
  • @Servy Yes, that's exactly what I attempted to imply in my answer. You can read the unmarshaled string in the hope that noone gets to read it. But I don't really see any other way given how the `SecureString` works. It won't ever be completely secure though – Camilo Terevinto Nov 30 '17 at 22:19
  • I just want to be clear that I have no issue decrypting the string. I just don't want to decrypt it into a .Net string, which can be copied into memory and "float" around for a while in the GC, which is half the reason the SecureString even exists to begin with. Decrypting it into a lower-level, unmanaged string isn't a problem, so long as I can do my own garbage collection with the assurance that it's destroyed when I destroy it. – RLH Dec 01 '17 at 12:36