Convert to using use SPDX identifier on wsutil directory
[metze/wireshark/wip.git] / wsutil / eax.c
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+
10  */
11 #include "config.h"
12 #include <stdlib.h>
13 #include <string.h>
14 /* Use libgcrypt for cipher libraries. */
15 #include <wsutil/wsgcrypt.h>
16 #include "eax.h"
17
18 typedef struct {
19     guint8 L[EAX_SIZEOF_KEY];
20     guint8 D[EAX_SIZEOF_KEY];
21     guint8 Q[EAX_SIZEOF_KEY];
22 } eax_s;
23
24 static eax_s instance;
25
26 /* these are defined as macros so they'll be easy to redo in assembly if desired */
27 #define BLK_CPY(dst, src) { memcpy(dst, src, EAX_SIZEOF_KEY); }
28 #define BLK_XOR(dst, src) { int z; for (z=0; z < EAX_SIZEOF_KEY; z++) dst[z] ^= src[z]; }
29 static void Dbl(guint8 *out, const guint8 *in);
30 static void CTR(const guint8 *ws, guint8 *pK, guint8 *pN, guint16 SizeN);
31 static void CMAC(guint8 *pK, guint8 *ws, const guint8 *pN, guint16 SizeN);
32 static void dCMAC(guint8 *pK, guint8 *ws, const guint8 *pN, guint16 SizeN, const guint8 *pC, guint16 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 (canonified 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 gboolean Eax_Decrypt(guint8 *pN, guint8 *pK, guint8 *pC,
50                      guint32 SizeN, guint32 SizeK, guint32 SizeC, MAC_T *pMac,
51                      guint8 Mode)
52 {
53     guint8 wsn[EAX_SIZEOF_KEY];
54     guint8 wsc[EAX_SIZEOF_KEY];
55     int i;
56
57     /* key size must match this implementation */
58     if (SizeK != EAX_SIZEOF_KEY)
59         return FALSE;
60
61     /* the key is new */
62     for (i = 0; i < EAX_SIZEOF_KEY; i++)
63         instance.L[i] = 0;
64     AesEncrypt(instance.L, pK);
65     Dbl(instance.D, instance.L);
66     Dbl(instance.Q, instance.D);
67     /* the key is set up */
68     /* first copy the nonce into our working space */
69     BLK_CPY(wsn, instance.D);
70     if (Mode == EAX_MODE_CLEARTEXT_AUTH) {
71         dCMAC(pK, wsn, pN, SizeN, pC, SizeC);
72     } else {
73         CMAC(pK, wsn, pN, SizeN);
74     }
75     /*
76      *  In authentication mode the inputs are: pN, pK (and associated sizes),
77      *  the result is the 4 byte MAC.
78      */
79     if (Mode == EAX_MODE_CLEARTEXT_AUTH)
80     {
81         return (memcmp(pMac, &wsn[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) ? FALSE : TRUE);
82
83     }
84
85     /*
86      * In cipher mode the inputs are: pN, pK, pP (and associated sizes),
87      * the results are pC (and its size) along with the 4 byte MAC.
88      */
89     else if (Mode == EAX_MODE_CIPHERTEXT_AUTH)
90     {
91         if (SizeC == 0)
92             return (memcmp(pMac, &wsn[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) ? FALSE : TRUE);
93         {
94             /* first copy the nonce into our working space */
95             BLK_CPY(wsc, instance.Q);
96             CMAC(pK, wsc, pC, SizeC);
97             BLK_XOR(wsc, wsn);
98         }
99         if (memcmp(pMac, &wsc[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) == 0)
100         {
101             CTR(wsn, pK, pC, SizeC);
102             return TRUE;
103         }
104     }
105     return FALSE;
106 }
107
108 /* set up D or Q from L */
109 static void Dbl(guint8 *out, const guint8 *in)
110 {
111     int i;
112     guint8 carry = 0;
113
114     /* this might be a lot more efficient in assembly language */
115     for (i=0; i < EAX_SIZEOF_KEY; i++)
116     {
117         out[i] = ( in[i] << 1 ) | carry;
118         carry = (in[i] & 0x80) ? 1 : 0;
119     }
120     if (carry)
121         out[0] ^= 0x87;
122 }
123
124 static void CMAC(guint8 *pK, guint8 *ws, const guint8 *pN, guint16 SizeN)
125 {
126     dCMAC(pK, ws, pN, SizeN, NULL, 0);
127 }
128
129 static void dCMAC(guint8 *pK, guint8 *ws, const guint8 *pN, guint16 SizeN, const guint8 *pC, guint16 SizeC)
130 {
131     gcry_cipher_hd_t cipher_hd;
132     guint8 *work;
133     guint8  *ptr;
134     guint16 SizeT = SizeN + SizeC;
135     guint16 worksize = SizeT;
136
137     /* worksize must be an integral multiple of 16 */
138     if (SizeT & 0xf)  {
139         worksize += 0x10 - (worksize & 0xf);
140     }
141     work = (guint8 *)g_malloc(worksize);
142     if (work == NULL) {
143         return;
144     }
145     memcpy(work, pN, SizeN);
146     if (pC != NULL) {
147         memcpy(&work[SizeN], pC, SizeC);
148     }
149     /*
150      * pad the data if necessary, and XOR Q or D, depending on
151      * whether data was padded or not
152      */
153     if (worksize != SizeT) {
154         work[SizeT] = 0x80;
155         for (ptr = &work[SizeT+1]; ptr < &work[worksize]; ptr++)
156             *ptr = 0;
157         ptr= &work[worksize-0x10];
158         BLK_XOR(ptr, instance.Q);
159     } else {
160         ptr = &work[worksize-0x10];
161         BLK_XOR(ptr, instance.D);
162     }
163     /* open the cipher */
164     if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC,0)){/* GCRY_CIPHER_CBC_MAC)) { */
165         g_free(work);
166         return;
167     }
168     if (gcry_cipher_setkey(cipher_hd, pK, EAX_SIZEOF_KEY)) {
169         g_free(work);
170         gcry_cipher_close(cipher_hd);
171         return;
172     }
173     if (gcry_cipher_setiv(cipher_hd, ws, EAX_SIZEOF_KEY)) {
174         g_free(work);
175         gcry_cipher_close(cipher_hd);
176         return;
177     }
178     if (gcry_cipher_encrypt(cipher_hd, work, worksize, work, worksize)) {
179         g_free(work);
180         gcry_cipher_close(cipher_hd);
181         return;
182     }
183     memcpy(ws, ptr, EAX_SIZEOF_KEY);
184
185     g_free(work);
186     gcry_cipher_close(cipher_hd);
187     return;
188 }
189
190 static void CTR(const guint8 *ws, guint8 *pK, guint8 *pN, guint16 SizeN)
191 {
192     gcry_cipher_hd_t cipher_hd;
193     guint8 ctr[EAX_SIZEOF_KEY];
194
195     BLK_CPY(ctr, ws);
196     ctr[12] &= 0x7f;
197     ctr[14] &= 0x7f;
198     /* open the cipher */
199     if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0)) {
200         return;
201     }
202     if (gcry_cipher_setkey(cipher_hd, pK, EAX_SIZEOF_KEY)) {
203         gcry_cipher_close(cipher_hd);
204         return;
205     }
206     if (gcry_cipher_setctr(cipher_hd, ctr, EAX_SIZEOF_KEY)) {
207         gcry_cipher_close(cipher_hd);
208         return;
209     }
210     if (gcry_cipher_encrypt(cipher_hd, pN, SizeN, pN, SizeN)) {
211         gcry_cipher_close(cipher_hd);
212         return;
213     }
214     gcry_cipher_close(cipher_hd);
215     return;
216 }
217
218 void AesEncrypt(unsigned char msg[EAX_SIZEOF_KEY], unsigned char key[EAX_SIZEOF_KEY])
219 {
220     gcry_cipher_hd_t cipher_hd;
221
222     /* open the cipher */
223     if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0)) {
224         return;
225     }
226     if (gcry_cipher_setkey(cipher_hd, key, EAX_SIZEOF_KEY)) {
227         gcry_cipher_close(cipher_hd);
228         return;
229     }
230     if (gcry_cipher_encrypt(cipher_hd, msg, EAX_SIZEOF_KEY, msg, EAX_SIZEOF_KEY)) {
231         gcry_cipher_close(cipher_hd);
232         return;
233     }
234     gcry_cipher_close(cipher_hd);
235     return;
236 }
237
238 /*
239  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
240  *
241  * Local variables:
242  * c-basic-offset: 4
243  * tab-width: 8
244  * indent-tabs-mode: nil
245  * End:
246  *
247  * vi: set shiftwidth=4 tabstop=8 expandtab:
248  * :indentSize=4:tabSize=8:noTabs=true:
249  */