From ed49289d7ba0b56d8d308db0dd110cee6d1d20a9 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 8 Oct 2015 19:17:30 +0200 Subject: [PATCH] Port to libsodium, switch to AES256-GCM, revamp authentication --- auth.c | 97 +++--- auth.h | 2 +- cfg_file.y | 1 + cfg_kwords.h | 13 +- configure.ac | 78 ++--- lfd_encrypt.c | 806 +++++++++----------------------------------------- main.c | 10 + vtun.h | 17 +- vtund.conf | 13 +- vtund.conf.5 | 26 +- 10 files changed, 211 insertions(+), 852 deletions(-) diff --git a/auth.c b/auth.c index d299743..3451bd9 100644 --- a/auth.c +++ b/auth.c @@ -27,6 +27,7 @@ #include "config.h" +#include #include #include #include @@ -56,66 +57,44 @@ #include "auth.h" /* Encryption and Decryption of the challenge key */ -#ifdef HAVE_SSL +#include -#include -#include -#include - -static void gen_chal(char *buf) +static int derive_key(struct vtun_host *host) { - RAND_bytes(buf, VTUN_CHAL_SIZE); + unsigned char salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; + int ret = -1; + + if (host->key != NULL) { + return 0; + } + if ((host->key = sodium_malloc(HOST_KEYBYTES)) == NULL) { + return -1; + } + memset(salt, 0xd1, sizeof salt); + if (crypto_pwhash_scryptsalsa208sha256 + (host->key, HOST_KEYBYTES, host->passwd, strlen(host->passwd), salt, + crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE, + crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) == 0) { + ret = 0; + } + sodium_memzero(host->passwd, strlen(host->passwd)); + free(host->passwd); + host->passwd = NULL; + vtun_syslog(LOG_DEBUG,"Key ready for host %s.", host->host); + + return ret; } -static void encrypt_chal(char *chal, char *pwd) -{ - register int i; - BF_KEY key; - - BF_set_key(&key, 16, MD5(pwd,strlen(pwd),NULL)); - - for(i=0; i < VTUN_CHAL_SIZE; i += 8 ) - BF_ecb_encrypt(chal + i, chal + i, &key, BF_ENCRYPT); -} - -static void decrypt_chal(char *chal, char *pwd) -{ - register int i; - BF_KEY key; - - BF_set_key(&key, 16, MD5(pwd,strlen(pwd),NULL)); - - for(i=0; i < VTUN_CHAL_SIZE; i += 8 ) - BF_ecb_encrypt(chal + i, chal + i, &key, BF_DECRYPT); -} - -#else /* HAVE_SSL */ - -static void encrypt_chal(char *chal, char *pwd) -{ - char * xor_msk = pwd; - register int i, xor_len = strlen(xor_msk); - - for(i=0; i < VTUN_CHAL_SIZE; i++) - chal[i] ^= xor_msk[i%xor_len]; -} - -static void inline decrypt_chal(char *chal, char *pwd) -{ - encrypt_chal(chal, pwd); -} - -/* Generate PSEUDO random challenge key. */ -static void gen_chal(char *buf) +static void gen_chal(char *chal) { - register int i; - - srand(time(NULL)); - - for(i=0; i < VTUN_CHAL_SIZE; i++) - buf[i] = (unsigned int)(255.0 * rand()/RAND_MAX); + randombytes_buf((unsigned char *) chal, VTUN_CHAL_SIZE); +} + +static void auth_chal(char *chal, const struct vtun_host *host) +{ + crypto_generichash(chal, VTUN_CHAL_SIZE, chal, VTUN_CHAL_SIZE, + host->key, HOST_KEYBYTES); } -#endif /* HAVE_SSL */ /* * Functions to convert binary flags to character string. @@ -348,10 +327,10 @@ struct vtun_host * auth_server(int fd) if( !(h = find_host(host)) ) break; - - decrypt_chal(chal_res, h->passwd); + derive_key(h); + auth_chal(chal_req, h); - if( !memcmp(chal_req, chal_res, VTUN_CHAL_SIZE) ){ + if( !sodium_memcmp(chal_req, chal_res, VTUN_CHAL_SIZE) ){ /* Auth successeful. */ /* Lock host */ @@ -400,8 +379,8 @@ int auth_client(int fd, struct vtun_host *host) case ST_HOST: if( !strncmp(buf,"OK",2) && cs2cl(buf,chal)){ stage = ST_CHAL; - - encrypt_chal(chal,host->passwd); + derive_key(host); + auth_chal(chal, host); print_p(fd,"CHAL: %s\n", cl2cs(chal)); continue; diff --git a/auth.h b/auth.h index f810a11..113a935 100644 --- a/auth.h +++ b/auth.h @@ -20,7 +20,7 @@ * $Id: auth.h,v 1.3.2.2 2008/01/07 22:35:19 mtbishop Exp $ */ -#define VTUN_CHAL_SIZE 16 +#define VTUN_CHAL_SIZE 16 #define ST_INIT 0 #define ST_HOST 1 diff --git a/cfg_file.y b/cfg_file.y index bf01e4d..8ac1c86 100644 --- a/cfg_file.y +++ b/cfg_file.y @@ -107,6 +107,7 @@ statement: '\n' memcpy(parse_host, &default_host, sizeof(struct vtun_host)); parse_host->host = strdup($1); parse_host->passwd = NULL; + parse_host->key = NULL; parse_host->sopt.host = strdup($1); /* Copy local address */ diff --git a/cfg_kwords.h b/cfg_kwords.h index 0f14ede..054ef14 100644 --- a/cfg_kwords.h +++ b/cfg_kwords.h @@ -86,17 +86,6 @@ struct kword cfg_param[] = { { "inetd", VTUN_INETD }, { "stand", VTUN_STAND_ALONE }, { "keep", VTUN_PERSIST_KEEPIF }, - { "blowfish128cbc", VTUN_ENC_BF128CBC }, - { "blowfish128cfb", VTUN_ENC_BF128CFB }, - { "blowfish128ofb", VTUN_ENC_BF128OFB }, - { "blowfish256cbc", VTUN_ENC_BF256CBC }, - { "blowfish256cfb", VTUN_ENC_BF256CFB }, - { "blowfish256ofb", VTUN_ENC_BF256OFB }, - { "aes128cbc", VTUN_ENC_AES128CBC }, - { "aes128cfb", VTUN_ENC_AES128CFB }, - { "aes128ofb", VTUN_ENC_AES128OFB }, - { "aes256cbc", VTUN_ENC_AES256CBC }, - { "aes256cfb", VTUN_ENC_AES256CFB }, - { "aes256ofb", VTUN_ENC_AES256OFB }, + { "aes256gcm",VTUN_ENC_AES256GCM }, { NULL , 0 } }; diff --git a/configure.ac b/configure.ac index 86086df..8b1bb44 100644 --- a/configure.ac +++ b/configure.ac @@ -17,10 +17,10 @@ AC_ARG_ENABLE(shaper, SHAPER=yes ) dnl Encryption support -AC_ARG_ENABLE(ssl, - --disable-ssl Don not compile encryption module, - SSL=$enableval, - SSL=yes +AC_ARG_ENABLE(sodium, + --disable-sodium Don not compile encryption module, + SODIUM=$enableval, + SODIUM=yes ) dnl ZLIB support AC_ARG_ENABLE(zlib, @@ -48,13 +48,13 @@ AC_ARG_ENABLE(nathack, NATHACK=yes ) -AC_ARG_WITH(ssl-headers, - --with-ssl-headers=DIR Crypto Include files location, - SSL_HDR_DIR="$withval" +AC_ARG_WITH(sodium-headers, + --with-sodium-headers=DIR Crypto Include files location, + SODIUM_HDR_DIR="$withval" CPPFLAGS="$CPPFLAGS -I$withval" ) -AC_ARG_WITH(ssl-lib, - --with-ssl-lib=DIR Crypto Library location, +AC_ARG_WITH(sodium-lib, + --with-sodium-lib=DIR Crypto Library location, LIBS="$LIBS -L$withval" ) @@ -165,60 +165,16 @@ if test "$LZO" = "yes"; then fi fi -if test "$SSL" = "yes"; then +if test "$SODIUM" = "yes"; then AC_MSG_RESULT() - AC_CHECKING( for md5 Library and Header files ... ) -AC_SEARCH_HEADERS(md5.h, - $SSL_HDR_DIR /usr/include/openssl "" /usr/include /usr/include/ssl /usr/local/include /usr/local/ssl/include /usr/include/sys, + AC_CHECKING( for Sodium Library and Header files ... ) + AC_SEARCH_LIBS(crypto_aead_aes256gcm_aesni_encrypt, [sodium], + [AC_DEFINE(HAVE_SODIUM, [1], [Define to 1 if you have Sodium])], + AC_ERROR([libsodium with crypto_aead_aes256gcm_aesni_encrypt not found])) + AC_SEARCH_HEADERS(sodium.h, + $SSL_HDR_DIR /usr/include /usr/local/include /opt/include, , - AC_MSG_ERROR( SSL headers not found. ) - ) -fi - -if test "$SSL" = "yes"; then - AC_MSG_RESULT() - AC_CHECKING( for blowfish Library and Header files ... ) - AC_SEARCH_HEADERS(blowfish.h, - $BLOWFISH_HDR_DIR /usr/include/ssl /usr/include/openssl /usr/include /usr/local/include /usr/local/ssl/include /usr/include/crypto, - AC_CHECK_LIB(crypto, BF_set_key, - [ - LIBS="$LIBS -lcrypto" - AC_DEFINE(HAVE_SSL, [1], [Define to 1 if you have openssl]) - AC_DEFINE(HAVE_SSL_BLOWFISH, [1], [Define to 1 if you have blowfish in openssl]) - ], - AC_MSG_ERROR( SSL library not found. ) - ), - AC_MSG_ERROR( SSL headers not found. ) - ) -fi - -if test "$SSL" = "yes"; then - AC_MSG_RESULT() - AC_CHECKING( for AES Library and Header files ... ) - AC_SEARCH_HEADERS(aes.h, - $SSL_HDR_DIR /usr/include/ssl /usr/include/openssl /usr/include /usr/local/include /usr/local/ssl/include /usr/include/crypto, - AC_CHECK_LIB(crypto, AES_set_encrypt_key, - [ - AC_DEFINE(HAVE_SSL_AES, [1], [Define to 1 if you have AES in openssl]) - ], - AC_MSG_ERROR( AES library not found. ) - ), - AC_MSG_ERROR( AES headers not found. ) - ) -fi - -if test "$SSL" = "yes"; then - AC_MSG_RESULT() - AC_CHECKING( for EVP Library and Header files ... ) - AC_SEARCH_HEADERS(evp.h, - $SSL_HDR_DIR /usr/include/ssl /usr/include/openssl /usr/include /usr/local/include /usr/local/ssl/include /usr/include/crypto, - AC_CHECK_LIB(crypto, EVP_EncryptInit, - [ - AC_DEFINE(HAVE_SSL_EVP, [1], [Define to 1 if you have EVP in openssl]) - ], - AC_MSG_ERROR( EVP library not found. ) - ), - AC_MSG_ERROR( EVP headers not found. ) + AC_MSG_ERROR( Sodium headers not found. ) ) fi diff --git a/lfd_encrypt.c b/lfd_encrypt.c index 14fabb6..8a92ba9 100644 --- a/lfd_encrypt.c +++ b/lfd_encrypt.c @@ -1,707 +1,172 @@ -/* - VTun - Virtual Tunnel over TCP/IP network. - - Copyright (C) 1998-2008 Maxim Krasnyansky - - VTun has been derived from VPPP package by Maxim Krasnyansky. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - */ - -/* - Encryption module uses software developed by the OpenSSL Project - for use in the OpenSSL Toolkit. (http://www.openssl.org/) - Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. - */ - -/* - * This lfd_encrypt module uses MD5 to create 128 bits encryption - * keys and BlowFish for actual data encryption. - * It is based on code written by Chris Todd with - * several improvements and modifications by me. - */ - -/* - * The current lfd_encrypt module is based on code attributed above and - * uses new code written by Dale Fountain to - * allow multiple ciphers, modes, and key sizes. Feb 2004. - */ - #include "config.h" -#include -#include #include -#include -#include +#include #include +#include #include +#include #include "vtun.h" #include "linkfd.h" -#include "lib.h" -#ifdef HAVE_SSL +#ifdef HAVE_SODIUM +#include -/* OpenSSL includes */ -#include -#include -#include -#include +#define crypto_aead_NPUBBYTES crypto_aead_aes256gcm_NPUBBYTES +#define crypto_aead_ABYTES crypto_aead_aes256gcm_ABYTES +#define crypto_aead_KEYBYTES crypto_aead_aes256gcm_KEYBYTES -/* - * #define LFD_ENCRYPT_DEBUG - */ +#define MESSAGE_MAX_SIZE VTUN_FRAME_SIZE +#define CIPHERTEXT_ABYTES (crypto_aead_ABYTES + crypto_aead_NPUBBYTES) +#define CIPHERTEXT_MAX_SIZE MESSAGE_MAX_SIZE +#define CIPHERTEXT_MAX_TOTAL_SIZE (CIPHERTEXT_MAX_SIZE + CIPHERTEXT_ABYTES) -#define ENC_BUF_SIZE VTUN_FRAME_SIZE + 128 -#define ENC_KEY_SIZE 16 +#define MINIMUM_DATE 1444341043UL +#define SLEEP_WHEN_CLOCK_IS_OFF 10 -static BF_KEY key; -static char * enc_buf; -static char * dec_buf; +typedef struct CryptoCtx { + crypto_aead_aes256gcm_aesni_state *state; + unsigned char *ciphertext; + unsigned char *key; + unsigned char *message; + unsigned char *nonce; + unsigned char *previous_decrypted_nonce; +} CryptoCtx; -#define CIPHER_INIT 0 -#define CIPHER_CODE 1 -#define CIPHER_SEQUENCE 2 -#define CIPHER_REQ_INIT 3 +static CryptoCtx ctx; -static struct vtun_host *phost; - -extern int send_a_packet; - -/* out of sync packet threshold before forcing a re-init */ -#define MAX_GIBBERISH 10 -#define MIN_GIBBERISH 1 -#define MAX_GIBBERISH_TIME 2 -static int gibberish; -static time_t gib_time_start; - -static int cipher_enc_state; -static int cipher_dec_state; -static int cipher; -static int blocksize; -static int keysize; -static int enc_init_first_time; -static int dec_init_first_time; -static unsigned long sequence_num; -static char * pkey; -static char * iv_buf; - -static EVP_CIPHER_CTX ctx_enc; /* encrypt */ -static EVP_CIPHER_CTX ctx_dec; /* decrypt */ - -static EVP_CIPHER_CTX ctx_enc_ecb; /* sideband ecb encrypt */ -static EVP_CIPHER_CTX ctx_dec_ecb; /* sideband ecb decrypt */ - -static int send_msg(int len, char *in, char **out); -static int recv_msg(int len, char *in, char **out); -static int send_ib_mesg(int *len, char **in); -static int recv_ib_mesg(int *len, char **in); - -static int prep_key(char **key, int size, struct vtun_host *host) +static int +derive_key(unsigned char *key, size_t key_size, struct vtun_host *host) { - int tmplen, halflen; - char *hashkey; - - if ( !(hashkey = malloc(size)) ) - { - vtun_syslog(LOG_ERR,"Can't allocate buffer for key hash"); - return -1; - } - memset(hashkey,0,size); - - if (size == 32) - { - tmplen = strlen(host->passwd); - if (tmplen != 0) halflen = tmplen>>1; - else halflen = 0; - MD5(host->passwd, halflen, hashkey); - MD5((host->passwd)+halflen, tmplen-halflen, hashkey+16); - } - else if (size == 16) - { - MD5(host->passwd,strlen(host->passwd), hashkey); - } - else - { - /* don't know what to do */ - free(hashkey); - *key = NULL; - return -1; - } - *key = hashkey; - return 0; + crypto_generichash(key, key_size, host->key, HOST_KEYBYTES, NULL, 0U); + sodium_free(host->key); + host->key = NULL; } -static void free_key (char *key) +static int +init_nonce(unsigned char *nonce, size_t nonce_size) { - free(key); + time_t now; + + if (nonce_size < 5) { + return -1; + } + time(&now); + if (now < MINIMUM_DATE) { + sleep(SLEEP_WHEN_CLOCK_IS_OFF); + randombytes_buf(nonce, nonce_size); + } else { + randombytes_buf(nonce + 4, nonce_size - 4); + now <<= 2; + memcpy(nonce, &now, 3); + nonce[3] = (nonce[3] & 0x3) ^ *(((unsigned char *) &now) + 3); + } + return 0; } -static int alloc_encrypt(struct vtun_host *host) +static int +alloc_encrypt(struct vtun_host *host) { - int sb_init = 0; - int var_key = 0; - const EVP_CIPHER *cipher_type; - char tmpstr[64]; - char cipher_name[32]; - EVP_CIPHER_CTX *pctx_enc; - EVP_CIPHER_CTX *pctx_dec; - - enc_init_first_time = 1; - dec_init_first_time = 1; - - if( !(enc_buf = lfd_alloc(ENC_BUF_SIZE)) ){ - vtun_syslog(LOG_ERR,"Can't allocate buffer for encryptor"); - return -1; - } - if( !(dec_buf = lfd_alloc(ENC_BUF_SIZE)) ){ - vtun_syslog(LOG_ERR,"Can't allocate buffer for decryptor"); - return -1; - } - - RAND_bytes((char *)&sequence_num, 4); - gibberish = 0; - gib_time_start = 0; - phost = host; - cipher = host->cipher; - switch(cipher) - { - case VTUN_ENC_AES128OFB: - case VTUN_ENC_AES128CFB: - case VTUN_ENC_AES128CBC: - blocksize = 16; - keysize = 16; - sb_init=1; - cipher_type = EVP_aes_128_ecb(); - pctx_enc = &ctx_enc_ecb; - pctx_dec = &ctx_dec_ecb; - break; - - case VTUN_ENC_BF256OFB: - case VTUN_ENC_BF256CFB: - case VTUN_ENC_BF256CBC: - blocksize = 8; - keysize = 32; - var_key = 1; - sb_init = 1; - cipher_type = EVP_bf_ecb(); - pctx_enc = &ctx_enc_ecb; - pctx_dec = &ctx_dec_ecb; - break; - - case VTUN_ENC_BF128OFB: - case VTUN_ENC_BF128CFB: - case VTUN_ENC_BF128CBC: - blocksize = 8; - keysize = 16; - var_key = 1; - sb_init = 1; - cipher_type = EVP_bf_ecb(); - pctx_enc = &ctx_enc_ecb; - pctx_dec = &ctx_dec_ecb; - break; - case VTUN_ENC_AES256OFB: - case VTUN_ENC_AES256CFB: - case VTUN_ENC_AES256CBC: - default: - blocksize = 16; - keysize = 32; - sb_init = 1; - cipher_type = EVP_aes_256_ecb(); - pctx_enc = &ctx_enc_ecb; - pctx_dec = &ctx_dec_ecb; - strcpy(cipher_name,"AES-256-CBC"); - } /* switch(host->cipher) */ - - if (prep_key(&pkey, keysize, host) != 0) return -1; - EVP_CIPHER_CTX_init(pctx_enc); - EVP_CIPHER_CTX_init(pctx_dec); - EVP_EncryptInit_ex(pctx_enc, cipher_type, NULL, NULL, NULL); - EVP_DecryptInit_ex(pctx_dec, cipher_type, NULL, NULL, NULL); - if (var_key) - { - EVP_CIPHER_CTX_set_key_length(pctx_enc, keysize); - EVP_CIPHER_CTX_set_key_length(pctx_dec, keysize); - } - EVP_EncryptInit_ex(pctx_enc, NULL, NULL, pkey, NULL); - EVP_DecryptInit_ex(pctx_dec, NULL, NULL, pkey, NULL); - EVP_CIPHER_CTX_set_padding(pctx_enc, 0); - EVP_CIPHER_CTX_set_padding(pctx_dec, 0); - if (sb_init) - { - cipher_enc_state=CIPHER_INIT; - cipher_dec_state=CIPHER_INIT; - } - else - { - cipher_enc_state=CIPHER_CODE; - cipher_dec_state=CIPHER_CODE; - sprintf(tmpstr,"%s encryption initialized", cipher_name); - vtun_syslog(LOG_INFO, tmpstr); - } - return 0; + if (sodium_init() < 0) { + return -1; + } + ctx.state = sodium_malloc(sizeof *ctx.state); + ctx.key = sodium_malloc(crypto_aead_KEYBYTES); + ctx.message = sodium_malloc(MESSAGE_MAX_SIZE); + ctx.ciphertext = sodium_malloc(CIPHERTEXT_MAX_TOTAL_SIZE); + ctx.nonce = sodium_malloc(crypto_aead_NPUBBYTES); + ctx.previous_decrypted_nonce = sodium_malloc(crypto_aead_NPUBBYTES); + if (ctx.state == NULL || ctx.key == NULL || ctx.message == NULL || + ctx.ciphertext == NULL || ctx.ciphertext == NULL || ctx.nonce == NULL || + ctx.previous_decrypted_nonce == NULL) { + abort(); + } + if (init_nonce(ctx.nonce, crypto_aead_NPUBBYTES) != 0) { + return -1; + } + if (derive_key(ctx.key, crypto_aead_KEYBYTES, host) != 0) { + return -1; + } + crypto_aead_aes256gcm_aesni_beforenm(ctx.state, ctx.key); + sodium_free(ctx.key); + ctx.key = NULL; + return 0; } -static int free_encrypt() +static int +free_encrypt(void) { - free_key(pkey); pkey = NULL; + sodium_free(ctx.key); + sodium_free(ctx.message); + sodium_free(ctx.ciphertext); + sodium_free(ctx.nonce); + sodium_free(ctx.previous_decrypted_nonce); - lfd_free(enc_buf); enc_buf = NULL; - lfd_free(dec_buf); dec_buf = NULL; - - EVP_CIPHER_CTX_cleanup(&ctx_enc); - EVP_CIPHER_CTX_cleanup(&ctx_dec); - EVP_CIPHER_CTX_cleanup(&ctx_enc_ecb); - EVP_CIPHER_CTX_cleanup(&ctx_dec_ecb); - - return 0; + return 0; } -static int encrypt_buf(int len, char *in, char **out) -{ - register int pad, p, msg_len; - int outlen; - char *in_ptr, *out_ptr = enc_buf; - - msg_len = send_msg(len, in, out); - in = *out; - in_ptr = in+msg_len; - memcpy(out_ptr,in,msg_len); - out_ptr += msg_len; - - send_ib_mesg(&len, &in_ptr); - if (!len) return 0; - /* ( len % blocksize ) */ - p = (len & (blocksize-1)); pad = blocksize - p; - - memset(in_ptr+len, pad, pad); - outlen=len+pad; - if (pad == blocksize) - RAND_bytes(in_ptr+len, blocksize-1); - EVP_EncryptUpdate(&ctx_enc, out_ptr, &outlen, in_ptr, len+pad); - *out = enc_buf; - - sequence_num++; - - return outlen+msg_len; -} - -static int decrypt_buf(int len, char *in, char **out) +static int +is_lower_or_equal(const unsigned char *a, const unsigned char *b, size_t size) { - register int pad; - char *tmp_ptr, *in_ptr, *out_ptr = dec_buf; - int outlen; - - len = recv_msg(len, in, out); - in = *out; - in_ptr = in; - - outlen=len; - if (!len) return 0; - EVP_DecryptUpdate(&ctx_dec, out_ptr, &outlen, in_ptr, len); - recv_ib_mesg(&outlen, &out_ptr); - if (!outlen) return 0; - tmp_ptr = out_ptr + outlen; tmp_ptr--; - pad = *tmp_ptr; - if (pad < 1 || pad > blocksize) { - vtun_syslog(LOG_INFO, "decrypt_buf: bad pad length"); - return 0; - } - *out = out_ptr; - return outlen - pad; + size_t i; + + for (i = 0U; i < size; i++) { + if (a[i] > b[i]) { + return 0; + } + } + return 1; } -static int cipher_enc_init(char * iv) -{ - int var_key = 0; - const EVP_CIPHER *cipher_type; - char tmpstr[64]; - char cipher_name[32]; +static int +encrypt_buf(int message_len_, char *message_, char ** const ciphertext_p) +{ + const unsigned char *message = (const unsigned char *) message_; + const size_t message_len = (size_t) message_len_; + unsigned long long ciphertext_len; + + if (message_len_ < 0 || message_len > MESSAGE_MAX_SIZE) { + return -1; + } + crypto_aead_aes256gcm_aesni_encrypt_afternm(ctx.ciphertext, &ciphertext_len, + message, message_len, + NULL, 0ULL, + NULL, ctx.nonce, ctx.state); + memcpy(ctx.ciphertext + message_len + crypto_aead_ABYTES, + ctx.nonce, crypto_aead_NPUBBYTES); + sodium_increment(ctx.nonce, crypto_aead_NPUBBYTES); + *ciphertext_p = ctx.ciphertext; - switch(cipher) - { - case VTUN_ENC_AES256OFB: - cipher_type = EVP_aes_256_ofb(); - strcpy(cipher_name, "AES-256-OFB"); - break; - - case VTUN_ENC_AES256CFB: - cipher_type = EVP_aes_256_cfb(); - strcpy(cipher_name, "AES-256-CFB"); - break; - - case VTUN_ENC_AES256CBC: - cipher_type = EVP_aes_256_cbc(); - strcpy(cipher_name, "AES-256-CBC"); - break; - - case VTUN_ENC_AES128OFB: - cipher_type = EVP_aes_128_ofb(); - strcpy(cipher_name, "AES-128-OFB"); - break; - case VTUN_ENC_AES128CFB: - cipher_type = EVP_aes_128_cfb(); - strcpy(cipher_name, "AES-128-CFB"); - break; - case VTUN_ENC_AES128CBC: - cipher_type = EVP_aes_128_cbc(); - strcpy(cipher_name, "AES-128-CBC"); - break; - - case VTUN_ENC_BF256OFB: - var_key = 1; - cipher_type = EVP_bf_ofb(); - strcpy(cipher_name, "Blowfish-256-OFB"); - break; - case VTUN_ENC_BF256CFB: - var_key = 1; - cipher_type = EVP_bf_cfb(); - strcpy(cipher_name, "Blowfish-256-CFB"); - break; - - case VTUN_ENC_BF256CBC: - var_key = 1; - cipher_type = EVP_bf_cbc(); - strcpy(cipher_name, "Blowfish-256-CBC"); - break; - - case VTUN_ENC_BF128OFB: - var_key = 1; - cipher_type = EVP_bf_ofb(); - strcpy(cipher_name, "Blowfish-128-OFB"); - break; - case VTUN_ENC_BF128CFB: - var_key = 1; - cipher_type = EVP_bf_cfb(); - strcpy(cipher_name, "Blowfish-128-CFB"); - break; - case VTUN_ENC_BF128CBC: - var_key = 1; - cipher_type = EVP_bf_cbc(); - strcpy(cipher_name, "Blowfish-128-CBC"); - break; - default: - /* if we're here, something weird's going on */ - return -1; - break; - } /* switch(cipher) */ - - EVP_CIPHER_CTX_init(&ctx_enc); - EVP_EncryptInit_ex(&ctx_enc, cipher_type, NULL, NULL, NULL); - if (var_key) - EVP_CIPHER_CTX_set_key_length(&ctx_enc, keysize); - EVP_EncryptInit_ex(&ctx_enc, NULL, NULL, pkey, NULL); - EVP_EncryptInit_ex(&ctx_enc, NULL, NULL, NULL, iv); - EVP_CIPHER_CTX_set_padding(&ctx_enc, 0); - if (enc_init_first_time) - { - sprintf(tmpstr,"%s encryption initialized", cipher_name); - vtun_syslog(LOG_INFO, tmpstr); - enc_init_first_time = 0; - } - return 0; + return (int) ciphertext_len + crypto_aead_NPUBBYTES; } -static int cipher_dec_init(char * iv) -{ - int var_key = 0; - const EVP_CIPHER *cipher_type; - char tmpstr[64]; - char cipher_name[32]; +static int +decrypt_buf(int ciphertext_len_, char *ciphertext_, char ** const message_p) +{ + const unsigned char *ciphertext = (const unsigned char *) ciphertext_; + const unsigned char *nonce; + size_t ciphertext_len = (size_t) ciphertext_len_; + unsigned long long message_len; + + if (ciphertext_len_ < CIPHERTEXT_ABYTES || + ciphertext_len > CIPHERTEXT_MAX_SIZE) { + return -1; + } + ciphertext_len -= crypto_aead_NPUBBYTES; + nonce = ciphertext + ciphertext_len; + if (is_lower_or_equal(nonce, ctx.previous_decrypted_nonce, crypto_aead_NPUBBYTES) || + crypto_aead_aes256gcm_aesni_decrypt_afternm(ctx.message, &message_len, NULL, + ciphertext, ciphertext_len, + NULL, 0ULL, nonce, ctx.state) != 0) { + return -1; + } + memcpy(ctx.previous_decrypted_nonce, nonce, crypto_aead_NPUBBYTES); + *message_p = ctx.message; - switch(cipher) - { - case VTUN_ENC_AES256OFB: - cipher_type = EVP_aes_256_ofb(); - strcpy(cipher_name, "AES-256-OFB"); - break; - - case VTUN_ENC_AES256CFB: - cipher_type = EVP_aes_256_cfb(); - strcpy(cipher_name, "AES-256-CFB"); - break; - - case VTUN_ENC_AES256CBC: - cipher_type = EVP_aes_256_cbc(); - strcpy(cipher_name, "AES-256-CBC"); - break; - - case VTUN_ENC_AES128OFB: - cipher_type = EVP_aes_128_ofb(); - strcpy(cipher_name, "AES-128-OFB"); - break; - case VTUN_ENC_AES128CFB: - cipher_type = EVP_aes_128_cfb(); - strcpy(cipher_name, "AES-128-CFB"); - break; - case VTUN_ENC_AES128CBC: - cipher_type = EVP_aes_128_cbc(); - strcpy(cipher_name, "AES-128-CBC"); - break; - - case VTUN_ENC_BF256OFB: - var_key = 1; - cipher_type = EVP_bf_ofb(); - strcpy(cipher_name, "Blowfish-256-OFB"); - break; - case VTUN_ENC_BF256CFB: - var_key = 1; - cipher_type = EVP_bf_cfb(); - strcpy(cipher_name, "Blowfish-256-CFB"); - break; - case VTUN_ENC_BF256CBC: - var_key = 1; - cipher_type = EVP_bf_cbc(); - strcpy(cipher_name, "Blowfish-256-CBC"); - break; - - case VTUN_ENC_BF128OFB: - var_key = 1; - cipher_type = EVP_bf_ofb(); - strcpy(cipher_name, "Blowfish-128-OFB"); - break; - case VTUN_ENC_BF128CFB: - var_key = 1; - cipher_type = EVP_bf_cfb(); - strcpy(cipher_name, "Blowfish-128-CFB"); - break; - case VTUN_ENC_BF128CBC: - var_key = 1; - cipher_type = EVP_bf_cbc(); - strcpy(cipher_name, "Blowfish-128-CBC"); - break; - default: - /* if we're here, something weird's going on */ - return -1; - break; - } /* switch(cipher) */ - - EVP_CIPHER_CTX_init(&ctx_dec); - EVP_DecryptInit_ex(&ctx_dec, cipher_type, NULL, NULL, NULL); - if (var_key) - EVP_CIPHER_CTX_set_key_length(&ctx_dec, keysize); - EVP_DecryptInit_ex(&ctx_dec, NULL, NULL, pkey, NULL); - EVP_DecryptInit_ex(&ctx_dec, NULL, NULL, NULL, iv); - EVP_CIPHER_CTX_set_padding(&ctx_dec, 0); - if (dec_init_first_time) - { - sprintf(tmpstr,"%s decryption initialized", cipher_name); - vtun_syslog(LOG_INFO, tmpstr); - dec_init_first_time = 0; - } - return 0; + return (int) message_len; } -static int send_msg(int len, char *in, char **out) -{ - char * iv; char * in_ptr; - int outlen; - - switch(cipher_enc_state) - { - case CIPHER_INIT: - in_ptr = in - blocksize*2; - iv = malloc(blocksize); - RAND_bytes(iv, blocksize); - strncpy(in_ptr,"ivec",4); - in_ptr += 4; - memcpy(in_ptr,iv,blocksize); - in_ptr += blocksize; - cipher_enc_init(iv); - - memset(iv,0,blocksize); free(iv); iv = NULL; - RAND_bytes(in_ptr, in - in_ptr); - - in_ptr = in - blocksize*2; - outlen = blocksize*2; - EVP_EncryptUpdate(&ctx_enc_ecb, in_ptr, - &outlen, in_ptr, blocksize*2); - *out = in_ptr; - len = outlen; - cipher_enc_state = CIPHER_SEQUENCE; - break; - - case CIPHER_CODE: - default: - *out = in; - len = 0; - break; - } - return len; -} - -static int recv_msg(int len, char *in, char **out) -{ - char * iv; char * in_ptr; - int outlen; - - switch(cipher_dec_state) - { - case CIPHER_INIT: - in_ptr = in; - iv = malloc(blocksize); - outlen = blocksize*2; - EVP_DecryptUpdate(&ctx_dec_ecb, in_ptr, &outlen, in_ptr, blocksize*2); - - if ( !strncmp(in_ptr, "ivec", 4) ) - { - memcpy(iv, in_ptr+4, blocksize); - cipher_dec_init(iv); - - *out = in_ptr + blocksize*2; - len -= blocksize*2; - cipher_dec_state = CIPHER_SEQUENCE; - gibberish = 0; - gib_time_start = 0; - } - else - { - len = 0; - *out = in; - gibberish++; - if (gibberish == 1) gib_time_start = time(NULL); - - if (gibberish == MIN_GIBBERISH) - { - cipher_enc_state = CIPHER_REQ_INIT; - send_a_packet = 1; -#ifdef LFD_ENCRYPT_DEBUG - vtun_syslog(LOG_INFO, - "Min. gibberish threshold reached"); -#endif - } - if (gibberish >= MAX_GIBBERISH || - difftime(time(NULL), gib_time_start) >= MAX_GIBBERISH_TIME) - { - gibberish = 0; - gib_time_start = 0; - send_a_packet = 1; - -#ifdef LFD_ENCRYPT_DEBUG - vtun_syslog(LOG_INFO, - "Max. gibberish threshold reached"); -#endif - if (cipher_enc_state != CIPHER_INIT) - { - cipher_enc_state = CIPHER_INIT; - EVP_CIPHER_CTX_cleanup(&ctx_enc); -#ifdef LFD_ENCRYPT_DEBUG - vtun_syslog(LOG_INFO, - "Forcing local encryptor re-init"); -#endif - } - } - } - memset(iv,0,blocksize); free(iv); iv = NULL; - memset(in_ptr,0,blocksize*2); - break; - - case CIPHER_CODE: - default: - *out = in; - break; - } - return len; -} - -/* Send In-Band Message */ -static int send_ib_mesg(int *len, char **in) -{ - char *in_ptr = *in; - - /* To simplify matters, I assume that blocksize - will not be less than 8 bytes */ - if (cipher_enc_state == CIPHER_SEQUENCE) - { - in_ptr -= blocksize; - memset(in_ptr,0,blocksize); - strncpy(in_ptr,"seq#",4); - in_ptr+=4; - *((unsigned long *)in_ptr) = htonl(sequence_num); - in_ptr-=4; - - *in = in_ptr; - *len += blocksize; - } - else if (cipher_enc_state == CIPHER_REQ_INIT) - { - in_ptr -= blocksize; - memset(in_ptr,0,blocksize); - strncpy(in_ptr,"rsyn",4); - in_ptr+=4; - *((unsigned long *)in_ptr) = htonl(sequence_num); - in_ptr-=4; - - *in = in_ptr; - *len += blocksize; -#ifdef LFD_ENCRYPT_DEBUG - vtun_syslog(LOG_INFO, "Requesting remote encryptor re-init"); -#endif - cipher_enc_state = CIPHER_SEQUENCE; - send_a_packet = 1; - } - return 0; -} - -/* Receive In-Band Message */ -static int recv_ib_mesg(int *len, char **in) -{ - char *in_ptr = *in; - - if (cipher_dec_state == CIPHER_SEQUENCE) - { - /* To simplify matters, I assume that blocksize - will not be less than 8 bytes */ - if ( !strncmp(in_ptr, "seq#", 4) ) - { - *in += blocksize; - *len -= blocksize; - } - else if ( !strncmp(in_ptr, "rsyn", 4) ) - { - *in += blocksize; - *len -= blocksize; - - if (cipher_enc_state != CIPHER_INIT) - { - cipher_enc_state = CIPHER_INIT; - EVP_CIPHER_CTX_cleanup(&ctx_enc); - } -#ifdef LFD_ENCRYPT_DEBUG - vtun_syslog(LOG_INFO, "Remote requests encryptor re-init"); -#endif - } - else - { - *len = 0; - - if (cipher_dec_state != CIPHER_INIT && - cipher_enc_state != CIPHER_REQ_INIT && - cipher_enc_state != CIPHER_INIT) - { - EVP_CIPHER_CTX_cleanup (&ctx_dec); - cipher_dec_state = CIPHER_INIT; - cipher_enc_state = CIPHER_REQ_INIT; - } -#ifdef LFD_ENCRYPT_DEBUG - vtun_syslog(LOG_INFO, "Local decryptor out of sync"); -#endif - } - } - return 0; -} -/* - * Module structure. - */ struct lfd_mod lfd_encrypt = { "Encryptor", alloc_encrypt, @@ -714,9 +179,10 @@ struct lfd_mod lfd_encrypt = { NULL }; -#else /* HAVE_SSL */ +#else /* HAVE_SODIUM */ -static int no_encrypt(struct vtun_host *host) +static int +no_encrypt(struct vtun_host *host) { vtun_syslog(LOG_INFO, "Encryption is not supported"); return -1; @@ -727,4 +193,4 @@ struct lfd_mod lfd_encrypt = { no_encrypt, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#endif /* HAVE_SSL */ +#endif diff --git a/main.c b/main.c index ba1c896..d878682 100644 --- a/main.c +++ b/main.c @@ -35,6 +35,10 @@ #include #endif +#ifdef HAVE_SODIUM +#include +#endif + #include "vtun.h" #include "lib.h" #include "compat.h" @@ -193,6 +197,12 @@ int main(int argc, char *argv[], char *env[]) #endif break; } + +#ifdef HAVE_SODIUM + if (sodium_init() != 0) { + abort(); + } +#endif if( daemon ){ #ifdef HAVE_WORKING_FORK diff --git a/vtun.h b/vtun.h index fc7e565..bca56b4 100644 --- a/vtun.h +++ b/vtun.h @@ -82,9 +82,12 @@ struct vtun_addr { #define VTUN_ADDR_IFACE 0x01 #define VTUN_ADDR_NAME 0x02 +#define HOST_KEYBYTES 32 + struct vtun_host { char *host; char *passwd; + unsigned char *key; char *dev; llist up; @@ -138,19 +141,7 @@ extern llist host_list; #define VTUN_ENCRYPT 0x0008 /* Cipher options */ -#define VTUN_ENC_BF128CBC 2 -#define VTUN_ENC_BF128CFB 3 -#define VTUN_ENC_BF128OFB 4 -#define VTUN_ENC_BF256CBC 6 -#define VTUN_ENC_BF256CFB 7 -#define VTUN_ENC_BF256OFB 8 - -#define VTUN_ENC_AES128CBC 10 -#define VTUN_ENC_AES128CFB 11 -#define VTUN_ENC_AES128OFB 12 -#define VTUN_ENC_AES256CBC 14 -#define VTUN_ENC_AES256CFB 15 -#define VTUN_ENC_AES256OFB 16 +#define VTUN_ENC_AES256GCM 17 /* Mask to drop the flags which will be supplied by the server */ #define VTUN_CLNT_MASK 0xf000 diff --git a/vtund.conf b/vtund.conf index 3b5baeb..478aeed 100644 --- a/vtund.conf +++ b/vtund.conf @@ -150,18 +150,7 @@ # ----------- # encrypt - Enable 'yes' or disable 'no' encryption. # It is also possible to specify a method: -# 'blowfish128cbc' - Blowfish cipher, 128 bit key, mode CBC -# 'blowfish128cfb' - Blowfish cipher, 128 bit key, mode CFB -# 'blowfish128ofb' - Blowfish cipher, 128 bit key, mode OFB -# 'blowfish256cbc' - Blowfish cipher, 256 bit key, mode CBC -# 'blowfish256cfb' - Blowfish cipher, 256 bit key, mode CFB -# 'blowfish256ofb' - Blowfish cipher, 256 bit key, mode OFB -# 'aes128cbc' - AES cipher, 128 bit key, mode CBC -# 'aes128cfb' - AES cipher, 128 bit key, mode CFB -# 'aes128ofb' - AES cipher, 128 bit key, mode OFB -# 'aes256cbc' - AES cipher, 256 bit key, mode CBC -# 'aes256cfb' - AES cipher, 256 bit key, mode CFB -# 'aes256ofb' - AES cipher, 256 bit key, mode OFB +# 'aes256gcm' - AES cipher, 256 bit key, mode GCM # # Ignored by the client. # diff --git a/vtund.conf.5 b/vtund.conf.5 index a97fe0c..b7d4dbc 100644 --- a/vtund.conf.5 +++ b/vtund.conf.5 @@ -199,30 +199,8 @@ specifies encryption method to use. Encryption \fImethod\fRs include: no encryption .IP \fByes\fR default encryption method -.IP \fBblowfish128cbc\fR -Blowfish cipher, 128 bit key, mode CBC -.IP \fBblowfish128cfb\fR -Blowfish cipher, 128 bit key, mode CFB -.IP \fBblowfish128ofb\fR -Blowfish cipher, 128 bit key, mode OFB -.IP \fBblowfish256cbc\fR -Blowfish cipher, 256 bit key, mode CBC -.IP \fBblowfish256cfb\fR -Blowfish cipher, 256 bit key, mode CFB -.IP \fBblowfish256ofb\fR -Blowfish cipher, 256 bit key, mode OFB -.IP \fBaes128cbc\fR -AES cipher, 128 bit key, mode CBC -.IP \fBaes128cfb\fR -AES cipher, 128 bit key, mode CFB -.IP \fBaes128ofb\fR -AES cipher, 128 bit key, mode OFB -.IP \fBaes256cbc\fR -AES cipher, 256 bit key, mode CBC -.IP \fBaes256cfb\fR -AES cipher, 256 bit key, mode CFB -.IP \fBaes256ofb\fR -AES cipher, 256 bit key, mode OFB +.IP \fBaes256gcm\fR +AES cipher, 256 bit key, mode GCM .RE .IP This option is ignored by the client.