Added DRBG automatic reseeding tests
[strongswan.git] / src / libstrongswan / plugins / ntru / ntru_drbg.c
1 /*
2 * Copyright (C) 2013 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "ntru_drbg.h"
17
18 #include <utils/debug.h>
19
20 #define MAX_STRENGTH_BITS 256
21 #define MAX_DRBG_REQUESTS 0xfffffffe
22
23 typedef struct private_ntru_drbg_t private_ntru_drbg_t;
24
25 /**
26 * Private data of an ntru_drbg_t object.
27 */
28 struct private_ntru_drbg_t {
29 /**
30 * Public ntru_drbg_t interface.
31 */
32 ntru_drbg_t public;
33
34 /**
35 * Security strength in bits of the DRBG
36 */
37 u_int32_t strength;
38
39 /**
40 * Number of requests for pseudorandom bits
41 */
42 u_int32_t reseed_counter;
43
44 /**
45 * Maximum number of requests for pseudorandom bits
46 */
47 u_int32_t max_requests;
48
49 /**
50 * True entropy source
51 */
52 rng_t *entropy;
53
54 /**
55 * HMAC-SHA256
56 */
57 signer_t *hmac;
58
59 /**
60 * Internal state of HMAC-SHA256: key
61 */
62 chunk_t key;
63
64 /**
65 * Internal state of HMAC-SHA256: value
66 */
67 chunk_t value;
68
69 };
70
71 /**
72 * Update the internal state of the HMAC_DRBG
73 */
74 static bool update(private_ntru_drbg_t *this, chunk_t data)
75 {
76 chunk_t ch_00 = chunk_from_chars(0x00);
77 chunk_t ch_01 = chunk_from_chars(0x01);
78
79 if (!this->hmac->set_key(this->hmac, this->key) ||
80 !this->hmac->get_signature(this->hmac, this->value, NULL) ||
81 !this->hmac->get_signature(this->hmac, ch_00, NULL) ||
82 !this->hmac->get_signature(this->hmac, data, this->key.ptr) ||
83 !this->hmac->set_key(this->hmac, this->key) ||
84 !this->hmac->get_signature(this->hmac, this->value,
85 this->value.ptr))
86 {
87 return FALSE;
88 }
89
90 if (data.len > 0)
91 {
92 if (!this->hmac->set_key(this->hmac, this->key) ||
93 !this->hmac->get_signature(this->hmac, this->value, NULL) ||
94 !this->hmac->get_signature(this->hmac, ch_01, NULL) ||
95 !this->hmac->get_signature(this->hmac, data, this->key.ptr) ||
96 !this->hmac->set_key(this->hmac, this->key) ||
97 !this->hmac->get_signature(this->hmac, this->value,
98 this->value.ptr))
99 {
100 return FALSE;
101 }
102 }
103 DBG4(DBG_LIB, "HMAC_DRBG V: %B", &this->value);
104 DBG4(DBG_LIB, "HMAC_DRBG K: %B", &this->key);
105
106 return TRUE;
107 }
108
109 METHOD(ntru_drbg_t, get_strength, u_int32_t,
110 private_ntru_drbg_t *this)
111 {
112 return this->strength;
113 }
114
115 METHOD(ntru_drbg_t, reseed, bool,
116 private_ntru_drbg_t *this)
117 {
118 chunk_t seed;
119
120 seed = chunk_alloc(this->strength / BITS_PER_BYTE);
121 DBG2(DBG_LIB, "DBRG requesting %u bytes of entropy", seed.len);
122
123 if (!this->entropy->get_bytes(this->entropy, seed.len, seed.ptr))
124 {
125 chunk_free(&seed);
126 return FALSE;
127 }
128 if (!update(this, seed))
129 {
130 chunk_free(&seed);
131 return FALSE;
132 }
133 chunk_clear(&seed);
134 this->reseed_counter = 1;
135
136 return TRUE;
137 }
138
139 METHOD(ntru_drbg_t, generate, bool,
140 private_ntru_drbg_t *this, u_int32_t strength, u_int32_t len, u_int8_t *out)
141 {
142 size_t delta;
143 chunk_t output;
144
145 DBG2(DBG_LIB, "DRBG generates %u pseudorandom bytes", len);
146 if (!out || len == 0)
147 {
148 return FALSE;
149 }
150 output = chunk_create(out, len);
151
152 if (this->reseed_counter > this->max_requests)
153 {
154 if (!reseed(this))
155 {
156 return FALSE;
157 }
158 }
159 while (len)
160 {
161 if (!this->hmac->get_signature(this->hmac, this->value,
162 this->value.ptr))
163 {
164 return FALSE;
165 }
166 delta = min(len, this->value.len);
167 memcpy(out, this->value.ptr, delta);
168 len -= delta;
169 out += delta;
170 }
171 DBG4(DBG_LIB, "HMAC_DRBG Out: %B", &output);
172
173 if (!update(this, chunk_empty))
174 {
175 return FALSE;
176 }
177 this->reseed_counter++;
178
179 return TRUE;
180 }
181
182 METHOD(ntru_drbg_t, destroy, void,
183 private_ntru_drbg_t *this)
184 {
185 this->hmac->destroy(this->hmac);
186 chunk_clear(&this->key);
187 chunk_clear(&this->value);
188 free(this);
189 }
190
191 /*
192 * Described in header.
193 */
194 ntru_drbg_t *ntru_drbg_create(u_int32_t strength, chunk_t pers_str,
195 rng_t *entropy)
196 {
197 private_ntru_drbg_t *this;
198 chunk_t seed;
199 signer_t *hmac;
200 size_t entropy_len;
201 u_int32_t max_requests;
202
203 if (strength > MAX_STRENGTH_BITS)
204 {
205 return NULL;
206 }
207 if (strength <= 112)
208 {
209 strength = 112;
210 }
211 else if (strength <= 128)
212 {
213 strength = 128;
214 }
215 else if (strength <= 192)
216 {
217 strength = 192;
218 }
219 else
220 {
221 strength = 256;
222 }
223
224 hmac = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA2_256_256);
225 if (!hmac)
226 {
227 DBG1(DBG_LIB, "could not instantiate HMAC-SHA256");
228 return NULL;
229 }
230
231 max_requests = lib->settings->get_int(lib->settings,
232 "libstrongswan.plugins.ntru.max_drbg_requests",
233 MAX_DRBG_REQUESTS);
234
235 INIT(this,
236 .public = {
237 .get_strength = _get_strength,
238 .reseed = _reseed,
239 .generate = _generate,
240 .destroy = _destroy,
241 },
242 .strength = strength,
243 .entropy = entropy,
244 .hmac = hmac,
245 .key = chunk_alloc(hmac->get_key_size(hmac)),
246 .value = chunk_alloc(hmac->get_block_size(hmac)),
247 .max_requests = max_requests,
248 .reseed_counter = 1,
249 );
250
251 memset(this->key.ptr, 0x00, this->key.len);
252 memset(this->value.ptr, 0x01, this->value.len);
253
254 entropy_len = (strength + strength/2) / BITS_PER_BYTE;
255 seed = chunk_alloc(entropy_len + pers_str.len);
256 DBG2(DBG_LIB, "DBRG requesting %u bytes of entropy", entropy_len);
257
258 if (!this->entropy->get_bytes(this->entropy, entropy_len, seed.ptr))
259 {
260 chunk_free(&seed);
261 destroy(this);
262 return NULL;
263 }
264 memcpy(seed.ptr + entropy_len, pers_str.ptr, pers_str.len);
265 DBG4(DBG_LIB, "seed: %B", &seed);
266
267 if (!update(this, seed))
268 {
269 chunk_free(&seed);
270 destroy(this);
271 return NULL;
272 }
273 chunk_clear(&seed);
274
275 return &this->public;
276 }
277