1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 /**
5    @file gcm_done.c
6    GCM implementation, Terminate the stream, by Tom St Denis
7 */
8 #include "tomcrypt_private.h"
9 
10 #ifdef LTC_GCM_MODE
11 
12 /**
13   Terminate a GCM stream
14   @param gcm     The GCM state
15   @param tag     [out] The destination for the MAC tag
16   @param taglen  [in/out]  The length of the MAC tag
17   @return CRYPT_OK on success
18  */
gcm_done(gcm_state * gcm,unsigned char * tag,unsigned long * taglen)19 int gcm_done(gcm_state *gcm,
20                      unsigned char *tag,    unsigned long *taglen)
21 {
22    unsigned long x;
23    int err;
24 
25    LTC_ARGCHK(gcm     != NULL);
26    LTC_ARGCHK(tag     != NULL);
27    LTC_ARGCHK(taglen  != NULL);
28 
29    if (gcm->buflen > 16 || gcm->buflen < 0) {
30       return CRYPT_INVALID_ARG;
31    }
32 
33    if ((err = cipher_is_valid(gcm->cipher)) != CRYPT_OK) {
34       return err;
35    }
36 
37    if (gcm->mode == LTC_GCM_MODE_IV) {
38       /* let's process the IV */
39       if ((err = gcm_add_aad(gcm, NULL, 0)) != CRYPT_OK) return err;
40    }
41 
42    if (gcm->mode == LTC_GCM_MODE_AAD) {
43       /* let's process the AAD */
44       if ((err = gcm_process(gcm, NULL, 0, NULL, 0)) != CRYPT_OK) return err;
45    }
46 
47    if (gcm->mode != LTC_GCM_MODE_TEXT) {
48       return CRYPT_INVALID_ARG;
49    }
50 
51    /* handle remaining ciphertext */
52    if (gcm->buflen) {
53       gcm->pttotlen += gcm->buflen * CONST64(8);
54       gcm_mult_h(gcm, gcm->X);
55    }
56 
57    /* length */
58    STORE64H(gcm->totlen, gcm->buf);
59    STORE64H(gcm->pttotlen, gcm->buf+8);
60    for (x = 0; x < 16; x++) {
61        gcm->X[x] ^= gcm->buf[x];
62    }
63    gcm_mult_h(gcm, gcm->X);
64 
65    /* encrypt original counter */
66    if ((err = cipher_descriptor[gcm->cipher]->ecb_encrypt(gcm->Y_0, gcm->buf, &gcm->K)) != CRYPT_OK) {
67       return err;
68    }
69    for (x = 0; x < 16 && x < *taglen; x++) {
70        tag[x] = gcm->buf[x] ^ gcm->X[x];
71    }
72    *taglen = x;
73 
74    cipher_descriptor[gcm->cipher]->done(&gcm->K);
75 
76    return CRYPT_OK;
77 }
78 
79 #endif
80 
81