Skip to content

Commit c6dee56

Browse files
committed
feat: Save the secret to encrypt and decrypt messages. Next: Send it in a 'member added' message.
1 parent 8c6494f commit c6dee56

File tree

7 files changed

+74
-14
lines changed

7 files changed

+74
-14
lines changed

src/chat/chat_tests.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2889,6 +2889,45 @@ async fn test_block_broadcast() -> Result<()> {
28892889
Ok(())
28902890
}
28912891

2892+
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
2893+
async fn test_encrypt_decrypt_broadcast_integration() -> Result<()> {
2894+
let mut tcm = TestContextManager::new();
2895+
let alice = &tcm.alice().await;
2896+
let bob = &tcm.bob().await;
2897+
let bob_without_secret = &tcm.bob().await;
2898+
2899+
let secret = "secret";
2900+
2901+
let alice_bob_contact_id = alice.add_or_lookup_contact_id(bob).await;
2902+
2903+
tcm.section("Create a broadcast channel with Bob, and send a message");
2904+
let alice_chat_id = create_broadcast(alice, "My Channel".to_string()).await?;
2905+
add_contact_to_chat(alice, alice_chat_id, alice_bob_contact_id).await?;
2906+
2907+
let mut alice_chat = Chat::load_from_db(alice, alice_chat_id).await?;
2908+
alice_chat.param.set(Param::SymmetricKey, secret);
2909+
alice_chat.update_param(alice).await?;
2910+
2911+
// TODO the chat_id 10 is magical here:
2912+
bob.sql
2913+
.execute(
2914+
"INSERT INTO broadcasts_shared_secrets (chat_id, secret) VALUES (10, ?)",
2915+
(secret,),
2916+
)
2917+
.await?;
2918+
2919+
let sent = alice
2920+
.send_text(alice_chat_id, "Symmetrically encrypted message")
2921+
.await;
2922+
let rcvd = bob.recv_msg(&sent).await;
2923+
assert_eq!(rcvd.text, "Symmetrically encrypted message");
2924+
2925+
tcm.section("If Bob doesn't know the secret, he can't decrypt the message");
2926+
bob_without_secret.recv_msg_trash(&sent).await;
2927+
2928+
Ok(())
2929+
}
2930+
28922931
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
28932932
async fn test_create_for_contact_with_blocked() -> Result<()> {
28942933
let t = TestContext::new().await;

src/decrypt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::pgp;
1414
pub fn try_decrypt<'a>(
1515
mail: &'a ParsedMail<'a>,
1616
private_keyring: &'a [SignedSecretKey],
17-
symmetric_secrets: &[&str],
17+
symmetric_secrets: &[String],
1818
) -> Result<Option<::pgp::composed::Message<'static>>> {
1919
let Some(encrypted_data_part) = get_encrypted_mime(mail) else {
2020
return Ok(None);

src/mimefactory.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,7 @@ impl MimeFactory {
11331133
};
11341134

11351135
let encrypted = if let Some(symmetric_key) = symmetric_key {
1136+
info!(context, "Symmetrically encrypting for broadcast channel.");
11361137
encrypt_helper
11371138
.encrypt_for_broadcast(context, symmetric_key, message, compress)
11381139
.await?

src/mimeparser.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,21 @@ impl MimeMessage {
333333

334334
let mail_raw; // Memory location for a possible decrypted message.
335335
let decrypted_msg; // Decrypted signed OpenPGP message.
336-
let symmetric_secrets =
336+
let symmetric_secrets: Vec<String> = context
337+
.sql
338+
.query_map(
339+
"SELECT secret FROM broadcasts_shared_secrets",
340+
(),
341+
|row| row.get(0),
342+
|rows| {
343+
rows.collect::<std::result::Result<Vec<_>, _>>()
344+
.map_err(Into::into)
345+
},
346+
)
347+
.await?;
337348

338349
let (mail, is_encrypted) = match tokio::task::block_in_place(|| {
339-
try_decrypt(&mail, &private_keyring, symmetric_secrets)
350+
try_decrypt(&mail, &private_keyring, &symmetric_secrets)
340351
}) {
341352
Ok(Some(mut msg)) => {
342353
mail_raw = msg.as_data_vec().unwrap_or_default();

src/param.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ 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`]:
172+
/// For Chats of type [`Chattype::OutBroadcast`] and [`Chattype::InBroadcast`]: // TODO (or just OutBroadcast)
173173
/// The symmetric key shared among all chat participants,
174174
/// used to encrypt and decrypt messages.
175175
SymmetricKey = b'z',

src/pgp.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ pub fn pk_calc_signature(
239239
pub fn decrypt(
240240
ctext: Vec<u8>,
241241
private_keys_for_decryption: &[SignedSecretKey],
242-
symmetric_secrets: &[&str],
242+
symmetric_secrets: &[String],
243243
) -> Result<pgp::composed::Message<'static>> {
244244
let cursor = Cursor::new(ctext);
245245
let (msg, _headers) = Message::from_armor(cursor)?;
@@ -250,7 +250,7 @@ pub fn decrypt(
250250
// TODO it may degrade performance that we always try out all passwords here
251251
let message_password: Vec<Password> = symmetric_secrets
252252
.iter()
253-
.map(|p| Password::from(*p))
253+
.map(|p| Password::from(p.as_str()))
254254
.collect();
255255
let message_password: Vec<&Password> = message_password.iter().collect();
256256

@@ -320,7 +320,7 @@ pub async fn symm_encrypt(passphrase: &str, plain: Vec<u8>) -> Result<String> {
320320
tokio::task::spawn_blocking(move || {
321321
let mut rng = thread_rng();
322322
let s2k = StringToKey::new_default(&mut rng);
323-
let builder = MessageBuilder::from_bytes("", plain);
323+
let builder: MessageBuilder<'_> = MessageBuilder::from_bytes("", plain);
324324
let mut builder = builder.seipd_v1(&mut rng, SYMMETRIC_KEY_ALGORITHM);
325325
builder.encrypt_with_password(s2k, &passphrase)?;
326326

@@ -389,7 +389,7 @@ mod tests {
389389
use super::*;
390390
use crate::{
391391
key::load_self_secret_key,
392-
test_utils::{TestContext, TestContextManager, alice_keypair, bob_keypair},
392+
test_utils::{TestContextManager, alice_keypair, bob_keypair},
393393
};
394394

395395
fn pk_decrypt_and_validate<'a>(
@@ -401,7 +401,7 @@ mod tests {
401401
HashSet<Fingerprint>,
402402
Vec<u8>,
403403
)> {
404-
let mut msg = decrypt(ctext.to_vec(), private_keys_for_decryption)?;
404+
let mut msg = decrypt(ctext.to_vec(), private_keys_for_decryption, &[])?;
405405
let content = msg.as_data_vec()?;
406406
let ret_signature_fingerprints =
407407
valid_signature_fingerprints(&msg, public_keys_for_validation)?;
@@ -597,15 +597,21 @@ mod tests {
597597
let plain = Vec::from(b"this is the secret message");
598598
let shared_secret = "shared secret";
599599
let ctext = encrypt_for_broadcast(
600-
plain,
600+
plain.clone(),
601601
shared_secret,
602602
load_self_secret_key(alice).await?,
603603
true,
604604
)
605605
.await?;
606606

607607
let bob_private_keyring = crate::key::load_self_secret_keyring(bob).await?;
608-
let decrypted = decrypt(ctext.into(), &bob_private_keyring)?;
608+
let mut decrypted = decrypt(
609+
ctext.into(),
610+
&bob_private_keyring,
611+
&[shared_secret.to_string()],
612+
)?;
613+
614+
assert_eq!(decrypted.as_data_vec()?, plain);
609615

610616
Ok(())
611617
}

src/sql/migrations.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,10 +1250,13 @@ CREATE INDEX gossip_timestamp_index ON gossip_timestamp (chat_id, fingerprint);
12501250
inc_and_check(&mut migration_version, 133)?;
12511251
if dbversion < migration_version {
12521252
sql.execute_migration(
1253-
"CREATE TABLE symmetric_secrets(
1254-
chat_id INTEGER PRIMARY KEY NOT NULL,
1255-
symmetric_secret: ",
1253+
"CREATE TABLE broadcasts_shared_secrets(
1254+
chat_id INTEGER PRIMARY KEY NOT NULL, -- TODO we don't actually need the chat_id
1255+
secret TEXT NOT NULL
1256+
) STRICT",
1257+
migration_version,
12561258
)
1259+
.await?;
12571260
}
12581261

12591262
let new_version = sql

0 commit comments

Comments
 (0)