5.5 Using a Raw Block Cipher

5.5.1 Problem

You're trying to make one of our implementations for other block cipher modes work. They all use raw encryption operations as a foundation, and you would like to understand how to plug in third-party implementations.

5.5.2 Solution

Raw operations on block ciphers consist of three operations: key setup, encryption of a block, and decryption of a block. In other recipes, we provide three macros that you need to implement to use our code. In the discussion for this recipe, we'll look at several desirable bindings for these macros.

5.5.3 Discussion

Do not use raw encryption operations in your own designs! Such operations should only be used as a fundamental building block by skilled cryptographers.

Raw block ciphers operate on fixed-size chunks of data. That size is called the block size. The input and output are of this same fixed length. A block cipher also requires a key, which may be of a different length than the block size. Sometimes an algorithm will allow variable-length keys, but the block size is generally fixed.

Setting up a block cipher generally involves turning the raw key into a key schedule. Basically, the key schedule is just a set of keys derived from the original key in a cipher-dependent manner. You need to create the key schedule only once; it's good for every use of the underlying key because raw encryption always gives the same result for any {key, input} pair (the same is true for decryption).

Once you have a key schedule, you can generally pass it, along with an input block, into the cipher encryption function (or the decryption function) to get an output block.

To keep the example code as simple as possible, we've written it assuming you are going to want to use one and only one cipher with it (though it's not so difficult to make the code work with multiple ciphers).

To get the code in this book working, you need to define several macros:

SPC_BLOCK_SZ

Denotes the block size of the cipher in bytes.

SPC_KEY_SCHED

This macro must be an alias for the key schedule type that goes along with your cipher. This value will be library-specific and can be implemented by typedef instead of through a macro. Note that the key schedule type should be an array of bytes of some fixed size, so that we can ask for the size of the key schedule using sizeof(SPC_KEY_SCHED).

SPC_ENCRYPT_INIT(sched, key, keybytes) and SPC_DECRYPT_INIT(sched, key, keybytes)

Both of these macros take a pointer to a key schedule to write into, the key used to derive that schedule, and the number of bytes in that key. If you are using an algorithm with fixed-size keys, you can ignore the third parameter. Note that once you've built a key schedule, you shouldn't be able to tell the difference between different key lengths. In many implementations, initializing for encryption and initializing for decryption are the same operation.

SPC_DO_ENCRYPT(sched, in, out) and SPC_DO_DECRYPT(sched, in, out)

Both of these macros are expected to take a pointer to a key schedule and two pointers to memory corresponding to the input block and the output block. Both blocks are expected to be of size SPC_BLOCK_SZ.

In the following sections, we'll provide some bindings for these macros for Brian Gladman's AES implementation and for the OpenSSL API. Unfortunately, we cannot use Microsoft's CryptoAPI because it does not allow for exchanging symmetric encryption keys without encrypting them (see Recipe 5.26 and Recipe 5.27 to see how to work around this limitation)?and that would add significant complexity to what we're trying to achieve with this recipe. In addition, AES is only available in the .NET framework, which severely limits portability across various Windows versions. (The .NET framework is available only for Windows XP and Windows .NET Server 2003.)

5.5.3.1 Brian Gladman's AES implementation

Brian Gladman has written the fastest freely available AES implementation to date. He has a version in x86 assembly that works with Windows and a portable C version that is faster than the assembly versions other people offer. It's available from his web page at http://fp.gladman.plus.com/AES/.

To bind his implementation to our macros, do the following:

#include "aes.h"
   
#define SPC_BLOCK_SZ 16
typedef aes_ctx SPC_KEY_SCHED;
#define SPC_ENCRYPT_INIT(sched, key, keybytes) aes_enc_key(key, keybytes, sched)
#define SPC_DECRYPT_INIT(sched, key, keybytes) aes_dec_key(key, keybytes, sched)
#define SPC_DO_ENCRYPT(sched, in, out)         aes_enc_block(in, out, sched)
#define SPC_DO_DECRYPT(sched, in, out)         aes_dec_block(in, out, sched)
5.5.3.2 OpenSSL block cipher implementations

Next, we'll provide implementations for these macros for all of the ciphers in OpenSSL 0.9.7. Note that the block size for all of the algorithms listed in this section is 8 bytes, except for AES, which is 16.

Table 5-2 lists the block ciphers that OpenSSL exports, along with the header file you need to include for each cipher and the associated type for the key schedule.

Table 5-2. Block ciphers supported by OpenSSL

Cipher

Header file

Key schedule type

AES

openssl/aes.h

AES_KEY

Blowfish

openssl/blowfish.h

BF_KEY

CAST5

openssl/cast.h

CAST_KEY

DES

