aboutsummaryrefslogtreecommitdiffstats
path: root/epan/crypt
diff options
context:
space:
mode:
authorJörg Mayer <jmayer@loplof.de>2012-01-14 15:22:10 +0000
committerJörg Mayer <jmayer@loplof.de>2012-01-14 15:22:10 +0000
commit6197143d6c549ad6ab2197683773507bd8149500 (patch)
treea9e56c42142de8215020c054e4c443e7bfe5e298 /epan/crypt
parent8e8453df1bfd8d0477581bd4f1dab9eccc629ad3 (diff)
Ed Beroset <beroset@mindspring.com> via bug 5531
The ANSI C12.22 protocol is a smart grid protocol for utility meters, including gas, water and electric. The dissector implemented in the patch file includes full support for all EPSEM (Extended Protocol Specification for Electricity Metering) services and includes a full implementation of the C12.22 security modes. [...] To decrypt the attached sample file, you need to set up the key table in the preferences to include key 0 with a value of 6624C7E23034E4036FE5CB3A8B5DAB44. Me: Fixes for: [ 64%] Building C object epan/CMakeFiles/epan.dir/dissectors/packet-c1222.c.o ../../asn1/c1222/packet-c1222-template.c: In function ‘dissect_epsem’: ../../asn1/c1222/packet-c1222-template.c:860:15: error: variable ‘ft’ set but not used [-Werror=unused-but-set-variable] [ 5%] Building C object epan/CMakeFiles/epan.dir/dissectors/packet-c1222.c.o ../../asn1/c1222/packet-c1222-template.c:103:19: error: ‘c1222_flags’ defined but not used [-Werror=unused-variable] svn path=/trunk/; revision=40500
Diffstat (limited to 'epan/crypt')
-rw-r--r--epan/crypt/Makefile.common4
-rw-r--r--epan/crypt/eax.c252
-rw-r--r--epan/crypt/eax.h57
3 files changed, 312 insertions, 1 deletions
diff --git a/epan/crypt/Makefile.common b/epan/crypt/Makefile.common
index 02d2a753fb..b2119bdf04 100644
--- a/epan/crypt/Makefile.common
+++ b/epan/crypt/Makefile.common
@@ -34,7 +34,8 @@ LIBAIRPDCAP_SRC = \
crypt-md4.c \
crypt-md5.c \
crypt-rc4.c \
- crypt-sha1.c
+ crypt-sha1.c \
+ eax.c
LIBAIRPDCAP_INCLUDES = \
airpdcap_debug.h \
@@ -50,4 +51,5 @@ LIBAIRPDCAP_INCLUDES = \
crypt-md5.h \
crypt-rc4.h \
crypt-sha1.h \
+ eax.h \
wep-wpadefs.h
diff --git a/epan/crypt/eax.c b/epan/crypt/eax.c
new file mode 100644
index 0000000000..ad879d2fa4
--- /dev/null
+++ b/epan/crypt/eax.c
@@ -0,0 +1,252 @@
+/* eax.c
+ * Encryption and decryption routines implementing the EAX' encryption mode
+ * Copyright 2010, Edward J. Beroset, edward.j.beroset@us.elster.com
+ *
+ * $Id$
+ *
+ * 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
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdlib.h>
+#ifdef HAVE_LIBGCRYPT
+#include <string.h>
+/* Use libgcrypt for cipher libraries. */
+#include <gcrypt.h>
+#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 */
+#define BLK_CPY(dst, src) { memcpy(dst, src, EAX_SIZEOF_KEY); }
+#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).
+
+ @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
+ */
+gboolean Eax_Decrypt(guint8 *pN, guint8 *pK, guint8 *pC,
+ guint32 SizeN, guint32 SizeK, guint32 SizeC, MAC_T *pMac,
+ guint8 Mode)
+{
+ guint8 wsn[EAX_SIZEOF_KEY];
+ guint8 wsc[EAX_SIZEOF_KEY];
+ int i;
+
+ /* key size must match this implementation */
+ if (SizeK != EAX_SIZEOF_KEY)
+ return FALSE;
+
+ /* the key is new */
+ for (i = 0; i < EAX_SIZEOF_KEY; i++)
+ instance.L[i] = 0;
+ 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) {
+ dCMAC(pK, wsn, pN, SizeN, pC, SizeC);
+ } else {
+ CMAC(pK, wsn, pN, SizeN);
+ }
+ /*
+ * In authentication mode the inputs are: pN, pK (and associated sizes),
+ * the result is the 4 byte MAC.
+ */
+ if (Mode == EAX_MODE_CLEARTEXT_AUTH)
+ {
+ return (memcmp(pMac, &wsn[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) ? FALSE : TRUE);
+
+ }
+
+ /*
+ * In cipher mode the inputs are: pN, pK, pP (and associated sizes),
+ * the results are pC (and its size) along with the 4 byte MAC.
+ */
+ else if (Mode == EAX_MODE_CIPHERTEXT_AUTH)
+ {
+ if (SizeC == 0)
+ return (memcmp(pMac, &wsn[EAX_SIZEOF_KEY-sizeof(*pMac)], sizeof(*pMac)) ? FALSE : TRUE);
+ {
+ /* 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;
+ }
+ }
+ 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++)
+ {
+ out[i] = ( in[i] << 1 ) | carry;
+ carry = (in[i] & 0x80) ? 1 : 0;
+ }
+ if (carry)
+ out[0] ^= 0x87;
+}
+
+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) {
+ worksize += 0x10 - (worksize & 0xf);
+ }
+ work = g_malloc(worksize);
+ if (work == NULL) {
+ return;
+ }
+ memcpy(work, pN, SizeN);
+ memcpy(&work[SizeN], pC, SizeC);
+ /*
+ * pad the data if necessary, and XOR Q or D, depending on
+ * whether data was padded or not
+ */
+ if (worksize != SizeT) {
+ work[SizeT] = 0x80;
+ for (ptr = &work[SizeT+1]; ptr < &work[worksize]; ptr++)
+ *ptr = 0;
+ ptr= &work[worksize-0x10];
+ BLK_XOR(ptr, instance.Q);
+ } else {
+ ptr = &work[worksize-0x10];
+ BLK_XOR(ptr, instance.D);
+ }
+ /* open the cipher */
+ if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC,0)){/* GCRY_CIPHER_CBC_MAC)) { */
+ g_free(work);
+ return;
+ }
+ if (gcry_cipher_setkey(cipher_hd, pK, EAX_SIZEOF_KEY)) {
+ g_free(work);
+ gcry_cipher_close(cipher_hd);
+ return;
+ }
+ if (gcry_cipher_setiv(cipher_hd, ws, EAX_SIZEOF_KEY)) {
+ g_free(work);
+ gcry_cipher_close(cipher_hd);
+ return;
+ }
+ if (gcry_cipher_encrypt(cipher_hd, work, worksize, work, worksize)) {
+ g_free(work);
+ gcry_cipher_close(cipher_hd);
+ return;
+ }
+ memcpy(ws, ptr, EAX_SIZEOF_KEY);
+
+ g_free(work);
+ gcry_cipher_close(cipher_hd);
+ return;
+}
+
+static void CTR(const guint8 *ws, guint8 *pK, guint8 *pN, guint16 SizeN)
+{
+ 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)) {
+ return;
+ }
+ if (gcry_cipher_setkey(cipher_hd, pK, EAX_SIZEOF_KEY)) {
+ gcry_cipher_close(cipher_hd);
+ return;
+ }
+ if (gcry_cipher_setctr(cipher_hd, ctr, EAX_SIZEOF_KEY)) {
+ gcry_cipher_close(cipher_hd);
+ return;
+ }
+ if (gcry_cipher_encrypt(cipher_hd, pN, SizeN, pN, SizeN)) {
+ gcry_cipher_close(cipher_hd);
+ return;
+ }
+ gcry_cipher_close(cipher_hd);
+ return;
+}
+
+void AesEncrypt(unsigned char msg[EAX_SIZEOF_KEY], unsigned char key[EAX_SIZEOF_KEY])
+{
+ gcry_cipher_hd_t cipher_hd;
+
+ /* open the cipher */
+ if (gcry_cipher_open(&cipher_hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0)) {
+ return;
+ }
+ if (gcry_cipher_setkey(cipher_hd, key, EAX_SIZEOF_KEY)) {
+ gcry_cipher_close(cipher_hd);
+ return;
+ }
+ if (gcry_cipher_encrypt(cipher_hd, msg, EAX_SIZEOF_KEY, msg, EAX_SIZEOF_KEY)) {
+ gcry_cipher_close(cipher_hd);
+ return;
+ }
+ gcry_cipher_close(cipher_hd);
+ return;
+}
+#endif /* HAVE_LIBGCRYPT */
diff --git a/epan/crypt/eax.h b/epan/crypt/eax.h
new file mode 100644
index 0000000000..f9950e7120
--- /dev/null
+++ b/epan/crypt/eax.h
@@ -0,0 +1,57 @@
+/* eax.h
+ * Encryption and decryption routines implementing the EAX' encryption mode
+ * Copyright 2010, Edward J. Beroset, edward.j.beroset@us.elster.com
+ *
+ * $Id$
+ *
+ * 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
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+typedef struct tagMAC_T
+{
+ guint8 Mac[4];
+} MAC_T;
+
+#define EAX_MODE_CLEARTEXT_AUTH 1
+#define EAX_MODE_CIPHERTEXT_AUTH 2
+
+#define EAX_SIZEOF_KEY 16
+
+/*!
+ Decrypts cleartext data using EAX' mode (see ANSI Standard C12.22-2008).
+
+ @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
+ */
+gboolean Eax_Decrypt(guint8 *pN, guint8 *pK, guint8 *pC,
+ guint32 SizeN, guint32 SizeK, guint32 SizeC, MAC_T *pMac,
+ guint8 Mode);
+