Hi tech@,

I've written a driver for the Araneus Alea II USB TRNG:
    http://www.araneus.fi/products/alea2/en/

It produces 100kbit/sec of entropy, which my driver stuffs into
add_true_randomness().  A small thing, but maybe valuable in
situations that do a lot of crypto.  I mainly did it to get my head
around more of the codebase, and I happened to have one lying around,
so...  According to the docs the interface has not changed between the
Alea I and the Alea II so this driver should work for both, but I only
have a II.  I'm interested in writing drivers for other TRNGs if
anyone else finds it useful.

Tested under i386 and amd64.

I'm sure I've made many mistakes.  Comments and feedback most welcome.

Pax, -A

diff -Nurp src.orig/sys/arch/amd64/conf/GENERIC src/sys/arch/amd64/conf/GENERIC
--- src.orig/sys/arch/amd64/conf/GENERIC        Thu Apr  2 08:24:02 2015
+++ src/sys/arch/amd64/conf/GENERIC     Thu Apr  9 16:02:27 2015
@@ -271,6 +271,7 @@ uvideo*     at uhub?                # USB Video
 video* at uvideo?
 udl*   at uhub?                # DisplayLink USB displays
 wsdisplay* at udl?
+ualea* at uhub?                # Araneus Alea II USB TRNG
 
 puc*   at pci?                 # PCI "universal" communication device
 com*   at cardbus?
diff -Nurp src.orig/sys/arch/i386/conf/GENERIC src/sys/arch/i386/conf/GENERIC
--- src.orig/sys/arch/i386/conf/GENERIC Thu Apr  2 08:24:02 2015
+++ src/sys/arch/i386/conf/GENERIC      Thu Apr  9 16:02:01 2015
@@ -325,6 +325,7 @@ uvideo* at uhub?            # USB video
 video*  at uvideo?
 udl*   at uhub?                # DisplayLink USB displays
 wsdisplay* at udl?
+ualea* at uhub?                # Araneus Alea II USB TRNG
 
 puc*   at pci?                 # PCI "universal" communication device
 com*   at cardbus?
diff -Nurp src.orig/sys/arch/macppc/conf/GENERIC 
src/sys/arch/macppc/conf/GENERIC
--- src.orig/sys/arch/macppc/conf/GENERIC       Thu Apr  2 08:24:02 2015
+++ src/sys/arch/macppc/conf/GENERIC    Thu Apr  9 16:02:43 2015
@@ -292,6 +292,7 @@ utrh*       at uhidev?              # USBRH sensor
 utwitch* at uhidev?            # YUREX BBU sensor
 uow*   at uhub?                # Maxim/Dallas DS2490 1-Wire adapter
 onewire* at uow?
+ualea* at uhub?                # Araneus Alea II USB TRNG
 
 # USB Video
 uvideo* at uhub?
diff -Nurp src.orig/sys/arch/sparc64/conf/GENERIC 
src/sys/arch/sparc64/conf/GENERIC
--- src.orig/sys/arch/sparc64/conf/GENERIC      Tue Mar 24 06:00:39 2015
+++ src/sys/arch/sparc64/conf/GENERIC   Thu Apr  9 16:02:58 2015
@@ -245,6 +245,7 @@ ugold*      at uhidev?              # gold TEMPer sensor
 utwitch* at uhidev?            # UYUREX BBU sensor
 uow*   at uhub?                # Maxim/Dallas DS2490 1-Wire adapter
 onewire* at uow?
+ualea* at uhub?                # Araneus Alea II USB TRNG
 
 # USB Video
 uvideo* at uhub?
diff -Nurp src.orig/sys/arch/zaurus/conf/GENERIC 
src/sys/arch/zaurus/conf/GENERIC
--- src.orig/sys/arch/zaurus/conf/GENERIC       Sat Jan  3 15:24:19 2015
+++ src/sys/arch/zaurus/conf/GENERIC    Thu Apr  9 16:03:25 2015
@@ -135,6 +135,7 @@ umbg*               at uhub?                # Meinberg 
Funkuhren USB5131
 uow*           at uhub?                # Maxim/Dallas DS2490 1-Wire adapter
 onewire*       at uow?
 utwitch*       at uhidev?              # YUREX BBU sensor
+ualea*         at uhub?                # Araneus Alea II USB TRNG
 
 scsibus*       at scsi?
 sd*            at scsibus?             # SCSI disk drives
diff -Nurp src.orig/sys/dev/usb/files.usb src/sys/dev/usb/files.usb
--- src.orig/sys/dev/usb/files.usb      Thu Apr  2 08:24:02 2015
+++ src/sys/dev/usb/files.usb   Thu Apr  9 16:04:38 2015
@@ -195,6 +195,11 @@ device     utwitch: hid
 attach utwitch at uhidbus
 file   dev/usb/utwitch.c               utwitch
 
