143
Chapter 6. Symmetric Cryptography
So far, weve discussed how to use the OpenSSL programmatic interface for securing arbitrary TCPIP connections using SSL. While SSL is a great general-purpose protocol, there are situations
in which it is not appropriate. For example, SSL cant be used to store encrypted data, such as on a disk or in a cookie, nor can it encrypt UDP traffic. In these cases, you should use the OpenSSL
API for symmetric cryptography.
As you have probably noticed, weve been careful to recommend using SSL instead of raw cryptographic primitives for securing your applications if at all appropriate. We do this because it
is incredibly easy to apply cryptographic primitives in a way that is insecure. Even professional cryptographic protocol designers have a hard time writing secure cryptographic protocols built
on these primitives, which is one reason peer-review is so important in the world of cryptography.
If youre planning to use this chapter to do real work, then we assume that you have some sort of need that SSL cannot fill, such as long-term data storage. We recognize that many people will
want to design their own network protocols despite our recommendations. If you are considering such an option, we strongly urge you to prefer well-respected protocols, and even pre-existing
implementations of those protocols, if possible. Nonetheless, this chapter is a reference for the basic API, and it is your responsibility to use that API in a secure manner.
6.1 Concepts in Symmetric Cryptography
Although we gave a brief overview of symmetric key cryptography in Chapter 1
, there are some additional things we should discuss as background material for the rest of this chapter. Certainly,
we dont wish to serve as a general-purpose textbook on cryptography. For such things, we recommend other books, such as Bruce Schneiers Applied Cryptography John Wiley Sons.
For that reason, well avoid any topic that a developer need not care about, such as the internal workings of ciphers. Anything related to the choices you need to make, however, is fair game.
6.1.1 Block Ciphers and Stream Ciphers
Only two types of symmetric ciphers exist that are well-respected and see any sort of widespread use: block ciphers and stream ciphers. Block ciphers are traditionally the most popular. They
operate by breaking up data into fixed-size blocks, and then encrypting each block individually, in which the encryption algorithm is a reversible function of the input. Leftover data is traditionally
padded so that the length of the plaintext is a multiple of the ciphers block size. Stream ciphers are essentially just cryptographic pseudorandom number generators. They use a starting seed as a
key to produce a stream of random bits known as the keystream. To encrypt data, one takes the plaintext and simply XORs it with the keystream. Stream ciphers dont need to be padded per se,
though they are usually padded to byte-boundaries, since implementations usually operate on a per-byte level instead of a per-bit level.
The best block ciphers are a far more conservative solution than stream ciphers because they are better studied. Yet stream ciphers tend to be far faster than block ciphers. For example, RC4,
currently the most popular stream cipher, runs about 4 times faster than Blowfish, which is among the fastest available block ciphers, and runs almost 15 times faster than 3DES, which is a very
conservative cipher choice. AES is faster than 3DES and has more security in terms of a longer key size, but it is still generally slower than even Blowfish.
144
Neither block ciphers nor stream ciphers can give us perfect security, in which an attacker can never recover a message as long as the communicating parties use the algorithm properly. For
each type of cipher, the security is, at best, a function of the key length. Its always possible to launch a brute-force attack, in which the attacker tries every possible key until the message
properly decrypts. If the key length is long enough, the attack will take so long on average as to be infeasible in practice.
Even if there was no better attack on an individual cipher than brute force, there are other issues that plague naive use of both types of cipher. Stream ciphers have the problem that a one-bit flip
of the ciphertext causes a one-bit flip in the decrypted plaintext. Obviously, stream ciphers need to be supplemented with data integrity checks. For such purposes, we recommend message
authentication codes MACs—see
Chapter 8 .
When used directly, block ciphers always encrypt a given block of data in the same way, and thus do not effectively conceal patterns in a stream of data. An attacker can keep a dictionary of known
plaintext blocks to known ciphertext blocks, which can often be useful in deciphering real messages. Additionally, an attacker can easily substitute one ciphertext block for another, often
with great success. There are ways to use ciphers that can solve these problems to some degree, which we discuss in the next section. Additionally, MACs can be used to thwart actual
modification attacks.
Stream ciphers are subject to a similar, more serious problem. Once you start encrypting using a given key, you must continue to generate new data in the keystream, or generate and exchange a
new key. If you start over using the same key, the security of the stream cipher is effectively lost. The solution is to never reuse keys when using a stream cipher. Dont even use the same key
across reboots.
6.1.2 Basic Block Cipher Modes