Partilhar via


Windows Data Protection

 

NAI Labs, Network Associates, Inc.

October 2001

Summary: This article discusses how to use Data Protection application programming interface (DPAPI) and how DPAPI operates in Microsoft Windows XP.

Contents

Introduction
DPAPI Architecture
Using DPAPI
DPAPI Security
Contributors
References

Introduction

Starting with Microsoft® Windows® 2000, the operating system began to provide a data protection application-programming interface (API). This Data Protection API (DPAPI) is a pair of function calls that provide operating system-level data protection services to user and system processes. By operating system-level, we mean a service that is provided by the operating system itself and does not require any additional libraries. By data protection, we mean a service that provides confidentiality of data by using encryption. Because data protection is part of the operating system, every application can now secure data without needing any specific cryptographic code other than the necessary function calls to DPAPI. These calls are two simple functions with various options to modify DPAPI behavior. Overall, DPAPI is an easy-to-use service that will benefit developers who must provide protection for sensitive application data, such as passwords and private keys.

DPAPI is a password-based data protection service. It requires a password to provide protection. The drawback, of course, is that all protection provided by DPAPI rests on the password provided. This is offset by DPAPI using proven cryptographic routines, specifically the strong Triple-DES algorithm, and strong keys, which we'll cover in more detail later. 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.

To familiarize you with DPAPI, this article will first discuss how DPAPI works, including interactions between applications, DPAPI, and other system features. It will also detail how to use DPAPI, specifically for user applications. Finally, it will discuss the security of DPAPI, paying particular attention to how DPAPI generates and uses cryptographic keys. While DPAPI appeared in Windows 2000, this article will only discuss how to use DPAPI and how DPAPI operates in Windows XP.

DPAPI Architecture

The public DPAPI interfaces are part of Crypt32.dll and are available for any user process that has loaded it. This DLL is part of CryptoAPI; application developers can assume that all Windows systems have this DLL available.

Applications either pass plaintext data to DPAPI and receive an opaque protected data BLOB back, or pass the protected data BLOB to DPAPI and receive the plaintext data back. Figure 1, below, shows these two operations.

ms995355.windataprotection-dpapi-fig1(en-us,MSDN.10).gif

Figure 1. DPAPI is a simple API

The protected data BLOB is an opaque structure because, in addition to the encrypted data, it also contains data to allow DPAPI to unprotect it. Being opaque, application developers do not need to parse or understand the format at all. An important point to remember is that DPAPI merely applies cryptographic protection to the data. It does not store any of the protected data; therefore applications calling DPAPI must implement their own storage of the protected data.

When an application calls one of the DPAPI functions, the functions make a local RPC call to the Local Security Authority (LSA). The LSA is a system process that starts on boot and runs until the computer is shut down. These local RPC calls never traverse the network, so all data remains on the local machine. The endpoints of these RPC calls then call DPAPI private functions to protect or unprotect the data. These functions then call back into CryptoAPI, by using Crypt32.dll, for the actual encryption or decryption of the data in the security context of the LSA. The functions run in the security context of the LSA so that security audits can be generated.

The LSA also contains system-level functions for using DPAPI. These functions are available to any thread running inside the LSA and only to those threads. This is because the functions provide additional options for LSA threads, specifically to allow LSA threads to protect user data that cannot be unprotected by non-LSA threads that are using DPAPI, such as user applications.

Keys and Passwords in DPAPI

DPAPI is focused on providing data protection for users. Because DPAPI requires a password to provide protection, the logical step is for DPAPI to use a user's logon password, which it does, in a way. DPAPI actually uses the user's logon credential. In a typical system, in which the user logs on with a password, the logon credential is simply a hash of the user's password. In a system in which the user logs on with a smart card, however, the credential would be different. To keep matters simple, we'll use the terms user password, logon password, or just password to refer to this credential.

A small drawback to using the logon password is that all applications running under the same user can access any protected data that they know about. Of course, because applications must store their own protected data, gaining access to the data could be somewhat difficult for other applications, but certainly not impossible. To counteract this, DPAPI allows an application to use an additional secret when protecting data. This additional secret is then required to unprotect the data.

