1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3  *
4  * LibTomCrypt is a library that provides various cryptographic
5  * algorithms in a highly modular and flexible manner.
6  *
7  * The library is free for all purposes without any express
8  * guarantee it works.
9  */
10 
11 /**
12    @file gcm_process.c
13    GCM implementation, process message data, by Tom St Denis
14 */
15 #include "tomcrypt_private.h"
16 
17 #ifdef LTC_GCM_MODE
18 
19 /**
20   Process plaintext/ciphertext through GCM
21   @param gcm       The GCM state
22   @param pt        The plaintext
23   @param ptlen     The plaintext length (ciphertext length is the same)
24   @param ct        The ciphertext
25   @param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
26   @return CRYPT_OK on success
27  */
gcm_process(gcm_state * gcm,unsigned char * pt,unsigned long ptlen,unsigned char * ct,int direction)28 int gcm_process(gcm_state *gcm,
29                      unsigned char *pt,     unsigned long ptlen,
30                      unsigned char *ct,
31                      int direction)
32 {
33    unsigned long x;
34    int           y, err;
35    unsigned char b;
36 
37    LTC_ARGCHK(gcm != NULL);
38    if (ptlen > 0) {
39       LTC_ARGCHK(pt  != NULL);
40       LTC_ARGCHK(ct  != NULL);
41    }
42 
43    if (gcm->buflen > 16 || gcm->buflen < 0) {
44       return CRYPT_INVALID_ARG;
45    }
46 
47    if ((err = cipher_is_valid(gcm->cipher)) != CRYPT_OK) {
48       return err;
49    }
50 
51    /* 0xFFFFFFFE0 = ((2^39)-256)/8 */
52    if (gcm->pttotlen / 8 + (ulong64)gcm->buflen + (ulong64)ptlen >= CONST64(0xFFFFFFFE0)) {
53       return CRYPT_INVALID_ARG;
54    }
55 
56    if (gcm->mode == LTC_GCM_MODE_IV) {
57       /* let's process the IV */
58       if ((err = gcm_add_aad(gcm, NULL, 0)) != CRYPT_OK) return err;
59    }
60 
61    /* in AAD mode? */
62    if (gcm->mode == LTC_GCM_MODE_AAD) {
63       /* let's process the AAD */
64       if (gcm->buflen) {
65          gcm->totlen += gcm->buflen * CONST64(8);
66          gcm_mult_h(gcm, gcm->X);
67       }
68 
69       /* increment counter */
70       for (y = 15; y >= 12; y--) {
71           if (++gcm->Y[y] & 255) { break; }
72       }
73       /* encrypt the counter */
74       if ((err = cipher_descriptor[gcm->cipher]->ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
75          return err;
76       }
77 
78       gcm->buflen = 0;
79       gcm->mode   = LTC_GCM_MODE_TEXT;
80    }
81 
82    if (gcm->mode != LTC_GCM_MODE_TEXT) {
83       return CRYPT_INVALID_ARG;
84    }
85 
86    x = 0;
87 #ifdef LTC_FAST
88    if (gcm->buflen == 0) {
89       if (direction == GCM_ENCRYPT) {
90          for (x = 0; x < (ptlen & ~15); x += 16) {
91              /* ctr encrypt */
92              for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
93                  *(LTC_FAST_TYPE_PTR_CAST(&ct[x + y])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[x+y])) ^ *(LTC_FAST_TYPE_PTR_CAST(&gcm->buf[y]));
94                  *(LTC_FAST_TYPE_PTR_CAST(&gcm->X[y])) ^= *(LTC_FAST_TYPE_PTR_CAST(&ct[x+y]));
95              }
96              /* GMAC it */
97              gcm->pttotlen += 128;
98              gcm_mult_h(gcm, gcm->X);
99              /* increment counter */
100              for (y = 15; y >= 12; y--) {
101                  if (++gcm->Y[y] & 255) { break; }
102              }
103              if ((err = cipher_descriptor[gcm->cipher]->ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
104                 return err;
105              }
106          }
107       } else {
108          for (x = 0; x < (ptlen & ~15); x += 16) {
109              /* ctr encrypt */
110              for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
111                  *(LTC_FAST_TYPE_PTR_CAST(&gcm->X[y])) ^= *(LTC_FAST_TYPE_PTR_CAST(&ct[x+y]));
112                  *(LTC_FAST_TYPE_PTR_CAST(&pt[x + y])) = *(LTC_FAST_TYPE_PTR_CAST(&ct[x+y])) ^ *(LTC_FAST_TYPE_PTR_CAST(&gcm->buf[y]));
113              }
114              /* GMAC it */
115              gcm->pttotlen += 128;
116              gcm_mult_h(gcm, gcm->X);
117              /* increment counter */
118              for (y = 15; y >= 12; y--) {
119                  if (++gcm->Y[y] & 255) { break; }
120              }
121              if ((err = cipher_descriptor[gcm->cipher]->ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
122                 return err;
123              }
124          }
125       }
126    }
127 #endif
128 
129    /* process text */
130    for (; x < ptlen; x++) {
131        if (gcm->buflen == 16) {
132           gcm->pttotlen += 128;
133           gcm_mult_h(gcm, gcm->X);
134 
135           /* increment counter */
136           for (y = 15; y >= 12; y--) {
137               if (++gcm->Y[y] & 255) { break; }
138           }
139           if ((err = cipher_descriptor[gcm->cipher]->ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
140              return err;
141           }
142           gcm->buflen = 0;
143        }
144 
145        if (direction == GCM_ENCRYPT) {
146           b = ct[x] = pt[x] ^ gcm->buf[gcm->buflen];
147        } else {
148           b = ct[x];
149           pt[x] = ct[x] ^ gcm->buf[gcm->buflen];
150        }
151        gcm->X[gcm->buflen++] ^= b;
152    }
153 
154    return CRYPT_OK;
155 }
156 
157 #endif
158 
159 /* ref:         $Format:%D$ */
160 /* git commit:  $Format:%H$ */
161 /* commit time: $Format:%ai$ */
162