diff options
Diffstat (limited to 'src/auth_algo.c')
-rw-r--r-- | src/auth_algo.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/src/auth_algo.c b/src/auth_algo.c new file mode 100644 index 0000000..4f91338 --- /dev/null +++ b/src/auth_algo.c @@ -0,0 +1,245 @@ +/* + * ľAnytun + * + * ľAnytun is a tiny implementation of SATP. Unlike Anytun which is a full + * featured implementation ľAnytun has no support for multiple connections + * or synchronisation. It is a small single threaded implementation intended + * to act as a client on small platforms. + * The secure anycast tunneling protocol (satp) defines a protocol used + * for communication between any combination of unicast and anycast + * 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 + * 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> + * + * This file is part of ľAnytun. + * + * ľAnytun 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. + * + * ľAnytun 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. + * + * You should have received a copy of the GNU General Public License + * along with ľAnytun. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "datatypes.h" + +#include "encrypted_packet.h" + +#include "auth_algo.h" + +#include "log.h" + +#include <stdlib.h> +#include <string.h> + +int auth_algo_init(auth_algo_t* aa, const char* type) +{ + if(!aa) + return -1; + + aa->type_ = aa_unknown; + if(!strcmp(type, "null")) + aa->type_ = aa_null; + else if(!strcmp(type, "sha1")) + aa->type_ = aa_sha1; + else { + log_printf(ERR, "unknown auth algo type"); + return -1; + } + + aa->handle_ = 0; + + aa->key_.buf_ = NULL; + aa->key_.length_ = 0; + + int ret = 0; + if(aa->type_ == aa_sha1) + ret = auth_algo_sha1_init(aa); + + if(ret) + auth_algo_close(aa); + + return ret; +} + +void auth_algo_close(auth_algo_t* aa) +{ + if(!aa) + return; + + if(aa->type_ == aa_sha1) + auth_algo_sha1_close(aa); + + if(aa->key_.buf_) + free(aa->key_.buf_); +} + +void auth_algo_generate(auth_algo_t* aa, key_derivation_t* kd, encrypted_packet_t* packet) +{ + if(!aa) + return; + + u_int32_t len; + if(aa->type_ == aa_null) + return; + else if(aa->type_ == aa_sha1) + auth_algo_sha1_generate(aa, kd, packet); + else { + log_printf(ERR, "unknown auth algo type"); + return; + } +} + +int auth_algo_check_tag(auth_algo_t* aa, key_derivation_t* kd, encrypted_packet_t* packet) +{ + if(!aa) + return; + + u_int32_t len; + if(aa->type_ == aa_null) + return 1; + else if(aa->type_ == aa_sha1) + return auth_algo_sha1_check_tag(aa, kd, packet); + else { + log_printf(ERR, "unknown auth algo type"); + return; + } +} + +/* ---------------- HMAC Sha1 Auth Algo ---------------- */ + +int auth_algo_sha1_init(auth_algo_t* aa) +{ + if(!aa) + return -1; + + gcry_error_t err = gcry_md_open(&aa->handle_, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); + if(err) { + log_printf(ERR, "failed to open message digest algo: %s/%s", gcry_strerror(err), gcry_strsource(err)); + return -1; + } + + return 0; +} + +void auth_algo_sha1_close(auth_algo_t* aa) +{ + if(!aa) + return; + + if(aa->handle_) + gcry_md_close(aa->handle_); +} + + +void auth_algo_sha1_generate(auth_algo_t* aa, key_derivation_t* kd, encrypted_packet_t* packet) +{ + if(!aa) { + log_printf(ERR, "auth algo not initialized"); + return; + } + if(!kd) { + log_printf(ERR, "no key derivation supplied"); + return; + } + + + if(!aa->key_.buf_) { + aa->key_.length_ = SHA1_LENGTH; + aa->key_.buf_ = malloc(aa->key_.length_); + if(!aa->key_.buf_) { + log_printf(ERR, "memory error at auth algo generate"); + return; + } + } + + int ret = key_derivation_generate(kd, LABEL_SATP_MSG_AUTH, encrypted_packet_get_seq_nr(packet), aa->key_.buf_, aa->key_.length_); + if(ret < 0) + return; + gcry_error_t err = gcry_md_setkey(aa->handle_, aa->key_.buf_, aa->key_.length_); + if(err) { + log_printf(ERR, "failed to set hmac key: %s/%s", gcry_strerror(err), gcry_strsource(err)); + return; + } + + encrypted_packet_add_auth_tag(packet); + + gcry_md_reset(aa->handle_); + + gcry_md_write(aa->handle_, encrypted_packet_get_auth_portion(packet), encrypted_packet_get_auth_portion_length(packet)); + gcry_md_final(aa->handle_); + + u_int8_t* tag = encrypted_packet_get_auth_tag(packet); + u_int8_t* hmac = gcry_md_read(aa->handle_, 0); + u_int32_t length = (encrypted_packet_get_auth_tag_length(packet) < SHA1_LENGTH) ? encrypted_packet_get_auth_tag_length(packet) : SHA1_LENGTH; + + if(length > SHA1_LENGTH) + memset(tag, 0, encrypted_packet_get_auth_tag_length(packet)); + + memcpy(&tag[encrypted_packet_get_auth_tag_length(packet) - length], &hmac[SHA1_LENGTH - length], length); +} + + +int auth_algo_sha1_check_tag(auth_algo_t* aa, key_derivation_t* kd, encrypted_packet_t* packet) +{ + if(!aa) { + log_printf(ERR, "auth algo not initialized"); + return 0; + } + if(!kd) { + log_printf(ERR, "no key derivation supplied"); + return 0; + } + + if(!aa->key_.buf_) { + aa->key_.length_ = SHA1_LENGTH; + aa->key_.buf_ = malloc(aa->key_.length_); + if(!aa->key_.buf_) { + log_printf(ERR, "memory error at auth algo check tag"); + return; + } + } + + int ret = key_derivation_generate(kd, LABEL_SATP_MSG_AUTH, encrypted_packet_get_seq_nr(packet), aa->key_.buf_, aa->key_.length_); + if(ret < 0) + return 0; + gcry_error_t err = gcry_md_setkey(aa->handle_, aa->key_.buf_, aa->key_.length_); + if(err) { + log_printf(ERR, "failed to set hmac key: %s/%s", gcry_strerror(err), gcry_strsource(err)); + return; + } + + gcry_md_reset(aa->handle_); + + gcry_md_write(aa->handle_, encrypted_packet_get_auth_portion(packet), encrypted_packet_get_auth_portion_length(packet)); + gcry_md_final(aa->handle_); + + u_int8_t* tag = encrypted_packet_get_auth_tag(packet); + u_int8_t* hmac = gcry_md_read(aa->handle_, 0); + u_int32_t length = (encrypted_packet_get_auth_tag_length(packet) < SHA1_LENGTH) ? encrypted_packet_get_auth_tag_length(packet) : SHA1_LENGTH; + + if(length > SHA1_LENGTH) { + u_int32_t i; + for(i=0; i < (encrypted_packet_get_auth_tag_length(packet) - SHA1_LENGTH); ++i) + if(tag[i]) return 0; + } + + int result = memcmp(&tag[encrypted_packet_get_auth_tag_length(packet) - length], &hmac[SHA1_LENGTH - length], length); + encrypted_packet_remove_auth_tag(packet); + + if(result) + return 0; + + return 1; +} |