support for Padlock RNG
authorMartin Willi <martin@strongswan.org>
Thu, 18 Dec 2008 16:21:05 +0000 (16:21 -0000)
committerMartin Willi <martin@strongswan.org>
Thu, 18 Dec 2008 16:21:05 +0000 (16:21 -0000)
src/libstrongswan/plugins/padlock/Makefile.am
src/libstrongswan/plugins/padlock/padlock_plugin.c
src/libstrongswan/plugins/padlock/padlock_rng.c [new file with mode: 0644]
src/libstrongswan/plugins/padlock/padlock_rng.h [new file with mode: 0644]

index e2e76e9..e7c3ba4 100644 (file)
@@ -7,6 +7,7 @@ plugin_LTLIBRARIES = libstrongswan-padlock.la
 
 libstrongswan_padlock_la_SOURCES = padlock_plugin.h padlock_plugin.c \
        padlock_aes_crypter.c padlock_aes_crypter.h \
-       padlock_sha1_hasher.c padlock_sha1_hasher.h
+       padlock_sha1_hasher.c padlock_sha1_hasher.h \
+       padlock_rng.c padlock_rng.h
 libstrongswan_padlock_la_LDFLAGS = -module
 
index b6e2b7c..d0b55bc 100644 (file)
@@ -18,6 +18,7 @@
 #include "padlock_plugin.h"
 #include "padlock_aes_crypter.h"
 #include "padlock_sha1_hasher.h"
+#include "padlock_rng.h"
 
 #include <stdio.h>
 
