在使用OpenSSL的dhparam命令生成DH參數或使用GnuPG的--gen-key生成密鑰對時,需要系統(默認由塊設備/dev/random提供)生成大量的隨機數以供使用。但通常情況下熵池(entropy poll)中的隨機數資源不足,直接導致系統性能下降,相關操作耗時過於漫長。可藉助RNG工具rng-toolshaveged自動生成僞隨機數資源。本文記錄這兩個工具的安裝、配置、測試過程。

Introduction

Entropy,即 ,在信息論中表示數據的混亂程度或是不確定性,可理解為是 隨機數據。在GNU/Linux中,有2個設備文件用於生成隨機數資源,分別是/dev/random/dev/urandom,此二者又可稱爲Pseudorandom Number Generator(PRNG)。其中/dev/random的數據採集自硬件設備活動(如敲擊鍵盤、磁盤讀寫、移動鼠標等行為)和其它操作系統資源,其默認熵池隨機數資源大小是4KB,由內核參數/proc/sys/kernel/random/poolsize控制。

本人查閱的幾篇資料都說由設備/dev/random生成的隨機數纔是 真實 的隨機數,因爲它是塊設備,只有收集到足夠的熵數據纔會輸出。而設備/dev/urandomPseudorandom Number Generator(PRNG)而不是塊設備,當熵池中隨機數資源不足時,會自動生成 隨機數,質量較低,有安全風險。

但是Blog Myths about /dev/urandom則持不同的觀點,認爲設備/dev/urandom生成的隨機數質量優於/dev/random,建議使用/dev/urandom生成隨機數。

因本人目前尚無能力甄別對錯,故在本文中假設兩者生成的隨機數質量無差別。

熵池隨機數資源不足時的場景,如執行gpg2 --gen-key命令生成密鑰對,會出現如下提示信息:

We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy.

如果隨機數資源不足,則整個操作過程將非常耗時。

可通過如下命令查看系統可用的隨機數資源

1
cat /proc/sys/kernel/random/entropy_avail

其數值通常小於1000

rng-toolshaveged就是用來解決隨機數資源不足的工具。

  • rng-tools

Hardware random number generation tools.

  • haveged

A Linux entropy source using the HAVEGE algorithm

Haveged is a user space entropy daemon which is not dependent upon the standard mechanisms for harvesting randomness for the system entropy pool. This is important in systems with high entropy needs or limited user interaction (e.g. headless servers).

Haveged uses HAVEGE (HArdware Volatile Entropy Gathering and Expansion) to maintain a 1M pool of random bytes used to fill /dev/random whenever the supply of random bits in /dev/random falls below the low water mark of the device. The principle inputs to haveged are the sizes of the processor instruction and data caches used to setup the HAVEGE collector. The haveged default is a 4kb data cache and a 16kb instruction cache. On machines with a cpuid instruction, haveged will attempt to select appropriate values from internal tables.

Conventions

本文中相關操作在CentOS 7.3Debian Jessie中進行

  • CentOS 7.3
1
2
3
4
5
[[email protected] ~]$ cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)
[[email protected] ~]$ uname -r
3.10.0-514.2.2.el7.x86_64
  • Debian Jessie
1
2
3
4
5
6
7
8
Debian GNU/Linux 8 (jessie)
[email protected]:~$ uname -r
3.16.0-4-amd64
[email protected]:~$ apt-cache search -n 'rng-tools|haveged'
haveged - Linux entropy source using the HAVEGE algorithm
rng-tools - Daemon to use a Hardware TRNG

Installation

CentOS中,工具havegedEPEL源中,需先安裝epel-release

執行如下命令安裝

1
2
3
4
5
6
# CentOS 7.3
sudo yum install -y epel-release
sudo yum install -y rng-tools haveged
# Debian Jessie
sudo apt-get install -y rng-tools haveged

配置文件路徑

tool path
haveged /etc/default/haveged
rng-tools /etc/default/rng-tools

開啟服務並設置為開機啟動

執行如下命令

1
2
3
4
5
6
7
8
9
#haveged
sudo systemctl start haveged
sudo systemctl enable haveged
sudo systemctl status haveged
#rng-tools
sudo systemctl start rng-tools
sudo systemctl enable rng-tools
sudo systemctl status rng-tools

