]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/drbg/drbg_ctr.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libstrongswan / plugins / drbg / drbg_ctr.c
CommitLineData
737375a2
AS
1/*
2 * Copyright (C) 2016-2019 Andreas Steffen
19ef2aec
TB
3 *
4 * Copyright (C) secunet Security Networks AG
737375a2
AS
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 "drbg_ctr.h"
18
a43407df
AS
19#define MAX_DRBG_REQUESTS 0xfffffffe /* 2^32 - 2 */
20#define MAX_DRBG_BYTES 0x00010000 /* 2^19 bits = 2^16 bytes */
737375a2
AS
21
22typedef struct private_drbg_ctr_t private_drbg_ctr_t;
23
24/**
25 * Private data of an drbg_ctr_t object.
26 */
27struct private_drbg_ctr_t {
28
29 /**
30 * Public drbg_ctr_t interface.
31 */
32 drbg_ctr_t public;
33
34 /**
35 * DRBG type.
36 */
37 drbg_type_t type;
38
39 /**
40 * Security strength in bits.
41 */
42 uint32_t strength;
43
44 /**
45 * Number of requests for pseudorandom bits
46 */
47 uint32_t reseed_counter;
48
49 /**
50 * Maximum number of requests for pseudorandom bits
51 */
52 uint32_t max_requests;
53
54 /**
55 * True entropy source
56 */
57 rng_t *entropy;
58
59 /**
60 * Block cipher in counter mode used by the DRBG
61 */
62 crypter_t *crypter;
63
64 /**
65 * Internal state of HMAC: key
66 */
67 chunk_t key;
68
69 /**
70 * Internal state of HMAC: value
71 */
72 chunk_t value;
73
74 /**
75 * reference count
76 */
77 refcount_t ref;
78
79};
80
81METHOD(drbg_t, get_type, drbg_type_t,
82 private_drbg_ctr_t *this)
83{
84 return this->type;
85}
86
87METHOD(drbg_t, get_strength, uint32_t,
88 private_drbg_ctr_t *this)
89{
90 return this->strength;
91}
92
93static bool encrypt_ctr(private_drbg_ctr_t *this, chunk_t out)
94{
737375a2
AS
95 chunk_t bl = chunk_alloca(this->value.len);
96 chunk_t block;
97 size_t delta, pos = 0;
737375a2 98
737375a2
AS
99 if (!this->crypter->set_key(this->crypter, this->key))
100 {
101 return FALSE;
102 }
103
104 while (pos < out.len)
105 {
106 /* Increment counter by one */
107 chunk_increment(this->value);
108
109 /* Copy current counter to input block */
110 delta = out.len - pos;
111 block = (delta < this->value.len) ?
112 bl : chunk_create(out.ptr + pos, this->value.len);
113 memcpy(block.ptr, this->value.ptr, this->value.len);
114
115 /* ECB encryption */
86a4b95e 116 if (!this->crypter->encrypt(this->crypter, block, chunk_empty, NULL))
737375a2
AS
117 {
118 return FALSE;
119 }
120
121 /* Partial output block at the end? */
122 if (delta < this->value.len)
123 {
124 memcpy(out.ptr + pos, block.ptr, delta);
125 }
126 pos += this->value.len;
127 }
128
129 return TRUE;
130}
131
132/**
133 * Update the internal state of the CTR_DRBG
134 */
135static bool update(private_drbg_ctr_t *this, chunk_t data)
136{
137 chunk_t temp;
138
139 if (data.len && data.len != (this->key.len + this->value.len))
140 {
141 return FALSE;
142 }
143 temp = chunk_alloca(this->key.len + this->value.len);
144
145 if (!encrypt_ctr(this, temp))
146 {
147 return FALSE;
148 }
149 /* Apply data */
150 memxor(temp.ptr, data.ptr, data.len);
151
152 /* Copy new key and value */
153 memcpy(this->key.ptr, temp.ptr, this->key.len);
154 memcpy(this->value.ptr, temp.ptr + this->key.len, this->value.len);
155 memwipe(temp.ptr, temp.len);
156 DBG4(DBG_LIB, "CTR_DRBG K: %B", &this->key);
157 DBG4(DBG_LIB, "CTR_DRBG V: %B", &this->value);
158
159 return TRUE;
160}
161
162METHOD(drbg_t, reseed, bool,
163 private_drbg_ctr_t *this)
164{
165 chunk_t seed;
166 bool success;
167
168 seed = chunk_alloc(this->key.len + this->value.len);
169 DBG2(DBG_LIB, "DRBG requests %u bytes of entropy", seed.len);
170
171 if (!this->entropy->get_bytes(this->entropy, seed.len, seed.ptr))
172 {
173 chunk_free(&seed);
174 return FALSE;
175 }
176 DBG4(DBG_LIB, "reseed: %B", &seed);
177
178 success = update(this, seed);
179 chunk_clear(&seed);
180
181 if (!success)
182 {
183 return FALSE;
184 }
185 this->reseed_counter = 1;
186
187 return TRUE;
188}
189
190METHOD(drbg_t, generate, bool,
191 private_drbg_ctr_t *this, uint32_t len, uint8_t *out)
192{
193 chunk_t output;
194
a43407df
AS
195 if (len > MAX_DRBG_BYTES)
196 {
197 DBG1(DBG_LIB, "DRBG cannot generate more than %d bytes", MAX_DRBG_BYTES);
198 return FALSE;
199 }
200
737375a2
AS
201 if (this->reseed_counter > this->max_requests)
202 {
203 if (!reseed(this))
204 {
205 return FALSE;
206 }
207 }
208
209 DBG2(DBG_LIB, "DRBG generates %u pseudorandom bytes", len);
210 if (!out || len == 0)
211 {
212 return FALSE;
213 }
214 output = chunk_create(out, len);
215
216 if (!encrypt_ctr(this, output))
217 {
218 return FALSE;
219 }
220 DBG4(DBG_LIB, "CTR_DRBG Out: %B", &output);
221
222 if (!update(this, chunk_empty))
223 {
224 return FALSE;
225 }
226 this->reseed_counter++;
227
228 return TRUE;
229}
230
231METHOD(drbg_t, get_ref, drbg_t*,
232 private_drbg_ctr_t *this)
233{
234 ref_get(&this->ref);
235 return &this->public.interface;
236}
237
238METHOD(drbg_t, destroy, void,
239 private_drbg_ctr_t *this)
240{
241 if (ref_put(&this->ref))
242 {
11e9d2b8 243 DESTROY_IF(this->entropy);
737375a2
AS
244 this->crypter->destroy(this->crypter);
245 chunk_clear(&this->key);
246 chunk_clear(&this->value);
247 free(this);
248 }
249}
250
251/**
252 * See header
253 */
254drbg_ctr_t *drbg_ctr_create(drbg_type_t type, uint32_t strength,
255 rng_t *entropy, chunk_t personalization_str)
256{
257 private_drbg_ctr_t *this;
258 encryption_algorithm_t crypter_type;
259 crypter_t *crypter;
260 chunk_t seed;
261 size_t key_len, out_len, seed_len;
262 uint32_t max_requests;
263 bool success;
264
265 switch (type)
266 {
267 case DRBG_CTR_AES128:
86a4b95e 268 crypter_type = ENCR_AES_ECB;
737375a2
AS
269 key_len = 16;
270 break;
271 case DRBG_CTR_AES192:
86a4b95e 272 crypter_type = ENCR_AES_ECB;
737375a2
AS
273 key_len = 24;
274 break;
275 case DRBG_CTR_AES256:
86a4b95e 276 crypter_type = ENCR_AES_ECB;
737375a2
AS
277 key_len = 32;
278 break;
279 default:
280 DBG1(DBG_LIB, "%N not supported", drbg_type_names, type);
281 return NULL;
282 }
283
284 if (strength > key_len * BITS_PER_BYTE)
285 {
286 DBG1(DBG_LIB, "%d bit block encryption key not sufficient for security "
e635d3dc 287 "strength of %u bits", key_len * BITS_PER_BYTE, strength);
737375a2
AS
288 return NULL;
289 }
290
291 crypter = lib->crypto->create_crypter(lib->crypto, crypter_type, key_len);
292 if (!crypter)
293 {
294 DBG1(DBG_LIB, "creation of %N for DRBG failed",
295 encryption_algorithm_names, crypter_type);
296 return NULL;
297 }
298 out_len = crypter->get_block_size(crypter);
299 seed_len = key_len + out_len;
300
301 if (personalization_str.len > seed_len)
302 {
303 DBG1(DBG_LIB, "personalization string length of %d bytes is larger "
e635d3dc 304 "than seed length of %u bytes", personalization_str.len, seed_len);
737375a2
AS
305 crypter->destroy(crypter);
306 return NULL;
307 }
308
309 max_requests = lib->settings->get_int(lib->settings,
310 "%s.plugins.drbg.max_drbg_requests",
311 MAX_DRBG_REQUESTS, lib->ns);
312
313 INIT(this,
314 .public = {
315 .interface = {
316 .get_type = _get_type,
317 .get_strength = _get_strength,
318 .reseed = _reseed,
319 .generate = _generate,
320 .get_ref = _get_ref,
321 .destroy = _destroy,
322 },
323 },
324 .type = type,
325 .strength = strength,
737375a2
AS
326 .crypter = crypter,
327 .key = chunk_alloc(key_len),
328 .value = chunk_alloc(out_len),
329 .max_requests = max_requests,
330 .reseed_counter = 1,
331 .ref = 1,
332 );
333
334 memset(this->key.ptr, 0x00, key_len);
335 memset(this->value.ptr, 0x00, out_len);
336
337 seed = chunk_alloc(seed_len);
338 DBG2(DBG_LIB, "DRBG requests %u bytes of entropy", seed_len);
339
11e9d2b8 340 if (!entropy->get_bytes(entropy, seed.len, seed.ptr))
737375a2
AS
341 {
342 chunk_free(&seed);
343 destroy(this);
344 return NULL;
345 }
346 memxor(seed.ptr, personalization_str.ptr, personalization_str.len);
347 DBG4(DBG_LIB, "seed: %B", &seed);
348
349 success = update(this, seed);
350 chunk_clear(&seed);
351
352 if (!success)
353 {
354 destroy(this);
355 return NULL;
356 }
357
11e9d2b8
AS
358 /* ownership of entropy source is transferred to DRBG */
359 this->entropy = entropy;
360
737375a2
AS
361 return &this->public;
362}