Annotation of embedaddon/strongswan/src/libstrongswan/plugins/rdrand/rdrand_rng.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012 Martin Willi
3: * Copyright (C) 2012 revosec AG
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 "rdrand_rng.h"
17:
18: #include <unistd.h>
19:
20: typedef struct private_rdrand_rng_t private_rdrand_rng_t;
21:
22: /**
23: * Private data of an rdrand_rng_t object.
24: */
25: struct private_rdrand_rng_t {
26:
27: /**
28: * Public rdrand_rng_t interface.
29: */
30: rdrand_rng_t public;
31:
32: /**
33: * Quality we produce RNG data
34: */
35: rng_quality_t quality;
36: };
37:
38: /**
39: * Retries for failed RDRAND instructions
40: */
41: #define MAX_TRIES 16
42:
43: /**
44: * After how many bytes should we reseed for RNG_STRONG
45: * (must be a power of two >= 8)
46: */
47: #define FORCE_RESEED 16
48:
49: /**
50: * How many times we mix reseeded RDRAND output when using RNG_TRUE
51: */
52: #define MIX_ROUNDS 32
53:
54: /**
55: * Get a two byte word using RDRAND
56: */
57: static bool rdrand16(uint16_t *out)
58: {
59: u_char res;
60: int i;
61:
62: for (i = 0; i < MAX_TRIES; i++)
63: {
64: asm(".byte 0x66;.byte 0x0f;.byte 0xc7;.byte 0xf0; " /* rdrand */
65: "setc %1;"
66: : "=a"(*out), "=qm"(res));
67:
68: if (res)
69: {
70: return TRUE;
71: }
72: }
73: return FALSE;
74: }
75:
76: /**
77: * Get a four byte word using RDRAND
78: */
79: static bool rdrand32(uint32_t *out)
80: {
81: u_char res;
82: int i;
83:
84: for (i = 0; i < MAX_TRIES; i++)
85: {
86: asm(".byte 0x0f;.byte 0xc7;.byte 0xf0;" /* rdrand */
87: "setc %1;"
88: : "=a"(*out), "=qm"(res));
89:
90: if (res)
91: {
92: return TRUE;
93: }
94: }
95: return FALSE;
96: }
97:
98: #ifdef __x86_64__
99: /**
100: * Get a eight byte word using RDRAND
101: */
102: static bool rdrand64(uint64_t *out)
103: {
104: u_char res;
105: int i;
106:
107: for (i = 0; i < MAX_TRIES; i++)
108: {
109: asm(".byte 0x48;.byte 0x0f;.byte 0xc7;.byte 0xf0;" /* rdrand */
110: "setc %1;"
111: : "=a"(*out), "=qm"(res));
112:
113: if (res)
114: {
115: return TRUE;
116: }
117: }
118: return FALSE;
119: }
120: #endif /* __x86_64__ */
121:
122: /**
123: * Get a one byte word using RDRAND
124: */
125: static bool rdrand8(uint8_t *out)
126: {
127: uint16_t u16;
128:
129: if (!rdrand16(&u16))
130: {
131: return FALSE;
132: }
133: *out = u16;
134: return TRUE;
135: }
136:
137: /**
138: * Get a 16 byte word using RDRAND
139: */
140: static bool rdrand128(void *out)
141: {
142: #ifdef __x86_64__
143: if (!rdrand64(out) ||
144: !rdrand64(out + sizeof(uint64_t)))
145: {
146: return FALSE;
147: }
148: #else /* __i386__ */
149: if (!rdrand32(out) ||
150: !rdrand32(out + 1 * sizeof(uint32_t)) ||
151: !rdrand32(out + 2 * sizeof(uint32_t)) ||
152: !rdrand32(out + 3 * sizeof(uint32_t)))
153: {
154: return FALSE;
155: }
156: #endif /* __x86_64__ / __i386__ */
157: return TRUE;
158: }
159:
160: /**
161: * Enforce a DRNG reseed by reading 511 128-bit samples
162: */
163: static bool reseed()
164: {
165: int i;
166:
167: #ifdef __x86_64__
168: uint64_t tmp;
169:
170: for (i = 0; i < 511 * 16 / sizeof(uint64_t); i++)
171: {
172: if (!rdrand64(&tmp))
173: {
174: return FALSE;
175: }
176: }
177: #else /* __i386__ */
178: uint32_t tmp;
179:
180: for (i = 0; i < 511 * 16 / sizeof(uint32_t); i++)
181: {
182: if (!rdrand32(&tmp))
183: {
184: return FALSE;
185: }
186: }
187: #endif /* __x86_64__ / __i386__ */
188: return TRUE;
189: }
190:
191: /**
192: * Fill a preallocated chunk of data with random bytes
193: */
194: static bool rdrand_chunk(private_rdrand_rng_t *this, chunk_t chunk)
195: {
196: if (this->quality == RNG_STRONG)
197: {
198: if (!reseed())
199: {
200: return FALSE;
201: }
202: }
203:
204: /* align to 2 byte */
205: if (chunk.len >= sizeof(uint8_t))
206: {
207: if ((uintptr_t)chunk.ptr % 2)
208: {
209: if (!rdrand8((uint8_t*)chunk.ptr))
210: {
211: return FALSE;
212: }
213: chunk = chunk_skip(chunk, sizeof(uint8_t));
214: }
215: }
216:
217: /* align to 4 byte */
218: if (chunk.len >= sizeof(uint16_t))
219: {
220: if ((uintptr_t)chunk.ptr % 4)
221: {
222: if (!rdrand16((uint16_t*)chunk.ptr))
223: {
224: return FALSE;
225: }
226: chunk = chunk_skip(chunk, sizeof(uint16_t));
227: }
228: }
229:
230: #ifdef __x86_64__
231:
232: /* align to 8 byte */
233: if (chunk.len >= sizeof(uint32_t))
234: {
235: if ((uintptr_t)chunk.ptr % 8)
236: {
237: if (!rdrand32((uint32_t*)chunk.ptr))
238: {
239: return FALSE;
240: }
241: chunk = chunk_skip(chunk, sizeof(uint32_t));
242: }
243: }
244:
245: /* fill with 8 byte words */
246: while (chunk.len >= sizeof(uint64_t))
247: {
248: if (this->quality == RNG_STRONG && chunk.len % FORCE_RESEED == 0)
249: {
250: if (!reseed())
251: {
252: return FALSE;
253: }
254: }
255: if (!rdrand64((uint64_t*)chunk.ptr))
256: {
257: return FALSE;
258: }
259: chunk = chunk_skip(chunk, sizeof(uint64_t));
260: }
261:
262: /* append 4 byte word */
263: if (chunk.len >= sizeof(uint32_t))
264: {
265: if (!rdrand32((uint32_t*)chunk.ptr))
266: {
267: return FALSE;
268: }
269: chunk = chunk_skip(chunk, sizeof(uint32_t));
270: }
271:
272: #else /* __i386__ */
273:
274: /* fill with 4 byte words */
275: while (chunk.len >= sizeof(uint32_t))
276: {
277: if (this->quality == RNG_STRONG && chunk.len % FORCE_RESEED == 0)
278: {
279: if (!reseed())
280: {
281: return FALSE;
282: }
283: }
284: if (!rdrand32((uint32_t*)chunk.ptr))
285: {
286: return FALSE;
287: }
288: chunk = chunk_skip(chunk, sizeof(uint32_t));
289: }
290:
291: #endif /* __x86_64__ / __i386__ */
292:
293: if (this->quality == RNG_STRONG)
294: {
295: if (!reseed())
296: {
297: return FALSE;
298: }
299: }
300:
301: /* append 2 byte word */
302: if (chunk.len >= sizeof(uint16_t))
303: {
304: if (!rdrand16((uint16_t*)chunk.ptr))
305: {
306: return FALSE;
307: }
308: chunk = chunk_skip(chunk, sizeof(uint16_t));
309: }
310:
311: /* append 1 byte word */
312: if (chunk.len >= sizeof(uint8_t))
313: {
314: if (!rdrand8((uint8_t*)chunk.ptr))
315: {
316: return FALSE;
317: }
318: chunk = chunk_skip(chunk, sizeof(uint8_t));
319: }
320:
321: return TRUE;
322: }
323:
324: /**
325: * Stronger variant mixing reseeded results of rdrand output
326: *
327: * This is based on the Intel DRNG "Software Implementation Guide", using
328: * AES-CBC to mix several reseeded RDRAND outputs.
329: */
330: static bool rdrand_mixed(private_rdrand_rng_t *this, chunk_t chunk)
331: {
332: u_char block[16], forward[16], key[16], iv[16];
333: crypter_t *crypter;
334: int i, len;
335:
336: memset(iv, 0, sizeof(iv));
337: crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, 16);
338: if (!crypter)
339: {
340: return FALSE;
341: }
342: for (i = 0; i < sizeof(key); i++)
343: {
344: key[i] = i;
345: }
346: if (!crypter->set_key(crypter, chunk_from_thing(key)))
347: {
348: crypter->destroy(crypter);
349: return FALSE;
350: }
351: while (chunk.len > 0)
352: {
353: memset(forward, 0, sizeof(forward));
354: for (i = 0; i < MIX_ROUNDS; i++)
355: {
356: /* sleep to reseed PRNG */
357: usleep(10);
358: if (!rdrand128(block))
359: {
360: crypter->destroy(crypter);
361: return FALSE;
362: }
363: memxor(forward, block, sizeof(block));
364: if (!crypter->encrypt(crypter, chunk_from_thing(forward),
365: chunk_from_thing(iv), NULL))
366: {
367: crypter->destroy(crypter);
368: return FALSE;
369: }
370: }
371: len = min(chunk.len, sizeof(forward));
372: memcpy(chunk.ptr, forward, len);
373: chunk = chunk_skip(chunk, len);
374: }
375: crypter->destroy(crypter);
376:
377: return TRUE;
378: }
379:
380: METHOD(rng_t, get_bytes, bool,
381: private_rdrand_rng_t *this, size_t bytes, uint8_t *buffer)
382: {
383: switch (this->quality)
384: {
385: case RNG_WEAK:
386: case RNG_STRONG:
387: return rdrand_chunk(this, chunk_create(buffer, bytes));
388: case RNG_TRUE:
389: return rdrand_mixed(this, chunk_create(buffer, bytes));
390: default:
391: return FALSE;
392: }
393: }
394:
395: METHOD(rng_t, allocate_bytes, bool,
396: private_rdrand_rng_t *this, size_t bytes, chunk_t *chunk)
397: {
398: *chunk = chunk_alloc(bytes);
399: if (get_bytes(this, bytes, chunk->ptr))
400: {
401: return TRUE;
402: }
403: free(chunk->ptr);
404: return FALSE;
405: }
406:
407: METHOD(rng_t, destroy, void,
408: private_rdrand_rng_t *this)
409: {
410: free(this);
411: }
412:
413: /*
414: * Described in header.
415: */
416: rdrand_rng_t *rdrand_rng_create(rng_quality_t quality)
417: {
418: private_rdrand_rng_t *this;
419:
420: switch (quality)
421: {
422: case RNG_WEAK:
423: case RNG_STRONG:
424: case RNG_TRUE:
425: break;
426: default:
427: return NULL;
428: }
429:
430: INIT(this,
431: .public = {
432: .rng = {
433: .get_bytes = _get_bytes,
434: .allocate_bytes = _allocate_bytes,
435: .destroy = _destroy,
436: },
437: },
438: .quality = quality,
439: );
440:
441: return &this->public;
442: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>