2012-01-14 15:22:10 +00:00
|
|
|
/* eax.c
|
|
|
|
* Encryption and decryption routines implementing the EAX' encryption mode
|
|
|
|
* Copyright 2010, Edward J. Beroset, edward.j.beroset@us.elster.com
|
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-06-28 22:56:06 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2012-01-14 15:22:10 +00:00
|
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#ifdef HAVE_LIBGCRYPT
|
|
|
|
#include <string.h>
|
|
|
|
/* Use libgcrypt for cipher libraries. */
|
2013-02-21 18:23:29 +00:00
|
|
|
#include <wsutil/wsgcrypt.h>
|
2012-01-14 15:22:10 +00:00
|
|
|
#include "eax.h"
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
guint8 L[EAX_SIZEOF_KEY];
|
|
|
|
guint8 D[EAX_SIZEOF_KEY];
|
|
|
|
guint8 Q[EAX_SIZEOF_KEY];
|
|
|
|
} eax_s;
|
|
|
|
|
|
|
|
static eax_s instance;
|
|
|
|
|
|
|
|
/* these are defined as macros so they'll be easy to redo in assembly if desired */
|
2013-08-01 23:34:47 +00:00
|
|
|
#define BLK_CPY(dst, src) { memcpy(dst, src, EAX_SIZEOF_KEY); }
|
2012-01-14 15:22:10 +00:00
|
|
|
#define BLK_XOR(dst, src) { int z; for (z=0; z < EAX_SIZEOF_KEY; z++) dst[z] ^= src[z]; }
|
|
|
|
static void Dbl(guint8 *out, const guint8 *in);
|
|
|
|
static void CTR(const guint8 *ws, guint8 *pK, guint8 *pN, guint16 SizeN);
|
|
|
|
static void CMAC(guint8 *pK, guint8 *ws, const guint8 *pN, guint16 SizeN);
|
|
|
|
static void dCMAC(guint8 *pK, guint8 *ws, const guint8 *pN, guint16 SizeN, const guint8 *pC, guint16 SizeC);
|
|
|
|
void AesEncrypt(unsigned char msg[EAX_SIZEOF_KEY], unsigned char key[EAX_SIZEOF_KEY]);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Decrypts cleartext data using EAX' mode (see ANSI Standard C12.22-2008).
|
|
|
|
|
2014-10-14 15:12:16 +00:00
|
|
|
@param[in] pN pointer to cleartext (canonified form)
|
|
|
|
@param[in] pK pointer to secret key
|
|
|
|
@param[in,out] pC pointer to ciphertext
|
|
|
|
@param[in] SizeN byte length of cleartext (pN) buffer
|
|
|
|
@param[in] SizeK byte length of secret key (pK)
|
|
|
|
@param[in] SizeC byte length of ciphertext (pC) buffer
|
|
|
|
@param[in] pMac four-byte Message Authentication Code
|
|
|
|
@param[in] Mode EAX_MODE_CLEARTEXT_AUTH or EAX_MODE_CIPHERTEXT_AUTH
|
|
|
|
@return TRUE if message has been authenticated; FALSE if not
|
|
|
|
authenticated, invalid Mode or error
|
2012-01-14 15:22:10 +00:00
|
|
|
*/
|
2013-08-01 23:34:47 +00:00
|
|
|
gboolean Eax_Decrypt(guint8 *pN, guint8 *pK, guint8 *pC,
|
2014-10-14 15:12:16 +00:00
|
|
|
guint32 SizeN, guint32 SizeK, guint32 SizeC, MAC_T *pMac,
|
|
|
|
guint8 Mode)
|
2012-01-14 15:22:10 +00:00
|
|
|
{
|
|
|
|
guint8 wsn[EAX_SIZEOF_KEY];
|
|
|
|
guint8 wsc[EAX_SIZEOF_KEY];
|
|
|
|
int i;
|
2013-08-01 23:34:47 +00:00
|
|
|
|
2012-01-14 15:22:10 +00:00
|
|
|
/* key size must match this implementation */
|
|
|
|
if (SizeK != EAX_SIZEOF_KEY)
|
2014-10-14 15:12:16 +00:00
|
|
|
return FALSE;
|
2012-01-14 15:22:10 +00:00
|
|
|
|
|
|
|
/* the key is new */
|
|
|
|
for (i = 0; i < EAX_SIZEOF_KEY; i++)
|
2014-10-14 15:12:16 +00:00
|
|
|
instance.L[i] = 0;
|
2012-01-14 15:22:10 +00:00
|
|
|
AesEncrypt(instance.L, pK);
|
|
|
|
Dbl(instance.D, instance.L);
|
|
|
|
Dbl(instance.Q, instance.D);
|
|
|
|
/* the key is set up */
|
|
|
|
/* first copy the nonce into our working space */
|
|
|
|
BLK_CPY(wsn, instance.D);
|
|
|
|
if (Mode == EAX_MODE_CLEARTEXT_AUTH) {
|
2014-10-14 15:12:16 +00:00
|
|
|
dCMAC(pK, wsn, pN, SizeN, pC, SizeC);
|
2012-01-14 15:22:10 +00:00
|
|
|
} else {
|
2014-10-14 15:12:16 +00:00
|
|
|
CMAC(pK, wsn, pN, SizeN);
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
2013-08-01 23:34:47 +00:00
|
|
|
/*
|
|
|
|
* In authentication mode the inputs are: pN, pK (and associated sizes),
|
2014-10-14 15:12:16 +00:00
|
|
|
* the result is the 4 byte MAC.
|
2012-01-14 15:22:10 +00:00
|
|
|
*/
|
|
|
|
if (Mode == EAX_MODE_CLEARTEXT_AUTH)
|
|
|
|
{
|
|
|
|
return (memcmp(pMac, &wsn[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) ? FALSE : TRUE);
|
2013-08-01 23:34:47 +00:00
|
|
|
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
|
2013-08-01 23:34:47 +00:00
|
|
|
/*
|
|
|
|
* In cipher mode the inputs are: pN, pK, pP (and associated sizes),
|
2012-01-14 15:22:10 +00:00
|
|
|
* the results are pC (and its size) along with the 4 byte MAC.
|
|
|
|
*/
|
|
|
|
else if (Mode == EAX_MODE_CIPHERTEXT_AUTH)
|
|
|
|
{
|
2014-10-14 15:12:16 +00:00
|
|
|
if (SizeC == 0)
|
2012-01-14 15:22:10 +00:00
|
|
|
return (memcmp(pMac, &wsn[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) ? FALSE : TRUE);
|
2014-10-14 15:12:16 +00:00
|
|
|
{
|
|
|
|
/* first copy the nonce into our working space */
|
|
|
|
BLK_CPY(wsc, instance.Q);
|
|
|
|
CMAC(pK, wsc, pC, SizeC);
|
|
|
|
BLK_XOR(wsc, wsn);
|
|
|
|
}
|
|
|
|
if (memcmp(pMac, &wsc[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) == 0)
|
|
|
|
{
|
|
|
|
CTR(wsn, pK, pC, SizeC);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set up D or Q from L */
|
|
|
|
static void Dbl(guint8 *out, const guint8 *in)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
guint8 carry = 0;
|
|
|
|
|
|
|
|
/* this might be a lot more efficient in assembly language */
|
|
|
|
for (i=0; i < EAX_SIZEOF_KEY; i++)
|
|
|
|
{
|
2014-10-14 15:12:16 +00:00
|
|
|
out[i] = ( in[i] << 1 ) | carry;
|
|
|
|
carry = (in[i] & 0x80) ? 1 : 0;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
if (carry)
|
2014-10-14 15:12:16 +00:00
|
|
|
out[0] ^= 0x87;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void CMAC(guint8 *pK, guint8 *ws, const guint8 *pN, guint16 SizeN)
|
|
|
|
{
|
|
|
|
dCMAC(pK, ws, pN, SizeN, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dCMAC(guint8 *pK, guint8 *ws, const guint8 *pN, guint16 SizeN, const guint8 *pC, guint16 SizeC)
|
|
|
|
{
|
|
|
|
gcry_cipher_hd_t cipher_hd;
|
|
|
|
guint8 *work;
|
|
|
|
guint8 *ptr;
|
|
|
|
guint16 SizeT = SizeN + SizeC;
|
|
|
|
guint16 worksize = SizeT;
|
|
|
|
|
|
|
|
/* worksize must be an integral multiple of 16 */
|
|
|
|
if (SizeT & 0xf) {
|
2014-10-14 15:12:16 +00:00
|
|
|
worksize += 0x10 - (worksize & 0xf);
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
2013-03-02 12:10:56 +00:00
|
|
|
work = (guint8 *)g_malloc(worksize);
|
2012-01-14 15:22:10 +00:00
|
|
|
if (work == NULL) {
|
2014-10-14 15:12:16 +00:00
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
memcpy(work, pN, SizeN);
|
2012-04-28 02:25:15 +00:00
|
|
|
if (pC != NULL) {
|
|
|
|
memcpy(&work[SizeN], pC, SizeC);
|
|
|
|
}
|
2013-08-01 23:34:47 +00:00
|
|
|
/*
|
2012-01-14 15:22:10 +00:00
|
|
|
* pad the data if necessary, and XOR Q or D, depending on
|
2013-08-01 23:34:47 +00:00
|
|
|
* whether data was padded or not
|
2012-01-14 15:22:10 +00:00
|
|
|
*/
|
|
|
|
if (worksize != SizeT) {
|
2014-10-14 15:12:16 +00:00
|
|
|
work[SizeT] = 0x80;
|
|
|
|
for (ptr = &work[SizeT+1]; ptr < &work[worksize]; ptr++)
|
|
|
|
*ptr = 0;
|
|
|
|
ptr= &work[worksize-0x10];
|
|
|
|
BLK_XOR(ptr, instance.Q);
|
2012-01-14 15:22:10 +00:00
|
|
|
} else {
|
2014-10-14 15:12:16 +00:00
|
|
|
ptr = &work[worksize-0x10];
|
|
|
|
BLK_XOR(ptr, instance.D);
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
/* open the cipher */
|
|
|
|
if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC,0)){/* GCRY_CIPHER_CBC_MAC)) { */
|
2014-10-14 15:12:16 +00:00
|
|
|
g_free(work);
|
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
if (gcry_cipher_setkey(cipher_hd, pK, EAX_SIZEOF_KEY)) {
|
2014-10-14 15:12:16 +00:00
|
|
|
g_free(work);
|
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
if (gcry_cipher_setiv(cipher_hd, ws, EAX_SIZEOF_KEY)) {
|
2014-10-14 15:12:16 +00:00
|
|
|
g_free(work);
|
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
if (gcry_cipher_encrypt(cipher_hd, work, worksize, work, worksize)) {
|
2014-10-14 15:12:16 +00:00
|
|
|
g_free(work);
|
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
memcpy(ws, ptr, EAX_SIZEOF_KEY);
|
|
|
|
|
|
|
|
g_free(work);
|
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-01 23:34:47 +00:00
|
|
|
static void CTR(const guint8 *ws, guint8 *pK, guint8 *pN, guint16 SizeN)
|
2012-01-14 15:22:10 +00:00
|
|
|
{
|
|
|
|
gcry_cipher_hd_t cipher_hd;
|
|
|
|
guint8 ctr[EAX_SIZEOF_KEY];
|
|
|
|
|
|
|
|
BLK_CPY(ctr, ws);
|
|
|
|
ctr[12] &= 0x7f;
|
|
|
|
ctr[14] &= 0x7f;
|
|
|
|
/* open the cipher */
|
|
|
|
if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0)) {
|
2014-10-14 15:12:16 +00:00
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
if (gcry_cipher_setkey(cipher_hd, pK, EAX_SIZEOF_KEY)) {
|
2014-10-14 15:12:16 +00:00
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
if (gcry_cipher_setctr(cipher_hd, ctr, EAX_SIZEOF_KEY)) {
|
2014-10-14 15:12:16 +00:00
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
if (gcry_cipher_encrypt(cipher_hd, pN, SizeN, pN, SizeN)) {
|
2014-10-14 15:12:16 +00:00
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-01 23:34:47 +00:00
|
|
|
void AesEncrypt(unsigned char msg[EAX_SIZEOF_KEY], unsigned char key[EAX_SIZEOF_KEY])
|
2012-01-14 15:22:10 +00:00
|
|
|
{
|
|
|
|
gcry_cipher_hd_t cipher_hd;
|
|
|
|
|
|
|
|
/* open the cipher */
|
|
|
|
if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0)) {
|
2014-10-14 15:12:16 +00:00
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
if (gcry_cipher_setkey(cipher_hd, key, EAX_SIZEOF_KEY)) {
|
2014-10-14 15:12:16 +00:00
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
if (gcry_cipher_encrypt(cipher_hd, msg, EAX_SIZEOF_KEY, msg, EAX_SIZEOF_KEY)) {
|
2014-10-14 15:12:16 +00:00
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
2012-01-14 15:22:10 +00:00
|
|
|
}
|
|
|
|
gcry_cipher_close(cipher_hd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_LIBGCRYPT */
|
2014-10-14 15:12:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Editor modelines - http://www.wireshark.org/tools/modelines.html
|
|
|
|
*
|
|
|
|
* Local variables:
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* tab-width: 8
|
|
|
|
* indent-tabs-mode: nil
|
|
|
|
* End:
|
|
|
|
*
|
|
|
|
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
|
|
|
* :indentSize=4:tabSize=8:noTabs=true:
|
|
|
|
*/
|