Search code examples
c#encryptiondpapi

Why not use DPAPI for encrypting all settings instead of only encrypting main password?


In my application I need to encrypt various settings and a password. So far I have been doing this with the RijndaelManaged class etc. as seen here:

/// <summary>
/// Encrypts the string defined by parameter "data" and returns the encrypted data as string
/// </summary>
/// <param name="data">Data to be encrypted</param>
/// <returns>The encrypted data</returns>
public static string Encrypt(string data)
        {
            if (data == "")
                return "";

            byte[] bytes = Encoding.ASCII.GetBytes(initVector);
            byte[] rgbSalt = Encoding.ASCII.GetBytes(saltValue);
            byte[] buffer = Encoding.UTF8.GetBytes(data);
            byte[] rgbKey = new PasswordDeriveBytes(passPhrase, rgbSalt, hashAlgorithm, passwordIterations).GetBytes(keySize / 8);
            RijndaelManaged managed = new RijndaelManaged();
            managed.Mode = CipherMode.CBC;
            ICryptoTransform transform = managed.CreateEncryptor(rgbKey, bytes);
            MemoryStream memStream = new MemoryStream();
            CryptoStream cryStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write);
            cryStream.Write(buffer, 0, buffer.Length);
            cryStream.FlushFinalBlock();
            byte[] inArray = memStream.ToArray();
            memStream.Close();
            cryStream.Close();
            return Convert.ToBase64String(inArray);
        }

The usual problem is that I need to store the passPhrase (and saltValue) somewhere. To store the passPhrase in a sequre way I came across the DPAPI Protect() and Unprotect() classes as seen here:

/// <summary>
/// Use Windows' "Data Protection API" to encrypt the string defined by parameter "clearText".
/// To decrypt, use the method "Unprotect"
/// http://www.thomaslevesque.com/2013/05/21/an-easy-and-secure-way-to-store-a-password-using-data-protection-api/
/// </summary>
/// <param name="clearText"></param>
/// <param name="optionalEntropy"></param>
/// <param name="scope"></param>
/// <returns></returns>
        public static string Protect(string clearText, string optionalEntropy = null, DataProtectionScope scope = DataProtectionScope.CurrentUser)
        {
            if (clearText == null)
                throw new ArgumentNullException("The parameter \"clearText\" was empty");
            byte[] clearBytes = Encoding.UTF8.GetBytes(clearText);
            byte[] entropyBytes = string.IsNullOrEmpty(optionalEntropy) ? null : Encoding.UTF8.GetBytes(optionalEntropy);
            byte[] encryptedBytes = ProtectedData.Protect(clearBytes, entropyBytes, scope);
            return Convert.ToBase64String(encryptedBytes);
        }

My question is the following: With the DPAPI I can now store the passPhrase for my encryption method in a secure way, but why shouldn’t I simply use the DPAPI to encrypt all my setting directly? Would this fill up the DPAPI with an amount of data, that it is not meant for?

My idea was instead of doing the following:

string setting1 = ”mySettingValue1”;
StoreSettingSomewhere(Encrypt(setting1));

I could do the following:

string setting1 = ”mySettingValue1”;
StoreSettingSomewhere(Protect(setting1, bla bla bla));

I know that when using DPAPI I must decrypt on the same machine (or with the same user), but this would not be a problem in my case.

Any help is appreciated!


Solution

  • The Data Protection API hands you back an opaque blob that is the encrypted (and salted, and hashed) result of what you wanted encrypted.

    You cannot "fill up" the DP API - you would only "fill up" yourself (as the blobs are somewhat large; but they do internally contain everything need to later verify the encrypted data).

    The down-side of the Data Protection API is that you have to be logged in as the user; and you cannot share settings between users (unless you used the Machine-wide scope).