/* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * * 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. See . * * 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. */ #include #include "prf_plus.h" typedef struct private_prf_plus_t private_prf_plus_t; /** * Private data of an prf_plus_t object. * */ struct private_prf_plus_t { /** * Public interface of prf_plus_t. */ prf_plus_t public; /** * PRF to use. */ prf_t *prf; /** * Initial seed. */ chunk_t seed; /** * Octet which will be appended to the seed, 0 if not used */ u_int8_t counter; /** * Already given out bytes in current buffer. */ size_t used; /** * Buffer to store current PRF result. */ chunk_t buffer; }; METHOD(prf_plus_t, get_bytes, void, private_prf_plus_t *this, size_t length, u_int8_t *buffer) { size_t round, written = 0; while (length > 0) { if (this->buffer.len == this->used) { /* buffer used, get next round */ this->prf->get_bytes(this->prf, this->buffer, NULL); if (this->counter) { this->prf->get_bytes(this->prf, this->seed, NULL); this->prf->get_bytes(this->prf, chunk_from_thing(this->counter), this->buffer.ptr); this->counter++; } else { this->prf->get_bytes(this->prf, this->seed, this->buffer.ptr); } this->used = 0; } round = min(length, this->buffer.len - this->used); memcpy(buffer + written, this->buffer.ptr + this->used, round); length -= round; this->used += round; written += round; } } METHOD(prf_plus_t, allocate_bytes, void, private_prf_plus_t *this, size_t length, chunk_t *chunk) { if (length) { *chunk = chunk_alloc(length); get_bytes(this, length, chunk->ptr); } else { *chunk = chunk_empty; } } METHOD(prf_plus_t, destroy, void, private_prf_plus_t *this) { free(this->buffer.ptr); free(this->seed.ptr); free(this); } /* * Description in header. */ prf_plus_t *prf_plus_create(prf_t *prf, bool counter, chunk_t seed) { private_prf_plus_t *this; INIT(this, .public = { .get_bytes = _get_bytes, .allocate_bytes = _allocate_bytes, .destroy = _destroy, }, .prf = prf, .seed = chunk_clone(seed), .buffer = chunk_alloc(prf->get_block_size(prf)), ); if (counter) { this->counter = 0x01; this->prf->get_bytes(this->prf, this->seed, NULL); this->prf->get_bytes(this->prf, chunk_from_thing(this->counter), this->buffer.ptr); this->counter++; } else { this->prf->get_bytes(this->prf, this->seed, this->buffer.ptr); } return &this->public; }