Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove last remaining part of signaling key #277

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions libsignal-service/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ 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},
};
use crate::push_service::{HttpAuth, DEFAULT_DEVICE_ID};

#[derive(Clone)]
pub struct ServiceConfiguration {
Expand All @@ -21,14 +18,11 @@ 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 uuid: Option<uuid::Uuid>,
pub phonenumber: phonenumber::PhoneNumber,
pub password: Option<String>,
pub signaling_key: Option<SignalingKey>,
pub device_id: Option<u32>,
}

Expand Down
129 changes: 0 additions & 129 deletions libsignal-service/src/envelope.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
use std::convert::{TryFrom, TryInto};

use aes::cipher::block_padding::Pkcs7;
use aes::cipher::{BlockDecryptMut, KeyIvInit};
use prost::Message;
use uuid::Uuid;

use crate::{
configuration::SignalingKey, push_service::ServiceError,
utils::serde_optional_base64, ParseServiceAddressError, ServiceAddress,
};

Expand All @@ -27,62 +23,6 @@ impl TryFrom<EnvelopeEntity> for Envelope {
}

impl Envelope {
pub fn decrypt(
input: &[u8],
signaling_key: &SignalingKey,
is_signaling_key_encrypted: bool,
) -> Result<Self, ServiceError> {
if !is_signaling_key_encrypted {
log::trace!("Envelope::decrypt: not encrypted");
Ok(Envelope::decode(input)?)
} else {
log::trace!("Envelope::decrypt: decrypting");
if input.len() < VERSION_LENGTH
|| input[VERSION_OFFSET] != SUPPORTED_VERSION
{
return Err(ServiceError::InvalidFrameError {
reason: "Unsupported signaling cryptogram version".into(),
});
}

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");

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

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

fn new_from_entity(entity: EnvelopeEntity) -> Self {
Envelope {
r#type: Some(entity.r#type),
Expand Down Expand Up @@ -172,72 +112,3 @@ fn default_true() -> bool {
pub(crate) struct EnvelopeEntityList {
pub messages: Vec<EnvelopeEntity>,
}

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, &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 libsignal-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ pub mod prelude {
pub use super::ServiceAddress;
pub use crate::{
cipher::ServiceCipher,
configuration::{
ServiceConfiguration, ServiceCredentials, SignalingKey,
},
configuration::{ServiceConfiguration, ServiceCredentials},
content::Content,
envelope::Envelope,
groups_v2::{
Expand Down
24 changes: 10 additions & 14 deletions libsignal-service/src/messagepipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use futures::{
prelude::*,
stream::FusedStream,
};
use prost::Message;

pub use crate::{
configuration::ServiceCredentials,
Expand Down Expand Up @@ -39,15 +40,11 @@ pub trait WebSocketService {

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 @@ -98,14 +95,13 @@ impl MessagePipe {
reason: "Request without body.".into(),
});
};
Some(Incoming::Envelope(Envelope::decrypt(
body,
self.credentials
.signaling_key
.as_ref()
.expect("signaling_key required to decrypt envelopes"),
request.is_signal_key_encrypted(),
)?))
if request.is_signal_key_encrypted() {
return Err(ServiceError::InvalidFrameError {
reason: "Signal key encrypted envelope received, but not supported anymore.".into(),
});
} else {
Some(Incoming::Envelope(Envelope::decode(body as &[u8])?))
}
} else if request.is_queue_empty() {
Some(Incoming::QueueEmpty)
} else {
Expand Down
12 changes: 8 additions & 4 deletions libsignal-service/src/provisioning/cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@
use sha2::Sha256;

pub use crate::proto::{
ProvisionEnvelope, ProvisionMessage, ProvisioningVersion,

Check warning on line 14 in libsignal-service/src/provisioning/cipher.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-hyper, Rust stable)

unused import: `ProvisioningVersion`

Check warning on line 14 in libsignal-service/src/provisioning/cipher.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-hyper, Rust beta)

unused import: `ProvisioningVersion`

Check warning on line 14 in libsignal-service/src/provisioning/cipher.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-hyper, Rust nightly)

unused import: `ProvisioningVersion`

Check warning on line 14 in libsignal-service/src/provisioning/cipher.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-actix, Rust beta)

unused import: `ProvisioningVersion`

Check warning on line 14 in libsignal-service/src/provisioning/cipher.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-actix, Rust stable)

unused import: `ProvisioningVersion`

Check warning on line 14 in libsignal-service/src/provisioning/cipher.rs

View workflow job for this annotation

GitHub Actions / Build (libsignal-service-actix, Rust nightly)

unused import: `ProvisioningVersion`
};

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 libsignal-service/src/receiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl<Service: PushService> MessageReceiver<Service> {
Some(credentials.clone()),
)
.await?;
Ok(MessagePipe::from_socket(ws, credentials))
Ok(MessagePipe::from_socket(ws))
}

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

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

use crate::configuration::SignalingKey;
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::encode(signaling_key))
}

pub fn deserialize<'de, D>(
deserializer: D,
) -> Result<SignalingKey, D::Error>
where
D: Deserializer<'de>,
{
base64::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
Loading