Technically, this "secret" should be called secondary entropy. It is secondary because, while it doesn't strengthen the key used to encrypt the data, it does increase the difficulty of one application, running under the same user, to compromise another application's encryption key. Applications should be careful about how they use and store this entropy. If it is simply saved to a file unprotected, then adversaries could access the entropy and use it to unprotect an application's data.

Additionally, the application can pass in a data structure that will be used by DPAPI to prompt the user. This "prompt structure" allows the user to specify an additional password for this particular data. We discuss this structure further in the Using DPAPI section.

DPAPI initially generates a strong key called a MasterKey, which is protected by the user's password. DPAPI uses a standard cryptographic process called Password-Based Key Derivation, described in PKCS #5, to generate a key from the password. This password-derived key is then used with Triple-DES to encrypt the MasterKey, which is finally stored in the user's profile directory.

The MasterKey, however, is not used explicitly to protect the data. Instead, a symmetric session key is generated based on the MasterKey, some random data, and any additional entropy, if an application chooses to supply it. It is this session key that is used to protect the data. The session key is never stored. Instead, DPAPI stores the random data it used to generate the key in the opaque data BLOB. When the data BLOB is passed back in to DPAPI, the random data is used to re-derive the key and unprotect the data.

For security reasons, MasterKeys will expire, which means that after a period of time (the hard-coded value being three months), a new MasterKey is generated and protected in the same manner. This expiration prevents an attacker from compromising a single MasterKey and accessing all of a user's protected data.

You are probably wondering how an application can unprotect data that was protected under a MasterKey that has expired, because the session key is derived from the MasterKey, right? Well the answer involves a two-step process. First, DPAPI does not delete any expired MasterKeys. Instead, they are kept forever in the user's profile directory, protected by the user's password. Second, it stores the Globally Unique Identifier (GUID) of the MasterKey used to protect the data in the opaque data BLOB that is returned to applications. When the data BLOB is passed back in to DPAPI, the MasterKey that corresponds to the GUID is used to unprotect the data.

The other question you might have is how does DPAPI access MasterKeys after a user changes his or her password? The answer is again a two-step process. First, DPAPI hooks into the password-changing module and when a user's password is changed, all MasterKeys are re-encrypted under the new password. Second, the system keeps a "Credential History" file in the user's profile directory. When a user changes his or her password, the old password is added to the top of this file and then the file is encrypted by the new password. If necessary, DPAPI will use the current password to decrypt the "Credential History" file and try the old password to decrypt the MasterKey. If this fails, the old password is used to again decrypt the "Credential History" file and the next previous password is then tried. This continues until the MasterKey is successfully decrypted.

Key Backup and Restoration in DPAPI

When a computer is a member of a domain, DPAPI has a backup mechanism to allow unprotection of the data. When a MasterKey is generated, DPAPI talks to a Domain Controller. Domain Controllers have a domain-wide public/private key pair, associated solely with DPAPI. The local DPAPI client gets the Domain Controller public key from a Domain Controller by using a mutually authenticated and privacy protected RPC call. The client encrypts the MasterKey with the Domain Controller public key. It then stores this backup MasterKey along with the MasterKey protected by the user's password.

While unprotecting data, if DPAPI cannot use the MasterKey protected by the user's password, it sends the backup MasterKey to a Domain Controller by using a mutually authenticated and privacy protected RPC call. The Domain Controller then decrypts the MasterKey with its private key and sends it back to the client by using the same protected RPC call. This protected RPC call is used to ensure that no one listening on the network can get the MasterKey.

Now you're probably thinking that this backup works great with domain clients, but you're also wondering what about all the home users who run stand-alone or workgroup systems. Well, Windows XP has a new feature: the Password Reset Disk (PRD). A user can create a PRD from the Control Panel at any time, and it then allows the user to reset their password when they forget it. When the password is reset by the PRD, all of the user's MasterKeys are re-encrypted under the new password.

Using DPAPI

There are two sets of interfaces to DPAPI, the user interfaces and the system interfaces. These are discussed, along with two data structures, the CRYPTPROTECT_PROMPTSTRUCT structure, which is the "prompt structure" mentioned earlier, and the protected data BLOB that holds the protected data.

The user interfaces contain the only two functions that application developers need to know to use DPAPI. The protect function:CryptProtectData()and the unprotect function: CryptUnprotectData(). The only requirement for applications to use these functions is to either link with Crypt32.lib or dynamically load Crypt32.dll. The protect function takes a plaintext data as input and returns an opaque protected data BLOB. The unprotect function takes this opaque data BLOB and returns the plaintext data.

The system interfaces are part of the LSA. These interfaces cannot be called by a user application. They exist so that LSA threads can use DPAPI and specify theCRYPTPROTECT_SYSTEMflag to protect data that cannot be unprotected outside the LSA.

User Interfaces

The user interfaces are available through the Windows SDK and MSDN Library.

For more information and example source code, see CryptProtectData and CryptUnprotectData.

System Interfaces

Internal Protect Function

Definition

BOOL WINAPI Internal Protect Function (
   DATA_BLOB                  *pDataIn,
   LPCWSTR                     szDataDescr,
   DATA_BLOB                  *pOptionalEntropy,
   PVOID                        pvReserved,
   CRYPTPROTECT_PROMPTSTRUCT   *pPromptStruct,
   DWORD                        dwFlags,
   DATA_BLOB                  *pDataOut)

Parameters

  • pDataIn
    Pointer to aDATA_BLOBcontaining the plaintext data to be protected. ThecbDatamember holds the length of thepbDatamember's byte string that contains the data to be protected.

  • szDataDescr
    String with a readable description of the data to be encrypted. This description string is included with the protected data.

    This parameter is optional and can be NULL.

  • pOptionalEntropy
    Pointer to aDATA_BLOBcontaining additional entropy used to protect the data. ThecbDatamember holds the length of thepbDatamember's byte string that contains the optional entropy. TheDATA_BLOBused in the protection call must also be used in the unprotection call. This is the application specific "secret" mentioned earlier.

    This parameter is optional and can be NULL.

  • pvReserved
    Reserved for future use and must be NULL.

  • pPromptStruct
    Pointer to a CRYPTPROTECT_PROMPTSTRUCT that provides information about where and when prompts are displayed and what the content of those prompts should be. This structure is defined below, after the function definitions.

    This parameter is optional and can be NULL.

  • dwFlags
    The following table lists the defined flags values:

    CRYPTPROTECT_LOCAL_MACHINE When this flag is set, it associates the data protected with the current computer instead of with an individual user. Any user on the computer on which the internal protect function is called with this flag can use the internal unprotect function to unprotect the data. Application developers should understand that by using this flag no "real" protection is provided by DPAPI. By "real" we mean that any process running on the system can unprotect any data protected with this flag. We highly recommended that this flag not be used on workstations to protect user's data. It does make sense, however, for a server process to use the flag on a server where untrusted users are not allowed to logon. It also makes sense for a local machine process to use the flag to protect data to be stored off the machine or on a shared drive.
    CRYPTPROTECT_UI_FORBIDDEN This flag is used for remote situations where presenting a user interface (UI) is not an option. When this flag is set and a UI is specified for either protection or unprotection, the call fails and GetLastError() returns the ERROR_PASSWORD_RESTRICTION status code.
    CRYPTPROTECT_AUDIT This flag causes DPAPI to generate an audit when this data is protected or unprotected.
    CRYPTPROTECT_CRED_SYNC When this flag is used, no data is actually protected. Instead all MasterKeys are queried from disk, which will cause re-encryption in memory, presumably under a changed password.
    CRYPTPROTECT_SYSTEM Data protected with this flag set can only be unprotected with this flag set.
  • pDataOut
    Pointer to aDATA_BLOBthat receives the protected data. This buffer is allocated by the internal protect function and it is the responsibility of the calling application to free it with a call to LocalFree().

Return values

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. For extended error information, call GetLastError().

Internal Unprotect Function

Definition

BOOL WINAPI Internal Unprotect Function (
   DATA_BLOB                  *pDataIn,
   LPCWSTR                     *ppszDataDescr,
   DATA_BLOB                  *pOptionalEntropy,
   PVOID                        pvReserved,
   CRYPTPROTECT_PROMPTSTRUCT   *pPromptStruct,
   DWORD                        dwFlags,
   DATA_BLOB                  *pDataOut)

Parameters

  • pDataIn
    Pointer to aDATA_BLOBcontaining the protected data. ThecbDatamember holds the length of thepbDatamember's byte string that contains the data to be unprotected.

  • ppszDataDescr
    Pointer to a string where the readable description included with the protected data is placed. This buffer is allocated by the internal unprotect function and it is the responsibility of the calling application to free it with a call to LocalFree().

    This parameter is optional and can be NULL.

  • pOptionalEntropy
    Pointer to aDATA_BLOBcontaining additional entropy used when the data was protected. ThecbDatamember holds the length of thepbDatamember's byte string that contains the optional entropy. This is the application specific "secret" mentioned earlier.

    This parameter is optional and can be NULL. However, if the optional entropy was used in the protection call, that same entropy must be used in the unprotection call.

  • pvReserved
    Reserved for future use and must be NULL.

  • pPromptStruct
    Pointer to a CRYPTPROTECT_PROMPTSTRUCT that provides information about where and when prompts are displayed and what the content of those prompts should be. This structure is defined below, after the function definitions. While this parameter is optional for the protection call, it is recommended that the calling application provide a valid pointer here, because if apPromptStructwas provided to the internal protect function, this pointer will be required.

  • dwFlags
    The following table lists the defined flags values:

    CRYPTPROTECT_UI_FORBIDDEN This flag is used for remote situations where presenting a user interface (UI) is not an option. When this flag is set and a UI is specified for either protection or unprotection, the call fails and GetLastError() returns the ERROR_PASSWORD_RESTRICTION status code.
    CRYPTPROTECT_VERIFY_PROTECTION If the protected data blob would be better protected under a new call to the internal protect function and this call succeeds, then GetLastError will return a CRYPT_I_NEW_PROTECTION_REQUIRED status code.
    CRYPTPROTECT_SYSTEM If data was protected with this flag set, then this flag must be set to unprotect the data.
  • pDataOut
    Pointer to aDATA_BLOBthat receives the plaintext data. This buffer is allocated by the internal unprotect function and it is the responsibility of the calling application to free it with a call to LocalFree().

Return values

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. For extended error information, a developer should call GetLastError().

Data Structures

CRYPTPROTECT_PROMPTSTRUCT

The CRYPTPROTECT_PROMPTSTRUCT structure provides a prompt that is displayed when data is protected or unprotected. This is the "prompt structure" discussed earlier in the DPAPI Architecture section.

ms995355.windataprotection-dpapi-fig2(en-us,MSDN.10).gif

Figure 2. Initial dialog box

Figure 2, above, shows the dialog box which first asks the user to specify either Medium or High security for the data, with Medium being the default selected. If the security level is set to High, the dialog box then prompts the user for an additional password, and, if the application hasn't specified one, a description for the data. This dialog box is shown below in Figure 3.

ms995355.windataprotection-dpapi-fig3(en-us,MSDN.10).gif

Figure 3. Password and description dialog box

When calling CryptUnprotectData(), we recommend that an application always pass in a pointer to a prompt structure because if the data is protected with a prompt structure, DPAPI will require a prompt structure to unprotect the data, and the function will fail if one is not passed in.

For more information, see CRYPTPROTECT_PROMPTSTRUCT.

Protected data BLOB

As we said before, DPAPI does not actually store any data. It simply protects data. It is the application's responsibility to store the protected data.CryptProtectData()returns an opaque data BLOB, and it is sufficient for applications to store this BLOB in some way; they do not have to parse the internals of it for any reason. To protect against tampering of the DPAPI data or the encrypted data, the entire BLOB is hashed with a Hashed Message Authentication Code (HMAC), in this case SHA-1. For reference purposes, the size of the data BLOB is 708 bits plus the length of the description text, encrypted data, and MAC. In addition, if DPAPI has to provide a salt value to the Cryptographic Service Provider (CSP), the structure will be a little larger in size, but for most CSPs, this salt is not needed.

