feb3f22fff
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.
76 lines
2.3 KiB
C
76 lines
2.3 KiB
C
/*
|
|
prf.c -- Pseudo-Random Function for key material generation
|
|
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
|
|
|
|
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);
|
|
}
|