Entropy as a Service
There’s been a lot of talk about Entropy as a Service lately and as someone with an interest in security it got me thinking why, what devices are really lacking entropy such that they’d risk pulling in someone else’s… IoT devices needing to generate Strong cryptographic keys on or shortly after boot, Gitlab runners (Docker containers where /dev/random is not passed from the parent). Sounds like there is a need.
OpenBSD has high quality entropy and plenty of it on a busy server with network services. So I thought I’d write up an EaaS offering using it. I started simply DDing bytes from /dev/urandom. OpenBSD chroots it’s HTTPD daemon but that’s ok a MAKEDEV in webroot/dev solved this first hurdle.
Second hurdle I just couldn’t get python to run in OpenBSD’s chroot - It just wouldn’t execute. OpenBSD Pioneered W^X memory pages way back in OpenBSD 3.3 Released 2003 but since 2016 it became mandatory. If a program can’t cope with this it has to sit on the naughty partition (/usr/local by default) with wxallowed flag set a mount time. Python is marked as needing mixed writable and executable memory (Actually I think this is only needed by a few third party modules). Two options, enable wxallowed in httpd’s chroot but that’s weakening the security on an internet facing service, Ruby then… Nope same problem.
Perl then and arc4random (no longer a need for a chroot /dev/urandom) via BSD::arc4random module. Perl has always had an eye on security, with -T it will help highlight, indeed stop you executing user input without first giving it a bit of a scrub.
API Implementation
There are some implementation variations and standards, so I thought I’d add another very simple API.
curl --retry 2 https://entropy.rob-turner.net/api/v2/
Epoch-Time:
example below, this delivers time over https which can be used to sanity check ntp results, although personally you are reinventing the wheel here as yet again OpenBSD has solved this problem with Constraints in OpenNTPD
curl -v https://entropy.rob-turner.net/api/v2/ >/dev/null
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-type: text/plain: charset=utf-8
< Date: Wed, 14 Aug 2019 19:06:04 GMT
< Epoch-Time: 1565809564
< Server: OpenBSD httpd
< Transfer-Encoding: chunked
curl -s --retry 5 "https://entropy.rob-turner.net/api/v2/" | base64 -d |ent
Entropy = 7.612282 bits per byte.
Optimum compression would reduce the size
of this 512 byte file by 4 percent.
Chi square distribution for 512 samples is 246.00, and randomly
would exceed this value 64.57 percent of the times.
Arithmetic mean value of data bytes is 129.9121 (127.5 = random).
Monte Carlo value for Pi is 2.870588235 (error 8.63 percent).
Serial correlation coefficient is 0.059459 (totally uncorrelated = 0.0).
You shouldn’t use this directly to make keys, instead you should combine it with other sources, hash and salt it then use that to stir your entropy pool, for example see below where I combine it with data from random.org which gets it’s entropy from atmospheric noise. This example is from a GitLab runner I setup that’s creating/renewing SSL Certificates.
#!/bin/sh
#disk io provides good entropy
find / >/dev/null 2>&1
SALT=$(dd if=/dev/urandom bs=64 count=1 2>/dev/null)
echo got salt
RAND=$(curl -s --retry 5 'https://www.random.org/cgi-bin/randbyte?nbytes=512')
BBCN=$(curl -s --retry 5 "http://feeds.bbci.co.uk/news/rss.xml")
GITL=$(git log | sha512sum - | cut -d ' ' -f 1)
EAAS=$(curl -s --retry 5 "https://entropy.rob-turner.net/api/v2/" | base64 -d)
DATA=$(echo "${SALT}${EAAS}")
RD=$(echo "${GITL}${RAND}" | sha512sum - | cut -d ' ' -f 1)
BBC=$(echo "${SALT}${BBCN}" | sha512sum - | cut -d ' ' -f 1)
echo $DATA >/dev/random
echo $RD >/dev/random
echo $BBC >/dev/random
# as does network timing
ping -i .2 -c 10,1 gateway >/dev/null