implemented XCBC algorithms (signer, prf) for IKE on top of a crypter
authorMartin Willi <martin@strongswan.org>
Wed, 30 Apr 2008 14:26:24 +0000 (14:26 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 30 Apr 2008 14:26:24 +0000 (14:26 -0000)
supporting ike=...-aesxcbc-... in ipsec.conf
added AUTH_AES_XCBC_96 and PRF_AES128_CBC to default IKE proposal
AES XCBC testcase

14 files changed:
configure.in
src/charon/config/proposal.c
src/charon/plugins/unit_tester/tests.h
src/charon/plugins/unit_tester/tests/test_aes.c
src/libstrongswan/Makefile.am
src/libstrongswan/plugins/xcbc/Makefile.am [new file with mode: 0644]
src/libstrongswan/plugins/xcbc/xcbc.c [new file with mode: 0644]
src/libstrongswan/plugins/xcbc/xcbc.h [new file with mode: 0644]
src/libstrongswan/plugins/xcbc/xcbc_plugin.c [new file with mode: 0644]
src/libstrongswan/plugins/xcbc/xcbc_plugin.h [new file with mode: 0644]
src/libstrongswan/plugins/xcbc/xcbc_prf.c [new file with mode: 0644]
src/libstrongswan/plugins/xcbc/xcbc_prf.h [new file with mode: 0644]
src/libstrongswan/plugins/xcbc/xcbc_signer.c [new file with mode: 0644]
src/libstrongswan/plugins/xcbc/xcbc_signer.h [new file with mode: 0644]

index 9751651..fd24f6d 100644 (file)
@@ -258,6 +258,17 @@ AC_ARG_ENABLE(
 )
 
 AC_ARG_ENABLE(
+       [xcbc],
+       AS_HELP_STRING([--disable-xcbc],[disable xcbc crypto implementation plugin. (default is NO).]),
+       [if test x$enableval = xyes; then
+               xcbc=true
+        else
+               xcbc=false
+       fi],
+       xcbc=true
+)
+
+AC_ARG_ENABLE(
        [mysql],
        AS_HELP_STRING([--enable-mysql],[enable MySQL database support (default is NO). Requires libmysqlclient_r.]),
        [if test x$enableval = xyes; then
@@ -635,6 +646,7 @@ AM_CONDITIONAL(USE_GMP, test x$gmp = xtrue)
 AM_CONDITIONAL(USE_RANDOM, test x$random = xtrue)
 AM_CONDITIONAL(USE_X509, test x$x509 = xtrue)
 AM_CONDITIONAL(USE_HMAC, test x$hmac = xtrue)
+AM_CONDITIONAL(USE_XCBC, test x$xcbc = xtrue)
 AM_CONDITIONAL(USE_MYSQL, test x$mysql = xtrue)
 AM_CONDITIONAL(USE_SQLITE, test x$sqlite = xtrue)
 AM_CONDITIONAL(USE_STROKE, test x$stroke = xtrue)
@@ -693,6 +705,7 @@ AC_OUTPUT(
        src/libstrongswan/plugins/gmp/Makefile
        src/libstrongswan/plugins/random/Makefile
        src/libstrongswan/plugins/hmac/Makefile
+       src/libstrongswan/plugins/xcbc/Makefile
        src/libstrongswan/plugins/x509/Makefile
        src/libstrongswan/plugins/curl/Makefile
        src/libstrongswan/plugins/ldap/Makefile
index b7552fc..99be9db 100644 (file)
@@ -607,7 +607,7 @@ static status_t add_string_algo(private_proposal_t *this, chunk_t alg)
                add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
                if (this->protocol == PROTO_IKE)
                {
-                       add_algorithm(this, PSEUDO_RANDOM_FUNCTION, AUTH_AES_XCBC_96, 0);
+                       add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_AES128_CBC, 0);
                }
        }
        else if (strncmp(alg.ptr, "modp768", alg.len) == 0)
@@ -700,11 +700,13 @@ proposal_t *proposal_create_default(protocol_id_t protocol)
                        add_algorithm(this, ENCRYPTION_ALGORITHM,   ENCR_AES_CBC,         192);
                        add_algorithm(this, ENCRYPTION_ALGORITHM,   ENCR_AES_CBC,         256);
                        add_algorithm(this, ENCRYPTION_ALGORITHM,   ENCR_3DES,              0);
+                       add_algorithm(this, INTEGRITY_ALGORITHM,    AUTH_AES_XCBC_96,       0);
                        add_algorithm(this, INTEGRITY_ALGORITHM,    AUTH_HMAC_SHA2_256_128,     0);
                        add_algorithm(this, INTEGRITY_ALGORITHM,    AUTH_HMAC_SHA1_96,      0);
                        add_algorithm(this, INTEGRITY_ALGORITHM,    AUTH_HMAC_MD5_96,       0);
                        add_algorithm(this, INTEGRITY_ALGORITHM,    AUTH_HMAC_SHA2_384_192,     0);
                        add_algorithm(this, INTEGRITY_ALGORITHM,    AUTH_HMAC_SHA2_512_256,     0);
+                       add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_AES128_CBC,         0);
                        add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA2_256,      0);
                        add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1,          0);
                        add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5,           0);
