Skip to content

Commit

Permalink
Remove signaling key
Browse files Browse the repository at this point in the history
Quick and dirty rebase of
#277
  • Loading branch information
direc85 committed Jan 6, 2025
1 parent dd43d93 commit 3796165
Show file tree
Hide file tree
Showing 8 changed files with 27 additions and 201 deletions.
13 changes: 4 additions & 9 deletions src/configuration.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
use core::fmt;
use std::{borrow::Cow, collections::HashMap, str::FromStr};

use crate::utils::BASE64_RELAXED;
use crate::{
push_service::{HttpAuth, DEFAULT_DEVICE_ID},
utils::BASE64_RELAXED,
};
use base64::prelude::*;
use libsignal_protocol::PublicKey;
use serde::{Deserialize, Serialize};
use url::Url;
use zkgroup::ServerPublicParams;

use crate::{
envelope::{CIPHER_KEY_SIZE, MAC_KEY_SIZE},
push_service::{HttpAuth, DEFAULT_DEVICE_ID},
};

#[derive(Clone)]
pub struct ServiceConfiguration {
service_url: Url,
Expand All @@ -24,15 +22,12 @@ pub struct ServiceConfiguration {
pub zkgroup_server_public_params: ServerPublicParams,
}

pub type SignalingKey = [u8; CIPHER_KEY_SIZE + MAC_KEY_SIZE];

#[derive(Clone)]
pub struct ServiceCredentials {
pub aci: Option<uuid::Uuid>,
pub pni: Option<uuid::Uuid>,
pub phonenumber: phonenumber::PhoneNumber,
pub password: Option<String>,
pub signaling_key: Option<SignalingKey>,
pub device_id: Option<u32>,
}

Expand Down
134 changes: 0 additions & 134 deletions src/envelope.rs
Original file line number Diff line number Diff line change
@@ -1,72 +1,8 @@
use aes::cipher::block_padding::Pkcs7;
use aes::cipher::{BlockDecryptMut, KeyIvInit};
use libsignal_protocol::ServiceId;
use prost::Message;

use crate::{configuration::SignalingKey, push_service::ServiceError};

pub use crate::proto::Envelope;

impl Envelope {
#[tracing::instrument(skip(input, signaling_key), fields(signaling_key_present = signaling_key.is_some(), input_size = input.len()))]
pub fn decrypt(
input: &[u8],
signaling_key: Option<&SignalingKey>,
is_signaling_key_encrypted: bool,
) -> Result<Self, ServiceError> {
if !is_signaling_key_encrypted {
tracing::trace!("Envelope::decrypt: not encrypted");
Ok(Envelope::decode(input)?)
} else {
let signaling_key = signaling_key
.expect("signaling_key required to decrypt envelopes");
tracing::trace!("Envelope::decrypt: decrypting");
if input.len() < VERSION_LENGTH
|| input[VERSION_OFFSET] != SUPPORTED_VERSION
{
return Err(ServiceError::InvalidFrame {
reason: "unsupported signaling cryptogram version",
});
}

let aes_key = &signaling_key[..CIPHER_KEY_SIZE];
let mac_key = &signaling_key[CIPHER_KEY_SIZE..];
let mac = &input[(input.len() - MAC_SIZE)..];
let input_for_mac = &input[..(input.len() - MAC_SIZE)];
let iv = &input[IV_OFFSET..(IV_OFFSET + IV_LENGTH)];
debug_assert_eq!(mac_key.len(), MAC_KEY_SIZE);
debug_assert_eq!(aes_key.len(), CIPHER_KEY_SIZE);
debug_assert_eq!(iv.len(), IV_LENGTH);

// Verify MAC
use hmac::{Hmac, Mac};
use sha2::Sha256;
let mut verifier = Hmac::<Sha256>::new_from_slice(mac_key)
.expect("Hmac can take any size key");
verifier.update(input_for_mac);
// XXX: possible timing attack, but we need the bytes for a
// truncated view...
let our_mac = verifier.finalize().into_bytes();
if &our_mac[..MAC_SIZE] != mac {
return Err(ServiceError::MacError);
}

// libsignal-service-java uses Pkcs5,
// but that should not matter.
// https://crypto.stackexchange.com/questions/9043/what-is-the-difference-between-pkcs5-padding-and-pkcs7-padding
let cipher =
cbc::Decryptor::<aes::Aes256>::new(aes_key.into(), iv.into());
let input = &input[CIPHERTEXT_OFFSET..(input.len() - MAC_SIZE)];
let input = cipher
.decrypt_padded_vec_mut::<Pkcs7>(input)
.expect("decryption");

tracing::trace!("Envelope::decrypt: decrypted, decoding");

Ok(Envelope::decode(&input as &[u8])?)
}
}

pub fn is_unidentified_sender(&self) -> bool {
self.r#type() == crate::proto::envelope::Type::UnidentifiedSender
}
Expand Down Expand Up @@ -112,73 +48,3 @@ impl Envelope {
}
}
}

