Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wsutil/eax.c
Line
Count
Source
1
/* eax.c
2
 * Encryption and decryption routines implementing the EAX' encryption mode
3
 * Copyright 2010, Edward J. Beroset, edward.j.beroset@us.elster.com
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
#include "config.h"
12
#include "eax.h"
13
#include <stdlib.h>
14
#include <string.h>
15
/* Use libgcrypt for cipher libraries. */
16
#include <gcrypt.h>
17
18
#include <wsutil/ws_roundup.h>
19
20
typedef struct {
21
    uint8_t L[EAX_SIZEOF_KEY];
22
    uint8_t D[EAX_SIZEOF_KEY];
23
    uint8_t Q[EAX_SIZEOF_KEY];
24
} eax_s;
25
26
/* these are defined as macros so they'll be easy to redo in assembly if desired */
27
0
#define BLK_CPY(dst, src) { memcpy(dst, src, EAX_SIZEOF_KEY); }
28
0
#define BLK_XOR(dst, src) { int z; for (z=0; z < EAX_SIZEOF_KEY; z++) dst[z] ^= src[z]; }
29
static void Dbl(uint8_t *out, const uint8_t *in);
30
static void CTR(const uint8_t *ws, uint8_t *pK, uint8_t *pN, uint32_t SizeN);
31
static bool CMAC(const eax_s *instance, uint8_t *pK, uint8_t *ws, const uint8_t *pN, uint32_t SizeN);
32
static bool dCMAC(const eax_s *instance, uint8_t *pK, uint8_t *ws, const uint8_t *pN, uint32_t SizeN, const uint8_t *pC, uint32_t SizeC);
33
void AesEncrypt(unsigned char msg[EAX_SIZEOF_KEY], unsigned char key[EAX_SIZEOF_KEY]);
34
35
/*!
36
 Decrypts cleartext data using EAX' mode (see ANSI Standard C12.22-2008).
37
38
 @param[in]     pN      pointer to cleartext (canonicalized form)
39
 @param[in]     pK      pointer to secret key
40
 @param[in,out] pC      pointer to ciphertext
41
 @param[in]     SizeN   byte length of cleartext (pN) buffer
42
 @param[in]     SizeK   byte length of secret key (pK)
43
 @param[in]     SizeC   byte length of ciphertext (pC) buffer
44
 @param[in]     pMac    four-byte Message Authentication Code
45
 @param[in]     Mode    EAX_MODE_CLEARTEXT_AUTH or EAX_MODE_CIPHERTEXT_AUTH
46
 @return                true if message has been authenticated; false if not
47
                        authenticated, invalid Mode or error
48
 */
49
bool Eax_Decrypt(uint8_t *pN, uint8_t *pK, uint8_t *pC,
50
                     uint32_t SizeN, uint32_t SizeK, uint32_t SizeC, MAC_T *pMac,
51
                     uint8_t Mode)