index 9512fe6..dd3878c 100644 (file)
@@ -34,4 +34,5 @@ DEFINE_TEST("RSA key generation", test_rsa_gen, FALSE)
 DEFINE_TEST("RSA subjectPublicKeyInfo loading", test_rsa_load_any, FALSE)
 DEFINE_TEST("Mediation database key fetch", test_med_db, FALSE)
 DEFINE_TEST("AES-128 encryption", test_aes128, FALSE)
-DEFINE_TEST("Base64 converter", test_chunk_base64, TRUE)
+DEFINE_TEST("AES-XCBC", test_aes_xcbc, TRUE)
+DEFINE_TEST("Base64 converter", test_chunk_base64, FALSE)
index 22e8e25..5b69dc2 100644 (file)
@@ -13,6 +13,7 @@
  * for more details.
  */
 
+#include <daemon.h>
 #include <library.h>
 #include <utils/mutex.h>
 
@@ -166,3 +167,242 @@ bool test_aes128()
        }
        return TRUE;
 }
+
+/**
+ * run a single xcbc test for prf and signer
+ */
+static bool do_xcbc_test(u_int8_t *key, size_t keylen, u_int8_t *mac,
+                                                u_int8_t *plain, size_t len)
+{
+       signer_t *signer;
+       prf_t *prf;
+       u_int8_t res[16];
+       
+       prf = lib->crypto->create_prf(lib->crypto, PRF_AES128_CBC);
+       if (!prf)
+       {
+               return FALSE;
+       }
+       prf->set_key(prf, chunk_create(key, keylen));
+       prf->get_bytes(prf, chunk_create(plain, len), res);
+       if (!memeq(res, mac, 16))
+       {
+               DBG1(DBG_CFG, "expected %b\ngot %b", mac, 16, res, 16);
+               prf->destroy(prf);
+               return FALSE;
+       }
+       prf->destroy(prf);
+       
+       signer = lib->crypto->create_signer(lib->crypto, AUTH_AES_XCBC_96);
+       if (!signer)
+       {
+               return FALSE;
+       }
+       signer->set_key(signer, chunk_create(key, keylen));
+       if (!signer->verify_signature(signer, chunk_create(plain, len),
+                                                                 chunk_create(mac, 12)))
+       {
+               return FALSE;
+       }
+       signer->destroy(signer);
+       return TRUE;
+}
+
+
+/*******************************************************************************
+ * AES_XCBC mac test
+ ******************************************************************************/
+bool test_aes_xcbc()
+{
+       /*  Vectors from RFC 3566 */
+
+       /* Test Case #1   : AES-XCBC-MAC-96 with 0-byte input
+        * Key (K)        : 000102030405060708090a0b0c0d0e0f
+        * Message (M)    : <empty string>
+        * AES-XCBC-MAC   : 75f0251d528ac01c4573dfd584d79f29
+        * AES-XCBC-MAC-96: 75f0251d528ac01c4573dfd5
+        */
+       u_char key1[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+       };
+       u_char plain1[] = {
+       };
+       u_char mac1[] = {
+               0x75,0xf0,0x25,0x1d,0x52,0x8a,0xc0,0x1c,
+               0x45,0x73,0xdf,0xd5,0x84,0xd7,0x9f,0x29
+       };
+       if (!do_xcbc_test(key1, 16,  mac1, plain1, sizeof(plain1)))
+       {
+               return FALSE;
+       }
+       
+       /*
+        * Test Case #2   : AES-XCBC-MAC-96 with 3-byte input
+        * Key (K)        : 000102030405060708090a0b0c0d0e0f
+        * Message (M)    : 000102
+        * AES-XCBC-MAC   : 5b376580ae2f19afe7219ceef172756f
+        * AES-XCBC-MAC-96: 5b376580ae2f19afe7219cee
+        */
+       u_char key2[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+       };
+       u_char plain2[] = {
+               0x00,0x01,0x02
+       };
+       u_char mac2[] = {
+               0x5b,0x37,0x65,0x80,0xae,0x2f,0x19,0xaf,
+               0xe7,0x21,0x9c,0xee,0xf1,0x72,0x75,0x6f
+       };
+       if (!do_xcbc_test(key2, 16,  mac2, plain2, sizeof(plain2)))
+       {
+               return FALSE;
+       }
+
+       /* Test Case #3   : AES-XCBC-MAC-96 with 16-byte input
+        * Key (K)        : 000102030405060708090a0b0c0d0e0f
+        * Message (M)    : 000102030405060708090a0b0c0d0e0f
+        * AES-XCBC-MAC   : d2a246fa349b68a79998a4394ff7a263
+        * AES-XCBC-MAC-96: d2a246fa349b68a79998a439
+        */
+       u_char key3[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+       };
+       u_char plain3[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+       };
+       u_char mac3[] = {
+               0xd2,0xa2,0x46,0xfa,0x34,0x9b,0x68,0xa7,
+               0x99,0x98,0xa4,0x39,0x4f,0xf7,0xa2,0x63
+       };
+       if (!do_xcbc_test(key3, 16,  mac3, plain3, sizeof(plain3)))
+       {
+               return FALSE;
+       }
+
+       /* Test Case #4   : AES-XCBC-MAC-96 with 20-byte input
+        * Key (K)        : 000102030405060708090a0b0c0d0e0f
+        * Message (M)    : 000102030405060708090a0b0c0d0e0f10111213
+        * AES-XCBC-MAC   : 47f51b4564966215b8985c63055ed308
+        * AES-XCBC-MAC-96: 47f51b4564966215b8985c63
+        */
+       u_char key4[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+       };
+       u_char plain4[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+               0x10,0x11,0x12,0x13
+       };
+       u_char mac4[] = {
+               0x47,0xf5,0x1b,0x45,0x64,0x96,0x62,0x15,
+               0xb8,0x98,0x5c,0x63,0x05,0x5e,0xd3,0x08
+       };
+       if (!do_xcbc_test(key4, 16,  mac4, plain4, sizeof(plain4)))
+       {
+               return FALSE;
+       }
+
+       /* Test Case #5   : AES-XCBC-MAC-96 with 32-byte input
+        * Key (K)        : 000102030405060708090a0b0c0d0e0f
+        * Message (M)    : 000102030405060708090a0b0c0d0e0f10111213141516171819
+        *                      1a1b1c1d1e1f
+        * AES-XCBC-MAC   : f54f0ec8d2b9f3d36807734bd5283fd4
+        * AES-XCBC-MAC-96: f54f0ec8d2b9f3d36807734b
+        */
+       u_char key5[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+       };
+       u_char plain5[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+               0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+               0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
+       };
+       u_char mac5[] = {
+               0xf5,0x4f,0x0e,0xc8,0xd2,0xb9,0xf3,0xd3,
+               0x68,0x07,0x73,0x4b,0xd5,0x28,0x3f,0xd4
+       };
+       if (!do_xcbc_test(key5, 16,  mac5, plain5, sizeof(plain5)))
+       {
+               return FALSE;
+       }
+       
+       /* Test Case #7   : AES-XCBC-MAC-96 with 1000-byte input
+        * Key (K)        : 000102030405060708090a0b0c0d0e0f
+        * Message (M)    : 00000000000000000000 ... 00000000000000000000
+        *                  [1000 bytes]
+        * AES-XCBC-MAC   : f0dafee895db30253761103b5d84528f
+        * AES-XCBC-MAC-96: f0dafee895db30253761103b
+        */
+       u_char key7[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+       };
+       u_char plain7[1000];
+       memset(plain7, 0, 1000);
+       u_char mac7[] = {
+               0xf0,0xda,0xfe,0xe8,0x95,0xdb,0x30,0x25,
+               0x37,0x61,0x10,0x3b,0x5d,0x84,0x52,0x8f
+       };
+       if (!do_xcbc_test(key7, 16, mac7, plain7, sizeof(plain7)))
+       {
+               return FALSE;
+       }
+       
+       /* variable key test, RFC4434 */
+       
+       /* Test Case AES-XCBC-PRF-128 with 20-byte input
+        * Key        : 00010203040506070809
+        * Message    : 000102030405060708090a0b0c0d0e0f10111213
+        * PRF Output : 0fa087af7d866e7653434e602fdde835
+        */
+       u_char key8[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,
+       };
+       u_char plain8[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+               0x10,0x11,0x12,0x13
+       };
+       u_char mac8[] = {
+               0x0f,0xa0,0x87,0xaf,0x7d,0x86,0x6e,0x76,
+               0x53,0x43,0x4e,0x60,0x2f,0xdd,0xe8,0x35
+       };
+       if (!do_xcbc_test(key8, 10, mac8, plain8, sizeof(plain8)))
+       {
+               return FALSE;
+       }
+
+       /* Test Case AES-XCBC-PRF-128 with 20-byte input
+        * Key        : 000102030405060708090a0b0c0d0e0fedcb
+        * Message    : 000102030405060708090a0b0c0d0e0f10111213
+        * PRF Output : 8cd3c93ae598a9803006ffb67c40e9e4
+        */
+       u_char key9[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+               0xed,0xcb
+       };
+       u_char plain9[] = {
+               0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+               0x10,0x11,0x12,0x13
+       };
+       u_char mac9[] = {
+               0x8c,0xd3,0xc9,0x3a,0xe5,0x98,0xa9,0x80,
+               0x30,0x06,0xff,0xb6,0x7c,0x40,0xe9,0xe4
+       };
+       if (!do_xcbc_test(key9, 18, mac9, plain9, sizeof(plain9)))
+       {
+               return FALSE;
+       }
+       return TRUE; 
+}
+
index 29c3157..801369e 100644 (file)
@@ -120,6 +120,10 @@ if USE_HMAC
   SUBDIRS += plugins/hmac
 endif
 
