Skip to content

Commit

Permalink
Merge pull request #1699 from matrix-org/andy/crypto_password
Browse files Browse the repository at this point in the history
Set passphrase for the crypto store
  • Loading branch information
Anderas authored Jan 30, 2023
2 parents 735fac4 + 93e3b95 commit 496b17e
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 78 deletions.
3 changes: 2 additions & 1 deletion MatrixSDK/Crypto/CryptoMachine/MXCryptoMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,14 @@ class MXCryptoMachine {
MXCryptoSDKLogger.shared.log(logLine: "Starting logs")

let url = try MXCryptoMachineStore.createStoreURLIfNecessary(for: userId)
let passphrase = try MXCryptoMachineStore.storePassphrase()
log.debug("Opening crypto store at \(url.path)/matrix-sdk-crypto.sqlite3") // Hardcoding path to db for debugging purpose

machine = try OlmMachine(
userId: userId,
deviceId: deviceId,
path: url.path,
passphrase: nil
passphrase: passphrase
)

self.requests = MXCryptoRequests(restClient: restClient)
Expand Down
16 changes: 16 additions & 0 deletions MatrixSDK/Crypto/CryptoMachine/MXCryptoMachineStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import Foundation
struct MXCryptoMachineStore {
enum Error: Swift.Error {
case invalidStorage
case invalidPassphrase
}

private static let storeFolder = "MXCryptoStore"
Expand All @@ -36,6 +37,21 @@ struct MXCryptoMachineStore {
.appendingPathComponent(userId)
}

static func storePassphrase() throws -> String {
let key = MXKeyProvider.sharedInstance()
.keyDataForData(
ofType: MXCryptoSDKStoreKeyDataType,
isMandatory: true,
expectedKeyType: .rawData
)

guard let key = key as? MXRawDataKey else {
throw Error.invalidPassphrase
}

return MXBase64Tools.base64(from: key.key)
}

private static func storeContainerURL() throws -> URL {
let container: URL
if let sharedContainerURL = FileManager.default.applicationGroupContainerURL() {
Expand Down
4 changes: 4 additions & 0 deletions MatrixSDK/Crypto/Data/MXCryptoConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ FOUNDATION_EXPORT NSString *const kMXCryptoAes256KeyBackupAlgorithm;
*/
FOUNDATION_EXPORT NSString *const MXCryptoOlmPickleKeyDataType;

/**
MXKeyProvider identifier for a 32 bytes long key to a store managed by the Crypto SDK.
*/
FOUNDATION_EXPORT NSString *const MXCryptoSDKStoreKeyDataType;

#pragma mark - Encrypting error

Expand Down
1 change: 1 addition & 0 deletions MatrixSDK/Crypto/Data/MXCryptoConstants.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
NSString *const kMXCryptoCurve25519KeyBackupAlgorithm = @"m.megolm_backup.v1.curve25519-aes-sha2";
NSString *const kMXCryptoAes256KeyBackupAlgorithm = @"org.matrix.msc3270.v1.aes-hmac-sha2";
NSString *const MXCryptoOlmPickleKeyDataType = @"org.matrix.sdk.olm.pickle.key";
NSString *const MXCryptoSDKStoreKeyDataType = @"org.matrix.sdk.crypto.store.key";


#pragma mark - Encrypting error
Expand Down
53 changes: 40 additions & 13 deletions MatrixSDK/Crypto/MXCryptoV2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,9 @@ class MXCryptoV2: NSObject, MXCrypto {
// MARK: - Public properties

var version: String {
guard let sdkVersion = Bundle(for: OlmMachine.self).infoDictionary?["CFBundleShortVersionString"] else {
return "Matrix SDK Crypto"
}
return "Matrix SDK Crypto \(sdkVersion)"
let sdkVersion = Bundle(for: OlmMachine.self).infoDictionary?["CFBundleShortVersionString"] ?? ""
return "Matrix Crypto SDK \(sdkVersion)"

}

var deviceCurve25519Key: String? {
Expand Down Expand Up @@ -173,7 +172,7 @@ class MXCryptoV2: NSObject, MXCrypto {

log.debug("Crypto module started")
await MainActor.run {
listenToRoomEvents()
registerEventHandlers()
onComplete?()
}
} catch {
Expand Down Expand Up @@ -624,26 +623,54 @@ class MXCryptoV2: NSObject, MXCrypto {

// MARK: - Private

private func listenToRoomEvents() {
private func registerEventHandlers() {
guard let session = session else {
return
}

roomEventObserver = session.listenToEvents(Array(MXKeyVerificationManagerV2.dmEventTypes)) { [weak self] event, direction, _ in
guard let self = self else { return }
let verificationTypes = MXKeyVerificationManagerV2.dmEventTypes
let allTypes = verificationTypes + [.roomEncryption, .roomMember]

roomEventObserver = session.listenToEvents(allTypes) { [weak self] event, direction, customObject in
guard let self = self, direction == .forwards else {
return
}

if direction == .forwards && event.sender != session.myUserId {
Task {
do {
Task {
do {
if event.eventType == .roomEncryption {
try await self.encryptor.handleRoomEncryptionEvent(event)

} else if event.eventType == .roomMember {
await self.handleRoomMemberEvent(event, roomState: customObject as? MXRoomState)

} else if verificationTypes.contains(where: { $0.identifier == event.type }) {
try await self.keyVerification.handleRoomEvent(event)
} catch {
self.log.error("Error handling event", context: error)
}
} catch {
self.log.error("Error handling event", context: error)
}
}
}
}

private func handleRoomMemberEvent(_ event: MXEvent, roomState: MXRoomState?) async {
guard
let userId = event.stateKey,
let state = roomState,
let member = state.members?.member(withUserId: userId)
else {
return
}

guard member.membership == .join || (member.membership == .invite && state.historyVisibility != .joined) else {
return
}

log.debug("Tracking new user `\(userId)` due to \(member.membership) event")
machine.addTrackedUsers([userId])
}

private func restoreBackupIfPossible(event: MXEvent) {
guard
event.type == kMXEventTypeStringSecretSend
Expand Down
62 changes: 32 additions & 30 deletions MatrixSDK/Crypto/Migration/MXCryptoMigrationV2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,37 @@ import OLMKit
import MatrixSDKCrypto

class MXCryptoMigrationV2: NSObject {
enum Error: Swift.Error {
case unknownPickleKey
}

private static let SessionBatchSize = 1000

private let legacyDevice: MXOlmDevice
private let store: MXCryptoMigrationStore
private let log = MXNamedLog(name: "MXCryptoMachineMigration")

init(legacyStore: MXCryptoStore) {
MXCryptoSDKLogger.shared.log(logLine: "Starting logs")

// We need to create legacy OlmDevice which sets itself internally as pickle key delegate
// Once established we can get the pickleKey from OLMKit which is used to decrypt and migrate
// the legacy store data
legacyDevice = MXOlmDevice(store: legacyStore)
store = .init(legacyStore: legacyStore)
super.init()
OLMKit.sharedInstance().pickleKeyDelegate = self
}

func migrateCrypto(updateProgress: @escaping (Double) -> Void) throws {
log.debug("Starting migration")
MXCryptoSDKLogger.shared.log(logLine: "Starting logs")

let startDate = Date()
updateProgress(0)

let key = pickleKey()
let data = try store.extractData(with: key)
let pickleKey = try legacyPickleKey()
let data = try store.extractData(with: pickleKey)

let url = try MXCryptoMachineStore.storeURL(for: data.account.userId)
let passphrase = try MXCryptoMachineStore.storePassphrase()

if FileManager.default.fileExists(atPath: url.path) {
try FileManager.default.removeItem(at: url)
Expand All @@ -63,7 +73,7 @@ class MXCryptoMigrationV2: NSObject {
try migrate(
data: data,
path: url.path,
passphrase: nil,
passphrase: passphrase,
progressListener: self
)

Expand All @@ -73,14 +83,15 @@ class MXCryptoMigrationV2: NSObject {
let totalSessions = store.olmSessionCount + store.megolmSessionCount
let olmToMegolmRatio = totalSessions > 0 ? Double(store.olmSessionCount)/Double(totalSessions) : 0

store.extractSessions(with: key, batchSize: Self.SessionBatchSize) { [weak self] batch, progress in
store.extractSessions(with: pickleKey, batchSize: Self.SessionBatchSize) { [weak self] batch, progress in
updateProgress(progress * olmToMegolmRatio)

do {
try self?.migrateSessions(
data: data,
sessions: batch,
url: url
url: url,
passphrase: passphrase
)
} catch {
self?.log.error("Error migrating some sessions", context: error)
Expand All @@ -89,14 +100,15 @@ class MXCryptoMigrationV2: NSObject {

log.debug("Migrating megolm sessions in batches")

store.extractGroupSessions(with: key, batchSize: Self.SessionBatchSize) { [weak self] batch, progress in
store.extractGroupSessions(with: pickleKey, batchSize: Self.SessionBatchSize) { [weak self] batch, progress in
updateProgress(olmToMegolmRatio + progress * (1 - olmToMegolmRatio))

do {
try self?.migrateSessions(
data: data,
inboundGroupSessions: batch,
url: url
url: url,
passphrase: passphrase
)
} catch {
self?.log.error("Error migrating some sessions", context: error)
Expand All @@ -108,14 +120,22 @@ class MXCryptoMigrationV2: NSObject {
updateProgress(1)
}

private func legacyPickleKey() throws -> Data {
guard let key = OLMKit.sharedInstance().pickleKeyDelegate?.pickleKey() else {
throw Error.unknownPickleKey
}
return key
}

// To migrate sessions in batches and keep memory under control we are repeatedly calling `migrate`
// function whilst only passing data for sessions and account, keeping the rest empty.
// This API will be improved in `MatrixCryptoSDK` in the future.
private func migrateSessions(
data: MigrationData,
sessions: [PickledSession] = [],
inboundGroupSessions: [PickledInboundGroupSession] = [],
url: URL
url: URL,
passphrase: String
) throws {
try migrate(
data: .init(
Expand All @@ -129,30 +149,12 @@ class MXCryptoMigrationV2: NSObject {
trackedUsers: data.trackedUsers
),
path: url.path,
passphrase: nil,
passphrase: passphrase,
progressListener: self
)
}
}

extension MXCryptoMigrationV2: OLMKitPickleKeyDelegate {
public func pickleKey() -> Data {
let key = MXKeyProvider.sharedInstance()
.keyDataForData(
ofType: MXCryptoOlmPickleKeyDataType,
isMandatory: true,
expectedKeyType: .rawData
)

guard let key = key as? MXRawDataKey else {
log.failure("Wrong key")
return Data()
}

return key.key
}
}

extension MXCryptoMigrationV2: ProgressListener {
func onProgress(progress: Int32, total: Int32) {
// Progress loggged manually
Expand Down
10 changes: 3 additions & 7 deletions MatrixSDK/Crypto/Trust/MXTrustLevelSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,10 @@ struct MXTrustLevelSource {
)
}

func trustLevelSummary(userIds: [String]) -> MXUsersTrustLevelSummary? {
guard let devices = trustedDevices(userIds: userIds) else {
return nil
}

func trustLevelSummary(userIds: [String]) -> MXUsersTrustLevelSummary {
return .init(
trustedUsersProgress: trustedUsers(userIds: userIds),
andTrustedDevicesProgress: devices
andTrustedDevicesProgress: trustedDevices(userIds: userIds)
)
}

Expand All @@ -71,7 +67,7 @@ struct MXTrustLevelSource {
return progress
}

private func trustedDevices(userIds: [String]) -> Progress? {
private func trustedDevices(userIds: [String]) -> Progress {
let devices = userIds.flatMap {
devicesSource.devices(userId: $0)
}
Expand Down
10 changes: 8 additions & 2 deletions MatrixSDK/Crypto/Verification/MXKeyVerificationManagerV2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
}

func handleRoomEvent(_ event: MXEvent) async throws {
guard isRoomVerificationEvent(event) else {
guard isIncomingRoomVerificationEvent(event) else {
return
}

Expand Down Expand Up @@ -465,7 +465,13 @@ class MXKeyVerificationManagerV2: NSObject, MXKeyVerificationManager {
return roomId
}

private func isRoomVerificationEvent(_ event: MXEvent) -> Bool {
private func isIncomingRoomVerificationEvent(_ event: MXEvent) -> Bool {
// Only consider events not coming from our own user, because verification events
// for the same user are sent as encrypted to-device messages
guard event.sender != session?.myUserId else {
return false
}

// Filter incoming events by allowed list of event types
guard Self.dmEventTypes.contains(where: { $0.identifier == event.type }) else {
return false
Expand Down
Loading

0 comments on commit 496b17e

Please sign in to comment.