Improve entropy with PRG310 Hardware RNG on APU1D

Hello Community,

I just bought the PRG310 Hardware-RNG from https://www.ibbergmann.org to improve my entropy. To save external USB ports I got the PRG310-51, which can be directly connected to the internal USB-port on the motherboard, but there are also models with regular external USB connectors. To order simply send an email over the webpage. Shipment was very fast. :smile:

Following some posts in the old ipfire forum (https://forum.ipfire.org/viewtopic.php?f=17&t=12487) I just wanted to share how I installed the device:

0. Plug in PRG310 :crazy_face:

1. Create start script (e.g. under /root)

vi /root/startp310.sh

copy following content inside the script:

#!/bin/bash
#Log function
logme () {
  logger -t ipfire p310:$1
  echo "$1"
}
logme "HWRNG detected"
logme "setup stty"
/bin/stty raw -echo -ixoff -F /dev/hwrngtty speed 921600 > /dev/null
logme "execute start command"
/bin/echo -n "4b" >  /dev/hwrngtty

remark: in the last line 4 activates the PTG.3 AES128 encryption and with b the continuous random number generation is started

make the script executable with:

chmod +x /root/startp310.sh

2. Get serial from PRG310:

Execute the following command:

udevadm info -a -p $(udevadm info -q path -n ttyUSB0) | egrep -i "ATTRS{serial}|ATTRS{idVendor}|ATTRS{idProduct}" -m 3

Result should be something like this:

ATTRS{idProduct}=="6001"
ATTRS{idVendor}=="0403"
ATTRS{serial}=="XXXXXXXX"

:exclamation:If idProduct and idVendor are NOT 6001 and 0403 try the above command with different ttyUSB (e.g. ttyUSB1).
To find out which devices are connected to the system you can execute:
ls /dev/ttyUSB*

3. Create config file for udev:

vi /etc/udev/rules.d/99_ftdi_hwrng.rules

Copy the following content into the file AND replace XXXXXXXX with your serial from 2. :

SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="XXXXXXXX", SYMLINK+="hwrngtty", RUN+="/root/startp310.sh"

4. Restart udev and rngd

Execute the following 2 commands:

/etc/init.d/udev restart
/etc/init.d/rngd restart

5. Check functionality:

Go to the web interface of ipfire and go to “Status->Entropy”. The Entropy graph should rise quickly above 3k. “Random Number Generator Daemon” at the bottom should be green and “RUNNING”. If everything works reboot and check if everything still works as expected.

6. Enjoy

:sunglasses:

1 Like

7. Further investigations:

Checking the entropy and the quality of a 1MB output of /dev/random with “ent” command I got a much lower data quality than the PRG310 is capable of (PTG.3).
So what is going wrong?

After further investigations and digging deeper into how the entropy pool and rngd works, it was obvious what happened:

The entropy pool is filled with data from the kernel by default. The rngd daemon feeds random data from hardware devices and adds it to the entropy pool. So the entropy pool is a mix of 2 or more sources. The problem is, that if you mix data with a very high quality of entropy together with a lower quality of entropy, you lower the overall quality of the pool. If you have a trustful high quality source it is better to just use it alone. But looks like this can’t be changed, as this behavior is inside the kernel. This is somehow also a bit of an advantage: if the hardware RNG would fail there would be still entropy generated by the kernel - but in this case we want the external source to largely dominate the entropy pool.

8. The Solution

rngd has a configuration option --fill-watermark. The default setting is 2048 bits. This means that rngd fills a maximum of 2048 bits to the entropy pool which has usually a size of 4096 bits. The remaining 2048 bits are filled with data from the kernel. So by setting the watermark to the poolsize of 4096 there will be none or hardly any data of the kernel inside the entropy pool. Also the data generation of the kernel is very slow compared to an almost instant fill of 4096 bits from the PRG310. So let’s do this!

First check your entropy poolsize (4096 in most cases):

cat /proc/sys/kernel/random/poolsize

Edit /etc/init.d/rngd:

vi /etc/init.d/rngd

Change the start command of rngd in the start section (use your poolsize from above in the -W option):

loadproc /usr/sbin/rngd -x 1 -x 2 -x 4  --quiet -r $HWRNG  -W 4096

remark: The -x option disables other sources. As we have a very good source we do not want any other source to spoil the pool.
Use rngd -l to list the numbers of available sources on your system. In my case:
1: TPM RNG Device (does not work on APU1D anyways)
2: Intel RDRAND Instruction RNG (does not work on APU1D anyways)
4: NIST Network Entropy Beacon

Restart rngd:

/etc/init.d/rngd restart

Flush the entropy pool to get rid of the remaining kernel data (again use your poolsize there):

head -c 4096 < /dev/random > /dev/null

9. Now really enjoy

Entropy is now close to perfect and within specs of the PRG310!
:sunglasses: :beer:

1 Like

10. Final investigations (hopefully :sweat_smile:):

After two weeks of experience I discovered that the PRG310 stops outputting random data every few days and stops working. This is actually on purpose (=feature).

The PRG310 constantly checks the entropy of the data it generates on a hardware level (generated by thermal distortion of Zener diodes). If the entropy does not match the specs it will stop working to prevent from getting less random data without a notice. This behavior might be useful if you do e.g. complex simulations based on random data.

In our case we want a constant random data output and an automated restart. To automatically restart the entropy generation you have to perform the built in selftest. So we need to constantly check the PRG310 and perform the selftest by a cron script.

11. Create cron script (e.g. under /root):

vi /root/p310ctrl.sh

Copy the content into the file:

#!/bin/bash
#PRG310 control script 
#Version 0.1

#Change if necessary
DEVICE="/dev/hwrngtty"

#Log function
logme () {
  logger -t ipfire p310:$1
  echo "$1"
}

#usage
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
        echo "Program to perform PRG310 selftest"
	echo "-h prints this information"
	echo "-v outputs also the PRG310 hardware version"
	echo "Current device is "$DEVICE
	exit 0
fi
logme "Starting PRG310 selftest"
#Check if device is there
if [ ! -L "$DEVICE" ]; then
    logme "$DEVICE does not exist"
    exit 1
fi
#stop rngd
/etc/init.d/rngd stop > /dev/null
ps auwx | grep [r]ngd > /dev/null
if [ $? = 1 ]; then
	logme "Stopping rngd ... OK"
else
	logme "ERROR stopping rngd"
fi
#stop p310
echo e > $DEVICE

#get version if -v
if [ "$1" = "-v" ];then
  #flush buffer
  read -t 1 BUFFER < $DEVICE
  VERSION=""
  (COUNT=0 
  while [ true ]; do 
      echo v > /dev/hwrngtty 
  done) & 
  PID=$!
  read -t 4 VERSION < $DEVICE
  sleep 1
  kill $!
  logme "Version: "$(echo $VERSION)
fi

#flush buffer
read -t 1 BUFFER < $DEVICE

#do selftest
echo t  > $DEVICE
TEST=$(timeout 5 head -c 1 < $DEVICE)
TRYS=$(timeout .1 head -c 1 < $DEVICE)
case "$TRYS" in
          $(echo 0x05 | xxd -r))
	       TRYS=1
	       ;;
	  $(echo 0x04 | xxd -r))
	       TRYS=2
	       ;;
	  $(echo 0x03 | xxd -r))
	       TRYS=3
	       ;;
	  $(echo 0x02 | xxd -r))
	       TRYS=4
	       ;;
	  $(echo 0x01 | xxd -r))
	       TRYS=5
	       ;;
	  *)
	       TRYS="ERROR"
               ;;
