seedd(1) read entropy from BitBabbler hardware RNG devices

SYNOPSIS

seedd [options]

DESCRIPTION

The seedd program can be run as a foreground process or as a daemon to collect entropy from one or more BitBabbler devices, either streaming it to stdout for general purpose use, making it available on a UDP socket, or directly seeding the kernel entropy pool with it on demand.

USAGE

The number of configurable options for seedd has now outgrown what most people will care about or want to use, which would normally be less than ideal for something like this, but it does have a rather diverse range of user needs, and it is important that we support those well.

Unless you fall into the special use category, then the following examples are probably about all (or still more than) you might ever need:


  Show all available BitBabbler devices, in detail:


    seedd -sv   (or --scan --verbose)


  Output 1 million bytes to a file, drawn from all available devices:


    seedd -b 1000000 > random-bytes.out


  Stream entropy continuously to stdout (with no control socket):


    seedd -o -c none | your-thing-reading-stdin


  Run as a daemon, feeding entropy to the OS kernel pool:


    seedd -k -d

To read from only specific devices, add the --device-id option too.

OPTIONS

The following options are available:

-s, --scan
Scan the system for available BitBabbler devices, reporting them in a human readable format.

--shell-mr
Scan the system for available BitBabbler devices, reporting them in a machine readable format that is suitable for importing into shell scripts.

-i, --device-id=id
Select a BitBabbler device to read from by its unique ID. If no devices are explicitly specified then the default is to use all of them (including any devices that may be plugged in at a later time).

This option may be passed multiple times to attach to multiple devices. It is not an error to specify a device that is not currently present on the system. If hotplug support was enabled at compile time and available on the system at runtime, then such devices will be added to the pool at runtime if they are later plugged in.

The id may be the device serial number, or its logical address in the form:


   [busnum:]devnum

or on systems where knowing the USB topology is supported, its physical address in the form


   busnum-port[.port ...]

For a logical address the busnum part is optional, but if devnum is not unique across all buses, then exactly which device will be selected if it is not fully specified becomes a matter of chance. All of the available IDs which can be used to refer to a device will be reported by the --scan option. Bus, device, and port numbers are expected to be decimal integers.

The logical address isn't usually very useful to use when hotplug activity is expected, since it is allocated dynamically and is 'unpredictable' for most purposes here.

-d, --daemon
Fork to the background and run as a daemon process. If this option is not specified then seedd will remain in the foreground.

-b, --bytes=n
Send n bytes of entropy to stdout. The process will exit when that is completed. This option will be ignored if either the --kernel or --udp-out options are used. A suffix of 'k', 'M', or 'G' will multiply n by the respective power of two. If this option is not used, then entropy will be output until the process is explicitly terminated (or receives SIGPIPE). Passing this option implies --stdout, and also --control-socket=none unless the control socket option is explicitly passed to enable it.

-k, --kernel
Feed entropy directly to the kernel /dev/random pool on demand.

-u, --udp-out=host:port
Bind a UDP socket to the given address, which clients can use to request blocks of entropy directly from the internal pool. The host part can be a DNS hostname or address literal. If an IPv6 address literal is used it should be enclosed in square brackets (e.g. [::1]:2020 to bind to port 2020 on the local IPv6 interface). The port can be a port number or a service name (as defined in /etc/services or other system name-service databases which are queried by getaddrinfo(3)).

To obtain entropy from this port, write the desired number of bytes to it as a two-octet network-order short integer. It will reply with a datagram containing the requested number of bytes of entropy. Requests for 1 to 32768 bytes will be honored as soon as there is sufficient entropy in the internal pool to do so. Requests outside of that range are invalid and will simply be ignored. Note that no access control is placed on the socket, so if it uses a publicly accessible address anyone will be able to read entropy from it (and potentially to use it as a traffic amplifier if requests use a forged source address).

This facility is mainly provided for use on operating systems like Windows, where the native interfaces may be of questionable usefulness or quality and cannot be audited - but it is generic and so can be used on any system where obtaining entropy directly from the BitBabbler devices might be desirable. On Linux systems we do recommend using the system /dev/(u)random interfaces though, since that will mix in other entropy and transparently benefit all existing applications. They aren't mutually exclusive though, you can use both this and the --kernel option together too.

-o, --stdout
Stream entropy directly to stdout.

