Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
aumetra committed Dec 10, 2023
1 parent 3453708 commit d5c65c3
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 9 deletions.
54 changes: 51 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions lib/csurf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ edition.workspace = true
version.workspace = true

[dependencies]
aliri_braid = "0.4.0"
blake3 = "1.5.0"
cookie = "0.18.0"
hex-simd = "0.8.0"
http = "0.2.11"
rand = "0.8.5"
tower = { version = "0.4.13", default-features = false }
zeroize = { version = "1.7.0", features = ["derive"] }

Expand Down
84 changes: 78 additions & 6 deletions lib/csurf/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,105 @@
use hex_simd::{AsciiCase, Out};
use http::{Request, Response};
use std::task::{self, Poll};
use rand::RngCore;
use std::{
fmt::Display,
sync::{Arc, Mutex},
task::{self, Poll},
};
use tower::{Layer, Service};
use zeroize::{Zeroize, ZeroizeOnDrop};

#[aliri_braid::braid]
pub struct Hash;

#[aliri_braid::braid]
pub struct Message;

struct Shared {
read_data: Option<(Hash, Message)>,
set_data: Option<(Hash, Message)>,
}

#[derive(Zeroize, ZeroizeOnDrop)]
pub struct Signer {}
pub struct CsrfHandle {
#[zeroize(skip)]
inner: Arc<Mutex<Shared>>,
key: [u8; blake3::KEY_LEN],
}

fn raw_verify(key: &[u8; blake3::KEY_LEN], hash: &HashRef, message: &MessageRef) -> bool {
let (hash, message) = (hash.as_ref(), message.as_ref());
if hash.len() / 2 != blake3::OUT_LEN {
return false;
}

let mut decoded_hash = [0_u8; blake3::OUT_LEN];
if hex_simd::decode(hash.as_bytes(), Out::from_slice(&mut decoded_hash)).is_err() {
return false;
}

let expected_hash = blake3::keyed_hash(key, message.as_bytes());

// The `PartialEq` implementation on `Hash` is constant-time
expected_hash == decoded_hash
}

impl CsrfHandle {
pub fn sign<SID>(&self, session_id: SID) -> Message
where
SID: AsRef<[u8]> + Display,
{
let mut buf = [0; 16];
rand::thread_rng().fill_bytes(&mut buf);
let random = hex_simd::encode_to_string(buf, AsciiCase::Lower);

let message = format!("{session_id}!{random}");
let hash = blake3::keyed_hash(&self.key, message.as_bytes());
let hash = hex_simd::encode_to_string(hash.as_bytes(), AsciiCase::Lower);

let message: Message = message.into();
self.inner.lock().unwrap().set_data = Some((hash.into(), message.clone()));

message
}

#[must_use]
pub fn verify(&self, message: &MessageRef) -> bool {
let guard = self.inner.lock().unwrap();
let Some(ref read_data) = guard.read_data else {
return false;
};

if !raw_verify(&self.key, &read_data.0, &read_data.1) {
return false;
}

raw_verify(&self.key, &read_data.0, message)
}
}

#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct CsrfLayer {
key: Vec<u8>,
key: [u8; blake3::KEY_LEN],
}

impl<S> Layer<S> for CsrfLayer {
type Service = CsrfService<S>;

fn layer(&self, inner: S) -> Self::Service {
CsrfService::new(inner, self.key.clone())
CsrfService::new(inner, self.key)
}
}

#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct CsrfService<S> {
#[zeroize(skip)]
inner: S,
key: Vec<u8>,
key: [u8; blake3::KEY_LEN],
}

impl<S> CsrfService<S> {
pub fn new(inner: S, key: Vec<u8>) -> Self {
pub fn new(inner: S, key: [u8; blake3::KEY_LEN]) -> Self {
Self { inner, key }
}
}
Expand Down

0 comments on commit d5c65c3

Please sign in to comment.