Key Management Issues

Key Management Issues

Key management is generally considered the weakest link of cryptographic applications and hard to get right. Using cryptography is easy; securely storing, exchanging, and using keys is hard. All too often, good systems are let down by poor key management. For example, hard-coding a key in an executable image is trivial to break, even when people don't have access to your source code.

Breaking DVD Encryption: A Hard Lesson in Storing Secrets

Possibly the most famous exploit involving storing secret data in an executable file is the DVD encryption keys exposed by the XingDVD Player from RealNetworks Inc. subsidiary Xing Technologies. The software did not have the DVD keys satisfactorily protected, and hackers were able to release a controversial program named DeCSS to crack DVDs based on key information gleaned from the executable. More information about this is available at http://www.cnn.com/TECH/computing/9911/05/dvd.hack.idg/.

If a key is a simple text string such as This1sAPa$sword, you can use a tool (such as one named Strings) to dump all the strings in a .DLL or .EXE to determine the password. Simple trial and error by the attacker will determine which string contained in the file is the correct key. Trust me: such strings are extremely easy to break. File a bug if you see lines such as these:

//SSsshh!! Don't tell anyone. char *szPassword="&162hV1);sWa1";

And what if the password is highly random, as a good key should be? Surely a tool like Strings will not find the key because it's not an ASCII string. It too is easy to determine because the key data is random! Code and static data are not random. If you create a tool to scan for entropy in an executable image, you will quickly find the random key.