pub(crate) const SUPPORTED_VERSION: u8 = 1;
pub(crate) const CIPHER_KEY_SIZE: usize = 32;
pub(crate) const MAC_KEY_SIZE: usize = 20;
pub(crate) const MAC_SIZE: usize = 10;

pub(crate) const VERSION_OFFSET: usize = 0;
pub(crate) const VERSION_LENGTH: usize = 1;
pub(crate) const IV_OFFSET: usize = VERSION_OFFSET + VERSION_LENGTH;
pub(crate) const IV_LENGTH: usize = 16;
pub(crate) const CIPHERTEXT_OFFSET: usize = IV_OFFSET + IV_LENGTH;

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn decrypt_envelope() {
// This is a real message, reencrypted with the zero-key.
let body = [
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 32, 12, 100,
26, 157, 130, 210, 254, 174, 87, 45, 238, 126, 68, 39, 188, 171,
156, 16, 10, 138, 233, 73, 202, 52, 125, 102, 121, 182, 71, 148, 8,
3, 134, 149, 154, 67, 116, 40, 146, 253, 242, 196, 139, 203, 14,
174, 254, 78, 27, 47, 108, 60, 202, 60, 42, 210, 242, 58, 13, 185,
67, 147, 166, 191, 71, 164, 128, 81, 177, 199, 147, 252, 162, 229,
143, 98, 141, 222, 46, 83, 109, 82, 196, 109, 161, 40, 108, 207,
82, 53, 162, 205, 171, 33, 140, 5, 74, 76, 150, 22, 122, 176, 189,
228, 176, 234, 176, 13, 118, 181, 134, 35, 133, 164, 160, 205, 176,
32, 188, 185, 166, 73, 24, 164, 20, 187, 2, 226, 186, 238, 98, 57,
51, 76, 156, 83, 113, 72, 184, 50, 220, 49, 138, 46, 36, 4, 49,
215, 66, 173, 58, 139, 187, 6, 252, 97, 191, 69, 246, 82, 48, 177,
11, 149, 168, 93, 15, 170, 125, 131, 101, 103, 253, 177, 165, 71,
85, 219, 207, 106, 12, 58, 47, 159, 33, 243, 107, 6, 117, 141, 209,
115, 207, 19, 236, 137, 195, 230, 167, 225, 172, 99, 204, 113, 125,
69, 125, 97, 252, 90, 248, 198, 175, 240, 187, 246, 164, 220, 102,
7, 224, 124, 28, 170, 6, 4, 137, 155, 233, 85, 125, 93, 119, 97,
183, 114, 193, 10, 184, 191, 202, 109, 97, 116, 194, 152, 40, 46,
202, 49, 195, 138, 14, 2, 255, 44, 107, 160, 45, 150, 6, 78, 145,
99,
];

let signaling_key = [0u8; 52];
let envelope =
Envelope::decrypt(&body, Some(&signaling_key), true).unwrap();
assert_eq!(envelope.server_timestamp(), 1594373582421);
assert_eq!(envelope.timestamp(), 1594373580977);
assert_eq!(
envelope.content(),
[
51, 10, 33, 5, 239, 254, 183, 191, 204, 223, 85, 150, 43, 192,
240, 57, 46, 189, 153, 7, 48, 17, 9, 166, 185, 157, 205, 181,
66, 235, 99, 221, 114, 58, 187, 117, 16, 76, 24, 0, 34, 160, 1,
85, 61, 73, 83, 99, 213, 160, 109, 122, 125, 204, 137, 178,
237, 146, 87, 183, 107, 33, 213, 234, 64, 152, 132, 122, 173,
25, 33, 4, 65, 20, 134, 117, 62, 116, 80, 151, 18, 132, 187,
101, 235, 208, 74, 78, 214, 66, 59, 71, 171, 124, 167, 217,
157, 36, 194, 156, 12, 50, 239, 185, 230, 253, 38, 107, 106,
149, 194, 39, 214, 35, 245, 58, 216, 250, 225, 150, 170, 26,
241, 153, 133, 173, 197, 194, 27, 127, 56, 77, 119, 242, 26,
252, 168, 61, 221, 44, 76, 128, 69, 27, 203, 6, 173, 193, 179,
69, 27, 243, 36, 185, 181, 157, 41, 23, 72, 113, 40, 209, 46,
189, 63, 167, 156, 148, 118, 76, 153, 91, 40, 179, 180, 245,
193, 123, 180, 47, 115, 220, 191, 148, 245, 116, 32, 194, 232,
55, 13, 0, 217, 52, 116, 21, 48, 244, 17, 222, 26, 240, 31,
236, 199, 237, 94, 255, 93, 137, 192,
]
);
}
}
4 changes: 1 addition & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ pub const GROUP_LEAVE_FLAG: u32 = 2;
pub mod prelude {
pub use crate::{
cipher::ServiceCipher,
configuration::{
ServiceConfiguration, ServiceCredentials, SignalingKey,
},
configuration::{ServiceConfiguration, ServiceCredentials},
content::Content,
envelope::Envelope,
groups_v2::{
Expand Down
21 changes: 10 additions & 11 deletions src/messagepipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use futures::{
},
prelude::*,
};
use prost::Message;

pub use crate::{
configuration::ServiceCredentials,
Expand All @@ -24,15 +25,11 @@ pub enum Incoming {

pub struct MessagePipe {
ws: SignalWebSocket,
credentials: ServiceCredentials,
}

impl MessagePipe {
pub fn from_socket(
ws: SignalWebSocket,
credentials: ServiceCredentials,
) -> Self {
MessagePipe { ws, credentials }
pub fn from_socket(ws: SignalWebSocket) -> Self {
MessagePipe { ws }
}

/// Return a SignalWebSocket for sending messages and other purposes beyond receiving messages.
Expand Down Expand Up @@ -83,11 +80,13 @@ impl MessagePipe {
reason: "request without body.",
});
};
Some(Incoming::Envelope(Envelope::decrypt(
body,
self.credentials.signaling_key.as_ref(),
request.is_signal_key_encrypted(),
)?))
if request.is_signal_key_encrypted() {
return Err(ServiceError::InvalidFrame {
reason: "Signal key encrypted envelope received, but not supported anymore.",
});
} else {
Some(Incoming::Envelope(Envelope::decode(body as &[u8])?))
}
} else if request.is_queue_empty() {
Some(Incoming::QueueEmpty)
} else {
Expand Down
5 changes: 3 additions & 2 deletions src/profile_cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ use crate::{
/// # let mut rng = rand::thread_rng();
/// # let some_randomness = rng.gen();
/// let profile_key = ProfileKey::generate(some_randomness);
/// let profile_cipher = ProfileCipher::new(profile_key);
/// let name = ProfileName::<&str> {
/// given_name: "Bill",
/// family_name: None,
/// };
/// let cipher = ProfileCipher::from(profile_key);
/// let encrypted = cipher.encrypt_name(&name).unwrap();
/// let cipher = ProfileCipher::from(profile_cipher);
/// let encrypted = cipher.encrypt_name(&name, &mut rng).unwrap();
/// let decrypted = cipher.decrypt_name(&encrypted).unwrap().unwrap();
/// assert_eq!(decrypted.as_ref(), name);
/// ```
Expand Down
12 changes: 8 additions & 4 deletions src/provisioning/cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ use sha2::Sha256;

pub use crate::proto::{ProvisionEnvelope, ProvisionMessage};

use crate::{
envelope::{CIPHER_KEY_SIZE, IV_LENGTH, IV_OFFSET},
provisioning::ProvisioningError,
};
use crate::provisioning::ProvisioningError;

pub(crate) const CIPHER_KEY_SIZE: usize = 32;

pub(crate) const VERSION_OFFSET: usize = 0;
pub(crate) const VERSION_LENGTH: usize = 1;
pub(crate) const IV_OFFSET: usize = VERSION_OFFSET + VERSION_LENGTH;
pub(crate) const IV_LENGTH: usize = 16;

enum CipherMode {
DecryptAndEncrypt(KeyPair),
Expand Down
2 changes: 1 addition & 1 deletion src/receiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl MessageReceiver {
Some(credentials.clone()),
)
.await?;
Ok(MessagePipe::from_socket(ws, credentials))
Ok(MessagePipe::from_socket(ws))
}

pub async fn retrieve_contacts(
Expand Down
37 changes: 0 additions & 37 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,43 +231,6 @@ pub mod serde_optional_private_key {
}
}

pub mod serde_signaling_key {
use std::convert::TryInto;

use super::BASE64_RELAXED;
use crate::configuration::SignalingKey;
use base64::prelude::*;
use serde::{Deserialize, Deserializer, Serializer};

pub fn serialize<S>(
signaling_key: &SignalingKey,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&BASE64_RELAXED.encode(signaling_key))
}

pub fn deserialize<'de, D>(
deserializer: D,
) -> Result<SignalingKey, D::Error>
where
D: Deserializer<'de>,
{
BASE64_RELAXED
.decode(String::deserialize(deserializer)?)
.map_err(serde::de::Error::custom)?
.try_into()
.map_err(|buf: Vec<u8>| {
serde::de::Error::invalid_length(
buf.len(),
&"invalid signaling key length",
)
})
}
}

pub mod serde_phone_number {
use phonenumber::PhoneNumber;
use serde::{Deserialize, Deserializer, Serializer};
Expand Down

0 comments on commit 3796165

Please sign in to comment.