Streamlined DRBG and MGF1 debug output
[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 #include <utils/test.h>
20
21 #define MAX_STRENGTH_BITS 256
22 #define MAX_DRBG_REQUESTS 0xfffffffe
23
24 typedef struct private_ntru_drbg_t private_ntru_drbg_t;
25
26 /**
27 * Private data of an ntru_drbg_t object.
28 */
29 struct private_ntru_drbg_t {
30 /**
31 * Public ntru_drbg_t interface.
32 */
33 ntru_drbg_t public;
34
35 /**
36 * Security strength in bits of the DRBG
37 */
38 u_int32_t strength;
39
40 /**
41 * Number of requests for pseudorandom bits
42 */
43 u_int32_t reseed_counter;
44
45 /**
46 * Maximum number of requests for pseudorandom bits
47 */
48 u_int32_t max_requests;
49
50 /**
51 * True entropy source
52 */
53 rng_t *entropy;
54
55 /**
56 * HMAC-SHA256
57 */
58 signer_t *hmac;
59
60 /**
61 * Internal state of HMAC-SHA256: key
62 */
63 chunk_t key;
64
65 /**
66 * Internal state of HMAC-SHA256: value
67 */
68 chunk_t value;
69
70 };
71
72 /**
73 * Update the internal state of the HMAC_DRBG
74 */
75 static bool update(private_ntru_drbg_t *this, chunk_t data)
76 {
77 chunk_t ch_00 = chunk_from_chars(0x00);
78 chunk_t ch_01 = chunk_from_chars(0x01);
79
80 if (!this->hmac->set_key(this->hmac, this->key) ||
81 !this->hmac->get_signature(this->hmac, this->value, NULL) ||
82 !this->hmac->get_signature(this->hmac, ch_00, NULL) ||
83 !this->hmac->get_signature(this->hmac, data, this->key.ptr) ||
84 !this->hmac->set_key(this->hmac, this->key) ||
85 !this->hmac->get_signature(this->hmac, this->value,
86 this->value.ptr))
87 {
88 return FALSE;
89 }
90
91 if (data.len > 0)
92 {
93 if (!this->hmac->set_key(this->hmac, this->key) ||
94 !this->hmac->get_signature(this->hmac, this->value, NULL) ||
95 !this->hmac->get_signature(this->hmac, ch_01, NULL) ||
96 !this->hmac->get_signature(this->hmac, data, this->key.ptr) ||
97 !this->hmac->set_key(this->hmac, this->key) ||
98 !this->hmac->get_signature(this->hmac, this->value,
99 this->value.ptr))
100 {
101 return FALSE;
102 }
103 }
104 DBG4(DBG_LIB, "HMAC_DRBG V: %B", &this->value);
105 DBG4(DBG_LIB, "HMAC_DRBG K: %B", &this->key);
106
107 return TRUE;
108 }
109
110 METHOD(ntru_drbg_t, get_strength, u_int32_t,
111 private_ntru_drbg_t *this)
112 {
113 return this->strength;
114 }
115
116 METHOD(ntru_drbg_t, reseed, bool,
117 private_ntru_drbg_t *this)
118 {
119 chunk_t seed;
120
121 seed = chunk_alloc(this->strength / BITS_PER_BYTE);
122 DBG2(DBG_LIB, "DRG requests %u bytes of entropy", seed.len);
123
124 if (!this->entropy->get_bytes(this->entropy, seed.len, seed.ptr))
125 {
126 chunk_free(&seed);
127 return FALSE;
128 }
129 if (!update(this, seed))
130 {
131 chunk_free(&seed);
132 return FALSE;
133 }
134 chunk_clear(&seed);
135 this->reseed_counter = 1;
136
137 return TRUE;
138 }
139
140 METHOD(ntru_drbg_t, generate, bool,
141 private_ntru_drbg_t *this, u_int32_t strength, u_int32_t len, u_int8_t *out)
142 {
143 size_t delta;
144 chunk_t output;
145
146 DBG2(DBG_LIB, "DRBG generates %u pseudorandom bytes", len);
147 if (!out || len == 0)
148 {
149 return FALSE;
150 }
151 output = chunk_create(out, len);
152
153 if (this->reseed_counter > this->max_requests)
154 {
155 if (!reseed(this))
156 {
157 return FALSE;
158 }
159 }
160 while (len)
161 {
162 if (!this->hmac->get_signature(this->hmac, this->value,
163 this->value.ptr))
164 {
165 return FALSE;
166 }
167 delta = min(len, this->value.len);
168 memcpy(out, this->value.ptr, delta);
169 len -= delta;
170 out += delta;
171 }
172 DBG4(DBG_LIB, "HMAC_DRBG Out: %B", &output);
173
174 if (!update(this, chunk_empty))
175 {
176 return FALSE;
177 }
178 this->reseed_counter++;
179
180 return TRUE;
181 }
182
183 METHOD(ntru_drbg_t, destroy, void,
184 private_ntru_drbg_t *this)
185 {
186 this->hmac->destroy(this->hmac);
187 chunk_clear(&this->key);
188 chunk_clear(&this->value);
189 free(this);
190 }
191
192 /*
193 * Described in header.
194 */
195 ntru_drbg_t *ntru_drbg_create(u_int32_t strength, chunk_t pers_str,
196 rng_t *entropy)
197 {
198 private_ntru_drbg_t *this;
199 chunk_t seed;
200 signer_t *hmac;
201 size_t entropy_len;
202 u_int32_t max_requests;
203
204 if (strength > MAX_STRENGTH_BITS)
205 {
206 return NULL;
207 }
208 if (strength <= 112)
209 {
210 strength = 112;
211 }
212 else if (strength <= 128)
213 {
214 strength = 128;
215 }
216 else if (strength <= 192)
217 {
218 strength = 192;
219 }
220 else
221 {
222 strength = 256;
223 }
224
225 hmac = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA2_256_256);
226 if (!hmac)
227 {
228 DBG1(DBG_LIB, "could not instantiate HMAC-SHA256");
229 return NULL;
230 }
231
232 max_requests = lib->settings->get_int(lib->settings,
233 "libstrongswan.plugins.ntru.max_drbg_requests",
234 MAX_DRBG_REQUESTS);
235
236 INIT(this,
237 .public = {
238 .get_strength = _get_strength,
239 .reseed = _reseed,
240 .generate = _generate,
241 .destroy = _destroy,
242 },
243 .strength = strength,
244 .entropy = entropy,
245 .hmac = hmac,
246 .key = chunk_alloc(hmac->get_key_size(hmac)),
247 .value = chunk_alloc(hmac->get_block_size(hmac)),
248 .max_requests = max_requests,
249 .reseed_counter = 1,
250 );
251
252 memset(this->key.ptr, 0x00, this->key.len);
253 memset(this->value.ptr, 0x01, this->value.len);
254
255 entropy_len = (strength + strength/2) / BITS_PER_BYTE;
256 seed = chunk_alloc(entropy_len + pers_str.len);
257 DBG2(DBG_LIB, "DRBG requests %u bytes of entropy", entropy_len);
258
259 if (!this->entropy->get_bytes(this->entropy, entropy_len, seed.ptr))
260 {
261 chunk_free(&seed);
262 destroy(this);
263 return NULL;
264 }
265 memcpy(seed.ptr + entropy_len, pers_str.ptr, pers_str.len);
266 DBG4(DBG_LIB, "seed: %B", &seed);
267
268 if (!update(this, seed))
269 {
270 chunk_free(&seed);
271 destroy(this);
272 return NULL;
273 }
274 chunk_clear(&seed);
275
276 return &this->public;
277 }
278
279 EXPORT_FUNCTION_FOR_TESTS(ntru, ntru_drbg_create);