So you have written an application that stores some sensitive information about the user of the machine. But wait - how can you store that data securely? Popular answers might be using the various data encryption methods such as Rijndael (AES) or perhaps even RSA. Both of these solutions are tricky to implement and even more difficult to get right and most of the time this sort of data is going to stay resident on the machine and only used by the program - never transmitted over the wire. Because the aforementioned methods (et al.) are difficult, I've seen many programs that plainly store their sensitive user data on disk. Open to the world + prying eyes. Enter the Windows Data Protection API (DPAPI).
What is Windows Data Protection?
Introduced with Windows 2000, DPAPI is a pair of functions that provide data protection services at the operating system level. The DPAPI is a password based mechanism - it requires a password in order for protection to work. The major disadvantage is that the data under protection is reliant upon the password provided. Because DPAPI is focused on providing protection for users and requires a password to provide this protection, it logically uses the user's logon password for protection.
More about the DPAPI can be found here: http://msdn.microsoft.com/en-us/library/ms995355.aspx
How do I use it?
DPAPI makes it easy to quickly protect user-level application data without the hassle of implementing any of the methods described at the beginning of the thread. Using it is very easy - for those who are familiar with Win32 programming in C or C++, I'll describe how to use the DPAPI in your native tongue. For those who are more familiar with the .NET, I've provided a C# example. For the record, .NET has a wrapper over the top of DPAPI that makes using it much simpler than the unmanaged world in C or C++.
C# and the .NET Framework: DPAPI
We'll start with the easy part first, shall we? Using the DPAPI in C# from .NET is quite a lot easier than C or C++ in the unmanaged Win32 world.
The .NET folks have been kind enough to wrap up this unmanaged functionality in a managed type called the ProtectedData class. This class is very simple and contains only two methods, ProtectedData.Protect and ProtectedData.Unprotect
In this example I will show you how you can encrypt a Unicode string. The string that we will encrypt will be "I have less headaches in the managed world!". To begin, lets describe the prototypes for the two methods we will be using:
CryptProtectData
CryptUnprotectData
Data Encryption
Encrypting data is done in two easy steps: Reterieve the bytes for the data we wish to protect and call the ProtectedData.Protect method.
Data Decryption
Encrypting data was so simple, and decryption is no different:
C and C++: DPAPI
The two functions from Crypt32.dll (and thus Crypt32.lib for the linker) that will perform the protect and unprotect for our data are CryptProtectData and CryptUnprotectData, respectively.
CryptProtectData
CryptUnprotectData
Now that we have got the prototypes of these two functions out of the way, lets jump in to actually encrypting a piece of data in our application. We'll be dealing with a new stucture, DATA_BLOB. This structure simply contains an array of bytes and also the length of the byte array. We can supply *any* data into the byte array, however for this thread we will deal with encrypting and decrypting an ANSI string - we'll use the string "OCN is the best", for lack of anything better! The structure is defined as follows:
Data Encryption
To start with, we'll need to declare two DATA_BLOB structures: One that contains the bytes to be encrypted and one that contains the encrypted bytes from the CryptProtectData function:
Pretty simple so far right? OK let us go ahead and initialize the inputBlob with the data to be encrypted:
NOTE: When you have finished using sensitive information, clear it from memory by calling the SecureZeroMemory function.
Next we simply call the CryptProtectData function, passing in a pointer to our input structure, some flags and a pointer to the blob structure that will received the data in its encrypted form:
For more information on parameters for CryptProtectData the function, see here: http://msdn.microsoft.com/en-us/library/aa380261%28VS.85%29.aspx
Data Decryption
Decrypting the data is just as easy as encrypting it. As most of the explanation work has been done in the section on encryption, I'll include the code sample to decrypt the data directly:
NOTE: When you have finished using sensitive information, clear it from memory by calling the SecureZeroMemory function.
We'll start off with our DATA_BLOB structures:
For more information on parameters for CryptUnprotectData the function, see here: http://msdn.microsoft.com/en-us/library/aa380882%28v=vs.85%29.aspx
What is Windows Data Protection?
Introduced with Windows 2000, DPAPI is a pair of functions that provide data protection services at the operating system level. The DPAPI is a password based mechanism - it requires a password in order for protection to work. The major disadvantage is that the data under protection is reliant upon the password provided. Because DPAPI is focused on providing protection for users and requires a password to provide this protection, it logically uses the user's logon password for protection.
More about the DPAPI can be found here: http://msdn.microsoft.com/en-us/library/ms995355.aspx
How do I use it?
DPAPI makes it easy to quickly protect user-level application data without the hassle of implementing any of the methods described at the beginning of the thread. Using it is very easy - for those who are familiar with Win32 programming in C or C++, I'll describe how to use the DPAPI in your native tongue. For those who are more familiar with the .NET, I've provided a C# example. For the record, .NET has a wrapper over the top of DPAPI that makes using it much simpler than the unmanaged world in C or C++.
C# and the .NET Framework: DPAPI
We'll start with the easy part first, shall we? Using the DPAPI in C# from .NET is quite a lot easier than C or C++ in the unmanaged Win32 world.
The .NET folks have been kind enough to wrap up this unmanaged functionality in a managed type called the ProtectedData class. This class is very simple and contains only two methods, ProtectedData.Protect and ProtectedData.Unprotect
In this example I will show you how you can encrypt a Unicode string. The string that we will encrypt will be "I have less headaches in the managed world!". To begin, lets describe the prototypes for the two methods we will be using:
CryptProtectData
public static byte[] Protect(
byte[] userData,
byte[] optionalEntropy,
DataProtectionScope scope
)
CryptUnprotectData
public static byte[] Unprotect(
byte[] encryptedData,
byte[] optionalEntropy,
DataProtectionScope scope
)
Data Encryption
Encrypting data is done in two easy steps: Reterieve the bytes for the data we wish to protect and call the ProtectedData.Protect method.
Code:
string plainText = "I have less headaches in the managed world!";
byte[] plainTextBytes = Encoding.Unicode.GetBytes( plainText );
/* Call the method. The return value is a byte array of ENCRYPTED data */
byte[] encrypted = ProtectedData.Protect(
plainTextBytes, /* our byte array to be encrypted */
null, /* we can pass additional entropy in the form of a byte array (optional) */
DataProtectionScope.CurrentUser /* can also pass DataProtectionScope.LocalMachine */
);
/* Here we might write out the bytes in "encypted" to disk */
Data Decryption
Encrypting data was so simple, and decryption is no different:
Code:
byte[] encrypted = null; /* this is the ENCRYPTED data created by ProtectedData.Protect. if you saved this out to disk, then read the bytes back in from disk into a byte array */
/* Call the method. The return value is a byte array of DECRYPTED data */
byte[] encrypted = ProtectedData.Unprotect(
encrypted , /* our byte array to be decrypted */
null, /* if you set additional entropy in ProtectedData.Protect, you must supply the same entropy here for decryption
DataProtectionScope.CurrentUser /* can also pass DataProtectionScope.LocalMachine */
);
C and C++: DPAPI
The two functions from Crypt32.dll (and thus Crypt32.lib for the linker) that will perform the protect and unprotect for our data are CryptProtectData and CryptUnprotectData, respectively.
CryptProtectData
BOOL WINAPI CryptProtectData(
__in DATA_BLOB *pDataIn,
__in LPCWSTR szDataDescr,
__in DATA_BLOB *pOptionalEntropy,
__in PVOID pvReserved,
__in_opt CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct,
__in DWORD dwFlags,
__out DATA_BLOB *pDataOut
);
CryptUnprotectData
BOOL WINAPI CryptUnprotectData(
__in DATA_BLOB *pDataIn,
__out_opt LPWSTR *ppszDataDescr,
__in_opt DATA_BLOB *pOptionalEntropy,
__in PVOID pvReserved,
__in_opt CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct,
__in DWORD dwFlags,
__out DATA_BLOB *pDataOut
);
Now that we have got the prototypes of these two functions out of the way, lets jump in to actually encrypting a piece of data in our application. We'll be dealing with a new stucture, DATA_BLOB. This structure simply contains an array of bytes and also the length of the byte array. We can supply *any* data into the byte array, however for this thread we will deal with encrypting and decrypting an ANSI string - we'll use the string "OCN is the best", for lack of anything better! The structure is defined as follows:
Code:
typedef struct _CRYPTOAPI_BLOB {
DWORD cbData; /* Length of the byte array pointed to by pbData */
BYTE *pbData; /* Pointer to a byte array */
} DATA_BLOB, *PDATA_BLOB
Data Encryption
To start with, we'll need to declare two DATA_BLOB structures: One that contains the bytes to be encrypted and one that contains the encrypted bytes from the CryptProtectData function:
Code:
DATA_BLOB inputBlob;
DATA_BLOB outputBlob;
Pretty simple so far right? OK let us go ahead and initialize the inputBlob with the data to be encrypted:
Code:
inputBlob.pbData = ( BYTE* ) "OCN is the best"; /* cast our ANSI character array directly to a BYTE array */
inputBlob.cbSize = strlen( ( char* ) inputBlob.pbData ) + 1;
NOTE: When you have finished using sensitive information, clear it from memory by calling the SecureZeroMemory function.
Next we simply call the CryptProtectData function, passing in a pointer to our input structure, some flags and a pointer to the blob structure that will received the data in its encrypted form:
Code:
BOOL result = CryptProtectData(
&inputBlob, /* pDataIn: pointer to our input DATA_BLOB */
NULL, /* szDataDescr: this is mandatory in Windows 2000 only */
NULL, /* pOptionalEntropy: we don't supply any additional entropy */
NULL, /* pvReserved: reserved parameter */
NULL, /* pPromptStruct: set to NULL as we do not wish to display any UI to the user */
0, /* dwFlags: set to zero to use default. you can pass in CRYPTPROTECT_LOCAL_MACHINE to associate the encrypted data with the current computer instead of user */
&outputBlob /* pDataOut: recieves the data in its encrypted form */
);
if ( result )
{
/*
* The function succeeded - everybody is happy. Here we can use
* outputBlob, and we may wish to write the bytes from outputBlob.pbData to disk or something
*/
/* NOTE: You MUST call LocalFree on outputBlob.pbData after you have finished using it! */
}
For more information on parameters for CryptProtectData the function, see here: http://msdn.microsoft.com/en-us/library/aa380261%28VS.85%29.aspx
Data Decryption
Decrypting the data is just as easy as encrypting it. As most of the explanation work has been done in the section on encryption, I'll include the code sample to decrypt the data directly:
NOTE: When you have finished using sensitive information, clear it from memory by calling the SecureZeroMemory function.
We'll start off with our DATA_BLOB structures:
Code:
DATA_BLOB encrypted = {0}; /* this is the ENCRYPTED data created by CryptProtectData. if you saved this out to disk, then read the bytes back in from disk into the pbData member. */
DATA_BLOB decrypted;
Code:
BOOL result = CryptUnprotectData(
&encrypted, /* pDataIn: pointer to the DATA_BLOB that holds the encrypted data */
NULL, /* ppszDataDescr: if you set a description using CryptProtectData, you can retrieve it here */
NULL, /* pOptionalEntropy: if you set additional entropy in CryptProtectData, you must supply the same entropy here for decryption */
NULL, /* pvReserved: reserved parameter */
NULL, /* pPromptStruct: set to NULL as we do not wish to display any UI to the user */
0, /* dwFlags: set to zero to use default */
&decrypted /* pDataOut: receives the decrypted (plaintext) data */
);
if ( result )
{
/* The function succeeded - here we can use decrypted.pbData */
/* NOTE: You MUST call LocalFree on decrypted.pbData are you have finished using it! */
}
For more information on parameters for CryptUnprotectData the function, see here: http://msdn.microsoft.com/en-us/library/aa380882%28v=vs.85%29.aspx





