Use the reference implementation available from http://www.zork.org/cwc/, or use Brian Gladman's implementation, available from http://fp.gladman.plus.com/AES/cwc.zip.
CWC mode is a mode of operation for providing both encryption and message integrity. This mode is parallelizable, fast in both software and hardware (where it can achieve speeds of 10 gigabits per second), unencumbered by patents, and provably secure to good bounds with standard assumptions. (We compare CWC to other modes in Recipe 5.4.)
CWC mode is not simple to implement because it uses a universal hash function as a component that is conceptually straightforward but somewhat complex to implement well. We therefore recommend using an off-the-shelf implementation, such as the implementation on the official CWC web page (http://www.zork.org/cwc/).
Here, we'll discuss how to use the distribution available from the CWC web page. This implementation has a set of macros similar to the macros we develop in Recipe 5.5 allowing you to bind the library to any AES implementation. In particular, if you edit local_options.h , you need to do the following:
Set AES_KS_T
to whatever value you would set
SPC_KEY_SCHED
(see Recipe 5.5).
Set CWC_AES_SETUP
to whatever value you would set
SPC_ENCRYPT_INIT
(see Recipe 5.5).
Set CWC_AES_ENCRYPT
to whatever value you would
set SPC_DO_ENCRYPT
(see Recipe 5.5).
Once those bindings are made, the Zork CWC implementation has a simple API that accepts an entire message at once:
int cwc_init(cwc_t ctx[1], u_char key[ ], int keybits); void cwc_encrypt_message(cwc_t ctx[1], u_char a[ ], u_int32 alen, u_char pt[ ], u_int32 ptlen, u_char nonce[11], u_char output[ ]); int cwc_decrypt_message(cwc_t ctx[1], u_char a[ ], u_int32 alen, u_char ct[ ], u_int32 ctlen, u_char nonce[11], u_char output[ ]); void cwc_cleanup(cwc_t ctx[1]);
If you have very large messages, this API insists that you buffer them before encrypting or decrypting. That's not a fundamental limitation of CWC mode, but only of this implementation. A future version of the implementation might change that, but do note that it would require partially decrypting a message before the library could determine whether the message is authentic. The API above does not decrypt if the message isn't authentic.
If you need to operate on very large messages, check out Brian Gladman's CWC implementation, which works incrementally.
This API looks slightly different from the all-in-one APIs we've presented for other modes in this chapter. It's actually closer to the incremental mode. The CWC mode has a notion of individual messages. It is intended that each message be sent individually. You're expected to use a single key for a large number of messages, but each message gets its own nonce. Generally, each message is expected to be short but can be multiple gigabytes.
Note that encrypting a message grows the message by 16 bytes. The extra 16 bytes at the end are used for ensuring the integrity of the message (it is effectively the result of a message authentication code; see Chapter 6).
The previous API assumes that you have the entire message to encrypt or decrypt at once. In the following discussion, we'll talk about the API that allows you to incrementally process a single message.
The cwc_init( )
function allows us to initialize a CWC
context object of type cwc_t
that can be reused
across multiple messages. Generally, a single key will be used for an
entire session. The first argument is a pointer to the
cwc_t
object (the declaration as an array of one
is a specification saying that the pointer is only to a single object
rather than to an array of objects). The second argument is the AES
key, which must be a buffer of 16, 24, or 32 bytes. The third
argument specifies the number of bits in the key (128, 192 or 256).
The function fails if keybits
is not a correct
value.
The cwc_encrypt_message(
)
function has the following arguments:
ctx
Pointer to the cwc_t
context object.
a
Buffer containing optional data that you would like to authenticate, but that does not need to be encrypted, such as plaintext headers in the HTTP protocol.
alen
Length of extra authentication data buffer, specified in bytes. It may be zero if there is no such data.
pt
Buffer containing the plaintext you would like to encrypt and authenticate.
ptlen
Length of the plaintext buffer. It may be zero if there is no data to be encrypted.
nonce
Pointer to an 11-byte buffer, which must be unique for each message. (See Recipe 4.9 for hints on nonce selection.)
output
Buffer into which the ciphertext is written. This buffer must always
be at least ptlen + 16
bytes in size because the
message grows by 16 bytes when the authentication value is added.
This function always succeeds. The cwc_decrypt_message(
)
function, on the other hand, returns 1 on
success, and 0 on failure. Failure occurs only if the message
integrity check fails, meaning the data has somehow changed since it
was originally encrypted. This function has the following arguments:
ctx
Pointer to the cwc_t
context object.
a
Buffer containing optional data that you would like to authenticate, but that was not encrypted, such as plaintext headers in the HTTP protocol.
alen
Length of extra authentication data buffer, specified in bytes. It may be zero if there is no such data.
ct
Buffer containing the ciphertext you would like to authenticate and decrypt if it is valid.
ctlen
Length of the ciphertext buffer. It may be zero if there is no data to be decrypted.
nonce
Pointer to an 11-byte buffer, which must be unique for each message. (See Recipe 4.9 for hints on nonce selection.)
output
Buffer into which the plaintext is written. This buffer must always
be at least ctlen - 16
bytes in size because the
message shrinks by 16 bytes when the authentication value is removed.
The cwc_cleanup( )
function simply wipes the contents of the
cwc
context object passed into it.
CWC implementation from Brian Gladman: http://fp.gladman.plus.com/AES/cwc.zip
CWC home page: http://www.zork.org/cwc