-P, --pool-size=n
Specify the size of the internal entropy pool. Entropy read from a BitBabbler will gather in that pool after health and sanity checking. When multiple BitBabbler devices are in use, entropy from each group of devices will be mixed into it. Entropy read from stdout, or the UDP socket, or delivered to the kernel will be drawn from this pool. Fresh entropy will continue to be mixed into it while it is not being drained faster than it can be filled. The default pool size is 64kB, which provides a reasonable balance between what a single BitBabbler running at 1Mbps can fill completely about twice per second, and what most reasonable consumers might ever want to draw from it 'instantly'. There probably aren't many good reasons to make it much larger, but making it smaller will increase the number of input bits mixed into each output bit if the pool is not being drained completely faster than it can fill. We do not rely on this mixing to obtain good quality entropy from each BitBabbler device but it doesn't hurt to be mixing more good entropy into it while the demand is exceeded by supply.

-G, --group-size=group_number:size
Set the size of a single pool group. When multiple BitBabbler devices are available, there is a choice of whether to optimise for throughput or for redundancy. For example a pair of devices both running at 1Mbps can together produce an effective throughput of 2Mbps of entropy if their streams are output independently of each other, but they can also be mixed together in parallel to provide a stronger guarantee of entropy at 1Mbps with the stream being at least as unpredictable as the most unpredictable device. With more than two devices a combination of both strategies may be used.

Devices that are placed in the same group will not add entropy to the pool until every device in that group has contributed at least size bytes to it. If the devices are not running at the same bit rate, the faster device(s) will continue to mix entropy into the group until every device has contributed. This option enables configuration of that block size. The group_number is an arbitrary integer identifier (which will be passed to the --group option for the device(s) to add to it). The size may be followed by a suffix of 'k', 'M', or 'G' to multiply it by the respective power of two. The group size will be rounded up to the nearest power of two. Default is for groups to be the same size as the pool, but they may be set either smaller or larger than it if desired. The two values are separated by a colon with no other space between them.

-c, --control-socket=path
Set the filesystem path for the query and control socket that may be used to obtain information and statistics about the performance of the BitBabbler devices and control some aspects of the running process. The special value of 'none' may be passed to disable the creation of a control socket. Mostly this option is useful if you have more than one seedd process running which are each controlling different sets of devices.

On systems where unix domain sockets are not available, or if you wish to make the control socket visible to other machines on the network, you can instead use a string of the form tcp:host:port, where the host and port parts are as described in the --udp-out option above. Note that there is no access control when a TCP socket is used, so any user on any machine that is able to connect to this port will be able to do anything the control socket allows.

--socket-group=group
Permit access to the control socket by members of the named group. If this option is not specified, then only the owner of the seedd process will be able to connect to that socket. The adm group may be a reasonable choice to set this to on many systems (it is the default used by the Debian package init scripts), but you are free to use any group for this which best suits local access policies.

This option has no effect if a TCP port is used for the control socket instead of a unix domain socket path.

--watch=path:delay:block_size:bytes
Monitor an external device. This option does not directly effect the operation of collecting entropy from BitBabbler devices, or contribute in any way to the entropy that is output, either to stderr or the kernel. What it does do is leverage the quality assurance and health checking algorithms, and the trend monitoring functionality that this software provides, to also permit continuous supervision of other sources which are expected to be statistically random.

For example it can be used to regularly sample from /dev/urandom or even from /dev/random to ensure the quality of their output is really what you expect it to be. There's little point to putting the most awesome entropy that the universe can conjure in, if what's coming out and feeding the applications that are consuming it is totally predictable garbage.

If this is used to monitor a limited source of blocking entropy, such as /dev/random then you'll want to be judicious in selecting the rate of reading from it, so as not to consume all the available entropy that you were aiming to gain by feeding it from a BitBabbler in the first. If it's reading from an 'unlimited' source backed by a PRNG, such as /dev/urandom, then the only real consideration is how much of the other system resources do you want to consume in drinking from the firehose.

The path is the filesystem path to read from, it can be anything which can be opened and read from like a normal unix file. The delay is the amount of time, in milliseconds, to wait between reading blocks of data from it. The block_size is the number of bytes to read in a single block each time the watch process wakes up to read more. The total amount of data to read can by limited to bytes, once that limit is reached, the watch process for path will end (but all other processing will continue as per normal).

