* tunnel endpoints. It has less protocol overhead than IPSec in Tunnel
* mode and allows tunneling of every ETHER TYPE protocol (e.g.
* ethernet, ip, arp ...). satp directly includes cryptography and
- * message authentication based on the methodes used by SRTP. It is
+ * message authentication based on the methods used by SRTP. It is
* intended to deliver a generic, scaleable and secure solution for
* tunneling and relaying of packets of any protocol.
- *
*
- * Copyright (C) 2007-2008 Christian Pointner <equinox@anytun.org>
+ *
+ * Copyright (C) 2007-2014 Christian Pointner <equinox@anytun.org>
*
* This file is part of uAnytun.
*
* uAnytun is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
*
* uAnytun is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
*
* You should have received a copy of the GNU General Public License
* along with uAnytun. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
*/
#include "datatypes.h"
#include "key_derivation.h"
-#ifdef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+#include <openssl/crypto.h>
#include <openssl/sha.h>
+#include <openssl/modes.h>
+#elif defined(USE_NETTLE)
+#include <nettle/sha1.h>
+#include <nettle/sha2.h>
+#include <nettle/ctr.h>
#endif
#include "log.h"
int key_derivation_init(key_derivation_t* kd, const char* type, role_t role, const char* passphrase, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len)
{
- if(!kd)
+ if(!kd)
return -1;
kd->role_ = role;
if(type[7] == 0) {
kd->key_length_ = KD_AESCTR_DEFAULT_KEY_LENGTH;
}
- else if(type[7] != '-')
+ else if(type[7] != '-')
return -1;
else {
const char* tmp = &type[8];
if(kd->master_key_.buf_) {
log_printf(WARNING, "master key and passphrase provided, ignoring passphrase");
return 0;
- }
+ }
log_printf(NOTICE, "using passphrase to generate master key");
if(!key_length || (key_length % 8)) {
return -1;
}
-#ifndef USE_SSL_CRYPTO
- if(key_length > (gcry_md_get_algo_dlen(GCRY_MD_SHA256) * 8)) {
-#else
+#if defined(USE_SSL_CRYPTO)
if(key_length > (SHA256_DIGEST_LENGTH * 8)) {
+#elif defined(USE_NETTLE)
+ if(key_length > (SHA256_DIGEST_SIZE * 8)) {
+#else // USE_GCRYPT is the default
+ if(key_length > (gcry_md_get_algo_dlen(GCRY_MD_SHA256) * 8)) {
#endif
log_printf(ERROR, "master key too long for passphrase algorithm");
return -1;
}
buffer_t digest;
-#ifndef USE_SSL_CRYPTO
- digest.length_ = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
-#else
+#if defined(USE_SSL_CRYPTO)
digest.length_ = SHA256_DIGEST_LENGTH;
+#elif defined(USE_NETTLE)
+ digest.length_ = SHA256_DIGEST_SIZE;
+#else // USE_GCRYPT is the default
+ digest.length_ = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
#endif
digest.buf_ = malloc(digest.length_);
if(!digest.buf_)
return -2;
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+ SHA256((const u_int8_t*)passphrase, strlen(passphrase), digest.buf_);
+#elif defined(USE_NETTLE)
+ struct sha256_ctx ctx;
+ sha256_init(&ctx);
+ sha256_update(&ctx, strlen(passphrase), (const u_int8_t*)passphrase);
+ sha256_digest(&ctx, digest.length_, digest.buf_);
+#else // USE_GCRYPT is the default
gcry_md_hash_buffer(GCRY_MD_SHA256, digest.buf_, passphrase, strlen(passphrase));
-#else
- SHA256(passphrase, strlen(passphrase), digest.buf_);
#endif
kd->master_key_.length_ = key_length/8;
if(kd->master_salt_.buf_) {
log_printf(WARNING, "master salt and passphrase provided, ignoring passphrase");
return 0;
- }
+ }
log_printf(NOTICE, "using passphrase to generate master salt");
if(!salt_length || (salt_length % 8)) {
return -1;
}
-#ifndef USE_SSL_CRYPTO
- if(salt_length > (gcry_md_get_algo_dlen(GCRY_MD_SHA1) * 8)) {
-#else
+#if defined(USE_SSL_CRYPTO)
if(salt_length > (SHA_DIGEST_LENGTH * 8)) {
+#elif defined(USE_NETTLE)
+ if(salt_length > (SHA1_DIGEST_SIZE * 8)) {
+#else // USE_GCRYPT is the default
+ if(salt_length > (gcry_md_get_algo_dlen(GCRY_MD_SHA1) * 8)) {
#endif
log_printf(ERROR, "master salt too long for passphrase algorithm");
return -1;
}
buffer_t digest;
-#ifndef USE_SSL_CRYPTO
- digest.length_ = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
-#else
+#if defined(USE_SSL_CRYPTO)
digest.length_ = SHA_DIGEST_LENGTH;
+#elif defined(USE_NETTLE)
+ digest.length_ = SHA1_DIGEST_SIZE;
+#else // USE_GCRYPT is the default
+ digest.length_ = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
#endif
digest.buf_ = malloc(digest.length_);
if(!digest.buf_)
return -2;
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+ SHA1((const u_int8_t*)passphrase, strlen(passphrase), digest.buf_);
+#elif defined(USE_NETTLE)
+ struct sha1_ctx ctx;
+ sha1_init(&ctx);
+ sha1_update(&ctx, strlen(passphrase), (const u_int8_t*)passphrase);
+ sha1_digest(&ctx, digest.length_, digest.buf_);
+#else // USE_GCRYPT is the default
gcry_md_hash_buffer(GCRY_MD_SHA1, digest.buf_, passphrase, strlen(passphrase));
-#else
- SHA1(passphrase, strlen(passphrase), digest.buf_);
#endif
kd->master_salt_.length_ = salt_length/8;
int key_derivation_generate(key_derivation_t* kd, key_derivation_dir_t dir, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len)
{
- if(!kd || !key)
+ if(!kd || !key)
return -1;
if(label >= LABEL_NIL) {
return -2;
key_derivation_aesctr_param_t* params = kd->params_;
-#ifndef USE_SSL_CRYPTO
+#ifdef USE_GCRYPT
params->handle_ = 0;
#endif
}
#endif
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+ int ret = AES_set_encrypt_key(kd->master_key_.buf_, kd->master_key_.length_*8, ¶ms->aes_key_);
+ if(ret) {
+ log_printf(ERROR, "failed to set key derivation ssl aes-key (code: %d)", ret);
+ return -1;
+ }
+#elif defined(USE_NETTLE)
+ aes_set_encrypt_key(¶ms->ctx_, kd->master_key_.length_, kd->master_key_.buf_);
+#else // USE_GCRYPT is the default
int algo;
switch(kd->key_length_) {
case 128: algo = GCRY_CIPHER_AES128; break;
if(err) {
log_printf(ERROR, "failed to open key derivation cipher: %s", gcry_strerror(err));
return -1;
- }
+ }
err = gcry_cipher_setkey(params->handle_, kd->master_key_.buf_, kd->master_key_.length_);
if(err) {
log_printf(ERROR, "failed to set key derivation key: %s", gcry_strerror(err));
return -1;
}
-#else
- int ret = AES_set_encrypt_key(kd->master_key_.buf_, kd->master_key_.length_*8, ¶ms->aes_key_);
- if(ret) {
- log_printf(ERROR, "failed to set key derivation ssl aes-key (code: %d)", ret);
- return -1;
- }
#endif
return 0;
return;
if(kd->params_) {
+#ifdef USE_GCRYPT
key_derivation_aesctr_param_t* params = kd->params_;
-
-#ifndef USE_SSL_CRYPTO
if(params->handle_)
gcry_cipher_close(params->handle_);
#endif
return -1;
}
-#ifndef USE_SSL_CRYPTO
+#if defined(USE_SSL_CRYPTO)
+ if(KD_AESCTR_CTR_LENGTH != AES_BLOCK_SIZE) {
+ log_printf(ERROR, "failed to set key derivation CTR: size doesn't fit");
+ return -1;
+ }
+ u_int32_t num = 0;
+ memset(key, 0, len);
+ memset(params->ecount_buf_, 0, AES_BLOCK_SIZE);
+ CRYPTO_ctr128_encrypt(key, key, len, ¶ms->aes_key_, params->ctr_.buf_, params->ecount_buf_, &num, (block128_f)AES_encrypt);
+#elif defined(USE_NETTLE)
+ if(KD_AESCTR_CTR_LENGTH != AES_BLOCK_SIZE) {
+ log_printf(ERROR, "failed to set cipher CTR: size doesn't fit");
+ return -1;
+ }
+ memset(key, 0, len);
+ ctr_crypt(¶ms->ctx_, (nettle_crypt_func *)(aes_encrypt), AES_BLOCK_SIZE, params->ctr_.buf_, len, key, key);
+#else // USE_GCRYPT is the default
gcry_error_t err = gcry_cipher_reset(params->handle_);
if(err) {
log_printf(ERROR, "failed to reset key derivation cipher: %s", gcry_strerror(err));
log_printf(ERROR, "failed to generate key derivation bitstream: %s", gcry_strerror(err));
return -1;
}
-#else
- if(KD_AESCTR_CTR_LENGTH != AES_BLOCK_SIZE) {
- log_printf(ERROR, "failed to set key derivation CTR: size don't fits");
- return -1;
- }
- u_int32_t num = 0;
- memset(params->ecount_buf_, 0, AES_BLOCK_SIZE);
- memset(key, 0, len);
- AES_ctr128_encrypt(key, key, len, ¶ms->aes_key_, params->ctr_.buf_, params->ecount_buf_, &num);
#endif
-
+
return 0;
}