Using the Data Protection API (DPAPI)

A fairly common technique among teachers is to show the student how to do something the hard way, to make sure they understand the mechanics of what is going on, and then when they understand that, show them an easier way of doing things.

The Data Protection API (DPAPI) is no different. It provides a simplified API for protecting and unprotecting your data while removing the burden of explicitly generating and managing encryption keys from the developer.

When working with data protection, you need three things:

  • Data The data that you want to encrypt or decrypt.

  • Entropy Put simply, this is a random set of bytes used to add a measure of unpredictability to the encrypted output of your protected data. This is not required, but can come in handy.

  • Protection Scope When working directly with the cryptographic service providers, there is no sense of scope. With DPAPI, you can choose the scope in which you want the data protected. This means that you can choose to allow only a specific user to decrypt encrypted data or anyone on the machine. The following is a list of possible values for the protection scope:

CurrentUserData is associated with the user. Only code being executed by or on behalf of the user can decrypt the data.

LocalMachineThe data is protected at the machine level. Remote attempts to access the data will fail. This option is common in server-side enterprise applications.

One thing to keep in mind about the data protection API is that it is not designed for sending secure data from a source to a specific destination. It is designed to allow your application to encrypt data so that the data stored by your application will not be compromised. If you protect data using DPAPI, and then send the data to someone else, they will have no way of decrypting that data.

Both PKCS and DPAPI are extremely powerful encryption tools, but each one has a specific purpose. Knowing when to use PKCS and when to use DPAPI can save you countless hours of rewriting and troubleshooting.

Listing 15.1 is an illustration of how to encrypt and decrypt information using the Data Protection API. Run the code several times to convince yourself that the protection isn't session based and will work every time the protection scope matches the scope of the protected data.

When writing code with the Data Protection API, there are two different kinds of protection that you can use. You can choose to work with protected memory, which turns any array whose length is a multiple of 16 bytes into unreadable gibberish. When you lift the protection on that array, it becomes readable again. The main benefit of this is that when the array is protected, there is nowhere in memory that contains a decrypted copy of that data. This means that malicious attackers examining the memory used by your application or even trying to reverse engineer your application will not be able to locate the protected data in memory.

The second mode of working with the Data Protection API is more traditional. You pass it an array that you want encrypted, an entropy array, and a protection scope. As a return value, you are given an encrypted array of bytes. This method is more suitable for encrypting streams of data, files, and other longer strings. There is also no restriction that the protected data's size be a multiple of 16 as there is with memory protection.

The code in Listing 15.2 illustrates both memory protection and data protection using the Data Protection API.

Listing 15.2. Memory and Data Protection Using DPAPI

using System; using System.Security; using System.Security.Cryptography; using System.Collections.Generic; using System.Text; namespace DPAPIDemo { class Program { static void Main(string[] args) {     string messageToProtect = "aaaabbbbccccdddd";     byte[] messageArray = System.Text.ASCIIEncoding.ASCII.GetBytes(messageToProtect);     ProtectedMemory.Protect(messageArray, MemoryProtectionScope.SameLogon);     // this should print out 16 bytes of garbage     Console.WriteLine(System.Text.ASCIIEncoding.ASCII.GetString(messageArray)) ;     ProtectedMemory.Unprotect(messageArray, MemoryProtectionScope.SameLogon);     // now it should print just fine     Console.WriteLine(System.Text.ASCIIEncoding.ASCII.GetString(messageArray));     // protect data that will be used in a stream, in a file, etc     string fileMessage = "The purple turtle flies coach at dawn...";     byte[] fileMsgArray = System.Text.ASCIIEncoding.ASCII.GetBytes(fileMessage);     // some array of bytes for introduced entropy     byte[] entropy = { 0, 1, 3, 5, 7, 9 };     byte[] protectedMessage = ProtectedData.Protect(         fileMsgArray, entropy, DataProtectionScope.CurrentUser);     Console.WriteLine("Protected byte array:") ;     Console.WriteLine( System.Text.ASCIIEncoding.ASCII.GetString(protectedMessage));     byte[] clearMessage = ProtectedData.Unprotect(         protectedMessage, entropy, DataProtectionScope.CurrentUser);     Console.WriteLine("Unprotected/Decrypted Data:");     Console.WriteLine(ASCIIEncoding.ASCII.GetString(clearMessage));     Console.ReadLine(); } } } 

Make sure that when you create this application, you also add a reference to the System.Security assembly; otherwise, you won't be able to use the ProtectedMemory class or the DataProtection class.

When you compile and run the application, you will get output that looks like the output shown in Figure 15.3.

Figure 15.3. Output from the data protection sample.

Microsoft Visual C# 2005 Unleashed
Microsoft Visual C# 2005 Unleashed
ISBN: 0672327767
EAN: 2147483647
Year: 2004
Pages: 298 © 2008-2017.
If you may any questions please contact us: