Storing Secrets in Windows NT 4

Storing Secrets in Windows NT 4

Windows NT 4 does not include the DPAPI, but it includes CryptoAPI support and ACLs. You can protect data in Windows NT 4 by performing these steps:

  1. Create a random key by using CryptGenRandom.

  2. Store the key in the registry.

  3. ACL the registry key such that Creator/Owner and Administrators have full control.

  4. If you are really paranoid, place an audit ACE (SACL) on the resource so that you can see who is attempting to read the data.

Each time you want to encrypt or decrypt the data, only the user account that created the key (the object s owner) or a local administrator can read the key and use it to carry out the task. This is not perfect, but at least the security bar has been raised such that only an administrator or the user in question can carry out the process. Of course, if you invite a Trojan horse application to run on your computer, it can read the key data from the registry, because it runs under your account, and then decrypt the data.

You can also use LSA secrets (LsaStorePrivateData and LsaRetrievePrivateData) as discussed in the previous section, Storing Secrets in Windows 2000 and Windows XP. Four types of LSA secrets exist: local data, global data, machine data, and private data. Local data LSA secrets can be read only locally from the machine storing the data. Attempting to read such data remotely results in an Access Denied error. Local data LSA secrets have key names that begin with the prefix L$. Global data LSA secrets are global such that if they are created on a domain controller (DC), they are automatically replicated to all other DCs in that domain. Global LSA secrets have key names beginning with G$. Machine data LSA secrets can be accessed only by the operating system. These key names begin with M$. Private data LSA secrets, unlike the preceding specialized types, have key names that do not start with a prefix. Such data is not replicated and can be read locally or remotely.

Before you can store or retrieve LSA secret data, your application must acquire a handle to the LSA policy object. Here is a sample C++ function that will open the policy object:

#include "stdafx.h" #include <ntsecapi.h> LSA_HANDLE GetLSAPolicyHandle(WCHAR *wszSystemName) { LSA_OBJECT_ATTRIBUTES ObjectAttributes; ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); USHORT dwSystemNameLength = 0; if (NULL != wszSystemName) dwSystemNameLength = wcslen(wszSystemName); LSA_UNICODE_STRING lusSystemName; lusSystemName.Buffer = wszSystemName; lusSystemName.Length = dwSystemNameLength * sizeof(WCHAR); lusSystemName.MaximumLength = (dwSystemNameLength+1) * sizeof(WCHAR); LSA_HANDLE hLSAPolicy = NULL; NTSTATUS ntsResult = LsaOpenPolicy( &lusSystemName, &ObjectAttributes, POLICY_ALL_ACCESS, &hLSAPolicy); DWORD dwStatus = LsaNtStatusToWinError(ntsResult); if (dwStatus != ERROR_SUCCESS) { wprintf(L"OpenPolicy returned %lu\n", dwStatus); return NULL; } return hLSAPolicy; }

The following code example shows how to use LSA secrets to encrypt and decrypt information:

DWORD WriteLsaSecret(LSA_HANDLE hLSA, WCHAR *wszSecret, WCHAR *wszName) { LSA_UNICODE_STRING lucName; lucName.Buffer = wszName; lucName.Length = wcslen(wszName) * sizeof WCHAR; lucName.MaximumLength = lucName.Length + (2 * sizeof WCHAR); LSA_UNICODE_STRING lucSecret; lucSecret.Buffer = wszSecret; lucSecret.Length = wcslen(wszSecret) * sizeof WCHAR; lucSecret.MaximumLength = lucSecret.Length + (2 * sizeof WCHAR); NTSTATUS ntsResult = LsaStorePrivateData( hLSA, &lucName, &lucSecret); DWORD dwStatus = LsaNtStatusToWinError(ntsResult); if (dwStatus != ERROR_SUCCESS) wprintf(L"Store private data failed %lu\n", dwStatus); return dwStatus; } DWORD ReadLsaSecret(LSA_HANDLE hLSA, DWORD dwBuffLen, WCHAR *wszSecret, WCHAR *wszName) { LSA_UNICODE_STRING lucName; lucName.Buffer = wszName; lucName.Length = wcslen(wszName) * sizeof WCHAR; lucName.MaximumLength = lucName.Length + (2 * sizeof WCHAR); PLSA_UNICODE_STRING plucSecret = NULL; NTSTATUS ntsResult = LsaRetrievePrivateData( hLSA, &lucName, &plucSecret); DWORD dwStatus = LsaNtStatusToWinError(ntsResult); if (dwStatus != ERROR_SUCCESS) wprintf(L"Read private data failed %lu\n", dwStatus); else wcsncpy(wszSecret, plucSecret->Buffer, min((plucSecret->Length)/sizeof WCHAR, dwBuffLen)); // IMPORTANT: free memory allocated by LSA. if (plucSecret) LsaFreeMemory(plucSecret); return dwStatus; } void main() { LSA_HANDLE hLSA = GetLSAPolicyHandle(NULL); WCHAR *wszName = L"L$WritingSecureCode"; WCHAR *wszSecret = L"My Secret Data!"; if (WriteLsaSecret(hLSA, wszSecret, wszName) == ERROR_SUCCESS) { WCHAR wszSecretRead[128]; if (ReadLsaSecret(hLSA, sizeof wszSecretRead / sizeof WCHAR, wszSecretRead, wszName) == ERROR_SUCCESS) wprintf(L"LSA Secret '%s' is '%s'\n", wszName, wszSecretRead); } // Free the LSA handle. if (hLSA) LsaClose(hLSA); }

This example code is also available on the companion CD in the folder Secureco\Chapter 7\LSASecrets. You can delete an LSA secret by setting the last argument to LsaStorePrivateData NULL.

important

Unlike LSA secrets, DPAPI does not store data it only encrypts and decrypts data. The software developer has the responsibility to store the encrypted data. Also, DPAPI can be used by a roaming user because the key material is stored in the user s profile. LSA secrets remain on the computer or, in the case of global objects, on all domain controllers.

note

Secrets protected by LSA can be viewed by local computer administrators using LSADUMP2.exe from BindView. The tool is available at www.razor.bindview.com/tools/desc/lsadump2_readme.html. Of course, an administrator can do anything!



Writing Secure Code
Writing Secure Code, Second Edition
ISBN: 0735617228
EAN: 2147483647
Year: 2005
Pages: 153

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net