mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 20:06:51 +03:00
crypto: Update to the latest rust-sdk version
This commit is contained in:
parent
a3af73261c
commit
50cdbaf041
9 changed files with 105 additions and 57 deletions
|
@ -47,7 +47,6 @@ import org.matrix.android.sdk.internal.session.sync.model.DeviceListResponse
|
|||
import org.matrix.android.sdk.internal.session.sync.model.DeviceOneTimeKeysCountSyncResponse
|
||||
import org.matrix.android.sdk.internal.session.sync.model.ToDeviceSyncResponse
|
||||
import timber.log.Timber
|
||||
import uniffi.olm.BackupKey
|
||||
import uniffi.olm.BackupKeys
|
||||
import uniffi.olm.CrossSigningKeyExport
|
||||
import uniffi.olm.CrossSigningStatus
|
||||
|
@ -56,6 +55,7 @@ import uniffi.olm.DecryptionException
|
|||
import uniffi.olm.DeviceLists
|
||||
import uniffi.olm.KeyRequestPair
|
||||
import uniffi.olm.Logger
|
||||
import uniffi.olm.MegolmV1BackupKey
|
||||
import uniffi.olm.Request
|
||||
import uniffi.olm.RequestType
|
||||
import uniffi.olm.RoomKeyCounts
|
||||
|
@ -790,10 +790,10 @@ internal class OlmMachine(
|
|||
}
|
||||
|
||||
@Throws(CryptoStoreException::class)
|
||||
suspend fun enableBackup(key: String, version: String) {
|
||||
suspend fun enableBackupV1(key: String, version: String) {
|
||||
return withContext(Dispatchers.Default) {
|
||||
val backupKey = BackupKey(key, mapOf(), null)
|
||||
inner.enableBackup(backupKey, version)
|
||||
val backupKey = MegolmV1BackupKey(key, mapOf(), null, MXCRYPTO_ALGORITHM_MEGOLM_BACKUP)
|
||||
inner.enableBackupV1(backupKey, version)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
BackupRecoveryKey()
|
||||
}
|
||||
|
||||
val publicKey = key.publicKey()
|
||||
val publicKey = key.megolmV1PublicKey()
|
||||
val backupAuthData = SignalableMegolmBackupAuthData(
|
||||
publicKey = publicKey.publicKey,
|
||||
privateKeySalt = publicKey.passphraseInfo?.privateKeySalt,
|
||||
|
@ -144,7 +144,7 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
)
|
||||
|
||||
MegolmBackupCreationInfo(
|
||||
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
|
||||
algorithm = publicKey.backupAlgorithm,
|
||||
authData = signedMegolmBackupAuthData,
|
||||
recoveryKey = key.toBase58()
|
||||
)
|
||||
|
@ -264,7 +264,8 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
|
||||
override fun backupAllGroupSessions(progressListener: ProgressListener?,
|
||||
callback: MatrixCallback<Unit>?) {
|
||||
// This is only used in tests?
|
||||
// This is only used in tests? While it's fine have methods that are
|
||||
// only used for tests, this one has a lot of logic that is nowhere else used.
|
||||
TODO()
|
||||
}
|
||||
|
||||
|
@ -354,7 +355,7 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
// Check that the recovery key matches to the public key that we downloaded from the server.
|
||||
// If they match, we can trust the public key and enable backups since we have the private key.
|
||||
private fun checkRecoveryKey(recoveryKey: BackupRecoveryKey, keysBackupData: KeysVersionResult) {
|
||||
val backupKey = recoveryKey.publicKey()
|
||||
val backupKey = recoveryKey.megolmV1PublicKey()
|
||||
val authData = getMegolmBackupAuthData(keysBackupData)
|
||||
|
||||
when {
|
||||
|
@ -474,7 +475,7 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
|
||||
if (ciphertext != null && mac != null && ephemeralKey != null) {
|
||||
try {
|
||||
val decrypted = key.decrypt(ephemeralKey, mac, ciphertext)
|
||||
val decrypted = key.decryptV1(ephemeralKey, mac, ciphertext)
|
||||
|
||||
val moshi = MoshiProvider.providesMoshi()
|
||||
val adapter = moshi.adapter(MegolmSessionData::class.java)
|
||||
|
@ -729,7 +730,7 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
}
|
||||
|
||||
private fun isValidRecoveryKey(recoveryKey: BackupRecoveryKey, version: KeysVersionResult): Boolean {
|
||||
val publicKey = recoveryKey.publicKey().publicKey
|
||||
val publicKey = recoveryKey.megolmV1PublicKey().publicKey
|
||||
val authData = getMegolmBackupAuthData(version) ?: return false
|
||||
return authData.publicKey == publicKey
|
||||
}
|
||||
|
@ -800,7 +801,7 @@ internal class RustKeyBackupService @Inject constructor(
|
|||
|
||||
if (retrievedMegolmBackupAuthData != null) {
|
||||
try {
|
||||
olmMachine.enableBackup(retrievedMegolmBackupAuthData.publicKey, keysVersionResult.version)
|
||||
olmMachine.enableBackupV1(retrievedMegolmBackupAuthData.publicKey, keysVersionResult.version)
|
||||
keysBackupVersion = keysVersionResult
|
||||
} catch (e: OlmException) {
|
||||
Timber.e(e, "OlmException")
|
||||
|
|
|
@ -29,11 +29,11 @@ features = ["lax_deserialize"]
|
|||
|
||||
[dependencies.matrix-sdk-common]
|
||||
git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
||||
rev = "1943840b82fd323455d9ca9ce27243d37a660569"
|
||||
rev = "2e4d5f25cba03bd26415b91defd6e762e8c31b63"
|
||||
|
||||
[dependencies.matrix-sdk-crypto]
|
||||
git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
||||
rev = "1943840b82fd323455d9ca9ce27243d37a660569"
|
||||
rev = "2e4d5f25cba03bd26415b91defd6e762e8c31b63"
|
||||
features = ["sled_cryptostore", "qrcode", "backups_v1"]
|
||||
|
||||
[dependencies.tokio]
|
||||
|
|
|
@ -5,7 +5,10 @@ use sha2::Sha512;
|
|||
use std::{collections::HashMap, iter};
|
||||
use thiserror::Error;
|
||||
|
||||
use matrix_sdk_crypto::backups::{OlmPkDecryptionError, RecoveryKey};
|
||||
use matrix_sdk_crypto::{
|
||||
backups::{OlmPkDecryptionError, RecoveryKey},
|
||||
store::CryptoStoreError as InnerStoreError,
|
||||
};
|
||||
|
||||
/// The private part of the backup key, the one used for recovery.
|
||||
pub struct BackupRecoveryKey {
|
||||
|
@ -26,6 +29,9 @@ pub enum DecodeError {
|
|||
/// An error happened while decoding the recovery key.
|
||||
#[error(transparent)]
|
||||
Decode(#[from] matrix_sdk_crypto::backups::DecodeError),
|
||||
/// An error happened in the storage layer,
|
||||
#[error(transparent)]
|
||||
CryptoStore(#[from] InnerStoreError),
|
||||
}
|
||||
|
||||
/// Struct containing info about the way the backup key got derived from a
|
||||
|
@ -39,13 +45,15 @@ pub struct PassphraseInfo {
|
|||
}
|
||||
|
||||
/// The public part of the backup key.
|
||||
pub struct BackupKey {
|
||||
pub struct MegolmV1BackupKey {
|
||||
/// The actuall base64 encoded public key.
|
||||
pub public_key: String,
|
||||
/// Signatures that have signed our backup key.
|
||||
pub signatures: HashMap<String, HashMap<String, String>>,
|
||||
/// The passphrase info, if the key was derived from one.
|
||||
pub passphrase_info: Option<PassphraseInfo>,
|
||||
/// Get the full name of the backup algorithm this backup key supports.
|
||||
pub backup_algorithm: String,
|
||||
}
|
||||
|
||||
impl BackupRecoveryKey {
|
||||
|
@ -107,8 +115,8 @@ impl BackupRecoveryKey {
|
|||
}
|
||||
|
||||
/// Get the public part of the backup key.
|
||||
pub fn public_key(&self) -> BackupKey {
|
||||
let public_key = self.inner.public_key();
|
||||
pub fn megolm_v1_public_key(&self) -> MegolmV1BackupKey {
|
||||
let public_key = self.inner.megolm_v1_public_key();
|
||||
|
||||
let signatures: HashMap<String, HashMap<String, String>> = public_key
|
||||
.signatures()
|
||||
|
@ -121,10 +129,11 @@ impl BackupRecoveryKey {
|
|||
})
|
||||
.collect();
|
||||
|
||||
BackupKey {
|
||||
MegolmV1BackupKey {
|
||||
public_key: public_key.to_base64(),
|
||||
signatures,
|
||||
passphrase_info: self.passphrase_info.clone(),
|
||||
backup_algorithm: public_key.backup_algorithm().to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,14 +149,14 @@ impl BackupRecoveryKey {
|
|||
|
||||
/// Try to decrypt a message that was encrypted using the public part of the
|
||||
/// backup key.
|
||||
pub fn decrypt(
|
||||
pub fn decrypt_v1(
|
||||
&self,
|
||||
ephemeral_key: String,
|
||||
mac: String,
|
||||
ciphertext: String,
|
||||
) -> Result<String, PkDecryptionError> {
|
||||
self.inner
|
||||
.decrypt(ephemeral_key, mac, ciphertext)
|
||||
.decrypt_v1(ephemeral_key, mac, ciphertext)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use matrix_sdk_crypto::{
|
||||
store::CryptoStoreError as InnerStoreError, KeyExportError, MegolmError, OlmError,
|
||||
SignatureError as InnerSignatureError, SecretImportError as RustSecretImportError,
|
||||
SecretImportError as RustSecretImportError, SignatureError as InnerSignatureError,
|
||||
};
|
||||
use ruma::identifiers::Error as RumaIdentifierError;
|
||||
|
||||
|
@ -12,6 +12,8 @@ pub enum KeyImportError {
|
|||
Export(#[from] KeyExportError),
|
||||
#[error(transparent)]
|
||||
CryptoStore(#[from] InnerStoreError),
|
||||
#[error(transparent)]
|
||||
Json(#[from] serde_json::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
|
|
|
@ -18,7 +18,7 @@ mod users;
|
|||
mod verification;
|
||||
|
||||
pub use backup_recovery_key::{
|
||||
BackupKey, BackupRecoveryKey, DecodeError, PassphraseInfo, PkDecryptionError,
|
||||
BackupRecoveryKey, DecodeError, MegolmV1BackupKey, PassphraseInfo, PkDecryptionError,
|
||||
};
|
||||
pub use device::Device;
|
||||
pub use error::{
|
||||
|
@ -87,19 +87,19 @@ pub struct CrossSigningKeyExport {
|
|||
pub user_signing_key: Option<String>,
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Struct holding the number of room keys we have.
|
||||
pub struct RoomKeyCounts {
|
||||
/// TODO
|
||||
/// The total number of room keys.
|
||||
pub total: i64,
|
||||
/// TODO
|
||||
/// The number of backed up room keys.
|
||||
pub backed_up: i64,
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Backup keys and information we load from the store.
|
||||
pub struct BackupKeys {
|
||||
/// TODO
|
||||
/// The recovery key as a base64 encoded string.
|
||||
pub recovery_key: String,
|
||||
/// TODO
|
||||
/// The version that is used with the recovery key.
|
||||
pub backup_version: String,
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ use tokio::runtime::Runtime;
|
|||
|
||||
use matrix_sdk_common::{deserialized_responses::AlgorithmInfo, uuid::Uuid};
|
||||
use matrix_sdk_crypto::{
|
||||
backups::{MegolmV1BackupKey, RecoveryKey},
|
||||
backups::{MegolmV1BackupKey as RustBackupKey, RecoveryKey},
|
||||
decrypt_key_export, encrypt_key_export,
|
||||
matrix_qrcode::QrVerificationData,
|
||||
olm::ExportedRoomKey,
|
||||
|
@ -43,11 +43,11 @@ use matrix_sdk_crypto::{
|
|||
use crate::{
|
||||
error::{CryptoStoreError, DecryptionError, SecretImportError, SignatureError},
|
||||
responses::{response_from_string, OutgoingVerificationRequest, OwnedResponse},
|
||||
BackupKey, BackupKeys, BootstrapCrossSigningResult, ConfirmVerificationResult,
|
||||
CrossSigningKeyExport, CrossSigningStatus, DecryptedEvent, Device, DeviceLists, KeyImportError,
|
||||
KeysImportResult, ProgressListener, QrCode, Request, RequestType, RequestVerificationResult,
|
||||
RoomKeyCounts, ScanResult, SignatureUploadRequest, StartSasResult, UserIdentity, Verification,
|
||||
VerificationRequest,
|
||||
BackupKeys, BootstrapCrossSigningResult, ConfirmVerificationResult, CrossSigningKeyExport,
|
||||
CrossSigningStatus, DecodeError, DecryptedEvent, Device, DeviceLists, KeyImportError,
|
||||
KeysImportResult, MegolmV1BackupKey, ProgressListener, QrCode, Request, RequestType,
|
||||
RequestVerificationResult, RoomKeyCounts, ScanResult, SignatureUploadRequest, StartSasResult,
|
||||
UserIdentity, Verification, VerificationRequest,
|
||||
};
|
||||
|
||||
/// A high level state machine that handles E2EE for Matrix.
|
||||
|
@ -79,7 +79,7 @@ impl OlmMachine {
|
|||
pub fn new(user_id: &str, device_id: &str, path: &str) -> Result<Self, CryptoStoreError> {
|
||||
let user_id = UserId::try_from(user_id)?;
|
||||
let device_id = device_id.into();
|
||||
let runtime = Runtime::new().unwrap();
|
||||
let runtime = Runtime::new().expect("Couldn't create a tokio runtime");
|
||||
|
||||
Ok(OlmMachine {
|
||||
inner: runtime.block_on(InnerMachine::new_with_default_store(
|
||||
|
@ -499,7 +499,7 @@ impl OlmMachine {
|
|||
let encrypted_content = self
|
||||
.runtime
|
||||
.block_on(self.inner.encrypt(&room_id, content))
|
||||
.unwrap();
|
||||
.expect("Encrypting an event produced an error");
|
||||
|
||||
Ok(serde_json::to_string(&encrypted_content)?)
|
||||
}
|
||||
|
@ -644,13 +644,24 @@ impl OlmMachine {
|
|||
self.impor_keys_helper(keys, progress_listener)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Import room keys from the given serialized unencrypted key export.
|
||||
///
|
||||
/// This method is the same as [`OlmMachine::import_keys`] but the
|
||||
/// decryption step is skipped and should be performed by the caller. This
|
||||
/// may be useful for custom handling or for server-side key backups.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `keys` - The serialized version of the unencrypted key export.
|
||||
///
|
||||
/// * `progress_listener` - A callback that can be used to introspect the
|
||||
/// progress of the key import.
|
||||
pub fn import_decrypted_keys(
|
||||
&self,
|
||||
keys: &str,
|
||||
progress_listener: Box<dyn ProgressListener>,
|
||||
) -> Result<KeysImportResult, KeyImportError> {
|
||||
let keys: Vec<ExportedRoomKey> = serde_json::from_str(keys).unwrap();
|
||||
let keys: Vec<ExportedRoomKey> = serde_json::from_str(keys)?;
|
||||
self.impor_keys_helper(keys, progress_listener)
|
||||
}
|
||||
|
||||
|
@ -1263,30 +1274,47 @@ impl OlmMachine {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn enable_backup(&self, key: BackupKey, version: String) -> Result<(), CryptoStoreError> {
|
||||
let backup_key = MegolmV1BackupKey::from_base64(&key.public_key).unwrap();
|
||||
/// Activate the given backup key to be used with the given backup version.
|
||||
///
|
||||
/// **Warning**: The caller needs to make sure that the given `BackupKey` is
|
||||
/// trusted, otherwise we might be encrypting room keys that a malicious
|
||||
/// party could decrypt.
|
||||
///
|
||||
/// The [`OlmMachine::verify_backup`] method can be used to so.
|
||||
pub fn enable_backup_v1(
|
||||
&self,
|
||||
key: MegolmV1BackupKey,
|
||||
version: String,
|
||||
) -> Result<(), DecodeError> {
|
||||
let backup_key = RustBackupKey::from_base64(&key.public_key)?;
|
||||
backup_key.set_version(version);
|
||||
|
||||
self.runtime
|
||||
.block_on(self.inner.backup_machine().enable_backup(backup_key))?;
|
||||
.block_on(self.inner.backup_machine().enable_backup_v1(backup_key))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Are we able to encrypt room keys.
|
||||
///
|
||||
/// This returns true if we have an active `BackupKey` and backup version
|
||||
/// registered with the state machine.
|
||||
pub fn backup_enabled(&self) -> bool {
|
||||
self.runtime.block_on(self.inner.backup_machine().enabled())
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Disable and reset our backup state.
|
||||
///
|
||||
/// This will remove any pending backup request, remove the backup key and
|
||||
/// reset the backup state of each room key we have.
|
||||
pub fn disable_backup(&self) -> Result<(), CryptoStoreError> {
|
||||
Ok(self
|
||||
.runtime
|
||||
.block_on(self.inner.backup_machine().disable_backup())?)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Encrypt a batch of room keys and return a request that needs to be sent
|
||||
/// out to backup the room keys.
|
||||
pub fn backup_room_keys(&self) -> Result<Option<Request>, CryptoStoreError> {
|
||||
let request = self
|
||||
.runtime
|
||||
|
@ -1297,7 +1325,7 @@ impl OlmMachine {
|
|||
Ok(request)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Get the number of backed up room keys and the total number of room keys.
|
||||
pub fn room_key_counts(&self) -> Result<RoomKeyCounts, CryptoStoreError> {
|
||||
Ok(self
|
||||
.runtime
|
||||
|
@ -1305,7 +1333,10 @@ impl OlmMachine {
|
|||
.into())
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Store the recovery key in the cryptostore.
|
||||
///
|
||||
/// This is useful if the client wants to support gossiping of the backup
|
||||
/// key.
|
||||
pub fn save_recovery_key(
|
||||
&self,
|
||||
key: Option<String>,
|
||||
|
@ -1321,7 +1352,7 @@ impl OlmMachine {
|
|||
.block_on(self.inner.backup_machine().save_recovery_key(key, version))?)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Get the backup keys we have saved in our crypto store.
|
||||
pub fn get_backup_keys(&self) -> Result<Option<BackupKeys>, CryptoStoreError> {
|
||||
Ok(self
|
||||
.runtime
|
||||
|
@ -1330,7 +1361,8 @@ impl OlmMachine {
|
|||
.ok())
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Sign the given message using our device key and if available cross
|
||||
/// signing master key.
|
||||
pub fn sign(&self, message: &str) -> HashMap<String, HashMap<String, String>> {
|
||||
self.runtime
|
||||
.block_on(self.inner.sign(message))
|
||||
|
@ -1344,7 +1376,8 @@ impl OlmMachine {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Check if the given backup has been verified by us or by another of our
|
||||
/// devices that we trust.
|
||||
pub fn verify_backup(&self, auth_data: &str) -> Result<bool, CryptoStoreError> {
|
||||
let auth_data = serde_json::from_str(auth_data)?;
|
||||
Ok(self
|
||||
|
|
|
@ -19,6 +19,7 @@ enum PkDecryptionError {
|
|||
enum KeyImportError {
|
||||
"Export",
|
||||
"CryptoStore",
|
||||
"Json",
|
||||
};
|
||||
|
||||
[Error]
|
||||
|
@ -357,8 +358,8 @@ interface OlmMachine {
|
|||
boolean is_identity_verified([ByRef] string user_id);
|
||||
|
||||
record<DOMString, record<DOMString, string>> sign([ByRef] string message);
|
||||
[Throws=CryptoStoreError]
|
||||
void enable_backup(BackupKey key, string version);
|
||||
[Throws=DecodeError]
|
||||
void enable_backup_v1(MegolmV1BackupKey key, string version);
|
||||
[Throws=CryptoStoreError]
|
||||
void disable_backup();
|
||||
[Throws=CryptoStoreError]
|
||||
|
@ -379,10 +380,11 @@ dictionary PassphraseInfo {
|
|||
i32 private_key_iterations;
|
||||
};
|
||||
|
||||
dictionary BackupKey {
|
||||
dictionary MegolmV1BackupKey {
|
||||
string public_key;
|
||||
record<DOMString, record<DOMString, string>> signatures;
|
||||
PassphraseInfo? passphrase_info;
|
||||
string backup_algorithm;
|
||||
};
|
||||
|
||||
dictionary BackupKeys {
|
||||
|
@ -398,6 +400,7 @@ dictionary RoomKeyCounts {
|
|||
[Error]
|
||||
enum DecodeError {
|
||||
"Decode",
|
||||
"CryptoStore",
|
||||
};
|
||||
|
||||
interface BackupRecoveryKey {
|
||||
|
@ -412,7 +415,7 @@ interface BackupRecoveryKey {
|
|||
constructor(string key);
|
||||
string to_base58();
|
||||
string to_base64();
|
||||
BackupKey public_key();
|
||||
MegolmV1BackupKey megolm_v1_public_key();
|
||||
[Throws=PkDecryptionError]
|
||||
string decrypt(string ephemeral_key, string mac, string ciphertext);
|
||||
string decrypt_v1(string ephemeral_key, string mac, string ciphertext);
|
||||
};
|
||||
|
|
|
@ -10,13 +10,13 @@ pub enum Verification {
|
|||
/// The `m.sas.v1` verification flow.
|
||||
SasV1 {
|
||||
#[allow(missing_docs)]
|
||||
sas: Sas
|
||||
sas: Sas,
|
||||
},
|
||||
/// The `m.qr_code.scan.v1`, `m.qr_code.show.v1`, and `m.reciprocate.v1`
|
||||
/// verification flow.
|
||||
QrCodeV1 {
|
||||
#[allow(missing_docs)]
|
||||
qrcode: QrCode
|
||||
qrcode: QrCode,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue