1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6   @file hmac_done.c
7   HMAC support, terminate stream, Tom St Denis/Dobes Vandermeer
8 */
9 
10 #ifdef LTC_HMAC
11 
12 #define LTC_HMAC_BLOCKSIZE hash_descriptor[hash]->blocksize
13 
14 /**
15    Terminate an HMAC session
16    @param hmac    The HMAC state
17    @param out     [out] The destination of the HMAC authentication tag
18    @param outlen  [in/out]  The max size and resulting size of the HMAC authentication tag
19    @return CRYPT_OK if successful
20 */
hmac_done(hmac_state * hmac,unsigned char * out,unsigned long * outlen)21 int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
22 {
23     unsigned char *buf, *isha;
24     unsigned long hashsize, i;
25     int hash, err;
26 
27     LTC_ARGCHK(hmac  != NULL);
28     LTC_ARGCHK(out   != NULL);
29 
30     /* test hash */
31     hash = hmac->hash;
32     if((err = hash_is_valid(hash)) != CRYPT_OK) {
33         return err;
34     }
35 
36     /* get the hash message digest size */
37     hashsize = hash_descriptor[hash]->hashsize;
38 
39     /* allocate buffers */
40     buf  = XMALLOC(LTC_HMAC_BLOCKSIZE);
41     isha = XMALLOC(hashsize);
42     if (buf == NULL || isha == NULL) {
43        if (buf != NULL) {
44           XFREE(buf);
45        }
46        if (isha != NULL) {
47           XFREE(isha);
48        }
49        return CRYPT_MEM;
50     }
51 
52     /* Get the hash of the first HMAC vector plus the data */
53     if ((err = hash_descriptor[hash]->done(&hmac->md, isha)) != CRYPT_OK) {
54        goto LBL_ERR;
55     }
56 
57     /* Create the second HMAC vector vector for step (3) */
58     for(i=0; i < LTC_HMAC_BLOCKSIZE; i++) {
59         buf[i] = hmac->key[i] ^ 0x5C;
60     }
61 
62     /* Now calculate the "outer" hash for step (5), (6), and (7) */
63     if ((err = hash_descriptor[hash]->init(&hmac->md)) != CRYPT_OK) {
64        goto LBL_ERR;
65     }
66     if ((err = hash_descriptor[hash]->process(&hmac->md, buf, LTC_HMAC_BLOCKSIZE)) != CRYPT_OK) {
67        goto LBL_ERR;
68     }
69     if ((err = hash_descriptor[hash]->process(&hmac->md, isha, hashsize)) != CRYPT_OK) {
70        goto LBL_ERR;
71     }
72     if ((err = hash_descriptor[hash]->done(&hmac->md, buf)) != CRYPT_OK) {
73        goto LBL_ERR;
74     }
75 
76     /* copy to output  */
77     for (i = 0; i < hashsize && i < *outlen; i++) {
78         out[i] = buf[i];
79     }
80     *outlen = i;
81 
82     err = CRYPT_OK;
83 LBL_ERR:
84 #ifdef LTC_CLEAN_STACK
85     zeromem(isha, hashsize);
86     zeromem(buf,  hashsize);
87     zeromem(hmac, sizeof(*hmac));
88 #endif
89 
90     XFREE(isha);
91     XFREE(buf);
92 
93     return err;
94 }
95 
96 #endif
97