Linux hwrng以及ARM TRNG记录
关键词:hwrng,/dev/random,/dev/urandom,rngd,rngtest等。
Linux hwrng驱动比较简单,hwrng core注册设备提供sysfs几点给应用层使用。hwrnd driver提供具体硬件接口,然后注册到hwrng core中,以及往内核熵池提供随机数。
1. Linux hwrng框架
1.1 hwrng框架对外接口
hwrng对外提供的API接口包括:注册接口、去注册接口、将硬件产生随机数加入到/dev/random接口。
其中注册和去注册接口分是否创建device_add接口两种。
/** Register a new Hardware Random Number Generator driver. */ extern int hwrng_register(struct hwrng *rng); extern int devm_hwrng_register(struct device *dev, struct hwrng *rng); /** Unregister a Hardware Random Number Generator driver. */ extern void hwrng_unregister(struct hwrng *rng); extern void devm_hwrng_unregister(struct device *dve, struct hwrng *rng); /** Feed random bits into the pool. */ extern void add_hwgenerator_randomness(const char *buffer, size_t count, size_t entropy);
struct hwrng编写hwrnd硬件驱动的结构体,包含了操作函数集、熵质量、列表头、引用计数等。
一个驱动根据需要填写了结构体之后,即可通过hwrng_register()/devm_hwrng_register()注册到hwrng核心中,对/dev/hwrng设备的操作即可映射到注册的硬件。
struct hwrng { const char *name; int (*init)(struct hwrng *rng);--初始化回调函数。可为NULL。 void (*cleanup)(struct hwrng *rng);--当rng的ref为0时被调用。可为NULL。 int (*data_present)(struct hwrng *rng, int wait);--淘汰的接口。检查rng数据是否有效。 int (*data_read)(struct hwrng *rng, u32 *data);--淘汰的接口。读取rng数据。 int (*read)(struct hwrng *rng, void *data, size_t max, bool wait);--读取数据接口,替代data_present()和data_read()。 unsigned long priv; unsigned short quality;--熵质量,0表示未知;1~1024越大表示越随机。 /* internal. */ struct list_head list;--插入rng_list中。 struct kref ref; struct completion cleanup_done; };
1.2 rng core模块
rng core初始化时已经创建了/dev/hwrng设备,以及misc设备的一系列属性。
hwrng_modinit
->rng_buffer/rng_fillbuf--创建缓存。 ->register_miscdev ->misc_register(&rng_miscdev)
->device_create_with_groups--创建字符设备,操作函数集为rng_chrdev_ops,groups为rng_dev_groups。
device_create_with_groups()创建设备位于/sys/devices/virtual/misc下,目录名对应miscdevice->name;并将groups下面的attr创建对应的节点。
对于hw_random而言创建:
- rng_selected--是否由用户空间选择rng设备,1表示是,0表示没有设置过。
- rng_current--当前rng设备名称,可以写入名称来选择指定rng设备。
- rng_available--可用rng设备名称。
static struct miscdevice rng_miscdev = { .minor = HWRNG_MINOR, .name = RNG_MODULE_NAME, .nodename = "hwrng", .fops = &rng_chrdev_ops, .groups = rng_dev_groups, }; static const struct file_operations rng_chrdev_ops = { .owner = THIS_MODULE, .open = rng_dev_open, .read = rng_dev_read, .llseek = noop_llseek, }; static const struct attribute_group *rng_dev_groups[];
rng_dev_read()是hwrng设备read()调用底层函数:
rng_dev_read ->get_current_rng ->rng_get_data ->hwrng->read--调用驱动实现的read()函数。 ->hwrng->data_present--为NULL则表示数据一直可读。否则函数返回1表示数据可读,使用data_read()读取数据,0表示不可读。 ->hwrng->data_read--在data_present为NULL,或返回1时被调用。 ->copy_to_user--拷贝数据到用户空间缓存。
hwrng注册接口主要将当前hwrng加入到rng_list列表中,并选择熵质量最高的硬件作为当前随机数硬件设备。后续对/dev/hwrng的操作,会转换为对hwrng->read()等的调用。
devm_hwrng_register ->hwrng_register ->list_add_tail--将当前hwrng设备加入到rng_list中。 ->set_current_rng--根据hwrng->quality选择合适的hwrng设备作为当前设备。
->hwrng_init
->rng->init--hwrng设备初始化。
->start_khwrngd
->hwrng_fillfn ->add_early_randomness ->rng_get_data--从硬件读取随机数。 ->add_device_randomness--将硬件产生的随机数添加到inpu_pool熵池中。 ->device_add--创建
2. hwrng驱动
编写hwrng驱动,最主要的工作就是填充struct hwrng结构体,其他诸如dts解析,中断注册和处理,调试接口等。
其中init()完成hwrng设备初始化,cleanup()完成设备关闭扫尾工作,核心是read()读取随机数。data_read()和data_present()是被淘汰的接口。
2.1 硬件资料
ARM TRNG规格书《Arm True Random Number Generator (TRNG) Technical Reference Manual Revision r0p0》,对应的裸驱程序《TZ-TRNG: TrustZone True Number Generator》。
3. /dev/random和/dev/urandom
/dev/random和/devurandom都提供了随机数读取接口,更多参考《初探 Linux kernel 亂數產生器 – random generator》,《What are /dev/random and /dev/urandom in Linux?》,《Linux随机数发生器 (betheme.net)》。
static const struct memdev { const char *name; umode_t mode; const struct file_operations *fops; fmode_t fmode; } devlist[] = { [8] = { "random", 0666, &random_fops, 0 }, [9] = { "urandom", 0666, &urandom_fops, 0 }, }; const struct file_operations random_fops = { .read = random_read, .write = random_write, .poll = random_poll, .unlocked_ioctl = random_ioctl, .fasync = random_fasync, .llseek = noop_llseek, }; const struct file_operations urandom_fops = { .read = urandom_read, .write = random_write, .unlocked_ioctl = random_ioctl, .fasync = random_fasync, .llseek = noop_llseek, };
另外还提供了getrandom系统调用。
4. hwrng测试程序
通过dd读取/dev/hwrng数据到指定文件:
dd if=/dev/hrrng of=rng.dat bs=1024 count=1
安装rng-tools,里面包含rngd和rngtest两个程序。
rngd作为守护进程,从/dev/hwrng中读取随机数,喂到内核熵池中。
rngd --rng-device=/dev/hwrng
rngtest使用FIPS 140-2协议对从/dev/hwrng获取的数据进行检查。
cat /dev/hwrng | rngtest -c 1000
参考资料:《3.4. Using the Random Number Generator Red Hat Enterprise Linux 6》《》