在啓動rng-tools服務時會提示啓動失敗

Job for rng-tools.service failed. See ‘systemctl status rng-tools.service’ and ‘journalctl -xn’ for details.

通過命令

1
systemctl status rng-tools -l

查看到如下信息

Starting Hardware RNG entropy gatherer daemon: (Hardware RNG device inode not found)
/etc/init.d/rng-tools: Cannot find a hardware RNG device to use.

系統啓動時,也會提示該服務無法啓動。

解決方案:在配置文件/etc/default/rng-tools中添加指令HRNGDEVICE=/dev/urandom,可通過如下命令實現

1
sudo sed -i -r '/^HRNGDEVICE/d;/#HRNGDEVICE=\/dev\/null/a HRNGDEVICE=/dev/urandom' /etc/default/rng-tools

再次啓動rng-tools服務正常。

安裝完成後須重啟系統。重啟後,執行如下命令測試

1
2
3
cat /proc/sys/kernel/random/entropy_avail
cat /dev/random | rngtest -c 1000
haveged -n 4g -f - | dd of=/dev/null

Testing

注意:

  1. haveged的可執行程序路徑是/usr/sbin/haveged,在Debian中需使用sudo權限執行;
  2. 命令rngtestrng-tools提供的工具;

Testing On CentOS 7.3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# os info
[[email protected] ~]$ cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)
# entropy avail
[[email protected] ~]$ cat /proc/sys/kernel/random/entropy_avail
3107
# test via rngtest
[[email protected] ~]$ cat /dev/random | rngtest -c 1000
rngtest 5
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
rngtest: starting FIPS tests...
rngtest: bits received from input: 20000032
rngtest: FIPS 140-2 successes: 998
rngtest: FIPS 140-2 failures: 2
rngtest: FIPS 140-2(2001-10-10) Monobit: 1
rngtest: FIPS 140-2(2001-10-10) Poker: 0
rngtest: FIPS 140-2(2001-10-10) Runs: 1
rngtest: FIPS 140-2(2001-10-10) Long run: 0
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=5.328; avg=8.090; max=9.250)Mibits/s
rngtest: FIPS tests speed: (min=68.610; avg=104.069; max=126.314)Mibits/s
rngtest: Program run time: 2541737 microseconds
# test via haveged
[[email protected] ~]$ haveged -n 4g -f - | dd of=/dev/null
Writing 4 G byte output to stdout
8388608+0 records in
8388608+0 records out
4294967296 bytes (4.3 GB) copied, 10.0752 s, 426 MB/s

Testing On Debian Jessie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# os info
Debian GNU/Linux 8 (jessie)
# entropy avail
[email protected]:~$ cat /proc/sys/kernel/random/entropy_avail
2367
# test via rngtest
[email protected]:~$ cat /dev/random | rngtest -c 1000
rngtest 2-unofficial-mt.14
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
rngtest: starting FIPS tests...
rngtest: bits received from input: 20000032
rngtest: FIPS 140-2 successes: 999
rngtest: FIPS 140-2 failures: 1
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
rngtest: FIPS 140-2(2001-10-10) Poker: 0
rngtest: FIPS 140-2(2001-10-10) Runs: 0
rngtest: FIPS 140-2(2001-10-10) Long run: 1
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=1.884; avg=17.425; max=21.699)Mibits/s
rngtest: FIPS tests speed: (min=31.895; avg=123.796; max=150.185)Mibits/s
rngtest: Program run time: 1249093 microseconds
# test via haveged
[email protected]:~$ sudo haveged -n 4g -f - | dd of=/dev/null
Writing 4 G byte output to stdout
8388608+0 records in
8388608+0 records out
4294967296 bytes (4.3 GB) copied, 10.1313 s, 424 MB/s

Examples

實際案例

GnuPG

執行

1
gpg2 --list-keys

