Add a return value to hasher_t.get_hash()
[strongswan.git] / src / libstrongswan / crypto / prf_plus.c
1 /*
2 * Copyright (C) 2005-2006 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <string.h>
18
19 #include "prf_plus.h"
20
21 typedef struct private_prf_plus_t private_prf_plus_t;
22
23 /**
24 * Private data of an prf_plus_t object.
25 *
26 */
27 struct private_prf_plus_t {
28
29 /**
30 * Public interface of prf_plus_t.
31 */
32 prf_plus_t public;
33
34 /**
35 * PRF to use.
36 */
37 prf_t *prf;
38
39 /**
40 * Initial seed.
41 */
42 chunk_t seed;
43
44 /**
45 * Octet which will be appended to the seed, 0 if not used
46 */
47 u_int8_t counter;
48
49 /**
50 * Already given out bytes in current buffer.
51 */
52 size_t used;
53
54 /**
55 * Buffer to store current PRF result.
56 */
57 chunk_t buffer;
58 };
59
60 METHOD(prf_plus_t, get_bytes, bool,
61 private_prf_plus_t *this, size_t length, u_int8_t *buffer)
62 {
63 size_t round, written = 0;
64
65 while (length > 0)
66 {
67 if (this->buffer.len == this->used)
68 { /* buffer used, get next round */
69 if (!this->prf->get_bytes(this->prf, this->buffer, NULL))
70 {
71 return FALSE;
72 }
73 if (this->counter)
74 {
75 if (!this->prf->get_bytes(this->prf, this->seed, NULL) ||
76 !this->prf->get_bytes(this->prf,
77 chunk_from_thing(this->counter), this->buffer.ptr))
78 {
79 return FALSE;
80 }
81 this->counter++;
82 }
83 else
84 {
85 if (!this->prf->get_bytes(this->prf, this->seed,
86 this->buffer.ptr))
87 {
88 return FALSE;
89 }
90 }
91 this->used = 0;
92 }
93 round = min(length, this->buffer.len - this->used);
94 memcpy(buffer + written, this->buffer.ptr + this->used, round);
95
96 length -= round;
97 this->used += round;
98 written += round;
99 }
100 return TRUE;
101 }
102
103 METHOD(prf_plus_t, allocate_bytes, bool,
104 private_prf_plus_t *this, size_t length, chunk_t *chunk)
105 {
106 if (length)
107 {
108 *chunk = chunk_alloc(length);
109 return get_bytes(this, length, chunk->ptr);
110 }
111 *chunk = chunk_empty;
112 return TRUE;
113 }
114
115 METHOD(prf_plus_t, destroy, void,
116 private_prf_plus_t *this)
117 {
118 free(this->buffer.ptr);
119 free(this->seed.ptr);
120 free(this);
121 }
122
123 /*
124 * Description in header.
125 */
126 prf_plus_t *prf_plus_create(prf_t *prf, bool counter, chunk_t seed)
127 {
128 private_prf_plus_t *this;
129
130 INIT(this,
131 .public = {
132 .get_bytes = _get_bytes,
133 .allocate_bytes = _allocate_bytes,
134 .destroy = _destroy,
135 },
136 .prf = prf,
137 .seed = chunk_clone(seed),
138 .buffer = chunk_alloc(prf->get_block_size(prf)),
139 );
140
141 if (counter)
142 {
143 this->counter = 0x01;
144 if (!this->prf->get_bytes(this->prf, this->seed, NULL) ||
145 !this->prf->get_bytes(this->prf, chunk_from_thing(this->counter),
146 this->buffer.ptr))
147 {
148 destroy(this);
149 return NULL;
150 }
151 this->counter++;
152 }
153 else
154 {
155 if (!this->prf->get_bytes(this->prf, this->seed, this->buffer.ptr))
156 {
157 destroy(this);
158 return NULL;
159 }
160 }
161
162 return &this->public;
163 }