summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-09-21 15:07:11 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-09-21 15:10:28 +0200
commit2acd81bd7a1b364b02831ae5f8e46457d9d07865 (patch)
tree969429177db12b56e402ad767531189b7a41834c
parent65912e3e6fce703b03eafc2b4bf11a17a02bd39e (diff)
downloadfastd-2acd81bd7a1b364b02831ae5f8e46457d9d07865.tar
fastd-2acd81bd7a1b364b02831ae5f8e46457d9d07865.zip
Nicely encapsulate different crypto algorithm implementations
-rw-r--r--CMakeLists.txt33
-rw-r--r--config.h.in8
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/config.c81
-rw-r--r--src/config.l2
-rw-r--r--src/config.y11
-rw-r--r--src/crypto.c200
-rw-r--r--src/crypto.h77
-rw-r--r--src/crypto_linux.c259
-rw-r--r--src/fastd.c32
-rw-r--r--src/fastd.h19
-rw-r--r--src/linux_alg.c196
-rw-r--r--src/linux_alg.h42
-rw-r--r--src/method_aes128_gcm.c238
-rw-r--r--src/types.h28
15 files changed, 783 insertions, 446 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5c1c41e..4cdff4a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,14 +16,47 @@ find_package(UECC REQUIRED)
find_package(NaCl REQUIRED)
+set(WITH_CRYPTO_AES128CTR_NACL TRUE CACHE BOOL "Include the AES128-CTR implementation from the NaCl library")
+set(WITH_CRYPTO_AES128CTR_LINUX TRUE CACHE BOOL "Support using the AES128-CTR implementation in the Linux kernel")
+
+set(WITH_CRYPTO_GHASH_BUILTIN TRUE CACHE BOOL "Include the built-in GHASH implementation")
+set(WITH_CRYPTO_GHASH_LINUX TRUE CACHE BOOL "Support using the GHASH implementation in the Linux kernel")
+
set(WITH_METHOD_XSALSA20_POLY1305 TRUE CACHE BOOL "Include xsalsa20-poly1305 method")
set(WITH_METHOD_AES128_GCM TRUE CACHE BOOL "Include aes128-gcm method")
set(MAX_CONFIG_DEPTH 10 CACHE STRING "Maximum config include depth")
+if(WITH_CRYPTO_AES128CTR_NACL OR WITH_CRYPTO_AES128CTR_LINUX)
+ set(WITH_CRYPTO_AES128CTR TRUE)
+endif(WITH_CRYPTO_AES128CTR_NACL OR WITH_CRYPTO_AES128CTR_LINUX)
+
+if(WITH_CRYPTO_GHASH_BUILTIN OR WITH_CRYPTO_GHASH_LINUX)
+ set(WITH_CRYPTO_GHASH TRUE)
+endif(WITH_CRYPTO_GHASH_BUILTIN OR WITH_CRYPTO_GHASH_LINUX)
+
+
# Ensure the value is numeric
math(EXPR MAX_CONFIG_DEPTH_NUM ${MAX_CONFIG_DEPTH})
+set(USE_CRYPTO_AES128CTR FALSE)
+set(USE_CRYPTO_GHASH FALSE)
+
+if(WITH_METHOD_AES128_GCM)
+ set(USE_CRYPTO_AES128CTR TRUE)
+ set(USE_CRYPTO_GHASH TRUE)
+endif(WITH_METHOD_AES128_GCM)
+
+
+if(USE_CRYPTO_AES128CTR AND NOT WITH_CRYPTO_AES128CTR)
+ MESSAGE(FATAL_ERROR "No AES128-CTR implementation was selected, but a selected method needs it.")
+endif(USE_CRYPTO_AES128CTR AND NOT WITH_CRYPTO_AES128CTR)
+
+if(USE_CRYPTO_GHASH AND NOT WITH_CRYPTO_GHASH)
+ MESSAGE(FATAL_ERROR "No GHASH implementation was selected, but a selected method needs it.")
+endif(USE_CRYPTO_GHASH AND NOT WITH_CRYPTO_GHASH)
+
+
configure_file(${FASTD_SOURCE_DIR}/config.h.in ${FASTD_BINARY_DIR}/config.h)
add_subdirectory(src)
diff --git a/config.h.in b/config.h.in
index 6b9595d..fba95a8 100644
--- a/config.h.in
+++ b/config.h.in
@@ -28,6 +28,14 @@
#ifndef _FASTD_CONFIG_H_
#define _FASTD_CONFIG_H_
+#cmakedefine USE_CRYPTO_AES128CTR
+#cmakedefine USE_CRYPTO_GHASH
+
+#cmakedefine WITH_CRYPTO_AES128CTR_NACL
+#cmakedefine WITH_CRYPTO_AES128CTR_LINUX
+#cmakedefine WITH_CRYPTO_GHASH_BUILTIN
+#cmakedefine WITH_CRYPTO_GHASH_LINUX
+
#cmakedefine WITH_METHOD_XSALSA20_POLY1305
#cmakedefine WITH_METHOD_AES128_GCM
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 61dcbc6..da0d355 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -16,8 +16,9 @@ BISON_TARGET(fastd_config_parse config.y ${CMAKE_CURRENT_BINARY_DIR}/config.yy.c
add_executable(fastd
fastd.c
config.c
+ crypto.c
+ crypto_linux.c
handshake.c
- linux_alg.c
peer.c
printf.c
queue.c
diff --git a/src/config.c b/src/config.c
index 168a640..60c3bdc 100644
--- a/src/config.c
+++ b/src/config.c
@@ -31,8 +31,6 @@
#include <config.ll.h>
#include <config.yy.h>
-#include <config.h>
-
#include <arpa/inet.h>
#include <dirent.h>
#include <libgen.h>
@@ -54,6 +52,38 @@ extern const fastd_method fastd_method_aes128_gcm;
#endif
+#ifdef USE_CRYPTO_AES128CTR
+#ifdef WITH_CRYPTO_AES128CTR_NACL
+extern const fastd_crypto_aes128ctr fastd_crypto_aes128ctr_nacl;
+#endif
+#ifdef WITH_CRYPTO_AES128CTR_LINUX
+extern const fastd_crypto_aes128ctr fastd_crypto_aes128ctr_linux;
+#endif
+
+#ifdef WITH_CRYPTO_AES128CTR_NACL
+static const fastd_crypto_aes128ctr *fastd_crypto_aes128ctr_default = &fastd_crypto_aes128ctr_nacl;
+#else
+static const fastd_crypto_aes128ctr *fastd_crypto_aes128ctr_default = &fastd_crypto_aes128ctr_linux;
+#endif
+
+#endif
+
+#ifdef USE_CRYPTO_GHASH
+#ifdef WITH_CRYPTO_GHASH_BUILTIN
+extern const fastd_crypto_ghash fastd_crypto_ghash_builtin;
+#endif
+#ifdef WITH_CRYPTO_GHASH_LINUX
+extern const fastd_crypto_ghash fastd_crypto_ghash_linux;
+#endif
+
+#ifdef WITH_CRYPTO_GHASH_BUILTIN
+static const fastd_crypto_ghash *fastd_crypto_ghash_default = &fastd_crypto_ghash_builtin;
+#else
+static const fastd_crypto_ghash *fastd_crypto_ghash_default = &fastd_crypto_ghash_linux;
+#endif
+
+#endif
+
static void default_config(fastd_config *conf) {
conf->log_stderr_level = -1;
conf->log_syslog_level = -1;
@@ -86,8 +116,13 @@ static void default_config(fastd_config *conf) {
conf->secret = NULL;
conf->key_valid = 3600; /* 60 minutes */
conf->key_refresh = 3300; /* 55 minutes */
- conf->alg_impl_aes128ctr = ALG_IMPL_DEFAULT;
- conf->alg_impl_ghash = ALG_IMPL_DEFAULT;
+
+#ifdef USE_CRYPTO_AES128CTR
+ conf->crypto_aes128ctr = fastd_crypto_aes128ctr_default;
+#endif
+#ifdef USE_CRYPTO_GHASH
+ conf->crypto_ghash = fastd_crypto_ghash_default;
+#endif
conf->peer_dirs = NULL;
conf->peers = NULL;
@@ -177,30 +212,46 @@ bool fastd_config_method(fastd_context *ctx, fastd_config *conf, const char *nam
exit_bug(ctx, "MAX_METHODS too low");
}
-bool fastd_config_algorithm(fastd_context *ctx, fastd_config *conf, const char *alg, const char *impl) {
+bool fastd_config_crypto(fastd_context *ctx, fastd_config *conf, const char *alg, const char *impl) {
+#ifdef USE_CRYPTO_AES128CTR
if (!strcasecmp(alg, "aes128-ctr") || !strcasecmp(alg, "aes128") || !strcasecmp(alg, "aes-ctr") || !strcasecmp(alg, "aes")) {
if (!strcasecmp(impl, "default"))
- conf->alg_impl_aes128ctr = ALG_IMPL_DEFAULT;
- else if (!strcasecmp(impl, "algif"))
- conf->alg_impl_aes128ctr = ALG_IMPL_ALGIF;
+ conf->crypto_aes128ctr = fastd_crypto_aes128ctr_default;
+#ifdef WITH_CRYPTO_AES128CTR_NACL
+ else if (!strcasecmp(impl, "nacl"))
+ conf->crypto_aes128ctr = &fastd_crypto_aes128ctr_nacl;
+#endif
+#ifdef WITH_CRYPTO_AES128CTR_LINUX
+ else if (!strcasecmp(impl, "linux"))
+ conf->crypto_aes128ctr = &fastd_crypto_aes128ctr_linux;
+#endif
else
return false;
return true;
}
- else if (!strcasecmp(alg, "ghash")) {
+ else
+#endif
+#ifdef USE_CRYPTO_GHASH
+ if (!strcasecmp(alg, "ghash")) {
if (!strcasecmp(impl, "default"))
- conf->alg_impl_ghash = ALG_IMPL_DEFAULT;
- else if (!strcasecmp(impl, "algif"))
- conf->alg_impl_ghash = ALG_IMPL_ALGIF;
+ conf->crypto_ghash = fastd_crypto_ghash_default;
+#ifdef WITH_CRYPTO_GHASH_BUILTIN
+ else if (!strcasecmp(impl, "builtin"))
+ conf->crypto_ghash = &fastd_crypto_ghash_builtin;
+#endif
+#ifdef WITH_CRYPTO_GHASH_LINUX
+ else if (!strcasecmp(impl, "linux"))
+ conf->crypto_ghash = &fastd_crypto_ghash_linux;
+#endif
else
return false;
return true;
}
- else {
- return false;
- }
+ else
+#endif
+ return false;
}
bool fastd_config_add_log_file(fastd_context *ctx, fastd_config *conf, const char *name, int level) {
diff --git a/src/config.l b/src/config.l
index b640426..1ee4b28 100644
--- a/src/config.l
+++ b/src/config.l
@@ -97,7 +97,7 @@ yes { TOKEN(TOK_YES); }
no { TOKEN(TOK_NO); }
port { TOKEN(TOK_PORT); }
float { TOKEN(TOK_FLOAT); }
-algorithm { TOKEN(TOK_ALGORITHM); }
+crypto { TOKEN(TOK_CRYPTO); }
use { TOKEN(TOK_USE); }
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} {
diff --git a/src/config.y b/src/config.y
index 8fea5a3..2b1af0f 100644
--- a/src/config.y
+++ b/src/config.y
@@ -95,7 +95,7 @@
%token TOK_NO
%token TOK_PORT
%token TOK_FLOAT
-%token TOK_ALGORITHM
+%token TOK_CRYPTO
%token TOK_USE
%token <addr> TOK_ADDR
@@ -103,7 +103,6 @@
%code {
- #include <config.h>
#include <peer.h>
#include <stdint.h>
@@ -138,7 +137,7 @@ statement: TOK_LOG log ';'
| TOK_MODE mode ';'
| TOK_PROTOCOL protocol ';'
| TOK_METHOD method ';'
- | TOK_ALGORITHM algorithm ';'
+ | TOK_CRYPTO crypto ';'
| TOK_SECRET secret ';'
| TOK_ON TOK_UP on_up ';'
| TOK_ON TOK_DOWN on_down ';'
@@ -229,9 +228,9 @@ method: TOK_STRING {
}
;
-algorithm: TOK_STRING TOK_USE TOK_STRING {
- if (!fastd_config_algorithm(ctx, conf, $1->str, $3->str)) {
- fastd_config_error(&@$, ctx, conf, filename, depth, "invalid algorithm/implementation");
+crypto: TOK_STRING TOK_USE TOK_STRING {
+ if (!fastd_config_crypto(ctx, conf, $1->str, $3->str)) {
+ fastd_config_error(&@$, ctx, conf, filename, depth, "invalid crypto algorithm/implementation");
YYERROR;
}
}
diff --git a/src/crypto.c b/src/crypto.c
new file mode 100644
index 0000000..6aae261
--- /dev/null
+++ b/src/crypto.c
@@ -0,0 +1,200 @@
+/*
+ Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "fastd.h"
+#include "crypto.h"
+
+
+#ifdef USE_CRYPTO_AES128CTR
+#ifdef WITH_CRYPTO_AES128CTR_NACL
+
+#include <crypto_stream_aes128ctr.h>
+
+
+struct _fastd_crypto_aes128ctr_state {
+ fastd_buffer d;
+};
+
+
+static fastd_crypto_aes128ctr_context* aes128ctr_init(fastd_context *ctx) {
+ return (fastd_crypto_aes128ctr_context*)1;
+}
+
+static fastd_crypto_aes128ctr_state* aes128ctr_set_key(fastd_context *ctx, const fastd_crypto_aes128ctr_context *cctx, const fastd_block128 *key) {
+ fastd_crypto_aes128ctr_state *cstate = malloc(sizeof(fastd_crypto_aes128ctr_state));
+
+ cstate->d = fastd_buffer_alloc(crypto_stream_aes128ctr_BEFORENMBYTES, 0, 0);
+ crypto_stream_aes128ctr_beforenm(cstate->d.data, key->b);
+
+ return cstate;
+}
+
+static bool aes128ctr_crypt(fastd_context *ctx, const fastd_crypto_aes128ctr_state *cstate, fastd_block128 *out, const fastd_block128 *in, size_t len, const fastd_block128 *iv) {
+ crypto_stream_aes128ctr_xor_afternm(out->b, in->b, len, iv->b, cstate->d.data);
+ return true;
+}
+
+static void aes128ctr_free_state(fastd_context *ctx, fastd_crypto_aes128ctr_state *cstate) {
+ if (cstate) {
+ fastd_buffer_free(cstate->d);
+ free(cstate);
+ }
+}
+
+static void aes128ctr_free(fastd_context *ctx, fastd_crypto_aes128ctr_context *cctx) {
+}
+
+fastd_crypto_aes128ctr fastd_crypto_aes128ctr_nacl = {
+ .name = "nacl",
+
+ .init = aes128ctr_init,
+ .set_key = aes128ctr_set_key,
+ .crypt = aes128ctr_crypt,
+
+ .free_state = aes128ctr_free_state,
+ .free = aes128ctr_free,
+};
+
+#endif
+#endif
+
+#ifdef USE_CRYPTO_GHASH
+#ifdef WITH_CRYPTO_GHASH_BUILTIN
+
+struct _fastd_crypto_ghash_state {
+ fastd_block128 H[32][16];
+};
+
+
+static const fastd_block128 r = { .b = {0xe1} };
+
+
+static inline uint8_t shr(fastd_block128 *out, const fastd_block128 *in, int n) {
+ int i;
+ uint8_t c = 0;
+
+ for (i = 0; i < sizeof(fastd_block128); i++) {
+ uint8_t c2 = in->b[i] << (8-n);
+ out->b[i] = (in->b[i] >> n) | c;
+ c = c2;
+ }
+
+ return (c >> (8-n));
+}
+
+static inline void mulH_a(fastd_block128 *x, const fastd_crypto_ghash_state *cstate) {
+ fastd_block128 out = {};
+
+ int i;
+ for (i = 0; i < 16; i++) {
+ xor_a(&out, &cstate->H[2*i][x->b[i]>>4]);
+ xor_a(&out, &cstate->H[2*i+1][x->b[i]&0xf]);
+ }
+
+ *x = out;
+}
+
+
+static fastd_crypto_ghash_context* ghash_init(fastd_context *ctx) {
+ return (fastd_crypto_ghash_context*)1;
+}
+
+static fastd_crypto_ghash_state* ghash_set_h(fastd_context *ctx, const fastd_crypto_ghash_context *cctx, const fastd_block128 *h) {
+ fastd_crypto_ghash_state *cstate = malloc(sizeof(fastd_crypto_ghash_state));
+
+ fastd_block128 Hbase[4];
+ fastd_block128 Rbase[4];
+
+ Hbase[0] = *h;
+ Rbase[0] = r;
+
+ int i;
+ for (i = 1; i < 4; i++) {
+ uint8_t carry = shr(&Hbase[i], &Hbase[i-1], 1);
+ if (carry)
+ xor_a(&Hbase[i], &r);
+
+ shr(&Rbase[i], &Rbase[i-1], 1);
+ }
+
+ fastd_block128 R[16];
+ memset(cstate->H, 0, sizeof(cstate->H));
+ memset(R, 0, sizeof(R));
+
+ for (i = 0; i < 16; i++) {
+ int j;
+ for (j = 0; j < 4; j++) {
+ if (i & (8 >> j)) {
+ xor_a(&cstate->H[0][i], &Hbase[j]);
+ xor_a(&R[i], &Rbase[j]);
+ }
+ }
+ }
+
+ for (i = 1; i < 32; i++) {
+ int j;
+
+ for (j = 0; j < 16; j++) {
+ uint8_t carry = shr(&cstate->H[i][j], &cstate->H[i-1][j], 4);
+ xor_a(&cstate->H[i][j], &R[carry]);
+ }
+ }
+
+ return cstate;
+}
+
+static bool ghash_hash(fastd_context *ctx, const fastd_crypto_ghash_state *cstate, fastd_block128 *out, const fastd_block128 *in, size_t n_blocks) {
+ memset(out, 0, sizeof(fastd_block128));
+
+ int i;
+ for (i = 0; i < n_blocks; i++) {
+ xor_a(out, &in[i]);
+ mulH_a(out, cstate);
+ }
+
+ return true;
+}
+
+static void ghash_free_state(fastd_context *ctx, fastd_crypto_ghash_state *cstate) {
+ free(cstate);
+}
+
+static void ghash_free(fastd_context *ctx, fastd_crypto_ghash_context *cctx) {
+}
+
+fastd_crypto_ghash fastd_crypto_ghash_builtin = {
+ .name = "builtin",
+
+ .init = ghash_init,
+ .set_h = ghash_set_h,
+ .hash = ghash_hash,
+
+ .free_state = ghash_free_state,
+ .free = ghash_free,
+};
+
+#endif
+#endif
diff --git a/src/crypto.h b/src/crypto.h
new file mode 100644
index 0000000..89c44d6
--- /dev/null
+++ b/src/crypto.h
@@ -0,0 +1,77 @@
+/*
+ Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef _FASTD_CRYPTO_H_
+#define _FASTD_CRYPTO_H_
+
+#include "types.h"
+
+#include <stdint.h>
+
+
+typedef union _fastd_block128 {
+ uint8_t b[16];
+ uint64_t qw[2];
+} __attribute__((aligned(16))) fastd_block128;
+
+
+#ifdef USE_CRYPTO_AES128CTR
+struct _fastd_crypto_aes128ctr {
+ const char *name;
+
+ fastd_crypto_aes128ctr_context* (*init)(fastd_context *ctx);
+ fastd_crypto_aes128ctr_state* (*set_key)(fastd_context *ctx, const fastd_crypto_aes128ctr_context *cctx, const fastd_block128 *key);
+ bool (*crypt)(fastd_context *ctx, const fastd_crypto_aes128ctr_state *cstate, fastd_block128 *out, const fastd_block128 *in, size_t len, const fastd_block128 *iv);
+
+ void (*free_state)(fastd_context *ctx, fastd_crypto_aes128ctr_state *cstate);
+ void (*free)(fastd_context *ctx, fastd_crypto_aes128ctr_context *cctx);
+};
+#endif
+
+#ifdef USE_CRYPTO_GHASH
+struct _fastd_crypto_ghash {
+ const char *name;
+
+ fastd_crypto_ghash_context* (*init)(fastd_context *ctx);
+ fastd_crypto_ghash_state* (*set_h)(fastd_context *ctx, const fastd_crypto_ghash_context *cctx, const fastd_block128 *h);
+ bool (*hash)(fastd_context *ctx, const fastd_crypto_ghash_state *cstate, fastd_block128 *out, const fastd_block128 *in, size_t n_blocks);
+
+ void (*free_state)(fastd_context *ctx, fastd_crypto_ghash_state *cstate);
+ void (*free)(fastd_context *ctx, fastd_crypto_ghash_context *cctx);
+};
+#endif
+
+
+static inline void xor(fastd_block128 *x, const fastd_block128 *a, const fastd_block128 *b) {
+ x->qw[0] = a->qw[0] ^ b->qw[0];
+ x->qw[1] = a->qw[1] ^ b->qw[1];
+}
+
+static inline void xor_a(fastd_block128 *x, const fastd_block128 *a) {
+ xor(x, x, a);
+}
+
+#endif /* _FASTD_CRYPTO_H_ */
diff --git a/src/crypto_linux.c b/src/crypto_linux.c
new file mode 100644
index 0000000..902170b
--- /dev/null
+++ b/src/crypto_linux.c
@@ -0,0 +1,259 @@
+/*
+ Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "fastd.h"
+#include "crypto.h"
+
+#include <alloca.h>
+#include <linux/if_alg.h>
+#include <unistd.h>
+
+
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
+
+#ifdef USE_CRYPTO_AES128CTR
+#ifdef WITH_CRYPTO_AES128CTR_LINUX
+
+struct _fastd_crypto_aes128ctr_context {
+ int fd;
+};
+
+struct _fastd_crypto_aes128ctr_state {
+ int fd;
+};
+
+static fastd_crypto_aes128ctr_context* aes128ctr_init(fastd_context *ctx) {
+ int fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
+ if (fd < 0)
+ goto error;
+
+ struct sockaddr_alg sa = {};
+ sa.salg_family = AF_ALG;
+ strcpy((char*)sa.salg_type, "skcipher");
+ strcpy((char*)sa.salg_name, "ctr(aes)");
+ if (bind(fd, (struct sockaddr*)&sa, sizeof(sa)) < 0)
+ goto error;
+
+ fastd_crypto_aes128ctr_context *cctx = malloc(sizeof(fastd_crypto_aes128ctr_context));
+ cctx->fd = fd;
+ return cctx;
+
+ error:
+ if (fd >= 0)
+ close(fd);
+
+ pr_error(ctx, "no kernel support for AES-CTR was found");
+ return NULL;
+}
+
+static fastd_crypto_aes128ctr_state* aes128ctr_set_key(fastd_context *ctx, const fastd_crypto_aes128ctr_context *cctx, const fastd_block128 *key) {
+ if (setsockopt(cctx->fd, SOL_ALG, ALG_SET_KEY, key->b, 16) < 0) {
+ pr_error_errno(ctx, "aes128ctr_set_key(linux): setsockopt");
+ return NULL;
+ }
+
+ int fd = accept(cctx->fd, NULL, NULL);
+
+ if (fd < 0) {
+ pr_error_errno(ctx, "aes128ctr_set_key(linux): accept");
+ return NULL;
+ }
+
+ fastd_crypto_aes128ctr_state *cstate = malloc(sizeof(fastd_crypto_aes128ctr_state));
+ cstate->fd = fd;
+
+ return cstate;
+}
+
+static bool aes128ctr_crypt(fastd_context *ctx, const fastd_crypto_aes128ctr_state *cstate, fastd_block128 *out, const fastd_block128 *in, size_t len, const fastd_block128 *iv) {
+ if (!len)
+ return false;
+
+ struct iovec vec = { .iov_base = (void*)in, .iov_len = len };
+
+ static const size_t cmsglen = sizeof(struct cmsghdr)+sizeof(struct af_alg_iv)+16;
+ struct cmsghdr *cmsg = alloca(cmsglen);
+ cmsg->cmsg_len = cmsglen;
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_IV;
+
+ struct af_alg_iv *alg_iv = (void*)CMSG_DATA(cmsg);
+ alg_iv->ivlen = 16;
+ memcpy(alg_iv->iv, iv, 16);
+
+ struct msghdr msg = {
+ .msg_iov = &vec,
+ .msg_iovlen = 1,
+ .msg_control = cmsg,
+ .msg_controllen = cmsglen
+ };
+
+ if (sendmsg(cstate->fd, &msg, 0) < 0) {
+ pr_error_errno(ctx, "aes128ctr_crypt(linux): sendmsg");
+ return false;
+ }
+
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ vec.iov_base = out;
+
+ if (recvmsg(cstate->fd, &msg, 0) < 0) {
+ pr_error_errno(ctx, "aes128ctr_crypt(linux): recvmsg");
+ return false;
+ }
+
+ return true;
+}
+
+static void aes128ctr_free_state(fastd_context *ctx, fastd_crypto_aes128ctr_state *cstate) {
+ if (cstate) {
+ close(cstate->fd);
+ free(cstate);
+ }
+}
+
+static void aes128ctr_free(fastd_context *ctx, fastd_crypto_aes128ctr_context *cctx) {
+ if (cctx) {
+ close(cctx->fd);
+ free(cctx);
+ }
+}
+
+fastd_crypto_aes128ctr fastd_crypto_aes128ctr_linux = {
+ .name = "linux",
+
+ .init = aes128ctr_init,
+ .set_key = aes128ctr_set_key,
+ .crypt = aes128ctr_crypt,
+
+ .free_state = aes128ctr_free_state,
+ .free = aes128ctr_free,
+};
+
+#endif
+#endif
+
+#ifdef USE_CRYPTO_GHASH
+#ifdef WITH_CRYPTO_GHASH_LINUX
+
+struct _fastd_crypto_ghash_context {
+ int fd;
+};
+
+struct _fastd_crypto_ghash_state {
+ int fd;
+};
+
+static fastd_crypto_ghash_context* ghash_init(fastd_context *ctx) {
+ int fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
+ if (fd < 0)
+ goto error;
+
+ struct sockaddr_alg sa = {};
+ sa.salg_family = AF_ALG;
+ strcpy((char*)sa.salg_type, "hash");
+ strcpy((char*)sa.salg_name, "ghash");
+ if (bind(fd, (struct sockaddr*)&sa, sizeof(sa)) < 0)
+ goto error;
+
+ fastd_crypto_ghash_context *cctx = malloc(sizeof(fastd_crypto_ghash_context));
+ cctx->fd = fd;
+ return cctx;
+
+ error:
+ if (fd >= 0)
+ close(fd);
+
+ pr_error(ctx, "no kernel support for GHASH was found");
+ return NULL;
+}
+
+static fastd_crypto_ghash_state* ghash_set_h(fastd_context *ctx, const fastd_crypto_ghash_context *cctx, const fastd_block128 *h) {
+ if (setsockopt(cctx->fd, SOL_ALG, ALG_SET_KEY, h, 16) < 0) {
+ pr_error_errno(ctx, "ghash_set_h(linux): setsockopt");
+ return NULL;
+ }
+
+ int fd = accept(cctx->fd, NULL, NULL);
+
+ if (fd < 0) {
+ pr_error_errno(ctx, "ghash_set_h(linux): accept");
+ return NULL;
+ }
+
+ fastd_crypto_ghash_state *cstate = malloc(sizeof(fastd_crypto_ghash_state));
+ cstate->fd = fd;
+
+ return cstate;
+}
+
+static bool ghash_hash(fastd_context *ctx, const fastd_crypto_ghash_state *cstate, fastd_block128 *out, const fastd_block128 *in, size_t n_blocks) {
+ if (!n_blocks)
+ return false;
+
+ if (write(cstate->fd, in, n_blocks*16) < 0) {
+ pr_error_errno(ctx, "ghash_hash(linux): write");
+ return false;
+ }
+
+ if (read(cstate->fd, out, 16) < 16) {
+ pr_error_errno(ctx, "ghash_hash(linux): read");
+ return false;
+ }
+
+ return true;
+}
+
+static void ghash_free_state(fastd_context *ctx, fastd_crypto_ghash_state *cstate) {
+ if (cstate) {
+ close(cstate->fd);
+ free(cstate);
+ }
+}
+
+static void ghash_free(fastd_context *ctx, fastd_crypto_ghash_context *cctx) {
+ if (cctx) {
+ close(cctx->fd);
+ free(cctx);
+ }
+}
+
+fastd_crypto_ghash fastd_crypto_ghash_linux = {
+ .name = "linux",
+
+ .init = ghash_init,
+ .set_h = ghash_set_h,
+ .hash = ghash_hash,
+
+ .free_state = ghash_free_state,
+ .free = ghash_free,
+};
+
+#endif
+#endif
diff --git a/src/fastd.c b/src/fastd.c
index f9d8403..5388384 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -27,8 +27,8 @@
#define _GNU_SOURCE
#include "fastd.h"
+#include "crypto.h"
#include "handshake.h"
-#include "linux_alg.h"
#include "peer.h"
#include "task.h"
@@ -120,6 +120,32 @@ static void close_log(fastd_context *ctx) {
closelog();
}
+static void crypto_init(fastd_context *ctx) {
+#ifdef USE_CRYPTO_AES128CTR
+ ctx->crypto_aes128ctr = ctx->conf->crypto_aes128ctr->init(ctx);
+ if (!ctx->crypto_aes128ctr)
+ exit_error(ctx, "Unable to initialize AES128-CTR implementation");
+#endif
+
+#ifdef USE_CRYPTO_GHASH
+ ctx->crypto_ghash = ctx->conf->crypto_ghash->init(ctx);
+ if (!ctx->crypto_ghash)
+ exit_error(ctx, "Unable to initialize GHASH implementation");
+#endif
+}
+
+static void crypto_free(fastd_context *ctx) {
+#ifdef USE_CRYPTO_AES128CTR
+ ctx->conf->crypto_aes128ctr->free(ctx, ctx->crypto_aes128ctr);
+ ctx->crypto_aes128ctr = NULL;
+#endif
+
+#ifdef USE_CRYPTO_GHASH
+ ctx->conf->crypto_ghash->free(ctx, ctx->crypto_ghash);
+ ctx->crypto_ghash = NULL;
+#endif
+}
+
static void init_sockets(fastd_context *ctx) {
struct sockaddr_in addr_in = ctx->conf->bind_addr_in;
struct sockaddr_in6 addr_in6 = ctx->conf->bind_addr_in6;
@@ -790,7 +816,7 @@ int main(int argc, char *argv[]) {
init_log(&ctx);
- fastd_linux_alg_init(&ctx);
+ crypto_init(&ctx);
if (conf.generate_key) {
conf.protocol->generate_key(&ctx);
@@ -865,7 +891,7 @@ int main(int argc, char *argv[]) {
free(ctx.protocol_state);
free(ctx.eth_addr);
- fastd_linux_alg_close(&ctx);
+ crypto_free(&ctx);
close_log(&ctx);
fastd_config_release(&ctx, &conf);
diff --git a/src/fastd.h b/src/fastd.h
index 4d435a7..1ee8939 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -163,8 +163,13 @@ struct _fastd_config {
char *secret;
unsigned key_valid;
unsigned key_refresh;
- fastd_alg_impl alg_impl_aes128ctr;
- fastd_alg_impl alg_impl_ghash;
+
+#ifdef USE_CRYPTO_AES128CTR
+ const fastd_crypto_aes128ctr *crypto_aes128ctr;
+#endif
+#ifdef USE_CRYPTO_GHASH
+ const fastd_crypto_ghash *crypto_ghash;
+#endif
fastd_string_stack *peer_dirs;
fastd_peer_config *peers;
@@ -217,8 +222,12 @@ struct _fastd_context {
int sockfd;
int sock6fd;
- int algfd_ghash;
- int algfd_aesctr;
+#ifdef USE_CRYPTO_AES128CTR
+ fastd_crypto_aes128ctr_context *crypto_aes128ctr;
+#endif
+#ifdef USE_CRYPTO_GHASH
+ fastd_crypto_ghash_context *crypto_ghash;
+#endif
size_t eth_addr_size;
size_t n_eth_addr;
@@ -249,7 +258,7 @@ bool fastd_read_config(fastd_context *ctx, fastd_config *conf, const char *filen
bool fastd_config_protocol(fastd_context *ctx, fastd_config *conf, const char *name);
bool fastd_config_method(fastd_context *ctx, fastd_config *conf, const char *name);
-bool fastd_config_algorithm(fastd_context *ctx, fastd_config *conf, const char *alg, const char *impl);
+bool fastd_config_crypto(fastd_context *ctx, fastd_config *conf, const char *alg, const char *impl);
bool fastd_config_add_log_file(fastd_context *ctx, fastd_config *conf, const char *name, int level);
void fastd_configure(fastd_context *ctx, fastd_config *conf, int argc, char *const argv[]);
void fastd_reconfigure(fastd_context *ctx, fastd_config *conf);
diff --git a/src/linux_alg.c b/src/linux_alg.c
deleted file mode 100644
index ab08cab..0000000
--- a/src/linux_alg.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-
-#include "linux_alg.h"
-
-#include <alloca.h>
-#include <linux/if_alg.h>
-#include <unistd.h>
-
-
-#ifndef SOL_ALG
-#define SOL_ALG 279
-#endif
-
-
-static int init_aesctr(fastd_context *ctx) {
- int fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
- if (fd < 0)
- goto error;
-
- struct sockaddr_alg sa = {};
- sa.salg_family = AF_ALG;
- strcpy((char*)sa.salg_type, "skcipher");
- strcpy((char*)sa.salg_name, "ctr(aes)");
- if (bind(fd, (struct sockaddr*)&sa, sizeof(sa)) < 0)
- goto error;
-
- return fd;
-
- error:
- if (fd >= 0)
- close(fd);
-
- pr_info(ctx, "no kernel support for AES-CTR was found, falling back to userspace implementation");
- return -1;
-}
-
-static int init_ghash(fastd_context *ctx) {
- int fd = socket(AF_ALG, SOCK_SEQPACKET, 0);
- if (fd < 0)
- goto error;
-
- struct sockaddr_alg sa = {};
- sa.salg_family = AF_ALG;
- strcpy((char*)sa.salg_type, "hash");
- strcpy((char*)sa.salg_name, "ghash");
- if (bind(fd, (struct sockaddr*)&sa, sizeof(sa)) < 0)
- goto error;
-
- return fd;
-
- error:
- if (fd >= 0)
- close(fd);
-
- pr_info(ctx, "no kernel support for GHASH was found, falling back to userspace implementation");
- return -1;
-}
-
-void fastd_linux_alg_init(fastd_context *ctx) {
- if (ctx->conf->alg_impl_aes128ctr == ALG_IMPL_ALGIF)
- ctx->algfd_aesctr = init_aesctr(ctx);
- else
- ctx->algfd_aesctr = -1;
-
- if (ctx->conf->alg_impl_ghash == ALG_IMPL_ALGIF)
- ctx->algfd_ghash = init_ghash(ctx);
- else
- ctx->algfd_ghash = -1;
-}
-
-void fastd_linux_alg_close(fastd_context *ctx) {
- if (ctx->algfd_ghash >= 0)
- close(ctx->algfd_ghash);
-
- if (ctx->algfd_aesctr >= 0)
- close(ctx->algfd_aesctr);
-}
-
-int fastd_linux_alg_aesctr_init(fastd_context *ctx, uint8_t *key, size_t keylen) {
- if (ctx->algfd_aesctr < 0)
- return -1;
-
- if (setsockopt(ctx->algfd_aesctr, SOL_ALG, ALG_SET_KEY, key, keylen) < 0) {
- pr_error_errno(ctx, "fastd_linux_alg_aesctr_init: setsockopt");
- return -1;
- }
-
- int ret = accept(ctx->algfd_aesctr, NULL, NULL);
-
- if (ret < 0) {
- pr_error_errno(ctx, "fastd_linux_alg_aesctr_init: accept");
- return -1;
- }
-
- return ret;
-}
-
-bool fastd_linux_alg_aesctr(fastd_context *ctx, int fd, void *out, const void *in, size_t len, const uint8_t iv[16]) {
- if (!len)
- return false;
-
- struct iovec vec = { .iov_base = (void*)in, .iov_len = len };
-
- static const size_t cmsglen = sizeof(struct cmsghdr)+sizeof(struct af_alg_iv)+16;
- struct cmsghdr *cmsg = alloca(cmsglen);
- cmsg->cmsg_len = cmsglen;
- cmsg->cmsg_level = SOL_ALG;
- cmsg->cmsg_type = ALG_SET_IV;
-
- struct af_alg_iv *alg_iv = (void*)CMSG_DATA(cmsg);
- alg_iv->ivlen = 16;
- memcpy(alg_iv->iv, iv, 16);
-
- struct msghdr msg = {
- .msg_iov = &vec,
- .msg_iovlen = 1,
- .msg_control = cmsg,
- .msg_controllen = cmsglen
- };
-
- if (sendmsg(fd, &msg, 0) < 0) {
- pr_error_errno(ctx, "fastd_linux_alg_aesctr: sendmsg");
- return false;
- }
-
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- vec.iov_base = out;
-
- if (recvmsg(fd, &msg, 0) < 0) {
- pr_error_errno(ctx, "fastd_linux_alg_aesctr: recvmsg");
- return false;
- }
-
- return true;
-}
-
-int fastd_linux_alg_ghash_init(fastd_context *ctx, uint8_t key[16]) {
- if (ctx->algfd_ghash < 0)
- return -1;
-
- if (setsockopt(ctx->algfd_ghash, SOL_ALG, ALG_SET_KEY, key, 16) < 0) {
- pr_error_errno(ctx, "fastd_linux_alg_ghash_init: setsockopt");
- return -1;
- }
-
- int ret = accept(ctx->algfd_ghash, NULL, NULL);
-
- if (ret < 0) {
- pr_error_errno(ctx, "fastd_linux_alg_ghash_init: accept");
- return -1;
- }
-
- return ret;
-}
-
-bool fastd_linux_alg_ghash(fastd_context *ctx, int fd, uint8_t out[16], const void *data, size_t len) {
- if (!len)
- return false;
-
- if (write(fd, data, len) < 0) {
- pr_error_errno(ctx, "fastd_linux_alg_ghash: write");
- return false;
- }
-
- if (read(fd, out, 16) < 16) {
- pr_error_errno(ctx, "fastd_linux_alg_ghash: read");
- return false;
- }
-
- return true;
-}
diff --git a/src/linux_alg.h b/src/linux_alg.h
deleted file mode 100644
index 0099474..0000000
--- a/src/linux_alg.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-
-#ifndef _FASTD_LINUX_ALG_H_
-#define _FASTD_LINUX_ALG_H_
-
-#include "fastd.h"
-
-
-void fastd_linux_alg_init(fastd_context *ctx);
-void fastd_linux_alg_close(fastd_context *ctx);
-
-int fastd_linux_alg_ghash_init(fastd_context *ctx, uint8_t key[16]);
-bool fastd_linux_alg_ghash(fastd_context *ctx, int fd, uint8_t out[16], const void *data, size_t len);
-
-int fastd_linux_alg_aesctr_init(fastd_context *ctx, uint8_t *key, size_t keylen);
-bool fastd_linux_alg_aesctr(fastd_context *ctx, int fd, void *out, const void *in, size_t len, const uint8_t iv[16]);
-
-#endif /* _FASTD_LINUX_ALG_H_ */
diff --git a/src/method_aes128_gcm.c b/src/method_aes128_gcm.c
index bbecb69..68b9030 100644
--- a/src/method_aes128_gcm.c
+++ b/src/method_aes128_gcm.c
@@ -25,38 +25,26 @@
#include "fastd.h"
-#include "linux_alg.h"
+#include "crypto.h"
-#include <crypto_stream_aes128ctr.h>
#include <unistd.h>
#define KEYBYTES 16
#define NONCEBYTES 7
-#define BLOCKBYTES 16
-#define BLOCKQWORDS (BLOCKBYTES/8)
-
-
-typedef union _block_t {
- uint8_t b[BLOCKBYTES];
- uint64_t qw[BLOCKQWORDS];
-} __attribute__((aligned(16))) block_t;
struct _fastd_method_session_state {
struct timespec valid_till;
struct timespec refresh_after;
- fastd_buffer d;
- block_t H[32][16];
-
uint8_t send_nonce[NONCEBYTES];
uint8_t receive_nonce[NONCEBYTES];
struct timespec receive_last;
uint64_t receive_reorder_seen;
- int algfd_aesctr;
- int algfd_ghash;
+ fastd_crypto_aes128ctr_state *cstate_aes128ctr;
+ fastd_crypto_ghash_state *cstate_ghash;
};
@@ -90,12 +78,12 @@ static inline bool is_nonce_valid(const uint8_t nonce[NONCEBYTES], const uint8_t
}
static size_t method_max_packet_size(fastd_context *ctx) {
- return (fastd_max_packet_size(ctx) + NONCEBYTES + BLOCKBYTES);
+ return (fastd_max_packet_size(ctx) + NONCEBYTES + sizeof(fastd_block128));
}
static size_t method_min_encrypt_head_space(fastd_context *ctx) {
- return BLOCKBYTES;
+ return sizeof(fastd_block128);
}
static size_t method_min_decrypt_head_space(fastd_context *ctx) {
@@ -103,50 +91,13 @@ static size_t method_min_decrypt_head_space(fastd_context *ctx) {
}
static size_t method_min_encrypt_tail_space(fastd_context *ctx) {
- return (BLOCKBYTES-1);
+ return (sizeof(fastd_block128)-1);
}
static size_t method_min_decrypt_tail_space(fastd_context *ctx) {
- return (2*BLOCKBYTES-1);
-}
-
-
-static const block_t r = { .b = {0xe1} };
-
-static inline uint8_t shr(block_t *out, const block_t *in, int n) {
- int i;
- uint8_t c = 0;
-
- for (i = 0; i < BLOCKBYTES; i++) {
- uint8_t c2 = in->b[i] << (8-n);
- out->b[i] = (in->b[i] >> n) | c;
- c = c2;
- }
-
- return (c >> (8-n));
-}
-
-static inline void xor(block_t *x, const block_t *a, const block_t *b) {
- x->qw[0] = a->qw[0] ^ b->qw[0];
- x->qw[1] = a->qw[1] ^ b->qw[1];
-}
-
-static inline void xor_a(block_t *x, const block_t *a) {
- xor(x, x, a);
+ return (2*sizeof(fastd_block128)-1);
}
-static void aes128ctr(fastd_context *ctx, block_t *out, const block_t *in, size_t n_blocks, const block_t *iv, fastd_method_session_state *session) {
- if (session->algfd_aesctr >= 0) {
- if (fastd_linux_alg_aesctr(ctx, session->algfd_aesctr, out, in, n_blocks*BLOCKBYTES, iv->b))
- return;
-
- /* on error */
- close(session->algfd_aesctr);
- session->algfd_aesctr = -1;
- }
-
- crypto_stream_aes128ctr_xor_afternm(out->b, in->b, sizeof(block_t)*n_blocks, iv->b, session->d.data);
-}
static fastd_method_session_state* method_session_init(fastd_context *ctx, uint8_t *secret, size_t length, bool initiator) {
int i;
@@ -162,51 +113,16 @@ static fastd_method_session_state* method_session_init(fastd_context *ctx, uint8
session->refresh_after = ctx->now;
session->refresh_after.tv_sec += ctx->conf->key_refresh;
- session->d = fastd_buffer_alloc(crypto_stream_aes128ctr_BEFORENMBYTES, 0, 0);
- crypto_stream_aes128ctr_beforenm(session->d.data, secret);
-
- session->algfd_aesctr = fastd_linux_alg_aesctr_init(ctx, secret, KEYBYTES);
-
- static const block_t zeroblock = {};
-
- block_t Hbase[4];
- aes128ctr(ctx, &Hbase[0], &zeroblock, 1, &zeroblock, session);
-
- block_t Rbase[4];
- Rbase[0] = r;
-
- for (i = 1; i < 4; i++) {
- uint8_t carry = shr(&Hbase[i], &Hbase[i-1], 1);
- if (carry)
- xor_a(&Hbase[i], &r);
-
- shr(&Rbase[i], &Rbase[i-1], 1);
- }
-
- block_t R[16];
- memset(session->H, 0, sizeof(session->H));
- memset(R, 0, sizeof(R));
-
- for (i = 0; i < 16; i++) {
- int j;
- for (j = 0; j < 4; j++) {
- if (i & (8 >> j)) {
- xor_a(&session->H[0][i], &Hbase[j]);
- xor_a(&R[i], &Rbase[j]);
- }
- }
- }
+ fastd_block128 key;
+ memcpy(key.b, secret, sizeof(fastd_block128));
+ session->cstate_aes128ctr = ctx->conf->crypto_aes128ctr->set_key(ctx, ctx->crypto_aes128ctr, &key);
- for (i = 1; i < 32; i++) {
- int j;
+ static const fastd_block128 zeroblock = {};
+ fastd_block128 H;
- for (j = 0; j < 16; j++) {
- uint8_t carry = shr(&session->H[i][j], &session->H[i-1][j], 4);
- xor_a(&session->H[i][j], &R[carry]);
- }
- }
+ ctx->conf->crypto_aes128ctr->crypt(ctx, session->cstate_aes128ctr, &H, &zeroblock, sizeof(fastd_block128), &zeroblock);
- session->algfd_ghash = fastd_linux_alg_ghash_init(ctx, Hbase[0].b);
+ session->cstate_ghash = ctx->conf->crypto_ghash->set_h(ctx, ctx->crypto_ghash, &H);
session->send_nonce[0] = initiator ? 3 : 2;
session->receive_nonce[0] = initiator ? 0 : 1;
@@ -233,84 +149,62 @@ static bool method_session_want_refresh(fastd_context *ctx, fastd_method_session
static void method_session_free(fastd_context *ctx, fastd_method_session_state *session) {
if(session) {
- close(session->algfd_ghash);
-
- fastd_buffer_free(session->d);
+ ctx->conf->crypto_aes128ctr->free_state(ctx, session->cstate_aes128ctr);
+ ctx->conf->crypto_ghash->free_state(ctx, session->cstate_ghash);
memset(session, 0, sizeof(fastd_method_session_state));
free(session);
}
}
-static void mulH_a(block_t *x, fastd_method_session_state *session) {
- block_t out = {};
-
- int i;
- for (i = 0; i < 16; i++) {
- xor_a(&out, &session->H[2*i][x->b[i]>>4]);
- xor_a(&out, &session->H[2*i+1][x->b[i]&0xf]);
- }
-
- *x = out;
-}
-
-static inline void put_size(block_t *out, size_t len) {
- memset(out, 0, BLOCKBYTES-5);
- out->b[BLOCKBYTES-5] = len >> 29;
- out->b[BLOCKBYTES-4] = len >> 21;
- out->b[BLOCKBYTES-3] = len >> 13;
- out->b[BLOCKBYTES-2] = len >> 5;
- out->b[BLOCKBYTES-1] = len << 3;
-}
-
-static void ghash(fastd_context *ctx, block_t *out, const block_t *blocks, size_t n_blocks, fastd_method_session_state *session) {
- if (session->algfd_ghash >= 0) {
- if (fastd_linux_alg_ghash(ctx, session->algfd_ghash, out->b, blocks, n_blocks*BLOCKBYTES))
- return;
-
- /* on error */
- close(session->algfd_ghash);
- session->algfd_ghash = -1;
- }
-
- memset(out, 0, sizeof(block_t));
-
- int i;
- for (i = 0; i < n_blocks; i++) {
- xor_a(out, &blocks[i]);
- mulH_a(out, session);
- }
+static inline void put_size(fastd_block128 *out, size_t len) {
+ memset(out, 0, sizeof(fastd_block128)-5);
+ out->b[sizeof(fastd_block128)-5] = len >> 29;
+ out->b[sizeof(fastd_block128)-4] = len >> 21;
+ out->b[sizeof(fastd_block128)-3] = len >> 13;
+ out->b[sizeof(fastd_block128)-2] = len >> 5;
+ out->b[sizeof(fastd_block128)-1] = len << 3;
}
static bool method_encrypt(fastd_context *ctx, fastd_peer *peer, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in) {
- fastd_buffer_pull_head(&in, BLOCKBYTES);
- memset(in.data, 0, BLOCKBYTES);
+ fastd_buffer_pull_head(&in, sizeof(fastd_block128));
+ memset(in.data, 0, sizeof(fastd_block128));
- size_t tail_len = alignto(in.len, BLOCKBYTES)-in.len;
- *out = fastd_buffer_alloc(in.len, alignto(NONCEBYTES, 16), BLOCKBYTES+tail_len);
+ size_t tail_len = alignto(in.len, sizeof(fastd_block128))-in.len;
+ *out = fastd_buffer_alloc(in.len, alignto(NONCEBYTES, 16), sizeof(fastd_block128)+tail_len);
if (tail_len)
memset(in.data+in.len, 0, tail_len);
- block_t nonce;
+ fastd_block128 nonce;
memcpy(nonce.b, session->send_nonce, NONCEBYTES);
- memset(nonce.b+NONCEBYTES, 0, crypto_stream_aes128ctr_NONCEBYTES-NONCEBYTES-1);
- nonce.b[crypto_stream_aes128ctr_NONCEBYTES-1] = 1;
+ memset(nonce.b+NONCEBYTES, 0, sizeof(fastd_block128)-NONCEBYTES-1);
+ nonce.b[sizeof(fastd_block128)-1] = 1;
- int n_blocks = (in.len+BLOCKBYTES-1)/BLOCKBYTES;
+ int n_blocks = (in.len+sizeof(fastd_block128)-1)/sizeof(fastd_block128);
- block_t *inblocks = in.data;
- block_t *outblocks = out->data;
+ fastd_block128 *inblocks = in.data;
+ fastd_block128 *outblocks = out->data;
+ fastd_block128 sig;
- aes128ctr(ctx, outblocks, inblocks, n_blocks, &nonce, session);
+ bool ok = ctx->conf->crypto_aes128ctr->crypt(ctx, session->cstate_aes128ctr, outblocks, inblocks, n_blocks*sizeof(fastd_block128), &nonce);
- if (tail_len)
- memset(out->data+out->len, 0, tail_len);
+ if (ok) {
+ if (tail_len)
+ memset(out->data+out->len, 0, tail_len);
+
+ put_size(&outblocks[n_blocks], in.len-sizeof(fastd_block128));
+
+ ok = ctx->conf->crypto_ghash->hash(ctx, session->cstate_ghash, &sig, outblocks+1, n_blocks);
+ }
- put_size(&outblocks[n_blocks], in.len-BLOCKBYTES);
+ if (!ok) {
+ /* restore original buffer */
+ fastd_buffer_push_head(&in, sizeof(fastd_block128));
+ fastd_buffer_free(*out);
+ return false;
+ }
- block_t sig;
- ghash(ctx, &sig, outblocks+1, n_blocks, session);
xor_a(&outblocks[0], &sig);
fastd_buffer_free(in);
@@ -323,16 +217,16 @@ static bool method_encrypt(fastd_context *ctx, fastd_peer *peer, fastd_method_se
}
static bool method_decrypt(fastd_context *ctx, fastd_peer *peer, fastd_method_session_state *session, fastd_buffer *out, fastd_buffer in) {
- if (in.len < NONCEBYTES+BLOCKBYTES)
+ if (in.len < NONCEBYTES+sizeof(fastd_block128))
return false;
if (!method_session_is_valid(ctx, session))
return false;
- block_t nonce;
+ fastd_block128 nonce;
memcpy(nonce.b, in.data, NONCEBYTES);
- memset(nonce.b+NONCEBYTES, 0, crypto_stream_aes128ctr_NONCEBYTES-NONCEBYTES-1);
- nonce.b[crypto_stream_aes128ctr_NONCEBYTES-1] = 1;
+ memset(nonce.b+NONCEBYTES, 0, sizeof(fastd_block128)-NONCEBYTES-1);
+ nonce.b[sizeof(fastd_block128)-1] = 1;
int64_t age;
if (!is_nonce_valid(nonce.b, session->receive_nonce, &age))
@@ -348,25 +242,27 @@ static bool method_decrypt(fastd_context *ctx, fastd_peer *peer, fastd_method_se
fastd_buffer_push_head(&in, NONCEBYTES);
- size_t tail_len = alignto(in.len, BLOCKBYTES)-in.len;
+ size_t tail_len = alignto(in.len, sizeof(fastd_block128))-in.len;
*out = fastd_buffer_alloc(in.len, 0, tail_len);
- int n_blocks = (in.len+BLOCKBYTES-1)/BLOCKBYTES;
+ int n_blocks = (in.len+sizeof(fastd_block128)-1)/sizeof(fastd_block128);
- block_t *inblocks = in.data;
- block_t *outblocks = out->data;
+ fastd_block128 *inblocks = in.data;
+ fastd_block128 *outblocks = out->data;
+ fastd_block128 sig;
- aes128ctr(ctx, outblocks, inblocks, n_blocks, &nonce, session);
+ bool ok = ctx->conf->crypto_aes128ctr->crypt(ctx, session->cstate_aes128ctr, outblocks, inblocks, n_blocks*sizeof(fastd_block128), &nonce);
- if (tail_len)
- memset(in.data+in.len, 0, tail_len);
+ if (ok) {
+ if (tail_len)
+ memset(in.data+in.len, 0, tail_len);
- put_size(&inblocks[n_blocks], in.len-BLOCKBYTES);
+ put_size(&inblocks[n_blocks], in.len-sizeof(fastd_block128));
- block_t sig;
- ghash(ctx, &sig, inblocks+1, n_blocks, session);
+ ok = ctx->conf->crypto_ghash->hash(ctx, session->cstate_ghash, &sig, inblocks+1, n_blocks);
+ }
- if (memcmp(&sig, &outblocks[0], BLOCKBYTES) != 0) {
+ if (!ok || memcmp(&sig, &outblocks[0], sizeof(fastd_block128)) != 0) {
fastd_buffer_free(*out);
/* restore input buffer */
@@ -377,7 +273,7 @@ static bool method_decrypt(fastd_context *ctx, fastd_peer *peer, fastd_method_se
fastd_buffer_free(in);
- fastd_buffer_push_head(out, BLOCKBYTES);
+ fastd_buffer_push_head(out, sizeof(fastd_block128));
if (age < 0) {
session->receive_reorder_seen >>= age;
diff --git a/src/types.h b/src/types.h
index c27a99c..f079d3c 100644
--- a/src/types.h
+++ b/src/types.h
@@ -33,16 +33,14 @@
#ifndef _FASTD_TYPES_H_
#define _FASTD_TYPES_H_
+#include <config.h>
+
+
typedef enum _fastd_mode {
MODE_TAP,
MODE_TUN,
} fastd_mode;
-typedef enum _fastd_alg_impl {
- ALG_IMPL_DEFAULT,
- ALG_IMPL_ALGIF,
-} fastd_alg_impl;
-
typedef struct _fastd_buffer fastd_buffer;
typedef union _fastd_peer_address fastd_peer_address;
@@ -66,12 +64,30 @@ typedef struct _fastd_string_stack fastd_string_stack;
typedef struct _fastd_resolve_return fastd_resolve_return;
+#ifdef USE_CRYPTO_AES128CTR
+typedef struct _fastd_crypto_aes128ctr fastd_crypto_aes128ctr;
+#endif
+#ifdef USE_CRYPTO_GHASH
+typedef struct _fastd_crypto_ghash fastd_crypto_ghash;
+#endif
+
-/* May be defined by the protocol/method however it likes */
+/* May be defined by the protocol/method/crypto implementations however they like */
typedef struct _fastd_protocol_config fastd_protocol_config;
typedef struct _fastd_protocol_state fastd_protocol_state;
typedef struct _fastd_protocol_peer_config fastd_protocol_peer_config;
typedef struct _fastd_protocol_peer_state fastd_protocol_peer_state;
+
typedef struct _fastd_method_session_state fastd_method_session_state;
+#ifdef USE_CRYPTO_AES128CTR
+typedef struct _fastd_crypto_aes128ctr_context fastd_crypto_aes128ctr_context;
+typedef struct _fastd_crypto_aes128ctr_state fastd_crypto_aes128ctr_state;
+#endif
+
+#ifdef USE_CRYPTO_GHASH
+typedef struct _fastd_crypto_ghash_context fastd_crypto_ghash_context;
+typedef struct _fastd_crypto_ghash_state fastd_crypto_ghash_state;
+#endif
+
#endif /* _FASTD_TYPES_H_ */