All qualifiers except the path are optional, and separated by colons with no other space between them, but all options must be explicitly set up to the last one that is provided. The delay may be followed by a suffix of 'k', 'M', or 'G' to multiply it by the respective power of 10, or by 'ki', 'Mi', or 'Gi' for powers of two if you're into that kind of thing. The block_size and bytes options may be similarly suffixed, but like all good sizes on computers are always a power of two if so.

--kernel-refill=sec
Set the maximum time in seconds before fresh entropy will be added to the OS kernel pool, even when it has not been drained below its usual refill threshold. This option has no effect unless the --kernel option is being used.

When feeding the OS pool, seedd will be woken to immediately add more entropy to it any time that it falls below the configured minimum watermark (which on Linux is set by /proc/sys/kernel/random/write_wakeup_threshold and can be configured persistently in /etc/sysctl.d/bit-babbler-sysctl.conf).

In addition to that, it will also wake up periodically to mix fresh entropy into the OS pool even if it is not being consumed (testing that the output of the device is still passing all the QA testing in the process). This option configures how long it will wait since the last time fresh entropy was added before doing that. If set to 0, then we will never add more entropy unless explicitly woken by the OS pool falling below its watermark. The default is 60 seconds, and there probably aren't many reasons to reduce that, but you may want to increase or disable it on low power systems which you don't want to be waking up just to do this.

The main downside to increasing it is that on relatively quiet systems it may take (significantly) longer for the long term QA tests (in particular the 16 bit tests) to accumulate enough results for analysis, and you lose some of the confidence that comes with a higher rate of continual sampling from the device. This option lets you choose the right balance for your own use. If unsure, leaving it at its default setting is probably the right answer.

-v, --verbose
Make more noise about what is going on internally. If used (once) with the --scan option this will show more information about each device, but otherwise it's mostly only information useful for debugging. It may be passed multiple times to get swamped with even more information.

-?, --help
Show a shorter version of all of this, which may fit on a single page, FSVO of page size.

--version
Report the seedd release version.

Per device options

The following options may be used multiple times to individually configure each device when more than one BitBabbler is available. If passed before any --device-id option, then they set new default values which will apply to every device. If passed after one of those options they will only be applied to the immediately preceding device.

-r, --bitrate=Hz
Select the device bitrate in bits per second. The available bitrates are determined by an integer clock divider, so not every rate is exactly achievable. An unsupported rate will be rounded up to the next higher rate. For convenience the rate may be followed by an SI multiplier (eg. 2.5M for 2500000).

--latency=ms
Override the calculated value for the USB latency timer. This controls the maximum amount of time that the device will wait if there is any data in its internal buffer (but less than a full packet), before sending it to the host. If this timer expires before a packet can be filled, then a short packet will be sent to the host. The default value is chosen to ensure that we do not send more short packets than necessary for the selected bitrate, since that will increase the number of packets sent and the amount of CPU time which must be spent processing them, to transfer the same amount of data.

Unless you are experimenting with changes to the low level code, there is probably no reason to ever use this option to override the latency manually.

-f, --fold=n
Set the number of times to fold the BitBabbler output before adding it to the pool. Each fold will take the first half of the block that was read and XOR it with the bits in the second half. This will halve the throughput, but concentrate the available entropy more densely into the bits that remain.

There are two main things this is expected to do based on the BitBabbler design. It will better mix the low-frequency noise that is captured with that of the higher frequencies, allowing it to sample at higher bitrates without narrowing the noise bandwidth available to influence adjacent bits. It will help to break up any transient local correlations that might occur in the physical processes from which ambient environmental noise is collected.

Folding should never reduce the real entropy of each sample, but when all is working exactly as it should, it may not do anything to increase it either. Mathematically, an XOR summation is expected to exponentially smooth any bias in a stream of independent bits, with the result having at least as much entropy as the least predictable of either of the two inputs (in the same way that a one time pad is no less secure despite the plaintext having much less entropy than the pad does).

-g, --group=n
The entropy pooling group to add this device to. See the --group-size option for a discussion of pool groups. You do not need to declare or define a group in any way before using this option, devices that have the same group number specified will be simply be grouped together. By default, all devices are placed in group 0 if this is not set explicitly for them.

The group 0 is special in that its size can be set explicitly, but it does not wait for all devices in it to have contributed entropy before mixing into the common pool, which is functionally equivalent to all of those devices being placed into separate groups that are the same size.

