From feb3f22fffa2620b9b11a509ce51ff9fa3be9418 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 3 Jul 2011 15:26:58 +0200 Subject: [PATCH] Add PRF to derive key material from the ECDH shared secret. It is modelled after the pseudorandom function from RFC4346 (TLS 1.1), the only significant change is the use of SHA512 and Whirlpool instead of MD5 and SHA1. --- src/Makefile.am | 4 +-- src/openssl/prf.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++ src/openssl/prf.h | 25 ++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/openssl/prf.c create mode 100644 src/openssl/prf.h diff --git a/src/Makefile.am b/src/Makefile.am index f7876907..a7c56c8a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,7 +11,7 @@ tincd_SOURCES = \ protocol_key.c protocol_subnet.c route.c subnet.c tincd.c nodist_tincd_SOURCES = \ - device.c cipher.c crypto.c ecdh.c digest.c rsa.c + device.c cipher.c crypto.c ecdh.c digest.c prf.c rsa.c tincctl_SOURCES = \ utils.c getopt.c getopt1.c dropin.c \ @@ -32,7 +32,7 @@ INCLUDES = @INCLUDES@ -I$(top_builddir) noinst_HEADERS = \ xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \ - buffer.h cipher.h conf.h connection.h control.h control_common.h crypto.h device.h ecdh.h digest.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h \ + buffer.h cipher.h conf.h connection.h control.h control_common.h crypto.h device.h ecdh.h digest.h edge.h graph.h logger.h meta.h net.h netutl.h node.h prf.h process.h \ protocol.h route.h rsa.h rsagen.h subnet.h tincctl.h top.h bsd/tunemu.h LIBS = @LIBS@ @LIBGCRYPT_LIBS@ diff --git a/src/openssl/prf.c b/src/openssl/prf.c new file mode 100644 index 00000000..2830d609 --- /dev/null +++ b/src/openssl/prf.c @@ -0,0 +1,76 @@ +/* + prf.c -- Pseudo-Random Function for key material generation + Copyright (C) 2011 Guus Sliepen + + 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. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "system.h" + +#include "digest.h" +#include "prf.h" + +/* Generate key material from a master secret and a seed, based on RFC 2246. + We use SHA512 and Whirlpool instead of MD5 and SHA1. + */ + +static bool prf_xor(int nid, char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, ssize_t outlen) { + digest_t digest; + + if(!digest_open_by_nid(&digest, nid, 0)) + return false; + + if(!digest_set_key(&digest, secret, secretlen)) + return false; + + size_t len = digest_length(&digest); + + /* Data is what the "inner" HMAC function processes. + It consists of the previous HMAC result plus the seed. + */ + + char data[len + seedlen]; + memset(data, 0, len); + memcpy(data + len, seed, seedlen); + + char hash[len]; + + while(outlen > 0) { + /* Inner HMAC */ + digest_create(&digest, data, len + seedlen, data); + + /* Outer HMAC */ + digest_create(&digest, data, len + seedlen, hash); + + /* XOR the results of the outer HMAC into the out buffer */ + for(int i = 0; i < len && i < outlen; i++) + *out++ ^= hash[i]; + + outlen -= len; + } + + digest_close(&digest); + return true; +} + +bool prf(char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) { + /* Split secret in half, generate outlen bits with two different hash algorithms, + and XOR the results. */ + + memset(out, 0, outlen); + + return prf_xor(NID_sha512, secret, secretlen / 2, seed, seedlen, out, outlen) + && prf_xor(NID_whirlpool, secret, secretlen / 2, seed, seedlen, out, outlen); +} diff --git a/src/openssl/prf.h b/src/openssl/prf.h new file mode 100644 index 00000000..264d1980 --- /dev/null +++ b/src/openssl/prf.h @@ -0,0 +1,25 @@ +/* + prf.h -- header file for prf.c + Copyright (C) 2011 Guus Sliepen + + 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. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef __TINC_PRF_H__ +#define __TINC_PRF_H__ + +extern bool prf(char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen); + +#endif -- 2.20.1