@@ -107,6 +108,15 @@ static padlock_feature_t get_padlock_features()
  */
 static void destroy(private_padlock_plugin_t *this)
 {
+       if (this->features & PADLOCK_RNG_ENABLED)
+       {
+               lib->crypto->remove_rng(lib->crypto,
+                                                       (rng_constructor_t)padlock_rng_create);
+               lib->crypto->remove_rng(lib->crypto,
+                                                       (rng_constructor_t)padlock_rng_create);
+               lib->crypto->remove_rng(lib->crypto,
+                                                       (rng_constructor_t)padlock_rng_create);
+       }
        if (this->features & PADLOCK_ACE2_ENABLED)
        {
                lib->crypto->remove_crypter(lib->crypto,
@@ -147,6 +157,15 @@ plugin_t *plugin_create()
                 this->features & PADLOCK_PHE_ENABLED ? " PHE" : "",
                 this->features & PADLOCK_PMM_ENABLED ? " PMM" : "");
        
+       if (this->features & PADLOCK_RNG_ENABLED)
+       {
+               lib->crypto->add_rng(lib->crypto, RNG_REAL,
+                                               (rng_constructor_t)padlock_rng_create);
+               lib->crypto->add_rng(lib->crypto, RNG_STRONG,
+                                               (rng_constructor_t)padlock_rng_create);
+               lib->crypto->add_rng(lib->crypto, RNG_WEAK,
+                                               (rng_constructor_t)padlock_rng_create);
+       }
        if (this->features & PADLOCK_ACE2_ENABLED)
        {
                lib->crypto->add_crypter(lib->crypto, ENCR_AES_CBC,
diff --git a/src/libstrongswan/plugins/padlock/padlock_rng.c b/src/libstrongswan/plugins/padlock/padlock_rng.c
new file mode 100644 (file)
index 0000000..50d9f0c
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * $Id$
+ */
+
+#include "padlock_rng.h"
+
+typedef struct private_padlock_rng_t private_padlock_rng_t;
+typedef enum padlock_quality_factor_t padlock_quality_factor_t;
+
+/**
+ * Padlock RNG quality factors
+ */
+enum padlock_quality_factor_t {
+       /* Lowest quality: Reads 8 bytes */
+       PADLOCK_QF0 = 0x00,
+       /* Medium quality: Reads 4 bytes */
+       PADLOCK_QF1 = 0x01,
+       /* Better quality: Reads 2 bytes */
+       PADLOCK_QF2 = 0x10,
+       /* Highest quality: Reads 1 byte */
+       PADLOCK_QF3 = 0x11,
+};
+
+/**
+ * Private data of an padlock_rng_t object.
+ */
+struct private_padlock_rng_t {
+       
+       /**
+        * Public padlock_rng_t interface.
+        */
+       padlock_rng_t public;
+       
+       /**
+        * Padlock quality factor
+        */
+       padlock_quality_factor_t quality;
+};
+
+/**
+ * Get bytes from Padlock RNG. buf should have space for (len + 7)
+ */
+static void rng(char *buf, int len, int quality)
+{
+       while (len > 0)\r
+       {
+               int status;
+               
+               /* run XSTORE until we have all bytes needed. We do not use REP, as
+                * this should not be performance critical and it's easier this way. */
+               asm volatile (
+                       ".byte 0x0F,0xA7,0xC0 \n\t"\r
+                       : "=D"(buf), "=a"(status)\r
+                       : "d"(quality), "D"(buf));
+               
+               /* bits[0..4] of status word contains the number of bytes read */
+               len -= status & 0x1F;
+       }
+}
+
+/**
+ * Implementation of padlock_rng_t.allocate_bytes.
+ */
+static void allocate_bytes(private_padlock_rng_t *this, size_t bytes,
+                                                  chunk_t *chunk)
+{
+       chunk->len = bytes;
+       /* padlock requires some additional bytes */
+       chunk->ptr = malloc(bytes + 7);
+       
+       rng(chunk->ptr, chunk->len, this->quality);
+}
+
+/**
+ * Implementation of padlock_rng_t.get_bytes.
+ */
+static void get_bytes(private_padlock_rng_t *this, size_t bytes,
+                                         u_int8_t *buffer)
+{
+       chunk_t chunk;
+       
+       /* Padlock needs a larger buffer than "bytes", we need a new buffer */
+       allocate_bytes(this, bytes, &chunk);
+       memcpy(buffer, chunk.ptr, bytes);
+       chunk_clear(&chunk);
+}
+
+/**
+ * Implementation of padlock_rng_t.destroy.
+ */
+static void destroy(private_padlock_rng_t *this)
+{
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+padlock_rng_t *padlock_rng_create(rng_quality_t quality)
+{
+       private_padlock_rng_t *this = malloc_thing(private_padlock_rng_t);
+       
+       this->public.rng.get_bytes = (void (*) (rng_t *, size_t, u_int8_t*)) get_bytes;
+       this->public.rng.allocate_bytes = (void (*) (rng_t *, size_t, chunk_t*)) allocate_bytes;
+       this->public.rng.destroy = (void (*) (rng_t *))destroy;
+       
+       /* map RNG quality to Padlock quality factor */
+       switch (quality)
+       {
+               case RNG_WEAK:
+                       this->quality = PADLOCK_QF0;
+                       break;
+               case RNG_STRONG:
+                       this->quality = PADLOCK_QF1;
+                       break;
+               case RNG_REAL:
+                       this->quality = PADLOCK_QF3;
+                       break;
+       }
+       
+       return &this->public;
+}
+
diff --git a/src/libstrongswan/plugins/padlock/padlock_rng.h b/src/libstrongswan/plugins/padlock/padlock_rng.h
new file mode 100644 (file)
index 0000000..a76ecd2
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup padlock_rng padlock_rng
+ * @{ @ingroup padlock
+ */
+
+#ifndef PADLOCK_RNG_H_
+#define PADLOCK_RNG_H_
+
+#include <crypto/rngs/rng.h>
+
+typedef struct padlock_rng_t padlock_rng_t;
+
+/**
+ * Hardware-RNG based on via Padlock.
+ */
+struct padlock_rng_t {
+       
+       /**
+        * Implements rng_t interface.
+        */
+       rng_t rng;
+};
+
+/**
+ * Create a padlock_rng instance.
+ *
+ * @param quality      required quality of randomness
+ * @return                     created random_rng_t
+ */
+padlock_rng_t *padlock_rng_create(rng_quality_t quality);
+
+#endif /* PADLOCK_RNG_ @}*/