blob: f4d21d3000cb2bd4bcfb45be2c8ecd8ecb07a4f6 [file] [log] [blame]
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
*/
/**
@file gcm_process.c
GCM implementation, process message data, by Tom St Denis
*/
#include "tomcrypt.h"
#ifdef GCM_MODE
/**
Process plaintext/ciphertext through GCM
@param gcm The GCM state
@param pt The plaintext
@param ptlen The plaintext length (ciphertext length is the same)
@param ct The ciphertext
@param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
@return CRYPT_OK on success
*/
int gcm_process(gcm_state *gcm,
unsigned char *pt, unsigned long ptlen,
unsigned char *ct,
int direction)
{
unsigned long x;
int y, err;
unsigned char b;
LTC_ARGCHK(gcm != NULL);
if (ptlen > 0) {
LTC_ARGCHK(pt != NULL);
LTC_ARGCHK(ct != NULL);
}
if (gcm->buflen > 16 || gcm->buflen < 0) {
return CRYPT_INVALID_ARG;
}
if ((err = cipher_is_valid(gcm->cipher)) != CRYPT_OK) {
return err;
}
/* in AAD mode? */
if (gcm->mode == GCM_MODE_AAD) {
/* let's process the AAD */
if (gcm->buflen) {
gcm->totlen += gcm->buflen * CONST64(8);
gcm_mult_h(gcm, gcm->X);
}
/* increment counter */
for (y = 15; y >= 12; y--) {
if (++gcm->Y[y] & 255) { break; }
}
/* encrypt the counter */
if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
return err;
}
gcm->buflen = 0;
gcm->mode = GCM_MODE_TEXT;
}
if (gcm->mode != GCM_MODE_TEXT) {
return CRYPT_INVALID_ARG;
}
x = 0;
#ifdef LTC_FAST
if (gcm->buflen == 0) {
if (direction == GCM_ENCRYPT) {
for (x = 0; x < (ptlen & ~15); x += 16) {
/* ctr encrypt */
for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
*((LTC_FAST_TYPE*)(&ct[x + y])) = *((LTC_FAST_TYPE*)(&pt[x+y])) ^ *((LTC_FAST_TYPE*)(&gcm->buf[y]));
*((LTC_FAST_TYPE*)(&gcm->X[y])) ^= *((LTC_FAST_TYPE*)(&ct[x+y]));
}
/* GMAC it */
gcm->pttotlen += 128;
gcm_mult_h(gcm, gcm->X);
/* increment counter */
for (y = 15; y >= 12; y--) {
if (++gcm->Y[y] & 255) { break; }
}
if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
return err;
}
}
} else {
for (x = 0; x < (ptlen & ~15); x += 16) {
/* ctr encrypt */
for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
*((LTC_FAST_TYPE*)(&gcm->X[y])) ^= *((LTC_FAST_TYPE*)(&ct[x+y]));
*((LTC_FAST_TYPE*)(&pt[x + y])) = *((LTC_FAST_TYPE*)(&ct[x+y])) ^ *((LTC_FAST_TYPE*)(&gcm->buf[y]));
}
/* GMAC it */
gcm->pttotlen += 128;
gcm_mult_h(gcm, gcm->X);
/* increment counter */
for (y = 15; y >= 12; y--) {
if (++gcm->Y[y] & 255) { break; }
}
if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
return err;
}
}
}
}
#endif
/* process text */
for (; x < ptlen; x++) {
if (gcm->buflen == 16) {
gcm->pttotlen += 128;
gcm_mult_h(gcm, gcm->X);
/* increment counter */
for (y = 15; y >= 12; y--) {
if (++gcm->Y[y] & 255) { break; }
}
if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
return err;
}
gcm->buflen = 0;
}
if (direction == GCM_ENCRYPT) {
b = ct[x] = pt[x] ^ gcm->buf[gcm->buflen];
} else {
b = ct[x];
pt[x] = ct[x] ^ gcm->buf[gcm->buflen];
}
gcm->X[gcm->buflen++] ^= b;
}
return CRYPT_OK;
}
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/encauth/gcm/gcm_process.c,v $ */
/* $Revision: 1.14 $ */
/* $Date: 2006/11/19 19:33:36 $ */