crypto: Move the olm encryption logic into the Session struct.

master
Damir Jelić 2020-07-21 12:03:05 +02:00
parent 3d6872607e
commit 3f1439fe28
4 changed files with 79 additions and 60 deletions

View File

@ -32,13 +32,10 @@ use super::{device::Device, store::Result as StoreResult, CryptoStore};
use matrix_sdk_common::api; use matrix_sdk_common::api;
use matrix_sdk_common::events::{ use matrix_sdk_common::events::{
forwarded_room_key::ForwardedRoomKeyEventContent, forwarded_room_key::ForwardedRoomKeyEventContent, room::encrypted::EncryptedEventContent,
room::encrypted::{CiphertextInfo, EncryptedEventContent, OlmV1Curve25519AesSha2Content}, room::message::MessageEventContent, room_key::RoomKeyEventContent,
room::message::MessageEventContent, room_key_request::RoomKeyRequestEventContent, Algorithm, AnySyncRoomEvent, AnyToDeviceEvent,
room_key::RoomKeyEventContent, EventJson, EventType, SyncMessageEvent, ToDeviceEvent,
room_key_request::RoomKeyRequestEventContent,
Algorithm, AnySyncRoomEvent, AnyToDeviceEvent, EventJson, EventType, SyncMessageEvent,
ToDeviceEvent,
}; };
use matrix_sdk_common::identifiers::{DeviceId, RoomId, UserId}; use matrix_sdk_common::identifiers::{DeviceId, RoomId, UserId};
use matrix_sdk_common::uuid::Uuid; use matrix_sdk_common::uuid::Uuid;
@ -50,7 +47,7 @@ use api::r0::{
to_device::{send_event_to_device::Request as ToDeviceRequest, DeviceIdOrAllDevices}, to_device::{send_event_to_device::Request as ToDeviceRequest, DeviceIdOrAllDevices},
}; };
use serde_json::{json, Value}; use serde_json::Value;
use tracing::{debug, error, info, instrument, trace, warn}; use tracing::{debug, error, info, instrument, trace, warn};
/// A map from the algorithm and device id to a one-time key. /// A map from the algorithm and device id to a one-time key.
@ -807,52 +804,12 @@ impl OlmMachine {
event_type: EventType, event_type: EventType,
content: Value, content: Value,
) -> OlmResult<EncryptedEventContent> { ) -> OlmResult<EncryptedEventContent> {
let identity_keys = self.account.identity_keys(); let message = session
.encrypt(self.account.clone(), recipient_device, event_type, content)
// TODO most of this could go into the session, the session already .await;
// stores the curve key of the device, if we also store the ed25519 key
// with the session we'll only need to pass in the account to the
// session and all of this can live in the session.
let recipient_signing_key = recipient_device
.get_key(KeyAlgorithm::Ed25519)
.ok_or(EventError::MissingSigningKey)?;
let recipient_sender_key = recipient_device
.get_key(KeyAlgorithm::Curve25519)
.ok_or(EventError::MissingSigningKey)?;
let payload = json!({
"sender": self.user_id,
"sender_device": self.device_id,
"keys": {
"ed25519": identity_keys.ed25519(),
},
"recipient": recipient_device.user_id(),
"recipient_keys": {
"ed25519": recipient_signing_key,
},
"type": event_type,
"content": content,
});
let plaintext = cjson::to_string(&payload)
.unwrap_or_else(|_| panic!(format!("Can't serialize {} to canonical JSON", payload)));
let ciphertext = session.encrypt(&plaintext).await.to_tuple();
let message_type: usize = ciphertext.0.into();
let ciphertext = CiphertextInfo::new(ciphertext.1, (message_type as u32).into());
let mut content = BTreeMap::new();
content.insert(recipient_sender_key.to_owned(), ciphertext);
self.store.save_sessions(&[session]).await?; self.store.save_sessions(&[session]).await?;
Ok(EncryptedEventContent::OlmV1Curve25519AesSha2( message
OlmV1Curve25519AesSha2Content::new(content, identity_keys.curve25519().to_owned()),
))
} }
/// Should the client share a group session for the given room. /// Should the client share a group session for the given room.

View File

