libsignal_protocol/
group_cipher.rs

1//
2// Copyright 2020-2021 Signal Messenger, LLC.
3// SPDX-License-Identifier: AGPL-3.0-only
4//
5
6use rand::{CryptoRng, Rng};
7use uuid::Uuid;
8
9use crate::protocol::SENDERKEY_MESSAGE_CURRENT_VERSION;
10use crate::sender_keys::{SenderKeyState, SenderMessageKey};
11use crate::{
12    consts, CiphertextMessageType, KeyPair, ProtocolAddress, Result, SenderKeyDistributionMessage,
13    SenderKeyMessage, SenderKeyRecord, SenderKeyStore, SignalProtocolError,
14};
15
16pub async fn group_encrypt<R: Rng + CryptoRng>(
17    sender_key_store: &mut dyn SenderKeyStore,
18    sender: &ProtocolAddress,
19    distribution_id: Uuid,
20    plaintext: &[u8],
21    csprng: &mut R,
22) -> Result<SenderKeyMessage> {
23    let mut record = sender_key_store
24        .load_sender_key(sender, distribution_id)
25        .await?
26        .ok_or(SignalProtocolError::NoSenderKeyState { distribution_id })?;
27
28    let sender_key_state = record
29        .sender_key_state_mut()
30        .map_err(|_| SignalProtocolError::InvalidSenderKeySession { distribution_id })?;
31
32    let message_version = sender_key_state
33        .message_version()
34        .try_into()
35        .map_err(|_| SignalProtocolError::InvalidSenderKeySession { distribution_id })?;
36
37    let sender_chain_key = sender_key_state
38        .sender_chain_key()
39        .ok_or(SignalProtocolError::InvalidSenderKeySession { distribution_id })?;
40
41    let message_keys = sender_chain_key.sender_message_key();
42
43    let ciphertext =
44        signal_crypto::aes_256_cbc_encrypt(plaintext, message_keys.cipher_key(), message_keys.iv())
45            .map_err(|_| {
46                log::error!(
47                    "outgoing sender key state corrupt for distribution ID {distribution_id}",
48                );
49                SignalProtocolError::InvalidSenderKeySession { distribution_id }
50            })?;
51
52    let signing_key = sender_key_state
53        .signing_key_private()
54        .map_err(|_| SignalProtocolError::InvalidSenderKeySession { distribution_id })?;
55
56    let skm = SenderKeyMessage::new(
57        message_version,
58        distribution_id,
59        sender_key_state.chain_id(),
60        message_keys.iteration(),
61        ciphertext.into_boxed_slice(),
62        csprng,
63        &signing_key,
64    )?;
65
66    sender_key_state.set_sender_chain_key(sender_chain_key.next()?);
67
68    sender_key_store
69        .store_sender_key(sender, distribution_id, &record)
70        .await?;
71
72    Ok(skm)
73}
74
75fn get_sender_key(
76    state: &mut SenderKeyState,
77    iteration: u32,
78    distribution_id: Uuid,
79) -> Result<SenderMessageKey> {
80    let sender_chain_key = state
81        .sender_chain_key()
82        .ok_or(SignalProtocolError::InvalidSenderKeySession { distribution_id })?;
83    let current_iteration = sender_chain_key.iteration();
84
85    if current_iteration > iteration {
86        if let Some(smk) = state.remove_sender_message_key(iteration) {
87            return Ok(smk);
88        } else {
89            log::info!(
90                "SenderKey distribution {distribution_id} Duplicate message for iteration: {iteration}"
91            );
92            return Err(SignalProtocolError::DuplicatedMessage(
93                current_iteration,
94                iteration,
95            ));
96        }
97    }
98
99    let jump = (iteration - current_iteration) as usize;
100    if jump > consts::MAX_FORWARD_JUMPS {
101        log::error!(
102            "SenderKey distribution {} Exceeded future message limit: {}, current iteration: {})",
103            distribution_id,
104            consts::MAX_FORWARD_JUMPS,
105            current_iteration
106        );
107        return Err(SignalProtocolError::InvalidMessage(
108            CiphertextMessageType::SenderKey,
109            "message from too far into the future",
110        ));
111    }
112
113    let mut sender_chain_key = sender_chain_key;
114
115    while sender_chain_key.iteration() < iteration {
116        state.add_sender_message_key(&sender_chain_key.sender_message_key());
117        sender_chain_key = sender_chain_key.next()?;
118    }
119
120    state.set_sender_chain_key(sender_chain_key.next()?);
121    Ok(sender_chain_key.sender_message_key())
122}
123
124pub async fn group_decrypt(
125    skm_bytes: &[u8],
126    sender_key_store: &mut dyn SenderKeyStore,
127    sender: &ProtocolAddress,
128) -> Result<Vec<u8>> {
129    let skm = SenderKeyMessage::try_from(skm_bytes)?;
130
131    let distribution_id = skm.distribution_id();
132    let chain_id = skm.chain_id();
133
134    let mut record = sender_key_store
135        .load_sender_key(sender, skm.distribution_id())
136        .await?
137        .ok_or(SignalProtocolError::NoSenderKeyState { distribution_id })?;
138
139    let sender_key_state = match record.sender_key_state_for_chain_id(chain_id) {
140        Some(state) => state,
141        None => {
142            log::error!(
143                "SenderKey distribution {} could not find chain ID {} (known chain IDs: {:?})",
144                distribution_id,
145                chain_id,
146                record.chain_ids_for_logging().collect::<Vec<_>>(),
147            );
148            return Err(SignalProtocolError::NoSenderKeyState { distribution_id });
149        }
150    };
151
152    let message_version = skm.message_version() as u32;
153    if message_version != sender_key_state.message_version() {
154        return Err(SignalProtocolError::UnrecognizedMessageVersion(
155            message_version,
156        ));
157    }
158
159    let signing_key = sender_key_state
160        .signing_key_public()
161        .map_err(|_| SignalProtocolError::InvalidSenderKeySession { distribution_id })?;
162    if !skm.verify_signature(&signing_key)? {
163        return Err(SignalProtocolError::SignatureValidationFailed);
164    }
165
166    let sender_key = get_sender_key(sender_key_state, skm.iteration(), distribution_id)?;
167
168    let plaintext = match signal_crypto::aes_256_cbc_decrypt(
169        skm.ciphertext(),
170        sender_key.cipher_key(),
171        sender_key.iv(),
172    ) {
173        Ok(plaintext) => plaintext,
174        Err(signal_crypto::DecryptionError::BadKeyOrIv) => {
175            log::error!(
176                "incoming sender key state corrupt for {sender}, distribution ID {distribution_id}, chain ID {chain_id}",
177            );
178            return Err(SignalProtocolError::InvalidSenderKeySession { distribution_id });
179        }
180        Err(signal_crypto::DecryptionError::BadCiphertext(msg)) => {
181            log::error!("sender key decryption failed: {msg}");
182            return Err(SignalProtocolError::InvalidMessage(
183                CiphertextMessageType::SenderKey,
184                "decryption failed",
185            ));
186        }
187    };
188
189    sender_key_store
190        .store_sender_key(sender, distribution_id, &record)
191        .await?;
192
193    Ok(plaintext)
194}
195
196pub async fn process_sender_key_distribution_message(
197    sender: &ProtocolAddress,
198    skdm: &SenderKeyDistributionMessage,
199    sender_key_store: &mut dyn SenderKeyStore,
200) -> Result<()> {
201    let distribution_id = skdm.distribution_id()?;
202    log::info!(
203        "{} Processing SenderKey distribution {} with chain ID {}",
204        sender,
205        distribution_id,
206        skdm.chain_id()?
207    );
208
209    let mut sender_key_record = sender_key_store
210        .load_sender_key(sender, distribution_id)
211        .await?
212        .unwrap_or_else(SenderKeyRecord::new_empty);
213
214    sender_key_record.add_sender_key_state(
215        skdm.message_version(),
216        skdm.chain_id()?,
217        skdm.iteration()?,
218        skdm.chain_key()?,
219        *skdm.signing_key()?,
220        None,
221    );
222    sender_key_store
223        .store_sender_key(sender, distribution_id, &sender_key_record)
224        .await?;
225    Ok(())
226}
227
228pub async fn create_sender_key_distribution_message<R: Rng + CryptoRng>(
229    sender: &ProtocolAddress,
230    distribution_id: Uuid,
231    sender_key_store: &mut dyn SenderKeyStore,
232    csprng: &mut R,
233) -> Result<SenderKeyDistributionMessage> {
234    let sender_key_record = sender_key_store
235        .load_sender_key(sender, distribution_id)
236        .await?;
237
238    let sender_key_record = match sender_key_record {
239        Some(record) => record,
240        None => {
241            // libsignal-protocol-java uses 31-bit integers for sender key chain IDs
242            let chain_id = (csprng.random::<u32>()) >> 1;
243            log::info!(
244                "Creating SenderKey for distribution {distribution_id} with chain ID {chain_id}"
245            );
246
247            let iteration = 0;
248            let sender_key: [u8; 32] = csprng.random();
249            let signing_key = KeyPair::generate(csprng);
250            let mut record = SenderKeyRecord::new_empty();
251            record.add_sender_key_state(
252                SENDERKEY_MESSAGE_CURRENT_VERSION,
253                chain_id,
254                iteration,
255                &sender_key,
256                signing_key.public_key,
257                Some(signing_key.private_key),
258            );
259            sender_key_store
260                .store_sender_key(sender, distribution_id, &record)
261                .await?;
262            record
263        }
264    };
265
266    let state = sender_key_record
267        .sender_key_state()
268        .map_err(|_| SignalProtocolError::InvalidSenderKeySession { distribution_id })?;
269    let sender_chain_key = state
270        .sender_chain_key()
271        .ok_or(SignalProtocolError::InvalidSenderKeySession { distribution_id })?;
272    let message_version = state
273        .message_version()
274        .try_into()
275        .map_err(|_| SignalProtocolError::InvalidSenderKeySession { distribution_id })?;
276
277    SenderKeyDistributionMessage::new(
278        message_version,
279        distribution_id,
280        state.chain_id(),
281        sender_chain_key.iteration(),
282        sender_chain_key.seed().to_vec(),
283        state
284            .signing_key_public()
285            .map_err(|_| SignalProtocolError::InvalidSenderKeySession { distribution_id })?,
286    )
287}