Normally if a single device in a group fails QA testing, then the entire group will stop contributing to the pool until it is removed or further extended testing confirms that failure to be an anomaly and not a persistent condition. For group 0 (and devices in other separate groups), a failed device will not prevent the remaining devices from continuing to contribute entropy if their own output is still passing the QA testing.

--enable=mask
Select a subset of the generators on BitBabbler devices with multiple entropy sources. The argument is a bitmask packed from the LSB, with each bit position controlling an individual source, enabling it when set to 1.

--idle-sleep=initial:max
This option permits tuning how the devices back off from generating entropy at the maximum rate, when it is not being consumed from the output pool. When the output pool is not full, entropy will be read from the devices as quickly as possible to try to refill it. Once it is full, they will begin to be throttled according to the following algorithm:

The initial value is the number of milliseconds to sleep when the output pool first becomes full again. If this value is 0, then the device will immediately remain idle until the output pool is no longer full. Otherwise, reading from the device will pause for either this number of milliseconds, or until the pool is no longer full, whichever comes first. If that timeout expires and the pool is still full, another block of entropy will be generated and mixed into the pool, then the timeout will be doubled. This process will continue until the timeout reaches the max value (which is also in milliseconds), at which point it will not increase any further. The device will always be woken immediately any time the output pool is not full, and the timeout cycle will begin again from the initial value each time that occurs.

As a special case, if the max value is set to 0, with an initial value that is not zero, the exponential back off will occur as above until the timeout reaches or exceeds 512 ms, at which point further activity will again be suspended indefinitely until the output pool is no longer full. This allows for a mode of operation where the device will still go into a hard suspend when no entropy is being consumed from the output pool, but only after mixing several blocks of entropy from each device that is configured this way into it.

The default configuration used if this is not set explicitly is initial=100 and max=60000. Usually the only reason to change this is if you are trying to minimise the power usage on a low power system which you don't want continually waking up to generate entropy that nothing is using. For that use, if you are feeding the OS kernel pool, you will probably also want to set the --kernel-refill option to a suitable value, since it will cause the devices to wake up independently of what is set here (by reading from the output pool, making it be no longer full). Dialling the verbosity up to level 6 (with -vvvvvv) while tweaking this will let you watch how the reads from the devices are actually throttled.

When setting this, either of initial or max may be omitted (in which case they will retain their default value), but the ':' must always be included. It probably doesn't make a lot of sense to set this differently for each device (especially not for devices which are grouped together), but that is permitted if you really have some reason to want to do that.

--suspend-after=ms
Set the minimum expected device idle time for which we should allow the device to be suspended. On Linux, USB devices that are idle can automatically be suspended into a low power state, but in order to qualify as being 'idle' for that purpose, we need to release our claim on the device. Full details of the OS part of that can be found here:

https://www.kernel.org/doc/Documentation/usb/power-management.txt

The default is 0, which means seedd will never release a device it has claimed. The benefit of this is that no other process can claim it while it is released (accidentally or otherwise), which would prevent us from being able to use it again when we do require entropy from it. It also ensures there is minimal latency when we are woken up to read entropy from it again.

Setting this to a value greater than zero means that when the output pool is full, and we are expecting to sleep for at least that amount of time before reading from the device again, then the claim on the device will be released, and the OS will be able to suspend it until we need it again. If the pool is drained and requires more entropy before that time, then we will still reclaim the device immediately and begin reading from it again, but there will be a small amount of additional latency while it wakes up and is reinitialised for use. This option should usually be set in conjunction with --idle-sleep and --kernel-refill which control how often the device will be woken again to refresh the entropy pools when it might otherwise have remained idle. If they never allow it to sleep for longer than this time, then this option will have no effect.

It probably doesn't make much sense to set this below about 10000 (10 seconds) otherwise the overhead of releasing, reclaiming, and reinitialising the device might actually use more power than suspending it saves. And it definitely doesn't make much sense to set it to a value less than what is configured for the autosuspend_delay_ms option in the kernel, since while we will release the device any time that we expect to sleep for this long (regardless of whether we actually do or not), the kernel will not actually suspend it until the autosuspend_delay_ms time has elapsed after we have released it. So if it doesn't get to actually suspend it, we would just be chewing extra CPU cycles, and adding extra latency to obtaining entropy when it is needed, for no net gain.