DPAPI Security

DPAPI provides an essential data protection capability that ensures the confidentiality of protected data while allowing recovery of the underlying data in the event of lost or changed passwords. The password-based protection provided by DPAPI is excellent for a number of reasons.

  • It uses proven cryptographic routines, such as the strong Triple-DES algorithm in CBC mode, the strong SHA-1 algorithm, and the PBKDF2 password-based key derivation routine.
  • It uses proven cryptographic constructs to protect data. All critical data is cryptographically integrity protected, and secret data is wrapped by using standard methods.
  • It uses large secret sizes to greatly reduce the possibility of brute-force attacks to compromise the secrets.
  • It uses PBKDF2 with 4000 iterations to increase the work factor of an adversary trying to compromise the password.
  • It sanity checks MasterKey expiration dates.
  • It protects all required network communication with Domain Controllers by using mutually authenticated and privacy protected RPC channels.
  • It minimizes the risk of exposing any secrets, by never writing them to disk and minimizing their exposure in swappable RAM.
  • It requires Administrator privileges to make any modifications to the DPAPI parameters in the registry.
  • It uses Windows File Protection to help protect all critical DLLs from online changes even by processes with Administrator privileges.

DPAPI, however, is not 100 percent foolproof. The Password Reset Disk can be stolen, allowing an attacker to reset a user's password. DPAPI is also susceptible, as any password-based system is, to social engineering attacks, in which an adversary tricks a user into disclosing a password or tricks a domain administrator into resetting a user's password. Finally, while the CRYPTPROTECT_LOCAL_MACHINE flag can provide excellent protection in certain circumstances, it is possible to use it in an inappropriate manner in which no real protection is provided.

DPAPI can be configured to operate with a Windows 2000 server in a legacy mode. In this mode, it is possible to back up the MasterKeys under a local LSA secret. The MasterKeys, along with the LSA, and any protected data can then be stolen by an adversary and decrypted at will. For this to occur, however, an Administrator must modify the registry to configure DPAPI for this legacy mode.

Other vulnerabilities also require greater attacker effort and reduced payoff. These include attacks such as inserting a rogue CSP into the operating system or forcing hibernation at a critical moment so that in-use secrets in RAM get written to the hibernation file.

Overall, DPAPI provides very good security, considering the protection is based on a user's password. Later, we discuss in more detail the security of DPAPI, specifically how it generates and uses cryptographic keys.

Key Relationships

Figure 4, later, shows how all the different keys operate together to allow DPAPI to provide data protection. The keys are discussed further in the following sections.

The bold circle indicates the center of the DPAPI key relationships: the user password. On standalone systems, the recovery key protects the password to allow users to reset their passwords with the PRD. The user password is used to derive the MasterKey Encryption Key, which is used to protect the MasterKey. Finally, a derivation of this password, the user credential, is stored in the "Credential History" file, which allows DPAPI to access MasterKeys protected under old passwords.

On domain workstations, a Domain Controller public key also protects the MasterKey. This allows DPAPI to access a Domain Controller and restore the MasterKey, if it cannot use the MasterKey Encryption Key. Finally, the MasterKey is used to derive the Symmetric Session Key, which then protects the application data.

ms995355.windataprotection-dpapi-fig4(en-us,MSDN.10).gif

Figure 4. Key relationships

MasterKey

We said earlier that DPAPI generates a strong key called the MasterKey. Calling the MasterKey a key isn't really correct because it is never used in any explicit encryption or decryption functions. The MasterKey is more accurately a strong secret: strong because it is 512 bits of random data, and secret because it is used, with some additional data, to generate an actual symmetric session key. This secret, however, needs to be kept secure from everyone but the intended user.

