From 2acd81bd7a1b364b02831ae5f8e46457d9d07865 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 21 Sep 2012 15:07:11 +0200 Subject: Nicely encapsulate different crypto algorithm implementations --- CMakeLists.txt | 33 ++++++ config.h.in | 8 ++ src/CMakeLists.txt | 3 +- src/config.c | 81 ++++++++++++--- src/config.l | 2 +- src/config.y | 11 +- src/crypto.c | 200 +++++++++++++++++++++++++++++++++++++ src/crypto.h | 77 ++++++++++++++ src/crypto_linux.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++++ src/fastd.c | 32 +++++- src/fastd.h | 19 +++- src/linux_alg.c | 196 ------------------------------------ src/linux_alg.h | 42 -------- src/method_aes128_gcm.c | 238 +++++++++++++------------------------------- src/types.h | 28 ++++-- 15 files changed, 783 insertions(+), 446 deletions(-) create mode 100644 src/crypto.c create mode 100644 src/crypto.h create mode 100644 src/crypto_linux.c delete mode 100644 src/linux_alg.c delete mode 100644 src/linux_alg.h 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 #include -#include - #include #include #include @@ -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 TOK_ADDR @@ -103,7 +103,6 @@ %code { - #include #include #include @@ -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 + 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 + + +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 + 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 + + +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 + 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 +#include +#include + + +#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 - 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 -#include -#include - - -#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 - 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 #include #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 + + 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_ */ -- cgit v1.2.3