esac

if [ "$TEST" = $(echo  0x55 | xxd -r) ]; then
     logme "Selfest: result OK"
elif [ "$TEST" = $(echo 0xaa | xxd -r) ]; then 
     logme "Selftest result: ERROR quality of raw data not sufficiant. Number of tries: $TRYS"
     /bin/stty raw -echo -ixoff -F $DEVICE speed 921600 > /dev/null
else
     logme "Selftest result: ERROR failed"
     /bin/stty raw -echo -ixoff -F $DEVICE speed 921600 > /dev/null
fi
#flush data
read -t 1 BUFFER < $DEVICE
#start random number generation
echo 4b > $DEVICE
DATA=$(timeout 3 xxd -l 2 -p $DEVICE)
if [ "$DATA" != "" ]; then
   logme "Restart random number generation ... OK"
else
   logme "Restart random number generation ... ERROR"
fi
#start rngd
/etc/init.d/rngd start > /dev/null
ps auwx | grep [r]ngd > /dev/null

if [ $? = 0 ]; then
   logme "Starting rngd ... OK"
else
   logme "Starting rngd ... ERROR"
fi

logme "PRG310 selftest done."

make the script executable with:

chmod +x /root/p310ctrl.sh

Execute the script for a test run and check if it works as expected:

/root/p310ctrl.sh

remark: the script has also a -v option which displays the hardware version and a -h option to show some help

12. Add script to cron:

Edit crontab:

fcrontab -e

Add the following line to crontab to execute the script e.g. every 10 minutes and save the changes:

*/10 * * * *	/root/p310ctrl.sh &

13. Now really really enjoy :beers: :sunglasses:

Checking the entropy with “ent” on a 1MB output of /dev/random gives the following result

Entropy = 7.999833 bits per byte (99.9979125 percent).

Optimum compression would reduce the size
of this 1048576 byte file by 0 percent.

Chi square distribution for 1048576 samples is 243.29, and randomly
would exceed this value 69.05 percent of the times.

Arithmetic mean value of data bytes is 127.4034 (127.5 = random).
Monte Carlo value for Pi is 3.143337797 (error 0.06 percent).
Serial correlation coefficient is 0.000221 (totally uncorrelated = 0.0).
1 Like