1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 /**
5    @file gcm_memory.c
6    GCM implementation, process a packet, by Tom St Denis
7 */
8 #include "tomcrypt_private.h"
9 
10 #ifdef LTC_GCM_MODE
11 
12 /**
13   Process an entire GCM packet in one call.
14   @param cipher            Index of cipher to use
15   @param key               The secret key
16   @param keylen            The length of the secret key
17   @param IV                The initialization vector
18   @param IVlen             The length of the initialization vector
19   @param adata             The additional authentication data (header)
20   @param adatalen          The length of the adata
21   @param pt                The plaintext
22   @param ptlen             The length of the plaintext (ciphertext length is the same)
23   @param ct                The ciphertext
24   @param tag               [out] The MAC tag
25   @param taglen            [in/out] The MAC tag length
26   @param direction         Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
27   @return CRYPT_OK on success
28  */
gcm_memory(int cipher,const unsigned char * key,unsigned long keylen,const unsigned char * IV,unsigned long IVlen,const unsigned char * adata,unsigned long adatalen,unsigned char * pt,unsigned long ptlen,unsigned char * ct,unsigned char * tag,unsigned long * taglen,int direction)29 int gcm_memory(      int           cipher,
30                const unsigned char *key,    unsigned long keylen,
31                const unsigned char *IV,     unsigned long IVlen,
32                const unsigned char *adata,  unsigned long adatalen,
33                      unsigned char *pt,     unsigned long ptlen,
34                      unsigned char *ct,
35                      unsigned char *tag,    unsigned long *taglen,
36                                int direction)
37 {
38     void      *orig;
39     gcm_state *gcm;
40     int        err;
41 
42     if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
43        return err;
44     }
45 
46     if (cipher_descriptor[cipher]->accel_gcm_memory != NULL) {
47        return cipher_descriptor[cipher]->accel_gcm_memory
48                                           (key,   keylen,
49                                            IV,    IVlen,
50                                            adata, adatalen,
51                                            pt,    ptlen,
52                                            ct,
53                                            tag,   taglen,
54                                            direction);
55     }
56 
57 
58 
59 #ifndef LTC_GCM_TABLES_SSE2
60     orig = gcm = XMALLOC(sizeof(*gcm));
61 #else
62     orig = gcm = XMALLOC(sizeof(*gcm) + 16);
63 #endif
64     if (gcm == NULL) {
65         return CRYPT_MEM;
66     }
67 
68    /* Force GCM to be on a multiple of 16 so we can use 128-bit aligned operations
69     * note that we only modify gcm and keep orig intact.  This code is not portable
70     * but again it's only for SSE2 anyways, so who cares?
71     */
72 #ifdef LTC_GCM_TABLES_SSE2
73    if ((unsigned long)gcm & 15) {
74       gcm = (gcm_state *)((unsigned long)gcm + (16 - ((unsigned long)gcm & 15)));
75    }
76 #endif
77 
78     if ((err = gcm_init(gcm, cipher, key, keylen)) != CRYPT_OK) {
79        goto LTC_ERR;
80     }
81     if ((err = gcm_add_iv(gcm, IV, IVlen)) != CRYPT_OK) {
82        goto LTC_ERR;
83     }
84     if ((err = gcm_add_aad(gcm, adata, adatalen)) != CRYPT_OK) {
85        goto LTC_ERR;
86     }
87     if ((err = gcm_process(gcm, pt, ptlen, ct, direction)) != CRYPT_OK) {
88        goto LTC_ERR;
89     }
90     if (direction == GCM_ENCRYPT) {
91       if ((err = gcm_done(gcm, tag, taglen)) != CRYPT_OK) {
92          goto LTC_ERR;
93       }
94     }
95     else if (direction == GCM_DECRYPT) {
96        unsigned char buf[MAXBLOCKSIZE];
97        unsigned long buflen = sizeof(buf);
98        if ((err = gcm_done(gcm, buf, &buflen)) != CRYPT_OK) {
99           goto LTC_ERR;
100        }
101        if (buflen != *taglen || XMEM_NEQ(buf, tag, buflen) != 0) {
102           err = CRYPT_ERROR;
103        }
104     }
105     else {
106        err = CRYPT_INVALID_ARG;
107     }
108 LTC_ERR:
109     XFREE(orig);
110     return err;
111 }
112 #endif
113 
114