summaryrefslogtreecommitdiff
path: root/md/writeup/kernel_dev_hwrng.md
blob: 104b52297cbe7a3ac833ce4e2689501dab7e7829 (plain) (blame)
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# /dev/hwrng

## Intro

There is hardware that are can generate "randomness". It can be accesed trought
/dev/hwrng device. Funnies part of hardware random generator it could generate
anything. That why need to verify that data comming from /dev/hwrng. Good
advice is to use /dev/hwrng as additional entropy source. Why we dont trust
/dev/hwrng as random number souce? There is some articles about HW random
generators could be backdoored and could generate predictable values that why
as we cant verify HW design as its not opensourced we choose not to trust it.
In general if you belive in HW random generator you can use it.

## Switching hardware rng

Hardware random generator have own entry inside sysfs lets check 
_/sys/class/misc/hw_random/

```
$ls /sys/class/misc/hw_random/
dev  power  rng_available  rng_current  subsystem  uevent
```
Check avaliable hwrng modules

```
$cat /sys/class/misc/hw_random/rng_available 
zero-rng
```

Check currently running hwrng module

```
$cat /sys/class/misc/hw_random/rng_current 
zero-rng
```

## Testing /dev/hwrng

There couple of ways how you can test if data is "random" enought. There
is standarts like FIPS 140-2 with have criterias to check if data source is
pseudo-random. And there is couple of implementations of it. You can get 
tool like rng-tools and test data. Lets imagine that you have installed it
allready in your favorite way.

_Output every 5 seconds pseudo random tests results_
```sh
$cat /dev/urandom | rngtest -t 5
```

_Program output_
```
rngtest: starting FIPS tests...
rngtest: bits received from input: 462500032
rngtest: FIPS 140-2 successes: 23108
rngtest: FIPS 140-2 failures: 17
rngtest: FIPS 140-2(2001-10-10) Monobit: 1
rngtest: FIPS 140-2(2001-10-10) Poker: 2
rngtest: FIPS 140-2(2001-10-10) Runs: 8
rngtest: FIPS 140-2(2001-10-10) Long run: 6
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=2.166; avg=216.912; max=19073.486)Mibits/s
rngtest: FIPS tests speed: (min=56.598; avg=148.791; max=178.257)Mibits/s
rngtest: Program run time: 5016745 microseconds
```

## Example driver

Create files _Makefile_ and _zero_hwrng.c_ and copy code.

__Makefile__
```Makefile
obj-m += zero_hwrng.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

load:
	insmod zero_hwrng.ko
unload:
	rmmod zero_hwrng
```

__zero_hwrng.c__
```c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hw_random.h>
#include <linux/completion.h>
#include <linux/atomic.h>
#include <linux/slab.h>
#include <linux/device.h>

#define PRINTK printk
#define PRN(format, args ... ) PRINTK("DBG FUN:%s LINE:%d " format,__FUNCTION__,__LINE__, ##args);
#define PNL() PRINTK("%s:%d\n",__FUNCTION__,__LINE__);

static int zero_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
	int i;
	u8 *buf;

	PNL();

	buf = data;

	for (i=0;i<max;i++)
	{
		buf[i] = 0;
	}

	return max;
}

static void zero_rng_cleanup(struct hwrng *rng)
{
	PNL();
}

static struct hwrng zero_rng = {
	.name = "zero-rng",
	.cleanup = zero_rng_cleanup, 
	.read    = zero_rng_read,
};

static void zero_rng_exit(void)
{
	PNL();

	hwrng_unregister(&zero_rng);
}

static int zero_rng_init(void)
{
	PNL();

	PRN("register device");
	
	return hwrng_register(&zero_rng);
}

module_init(zero_rng_init);
module_exit(zero_rng_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Zero /dev/hwrng");
MODULE_AUTHOR("Internet User");
```

### Loading module

Rng module depends on rng-core module 

```
modprobe rng-core
```

then load our module

```
insmode zero_rng.ko
```

check if everything is properly loaded

```
$lsmod | grep rng
zero_hwrng             16384  0
rng_core               16384  1 zero_hwrng
```

### Verify randomness

Lets test how our stuff works

```
$ dd if=/dev/hwrng of=/tmp/random bs=1024 count=32
32+0 records in
32+0 records out
32768 bytes (33 kB, 32 KiB) copied, 0.00111024 s, 29.5 MB/s
$ hexdump /tmp/random 
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
0008000
```

As we can see all data that we get is just zeros lets check it with rng-tools
```
$ cat /tmp/random | rngtest -t 5
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: entropy source drained
rngtest: bits received from input: 262144
rngtest: FIPS 140-2 successes: 0
rngtest: FIPS 140-2 failures: 13
rngtest: FIPS 140-2(2001-10-10) Monobit: 13
rngtest: FIPS 140-2(2001-10-10) Poker: 13
rngtest: FIPS 140-2(2001-10-10) Runs: 13
rngtest: FIPS 140-2(2001-10-10) Long run: 13
rngtest: FIPS 140-2(2001-10-10) Continuous run: 13
rngtest: input channel speed: (min=6.209; avg=13.452; max=18.626)Gibits/s
rngtest: FIPS tests speed: (min=168.792; avg=201.099; max=207.321)Mibits/s
rngtest: Program run time: 1369 microseconds
```

Well all tests fails thats good

### Practical example

Lets asume that we are running this code on Intel arch and it supports
_rdrand_ instruction for random genertion.


```
void get_hw_rand2(uint8_t *mem)
{
    int i=0;
    asm("rdrand %%rax\n\t"
    	"mov %%rax, %0\n\t"
    	:"=m"(*mem)::"0");

}
```

Lets replace intel_rng_read function with our naive implementation of _rdrand_

```
static int intel_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
	int i;
	u8 *buf;
	u64 rnd;
	u8 rnd8[8];
	u8 val;

	PNL();

	buf = data;
	for (i=0;i<max;i++)
	{
		if ((i%8)==0)
		{
			get_hw_rand2(rnd8);
		}
		buf[i] = rnd8[i%8];
	}

	return max;
}
```

Verify that our module loaded

```
$ cat /sys/class/misc/hw_random/rng_available 
zero-rng intel-rng
```

Check with module are currently used

```
$ cat /sys/class/misc/hw_random/rng_current 
zero-rng
```

if not our module set lets set it

```
$ echo "intel-rng" > /sys/class/misc/hw_random/rng_current
```

check if its current module used

```
$ cat /sys/class/misc/hw_random/rng_current 
intel-rng
```

Well everything looks fine and test are passsed if you goint to try test it
with rng-tools.

## Links

1. [Documentation/hw_random.txt](https://www.kernel.org/doc/Documentation/hw_random.txt)
2. [295_linux_really_using_hardware_random_number_generators.html](http://blog.coldtobi.de/1_coldtobis_blog/archive/295_linux_really_using_hardware_random_number_generators.html)
3. [rng-tools](https://www.archlinux.org/packages/community/x86_64/rng-tools/)
4. [include/linux/hw_random.h](https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/include/linux/hw_random.h?id=refs/tags/v4.7.4)
5. [/writeup/gcc_inline_assembly.md#toc-12](/writeup/gcc_inline_assembly.md#toc-12)