summaryrefslogblamecommitdiffstats
path: root/md/writeup/kernel_dev_hwrng.md
blob: 5c43b92e7c4bdddd4b25a0bbbfacf5aae67404bd (plain) (tree)
1
2
3
4
5
6
7
8
9
                        



            
                                                                               
                                                                              
                                                                        
                                                                           
                                                                          
                                                                             
                                                                              







                                                                                  





                                                                 
       


                                                         
                             
 
       





                                             
       





                                           

                                                                          

                                                                          
                             






                                                    
     







































































































                                                                                                  
     




                    
     




                                      
     








                                          
     










                                                                             
     























                                                                                                                                                      

                                                                       

 
    











                                                                              
    

























                                                                               
     





                                              
     





                                            
     




                                                          
     



                                            
                                                                          








                                                                                                                                                                                  
title: Kernel /dev/hwrng
# /dev/hwrng

## Intro

There is hardware that are can generate "randomness". It can be accessed trough
/dev/hwrng device. Funnies part of hardware random generator it could generate
anything. That why need to verify that data coming from /dev/hwrng. Good
advice is to use /dev/hwrng as additional entropy source. Why we dont trust
/dev/hwrng as random number source? 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 open sourced we choose not to trust it.
In general if you trust in HW random generators you can use them, but for security
you better not trust them as there is no way to verify on your side if there is no
backdoors, so use default secure linux implementation.

First code example is introducing crypto subsystem of linux and how to use it, by
creating "random" generator that generates zeros. Second example is utilise Intel
builtin random generator and instruction __rdrand__.


## Switching hardware rng

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

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

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

Check currently running hwrng module

```bash
$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" enough. There
is standards like FIPS 140-2 with have criteria 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
already in your favorite way.

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

_Program output_
```sh
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 

```sh
modprobe rng-core
```

then load our module

```sh
insmode zero_rng.ko
```

check if everything is properly loaded

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

### Verify randomness

Lets test how our stuff works

```sh
$ 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
```sh
$ 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 assume that we are running this code on Intel arch and it supports
_rdrand_ instruction for random generation.


```c
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_

```c
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

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

Check with module are currently used

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

if not our module set lets set it

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

check if its current module used

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

Well everything looks fine and test are passed if you going 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)