98 lines
2.3 KiB
Rust
98 lines
2.3 KiB
Rust
use crate::consts::Type;use siphasher::sip::SipHasher24 as SipHasher;
|
|
|
|
/// A key used to sign a pointer
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
#[repr(align(16))]
|
|
pub struct PointerKey(pub u64, pub u64);
|
|
|
|
impl PointerKey {
|
|
#[inline(always)]
|
|
fn build_hasher(&self) -> SipHasher {
|
|
SipHasher::new_with_keys(self.0, self.1)
|
|
}
|
|
}
|
|
|
|
/// A signed pointer, the `payload` should never by dereferenced
|
|
/// without verifying the pointer first
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
#[repr(align(16))]
|
|
pub struct Pointer {
|
|
pub hmac: u64,
|
|
pub payload: u64,
|
|
}
|
|
|
|
impl From<Pointer> for PointerKey {
|
|
#[inline(always)]
|
|
/// allows to derive a pointer key from a pointer
|
|
fn from(x: Pointer) -> Self {
|
|
Self(x.hmac, x.payload)
|
|
}
|
|
}
|
|
|
|
impl Pointer {
|
|
fn calculate_hmac(payload: u64, key: &PointerKey) -> u64 {
|
|
use core::hash::Hasher;
|
|
let mut h = key.build_hasher();
|
|
h.write_u64(payload);
|
|
h.finish()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn new_with_key(payload: u64, key: &PointerKey) -> Pointer {
|
|
Pointer {
|
|
hmac: Self::calculate_hmac(payload, key),
|
|
payload,
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn verify(&self, key: &PointerKey) -> Option<u64> {
|
|
if self.hmac == Self::calculate_hmac(self.payload, key) {
|
|
Some(self.payload)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub enum Value {
|
|
Pointer(Pointer),
|
|
Int(u64),
|
|
Bytes(Vec<u8>),
|
|
}
|
|
|
|
impl Value {
|
|
#[inline]
|
|
pub fn typ(&self) -> Type {
|
|
match self {
|
|
Value::Pointer(_) => Type::Pointer,
|
|
Value::Int(_) => Type::Int_,
|
|
Value::Bytes(_) => Type::Bytes,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn pointer_repr() {
|
|
use core::mem;
|
|
assert_eq!(mem::size_of::<PointerKey>(), 16);
|
|
assert_eq!(mem::align_of::<PointerKey>(), 16);
|
|
assert_eq!(mem::size_of::<Pointer>(), 16);
|
|
assert_eq!(mem::align_of::<Pointer>(), 16);
|
|
}
|
|
|
|
#[test]
|
|
fn pointer_usage() {
|
|
let k = PointerKey(0xdead, 0xbeef);
|
|
let p = Pointer::new_with_key(0xfefe, &k);
|
|
// verify that this is the same value on all systems
|
|
assert_eq!(p.hmac, 0xf5779875fe3ef8e);
|
|
assert_eq!(p.verify(&k), Some(0xfefe));
|
|
}
|
|
}
|