aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/charon/config/proposal.c4
-rw-r--r--src/charon/plugins/unit_tester/tests.h3
-rw-r--r--src/charon/plugins/unit_tester/tests/test_aes.c240
-rw-r--r--src/libstrongswan/Makefile.am4
-rw-r--r--src/libstrongswan/plugins/xcbc/Makefile.am11
-rw-r--r--src/libstrongswan/plugins/xcbc/xcbc.c231
-rw-r--r--src/libstrongswan/plugins/xcbc/xcbc.h78
-rw-r--r--src/libstrongswan/plugins/xcbc/xcbc_plugin.c65
-rw-r--r--src/libstrongswan/plugins/xcbc/xcbc_plugin.h47
-rw-r--r--src/libstrongswan/plugins/xcbc/xcbc_prf.c131
-rw-r--r--src/libstrongswan/plugins/xcbc/xcbc_prf.h50
-rw-r--r--src/libstrongswan/plugins/xcbc/xcbc_signer.c177
-rw-r--r--src/libstrongswan/plugins/xcbc/xcbc_signer.h47
13 files changed, 1086 insertions, 2 deletions
diff --git a/src/charon/config/proposal.c b/src/charon/config/proposal.c
index b7552fc47..99be9db6c 100644
--- a/src/charon/config/proposal.c
+++ b/src/charon/config/proposal.c
@@ -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);
diff --git a/src/charon/plugins/unit_tester/tests.h b/src/charon/plugins/unit_tester/tests.h
index 9512fe6a7..dd3878c76 100644
--- a/src/charon/plugins/unit_tester/tests.h
+++ b/src/charon/plugins/unit_tester/tests.h
@@ -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)
diff --git a/src/charon/plugins/unit_tester/tests/test_aes.c b/src/charon/plugins/unit_tester/tests/test_aes.c
index 22e8e2575..5b69dc25d 100644
--- a/src/charon/plugins/unit_tester/tests/test_aes.c
+++ b/src/charon/plugins/unit_tester/tests/test_aes.c
@@ -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;
+}
+
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am
index 29c31574d..801369e6e 100644
--- a/src/libstrongswan/Makefile.am
+++ b/src/libstrongswan/Makefile.am
@@ -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
index 000000000..1b10d21f8
--- /dev/null
+++ b/src/libstrongswan/plugins/xcbc/Makefile.am
@@ -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
index 000000000..dc1398950
--- /dev/null
+++ b/src/libstrongswan/plugins/xcbc/xcbc.c
@@ -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
index 000000000..81812442e
--- /dev/null
+++ b/src/libstrongswan/plugins/xcbc/xcbc.h
@@ -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
index 000000000..bb2801fde
--- /dev/null
+++ b/src/libstrongswan/plugins/xcbc/xcbc_plugin.c
@@ -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
index 000000000..728d84690
--- /dev/null
+++ b/src/libstrongswan/plugins/xcbc/xcbc_plugin.h
@@ -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
index 000000000..0c480c455
--- /dev/null
+++ b/src/libstrongswan/plugins/xcbc/xcbc_prf.c
@@ -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
index 000000000..e8692ae23
--- /dev/null
+++ b/src/libstrongswan/plugins/xcbc/xcbc_prf.h
@@ -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
index 000000000..29eb2d25b
--- /dev/null
+++ b/src/libstrongswan/plugins/xcbc/xcbc_signer.c
@@ -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
index 000000000..c7eff7e17
--- /dev/null
+++ b/src/libstrongswan/plugins/xcbc/xcbc_signer.h
@@ -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_ @}*/