static plugin_feature_t f[] = {
PLUGIN_REGISTER(RNG, rdrand_rng_create),
PLUGIN_PROVIDE(RNG, RNG_WEAK),
+ PLUGIN_PROVIDE(RNG, RNG_STRONG),
};
*features = f;
return countof(f);
*/
#define MAX_TRIES 16
+/**
+ * After how many bytes should we reseed for RNG_STRONG
+ * (must be a power of two >= 8)
+ */
+#define FORCE_RESEED 16
+
/**
* Get a two byte word using RDRAND
*/
return TRUE;
}
+/**
+ * Enforce a DRNG reseed by reading 511 128-bit samples
+ */
+static bool reseed()
+{
+ int i;
+
+#ifdef __x86_64__
+ u_int64_t tmp;
+
+ for (i = 0; i < 511 * 16 / sizeof(u_int64_t); i++)
+ {
+ if (!rdrand64(&tmp))
+ {
+ return FALSE;
+ }
+ }
+#else /* __i386__ */
+ u_int32_t tmp;
+
+ for (i = 0; i < 511 * 16 / sizeof(u_int32_t); i++)
+ {
+ if (!rdrand32(&tmp))
+ {
+ return FALSE;
+ }
+ }
+#endif /* __x86_64__ / __i386__ */
+ return TRUE;
+}
+
METHOD(rng_t, get_bytes, bool,
private_rdrand_rng_t *this, size_t bytes, u_int8_t *buffer)
{
chunk = chunk_create(buffer, bytes);
+ if (this->quality == RNG_STRONG)
+ {
+ if (!reseed())
+ {
+ return FALSE;
+ }
+ }
+
/* align to 2 byte */
if (chunk.len >= sizeof(u_int8_t))
{
/* fill with 8 byte words */
while (chunk.len >= sizeof(u_int64_t))
{
+ if (this->quality == RNG_STRONG && chunk.len % FORCE_RESEED)
+ {
+ if (!reseed())
+ {
+ return FALSE;
+ }
+ }
if (!rdrand64((u_int64_t*)chunk.ptr))
{
return FALSE;
/* fill with 4 byte words */
while (chunk.len >= sizeof(u_int32_t))
{
+ if (this->quality == RNG_STRONG && chunk.len % FORCE_RESEED)
+ {
+ if (!reseed())
+ {
+ return FALSE;
+ }
+ }
if (!rdrand32((u_int32_t*)chunk.ptr))
{
return FALSE;
#endif /* __x86_64__ / __i386__ */
+ if (this->quality == RNG_STRONG)
+ {
+ if (!reseed())
+ {
+ return FALSE;
+ }
+ }
+
/* append 2 byte word */
if (chunk.len >= sizeof(u_int16_t))
{
switch (quality)
{
case RNG_WEAK:
- break;
case RNG_STRONG:
+ break;
case RNG_TRUE:
default:
/* not yet */