--low-power
This is a convenience option, which is equivalent to setting:


 --kernel-refill=3600 --idle-sleep=100:0 --suspend-after=10000

And which in turn means:

We will wake up to mix more entropy into the kernel pool at least once an hour (though it is likely that most systems will already drain it below its threshold and so wake us to refill it before that time expires anyway).

We will mix at least 6 blocks of fresh entropy into the seedd output pool each time we are woken, before suspending indefinitely again (until either we are woken by the kernel needing entropy or by the timeout above expiring, or until something else consumes entropy from the output pool - such as from the UDP socket if that is enabled). This is based on doubling the initial --idle-sleep timeout each time the output pool remains full, until we exceed the minimum amount of time that really will perform a sleep (512ms), and then sleeping until explicitly woken again after that.

We will release the device, giving the OS the opportunity to suspend it, each time it does become fully idle (since an indefinite sleep is considered to be longer than any fixed amount of time).

Any or all of those options may still be customised by passing them explicitly after this option on the command line (in the same way that passing them twice would also override the first instance).

This isn't necessarily the configuration offering the lowest possible power consumption, but it's intended to strike a reasonable balance for systems where keeping idle power consumption low is more a important concern than continually mixing in additional fresh entropy or minimising the latency if demand for entropy suddenly surges (which is what the normal defaults are more oriented toward). At the very least it should be a reasonable starting point to begin experimenting from on low power systems.

--no-qa
Disable gating entropy output on the result of quality and health checking. You pretty much never want to use this unless you are generating streams to stdout for no other reason than to analyse their quality with some other tool, such as dieharder(1) or the NIST test suite or similar. For that type of use we definitely don't want to be filtering out blocks which have already failed our own internal quality analysis, otherwise the value of such testing will be almost as tainted as that of the people who say "after whitening our RNG with SHA-1 it now passes all of the statistical tests perfectly!", and there's already more than enough fossils in that tarpit.

It is not possible to disable this for data which is passed directly to the kernel entropy pool, there is absolutely no reason to ever want to do that, and this does not actually disable the QA checks from being performed (so the results of them will still be seen in the monitoring output and can generate external alerts if this mode was entered 'by accident'). It just permits any failing blocks to still pass through to stdout, so other tools can heap all the scorn on the output that it deserves if it is failing.

CONTINUOUS MONITORING

The query and control socket enables device performance and QA statistics to be examined in real-time. The bbctl(1) tool can be used to produce human readable reports on demand from the information it provides, but it can also be queried directly by other tools that want that information in a more machine readable form (see the json_protocol document for a full description of that). For users of munin, a plugin is provided which will continuously graph the status of each device, and which can be used to trigger an alert if an abnormal condition occurs.

The munin plugin requires the perl JSON::XS module (provided by the libjson-xs-perl package on Debian systems), and it must be explicitly enabled on each system where it is desired to run. Typically that will require doing something like this:

 # munin-node-configure --shell
 # ln -s /usr/share/munin/plugins/bit_babbler /etc/munin/plugins/bit_babbler
 # service munin-node restart

If munin-node-configure does not report that plugin autoconfiguration succeeded, the most likely reason is that JSON::XS is not available. There are a few options to configure the plugin's behaviour, these are all documented in /etc/munin/plugin-conf.d/bit-babbler (where they should be set if desired). The munin-node service needs to be restarted for changes to its plugins to take effect.

FILES

/etc/default/seedd
The optional configuration overrides for the init script, used when automatically starting as a daemon at system boot time.

/var/run/bit-babbler/seedd.socket
The default control socket path if not explicitly specified.

/etc/sysctl.d/bit-babbler-sysctl.conf
Configuration for kernel system variables. Mostly used to adjust the low-water mark for the kernel entropy pool, which controls when it will wake seedd for an immediate top up.

/lib/udev/rules.d/60-bit-babbler.rules
The default udev(7) rules granting direct device access to users in the group bit-babbler, enabling USB autosuspend when the device is idle, and invoking bbvirt to handle device hotplug for virtual machines. These can be overridden by creating /etc/udev/rules.d/60-bit-babbler.rules and populating it with your own rules.

/etc/munin/plugin-conf.d/bit-babbler
The munin-node configuration for continuous monitoring.

AUTHOR

seedd was written by Ron <[email protected]>. You can send bug reports, feature requests, praise and complaints to [email protected].