Protecting Secrets in Windows 95, Windows 98, Windows Me, and Windows CE

Protecting Secrets in Windows 95, Windows 98, Windows Me, and Windows CE

Windows 95, Windows 98, Windows Me, and Windows CE (used in Pocket PCs) all have CryptoAPI support, but none have ACLs. Although it's easy to save secret data in a resource such as the registry or a file, where do you store the key used to encrypt the data? In the registry too? How do you secure that, especially with no ACL support? This is a difficult problem. These platforms cannot be used in secure environments. You can hide secrets, but they will be much easier to find than on Windows NT 4, Windows 2000, or Windows XP. In short, if the data being secured is high-risk (such as medical data), use Windows 95, Windows 98, Windows Me, or Windows CE only if you get a key from a user or an external source to encrypt and decrypt the data.

When using these less-secure platforms, you could derive the key by calling CryptGenRandom, storing this key in the registry, and encrypting it with a key derived from something held on the device, such as a volume name, a device name, a video card name, and so on. (I bet you wish Intel had stuck with shipping their Pentium III serial numbers enabled, don't you?) Your code can read the device to get the key to unlock the registry key. However, if an attacker can determine what you are using as key material, he can derive the key. Still, you've made the task more difficult for the attacker, as he has to go through more steps to get the plaintext. Also, if the user changes hardware, the key material might be lost also. This solution is hardly perfect, but it might be good enough for noncritical data.

The HKEY_LOCAL_MACHINE\HARDWARE portion of the registry in Windows 95, Windows 98, and Windows Me computers is full of hardware-specific data you can use to derive an encryption key. It's not perfect, but again, the bar is raised somewhat. That said, let's look at some ways to derive system information to help build key material.

Getting Device Details Using PnP

Plug and Play support in Windows 98 and later, and Windows 2000 and later, allows a developer to access system hardware information. This information is sufficiently convoluted that it can serve as the basis for key material to protect data that should not leave the computer. The following code outlines the process involved; it enumerates devices on the computer, gets the hardware description, and uses this data to build a SHA-1 that could be used as non-persistent key material. You can learn more about the device management functions at http://msdn.microsoft.com/library/en-us/devio/deviceman_7u9f.asp.

#include "windows.h" #include "wincrypt.h" #include "initguid.h" #include "Setupapi.h" #include "winioctl.h" #include "strsafe.h" //These are defined in the DDK, but not everyone has the DDK! DEFINE_GUID( GUID_DEVCLASS_CDROM, \ 0x4d36e965L, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 ); DEFINE_GUID( GUID_DEVCLASS_NET, \ 0x4d36e972L, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 ); DEFINE_GUID( GUID_DEVCLASS_DISPLAY, \ 0x4d36e968L, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 ); DEFINE_GUID( GUID_DEVCLASS_KEYBOARD, \ 0x4d36e96bL, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 ); DEFINE_GUID( GUID_DEVCLASS_MOUSE, \ 0x4d36e96fL, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 ); DEFINE_GUID( GUID_DEVCLASS_SOUND, \ 0x4d36e97cL, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 ); DEFINE_GUID( GUID_DEVCLASS_USB, \ 0x36fc9e60L, 0xc465, 0x11cf, 0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 ); DEFINE_GUID( GUID_DEVCLASS_DISKDRIVE, \ 0x4d36e967L, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 ); DEFINE_GUID( GUID_DEVCLASS_PORTS, \ 0x4d36e978L, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 ); DEFINE_GUID( GUID_DEVCLASS_PROCESSOR, \ 0x50127dc3L, 0x0f36, 0x415e, 0xa6, 0xcc, 0x4c, 0xb3, 0xbe, 0x91, 0x0B, 0x65 ); DWORD GetPnPStuff(LPGUID pGuid, LPTSTR szData, DWORD cData) { HDEVINFO hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT DIGCF_ALLCLASSES); if (INVALID_HANDLE_VALUE == hDevInfo) return GetLastError(); //Enumerate all devices in Set. SP_DEVINFO_DATA did; did.cbSize = sizeof(SP_DEVINFO_DATA); for (int i = 0; SetupDiEnumDeviceInfo(hDevInfo,i,&did); i++) { //Is this device we're interested in? if (*pGuid != did.ClassGuid) continue; const DWORD cBuff = 256; char Buff[cBuff]; DWORD dwRegType = 0, cNeeded = 0; if (SetupDiGetDeviceRegistryProperty(hDevInfo, &did, SPDRP_HARDWAREID, &dwRegType, (PBYTE)Buff, cBuff, &cNeeded)) //Potential for data loss, but that's ok. if (cData > cNeeded) { StringCchCat(szData,cData,"\n\t"); StringCchCat(szData,cData,Buff); } } return 0; } DWORD CreateHashFromPnPStuff(HCRYPTHASH hHash) { struct { LPGUID guid; _TCHAR *szDevice; } device [] = { {(LPGUID)&GUID_DEVCLASS_CDROM, "CD"}, {(LPGUID)&GUID_DEVCLASS_DISPLAY, "VDU"}, {(LPGUID)&GUID_DEVCLASS_NET, "NET"}, {(LPGUID)&GUID_DEVCLASS_KEYBOARD, "KBD"}, {(LPGUID)&GUID_DEVCLASS_MOUSE, "MOU"}, {(LPGUID)&GUID_DEVCLASS_USB, "USB"}, {(LPGUID)&GUID_DEVCLASS_PROCESSOR,"CPU"} }; const DWORD cData = 4096; TCHAR *pData = new TCHAR[cData]; if (!pData) return ERROR_NOT_ENOUGH_MEMORY; DWORD dwErr = 0; for (int i=0; i < sizeof(device)/sizeof(device[0]); i++) { ZeroMemory(pData,cData); if (GetPnPStuff(device[i].guid,pData,cData) == 0) { #ifdef _DEBUG printf("%s: %s\n",device[i].szDevice, pData); #endif if (!CryptHashData(hHash, (LPBYTE)pData, lstrlen(pData), 0)) { dwErr = GetLastError(); break; } } else { dwErr = GetLastError(); } } delete [] pData; return dwErr; } int _tmain(int argc, _TCHAR* argv[]) { HCRYPTPROV hProv = NULL; HCRYPTHASH hHash = NULL; if (CryptAcquireContext (&hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT)) { if (CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)) { if (CreateHashFromPnPStuff(hHash) == 0) { //get the hash BYTE hash[20]; DWORD cbHash = 20; if (CryptGetHashParam (hHash,HP_HASHVAL,hash,&cbHash,0)) { for (DWORD i=0; i < cbHash; i++) { printf("%02X",hash[i]); } } } } } if (hHash) CryptDestroyHash(hHash); if (hProv) CryptReleaseContext(hProv, 0); }

 if (hHash) CryptDestroyHash(hHash); if (hProv) CryptReleaseContext(hProv, 0); }

Be careful if you use code like this to build long-lived encryption keys. If the hardware changes, so does the key. With this in mind, restrict the hardware you query to hardware that never changes. And be mindful of a laptop in the docked and undocked state!

It's important to realize that none of this is truly secure it just might be secure enough for the data you're trying to protect. That last point again: it might be secure enough.

NOTE
It's important to notify the user in Help files or documentation that the platform stores secrets on a best-effort basis.



Writing Secure Code
Writing Secure Code, Second Edition
ISBN: 0735617228
EAN: 2147483647
Year: 2001
Pages: 286

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