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.[14] [14] EVP stands for "envelope." 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 Cipher | Key strength / actual size (if different) | Cipher mode | Call for EVP_CIPHER object | Cipher lookup string |
---|
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[15]: 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 | [15] There are known plaintext attacks against DESX that reduce the effective strength to 60 bits, but these are generally considered infeasible. 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 |