Spreading entropy with rngnet, a first software edition

Filed under: Hardware, JWRD, Networks, News, Philosophia, Software — Jacob Welsh @ 05:21

A couple years ago (August 2021) I was building a cluster of small machines for a hosting installation. It could have all fit on one server, but the thinking went that some applications handle more sensitive data than others, requiring different levels of access, while none of the current software-based approaches to compartmentalizing actually work. Virtualization is only virtual, containers don't contain, partitions don't partition, and jails are jailbroken. Add in memory chips that rowhammer and processors that speculatively execute - execute the user, that is, and without due legal process! - and it can't even be blamed on or fixed by software anymore. No, if you want true separation of concerns then you need separate physical machines, and mind how they communicate too, lest they become in fact just that much costlier a pool of well-shared bits.

As all security online rests on the foundation of large unpredictable numbers aka entropy, and JWRD happens to have a small stockpile of hardware entropy devices, we naturally included one in the deal; but since they remain out of production we couldn't justify any more than one for this deployment. So how to make the most of it? By drilling a (hopefully) small hole in that wall of "how they communicate" so that one entropy-rich machine can spread the love to everyone in the neighborhood. At worst, you're no worse off than the alternatives of a single machine or a bunch of pseudorandom software generators of pseudoscience; and at best you're significantly better off.

How hard could it be to implement? As it often seems to go, at core it's quite simple and most of the work is in the periphery. It's a perfect fit for UDP, working in much the same way as the hardware does: entropy is gathered into a suitably sized buffer; once full, it's sent off to the recipient - in this case, one of possibly many in rotation. The sender doesn't even need to care what happens to the packet; if it doesn't make it to the receiver, no big deal, maybe the next one will. If the network is so flooded that nothing gets through, the sender isn't in a position to fix it anyway.

I felt a little dirty about the whole thing - compromise! cheapening! not the Right Thing! - and this may have contributed to the delay in publication. But as work progressed some ancillary benefits came to light, at least in the realm of possibilities opened up:

jfw: I realized a couple upsides to having rngnet, even past the workaround stage: getting entropy to the ERLs which otherwise don't have any way to get at an FG; it's helpful just for feeding the local system (compared to just cat /dev/tty?? > /dev/urandom) as it provides packet counters that can be monitored for health; and it provides a basis for adding fancier monitoring like statistical entropy measurement.
jfw: you could essentially combine the sender & receiver loops, cutting out the UDP part, for local usage; or just leave it as is if not too worried about compromised processes dumping in pseudo-entropy.
dorion: <jfw> I realized a couple upsides to having rngnet -- nice upsides indeed.

The flooded network or denial-of-service condition is much the same as if the hardware source fails: entropy starvation, reversion to self-deception, a little red light in a black box in a locked room somewhere, silent, unnoticed. Better have something in your higher level process to do the noticing, on the receiving end; and that holds with or without the networked aspect.

Between the first internal version and today's release came a number of improvements:

  • More useful packet counters, showing delta since last reading rather than just totals ;
  • Build fix for glibc systems (prior work having been just on Gales) ;
  • Packaging refinements and expanded documentation (README file) ;
  • The afore-teased statistical monitoring.(i)

The result is 546 lines (raw) of tight C code in my usual style, aiming for POSIX-portability and no bugs, distrusting of "helpful" but unnecessary libc abstraction layers. The only such dependency brought in for the user's convenience is hostname lookup in the sender program, so you can use your hosts file (or even DNS, sure) to specify recipients rather than entering bare IP addresses.

Meanwhile the state of the art in software publication advanced, and having got a little practice with the tools already, I took advantage of this as a first tidy home-grown project to release in the new mode. This then maintains the "reference code shelf" versus "loose code" distinction on my blog, where the reference shelf contains cryptographically verifiable patches from reputable sources and contents are mirrored under the code viewer (only now holding a mix of data in VaMP and the old V formats). There was just one structural point with which the VaMP tool took issue in my codebase, which led to a constructive discussion(ii) and a first example of a services index file for Gales packages.


