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 assumes 128-bit blocks and 128-bit keys. We also use the OpenSSL AES API, although it is easy to bind to other AES implementations.
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.
void gcm_init(gcm_ctx *c, uchar key[16]);
The key parameter is a 128-bit AES key. This key does not normally change between messages, but you can change it by calling gcm_init() again. Encrypting a message is done with gcm_encrypt():
void gcm_encrypt(gcm_ctx *c, uchar *nonce, size_t nlen,
uchar *in, uchar *out, size_t inlen);
The parameters to this function have the following meanings:
int gcm_decrypt(gcm_ctx *c, uchar *nonce, size_t nlen, uchar
*ct, uchar *pt, size_t ptlen);
This function takes the same parameters as gcm_encrypt(). However, this function behaves a tiny bit differently. First, if the message does not decrypt properly, then nothing will be written to the output buffer and the function will return 0. Second, if the message is intact then the output buffer will always be 16 bytes shorter than the input buffer. Note that you are expected to specify the length of the input buffer, not the output buffer.
If one wishes to authenticate additional data with a message beyond what is beind encrypted or decrypted then one can call gcm_set_associated_data() before performing the encryption or decryption operation:
void gcm_set_associated_data(gcm_ctx *c, uchar *ad, size_t len);
This function requires only a pointer to a context object, the additional data to authenticate and the length of that data. One can erase a context by calling gcm_destroy():
gcm_destroy(gcm_ctx *c);
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.
GMAC's API consists of the following four functions:
void gmac_init(gmac_ctx *c, uchar key[16]);
void gmac_compute(gmac_ctx *c, uchar *nonce, size_t nlen, uchar *msg, size_t mlen, uchar tag[16]);
int gmac_compare(gmac_ctx *c, uchar *nonce, size_t nlen, uchar *msg, size_t mlen, uchar tag[16]);
void gmac_destroy(gmac_ctx *c);
The nonce has the exact same requirements as for GCM mode above.
The message sender should call gcm_compute(), which given an
input, produces an authentication tag. The message receiver should
pass that tag along with the information needed to recompute that tag
to gcm_compare(). If the message is intact,
gcm_compare() will return non-zero.
Note that GMAC shares the same security considerations as GCM mode.
void igcm_encrypt_init(gcm_ctx *c, uchar *nonce, size_t nlen);
void igcm_encrypt_update(gcm_ctx *c, uchar *pt, uchar *ct, size_t len);
void igcm_encrypt_final(gcm_ctx *c, uchar tag[16]);
void igcm_decrypt_init(gcm_ctx *c, uchar *nonce, size_t nlen);
void igcm_decrypt_update(gcm_ctx *c, uchar *pt, uchar *ct, size_t len);
void igcm_decrypt_final(gcm_ctx *c, uchar tag_loc[16]);
void igcm_assoc_update(gcm_ctx *c, uchar *data, size_t len);
Note that, before one uses this API, one must still key the
gcm_ctx object using gcm_init().
The functions igcm_encrypt_init() and
igcm_decrypt_init() set the nonce for a given message and
must be called before further processing is done (although the GCM API
will not actually enforce this... you will just get incorrect
results).
igcm_encrypt_update() encrypts part of a message, and always outputs exactly as many bytes as are input. igcm_decrypt_update() is the analog for decryption, and also outputs as many bytes as are input.
igcm_encrypt_final() produces the last 16 bytes of the message (the message authentication tag). igcm_decrypt_final() takes the message authentication tag as an input and makes sure it is correct, returning non-zero if it is.
WARNING: Using this API, the message will be decrypted before its validity is definitively determined. The regular GCM API doesn't bother decrypting if the message isn't valid. Be sure to check the return value of igcm_decrypt_final() and act accordingly!
void igmac_init(gmac_ctx *c, uchar key[16], uchar *nonce, size_t nlen);
void igmac_update(gmac_ctx *c, uchar *data, size_t dlen);
void igmac_final_compute(gmac_ctx *c, uchar tag[16]);
int igmac_final_compare(gmac_ctx *c, uchar tag[16]);