feat(keystore): sealed real/duress slots (argon2id 16MiB/3, ChaCha20-Poly1305), torn-write-safe 2-copy record, wipe state; virtio-rng driver + Entropy port; RustCrypto deps

This commit is contained in:
2026-10-27 23:06:25 +01:00
parent 6b13bf8bbf
commit 600140d518
12 changed files with 882 additions and 3 deletions

View File

@@ -0,0 +1,10 @@
[package]
name = "driver-rng-virtio"
version = "0.1.0"
edition = "2024"
[dependencies]
types = { workspace = true }
libkos = { workspace = true }
hw-virtio = { workspace = true }
port-entropy = { workspace = true }

View File

@@ -0,0 +1,74 @@
//! virtio-rng (virtio spec 5.4): the device fills a buffer with entropy.
#![no_std]
#![forbid(unsafe_code)]
use hw_virtio::mmio::{MmioAccess, Registers};
use hw_virtio::queue::{Descriptor, VirtioQueue};
use libkos::device::Dma;
use port_entropy::Entropy;
use types::address::{ByteOffset, VirtualAddress};
use types::bounded::PageCount;
const MMIO_VA: VirtualAddress = VirtualAddress::from_raw(0x2A000);
const VQUEUE_VA: VirtualAddress = VirtualAddress::from_raw(0x2B000);
const BUFFER_VA: VirtualAddress = VirtualAddress::from_raw(0x2D000);
/// Asked for at most this much at a time.
const CHUNK: usize = 256;
pub struct VirtioRng {
regs: Registers,
queue: VirtioQueue,
buffer: Dma,
}
impl VirtioRng {
/// Takes over the virtio-rng device behind `mmio`; `None` if it is not
/// one or any step fails.
pub fn new(mmio: types::bounded::CapSlot) -> Option<Self> {
let regs = Registers::new(libkos::device::map_mmio(mmio, MMIO_VA).ok()?);
if regs.read(hw_virtio::mmio::REG_MAGIC) != hw_virtio::mmio::MAGIC
|| regs.read(hw_virtio::mmio::REG_DEVICE_ID) != hw_virtio::mmio::DEVICE_ID_RNG
{
return None;
}
let rings = libkos::device::dma(PageCount::new(2)?, VQUEUE_VA).ok()?;
let buffer = libkos::device::dma(PageCount::new(1)?, BUFFER_VA).ok()?;
hw_virtio::mmio::init_legacy_device(
&regs,
rings.physical,
hw_virtio::queue::QUEUE_SIZE as u32,
);
Some(Self {
regs,
queue: VirtioQueue::new(rings.window),
buffer,
})
}
}
impl Entropy for VirtioRng {
fn fill(&mut self, buf: &mut [u8]) -> bool {
let mut done = 0;
while done < buf.len() {
let want = (buf.len() - done).min(CHUNK);
let desc = [Descriptor {
addr: self.buffer.physical.raw() as u64,
len: want as u32,
writable: true,
}];
let got = match self.queue.submit_written(&self.regs, &desc) {
Some(n) if n > 0 => (n as usize).min(want),
// The device gave nothing (or never answered): no randomness.
_ => return false,
};
self.buffer
.window
.copy_to(ByteOffset::ZERO, &mut buf[done..done + got]);
done += got;
}
// What was handed out is not left lying in the buffer.
self.buffer.window.fill_u32(ByteOffset::ZERO, CHUNK / 4, 0);
true
}
}