mirror of
https://github.com/polhenarejos/pico-rng.git
synced 2026-04-28 09:43:22 +02:00
Updated with kernel thread to add randmoness
This commit is contained in:
@@ -10,6 +10,8 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/semaphore.h>
|
#include <linux/semaphore.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
#include <linux/hw_random.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
@@ -18,13 +20,14 @@ MODULE_DESCRIPTION("Random number generator using a Raspberry Pi Pico");
|
|||||||
MODULE_VERSION("1.0");
|
MODULE_VERSION("1.0");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static constants
|
* Macros
|
||||||
**/
|
**/
|
||||||
#define VENDOR_ID 0x0
|
#define VENDOR_ID 0x0
|
||||||
#define PRODUCT_ID 0x4
|
#define PRODUCT_ID 0x4
|
||||||
|
#define PICO_RNG_ENTROPY(x) (((x) * 8 * 10) >> 5) /* quality: 10/32 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper macros
|
* Logger macros
|
||||||
**/
|
**/
|
||||||
#define LOGGER_INFO(fmt, args ...) printk( KERN_INFO "[info] %s(%d): " fmt, __FUNCTION__, __LINE__, ## args)
|
#define LOGGER_INFO(fmt, args ...) printk( KERN_INFO "[info] %s(%d): " fmt, __FUNCTION__, __LINE__, ## args)
|
||||||
#define LOGGER_ERR(fmt, args ...) printk( KERN_ERR "[err] %s(%d): " fmt, __FUNCTION__, __LINE__, ## args)
|
#define LOGGER_ERR(fmt, args ...) printk( KERN_ERR "[err] %s(%d): " fmt, __FUNCTION__, __LINE__, ## args)
|
||||||
@@ -46,8 +49,9 @@ struct pico_rng_data {
|
|||||||
struct usb_device *dev;
|
struct usb_device *dev;
|
||||||
struct usb_interface *interface;
|
struct usb_interface *interface;
|
||||||
struct usb_endpoint_descriptor *endpoint;
|
struct usb_endpoint_descriptor *endpoint;
|
||||||
char *buffer;
|
void *buffer;
|
||||||
int pipe;
|
int pipe;
|
||||||
|
struct task_struct *rng_task;
|
||||||
} module_data;
|
} module_data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,9 +62,15 @@ static void pico_rng_usb_disconnect(struct usb_interface *interface);
|
|||||||
static int __init pico_rng_driver_init(void);
|
static int __init pico_rng_driver_init(void);
|
||||||
static void __exit pico_rng_driver_exit(void);
|
static void __exit pico_rng_driver_exit(void);
|
||||||
|
|
||||||
|
static int pico_rng_read_data(void);
|
||||||
|
|
||||||
static ssize_t pico_rng_read(struct file *file, char __user *user_buffer, size_t size, loff_t *offset);
|
static ssize_t pico_rng_read(struct file *file, char __user *user_buffer, size_t size, loff_t *offset);
|
||||||
static int pico_rng_open(struct inode *inode, struct file *file);
|
static int pico_rng_open(struct inode *inode, struct file *file);
|
||||||
|
|
||||||
|
static int pico_rng_kthread(void *data);
|
||||||
|
void pico_rng_kthread_start(void);
|
||||||
|
void pico_rng_kthread_stop(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data structure of the USB vid:pid device that we will support
|
* Data structure of the USB vid:pid device that we will support
|
||||||
**/
|
**/
|
||||||
@@ -93,7 +103,7 @@ static struct file_operations pico_rng_fops = {
|
|||||||
* USB class data structure
|
* USB class data structure
|
||||||
**/
|
**/
|
||||||
struct usb_class_driver pico_rng_usb_class = {
|
struct usb_class_driver pico_rng_usb_class = {
|
||||||
.name = "pico_rng",
|
.name = "pico_raw",
|
||||||
.fops = &pico_rng_fops,
|
.fops = &pico_rng_fops,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -107,14 +117,12 @@ static int pico_rng_open(struct inode *inode, struct file *file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File ops:read
|
* Read data from the pico rng
|
||||||
**/
|
*/
|
||||||
static ssize_t pico_rng_read(struct file *file, char __user *user_buffer, size_t size, loff_t *offset)
|
static int pico_rng_read_data()
|
||||||
{
|
{
|
||||||
|
int retval = 0;
|
||||||
int actual_length = 0;
|
int actual_length = 0;
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
LOGGER_DEBUG("inside pico_rng_read with file %p, user_buffer %p, size %ld, offset %lld\n", file, user_buffer, size, *offset);
|
|
||||||
|
|
||||||
// int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
|
// int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
|
||||||
LOGGER_DEBUG("Calling usb_bulk_msg dev %p, pipe %d, buffer %p, size %d, and timeout %d", \
|
LOGGER_DEBUG("Calling usb_bulk_msg dev %p, pipe %d, buffer %p, size %d, and timeout %d", \
|
||||||
@@ -126,19 +134,38 @@ static ssize_t pico_rng_read(struct file *file, char __user *user_buffer, size_t
|
|||||||
module_data.endpoint->wMaxPacketSize,
|
module_data.endpoint->wMaxPacketSize,
|
||||||
&actual_length,
|
&actual_length,
|
||||||
timeout);
|
timeout);
|
||||||
|
|
||||||
if(retval)
|
if(retval)
|
||||||
{
|
{
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER_DEBUG("Copying %d bytest of random data to userspace with offset %lld\n", actual_length, *offset);
|
return actual_length;
|
||||||
if(copy_to_user(user_buffer, module_data.buffer, module_data.endpoint->wMaxPacketSize))
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File ops:read
|
||||||
|
**/
|
||||||
|
static ssize_t pico_rng_read(struct file *file, char __user *user_buffer, size_t size, loff_t *offset)
|
||||||
|
{
|
||||||
|
int bytes_read = 0;
|
||||||
|
|
||||||
|
LOGGER_DEBUG("inside pico_rng_read with file %p, user_buffer %p, size %ld, offset %lld\n", file, user_buffer, size, *offset);
|
||||||
|
|
||||||
|
bytes_read = pico_rng_read_data();
|
||||||
|
if(!bytes_read)
|
||||||
|
{
|
||||||
|
LOGGER_ERR("Failed to read data");
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER_DEBUG("Copying %d bytest of random data to userspace with offset %lld\n", bytes_read, *offset);
|
||||||
|
if(copy_to_user(user_buffer, module_data.buffer, bytes_read))
|
||||||
{
|
{
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return module_data.endpoint->wMaxPacketSize;
|
return bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -192,6 +219,8 @@ static int pico_rng_usb_probe(struct usb_interface *interface, const struct usb_
|
|||||||
// int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
|
// int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
|
||||||
//retval = usb_bulk_msg(dev, pipe, buffer, 64, &actual_length, 500);
|
//retval = usb_bulk_msg(dev, pipe, buffer, 64, &actual_length, 500);
|
||||||
|
|
||||||
|
pico_rng_kthread_start();
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +231,7 @@ static int pico_rng_usb_probe(struct usb_interface *interface, const struct usb_
|
|||||||
static void pico_rng_usb_disconnect(struct usb_interface *interface)
|
static void pico_rng_usb_disconnect(struct usb_interface *interface)
|
||||||
{
|
{
|
||||||
LOGGER_INFO("pico rng usb device disconnected\n");
|
LOGGER_INFO("pico rng usb device disconnected\n");
|
||||||
|
pico_rng_kthread_stop();
|
||||||
usb_deregister_dev(module_data.interface, &pico_rng_usb_class);
|
usb_deregister_dev(module_data.interface, &pico_rng_usb_class);
|
||||||
module_data.dev = NULL;
|
module_data.dev = NULL;
|
||||||
module_data.interface = NULL;
|
module_data.interface = NULL;
|
||||||
@@ -210,6 +240,59 @@ static void pico_rng_usb_disconnect(struct usb_interface *interface)
|
|||||||
module_data.buffer = NULL;
|
module_data.buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pico rng thread that periodically adds hardware randomness
|
||||||
|
*/
|
||||||
|
static int pico_rng_kthread(void *data)
|
||||||
|
{
|
||||||
|
int bytes_read;
|
||||||
|
|
||||||
|
while (!kthread_should_stop())
|
||||||
|
{
|
||||||
|
bytes_read = pico_rng_read_data();
|
||||||
|
if(!bytes_read)
|
||||||
|
{
|
||||||
|
LOGGER_ERR("Failed to read data\n");
|
||||||
|
|
||||||
|
// sleep for at least a second, max 2 seconds
|
||||||
|
usleep_range(1000000, 2000000);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER_DEBUG("Adding hardware randomness\n");
|
||||||
|
add_hwgenerator_randomness(module_data.buffer, bytes_read, PICO_RNG_ENTROPY(bytes_read));
|
||||||
|
LOGGER_DEBUG("Randomness added\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the rng thread
|
||||||
|
**/
|
||||||
|
void pico_rng_kthread_start()
|
||||||
|
{
|
||||||
|
module_data.rng_task = kthread_run(pico_rng_kthread, &module_data, "pico_rng_thread");
|
||||||
|
if(IS_ERR(module_data.rng_task))
|
||||||
|
{
|
||||||
|
module_data.rng_task = NULL;
|
||||||
|
LOGGER_ERR("Failed to launch the pico rng task\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the rng thread
|
||||||
|
**/
|
||||||
|
void pico_rng_kthread_stop()
|
||||||
|
{
|
||||||
|
if(module_data.rng_task)
|
||||||
|
{
|
||||||
|
kthread_stop(module_data.rng_task);
|
||||||
|
module_data.rng_task = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int __init pico_rng_driver_init(void)
|
static int __init pico_rng_driver_init(void)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|||||||
@@ -564,6 +564,9 @@ void get_random_data(char *buf, uint16_t len) {
|
|||||||
memcpy(&buf[i-1], (void*)&adc_result, 2);
|
memcpy(&buf[i-1], (void*)&adc_result, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The pico has a clock, use it as the seed because time always changes
|
||||||
|
// https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__clocks.html
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In an attempt to make the rng even more random this will slow down the amount of data the
|
* In an attempt to make the rng even more random this will slow down the amount of data the
|
||||||
* pico can generate. It appears to be more random, but not good enough for FIPS 140-2.
|
* pico can generate. It appears to be more random, but not good enough for FIPS 140-2.
|
||||||
|
|||||||
Reference in New Issue
Block a user