生成密鑰對

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
[email protected]:~$ gpg2 --list-keys
gpg: checking the trustdb
gpg: no ultimately trusted keys found
[email protected]:~$ gpg2 --gen-key
gpg (GnuPG) 2.0.26; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection? 2
DSA keys may be between 1024 and 3072 bits long.
What keysize do you want? (2048) 3072
Requested keysize is 3072 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 1y
Key expires at Thu 11 Jan 2018 03:26:00 PM CST
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: LempStacker
Email address: [email protected]
Comment: LempStacker Entropy Testing
You selected this USER-ID:
"LempStacker (LempStacker Entropy Testing) <[email protected]>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.
Gtk-Message: Failed to load module "canberra-gtk-module"
Gtk-Message: Failed to load module "canberra-gtk-module"
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: WARNING: some OpenPGP programs can't handle a DSA key with this digest size
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 6F84EE2B marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2018-01-11
pub 3072D/6F84EE2B 2017-01-11 [expires: 2018-01-11]
Key fingerprint = DBA8 A277 0156 13C2 F217 9CA3 A7F9 13AE 6F84 EE2B
uid [ultimate] LempStacker (LempStacker Entropy Testing) <[email protected]>
sub 3072g/365E7E26 2017-01-11 [expires: 2018-01-11]
[email protected]:~$ gpg2 --list-keys
/home/flying/.gnupg/pubring.gpg
-------------------------------
pub 3072D/6F84EE2B 2017-01-11 [expires: 2018-01-11]
uid [ultimate] LempStacker (LempStacker Entropy Testing) <[email protected]>
sub 3072g/365E7E26 2017-01-11 [expires: 2018-01-11]

OpenSSL

執行

1
openssl dhparam -out dhparams.pem 4096

生成DH參數,該過程須耗時十幾到幾十分鐘。

haveged

haveged可生成多種類型的隨機數據,具體查看man haveged,示例可通過命令

1
man haveged | sed -n '/EXAMPLES/,/SEE ALSO/p'

輸出如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
EXAMPLES
Write 1.5MB of random data to the file /tmp/random
haveged -n 1.5M -f /tmp/random
Generate a /tmp/keyfile for disk encryption with LUKS
haveged -n 2048 -f /tmp/keyfile
Overwrite partition /dev/sda1 with random data. Be careful, all data on the partition will be lost!
haveged -n 0 | dd of=/dev/sda1
Generate random ASCII passwords of the length 16 characters
(haveged -n 1000 -f - 2>/dev/null | tr -cd '[:graph:]' | fold -w 16 && echo ) | head
Write endless stream of random bytes to the pipe. Utility pv measures the speed by which data are written to
the pipe.
haveged -n 0 | pv > /dev/null
Evaluate speed of haveged to generate 1GB of random data
haveged -n 1g -f - | dd of=/dev/null
Create a random key file containing 65 random keys for the encryption program aespipe.
haveged -n 3705 -f - 2>/dev/null | uuencode -m - | head -n 66 | tail -n 65
Test the randomness of the generated data with dieharder test suite
haveged -n 0 | dieharder -g 200 -a
Generate 16k of data, testing with procedure A and B with detailed test results. No c result seen because a
single buffer fill did not contain enough data to complete the test.
haveged -n 16k -o tba8ca8 -v 33
Generate 16k of data as above with larger buffer. The c test now completes - enough data now generated to com‐
plete the test.
haveged -n 16k -o tba8ca8 -v 33 -b 512
Generate 16m of data as above, observe many c test completions with default buffer size.
haveged -n 16m -o tba8ca8 -v 33
Generate large amounts of data - in this case 16TB. Enable initialization test but made continuous tests advi‐
sory only to avoid a possible situation that program will terminate because of procedureB failing two times in
a row. The probability of procedureB to fail two times in a row can be estimated as <TB to generate>/3000 which
yields 0.5% for 16TB.
haveged -n 16T -o tba8cbw -f - | pv > /dev/null
Generate large amounts of data (16TB). Disable continuous tests for the maximum throughput but run the online
tests at the startup to make sure that generator for properly initialized:
haveged -n 16T -o tba8c -f - | pv > /dev/null
SEE ALSO

References

Change Logs

  • 2017.01.11 15:35 Wed Asia/Shanghai
    • 初稿完成
  • 2017.02.02 14:27 Thu America/Boston
    • 內容更新,新增配置文件修改