In fact, such a tool has been created by a British company named nCipher (http://www.ncipher.com). The tool operates by attaching itself to a running process and then scanning the process memory looking for entropy. When it finds areas of high randomness, it determines whether the data is a key, such as a key used for SSL/TLS. Most of the time, it gets it right! A document outlining this sort of attack, Playing Hide and Seek with Stored Keys, is available at http://www.ncipher.com/resources/downloads/files/white_papers/keyhide2.pdf. nCipher has kept the tool to itself.

More Info
Refer to Chapter 9 for information about storing secret information in software.

IMPORTANT
Do not hard-code secret keys in your code, and that includes resource files (.RC files) and configuration files. They will be found out; it is just a matter of time. If you think no one will work it out, you are sadly mistaken.

Long-Term and Short-Term Keys

There are two classes of keys: short-term keys and long-term keys. Short-term keys are often called ephemeral keys and are used by numerous networking protocols, such as IPSec, SSL/TLS, RPC, and DCOM. The key generation management process is hidden from the application and the user.

Long-term keys are used for authentication, integrity, and nonrepudiation and can be used to establish ephemeral keys. For example, when using SSL/TLS, the server uses its private key identified by its public key certificate to help generate ephemeral keys for each encrypted SSL/TLS session. It's a little more complex than this, but you get the idea.

Long-term keys are also used to protect persistent data held in databases and files, and because of their long-term nature, attackers could attempt to break the key over a long period of time. Obviously, long-term keys must be generated and protected securely. Now let's look at some good key management practices.

Use Appropriate Key Lengths to Protect Data

Encrypted data should be protected with an appropriately long encryption key. Obviously, the shorter the key, the easier it is to attack. However, the keys used for different algorithms are attacked in different ways. For example, attacking most symmetric ciphers, such as DES and RC4, requires that the attacker try every key. However, attacking RSA (an asymmetric cipher) keys requires that the attacker attempt to derive the random values used to create the public and private keys. This is a process called factoring. Because of this, you cannot say that a 112-bit 3DES key is less secure than a 512-bit RSA key because they are attacked in different ways. In fact, in this case, a 512-bit RSA key can be factored faster than performing a brute-force attack against the 112-bit 3DES key space.

More Info
Take a look at Cryptographic Challenges at http://www.rsasecurity.com/rsalabs/challenges for information about attacking DES by brute force and RSA by factoring.

However, if you protect symmetric keys using asymmetric keys, you should use an appropriately long asymmetric key. Table 8-2, derived from an Internet draft Determining Strengths For Public Keys Used For Exchanging Symmetric Keys at http://ietf.org/internet-drafts/draft-orman-public-key-lengths-05.txt, gives an idea for the key-size relationships.

Table 8-2. Key-Size Equivalences

Symmetric Key Size (Bits)

Equivalent RSA Modulus Size (Bits)

Equivalent DSA Subgroup Size (Bits)

70

947

128

80

1228

145

90

1553

153

100

1926

184

150

4575

279

200

8719

373

250

14596

475

This table tells us that to protect an 80-bit symmetric key using RSA, the RSA key must be at least 1228 bits. If the latter is shorter than that, it will be easier for a hacker to break the RSA key than it will to attempt a brute-force attack against the 80-bit key.

IMPORTANT
Do not protect a 128-bit AES key by using a 512-bit RSA key!

Keep Keys Close to the Source

When using secret information such as cryptographic keys and passwords, you must keep the keys close to the point where they encrypt and decrypt data. The rationale is simple: highly mobile secrets stay secret only a short time! As a friend once said to me, The value of a secret is inversely proportional to its availability. Or, put another way, A secret known by many is no longer a secret! This applies not only to people knowing a secret but also to code that uses secret data. As I mentioned earlier in this book, all code has bugs, and the more code that has access to secret data, the greater the chance the secret will be exposed to an attacker. Take a look at Figure 8-3.

figure 8-3 allowing keys to roam through an application and keeping keys close to the point where they are used.

Figure 8-3. Allowing keys to roam through an application and keeping keys close to the point where they are used.

The example on the left of Figure 8-3 shows the password passed from function to function and executable to executable. GetKey reads the password from a persistent store and passes the password through EncryptWithKey, Encrypt, DoWork, and ultimately to EncryptData. This is a poor design because a security flaw in any of the functions could leak the private password to an assailant armed with a debugger.

The example on the right is a better design. GetKeyHandle acquires a handle to the password and passes the handle eventually to EncryptData, which then reads the key from the persistent store. If any of the intermediate functions are compromised, the attacker has access only to the handle and not to the password directly.

IMPORTANT
Secret data, including passwords, passed throughout an application is more likely to be compromised than secret data maintained in a central location and used only locally.

The CryptGenKey and CryptExportKey Functions

Microsoft CryptoAPI includes the CryptGenKey function to generate a cryptographically strong key, yet you never see the key value directly. Rather, you access it using a handle to the key. The key is protected by CryptoAPI, and all references to the key are made through the handle. If you need to store the key in some form of persistent storage, such as a floppy disk, a database, a file, or the registry, you can export the key by using the CryptExportKey function and import the key from the persistent store by using CryptImportKey. The key is protected by either a public key in a certificate (and later decrypted with the private key) or, new in Windows 2000 and later, a symmetric key. The key is never in plaintext except deep inside CryptoAPI, and hence the key is safer. Plaintext refers to text that hasn't been encrypted. Sometimes it's also called cleartext.

The following C++ code shows how to generate and export a private key:

/* ProtectKey.cpp */ #include "stdafx.h" using namespace std; //Get the symmetric exchange key used to encrypt the key. void GetExchangeKey(HCRYPTPROV hProv, HCRYPTKEY *hXKey) { //The key-exchange key comes from an external source. HCRYPTHASH hHash; BYTE bKey[16]; if (!GetKeyFromStorage(bKey, sizeof bKey)) throw GetLastError(); if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)) throw GetLastError(); if (!CryptHashData(hHash, bKey, sizeof bKey, 0)) throw GetLastError(); if (!CryptDeriveKey(hProv, CALG_3DES, hHash, CRYPT_EXPORTABLE, hXKey)) throw GetLastError(); } void main() { HCRYPTPROV hProv = NULL; HCRYPTKEY hKey = NULL; HCRYPTKEY hExchangeKey = NULL; LPBYTE pbKey = NULL; try { if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) throw GetLastError(); //Generate two 3DES keys, and mark them as exportable. //Note: these keys are kept in CryptoAPI at this point. if (!CryptGenKey(hProv, CALG_3DES, CRYPT_EXPORTABLE, &hKey)) throw GetLastError(); //Get a key that we can use to encrypt the two 3DES keys. GetExchangeKey(hProv, &hExchangeKey); //Determine blob size. DWORD dwLen = 0; if (!CryptExportKey(hKey, hExchangeKey, SYMMETRICWRAPKEYBLOB, 0, pb Key, &dwLen)) throw GetLastError(); pbKey = new BYTE[dwLen]; //Array to hold 3DES keys ZeroMemory(pbKey, dwLen); /if(!pbKey)throwError_NOT_ENOUGH_MEMORY; //Now get the shrouded blob. if (!CryptExportKey(hKey, hExchangeKey, SYMMETRICWRAPKEYBLOB, 0, pbKey, &dwLen)) throw GetLastError(); cout << "Cool, " << dwLen << " byte wrapped key is exported."  << endl; //Write shrouded key to Key.bin; overwrite if needed //using ostream::write() rather than operator<<, //as the data may contain NULLs. ofstream file("c:\\keys\\key.bin", ios_base::binary); file.write(reinterpret_cast<const char *>(pbKey ), dwLen); file.close(); } catch(DWORD e) { cerr << "Error " << e << hex << " " << e << endl; } // Clean up. if (hExchangeKey) CryptDestroyKey(hExchangeKey); if (hKey) CryptDestroyKey(hKey); if (hProv) CryptReleaseContext(hProv, 0); if (pbKey) delete [] pbKey; }

You can also find the example code with the book's sample files in the folder Secureco2\Chapter08. Note that the GetExchangeKey function is only an example your application will need to have a version of this function to acquire the key-exchange key from its storage location or possibly from the user. From now on, you can acquire the shrouded key from storage and use it to encrypt and decrypt data without knowing what the key actually is! This application generates two Triple-DES (3DES) keys. 3DES is an encrypting algorithm that processes data three times in succession with three different keys. It's more difficult to break than straight DES.

Key Exchange Issues

Exchanging keys is a subset of key management, and it is a huge headache. After all, if an attacker can compromise the key exchange process, he might access the keys used to encrypt data and therefore be able defeat the application. The main threats to insecure or weak key exchange include information disclosure and tampering. Both could lead to spoofing attacks if the key is used to authenticate the end points or is used to sign some data. Remember: verifying a signature is proving the authenticity and integrity of a signed document, and if the key used to sign the document is compromised, then the integrity of the document cannot be ascertained with confidence.

When exchanging keys, there are a number of best practices to follow:

  • Some keys should never be exchanged! Private keys used to sign data are private. (That's why they are called private keys!) So ask yourself, Does my application require that I share this key? You'll be surprised how often you realize you do not need to exchange a key and you can use some other security protocol that mitigates the need to perform key exchange.

  • Obviously, do not embed the key in your code. You may have solved the key exchange problem, because you have no keys to exchange; however, you have a very serious key management problem if the key is disclosed by an attacker, and you can bet it will be. You can read more about storing secrets in Chapter 9.

  • Don't rule out supporting a sneaker-net solution. After all, you mitigate the problem of a hacker accessing the key as it travels across the network if your application supports transferring the key by using humans rather than a piece of wire. There are usability issues to worry about, but this might be a viable option if the security of the application outweighs the extra effort required of the user. This is one mode used by the IPSec administration tool in Windows 2000 and beyond. Figure 8-4 shows the IPSec dialog box for using a certificate that you could distribute by sneaker-net.

    figure 8-4 the ipsec authentication methods dialog box showing the option to use a certificate rather than use a network-based key exchange mechanism.

    Figure 8-4. The IPSec authentication methods dialog box showing the option to use a certificate rather than use a network-based key exchange mechanism.

  • Consider using a protocol that performs key exchange for you so that you don't need to. This works only for ephemeral or short-lived data, such as data that travels over the network. For example, SSL/TLS and IPSec perform a key exchange prior to transferring data. However, if you persist data in the registry or a database, you cannot use this mode.

  • Finally, if you must perform key exchange, use a tried and trusted exchange mechanism such as Diffie-Hellman key agreement or RSA key exchange and do not create your own key exchange protocol. Chances are you'll get it horrendously wrong and your keys will be vulnerable to disclosure and tampering threats.



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