securedrop_protocol_minimal/schemes/
challenge.rs1use alloc::vec::Vec;
2use anyhow::Error;
3use rand_core::{CryptoRng, RngCore};
4
5use crate::primitives::provider::{self, chacha20poly1305::KEY_LEN};
6
7use crate::primitives::ristretto255::DHPublicKey;
8
9pub const MAX_MESSAGES: usize = 10;
14
15const CHALLENGE_SALT: &[u8] = b"securedrop-challenge-v1";
17
18pub fn derive_challenge_key(
23 shared_secret: &DHPublicKey,
24 newsroom_id: &[u8],
25) -> Result<[u8; KEY_LEN], Error> {
26 use crate::primitives::provider::hkdf;
27
28 let mut challenge_key: [u8; KEY_LEN] = [0u8; KEY_LEN];
29 hkdf::sha256(
31 &mut challenge_key,
32 CHALLENGE_SALT,
33 &shared_secret.into_bytes(),
34 newsroom_id,
35 )
36 .map_err(|_| anyhow::anyhow!("HKDF challenge key derivation failed"))?;
37
38 Ok(challenge_key)
39}
40
41#[cfg_attr(hax, hax_lib::requires(
46 message_id.len()
47 <= usize::MAX
48 - provider::chacha20poly1305::NONCE_LEN
49 - provider::chacha20poly1305::TAG_LEN
50))]
51pub fn encrypt_message_id(key: &[u8; KEY_LEN], message_id: &[u8]) -> Result<Vec<u8>, Error> {
52 use provider::chacha20poly1305::{NONCE_LEN, TAG_LEN};
53
54 let nonce = [0u8; NONCE_LEN];
56
57 let mut output = alloc::vec::Vec::new();
59 let mut ciphertext = alloc::vec![0u8; message_id.len() + TAG_LEN];
60
61 match provider::chacha20poly1305::encrypt(key, message_id, &mut ciphertext, &[], &nonce) {
63 Ok(_) => {}
64 Err(e) => {
65 return Err(anyhow::anyhow!(
66 "ChaCha20-Poly1305 encryption failed: {:?}",
67 e
68 ));
69 }
70 }
71 output.extend_from_slice(&ciphertext);
72 Ok(output)
73}
74
75pub fn decrypt_message_id(key: &[u8; KEY_LEN], encrypted_data: &[u8]) -> Result<Vec<u8>, Error> {
79 use provider::chacha20poly1305::{NONCE_LEN, TAG_LEN};
80
81 if encrypted_data.len() < TAG_LEN {
82 return Err(anyhow::anyhow!("Encrypted data too short"));
83 }
84
85 let nonce = [0u8; NONCE_LEN];
87
88 let mut plaintext = alloc::vec![0u8; encrypted_data.len() - TAG_LEN];
90
91 provider::chacha20poly1305::decrypt(
93 key,
94 &mut plaintext,
95 encrypted_data,
96 &[], &nonce,
98 )
99 .map_err(|e| anyhow::anyhow!("ChaCha20-Poly1305 decryption failed: {:?}", e))?;
100
101 Ok(plaintext)
102}