The Zork GCM API

GCM is an encryption mode that provides both data secrecy and message integrity. When using this mode, one can determine definitively whether the plaintext is in the original form that it was in when originally encrypted. The ciphertext is always 128 bits longer than the plaintext.

GCM is a provably secure construct. This means that the any attack on GCM can be turned into an attack on the underlying block cipher. As a result, if your block cipher is secure, then GCM will be secure, when used as intended.

GCM can work with any block cipher, but it is expected that it will primarily be used with 128-bit block ciphers such as AES. This implementation provides an AES implementation based on the "fast" reference implementation.

GCM can also be used to authenticate data that it does not encrypt. This is intended for plaintext headers and other things that don't need to be secret, but still need to be transmitted without modification.

A related construct is GMAC, which provides message integrity checking without secrecy. Our API includes an interface to GMAC.

Basic GCM operation

In the Zork GCM API, one instantiates a GCM context object (type gcm_ctx, defined in gcm.h) and uses this context object to encrypt individual messages. Setting up a context object is done with gcm_init_256b():

void gcm_init_256b(gcm_ctx_256b *c, uchar key[], size_t keylen);

The key parameter is an AES key, and keylen is a length in bits. This key does not normally change between messages, but you can change it by calling gcm_init_256b() again.

Note that there are different APIs depending on the internal table size used. We recommend 256 byte tables, but 4K also seems acceptable. We would stay away from larger table sizes, due to the table not fitting comfortably in cache (this could result in timing attacks). Encrypting a message is done with gcm_encrypt_256b():

void gcm_encrypt_256b(gcm_ctx_256b *c, uchar *nonce, size_t nlen, uchar *pt, size_t ptlen, uchar *adata, size_t al en, uchar *ct, uchar *tag);

The parameters to this function have the following meanings:

One can decrypt and check the integrity of a message using gcm_decrypt_256b():

int gcm_decrypt_256b(gcm_ctx_256b *c, uchar *nonce, size_t nlen, uchar *ct, size_t ctlen, uchar *tag, size_t taglen, uchar *adata, size_t alen, uchar *pt);

If message does not decrypt properly, then nothing will be written to the output buffer and the function will return 0. The parameter taglen specifies how many bytes the tag is (thus, supporting tag truncation).

One can erase a context by calling gcm_destroy():

gcm_destroy_256b(gcm_ctx_256b *c);

Security Considerations

The Secure Programming Cookbook shows how to use modes like GCM in such a way as to prevent against risks that are not the responsibility of an encryption mode. However, we go through the issues at a high level here.

Nonces must be unique. It is critical that key, nonce pairs never be reused. It's sufficient to choose a random session key and then use a message counter for the nonce. Using other data in the nonce is perfectly acceptable as well. We personally recommend using a 48-bit random salt and a 48-bit message counter.

Note that the nonce is automatically authenticated alongside the message. As a result, there is no technical need for "additional authenticated data" (AAD). However, GCM uses the AAD notion to achieve efficiency in high-speed hardware implementations (e.g., links that are 10Gbit/sec or higher). If your application might conceivably need to run in such an environment, we recommend making the nonce exactly 12 bytes and authenticating any additional data using the AAD parameter.

Capture replay is not GCM's responsibility. GCM does not automatically provide protection against capture-replay problems. However, protecting against such problems is easy. One only needs to ensure that the nonce on the arriving message has never been used with a previous message that we managed to decrypt. One can do this simply by always incrementing the nonce by one for each message and then checking on the receiving end to make sure that the nonce is always incrementing.

Secure memory is not GCM's responsibility. If local attacks are in your threat model, then you pay wish to try keeping GCM contexts and other sensitive data protected in memory. Techniques for doing this are detailed in the Secure Programming Cookbook.

Generally, we recommend erasing key material and plaintext immediately after use. That is, after calling gcm_init(), one should write over the key with zeros in order to minimize the risk of accidental information leakage.


Back