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:
10
crates/drivers/rng/virtio/Cargo.toml
Normal file
10
crates/drivers/rng/virtio/Cargo.toml
Normal 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 }
|
||||
74
crates/drivers/rng/virtio/src/lib.rs
Normal file
74
crates/drivers/rng/virtio/src/lib.rs
Normal 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(
|
||||
®s,
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user