52
0
{
53
0
    eax_s instance;
54
0
    uint8_t wsn[EAX_SIZEOF_KEY];
55
0
    uint8_t wsc[EAX_SIZEOF_KEY];
56
0
    int i;
57
58
    /* key size must match this implementation */
59
0
    if (SizeK != EAX_SIZEOF_KEY)
60
0
        return false;
61
62
    /* the key is new */
63
0
    for (i = 0; i < EAX_SIZEOF_KEY; i++)
64
0
        instance.L[i] = 0;
65
0
    AesEncrypt(instance.L, pK);
66
0
    Dbl(instance.D, instance.L);
67
0
    Dbl(instance.Q, instance.D);
68
    /* the key is set up */
69
    /* first copy the nonce into our working space */
70
0
    BLK_CPY(wsn, instance.D);
71
0
    if (Mode == EAX_MODE_CLEARTEXT_AUTH) {
72
0
        if (!dCMAC(&instance, pK, wsn, pN, SizeN, pC, SizeC)) {
73
0
            return false;
74
0
        }
75
0
    } else {
76
0
        if (!CMAC(&instance, pK, wsn, pN, SizeN)) {
77
0
            return false;
78
0
        }
79
0
    }
80
    /*
81
     *  In authentication mode the inputs are: pN, pK (and associated sizes),
82
     *  the result is the 4 byte MAC.
83
     */
84
0
    if (Mode == EAX_MODE_CLEARTEXT_AUTH)
85
0
    {
86
0
        return (memcmp(pMac, &wsn[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) ? false : true);
87
88
0
    }
89
90
    /*
91
     * In cipher mode the inputs are: pN, pK, pP (and associated sizes),
92
     * the results are pC (and its size) along with the 4 byte MAC.
93
     */
94
0
    else if (Mode == EAX_MODE_CIPHERTEXT_AUTH)
95
0
    {
96
0
        if (SizeC == 0)
97
0
            return (memcmp(pMac, &wsn[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) ? false : true);
98
0
        {
99
            /* first copy the nonce into our working space */
100
0
            BLK_CPY(wsc, instance.Q);
101
0
            CMAC(&instance, pK, wsc, pC, SizeC);
102
0
            BLK_XOR(wsc, wsn);
103
0
        }
104
0
        if (memcmp(pMac, &wsc[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) == 0)
105
0
        {
106
0
            CTR(wsn, pK, pC, SizeC);
107
0
            return true;
108
0
        }
109
0
    }
110
0
    return false;
111
0
}
112
113
/* set up D or Q from L */
114
static void Dbl(uint8_t *out, const uint8_t *in)
115
0
{
116
0
    int i;
117
0
    uint8_t carry = 0;
118
119
    /* this might be a lot more efficient in assembly language */
120
0
    for (i=0; i < EAX_SIZEOF_KEY; i++)
121
0
    {
122
0
        out[i] = ( in[i] << 1 ) | carry;
123
0
        carry = (in[i] & 0x80) ? 1 : 0;
124
0
    }
125
0
    if (carry)
126
0
        out[0] ^= 0x87;
127
0
}
128
129
static bool CMAC(const eax_s *instance, uint8_t *pK, uint8_t *ws, const uint8_t *pN, uint32_t SizeN)
130
0
{
131
0
    return dCMAC(instance, pK, ws, pN, SizeN, NULL, 0);
132
0
}
133
134
static bool dCMAC(const eax_s *instance, uint8_t *pK, uint8_t *ws, const uint8_t *pN, uint32_t SizeN, const uint8_t *pC, uint32_t SizeC)
135
0
{
136
0
    gcry_cipher_hd_t cipher_hd;
137
0
    uint8_t *work;
138
0
    uint8_t *ptr;
139
0
    uint32_t SizeT;
140
0
    size_t worksize;
141
142
0
    if (ckd_add(&SizeT, SizeN, SizeC)) {
143
0
        return false;
144
0
    }
145
146
    /* worksize must be an integral multiple of 16 */
147
0
    worksize = WS_ROUNDUP_16(SizeT);
148
    /* WS_ROUNDUP_16 can "round up" to 0, but then g_malloc will
149
     * safely return NULL and we'll return false. */
150
0
    work = (uint8_t *)g_malloc(worksize);
151
0
    if (work == NULL) {
152
0
        return false;
153
0
    }
154
0
    memcpy(work, pN, SizeN);
155
0
    if (pC != NULL) {
156
0
        memcpy(&work[SizeN], pC, SizeC);
157
0
    }
158
    /*
159
     * pad the data if necessary, and XOR Q or D, depending on
160
     * whether data was padded or not
161
     */
162
0
    if (worksize != SizeT) {
163
0
        work[SizeT] = 0x80;
164
0
        for (ptr = &work[SizeT+1]; ptr <= &work[worksize-1]; ptr++)
165
0
            *ptr = 0;
166
0
        ptr= &work[worksize-0x10];
167
0
        BLK_XOR(ptr, instance->Q);
168
0
    } else {
169
0
        ptr = &work[worksize-0x10];
170
0
        BLK_XOR(ptr, instance->D);
171
0
    }
172
    /* open the cipher */
173
0
    if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC,0)){/* GCRY_CIPHER_CBC_MAC)) { */
174
0
        g_free(work);
175
0
        return false;
176
0
    }
177
0
    if (gcry_cipher_setkey(cipher_hd, pK, EAX_SIZEOF_KEY)) {
178
0
        g_free(work);
179
0
        gcry_cipher_close(cipher_hd);
180
0
        return false;
181
0
    }
182
0
    if (gcry_cipher_setiv(cipher_hd, ws, EAX_SIZEOF_KEY)) {
183
0
        g_free(work);
184
0
        gcry_cipher_close(cipher_hd);
185
0
        return false;
186
0
    }
187
0
    if (gcry_cipher_encrypt(cipher_hd, work, worksize, work, worksize)) {
188
0
        g_free(work);
189
0
        gcry_cipher_close(cipher_hd);
190
0
        return false;
191
0
    }
192
0
    memcpy(ws, ptr, EAX_SIZEOF_KEY);
193
194
0
    g_free(work);
195
0
    gcry_cipher_close(cipher_hd);
196
0
    return true;
197
0
}
198
199
static void CTR(const uint8_t *ws, uint8_t *pK, uint8_t *pN, uint32_t SizeN)
200
0
{
201
0
    gcry_cipher_hd_t cipher_hd;
202
0
    uint8_t ctr[EAX_SIZEOF_KEY];
203
204
0
    BLK_CPY(ctr, ws);
205
0
    ctr[12] &= 0x7f;
206
0
    ctr[14] &= 0x7f;
207
    /* open the cipher */
208
0
    if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0)) {
209
0
        return;
210
0
    }
