5.17 Performing Block Cipher Setup (for CBC, CFB, OFB, and ECB Modes) in OpenSSL
5.17.1 Problem
You need to set up a cipher so that you
can perform encryption and/or decryption operations in CBC,
CFB, OFB, or ECB mode.
5.17.2 Solution
Here are the steps you need to perform for cipher setup in OpenSSL,
using their high-level API:
Make sure your code includes openssl/evp.h and
links to libcrypto (-lcrypto). Decide which algorithm and mode you want to use, looking up the mode
in Table 5-6 to determine which function
instantiates an OpenSSL object representing that mode. Note that
OpenSSL provides only a CTR mode implementation for AES. See Recipe
5.9 for more on CTR mode. Instantiate a cipher context (type EVP_CIPHER_CTX). Pass a pointer to the cipher context to EVP_CIPHER_CTX_init(
) to initialize memory properly. Choose an IV or nonce, if appropriate to the mode (all except ECB). Initialize the mode by calling EVP_EncryptInit_ex(
) or EVP_DecryptInit_ex(
), as appropriate: int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE
*engine, unsigned char *key, unsigned char *ivornonce);
int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE
*engine, unsigned char *key, unsigned char *ivornonce); If desired, perform any additional configuration the cipher may allow
(see Recipe 5.20).
5.17.3 Discussion
|
Use the raw OpenSSL API only when absolutely necessary because there
is a huge potential for introducing a security vulnerability by
accident. For general-purpose use, we recommend a high-level
abstraction, such as that discussed in Recipe 5.16.
|
|
The OpenSSL EVP API is a reasonably high-level interface to a
multitude of cryptographic primitives. It attempts to abstract out
most algorithm dependencies, so that algorithms are easy to
swap.
The EVP_EncryptInit_ex(
) and EVP_DecryptInit_ex(
) functions set up a cipher context object to
be used for further operations. It takes four arguments that provide
all the information necessary before encryption or decryption can
begin. Both take the same arguments:
- ctx
-
Pointer to an EVP_CIPHER_CTX object, which stores
cipher state across calls.
- type
-
Pointer to an EVP_CIPHER object, which represents
the cipher configuration to use (see the later discussion).
- engine
-
Pointer to an ENGINE object representing the
actual implementation to use. For example, if you want to use
hardware acceleration, you can pass in an ENGINE
object that represents your cryptographic accelerator.
- key
-
Pointer to the encryption key to be used.
- ivornonce
-
Pointer to an initialization vector or none, if appropriate (use
NULL otherwise). For CBC, CFB, and OFB modes, the
initialization vector or nonce is always the same size as the block
size of the cipher, which is often different from the key size of the
cipher.
There are also deprecated versions of these calls,
EVP_EncryptInit(
) and EVP_DecryptInit(
), that are the same except that they do not
take the engine argument, and they use only the
built-in software implementation.
Calling a function that returns an EVP_CIPHER
object will cause the cipher's implementation to
load dynamically and place information about the algorithm into an
internal table if it has not yet done so. Alternatively, you can load
all possible symmetric ciphers at once with a call to the function
OpenSSL_add_all_ciphers(
), or all ciphers and message digest algorithms
with a call to the function OpenSSL_add_all_algorithms(
) (neither function takes any arguments). For
algorithms that have been loaded, you can retrieve pointers to their
objects by name using the EVP_get_cipherbyname(
) function, which takes a single parameter of
type char *, representing the desired cipher
configuration.
Table 5-6 summarizes the possible functions that
can load ciphers (if necessary) and return
EVP_CIPHER objects. The table also shows the
strings that can be used to look up loaded ciphers.
|
As noted in Recipe 5.2, we personally recommend AES-based solutions,
or (of the ciphers OpenSSL offers) Triple-DES if AES is not
appropriate. If you use other algorithms, be sure to research them
thoroughly.
|
|
Table 5-6. Cipher instantiation reference|
AES
|
128 bits
|
ECB
|
EVP_aes_128_ecb( )
|
aes-128-ecb
|
AES
|
128 bits
|
CBC
|
EVP_aes_128_cbc( )
|
aes-128-cbc
|
AES
|
128 bits
|
CFB
|
EVP_aes_128_cfb( )
|
aes-128-cfb
|
AES
|
128 bits
|
OFB
|
EVP_aes_128_ofb( )
|
aes-128-ofb
|
AES
|
192 bits
|
ECB
|
EVP_aes_192_ecb( )
|
aes-192-ecb
|
AES
|
192 bits
|
CBC
|
EVP_aes_192_cbc( )
|
aes-192-cbc
|
AES
|
192 bits
|
CFB
|
EVP_aes_192_cfb( )
|
aes-192-cfb
|
AES
|
192 bits
|
OFB
|
EVP_aes_192_ofb( )
|
aes-192-ofb
|
AES
|
256 bits
|
ECB
|
EVP_aes_256_ecb( )
|
aes-256-ecb
|
AES
|
256 bits
|
CBC
|
EVP_aes_256_cbc( )
|
aes-256-cbc
|
AES
|
256 bits
|
CFB
|
EVP_aes_256_cfb( )
|
aes-256-cfb
|
AES
|
256 bits
|
OFB
|
EVP_aes_256_ofb( )
|
aes-256-ofb
|
Blowfish
|
128 bits
|
ECB
|
EVP_bf_ecb( )
|
bf-ecb
|
Blowfish
|
128 bits
|
CBC
|
EVP_bf_cbc( )
|
bf-cbc
|
Blowfish
|
128 bits
|
CFB
|
EVP_bf_cfb( )
|
bf-cfb
|
Blowfish
|
128 bits
|
OFB
|
EVP_bf_ofb( )
|
bf-ofb
|
CAST5
|
128 bits
|
ECB
|
EVP_cast_ecb( )
|
cast-ecb
|
CAST5
|
128 bits
|
CBC
|
EVP_cast_cbc( )
|
cast-cbc
|
CAST5
|
128 bits
|
CFB
|
EVP_cast_cfb( )
|
cast-cfb
|
CAST5
|
128 bits
|
OFB
|
EVP_cast_ofb( )
|
cast-ofb
|
DES
|
Effective: 56 bitsActual: 64 bits
|
ECB
|
EVP_des_ecb( )
|
des-ecb
|
DES
|
Effective: 56 bitsActual: 64 bits
|
CBC
|
EVP_des_cbc( )
|
des-cbc
|
DES
|
Effective: 56 bitsActual: 64 bits
|
CFB
|
EVP_des_cfb( )
|
des-cfb
|
DES
|
Effective: 56 bitsActual: 64 bits
|
OFB
|
EVP_des_ofb( )
|
des-ofb
|
DESX
|
Effective: 120 bitsActual:
128 bits
|
CBC
|
EVP_desx_cbc( )
|
desx
|
3-key Triple-DES
|
Effective: 112 bitsActual: 192 bits
|
ECB
|
EVP_des_ede3( )
|
des-ede3
|
3-key Triple-DES
|
Effective: 112 bitsActual: 192 bits
|
CBC
|
EVP_des_ede3_cbc( )
|
des-ede3-cbc
|
3-key Triple-DES
|
Effective: 112 bitsActual: 192 bits
|
CFB
|
EVP_des_ede3_cfb( )
|
des-ede3-cfb
|
3-key Triple-DES
|
Effective: 112 bitsActual: 192 bits
|
OFB
|
EVP_des_ede3_ofb( )
|
des-ede3-ofb
|
2-key Triple-DES
|
Effective: 112 bitsActual: 128 bits
|
ECB
|
EVP_des_ede( )
|
des-ede
|
2-key Triple-DES
|
Effective: 112 bitsActual: 128 bits
|
CBC
|
EVP_des_ede_cbc( )
|
des-ede-cbc
|
2-key Triple-DES
|
Effective: 112 bitsActual: 128 bits
|
CFB
|
EVP_des_ede_cfb( )
|
des-ede-cfb
|
2-key Triple-DES
|
Effective: 112 bitsActual: 128 bits
|
OFB
|
EVP_des_ede_ofb( )
|
des-ede-ofb
|
IDEA
|
128 bits
|
ECB
|
EVP_idea_ecb( )
|
idea-ecb
|
IDEA
|
128 bits
|
CBC
|
EVP_idea_cbc( )
|
idea-cbc
|
IDEA
|
128 bits
|
CFB
|
EVP_idea_cfb( )
|
idea-cfb
|
IDEA
|
128 bits
|
OFB
|
EVP_idea_ofb( )
|
idea-ofb
|
RC2™
|
128 bits
|
ECB
|
EVP_rc2_ecb( )
|
rc2-ecb
|
RC2™
|
128 bits
|
CBC
|
EVP_rc2_cbc( )
|
rc2-cbc
|
RC2™
|
128 bits
|
CFB
|
EVP_rc2_cfb( )
|
rc2-cfb
|
RC2™
|
128 bits
|
OFB
|
EVP_rc2_ofb( )
|
rc2-ofb
|
RC4™
|
40 bits
|
n/a
|
EVP_rc4_40( )
|
rc4-40
|
RC4™
|
128 bits
|
n/a
|
EVP_rc4( )
|
rc4
|
RC5™
|
128 bits
|
ECB
|
EVP_rc5_32_16_12_ecb( )
|
rc5-ecb
|
RC5™
|
128 bits
|
CBC
|
EVP_rc5_32_16_12_cbc( )
|
rc5-cbc
|
RC5™
|
128 bits
|
CFB
|
EVP_rc5_32_16_12_cfb( )
|
rc5-cfb
|
RC5™
|
128 bits
|
OFB
|
EVP_rc5_32_16_12_ofb( )
|
rc5-ofb
|
For stream-based modes (CFB and OFB), encryption and decryption are
identical operations. Therefore, EVP_EncryptInit_ex(
) and EVP_DecryptInit_ex( ) are
interchangeable in these cases.
|
While RC4 can be set up using these instructions, you must be very
careful to set it up securely. We discuss how to do so in Recipe
5.23.
|
|
Here is an example of setting up an encryption context using 128-bit
AES in CBC mode:
#include <openssl/evp.h>
#include <openssl/rand.h>
/* key must be of size EVP_MAX_KEY_LENGTH.
* iv must be of size EVP_MAX_IV_LENGTH.
*/
EVP_CIPHER_CTX *sample_setup(unsigned char *key, unsigned char *iv) {
EVP_CIPHER_CTX *ctx;
/* This uses the OpenSSL PRNG . See Recipe 11.9 */
RAND_bytes(key, EVP_MAX_KEY_LENGTH);
RAND_bytes(iv, EVP_MAX_IV_LENGTH);
if (!(ctx = (EVP_CIPHER_CTX *)malloc(sizeof(EVP_CIPHER_CTX)))) return 0;
EVP_CIPHER_CTX_init(ctx);
EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc( ), 0, key, iv);
return ctx;
}
This example selects a key and initialization vector at random. Both
of these items need to be communicated to any party that needs to
decrypt the data. The caller therefore needs to be able to recover
this information. In this example, we handle this by having the
caller pass in allocated memory, which we fill with the new key and
IV. The caller can then communicate them to the other party in
whatever manner is appropriate.
Note that to make replacing algorithms easier, we always create keys
and initialization vectors of the maximum possible length, using
macros defined in the openssl/evp.h header file.
5.17.4 See Also
Recipe 5.2, Recipe 5.9, Recipe 5.16, Recipe 5.18, Recipe 5.20, Recipe 5.23
|