+# Araneus Alea II TRNG
+device ualea
+attach ualea at uhub
+file   dev/usb/ualea.c                 ualea
+
 # Ethernet adapters
 # ADMtek AN986 Pegasus
 device aue: ether, ifnet, mii, ifmedia
diff -Nurp src.orig/sys/dev/usb/ualea.c src/sys/dev/usb/ualea.c
--- src.orig/sys/dev/usb/ualea.c        Wed Dec 31 18:00:00 1969
+++ src/sys/dev/usb/ualea.c     Fri Apr 10 15:46:30 2015
@@ -0,0 +1,265 @@
+/* -*- mode:c; tab-width:8; indent-tabs-mode:t; c-basic-offset:8 -*- */
+/*
+ * Copyright (C) 2015 by attila <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Alea II TRNG.  Produces 100kbit/sec of entropy by black magic
+ *
+ * Product information in English can be found here:
+ *     http://www.araneus.fi/products/alea2/en/
+ *
+ * I only have an Alea II to play with but the documentation says
+ * that the Alea I is the same, so they should also work.
+ *
+ * I cribbed liberally from both the uow and umbg drivers, both of
+ * which are similar to this situation in different ways.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/timeout.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+
+#include <dev/rndvar.h>
+
+#define ALEA_IFACE     0
+#define ALEA_MSECS     10
+#define ALEA_READ_TOUT 1100
+#define ALEA_BUFSIZ    ((1024/8)*100)  /* 100 kbits */
+/*#define ALEA_DEBUG   1*/             /* comment out */
+
+#define OURNAME(x)     x->sc_dev.dv_xname
+
+struct ualea_softc {
+       struct  device sc_dev;
+       struct  usbd_device *sc_udev;
+       struct  usbd_interface *sc_iface;
+       struct  usbd_pipe *sc_ibulk;
+       struct  timeout sc_tout;
+       struct  usb_task sc_task;
+#ifdef ALEA_DEBUG
+       struct  timespec sc_tattach;
+       u_int32_t sc_nbits;
+#endif
+};
+
+int ualea_match(struct device *, void *, void *);
+void ualea_attach(struct device *, struct device *, void *);
+int ualea_detach(struct device *, int);
+void ualea_task(void *);
+void ualea_intr(void *);
+
+struct cfdriver ualea_cd = {
+       NULL, "ualea", DV_DULL
+};
+
+const struct cfattach ualea_ca = {
+       sizeof(struct ualea_softc),
+       ualea_match,
+       ualea_attach,
+       ualea_detach
+};
+
+static const struct usb_devno ualea_devs[] = {
+       { USB_VENDOR_ARANEUS,   USB_PRODUCT_ARANEUS_ALEA }
+};
+
+int
+ualea_match(struct device *parent, void *match, void *aux)
+{
+       struct usb_attach_arg *uaa = aux;
+
+       if (uaa->iface != NULL)
+               return (UMATCH_NONE);
+#ifdef ALEA_DEBUG
+       if (uaa->vendor == USB_VENDOR_ARANEUS)
+               printf("ualea: vendor 0x%x (%d) (ARANEUS) product 0x%x (%d)\n",
+                   uaa->vendor, uaa->vendor, uaa->product, uaa->product);
+#endif
+       return ((usb_lookup(ualea_devs, uaa->vendor, uaa->product) != NULL) ?
+           UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
+}
+
+void
+ualea_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct ualea_softc *sc = (struct ualea_softc *)self;
+       struct usb_attach_arg *uaa = aux;
+       usb_interface_descriptor_t *id;
+       usb_endpoint_descriptor_t *ed;
+       int ep_ibulk = -1;
+       usbd_status error;
+       int i;
+
+       sc->sc_udev = uaa->device;
+       error = usbd_set_config_index(sc->sc_udev, 0, 1);
+       if (error != 0) {
+               printf("%s: failed to set config: %s\n",
+                      OURNAME(sc), usbd_errstr(error));
+       }
+       error = usbd_device2interface_handle(
+                   sc->sc_udev, ALEA_IFACE, &sc->sc_iface);
+       if (error != 0) {
+               printf("%s: failed to get iface %d: %s\n",
+                   OURNAME(sc), ALEA_IFACE, usbd_errstr(error));
+               return;
+       }
+       /* Get endpoint (there can be only one) */
+       id = usbd_get_interface_descriptor(sc->sc_iface);
+       for (i = 0; i < id->bNumEndpoints; i++) {
+               ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
+               if (ed == NULL) {
+                       printf("%s: failed to get endpoint %d descriptor\n",
+                           OURNAME(sc), i);
+                       return;
+               }
+
+#ifdef ALEA_DEBUG
+               printf("%s: iface#%d endpoint#%d type %d\n",
+                   OURNAME(sc), i, UE_GET_DIR(ed->bEndpointAddress),
+                   UE_GET_XFERTYPE(ed->bmAttributes));
+#endif /* ALEA_DEBUG */
+
+               if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+                   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK &&
+                   ep_ibulk == -1) {
+                       ep_ibulk = ed->bEndpointAddress;
+#ifdef ALEA_DEBUG
+                       printf("%s: chosing ibulk endpoint#%d\n",
+                           OURNAME(sc), ep_ibulk);
+#else
+                       break;
+#endif /* ALEA_DEBUG */
+               }
+       }
+       if (ep_ibulk == -1) {
+               printf("%s: missing ibulk endpoint - cannot initialize\n",
+                   OURNAME(sc));
+               return;
+       }
+       /* Open pipe */
+       error = usbd_open_pipe(sc->sc_iface, ep_ibulk, USBD_EXCLUSIVE_USE,
+                   &sc->sc_ibulk);
+       if (error) {
+               printf("%s: failed to open bulk-in pipe: %s\n",
+                   OURNAME(sc), usbd_errstr(error));
+               return;
+       }
+       /* Get our task going */
+       usb_init_task(&sc->sc_task, ualea_task, sc, USB_TASK_TYPE_GENERIC);
+       timeout_set(&sc->sc_tout, ualea_intr, sc);
+       timeout_add_msec(&sc->sc_tout, ALEA_MSECS);
+#ifdef ALEA_DEBUG
+       nanotime(&sc->sc_tattach);
+       sc->sc_nbits = 0;
+#endif /* ALEA_DEBUG */
+}
+
+int
+ualea_detach(struct device *self, int flags)
+{
+       struct ualea_softc *sc = (struct ualea_softc *)self;
+
+       if (timeout_initialized(&sc->sc_tout))
+               timeout_del(&sc->sc_tout);
+       if (sc->sc_ibulk != NULL) {
+               usbd_abort_pipe(sc->sc_ibulk);
+               usbd_close_pipe(sc->sc_ibulk);
+               sc->sc_ibulk = NULL;
+       }
+
+       return 0;
+}
+
+void
+ualea_task(void *arg)
+{
+       struct ualea_softc *sc = (struct ualea_softc *)arg;
+       usbd_status error;
+       u_int32_t n, i;
+       int *buf;
+       struct usbd_xfer *xfer;
+#ifdef ALEA_DEBUG
+       u_int32_t kbps, dt, nbits;
+       struct timespec now;
+#endif /* ALEA_DEBUG */
+
+       xfer = usbd_alloc_xfer(sc->sc_udev);
+       if (xfer == NULL) {
+               printf("%s: could not alloc xfer\n", OURNAME(sc));
+               goto bail;
+       }
+       /* Is there any chance this buffer is not at least int-aligned? */
+       buf = usbd_alloc_buffer(xfer, ALEA_BUFSIZ);
+       usbd_setup_xfer(xfer, sc->sc_ibulk, NULL, (void *)buf,
+           ALEA_BUFSIZ, USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS,
+           ALEA_READ_TOUT, NULL);
+       error = usbd_transfer(xfer);
+       if (error) {
+               printf("%s: xfer failed: %s\n", OURNAME(sc),
+                   usbd_errstr(error));
+               goto bail;
+       }
+       usbd_get_xfer_status(xfer, NULL, NULL, &n, NULL);
+       if (n < sizeof(int)) {
+               printf("%s: xfer too short (%u bytes) - dropping\n",
+                   OURNAME(sc), n);
+               goto bail;
+       }
+#ifdef ALEA_DEBUG
+       else if (n != ALEA_BUFSIZ)
+               printf("%s: short read got %u bytes (exp. %u)\n", OURNAME(sc),
+                   n, ALEA_BUFSIZ);
+#endif /* ALEA_DEBUG */
+       n /= sizeof(int);
+       /*
+        * A random(|ness) koan:
+        *   children chug entropy like thirsty rhinos
+        *     surfing at the mall
+        *    privacy died in their hands
+        */
+       for (i = 0; i < n; i++)
+               add_true_randomness(buf[i]);
+#ifdef ALEA_DEBUG
+       nanotime(&now);
+       dt = now.tv_sec - sc->sc_tattach.tv_sec;
+       nbits = n * sizeof(int) * 8;
+       sc->sc_nbits += nbits;
+       kbps = dt ? ((sc->sc_nbits / 1024) / dt) : 0;
+       printf("%s: added %d bits: %dkbit/sec\n", OURNAME(sc), nbits, kbps);
+#endif /* ALEA_DEBUG */
+bail:
+       if (xfer)
+               usbd_free_xfer(xfer);
+       timeout_add_msec(&sc->sc_tout, ALEA_MSECS);
+}
+
+void
+ualea_intr(void *arg)
+{
+       struct ualea_softc *sc = arg;
+
+       usb_add_task(sc->sc_udev, &sc->sc_task);
+}

Reply via email to