use super::{Keychain, RotateKeys};
use crate::{Error, Result};
use bramble_common::transport::{Id, Latency};
use bramble_crypto::{kdf, Role, SymmetricKey};
use futures::{AsyncRead, AsyncWrite};
use std::marker::PhantomData;
pub struct RotationKeys<T>
where
T: Id + Latency + AsyncRead + AsyncWrite,
{
now: u64,
outgoing: Keychain,
incoming_previous: Keychain,
incoming_current: Keychain,
incoming_next: Keychain,
transport: PhantomData<T>,
}
impl<T> RotateKeys for RotationKeys<T>
where
T: Id + Latency + AsyncRead + AsyncWrite,
{
fn outgoing_keys_for(&mut self, period: u64) -> Result<Keychain> {
if period < self.now {
return Err(Error::TimePeriodIsPast);
}
while self.now != period {
self.rotate();
}
Ok(self.outgoing)
}
fn incoming_keys_for(&mut self, period: u64) -> Result<Keychain> {
if period < self.now - 1 {
return Err(Error::TimePeriodIsPast);
}
while period > self.now + 1 {
self.rotate();
}
Ok(if period == self.now - 1 {
self.incoming_previous
} else if period == self.now {
self.incoming_current
} else {
self.incoming_next
})
}
}
impl<T> RotationKeys<T>
where
T: Id + Latency + AsyncRead + AsyncWrite,
{
pub fn new(root_key: SymmetricKey, now: u64, role: Role) -> Self {
let (our_tag_key_label, our_header_key_label, their_tag_key_label, their_header_key_label) =
match role {
Role::Alice => (
ALICE_TAG_KEY_LABEL,
ALICE_HEADER_KEY_LABEL,
BOB_TAG_KEY_LABEL,
BOB_HEADER_KEY_LABEL,
),
Role::Bob => (
BOB_TAG_KEY_LABEL,
BOB_HEADER_KEY_LABEL,
ALICE_TAG_KEY_LABEL,
ALICE_HEADER_KEY_LABEL,
),
};
let outgoing = Keychain::new(
kdf(our_tag_key_label, &root_key, &[T::ID]),
kdf(our_header_key_label, &root_key, &[T::ID]),
)
.next(now);
let incoming_previous = Keychain::new(
kdf(their_tag_key_label, &root_key, &[T::ID]),
kdf(their_header_key_label, &root_key, &[T::ID]),
);
let incoming_current = incoming_previous.next(now);
let incoming_next = incoming_current.next(now + 1);
Self {
now,
outgoing,
incoming_previous,
incoming_current,
incoming_next,
transport: PhantomData,
}
}
pub fn rotate(&mut self) {
self.now += 1;
self.outgoing.rotate(self.now);
self.incoming_previous = self.incoming_current;
self.incoming_current = self.incoming_next;
self.incoming_next.rotate(self.now + 1);
}
}
const ALICE_TAG_KEY_LABEL: &[u8] = b"org.briarproject.bramble.transport/ALICE_TAG_KEY";
const ALICE_HEADER_KEY_LABEL: &[u8] = b"org.briarproject.bramble.transport/ALICE_HEADER_KEY";
const BOB_TAG_KEY_LABEL: &[u8] = b"org.briarproject.bramble.transport/BOB_TAG_KEY";
const BOB_HEADER_KEY_LABEL: &[u8] = b"org.briarproject.bramble.transport/BOB_HEADER_KEY";