openssl/des.h

DES_key_schedule

3-key Triple-DES

openssl/des.h

DES_EDE_KEY

2-key Triple-DES

openssl/des.h

DES_EDE_KEY

IDEA

openssl/idea.h

IDEA_KEY_SCHEDULE

RC2

openssl/rc2.h

RC2_KEY

RC5

openssl/rc5.h

RC5_32_KEY

Table 5-3 provides implementations of the SPC_ENCRYPT_INIT macro for each of the block ciphers listed in Table 5-2.

Table 5-3. Implementations for the SPC_ENCRYPT_INIT macro for each OpenSSL-supported block cipher

Cipher

OpenSSL-based SPC_ENCRYPT_INIT implementation

AES

AES_set_encrypt_key(key, keybytes * 8, sched)

Blowfish

BF_set_key(sched, keybytes, key)

CAST5

CAST_set_key(sched, keybytes, key)

DES

DES_set_key_unchecked((DES_cblock *)key, sched)

3-key Triple-DES

DES_set_key_unchecked((DES_cblock *)key, &sched->ks1); \DES_set_key_unchecked((DES_cblock *)(key + 8), &sched->ks2); \DES_set_key_unchecked((DES_cblock *)(key + 16), &sched->ks3);

2-key Triple-DES

DES_set_key_unchecked((DES_cblock *)key, &sched->ks1); \DES_set_key_unchecked((DES_cblock *)(key + 8), &sched->ks2);

IDEA

idea_set_encrypt_key(key, sched);

RC2

RC2_set_key(sched, keybytes, key, keybytes * 8);

RC5

RC5_32_set_key(sched, keybytes, key, 12);

In most of the implementations in Table 5-3, SPC_DECRYPT_INIT will be the same as SPC_ENCRYPT_INIT (you can define one to the other). The two exceptions are AES and IDEA. For AES:

#define SPC_DECRYPT_INIT(sched, key, keybytes) \
            AES_set_decrypt_key(key, keybytes * 8, sched)

For IDEA:

#define SPC_DECRYPT_INIT(sched, key, keybytes) { \
            IDEA_KEY_SCHEDULE tmp;\
            idea_set_encrypt_key(key, &tmp);\
            idea_set_decrypt_key(&tmp, sched);\
}

Table 5-4 and Table 5-5 provide implementations of the SPC_DO_ENCRYPT and SPC_DO_DECRYPT macros.

Table 5-4. Implementations for the SPC_DO_ENCRYPT macro for each OpenSSL-supported block cipher

Cipher

OpenSSL-based SPC_DO_ENCRYPT implementation

AES

AES_encrypt(in, out, sched)

Blowfish

BF_ecb_encrypt(in, out, sched, 1)

CAST5

CAST_ecb_encrypt(in, out, sched, 1)

DES

DES_ecb_encrypt(in, out, sched, 1)

3-key Triple-DES

DES_ecb3_encrypt((DES_cblock *)in, (DES_cblock *)out, \ &sched->ks1, &sched->ks2, &sched->ks3, 1);

2-key Triple-DES

DES_ecb3_encrypt((DES_cblock *)in, (DES_cblock *)out, \ &sched->ks1, &sched->ks2, &sched->ks1, 1);

IDEA

idea_ecb_encrypt(in, out, sched);

RC2

RC2_ecb_encrypt(in, out, sched, 1);

RC5

RC5_32_ecb_encrypt(in, out, sched, 1);

Table 5-5. Implementations for the SPC_DO_DECRYPT macro for each OpenSSL-supported block cipher

Cipher

OpenSSL-based SPC_DO_DECRYPT implementation

AES

AES_decrypt(in, out, sched)

Blowfish

BF_ecb_encrypt(in, out, sched, 0)

CAST5

CAST_ecb_encrypt(in, out, sched, 0)

DES

DES_ecb_encrypt(in, out, sched, 0)

3-key Triple-DES

DES_ecb3_encrypt((DES_cblock *)in, (DES_cblock *)out, \ &sched->ks1, &sched->ks2, &sched->ks3, 0);

2-key Triple-DES

DES_ecb3_encrypt((DES_cblock *)in, (DES_cblock *)out, \ &sched->ks1, &sched->ks2, &sched->ks1, 0);

IDEA

idea_ecb_encrypt(in, out, sched);

RC2

RC2_ecb_encrypt(in, out, sched, 0);

RC5

RC5_32_ecb_encrypt(in, out, sched, 0);

5.5.4 See Also

  • Brian Gladman's AES page: http://fp.gladman.plus.com/AES/

  • OpenSSL home page: http://www.openssl.org/

  • Recipe 5.4, Recipe 5.26, Recipe 5.27.