To protect this secret, DPAPI uses the Password-Based Key Derivation Function, PBKDF2, described in PKCS #5. First, DPAPI takes the user's password and passes it through SHA-1 to get a password hash. This is the logon credential mentioned earlier. Next, the password hash is provided to the PBKDF2 function, along with sixteen random bytes for a salt and an iteration count. The PBKDF2 function calls an additional function a number of times, specified by the iteration count, to derive a key from the given data. DPAPI uses SHA-1 for that underlying function. The default iteration count is 4000, which increases the work load required to brute-force compromise the password by a factor of 4000, without creating undue performance restrictions in normal operations. There is a registry valueMasterKeyIterationCountstored in theHKEY_LOCAL_MACHINE\Software\Microsoft\Cryptography\Protect\Providers\GUIDkey that allows a system administrator to increase this iteration count. It cannot, however, be decreased below 4000.

To prevent tampering of the MasterKey, it is hashed with an HMAC. DPAPI again uses SHA-1 for the HMAC and the user's password to derive the HMAC key. The password-derived encryption key, from above, is then used with Triple-DES to encrypt the MasterKey and the HMAC of the MasterKey. The salt and iteration count are both non-secret values, and therefore are stored along with the encrypted MasterKey, but are not encrypted. This allows DPAPI to easily decrypt the MasterKey, given the user's password.

At this point, if the computer is a domain member, the backup steps, outlined in the Key Backup and Restoration in DPAPI section, are performed. Finally, the encrypted MasterKey and HMAC, salt, iteration count, and backup MasterKey are all stored in a MasterKey file, which resides in the user's profile directory.

Session Key

The session key is the real symmetric key that is used for encrypting and decrypting the application data. DPAPI uses a simple process to derive the session key. First, 16 bytes of random data are generated and then hashed, by using SHA-1, with the MasterKey. This hash is then appended with the optional entropy and optional user password, mentioned earlier, by using CryptHashData(), a CryptoAPI call. The result is then passed to CryptDeriveKey(), another CryptoAPI call, which derives and returns the session key.

As we mentioned earlier, the session key is never stored anywhere; it is derived, used, and then removed from memory. So that DPAPI can unprotect the data, the generated random bytes are stored in the protected data BLOB. These random bytes are stored unprotected; however, since the MasterKey is protected, they are authenticated with an HMAC to prevent tampering.

Recovery Key

The recovery key is generated when a user chooses to create a Password Reset Disk (PRD) from the user's Control Panel. First, DPAPI generates a 2048-bit RSA public/private key pair, which is the recovery key. The current password is then encrypted with the public key and stored in the user's profile, while the private key is stored to the PRD, which can actually be any removable media, and then removed from memory. The private key is only stored on the PRD, and nowhere else, so it is important for a user to keep the PRD in a safe place.

If users enter the wrong password, Windows asks them whether they would like to use the PRD and reset the password. If they choose to, a wizard runs that prompts for the new password and uses the private key on the PRD to decrypt the old password and make the change.

Contributors

The contributors of this document are Wesley Griffin, Michael Heyman, David Balenson, and David Carman, members of the Cryptographic Technologies Group in NAI Labs, the Security Research Division of Network Associates, Inc. NAI Labs is a multi-discipline research organization with world-renowned expertise in the areas of network security, applied cryptographic technologies, secure execution environments, security infrastructure, adaptive network defenses, distributed systems security, and information assurance.

NAI Labs would like to acknowledge the help of Peter Brundrett, Mike Lai, David Hubbard, John Banes, Scott Field, George Masters, and Craig Delthony, all at Microsoft, for providing information on DPAPI. We would also like to thank Dave Thompson and Doug Bayer for contributing Microsoft resources.

References

  1. CryptProtectData.
  2. CryptUnprotectData.
  3. CRYPTPROTECT_PROMPTSTRUCT.
  4. PKCS #5 v2.0: Password-Based Cryptography Standard. RSA Laboratories. March 25, 1999. ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-5v2/pkcs5v2-0.doc.
  5. RFC-2404: The Use of HMAC-SHA-1-96 within ESP and AH. C. Madson, R. Glenn. November 1998. https://www.ietf.org/rfc/rfc2404.txt.