+if USE_XCBC
+  SUBDIRS += plugins/xcbc
+endif
+
 if USE_X509
   SUBDIRS += plugins/x509
 endif
diff --git a/src/libstrongswan/plugins/xcbc/Makefile.am b/src/libstrongswan/plugins/xcbc/Makefile.am
new file mode 100644 (file)
index 0000000..1b10d21
--- /dev/null
@@ -0,0 +1,11 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+
+AM_CFLAGS = -rdynamic
+
+plugin_LTLIBRARIES = libstrongswan-xcbc.la
+
+libstrongswan_xcbc_la_SOURCES = xcbc_plugin.h xcbc_plugin.c xcbc.h xcbc.c \
+       xcbc_prf.h xcbc_prf.c xcbc_signer.h xcbc_signer.c
+libstrongswan_xcbc_la_LDFLAGS = -module
+
diff --git a/src/libstrongswan/plugins/xcbc/xcbc.c b/src/libstrongswan/plugins/xcbc/xcbc.c
new file mode 100644 (file)
index 0000000..dc13989
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General xcbc License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 xcbc License
+ * for more details.
+ *
+ * $Id: xcbc.c 3589 2008-03-13 14:14:44Z martin $
+ */
+
+#include <string.h>
+
+#include "xcbc.h"
+
+#include <debug.h>
+
+typedef struct private_xcbc_t private_xcbc_t;
+
+/**
+ * Private data of a xcbc_t object.
+ * 
+ * The variable names are the same as in the RFC.
+ */
+struct private_xcbc_t {
+       /**
+        * Public xcbc_t interface.
+        */
+       xcbc_t xcbc;
+       
+       /**
+        * Block size, in bytes
+        */
+       u_int8_t b;
+       
+       /**
+        * crypter using k1
+        */
+       crypter_t *k1;
+       
+       /**
+        * k2
+        */
+       u_int8_t *k2;
+       
+       /**
+        * k3
+        */
+       u_int8_t *k3;
+};
+
+/**
+ * Implementation of xcbc_t.get_mac.
+ */
+static void get_mac(private_xcbc_t *this, chunk_t data, u_int8_t *e)
+{
+       int n, i, padding;
+       u_int8_t *m;
+       chunk_t iv;
+       
+       if (e == NULL)
+       {
+               DBG1("XCBC append mode not implemented!");
+               /* TODO: append mode */
+               return;
+       }
+       
+       n = data.len / this->b;
+       padding = data.len % this->b;
+       if (padding || data.len == 0)
+       {       /* do an additional block if we have padding or zero-length data */
+               n++;
+       }
+       iv = chunk_alloca(this->b);
+       memset(iv.ptr, 0, iv.len);
+       m = data.ptr;
+       
+       /* (2) Define E[0] = 0x00000000000000000000000000000000 */
+       memset(e, 0, this->b);
+       
+       /* (3) For each block M[i], where i = 1 ... n-1:
+     *     XOR M[i] with E[i-1], then encrypt the result with Key K1,
+     *     yielding E[i].
+     */
+       for (i = 1; i < n; i++)
+       {
+               memxor(e, m + (i - 1) * this->b, this->b);
+               this->k1->encrypt(this->k1, chunk_create(e, this->b), iv, NULL);
+       }
+       
+       /* (4) For block M[n]: */
+       if (data.len && padding == 0)
+       {
+               /* a) If the blocksize of M[n] is 128 bits:
+         *    XOR M[n] with E[n-1] and Key K2, then encrypt the result with
+         *    Key K1, yielding E[n].
+         */
+               memxor(e, m + (i - 1) * this->b, this->b);
+               memxor(e, this->k2, this->b);
+               this->k1->encrypt(this->k1, chunk_create(e, this->b), iv, NULL);
+       }
+       else
+       {
+               /* b) If the blocksize of M[n] is less than 128 bits:
+                *
+                *  i) Pad M[n] with a single "1" bit, followed by the number of
+         *     "0" bits (possibly none) required to increase M[n]'s
+         *     blocksize to 128 bits.
+         */
+        u_int8_t *mn = alloca(this->b);
+        memcpy(mn, m + (n - 1) * this->b, padding);
+        mn[padding] = 0x80;
+        while (++padding < this->b)
+        {
+               mn[padding] = 0x00;
+        }
+        /*  ii) XOR M[n] with E[n-1] and Key K3, then encrypt the result
+         *      with Key K1, yielding E[n].
+         */
+               memxor(e, mn, this->b);
+               memxor(e, this->k3, this->b);
+               this->k1->encrypt(this->k1, chunk_create(e, this->b), iv, NULL);
+       }
+}
+       
+/**
+ * Implementation of xcbc_t.get_block_size.
+ */
+static size_t get_block_size(private_xcbc_t *this)
+{
+       return this->b;
+}
+
+/**
+ * Implementation of xcbc_t.set_key.
+ */
+static void set_key(private_xcbc_t *this, chunk_t key)
+{
+       chunk_t iv, k1, lengthened;
+
+       /* we support variable keys from RFC4434 */
+       if (key.len == this->b)
+       {
+               lengthened = key;
+       }
+       else if (key.len < this->b)
+       {       /* pad short keys */
+               lengthened = chunk_alloca(this->b);
+               memset(lengthened.ptr, 0, lengthened.len);
+               memcpy(lengthened.ptr, key.ptr, key.len);
+       }
+       else
+       {       /* shorten key using xcbc */
+               lengthened = chunk_alloca(this->b);
+               memset(lengthened.ptr, 0, lengthened.len);
+               set_key(this, lengthened);
+               get_mac(this, key, lengthened.ptr);
+       }
+
+       k1 = chunk_alloca(this->b);
+       iv = chunk_alloca(this->b);
+       memset(iv.ptr, 0, iv.len);
+       
+       /* 
+        * (1) Derive 3 128-bit keys (K1, K2 and K3) from the 128-bit secret
+     *     key K, as follows:
+     *     K1 = 0x01010101010101010101010101010101 encrypted with Key K
+     *     K2 = 0x02020202020202020202020202020202 encrypted with Key K
+     *     K3 = 0x03030303030303030303030303030303 encrypted with Key K
+     */
+       this->k1->set_key(this->k1, lengthened);
+       memset(this->k2, 0x02, this->b);
+       this->k1->encrypt(this->k1, chunk_create(this->k2, this->b), iv, NULL);
+       memset(this->k3, 0x03, this->b);
+       this->k1->encrypt(this->k1, chunk_create(this->k3, this->b), iv, NULL);
+       memset(k1.ptr, 0x01, this->b);
+       this->k1->encrypt(this->k1, k1, iv, NULL);
+       this->k1->set_key(this->k1, k1);
+}
+
+/**
+ * Implementation of xcbc_t.destroy.
+ */
+static void destroy(private_xcbc_t *this)
+{
+       this->k1->destroy(this->k1);
+       free(this->k2);
+       free(this->k3);
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+xcbc_t *xcbc_create(encryption_algorithm_t algo, size_t key_size)
+{
+       private_xcbc_t *this;
+       crypter_t *crypter;
+       
+       crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size);
+       if (!crypter)
+       {
+               return NULL;
+       }
+       /* input and output of crypter must be equal for xcbc */
+       if (crypter->get_block_size(crypter) != key_size)
+       {
+               crypter->destroy(crypter);
+               return NULL;
+       }
+       
+       this = malloc_thing(private_xcbc_t);
+       this->xcbc.get_mac = (void (*)(xcbc_t *,chunk_t,u_int8_t*))get_mac;
+       this->xcbc.get_block_size = (size_t (*)(xcbc_t *))get_block_size;
+       this->xcbc.set_key = (void (*)(xcbc_t *,chunk_t))set_key;
+       this->xcbc.destroy = (void (*)(xcbc_t *))destroy;
+       
+       this->b = crypter->get_block_size(crypter);
+       this->k1 = crypter;
+       this->k2 = malloc(this->b);
+       this->k3 = malloc(this->b);
+
+       return &this->xcbc;
+}
+
diff --git a/src/libstrongswan/plugins/xcbc/xcbc.h b/src/libstrongswan/plugins/xcbc/xcbc.h
new file mode 100644 (file)
index 0000000..8181244
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup xcbc xcbc
+ * @{ @ingroup xcbc_p
+ */
+
+#ifndef XCBC_H_
+#define XCBC_H_
+
+typedef struct xcbc_t xcbc_t;
+
+#include <crypto/hashers/hasher.h>
+
+/**
+ * Message authentication using CBC crypter.
+ *
+ * This class implements the message authenticaion algorithm
+ * described in RFC3566.
+ */
+struct xcbc_t {
+       
+       /**
+        * Generate message authentication code.
+        * 
+        * If buffer is NULL, no result is given back. A next call will
+        * append the data to already supplied data. If buffer is not NULL, 
+        * the mac of all apended data is calculated, returned and the
+        * state of the xcbc_t is reseted.
+        * 
+        * @param data          chunk of data to authenticate
+        * @param buffer        pointer where the generated bytes will be written
+        */
+       void (*get_mac) (xcbc_t *this, chunk_t data, u_int8_t *buffer);
+       
+       /**
+        * Get the block size of this xcbc_t object.
+        * 
+        * @return                      block size in bytes
+        */
+       size_t (*get_block_size) (xcbc_t *this);
+       
+       /**
+        * Set the key for this xcbc_t object.
+        * 
+        * @param key           key to set
+        */
+       void (*set_key) (xcbc_t *this, chunk_t key);
+       
+       /**
+        * Destroys a xcbc_t object.
+        */
+       void (*destroy) (xcbc_t *this);
+};
+
+/**
+ * Creates a new xcbc_t object.
+ * 
+ * @param algo                 underlying crypto algorithm
+ * @param key_size             key size to use, if required for algorithm
+ * @return                             xcbc_t object, NULL if not supported
+ */
+xcbc_t *xcbc_create(encryption_algorithm_t algo, size_t key_size);
+
+#endif /*xcbc_H_ @}*/
diff --git a/src/libstrongswan/plugins/xcbc/xcbc_plugin.c b/src/libstrongswan/plugins/xcbc/xcbc_plugin.c
new file mode 100644 (file)
index 0000000..bb2801f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "xcbc_plugin.h"
+
+#include <library.h>
+#include "xcbc_signer.h"
+#include "xcbc_prf.h"
+
+typedef struct private_xcbc_plugin_t private_xcbc_plugin_t;
+
+/**
+ * private data of xcbc_plugin
+ */
+struct private_xcbc_plugin_t {
+
+       /**
+        * public functions
+        */
+       xcbc_plugin_t public;
+};
+
+/**
+ * Implementation of xcbc_plugin_t.xcbctroy
+ */
+static void destroy(private_xcbc_plugin_t *this)
+{
+       lib->crypto->remove_prf(lib->crypto,
+                                                       (prf_constructor_t)xcbc_prf_create);
+       lib->crypto->remove_signer(lib->crypto,
+                                                          (signer_constructor_t)xcbc_signer_create);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *plugin_create()
+{
+       private_xcbc_plugin_t *this = malloc_thing(private_xcbc_plugin_t);
+       
+       this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
+       
+       lib->crypto->add_prf(lib->crypto, PRF_AES128_CBC, 
+                                                (prf_constructor_t)xcbc_prf_create);
+       lib->crypto->add_signer(lib->crypto, AUTH_AES_XCBC_96, 
+                                                       (signer_constructor_t)xcbc_signer_create);
+
+       return &this->public.plugin;
+}
+
diff --git a/src/libstrongswan/plugins/xcbc/xcbc_plugin.h b/src/libstrongswan/plugins/xcbc/xcbc_plugin.h
new file mode 100644 (file)
index 0000000..728d846
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup xcbc_p xcbc
+ * @ingroup plugins
+ *
+ * @defgroup xcbc_plugin xcbc_plugin
+ * @{ @ingroup xcbc_p
+ */
+
+#ifndef XCBC_PLUGIN_H_
+#define XCBC_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct xcbc_plugin_t xcbc_plugin_t;
+
+/**
+ * Plugin implementing xcbc algorithm to provide crypter based PRF and signers.
+ */
+struct xcbc_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       plugin_t plugin;
+};
+
+/**
+ * Create a xcbc_plugin instance.
+ */
+plugin_t *plugin_create();
+
+#endif /* XCBC_PLUGIN_H_ @}*/
diff --git a/src/libstrongswan/plugins/xcbc/xcbc_prf.c b/src/libstrongswan/plugins/xcbc/xcbc_prf.c
new file mode 100644 (file)
index 0000000..0c480c4
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "xcbc_prf.h"
+
+#include "xcbc.h"
+
+typedef struct private_xcbc_prf_t private_xcbc_prf_t;
+
+/**
+ * Private data of a xcbc_prf_t object.
+ */
+struct private_xcbc_prf_t {
+
+       /**
+        * Public xcbc_prf_t interface.
+        */
+       xcbc_prf_t public;      
+       
+       /**
+        * xcbc to use for generation.
+        */
+       xcbc_t *xcbc;
+};
+
+/**
+ * Implementation of prf_t.get_bytes.
+ */
+static void get_bytes(private_xcbc_prf_t *this, chunk_t seed, u_int8_t *buffer)
+{
+       this->xcbc->get_mac(this->xcbc, seed, buffer);
+}
+
+/**
+ * Implementation of prf_t.allocate_bytes.
+ */
+static void allocate_bytes(private_xcbc_prf_t *this, chunk_t seed, chunk_t *chunk)
+{
+       if (chunk)
+       {
+               *chunk = chunk_alloc(this->xcbc->get_block_size(this->xcbc));
+               get_bytes(this, seed, chunk->ptr);
+       }
+       else
+       {
+               get_bytes(this, seed, NULL);
+       }
+}
+
+/**
+ * Implementation of prf_t.get_block_size.
+ */
+static size_t get_block_size(private_xcbc_prf_t *this)
+{
+       return this->xcbc->get_block_size(this->xcbc);
+}
+
+/**
+ * Implementation of prf_t.get_block_size.
+ */
+static size_t get_key_size(private_xcbc_prf_t *this)
+{
+       /* in xcbc, block and key size are always equal */
+       return this->xcbc->get_block_size(this->xcbc);
+}
+
+/**
+ * Implementation of prf_t.set_key.
+ */
+static void set_key(private_xcbc_prf_t *this, chunk_t key)
+{
+       this->xcbc->set_key(this->xcbc, key);
+}
+
+/**
+ * Implementation of prf_t.destroy.
+ */
+static void destroy(private_xcbc_prf_t *this)
+{
+       this->xcbc->destroy(this->xcbc);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+xcbc_prf_t *xcbc_prf_create(pseudo_random_function_t algo)
+{
+       private_xcbc_prf_t *this;
+       xcbc_t *xcbc;
+       
+       switch (algo)
+       {
+               case PRF_AES128_CBC:
+                       xcbc = xcbc_create(ENCR_AES_CBC, 16);
+                       break;
+               default:
+                       return NULL;
+       }
+       if (!xcbc)
+       {
+               return NULL;
+       }
+       
+       this = malloc_thing(private_xcbc_prf_t);
+       this->xcbc = xcbc;
+       
+       this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes;
+       this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes;
+       this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size;
+       this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size;
+       this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key;
+       this->public.prf_interface.destroy = (void (*) (prf_t *))destroy;
+       
+       return &this->public;
+}
+
diff --git a/src/libstrongswan/plugins/xcbc/xcbc_prf.h b/src/libstrongswan/plugins/xcbc/xcbc_prf.h
new file mode 100644 (file)
index 0000000..e8692ae
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup xcbc_prf xcbc_prf
+ * @{ @ingroup xcbc_p
+ */
+
+#ifndef PRF_XCBC_H_
+#define PRF_XCBC_H_
+
+typedef struct xcbc_prf_t xcbc_prf_t;
+
+#include <crypto/prfs/prf.h>
+
+/**
+ * Implementation of prf_t on CBC block cipher using XCBC, RFC3664/RFC4434.
+ * 
+ * This simply wraps a xcbc_t in a prf_t. More a question of
+ * interface matching.
+ */
+struct xcbc_prf_t {
+       
+       /**
+        * Generic prf_t interface for this xcbc_prf_t class.
+        */
+       prf_t prf_interface;
+};
+
+/**
+ * Creates a new xcbc_prf_t object.
+ * 
+ * @param algo         algorithm to implement
+ * @return                     xcbc_prf_t object, NULL if hash not supported
+ */
+xcbc_prf_t *xcbc_prf_create(pseudo_random_function_t algo);
+
+#endif /*PRF_XCBC_SHA1_H_ @}*/
diff --git a/src/libstrongswan/plugins/xcbc/xcbc_signer.c b/src/libstrongswan/plugins/xcbc/xcbc_signer.c
new file mode 100644 (file)
index 0000000..29eb2d2
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include <string.h>
+
+#include "xcbc_signer.h"
+#include "xcbc.h"
+
+typedef struct private_xcbc_signer_t private_xcbc_signer_t;
+
+/**
+ * Private data structure with signing context.
+ */
+struct private_xcbc_signer_t {
+
+       /**
+        * Public interface of xcbc_signer_t.
+        */
+       xcbc_signer_t public;
+       
+       /**
+        * Assigned xcbc function.
+        */
+       xcbc_t *xcbc;
+       
+       /**
+        * Block size (truncation of XCBC MAC)
+        */
+       size_t block_size;
+};
+
+/**
+ * Implementation of signer_t.get_signature.
+ */
+static void get_signature(private_xcbc_signer_t *this,
+                                                 chunk_t data, u_int8_t *buffer)
+{
+       if (buffer == NULL)
+       {       /* append mode */
+               this->xcbc->get_mac(this->xcbc, data, NULL);
+       }
+       else
+       {
+               u_int8_t mac[this->xcbc->get_block_size(this->xcbc)];
+               
+               this->xcbc->get_mac(this->xcbc, data, mac);
+               memcpy(buffer, mac, this->block_size);
+       }
+}
+
+/**
+ * Implementation of signer_t.allocate_signature.
+ */
+static void allocate_signature (private_xcbc_signer_t *this,
+                                                               chunk_t data, chunk_t *chunk)
+{
+       if (chunk == NULL)
+       {       /* append mode */
+               this->xcbc->get_mac(this->xcbc, data, NULL);
+       }
+       else
+       {
+               u_int8_t mac[this->xcbc->get_block_size(this->xcbc)];
+               
+               this->xcbc->get_mac(this->xcbc, data, mac);
+
+               chunk->ptr = malloc(this->block_size);
+               chunk->len = this->block_size;
+               
+               memcpy(chunk->ptr, mac, this->block_size);
+       }
+}
+
+/**
+ * Implementation of signer_t.verify_signature.
+ */
+static bool verify_signature(private_xcbc_signer_t *this,
+                                                        chunk_t data, chunk_t signature)
+{
+       u_int8_t mac[this->xcbc->get_block_size(this->xcbc)];
+       
+       if (signature.len != this->block_size)
+       {
+               return FALSE;
+       }
+       
+       this->xcbc->get_mac(this->xcbc, data, mac);
+       return memeq(signature.ptr, mac, this->block_size);
+}
+
+/**
+ * Implementation of signer_t.get_key_size.
+ */
+static size_t get_key_size(private_xcbc_signer_t *this)
+{
+       return this->xcbc->get_block_size(this->xcbc);
+}
+
+/**
+ * Implementation of signer_t.get_block_size.
+ */
+static size_t get_block_size(private_xcbc_signer_t *this)
+{
+       return this->block_size;
+}
+
+/**
+ * Implementation of signer_t.set_key.
+ */
+static void set_key(private_xcbc_signer_t *this, chunk_t key)
+{
+       this->xcbc->set_key(this->xcbc, key);
+}
+
+/**
+ * Implementation of signer_t.destroy.
+ */
+static status_t destroy(private_xcbc_signer_t *this)
+{
+       this->xcbc->destroy(this->xcbc);
+       free(this);
+       return SUCCESS;
+}
+
+/*
+ * Described in header
+ */
+xcbc_signer_t *xcbc_signer_create(integrity_algorithm_t algo)
+{
+       private_xcbc_signer_t *this;
+       size_t trunc;
+       xcbc_t *xcbc;
+       
+       switch (algo)
+       {
+               case AUTH_AES_XCBC_96:
+                       xcbc = xcbc_create(ENCR_AES_CBC, 16);
+                       trunc = 12;
+                       break;
+               default:
+                       return NULL;
+       }
+       if (xcbc == NULL)
+       {
+               return NULL;
+       }
+       
+       this = malloc_thing(private_xcbc_signer_t);
+       this->xcbc = xcbc;
+       this->block_size = min(trunc, xcbc->get_block_size(xcbc));
+       
+       /* interface functions */
+       this->public.signer_interface.get_signature = (void (*) (signer_t*, chunk_t, u_int8_t*))get_signature;
+       this->public.signer_interface.allocate_signature = (void (*) (signer_t*, chunk_t, chunk_t*))allocate_signature;
+       this->public.signer_interface.verify_signature = (bool (*) (signer_t*, chunk_t, chunk_t))verify_signature;
+       this->public.signer_interface.get_key_size = (size_t (*) (signer_t*))get_key_size;
+       this->public.signer_interface.get_block_size = (size_t (*) (signer_t*))get_block_size;
+       this->public.signer_interface.set_key = (void (*) (signer_t*,chunk_t))set_key;
+       this->public.signer_interface.destroy = (void (*) (signer_t*))destroy;
+       
+       return &this->public;
+}
+
diff --git a/src/libstrongswan/plugins/xcbc/xcbc_signer.h b/src/libstrongswan/plugins/xcbc/xcbc_signer.h
new file mode 100644 (file)
index 0000000..c7eff7e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup xcbc_signer xcbc_signer
+ * @{ @ingroup xcbc_p
+ */
+
+#ifndef xcbc_SIGNER_H_
+#define xcbc_SIGNER_H_
+
+typedef struct xcbc_signer_t xcbc_signer_t;
+
+#include <crypto/signers/signer.h>
+
+/**
+ * Implementation of signer_t based on CBC symmetric cypher. XCBC, RFC3566.
+ */
+struct xcbc_signer_t {
+       
+       /**
+        * generic signer_t interface for this signer
+        */
+       signer_t signer_interface;
+};
+
+/**
+ * Creates a new xcbc_signer_t.
+ *
+ * @param algo         algorithm to implement
+ * @return                     xcbc_signer_t, NULL if  not supported
+ */
+xcbc_signer_t *xcbc_signer_create(integrity_algorithm_t algo);
+
+#endif /*xcbc_SIGNER_H_ @}*/