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);
+}