Skip to content
This repository has been archived by the owner on Apr 15, 2024. It is now read-only.

[v2.0] Move psk store to user #237

Merged
merged 14 commits into from
May 31, 2022
8 changes: 4 additions & 4 deletions lets/src/id/identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,8 @@ where

// TODO: Find a better way to represent this logic without the need for an additional trait
#[async_trait(?Send)]
impl ContentEncryptSizeOf for sizeof::Context {
async fn encrypt_sizeof(&mut self, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self> {
impl ContentEncryptSizeOf<Identifier> for sizeof::Context {
async fn encrypt_sizeof(&mut self, _recipient: &Identifier, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self> {
// TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey
// introdution)
match <[u8; 32]>::try_from(exchange_key) {
Expand All @@ -265,12 +265,12 @@ impl ContentEncryptSizeOf for sizeof::Context {
}

#[async_trait(?Send)]
impl<OS, F> ContentEncrypt for wrap::Context<OS, F>
impl<OS, F> ContentEncrypt<Identifier> for wrap::Context<OS, F>
where
F: PRP,
OS: io::OStream,
{
async fn encrypt(&mut self, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self> {
async fn encrypt(&mut self, _recipient: &Identifier, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self> {
// TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey
// introdution)
match <[u8; 32]>::try_from(exchange_key) {
Expand Down
19 changes: 2 additions & 17 deletions lets/src/id/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,6 @@ impl Identity {
}
}

// #[deprecated = "to be removed once key exchange is encapsulated within Identity"]
pub fn _ke(&self) -> [u8; 32] {
match self {
Self::Ed25519(ed25519) => {
let x_secret: x25519::SecretKey = ed25519.inner().into();
x_secret.to_bytes()
}
#[cfg(feature = "did")]
Self::DID(DID::PrivateKey(info)) => info.ke_kp().0.to_bytes(),
#[cfg(feature = "did")]
Self::DID(DID::Default) => unreachable!(),
// TODO: Account implementation
}
}

pub fn to_identifier(&self) -> Identifier {
match self {
Self::Ed25519(ed25519) => ed25519.inner().public_key().into(),
Expand Down Expand Up @@ -249,12 +234,12 @@ where
}

#[async_trait(?Send)]
impl<IS, F> ContentDecrypt for unwrap::Context<IS, F>
impl<IS, F> ContentDecrypt<Identity> for unwrap::Context<IS, F>
where
F: PRP,
IS: io::IStream,
{
async fn decrypt(&mut self, exchange_key: &[u8], key: &mut [u8]) -> Result<&mut Self> {
async fn decrypt(&mut self, _recipient: &Identity, exchange_key: &[u8], key: &mut [u8]) -> Result<&mut Self> {
// TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey
// introduction)
match <[u8; 32]>::try_from(exchange_key) {
Expand Down
52 changes: 1 addition & 51 deletions lets/src/id/permission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use spongos::{
};

// Local
use crate::id::{identifier::Identifier, PskId};
use crate::id::identifier::Identifier;

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum PermissionDuration {
Expand Down Expand Up @@ -207,53 +207,3 @@ where
Ok(self)
}
}

impl Mask<&Permissioned<PskId>> for sizeof::Context {
fn mask(&mut self, permission: &Permissioned<PskId>) -> Result<&mut Self> {
match permission {
Permissioned::Read(pskid) => {
let oneof = Uint8::new(0);
self.mask(oneof)?.mask(pskid)?;
Ok(self)
}
_ => return Err(anyhow!("Psk's can only be used as ReadOnly Permissioned")),
}
}
}

impl<OS, F> Mask<&Permissioned<PskId>> for wrap::Context<OS, F>
where
F: PRP,
OS: io::OStream,
{
fn mask(&mut self, permission: &Permissioned<PskId>) -> Result<&mut Self> {
match permission {
Permissioned::Read(pskid) => {
let oneof = Uint8::new(0);
self.mask(oneof)?.mask(pskid)?;
Ok(self)
}
_ => return Err(anyhow!("Psk's can only be used as ReadOnly Permissioned")),
}
}
}

impl<IS, F> Mask<&mut Permissioned<PskId>> for unwrap::Context<IS, F>
where
F: PRP,
IS: io::IStream,
{
fn mask(&mut self, permission: &mut Permissioned<PskId>) -> Result<&mut Self> {
let mut oneof = Uint8::new(0);
self.mask(&mut oneof)?;
match oneof.inner() {
0 => {
let mut psk_id = PskId::default();
self.mask(&mut psk_id)?;
*permission = Permissioned::Read(psk_id);
}
o => return Err(anyhow!("{} is not a valid permission option", o)),
}
Ok(self)
}
}
12 changes: 6 additions & 6 deletions lets/src/message/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ pub trait ContentVerify<T> {
}

#[async_trait(?Send)]
pub trait ContentEncryptSizeOf {
async fn encrypt_sizeof(&mut self, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self>;
pub trait ContentEncryptSizeOf<T> {
async fn encrypt_sizeof(&mut self, recipient: &T, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self>;
}

#[async_trait(?Send)]
pub trait ContentEncrypt {
async fn encrypt(&mut self, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self>;
pub trait ContentEncrypt<T> {
async fn encrypt(&mut self, recipient: &T, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self>;
}

#[async_trait(?Send)]
pub trait ContentDecrypt {
async fn decrypt(&mut self, exchange_key: &[u8], key: &mut [u8]) -> Result<&mut Self>;
pub trait ContentDecrypt<T> {
async fn decrypt(&mut self, recipient: &T, exchange_key: &[u8], key: &mut [u8]) -> Result<&mut Self>;
}
4 changes: 2 additions & 2 deletions streams/src/api/key_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ impl KeyStore {
self.keys.keys().copied()
}

pub(crate) fn get_exchange_key(&self, identifier: &Identifier) -> Option<&[u8]> {
self.keys.get(identifier).map(AsRef::as_ref)
pub(crate) fn get_exchange_key(&self, identifier: &Identifier) -> Option<&x25519::PublicKey> {
DyrellC marked this conversation as resolved.
Show resolved Hide resolved
self.keys.get(identifier)
}
}

Expand Down
38 changes: 23 additions & 15 deletions streams/src/api/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,17 @@ impl User<()> {
}

impl<T> User<T> {
pub(crate) fn new(user_id: Identity, psks: &[(PskId, Psk)], transport: T) -> Self {
pub(crate) fn new<Psks>(user_id: Identity, psks: Psks, transport: T) -> Self
where
Psks: IntoIterator<Item = (PskId, Psk)>,
{
let mut id_store = KeyStore::new();
let mut psk_store = HashMap::new();

// Store any pre shared keys
for (pskid, psk) in psks {
psk_store.insert(*pskid, *psk);
}
psks.into_iter().for_each(|(pskid, psk)| {
psk_store.insert(pskid, psk);
});
arnauorriols marked this conversation as resolved.
Show resolved Hide resolved

id_store.insert_key(user_id.to_identifier(), user_id._ke_sk().public_key());

Expand Down Expand Up @@ -158,7 +161,7 @@ impl<T> User<T> {
}

pub fn remove_psk(&mut self, pskid: PskId) -> bool {
self.state.psk_store.remove(&pskid).is_none()
self.state.psk_store.remove(&pskid).is_some()
}

pub(crate) async fn handle_message(&mut self, address: Address, msg: TransportMessage) -> Result<Message> {
Expand Down Expand Up @@ -288,11 +291,9 @@ impl<T> User<T> {
.expect("a subscriber that has received an stream announcement must keep its spongos in store");

// TODO: Remove Psk from Identity and Identifier, and manage it as a complementary permission
let user_ke_sk = self.state.user_id._ke();
let keyload = keyload::Unwrap::new(
&mut announcement_spongos,
&self.state.user_id,
&user_ke_sk,
author_identifier,
&self.state.psk_store,
);
Expand Down Expand Up @@ -588,7 +589,7 @@ where
) -> Result<SendResponse<TSR>>
where
Subscribers: IntoIterator<Item = Permissioned<Identifier>> + Clone,
Psks: IntoIterator<Item = PskId> + Clone,
Psks: IntoIterator<Item = PskId>,
{
// Check conditions
let stream_address = self
Expand Down Expand Up @@ -624,7 +625,6 @@ where
})
.collect::<Result<Vec<(_, _)>>>()?; // collect to handle possible error
let psk_ids_with_psks = psk_ids
.clone()
.into_iter()
.map(|pskid| {
Ok((
Expand All @@ -639,7 +639,7 @@ where
let content = PCF::new_final_frame().with_content(keyload::Wrap::new(
&mut announcement_spongos,
&subscribers_with_keys,
psk_ids_with_psks,
&psk_ids_with_psks,
encryption_key,
nonce,
&self.state.user_id,
Expand Down Expand Up @@ -672,23 +672,26 @@ where

pub async fn send_keyload_for_all(&mut self, link_to: MsgId) -> Result<SendResponse<TSR>> {
let psks: Vec<PskId> = self.state.psk_store.keys().copied().collect();
let subscribers: Vec<Permissioned<Identifier>> = self.subscribers().map(Permissioned::Read).collect();
self.send_keyload(
link_to,
// Alas, must collect to release the &self immutable borrow
self.subscribers().map(Permissioned::Read).collect::<Vec<_>>(),
subscribers,
psks,
)
.await
}

pub async fn send_keyload_for_all_rw(&mut self, link_to: MsgId) -> Result<SendResponse<TSR>> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm im not sure how this method passed review earlier. Did we get requested to add this method, or are we sure this will be needed in many cases? If thats the case, should we change the default? Alternatively, i think a way to specify the "Permisison type" per identifier is better. (not in this PR, but should be given thought. (I am referring to timed permissions)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth addressing when we get to the high level API rewrite, because defining the Permissions more directly will make more sense semantically once send_keyload assumes the new change_permissions() definition

let psks: Vec<PskId> = self.state.psk_store.keys().copied().collect();
let subscribers: Vec<Permissioned<Identifier>> = self
.subscribers()
.map(|s| Permissioned::ReadWrite(s, PermissionDuration::Perpetual))
.collect();
self.send_keyload(
link_to,
// Alas, must collect to release the &self immutable borrow
self.subscribers()
.map(|s| Permissioned::ReadWrite(s, PermissionDuration::Perpetual))
.collect::<Vec<_>>(),
subscribers,
psks,
)
.await
Expand Down Expand Up @@ -928,9 +931,14 @@ impl<T> Debug for User<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"\n* identifier: <{}>\n{:?}\n* messages:\n{}\n",
"\n* identifier: <{}>\n{:?}\n* PSKs: \n{}\n* messages:\n{}\n",
self.identifier(),
self.state.id_store,
self.state
.psk_store
.keys()
.map(|pskid| format!("\t<{:?}>\n", pskid))
.collect::<String>(),
self.state
.spongos_store
.keys()
Expand Down
2 changes: 1 addition & 1 deletion streams/src/api/user_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ impl<T> UserBuilder<T> {
.transport
.ok_or_else(|| anyhow!("transport not specified, cannot build User without Transport"))?;

Ok(User::new(id, &self.psks, transport))
Ok(User::new(id, self.psks, transport))
}

/// Recover a user instance from the builder parameters.
Expand Down
31 changes: 16 additions & 15 deletions streams/src/message/keyload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ impl<'a, Subscribers, Psks> Wrap<'a, Subscribers, Psks> {
author_id: &'a Identity,
) -> Self
where
Subscribers: IntoIterator<Item = &'a (Permissioned<Identifier>, &'a [u8])> + Clone,
Subscribers: IntoIterator<Item = &'a (Permissioned<Identifier>, &'a x25519::PublicKey)> + Clone,
Subscribers::IntoIter: ExactSizeIterator,
Psks: IntoIterator<Item = (PskId, &'a Psk)> + Clone,
Psks: IntoIterator<Item = &'a (PskId, &'a Psk)> + Clone,
Psks::IntoIter: ExactSizeIterator,
{
Self {
Expand All @@ -105,9 +105,9 @@ impl<'a, Subscribers, Psks> Wrap<'a, Subscribers, Psks> {
#[async_trait(?Send)]
impl<'a, Subscribers, Psks> message::ContentSizeof<Wrap<'a, Subscribers, Psks>> for sizeof::Context
where
Subscribers: IntoIterator<Item = &'a (Permissioned<Identifier>, &'a [u8])> + Clone,
Subscribers: IntoIterator<Item = &'a (Permissioned<Identifier>, &'a x25519::PublicKey)> + Clone,
Subscribers::IntoIter: ExactSizeIterator,
Psks: IntoIterator<Item = (PskId, &'a Psk)> + Clone,
Psks: IntoIterator<Item = &'a (PskId, &'a Psk)> + Clone,
Psks::IntoIter: ExactSizeIterator,
{
async fn sizeof(&mut self, keyload: &Wrap<'a, Subscribers, Psks>) -> Result<&mut sizeof::Context> {
Expand All @@ -120,14 +120,14 @@ where
for (subscriber, exchange_key) in subscribers {
self.fork()
.mask(subscriber)?
.encrypt_sizeof(exchange_key, &keyload.key)
.encrypt_sizeof(subscriber.identifier(), &exchange_key.to_bytes(), &keyload.key)
.await?;
}
self.absorb(n_psks)?;
// Loop through provided pskids, masking the shared key for each one
for (pskid, psk) in psks {
self.fork()
.mask(&pskid)?
.mask(pskid)?
.absorb(External::new(&NBytes::new(psk)))?
.commit()?
.mask(NBytes::new(&keyload.key))?;
Expand All @@ -143,9 +143,9 @@ where
#[async_trait(?Send)]
impl<'a, OS, Subscribers, Psks> message::ContentWrap<Wrap<'a, Subscribers, Psks>> for wrap::Context<OS>
where
Subscribers: IntoIterator<Item = &'a (Permissioned<Identifier>, &'a [u8])> + Clone,
Subscribers: IntoIterator<Item = &'a (Permissioned<Identifier>, &'a x25519::PublicKey)> + Clone,
Subscribers::IntoIter: ExactSizeIterator,
Psks: IntoIterator<Item = (PskId, &'a Psk)> + Clone,
Psks: IntoIterator<Item = &'a (PskId, &'a Psk)> + Clone,
Psks::IntoIter: ExactSizeIterator,
OS: io::OStream,
{
Expand All @@ -161,14 +161,14 @@ where
for (subscriber, exchange_key) in subscribers {
self.fork()
.mask(subscriber)?
.encrypt(exchange_key, &keyload.key)
.encrypt(subscriber.identifier(), &exchange_key.to_bytes(), &keyload.key)
.await?;
}
self.absorb(n_psks)?;
// Loop through provided pskids, masking the shared key for each one
for (pskid, psk) in psks {
self.fork()
.mask(&pskid)?
.mask(pskid)?
.absorb(External::new(&NBytes::new(psk)))?
.commit()?
.mask(NBytes::new(&keyload.key))?;
Expand All @@ -188,14 +188,12 @@ pub(crate) struct Unwrap<'a> {
psk_store: &'a HashMap<PskId, Psk>,
author_id: Identifier,
user_id: &'a Identity,
user_ke_key: &'a [u8],
}

impl<'a> Unwrap<'a> {
pub(crate) fn new(
initial_state: &'a mut Spongos,
user_id: &'a Identity,
user_ke_key: &'a [u8],
author_id: Identifier,
psk_store: &'a HashMap<PskId, Psk>,
) -> Self {
Expand All @@ -206,7 +204,6 @@ impl<'a> Unwrap<'a> {
psk_store,
author_id,
user_id,
user_ke_key,
}
}

Expand Down Expand Up @@ -244,8 +241,12 @@ where
fork.mask(&mut subscriber_id)?;

if subscriber_id.identifier() == &keyload.user_id.to_identifier() {
fork.decrypt(keyload.user_ke_key, key.get_or_insert([0u8; KEY_SIZE]))
.await?;
fork.decrypt(
keyload.user_id,
&keyload.user_id._ke_sk().to_bytes(),
key.get_or_insert([0u8; KEY_SIZE]),
)
.await?;
} else {
// Key is meant for another subscriber, skip it
fork.drop(KEY_SIZE + x25519::PUBLIC_KEY_LENGTH)?;
Expand Down