@ -49,8 +49,8 @@ use super::{InboundGroupSession, OutboundGroupSession, Session};
/// devices. /// devices.
#[derive(Clone)] #[derive(Clone)]
pub struct Account { pub struct Account {
user_id: Arc<UserId>, pub(crate) user_id: Arc<UserId>,
device_id: Arc<Box<DeviceId>>, pub(crate) device_id: Arc<Box<DeviceId>>,
inner: Arc<Mutex<OlmAccount>>, inner: Arc<Mutex<OlmAccount>>,
identity_keys: Arc<IdentityKeys>, identity_keys: Arc<IdentityKeys>,
shared: Arc<AtomicBool>, shared: Arc<AtomicBool>,

View File

@ -149,7 +149,7 @@ pub(crate) mod test {
let plaintext = "Hello world"; let plaintext = "Hello world";
let message = bob_session.encrypt(plaintext).await; let message = bob_session.encrypt_helper(plaintext).await;
let prekey_message = match message.clone() { let prekey_message = match message.clone() {
OlmMessage::PreKey(m) => m, OlmMessage::PreKey(m) => m,

View File

@ -12,22 +12,35 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use matrix_sdk_common::instant::Instant; use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use matrix_sdk_common::locks::Mutex;
pub use olm_rs::account::IdentityKeys;
use olm_rs::errors::OlmSessionError; use olm_rs::errors::OlmSessionError;
use olm_rs::session::OlmSession; use olm_rs::session::OlmSession;
use olm_rs::PicklingMode; use olm_rs::PicklingMode;
use serde_json::{json, Value};
pub use olm_rs::{ pub use olm_rs::{
session::{OlmMessage, PreKeyMessage}, session::{OlmMessage, PreKeyMessage},
utility::OlmUtility, utility::OlmUtility,
}; };
use super::Account;
use crate::error::{EventError, OlmResult};
use crate::Device;
use matrix_sdk_common::{
api::r0::keys::KeyAlgorithm,
events::{
room::encrypted::{CiphertextInfo, EncryptedEventContent, OlmV1Curve25519AesSha2Content},
EventType,
},
instant::Instant,
locks::Mutex,
};
/// Cryptographic session that enables secure communication between two /// Cryptographic session that enables secure communication between two
/// `Account`s /// `Account`s
#[derive(Clone)] #[derive(Clone)]
@ -71,12 +84,61 @@ impl Session {
/// # Arguments /// # Arguments
/// ///
/// * `plaintext` - The plaintext that should be encrypted. /// * `plaintext` - The plaintext that should be encrypted.
pub async fn encrypt(&mut self, plaintext: &str) -> OlmMessage { pub(crate) async fn encrypt_helper(&mut self, plaintext: &str) -> OlmMessage {
let message = self.inner.lock().await.encrypt(plaintext); let message = self.inner.lock().await.encrypt(plaintext);
self.last_use_time = Arc::new(Instant::now()); self.last_use_time = Arc::new(Instant::now());
message message
} }
/// Encrypt the given event content content as an m.room.encrypted event
/// content.
pub async fn encrypt(
&mut self,
account: Account,
recipient_device: &Device,
event_type: EventType,
content: Value,
) -> OlmResult<EncryptedEventContent> {
let recipient_signing_key = recipient_device
.get_key(KeyAlgorithm::Ed25519)
.ok_or(EventError::MissingSigningKey)?;
let recipient_sender_key = recipient_device
.get_key(KeyAlgorithm::Curve25519)
.ok_or(EventError::MissingSigningKey)?;
let payload = json!({
"sender": account.user_id.to_string(),
"sender_device": account.device_id.as_ref(),
"keys": {
"ed25519": account.identity_keys().ed25519(),
},
"recipient": recipient_device.user_id(),
"recipient_keys": {
"ed25519": recipient_signing_key,
},
"type": event_type,
"content": content,
});
let plaintext = cjson::to_string(&payload)
.unwrap_or_else(|_| panic!(format!("Can't serialize {} to canonical JSON", payload)));
let ciphertext = self.encrypt_helper(&plaintext).await.to_tuple();
let message_type = ciphertext.0;
let ciphertext = CiphertextInfo::new(ciphertext.1, (message_type as u32).into());
let mut content = BTreeMap::new();
content.insert(recipient_sender_key.to_owned(), ciphertext);
Ok(EncryptedEventContent::OlmV1Curve25519AesSha2(
OlmV1Curve25519AesSha2Content::new(
content,
account.identity_keys().curve25519().to_owned(),
),
))
}
/// Check if a pre-key Olm message was encrypted for this session. /// Check if a pre-key Olm message was encrypted for this session.
/// ///
/// Returns true if it matches, false if not and a OlmSessionError if there /// Returns true if it matches, false if not and a OlmSessionError if there