Skip to content

Commit fab39fd

Browse files
committed
WIP, untested: Sending side of transferring the secret in member-added message
1 parent 6366439 commit fab39fd

File tree

5 files changed

+54
-7
lines changed

5 files changed

+54
-7
lines changed

src/chat.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ use crate::smtp::send_msg_to_smtp;
4242
use crate::stock_str;
4343
use crate::sync::{self, Sync::*, SyncData};
4444
use crate::tools::{
45-
IsNoneOrEmpty, SystemTime, buf_compress, create_id, create_outgoing_rfc724_mid,
46-
create_smeared_timestamp, create_smeared_timestamps, get_abs_path, gm2local_offset,
47-
smeared_time, time, truncate_msg_text,
45+
IsNoneOrEmpty, SystemTime, buf_compress, create_broadcast_shared_secret, create_id,
46+
create_outgoing_rfc724_mid, create_smeared_timestamp, create_smeared_timestamps, get_abs_path,
47+
gm2local_offset, smeared_time, time, truncate_msg_text,
4848
};
4949
use crate::webxdc::StatusUpdateSerial;
5050
use crate::{chatlist_events, imap};
@@ -3710,14 +3710,18 @@ pub(crate) async fn create_broadcast_ex(
37103710
},
37113711
)?);
37123712
}
3713+
let mut param = Params::new();
3714+
// param.set(Param::Unpromoted, 1); // TODO broadcasts will just never be unpromoted for now
3715+
param.set(Param::SymmetricKey, create_broadcast_shared_secret());
37133716
t.execute(
37143717
"INSERT INTO chats \
37153718
(type, name, grpid, param, created_timestamp) \
3716-
VALUES(?, ?, ?, \'U=1\', ?);",
3719+
VALUES(?, ?, ?, ?, ?);",
37173720
(
37183721
Chattype::OutBroadcast,
37193722
&chat_name,
37203723
&grpid,
3724+
param.to_string(),
37213725
create_smeared_timestamp(context),
37223726
),
37233727
)?;
@@ -3918,7 +3922,7 @@ pub(crate) async fn add_contact_to_chat_ex(
39183922
}
39193923
add_to_chat_contacts_table(context, time(), chat_id, &[contact_id]).await?;
39203924
}
3921-
if chat.typ == Chattype::Group && chat.is_promoted() {
3925+
if chat.is_promoted() {
39223926
msg.viewtype = Viewtype::Text;
39233927

39243928
let contact_addr = contact.get_addr().to_lowercase();

src/headerdef.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ pub enum HeaderDef {
9393
/// This message obsoletes the text of the message defined here by rfc724_mid.
9494
ChatEdit,
9595

96+
/// The secret shared amongst all recipients of this broadcast channel.
97+
/// This secret.
98+
ChatBroadcastSecret,
99+
96100
/// [Autocrypt](https://autocrypt.org/) header.
97101
Autocrypt,
98102
AutocryptGossip,

src/mimefactory.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ impl MimeFactory {
789789
}
790790
}
791791

792-
if let Loaded::Message { chat, .. } = &self.loaded {
792+
if let Loaded::Message { msg, chat } = &self.loaded {
793793
if chat.typ == Chattype::OutBroadcast || chat.typ == Chattype::InBroadcast {
794794
headers.push((
795795
"List-ID",
@@ -799,6 +799,15 @@ impl MimeFactory {
799799
))
800800
.into(),
801801
));
802+
803+
if msg.param.get_cmd() == SystemMessage::MemberAddedToGroup {
804+
if let Some(secret) = chat.param.get(Param::SymmetricKey) {
805+
headers.push((
806+
"Chat-Broadcast-Secret",
807+
mail_builder::headers::text::Text::new(secret.to_string()).into(),
808+
));
809+
}
810+
}
802811
}
803812
}
804813

@@ -979,6 +988,15 @@ impl MimeFactory {
979988
} else {
980989
unprotected_headers.push(header.clone());
981990
}
991+
} else if header_name == "chat-broadcast-secret" {
992+
if is_encrypted {
993+
protected_headers.push(header.clone());
994+
} else {
995+
warn!(
996+
context,
997+
"Message is unnecrypted, not including broadcast secret"
998+
);
999+
}
9821000
} else if is_encrypted {
9831001
protected_headers.push(header.clone());
9841002

src/param.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ pub enum Param {
169169
/// post something to the mailing list.
170170
ListPost = b'p',
171171

172-
/// For Chats of type [`Chattype::OutBroadcast`] and [`Chattype::InBroadcast`]: // TODO (or just OutBroadcast)
172+
/// For Chats and Messages:
173+
/// For chats of type [`Chattype::OutBroadcast`] and [`Chattype::InBroadcast`] // TODO (or just OutBroadcast)
174+
/// and for messages adding members to such a chat.
173175
/// The symmetric key shared among all chat participants,
174176
/// used to encrypt and decrypt messages.
175177
SymmetricKey = b'z',

src/tools.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,25 @@ pub(crate) fn create_id() -> String {
300300
base64::engine::general_purpose::URL_SAFE.encode(arr)
301301
}
302302

303+
/// Generate a shared secret for a broadcast channel, consisting of 64 characters..
304+
///
305+
/// The string generated by this function has 384 bits of entropy
306+
/// and is returned as 64 Base64 characters, each containing 6 bits of entropy.
307+
/// 384 is chosen because it is sufficiently secure
308+
/// (larger than AES-128 keys used for message encryption)
309+
/// and divides both by 8 (byte size) and 6 (number of bits in a single Base64 character).
310+
// TODO ask someone what a good size would be here
311+
pub(crate) fn create_broadcast_shared_secret() -> String {
312+
// ThreadRng implements CryptoRng trait and is supposed to be cryptographically secure.
313+
let mut rng = thread_rng();
314+
315+
// Generate 384 random bits.
316+
let mut arr = [0u8; 48];
317+
rng.fill(&mut arr[..]);
318+
319+
base64::engine::general_purpose::URL_SAFE.encode(arr)
320+
}
321+
303322
/// Returns true if given string is a valid ID.
304323
///
305324
/// All IDs generated with `create_id()` should be considered valid.

0 commit comments

Comments
 (0)