From 06423bbb3f1550a6576f18a8aa991c878264952a Mon Sep 17 00:00:00 2001 From: Schmiddiii Date: Sun, 28 Jan 2024 20:19:56 +0100 Subject: [PATCH] Fix base64 --- libsignal-service/src/account_manager.rs | 20 ++++----- libsignal-service/src/cipher.rs | 5 ++- libsignal-service/src/configuration.rs | 9 ++-- libsignal-service/src/groups_v2/manager.rs | 3 +- libsignal-service/src/groups_v2/operations.rs | 3 +- libsignal-service/src/provisioning/mod.rs | 5 ++- libsignal-service/src/provisioning/pipe.rs | 5 ++- libsignal-service/src/utils.rs | 42 ++++++++++++++----- libsignal-service/src/websocket/sender.rs | 9 ++-- 9 files changed, 61 insertions(+), 40 deletions(-) diff --git a/libsignal-service/src/account_manager.rs b/libsignal-service/src/account_manager.rs index 0a0674cfd..1021e178c 100644 --- a/libsignal-service/src/account_manager.rs +++ b/libsignal-service/src/account_manager.rs @@ -20,6 +20,7 @@ use zkgroup::profiles::ProfileKey; use crate::pre_keys::{KyberPreKeyEntity, PreKeysStore}; use crate::proto::DeviceName; use crate::push_service::{AvatarWrite, RecaptchaAttributes, ServiceIdType}; +use crate::utils::BASE64; use crate::ServiceAddress; use crate::{ configuration::{Endpoint, ServiceCredentials}, @@ -297,7 +298,7 @@ impl AccountManager { &[], HttpAuthOverride::NoOverride, &ProvisioningMessage { - body: BASE64_STANDARD.encode(body), + body: BASE64.encode(body), }, ) .await @@ -327,7 +328,7 @@ impl AccountManager { let ephemeral_id = query.get("uuid").ok_or(LinkError::InvalidUuid)?; let pub_key = query.get("pub_key").ok_or(LinkError::InvalidPublicKey)?; - let pub_key = BASE64_STANDARD + let pub_key = BASE64 .decode(&**pub_key) .map_err(|_e| LinkError::InvalidPublicKey)?; let pub_key = PublicKey::deserialize(&pub_key) @@ -642,7 +643,7 @@ pub fn decrypt_device_name( #[cfg(test)] mod tests { - use base64::prelude::*; + use crate::utils::BASE64; use libsignal_protocol::{KeyPair, PrivateKey, PublicKey}; use super::DeviceName; @@ -670,22 +671,17 @@ mod tests { #[test] fn decrypt_device_name() -> anyhow::Result<()> { let ephemeral_private_key = PrivateKey::deserialize( - &BASE64_STANDARD - .decode("0CgxHjwwblXjvX8sD5wZDWdYToMRf+CZSlgaUrxCGVo=")?, + &BASE64.decode("0CgxHjwwblXjvX8sD5wZDWdYToMRf+CZSlgaUrxCGVo=")?, )?; let ephemeral_public_key = PublicKey::deserialize( - &BASE64_STANDARD - .decode("BcZS+Lt6yAKbEpXnRX+I5wHqesuvu93Q2V+fjidwW8R6")?, + &BASE64.decode("BcZS+Lt6yAKbEpXnRX+I5wHqesuvu93Q2V+fjidwW8R6")?, )?; let device_name = DeviceName { ephemeral_public: Some(ephemeral_public_key.serialize().to_vec()), - synthetic_iv: Some( - BASE64_STANDARD.decode("86gekHGmltnnZ9QARhiFcg==")?, - ), + synthetic_iv: Some(BASE64.decode("86gekHGmltnnZ9QARhiFcg==")?), ciphertext: Some( - BASE64_STANDARD - .decode("MtJ9/9KBWLBVAxfZJD4pLKzP4q+iodRJeCc+/A==")?, + BASE64.decode("MtJ9/9KBWLBVAxfZJD4pLKzP4q+iodRJeCc+/A==")?, ), }; diff --git a/libsignal-service/src/cipher.rs b/libsignal-service/src/cipher.rs index 6f5fa188b..12684045f 100644 --- a/libsignal-service/src/cipher.rs +++ b/libsignal-service/src/cipher.rs @@ -21,6 +21,7 @@ use crate::{ envelope::Envelope, push_service::ServiceError, sender::OutgoingPushMessage, + utils::BASE64, ServiceAddress, }; /// Decrypts incoming messages and encrypts outgoing messages. @@ -365,7 +366,7 @@ where r#type: Type::UnidentifiedSender as u32, destination_device_id: address.device_id().into(), destination_registration_id, - content: BASE64_STANDARD.encode(message), + content: BASE64.encode(message), }) } else { let message = message_encrypt( @@ -380,7 +381,7 @@ where let destination_registration_id = session_record.remote_registration_id()?; - let body = BASE64_STANDARD.encode(message.serialize()); + let body = BASE64.encode(message.serialize()); use crate::proto::envelope::Type; let message_type = match message.message_type() { diff --git a/libsignal-service/src/configuration.rs b/libsignal-service/src/configuration.rs index a5074e95e..3de836e2d 100644 --- a/libsignal-service/src/configuration.rs +++ b/libsignal-service/src/configuration.rs @@ -1,5 +1,6 @@ use std::{collections::HashMap, str::FromStr}; +use crate::utils::BASE64; use base64::prelude::*; use libsignal_protocol::PublicKey; use serde::{Deserialize, Serialize}; @@ -130,8 +131,8 @@ impl From<&SignalServers> for ServiceConfiguration { "https://api-staging.directory.signal.org".parse().unwrap(), certificate_authority: include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/certs/staging-root-ca.pem")).to_string(), unidentified_sender_trust_root: - PublicKey::deserialize(&BASE64_STANDARD.decode("BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx").unwrap()).unwrap(), - zkgroup_server_public_params: bincode::deserialize(&BASE64_STANDARD.decode("ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdlukrpzzsCIvEwjwQlJYVPOQPj4V0F4UXXBdHSLK05uoPBCQG8G9rYIGedYsClJXnbrgGYG3eMTG5hnx4X4ntARBgELuMWWUEEfSK0mjXg+/2lPmWcTZWR9nkqgQQP0tbzuiPm74H2wMO4u1Wafe+UwyIlIT9L7KLS19Aw8r4sPrXZSSsOZ6s7M1+rTJN0bI5CKY2PX29y5Ok3jSWufIKcgKOnWoP67d5b2du2ZVJjpjfibNIHbT/cegy/sBLoFwtHogVYUewANUAXIaMPyCLRArsKhfJ5wBtTminG/PAvuBdJ70Z/bXVPf8TVsR292zQ65xwvWTejROW6AZX6aqucUj").unwrap()).unwrap(), + PublicKey::deserialize(&BASE64.decode("BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx").unwrap()).unwrap(), + zkgroup_server_public_params: bincode::deserialize(&BASE64.decode("ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdlukrpzzsCIvEwjwQlJYVPOQPj4V0F4UXXBdHSLK05uoPBCQG8G9rYIGedYsClJXnbrgGYG3eMTG5hnx4X4ntARBgELuMWWUEEfSK0mjXg+/2lPmWcTZWR9nkqgQQP0tbzuiPm74H2wMO4u1Wafe+UwyIlIT9L7KLS19Aw8r4sPrXZSSsOZ6s7M1+rTJN0bI5CKY2PX29y5Ok3jSWufIKcgKOnWoP67d5b2du2ZVJjpjfibNIHbT/cegy/sBLoFwtHogVYUewANUAXIaMPyCLRArsKhfJ5wBtTminG/PAvuBdJ70Z/bXVPf8TVsR292zQ65xwvWTejROW6AZX6aqucUj").unwrap()).unwrap(), }, // configuration with the Signal API production endpoints // https://github.com/signalapp/Signal-Desktop/blob/master/config/production.json @@ -148,9 +149,9 @@ impl From<&SignalServers> for ServiceConfiguration { contact_discovery_url: "https://api.directory.signal.org".parse().unwrap(), certificate_authority: include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/certs/production-root-ca.pem")).to_string(), unidentified_sender_trust_root: - PublicKey::deserialize(&BASE64_STANDARD.decode("BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF").unwrap()).unwrap(), + PublicKey::deserialize(&BASE64.decode("BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF").unwrap()).unwrap(), zkgroup_server_public_params: bincode::deserialize( - &BASE64_STANDARD.decode("AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X36nOoGPs54XsEGzPdEV+itQNGUFEjY6X9Uv+Acuks7NpyGvCoKxGwgKgE5XyJ+nNKlyHHOLb6N1NuHyBrZrgtY/JYJHRooo5CEqYKBqdFnmbTVGEkCvJKxLnjwKWf+fEPoWeQFj5ObDjcKMZf2Jm2Ae69x+ikU5gBXsRmoF94GXTLfN0/vLt98KDPnxwAQL9j5V1jGOY8jQl6MLxEs56cwXN0dqCnImzVH3TZT1cJ8SW1BRX6qIVxEzjsSGx3yxF3suAilPMqGRp4ffyopjMD1JXiKR2RwLKzizUe5e8XyGOy9fplzhw3jVzTRyUZTRSZKkMLWcQ/gv0E4aONNqs4P").unwrap()).unwrap(), + &BASE64.decode("AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X36nOoGPs54XsEGzPdEV+itQNGUFEjY6X9Uv+Acuks7NpyGvCoKxGwgKgE5XyJ+nNKlyHHOLb6N1NuHyBrZrgtY/JYJHRooo5CEqYKBqdFnmbTVGEkCvJKxLnjwKWf+fEPoWeQFj5ObDjcKMZf2Jm2Ae69x+ikU5gBXsRmoF94GXTLfN0/vLt98KDPnxwAQL9j5V1jGOY8jQl6MLxEs56cwXN0dqCnImzVH3TZT1cJ8SW1BRX6qIVxEzjsSGx3yxF3suAilPMqGRp4ffyopjMD1JXiKR2RwLKzizUe5e8XyGOy9fplzhw3jVzTRyUZTRSZKkMLWcQ/gv0E4aONNqs4P").unwrap()).unwrap(), }, } } diff --git a/libsignal-service/src/groups_v2/manager.rs b/libsignal-service/src/groups_v2/manager.rs index 24102af34..7773bc125 100644 --- a/libsignal-service/src/groups_v2/manager.rs +++ b/libsignal-service/src/groups_v2/manager.rs @@ -7,6 +7,7 @@ use crate::{ prelude::{PushService, ServiceError}, proto::GroupContextV2, push_service::{HttpAuth, HttpAuthOverride, ServiceIds}, + utils::BASE64, }; use base64::prelude::*; @@ -41,7 +42,7 @@ impl CredentialResponse { self.credentials .into_iter() .map(|c| { - let bytes = BASE64_STANDARD.decode(c.credential)?; + let bytes = BASE64.decode(c.credential)?; let data = bincode::deserialize(&bytes)?; Ok((c.redemption_time, data)) }) diff --git a/libsignal-service/src/groups_v2/operations.rs b/libsignal-service/src/groups_v2/operations.rs index 322eb99a1..7431bed0c 100644 --- a/libsignal-service/src/groups_v2/operations.rs +++ b/libsignal-service/src/groups_v2/operations.rs @@ -15,6 +15,7 @@ use crate::{ self, group_attribute_blob, GroupAttributeBlob, Member as EncryptedMember, }, + utils::BASE64, }; use super::{ @@ -404,7 +405,7 @@ impl GroupOperations { let modify_invite_link_password = actions.modify_invite_link_password.into_iter().map(|m| { Ok(GroupChange::InviteLinkPassword( - BASE64_STANDARD.encode(m.invite_link_password), + BASE64.encode(m.invite_link_password), )) }); diff --git a/libsignal-service/src/provisioning/mod.rs b/libsignal-service/src/provisioning/mod.rs index 5774d43b4..e2b2fd301 100644 --- a/libsignal-service/src/provisioning/mod.rs +++ b/libsignal-service/src/provisioning/mod.rs @@ -6,7 +6,7 @@ use std::{array::TryFromSliceError, borrow::Cow}; pub use cipher::ProvisioningCipher; -use base64::prelude::*; +use base64::Engine; use derivative::Derivative; use futures::StreamExt; use futures::{channel::mpsc::Sender, pin_mut, SinkExt}; @@ -20,6 +20,7 @@ use zkgroup::profiles::ProfileKey; use pipe::{ProvisioningPipe, ProvisioningStep}; use crate::prelude::ServiceError; +use crate::utils::BASE64; use crate::{ account_manager::encrypt_device_name, pre_keys::{ @@ -223,7 +224,7 @@ pub async fn link_device< let pni_signed_pre_key = generate_signed_pre_key(pni_store, csprng, &pni_key_pair).await?; - let encrypted_device_name = BASE64_STANDARD.encode( + let encrypted_device_name = BASE64.encode( encrypt_device_name(csprng, device_name, &aci_public_key)? .encode_to_vec(), ); diff --git a/libsignal-service/src/provisioning/pipe.rs b/libsignal-service/src/provisioning/pipe.rs index ee6ba42c5..248e23d67 100644 --- a/libsignal-service/src/provisioning/pipe.rs +++ b/libsignal-service/src/provisioning/pipe.rs @@ -1,4 +1,4 @@ -use base64::prelude::*; +use base64::Engine; use bytes::Bytes; use futures::{ channel::{ @@ -16,6 +16,7 @@ use crate::{ ProvisioningUuid, WebSocketRequestMessage, WebSocketResponseMessage, }, provisioning::ProvisioningError, + utils::BASE64, websocket::SignalWebSocket, }; @@ -98,7 +99,7 @@ impl ProvisioningPipe { .append_pair("uuid", &uuid.uuid.unwrap()) .append_pair( "pub_key", - &BASE64_STANDARD.encode( + &BASE64.encode( self.provisioning_cipher.public_key().serialize(), ), ); diff --git a/libsignal-service/src/utils.rs b/libsignal-service/src/utils.rs index cd5e194e4..92c62460c 100644 --- a/libsignal-service/src/utils.rs +++ b/libsignal-service/src/utils.rs @@ -1,4 +1,18 @@ +// Signal sometimes adds padding, sometimes it does not. +// This requires a custom decoding engine. +// This engine is as general as possible. +pub const BASE64: base64::engine::GeneralPurpose = + base64::engine::GeneralPurpose::new( + &base64::alphabet::STANDARD, + base64::engine::GeneralPurposeConfig::new() + .with_encode_padding(true) + .with_decode_padding_mode( + base64::engine::DecodePaddingMode::Indifferent, + ), + ); + pub mod serde_base64 { + use super::BASE64; use base64::prelude::*; use serde::{Deserialize, Deserializer, Serializer}; @@ -7,7 +21,7 @@ pub mod serde_base64 { T: AsRef<[u8]>, S: Serializer, { - serializer.serialize_str(&BASE64_STANDARD.encode(bytes.as_ref())) + serializer.serialize_str(&BASE64.encode(bytes.as_ref())) } pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> @@ -16,7 +30,7 @@ pub mod serde_base64 { { use serde::de::Error; String::deserialize(deserializer).and_then(|string| { - BASE64_STANDARD + BASE64 .decode(string) .map_err(|err| Error::custom(err.to_string())) }) @@ -24,6 +38,7 @@ pub mod serde_base64 { } pub mod serde_optional_base64 { + use super::BASE64; use base64::prelude::*; use serde::{Deserialize, Deserializer, Serializer}; @@ -51,7 +66,7 @@ pub mod serde_optional_base64 { { use serde::de::Error; match Option::::deserialize(deserializer)? { - Some(s) => BASE64_STANDARD + Some(s) => BASE64 .decode(s) .map_err(|err| Error::custom(err.to_string())) .map(Some), @@ -61,6 +76,7 @@ pub mod serde_optional_base64 { } pub mod serde_public_key { + use super::BASE64; use base64::prelude::*; use libsignal_protocol::PublicKey; use serde::{Deserialize, Deserializer, Serializer}; @@ -73,7 +89,7 @@ pub mod serde_public_key { S: Serializer, { let public_key = public_key.serialize(); - serializer.serialize_str(&BASE64_STANDARD.encode(&public_key)) + serializer.serialize_str(&BASE64.encode(&public_key)) } pub fn deserialize<'de, D>(deserializer: D) -> Result @@ -81,7 +97,7 @@ pub mod serde_public_key { D: Deserializer<'de>, { PublicKey::deserialize( - &BASE64_STANDARD + &BASE64 .decode(String::deserialize(deserializer)?) .map_err(serde::de::Error::custom)?, ) @@ -90,6 +106,7 @@ pub mod serde_public_key { } pub mod serde_optional_public_key { + use super::BASE64; use base64::prelude::*; use libsignal_protocol::PublicKey; use serde::{Deserialize, Deserializer, Serializer}; @@ -120,7 +137,7 @@ pub mod serde_optional_public_key { match Option::::deserialize(deserializer)? { Some(public_key) => Ok(Some( PublicKey::deserialize( - &BASE64_STANDARD + &BASE64 .decode(public_key) .map_err(serde::de::Error::custom)?, ) @@ -132,6 +149,7 @@ pub mod serde_optional_public_key { } pub mod serde_private_key { + use super::BASE64; use base64::prelude::*; use libsignal_protocol::PrivateKey; use serde::{Deserialize, Deserializer, Serializer}; @@ -144,7 +162,7 @@ pub mod serde_private_key { S: Serializer, { let public_key = public_key.serialize(); - serializer.serialize_str(&BASE64_STANDARD.encode(public_key)) + serializer.serialize_str(&BASE64.encode(public_key)) } pub fn deserialize<'de, D>(deserializer: D) -> Result @@ -152,7 +170,7 @@ pub mod serde_private_key { D: Deserializer<'de>, { PrivateKey::deserialize( - &BASE64_STANDARD + &BASE64 .decode(String::deserialize(deserializer)?) .map_err(serde::de::Error::custom)?, ) @@ -161,6 +179,7 @@ pub mod serde_private_key { } pub mod serde_optional_private_key { + use super::BASE64; use base64::prelude::*; use libsignal_protocol::PrivateKey; use serde::{Deserialize, Deserializer, Serializer}; @@ -191,7 +210,7 @@ pub mod serde_optional_private_key { match Option::::deserialize(deserializer)? { Some(private_key) => Ok(Some( PrivateKey::deserialize( - &BASE64_STANDARD + &BASE64 .decode(private_key) .map_err(serde::de::Error::custom)?, ) @@ -205,6 +224,7 @@ pub mod serde_optional_private_key { pub mod serde_signaling_key { use std::convert::TryInto; + use super::BASE64; use crate::configuration::SignalingKey; use base64::prelude::*; use serde::{Deserialize, Deserializer, Serializer}; @@ -216,7 +236,7 @@ pub mod serde_signaling_key { where S: Serializer, { - serializer.serialize_str(&BASE64_STANDARD.encode(signaling_key)) + serializer.serialize_str(&BASE64.encode(signaling_key)) } pub fn deserialize<'de, D>( @@ -225,7 +245,7 @@ pub mod serde_signaling_key { where D: Deserializer<'de>, { - BASE64_STANDARD + BASE64 .decode(String::deserialize(deserializer)?) .map_err(serde::de::Error::custom)? .try_into() diff --git a/libsignal-service/src/websocket/sender.rs b/libsignal-service/src/websocket/sender.rs index cecc7e1c9..7fd7c3947 100644 --- a/libsignal-service/src/websocket/sender.rs +++ b/libsignal-service/src/websocket/sender.rs @@ -1,10 +1,11 @@ use crate::{ sender::{OutgoingPushMessages, SendMessageResponse}, unidentified_access::UnidentifiedAccess, + utils::BASE64, }; -use base64::prelude::*; use super::*; +use base64::Engine; impl SignalWebSocket { pub async fn send_messages( @@ -21,10 +22,8 @@ impl SignalWebSocket { access: &UnidentifiedAccess, ) -> Result { let path = format!("/v1/messages/{}", messages.recipient.uuid); - let header = format!( - "Unidentified-Access-Key:{}", - BASE64_STANDARD.encode(&access.key) - ); + let header = + format!("Unidentified-Access-Key:{}", BASE64.encode(&access.key)); self.put_json_with_headers(&path, messages, vec![header]) .await }