211
0
    if (gcry_cipher_setkey(cipher_hd, pK, EAX_SIZEOF_KEY)) {
212
0
        gcry_cipher_close(cipher_hd);
213
0
        return;
214
0
    }
215
0
    if (gcry_cipher_setctr(cipher_hd, ctr, EAX_SIZEOF_KEY)) {
216
0
        gcry_cipher_close(cipher_hd);
217
0
        return;
218
0
    }
219
0
    if (gcry_cipher_encrypt(cipher_hd, pN, SizeN, pN, SizeN)) {
220
0
        gcry_cipher_close(cipher_hd);
221
0
        return;
222
0
    }
223
0
    gcry_cipher_close(cipher_hd);
224
0
    return;
225
0
}
226
227
void AesEncrypt(unsigned char msg[EAX_SIZEOF_KEY], unsigned char key[EAX_SIZEOF_KEY])
228
0
{
229
0
    gcry_cipher_hd_t cipher_hd;
230
231
    /* open the cipher */
232
0
    if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0)) {
233
0
        return;
234
0
    }
235
0
    if (gcry_cipher_setkey(cipher_hd, key, EAX_SIZEOF_KEY)) {
236
0
        gcry_cipher_close(cipher_hd);
237
0
        return;
238
0
    }
239
0
    if (gcry_cipher_encrypt(cipher_hd, msg, EAX_SIZEOF_KEY, msg, EAX_SIZEOF_KEY)) {
240
0
        gcry_cipher_close(cipher_hd);
241
0
        return;
242
0
    }
243
0
    gcry_cipher_close(cipher_hd);
244
0
    return;
245
0
}
246
247
/*
248
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
249
 *
250
 * Local variables:
251
 * c-basic-offset: 4
252
 * tab-width: 8
253
 * indent-tabs-mode: nil
254
 * End:
255
 *
256
 * vi: set shiftwidth=4 tabstop=8 expandtab:
257
 * :indentSize=4:tabSize=8:noTabs=true:
258
 */