$ rngsend -d /dev/ttyUSB0 &
[1] 24040
$ sender started
$ rngrecv -d /dev/urandom
receiver started
STAT ok=0/0 weak=0/0 weak_rate=0 recv_err=0/0 bad_size=0/0
STAT ok=834/834 weak=5/5 weak_rate=0 recv_err=0/0 bad_size=0/0
STAT ok=834/1668 weak=1/6 weak_rate=6 recv_err=0/0 bad_size=0/0
STAT ok=834/2502 weak=1/7 weak_rate=0 recv_err=0/0 bad_size=0/0
STAT ok=834/3336 weak=3/10 weak_rate=3 recv_err=0/0 bad_size=0/0
STAT ok=833/4169 weak=1/11 weak_rate=1 recv_err=0/0 bad_size=0/0


In tar format for ease of deployment: rngnet-2.tar.gz (PGP signature)

In VaMP software edition format:

And in the code viewer: coming soon.

  1. Based on counting frequencies of 4-bit blocks. I'm famously stupid in stats - skipped it as an engineering school elective after having struggled enough through Probability - so I cracked open the textbook hoping to come up with some kind of expected results based on distributions and chi-squares and stuff. Got bored quickly and realized I could just calibrate the sensitivity based on good entropy data, since the exact threshold of "failure" here is pretty subjective anyway. Take that, Pearson! [^]
  2. Jacob Welsh: on the VaMP effort, I'm still tripping on the "control reversal" of new-to-old argument order in diff & add (i.e. my greater practice with the prior tools is working against me), and the notion that directories containing non-empty subdirs can still be "empty" for lack of text nodes at that branching level :/
    Jacob Welsh: in this case it comes perhaps from the daemontools design: a service is defined by a directory (non-empty, of course); a collection of more than one service - whether as deployed on a system or in this case as provided in a codebase as examples - logically deserves a directory to hold together those objects of the same type, separate from program code or docs etc. What else then would go in that directory besides a useless dummy file just to satisfy the formal requirements of the tool?
    Jacob Welsh: another result, fwiw, would be that I can't anymore give "cp -r service/* /etc/svc/" as a generic initial installation instruction and have to list them explicitly, or something

    Diana Coman: on the daemontools design, from the description you give, to my mind the logical thing that actually *should* rather go in that 'holding together' directory is exactly what is the criteria for that particular grouping/collection i.e. the reason for it to be in the first place and as such something that I think is a gain to have in fact (possibly even to... have to have).
    Jacob Welsh: like a file saying "these are example daemontools services"?

    Diana Coman: for the cp -r service/* /etc/svc/ , I'm possibly not familiar enough to fully get it - what's the trouble now?
    Jacob Welsh: that there's now an explanatory file which doesn't itself match the criteria for being in the collection (is not itself a service) but would get copied with the rest via the wildcard

    Diana Coman: in the one with example services, I guess so. The more specific/meaningful text in there, the more useful in the long run in my experience so dunno, what groups of services are there in the first place and/or what's the differentiating criteria in fact? (eg. are these example services perhaps literally not mandatory, can delete them without much loss ?)
    Diana Coman: ah, wait, so the situation is that they come grouped in "collections" but then these collections are in fact...dumped since all go into the same bin anyway?
    Diana Coman: kind of goes to show that the original 'collection' dir is actually not all that meaningful/needed aka... 'empty' from a meaning pov, huh?

    Jacob Welsh: well, in gales I have one place for all available services on the system (which may or may not be active at a given time). this software package provides a couple new ones.
    Jacob Welsh: you don't have to use the services at all, you could just run the programs in a screen or something but I find them helpful so I provide them.

    Diana Coman: yes, but I don't quite follow the grouping/collections which seem to be somehow needed/meaningful in some context (deployment?) but then considered spurious/not meaningful in the actual use context or not sure what I'm not getting there.
    Diana Coman: if in gales they are all in /etc/svc, then why can't they similarly be in /bla/svc ?

    Jacob Welsh: bla would represent the specific services provided by this package?
    Diana Coman: I guess so, i.e. gales keeps services in its svc dir, the package keeps the services it provides in its own svc dir, if deploying these services, copy all from its svc to gales' svc and what other collection dir is needed?

    Jacob Welsh: not sure how you mean dumped/spurious, but the point of doing the copying is that the contents are a matter of system configuration, not one-fits-all so copy from my reference tree to your own and do the editing there
    Jacob Welsh: there's no third collection dir

    Diana Coman: so what you are saying is that it's that svc dir that normally contains one dir for each service and it's those you want copied but now it ends up needing a text file in there as well, which then gets in the way because it gets copied to gales' etc/svc where it's not wanted/needed/desirable?
    Jacob Welsh: yes. though I was thinking it could be made somewhat more useful like an index "the services for xyz are a,b,c" with a specific name so it's at least distinct if it ends up in /etc/svc
    Diana Coman: exactly
    Diana Coman: wouldn't it make sense to basically have in gales' svc a notion of what was copied in there in the first place?
    Diana Coman: and this is why I was saying that it seemed like at the copy to gales, the original collection/grouping was somehow suddenly deemed spurious since they were dumped together without any 'collection' but even without trace at all as to what was thus collated
    Diana Coman: which is pretty much the definition of "don't care about that grouping criteria", no?

    Jacob Welsh: hm, that's where I get confused because if the criterion is "services" then it's still being maintained
    Diana Coman: lol, but it's not that, it's exactly "these are package x's services" because a package groups services like that, i.e. its own vs any others, no?
    Diana Coman: and yes, an index seems most appropriate, something like package_name_services.idx with a listing of what these are
    Diana Coman: which I'd say is even useful to have in gales/svc since one can then at least know what was kept/copied /etc
    Diana Coman: possibly that idx would need the version of the package in name, too
    Diana Coman: or in other words, if there is meaning to that grouping 'these are services from package x' and it's still valuable in the gales context, then it makes sense to have that index file in /etc/svc. If it's meaningful only in the package's own context i.e. "these are my services" then it doesn't get copied or it gets deleted.

    Jacob Welsh: in some cases, like that /usr/bin collection of program names, I like having that information explicit in the filesystem structure (there, in the form of symlinks into /gales/pkg/xyz/). for services I haven't gone that way I suppose because I see it more fundamentally up to the sysadmin/operator, what programs he wants to run & how. you can define your own services without any "package ownership". I guess the informal (not mechanically enforced) index file could fit well there, as the reminder if not the "proof" of where those services came from
    Jacob Welsh: then again you can write your own scripts without "package ownership" too so that part of the argument doesn't seem to do much.

    Diana Coman: I don't think it reduces in any way the freedom of the sysadmin/operator to add/remove/have in there whatever services they want, does it?
    Diana Coman: and yes, it's not a proof, only a helpful record as to what package(s) were at least at some point brought in and what they offer in full (not like it needs to be updated if one keeps for instance just one service from the list - it's about what the package offers, not about what that specific instance of gales ends up using or even keeping around)
    Jacob Welsh: yeah, sounds good so far.
    Diana Coman: cool [^]

  3. I'm thinking of this as the Vivian Sporepress key, after my Eulora2 character, since that's the environment the tool is currently available in. It's not up to the operational security standards of my PGP identity as I don't have a secure machine with the requisite software, new and GNATty as it is. But you gotta start somewhere. Or maybe I should hide out in the shadows a few years tinkering on compilers and faraday cages so as to have a fully secure identity before investing anything in it ? [^]


  1. Congrats on first published software edition! Working all fine here:

    The code in jfw_rngnet/ matches a signed software edition and has the following version description in its manifest.vamp:

    826750 rngnet_v2 jfw Initial patch for RNG network facilities, dubbed rngnet version 2; includes rngsend and rngrecv in C with a /package installation script, README and example services.

    The software edition producing this exact code version is:
    authored by d07c062cfc823db4e7d36979edd4d9fb
    signed by d07c062cfc823db4e7d36979edd4d9fb

    Regarding keys, it's worth noting that the Eulora2 key gives the in-game ID and as such it comes with its own use-environment as it were but you can use VaMP to create in fact any other number of RSA keys for other uses that might come with different security requirements. Anyways, for now it's actually good to have that Vivian Sporepress pub key, as it means we can finally switch from gpg-grams to vamp-grams, too!

    Comment by Diana Coman — 2024-01-29 @ 09:58

  2. Regarding keys, it's worth noting that the Eulora2 key gives the in-game ID and as such it comes with its own use-environment as it were but you can use VaMP to create in fact any other number of RSA keys for other uses that might come with different security requirements.

    Ah, it's not literally the character's key for the game, I had a looser association in mind. Indeed I created it in a separate environment, on a no-GUI VM even.

    Comment by Jacob Welsh — 2024-01-29 @ 19:31

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by MP-WP. Copyright Jacob Welsh.