tomcrypt/src/encauth/gcm/gcm_process.c

156 lines
4.5 KiB
C
Raw Normal View History

2005-04-17 11:37:13 +00:00
/* 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.
*/
/**
@file gcm_process.c
GCM implementation, process message data, by Tom St Denis
*/
#include "tomcrypt.h"
2007-07-20 17:48:02 +00:00
#ifdef LTC_GCM_MODE
2005-04-17 11:37:13 +00:00
2014-01-03 15:16:59 +01:00
/**
2005-04-17 11:37:13 +00:00
Process plaintext/ciphertext through GCM
2014-01-03 15:16:59 +01:00
@param gcm The GCM state
2005-04-17 11:37:13 +00:00
@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)
{
2006-11-17 14:21:24 +00:00
unsigned long x;
int y, err;
2005-04-17 11:37:13 +00:00
unsigned char b;
LTC_ARGCHK(gcm != NULL);
2005-04-19 11:30:30 +00:00
if (ptlen > 0) {
LTC_ARGCHK(pt != NULL);
LTC_ARGCHK(ct != NULL);
}
2005-04-17 11:37:13 +00:00
if (gcm->buflen > 16 || gcm->buflen < 0) {
return CRYPT_INVALID_ARG;
}
2014-01-03 15:16:59 +01:00
2005-04-17 11:37:13 +00:00
if ((err = cipher_is_valid(gcm->cipher)) != CRYPT_OK) {
return err;
}
/* 0xFFFFFFFE0 = ((2^39)-256)/8 */
if (gcm->pttotlen / 8 + (ulong64)gcm->buflen + (ulong64)ptlen >= CONST64(0xFFFFFFFE0)) {
return CRYPT_INVALID_ARG;
}
2005-04-17 11:37:13 +00:00
/* in AAD mode? */
2007-07-20 17:48:02 +00:00
if (gcm->mode == LTC_GCM_MODE_AAD) {
2005-04-17 11:37:13 +00:00
/* let's process the AAD */
if (gcm->buflen) {
gcm->totlen += gcm->buflen * CONST64(8);
gcm_mult_h(gcm, gcm->X);
}
/* increment counter */
2006-12-16 18:10:04 +00:00
for (y = 15; y >= 12; y--) {
2006-08-30 23:30:00 +00:00
if (++gcm->Y[y] & 255) { break; }
2005-04-17 11:37:13 +00:00
}
/* encrypt the counter */
2005-11-18 05:15:37 +00:00
if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
return err;
}
2005-04-17 11:37:13 +00:00
gcm->buflen = 0;
2007-07-20 17:48:02 +00:00
gcm->mode = LTC_GCM_MODE_TEXT;
2005-04-17 11:37:13 +00:00
}
2007-07-20 17:48:02 +00:00
if (gcm->mode != LTC_GCM_MODE_TEXT) {
2005-04-17 11:37:13 +00:00
return CRYPT_INVALID_ARG;
}
x = 0;
#ifdef LTC_FAST
if (gcm->buflen == 0) {
2014-01-03 15:16:59 +01:00
if (direction == GCM_ENCRYPT) {
2005-04-17 11:37:13 +00:00
for (x = 0; x < (ptlen & ~15); x += 16) {
/* ctr encrypt */
for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
2016-06-28 00:34:37 -04:00
*(LTC_FAST_TYPE_PTR_CAST(&ct[x + y])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[x+y])) ^ *(LTC_FAST_TYPE_PTR_CAST(&gcm->buf[y]));
*(LTC_FAST_TYPE_PTR_CAST(&gcm->X[y])) ^= *(LTC_FAST_TYPE_PTR_CAST(&ct[x+y]));
2005-04-17 11:37:13 +00:00
}
/* GMAC it */
gcm->pttotlen += 128;
gcm_mult_h(gcm, gcm->X);
/* increment counter */
2006-12-16 18:10:04 +00:00
for (y = 15; y >= 12; y--) {
2006-08-30 23:30:00 +00:00
if (++gcm->Y[y] & 255) { break; }
2005-04-17 11:37:13 +00:00
}
2005-11-18 05:15:37 +00:00
if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
return err;
}
2005-04-17 11:37:13 +00:00
}
} else {
for (x = 0; x < (ptlen & ~15); x += 16) {
/* ctr encrypt */
for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
2016-06-28 00:34:37 -04:00
*(LTC_FAST_TYPE_PTR_CAST(&gcm->X[y])) ^= *(LTC_FAST_TYPE_PTR_CAST(&ct[x+y]));
*(LTC_FAST_TYPE_PTR_CAST(&pt[x + y])) = *(LTC_FAST_TYPE_PTR_CAST(&ct[x+y])) ^ *(LTC_FAST_TYPE_PTR_CAST(&gcm->buf[y]));
2005-04-17 11:37:13 +00:00
}
/* GMAC it */
gcm->pttotlen += 128;
gcm_mult_h(gcm, gcm->X);
/* increment counter */
2006-12-16 18:10:04 +00:00
for (y = 15; y >= 12; y--) {
2006-08-30 23:30:00 +00:00
if (++gcm->Y[y] & 255) { break; }
2005-04-17 11:37:13 +00:00
}
2005-11-18 05:15:37 +00:00
if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
return err;
}
2005-04-17 11:37:13 +00:00
}
2015-12-19 17:30:38 +01:00
}
2005-04-17 11:37:13 +00:00
}
2014-01-03 15:16:59 +01:00
#endif
2005-04-17 11:37:13 +00:00
/* process text */
for (; x < ptlen; x++) {
if (gcm->buflen == 16) {
gcm->pttotlen += 128;
gcm_mult_h(gcm, gcm->X);
2014-01-03 15:16:59 +01:00
2005-04-17 11:37:13 +00:00
/* increment counter */
2006-12-16 18:10:04 +00:00
for (y = 15; y >= 12; y--) {
2006-08-30 23:30:00 +00:00
if (++gcm->Y[y] & 255) { break; }
2005-04-17 11:37:13 +00:00
}
2005-11-18 05:15:37 +00:00
if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
return err;
}
2005-04-17 11:37:13 +00:00
gcm->buflen = 0;
}
if (direction == GCM_ENCRYPT) {
2014-01-03 15:16:59 +01:00
b = ct[x] = pt[x] ^ gcm->buf[gcm->buflen];
2005-04-17 11:37:13 +00:00
} else {
b = ct[x];
pt[x] = ct[x] ^ gcm->buf[gcm->buflen];
}
2014-01-03 15:16:59 +01:00
gcm->X[gcm->buflen++] ^= b;
2005-04-17 11:37:13 +00:00
}
return CRYPT_OK;
}
#endif
2005-06-09 00:08:13 +00:00
/* $Source$ */
/* $Revision$ */
/* $Date$ */