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