mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-02-10 17:03:12 +00:00
Make Introduction encode/decode symmetric
This commit is contained in:
parent
fe23c39321
commit
4a32a21dd2
@ -6,9 +6,11 @@ use crate::{
|
|||||||
conversation::{ConversationId, ConversationIdOwned, ConversationStore},
|
conversation::{ConversationId, ConversationIdOwned, ConversationStore},
|
||||||
identity::Identity,
|
identity::Identity,
|
||||||
inbox::Inbox,
|
inbox::Inbox,
|
||||||
|
proto,
|
||||||
types::{ContentData, PayloadData},
|
types::{ContentData, PayloadData},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use crate::inbox::Introduction;
|
||||||
// This is the main entry point to the conversations api.
|
// This is the main entry point to the conversations api.
|
||||||
// Ctx manages lifetimes of objects to process and generate payloads.
|
// Ctx manages lifetimes of objects to process and generate payloads.
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
@ -30,17 +32,16 @@ impl Context {
|
|||||||
|
|
||||||
pub fn create_private_convo(
|
pub fn create_private_convo(
|
||||||
&mut self,
|
&mut self,
|
||||||
remote_bundle: &PrekeyBundle,
|
remote_bundle: &Introduction,
|
||||||
content: String,
|
content: String,
|
||||||
) -> ConversationIdOwned {
|
) -> (ConversationIdOwned, Vec<proto::EncryptedPayload>) {
|
||||||
let (convo, _payloads) = self
|
let (convo, payloads) = self
|
||||||
.inbox
|
.inbox
|
||||||
.invite_to_private_convo(remote_bundle, content)
|
.invite_to_private_convo(remote_bundle, content)
|
||||||
.unwrap_or_else(|_| todo!("Log/Surface Error"));
|
.unwrap_or_else(|_| todo!("Log/Surface Error"));
|
||||||
|
|
||||||
self.store.insert_convo(convo)
|
let convo_id = self.store.insert_convo(convo);
|
||||||
|
(convo_id, payloads)
|
||||||
// TODO: Change return type to handle outbout packets.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_content(&mut self, _convo_id: ConversationId, _content: &[u8]) -> Vec<PayloadData> {
|
pub fn send_content(&mut self, _convo_id: ConversationId, _content: &[u8]) -> Vec<PayloadData> {
|
||||||
|
|||||||
@ -12,4 +12,8 @@ pub enum ChatError {
|
|||||||
BadBundleValue(String),
|
BadBundleValue(String),
|
||||||
#[error("handshake initiated with a unknown ephemeral key")]
|
#[error("handshake initiated with a unknown ephemeral key")]
|
||||||
UnknownEphemeralKey(),
|
UnknownEphemeralKey(),
|
||||||
|
#[error("expected a different key length")]
|
||||||
|
InvalidKeyLength,
|
||||||
|
#[error("bytes provided to {0} failed")]
|
||||||
|
BadParsing(&'static str),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
mod handshake;
|
mod handshake;
|
||||||
mod inbox;
|
mod inbox;
|
||||||
|
mod introduction;
|
||||||
|
|
||||||
pub use inbox::Inbox;
|
pub use inbox::Inbox;
|
||||||
|
pub use introduction::Introduction;
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use crypto::{PrekeyBundle, SecretKey};
|
use crypto::{PrekeyBundle, SecretKey};
|
||||||
|
|
||||||
|
use crate::context::Introduction;
|
||||||
use crate::conversation::{ChatError, ConversationId, Convo, ConvoFactory, Id, PrivateV1Convo};
|
use crate::conversation::{ChatError, ConversationId, Convo, ConvoFactory, Id, PrivateV1Convo};
|
||||||
use crate::crypto::{Blake2b128, CopyBytes, Digest, PublicKey, StaticSecret};
|
use crate::crypto::{Blake2b128, CopyBytes, Digest, PublicKey, StaticSecret};
|
||||||
use crate::identity::Identity;
|
use crate::identity::Identity;
|
||||||
@ -66,13 +67,21 @@ impl Inbox {
|
|||||||
|
|
||||||
pub fn invite_to_private_convo(
|
pub fn invite_to_private_convo(
|
||||||
&self,
|
&self,
|
||||||
remote_bundle: &PrekeyBundle,
|
remote_bundle: &Introduction,
|
||||||
initial_message: String,
|
initial_message: String,
|
||||||
) -> Result<(PrivateV1Convo, Vec<proto::EncryptedPayload>), ChatError> {
|
) -> Result<(PrivateV1Convo, Vec<proto::EncryptedPayload>), ChatError> {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
||||||
|
// TODO: Include signature in introduction bundle. Manaully fill for now
|
||||||
|
let pkb = PrekeyBundle {
|
||||||
|
identity_key: remote_bundle.installation_key,
|
||||||
|
signed_prekey: remote_bundle.ephemeral_key,
|
||||||
|
signature: [0u8; 64],
|
||||||
|
onetime_prekey: None,
|
||||||
|
};
|
||||||
|
|
||||||
let (seed_key, ephemeral_pub) =
|
let (seed_key, ephemeral_pub) =
|
||||||
InboxHandshake::perform_as_initiator(&self.ident.secret(), remote_bundle, &mut rng);
|
InboxHandshake::perform_as_initiator(&self.ident.secret(), &pkb, &mut rng);
|
||||||
|
|
||||||
let mut convo = PrivateV1Convo::new(seed_key);
|
let mut convo = PrivateV1Convo::new(seed_key);
|
||||||
|
|
||||||
@ -89,8 +98,8 @@ impl Inbox {
|
|||||||
let header = proto::InboxHeaderV1 {
|
let header = proto::InboxHeaderV1 {
|
||||||
initiator_static: self.ident.public_key().copy_to_bytes(),
|
initiator_static: self.ident.public_key().copy_to_bytes(),
|
||||||
initiator_ephemeral: ephemeral_pub.copy_to_bytes(),
|
initiator_ephemeral: ephemeral_pub.copy_to_bytes(),
|
||||||
responder_static: remote_bundle.identity_key.copy_to_bytes(),
|
responder_static: remote_bundle.installation_key.copy_to_bytes(),
|
||||||
responder_ephemeral: remote_bundle.signed_prekey.copy_to_bytes(),
|
responder_ephemeral: remote_bundle.ephemeral_key.copy_to_bytes(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let handshake = proto::InboxHandshakeV1 {
|
let handshake = proto::InboxHandshakeV1 {
|
||||||
@ -226,7 +235,7 @@ mod tests {
|
|||||||
|
|
||||||
let bundle = raya_inbox.create_bundle();
|
let bundle = raya_inbox.create_bundle();
|
||||||
let (_, payloads) = saro_inbox
|
let (_, payloads) = saro_inbox
|
||||||
.invite_to_private_convo(&bundle, "hello".into())
|
.invite_to_private_convo(&bundle.into(), "hello".into())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let encrypted_payload = payloads
|
let encrypted_payload = payloads
|
||||||
|
|||||||
65
conversations/src/inbox/introduction.rs
Normal file
65
conversations/src/inbox/introduction.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use crypto::PrekeyBundle;
|
||||||
|
use x25519_dalek::PublicKey;
|
||||||
|
|
||||||
|
use crate::errors::ChatError;
|
||||||
|
|
||||||
|
/// Supplies remote participants with the required keys to use Inbox protocol
|
||||||
|
pub struct Introduction {
|
||||||
|
pub installation_key: PublicKey,
|
||||||
|
pub ephemeral_key: PublicKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PrekeyBundle> for Introduction {
|
||||||
|
fn from(value: PrekeyBundle) -> Self {
|
||||||
|
Introduction {
|
||||||
|
installation_key: value.identity_key,
|
||||||
|
ephemeral_key: value.signed_prekey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Vec<u8>> for Introduction {
|
||||||
|
fn into(self) -> Vec<u8> {
|
||||||
|
// TODO: avoid copies, via writing directly to slice
|
||||||
|
let link = format!(
|
||||||
|
"Bundle:{}:{}",
|
||||||
|
hex::encode(self.installation_key.as_bytes()),
|
||||||
|
hex::encode(self.ephemeral_key.as_bytes()),
|
||||||
|
);
|
||||||
|
|
||||||
|
link.into_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for Introduction {
|
||||||
|
type Error = ChatError;
|
||||||
|
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
|
let str_value =
|
||||||
|
String::from_utf8(value).map_err(|_| ChatError::BadParsing("Introduction"))?;
|
||||||
|
let parts: Vec<&str> = str_value.splitn(3, ':').collect();
|
||||||
|
|
||||||
|
if parts[0] != "Bundle" {
|
||||||
|
return Err(ChatError::BadBundleValue(
|
||||||
|
"not recognized as an introduction bundle".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let installation_bytes: [u8; 32] = hex::decode(parts[1])
|
||||||
|
.map_err(|_| ChatError::BadParsing("installation_key"))?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| ChatError::InvalidKeyLength)?;
|
||||||
|
let installation_key = PublicKey::from(installation_bytes);
|
||||||
|
|
||||||
|
let ephemeral_bytes: [u8; 32] = hex::decode(parts[1])
|
||||||
|
.map_err(|_| ChatError::BadParsing("ephemeral_key"))?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| ChatError::InvalidKeyLength)?;
|
||||||
|
let ephemeral_key = PublicKey::from(ephemeral_bytes);
|
||||||
|
|
||||||
|
Ok(Introduction {
|
||||||
|
installation_key,
|
||||||
|
ephemeral_key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user