From e1679d59be9c277493fc6b3a80f8196a030faeb0 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Sat, 6 Jun 2020 14:28:18 +0200 Subject: [PATCH] better smoothen out keys --- lib/encryption.dart | 1 + lib/encryption/cross_signing.dart | 6 +- lib/encryption/ssss.dart | 6 +- lib/encryption/utils/key_verification.dart | 8 +- lib/matrix_api.dart | 3 +- lib/matrix_api/matrix_api.dart | 2 +- lib/matrix_api/model/keys_query_response.dart | 3 +- .../model/matrix_cross_signing_key.dart | 65 --------- ...trix_device_keys.dart => matrix_keys.dart} | 85 +++++++++--- lib/src/utils/device_keys_list.dart | 127 +++++------------- test/matrix_api_test.dart | 2 +- 11 files changed, 113 insertions(+), 195 deletions(-) delete mode 100644 lib/matrix_api/model/matrix_cross_signing_key.dart rename lib/matrix_api/model/{matrix_device_keys.dart => matrix_keys.dart} (58%) diff --git a/lib/encryption.dart b/lib/encryption.dart index ef4f347..2239ee2 100644 --- a/lib/encryption.dart +++ b/lib/encryption.dart @@ -20,4 +20,5 @@ library encryption; export './encryption/encryption.dart'; export './encryption/key_manager.dart'; +export './encryption/ssss.dart'; export './encryption/utils/key_verification.dart'; diff --git a/lib/encryption/cross_signing.dart b/lib/encryption/cross_signing.dart index b525a7b..164b183 100644 --- a/lib/encryption/cross_signing.dart +++ b/lib/encryption/cross_signing.dart @@ -100,7 +100,7 @@ class CrossSigning { ]); } - bool signable(List keys) { + bool signable(List keys) { for (final key in keys) { if (key is CrossSigningKey && key.usage.contains('master')) { return true; @@ -114,13 +114,13 @@ class CrossSigning { return false; } - Future sign(List keys) async { + Future sign(List keys) async { Uint8List selfSigningKey; Uint8List userSigningKey; final signatures = {}; var signedKey = false; final addSignature = - (SignedKey key, SignedKey signedWith, String signature) { + (SignableKey key, SignableKey signedWith, String signature) { if (key == null || signedWith == null || signature == null) { return; } diff --git a/lib/encryption/ssss.dart b/lib/encryption/ssss.dart index ae792f5..9349a14 100644 --- a/lib/encryption/ssss.dart +++ b/lib/encryption/ssss.dart @@ -221,11 +221,7 @@ class SSSS { 'mac': encrypted.mac, }; // store the thing in your account data - await client.jsonRequest( - type: RequestType.PUT, - action: '/client/r0/user/${client.userID}/account_data/${type}', - data: content, - ); + await client.api.setAccountData(client.userID, type, content); if (CACHE_TYPES.contains(type) && client.database != null) { // cache the thing await client.database diff --git a/lib/encryption/utils/key_verification.dart b/lib/encryption/utils/key_verification.dart index 9c5b1ef..638c724 100644 --- a/lib/encryption/utils/key_verification.dart +++ b/lib/encryption/utils/key_verification.dart @@ -128,7 +128,7 @@ class KeyVerification { List possibleMethods; Map startPaylaod; String _nextAction; - List _verifiedDevices; + List _verifiedDevices; DateTime lastActivity; String lastStep; @@ -404,8 +404,8 @@ class KeyVerification { } Future verifyKeys(Map keys, - Future Function(String, SignedKey) verifier) async { - _verifiedDevices = []; + Future Function(String, SignableKey) verifier) async { + _verifiedDevices = []; if (!client.userDeviceKeys.containsKey(userId)) { await cancel('m.key_mismatch'); @@ -863,7 +863,7 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod { mac[entry.key] = entry.value; } } - await request.verifyKeys(mac, (String mac, SignedKey key) async { + await request.verifyKeys(mac, (String mac, SignableKey key) async { return mac == _calculateMac(key.ed25519Key, baseInfo + 'ed25519:' + key.identifier); }); diff --git a/lib/matrix_api.dart b/lib/matrix_api.dart index b12702b..5832d4f 100644 --- a/lib/matrix_api.dart +++ b/lib/matrix_api.dart @@ -31,9 +31,8 @@ export 'package:famedlysdk/matrix_api/model/filter.dart'; export 'package:famedlysdk/matrix_api/model/keys_query_response.dart'; export 'package:famedlysdk/matrix_api/model/login_response.dart'; export 'package:famedlysdk/matrix_api/model/login_types.dart'; -export 'package:famedlysdk/matrix_api/model/matrix_cross_signing_key.dart'; -export 'package:famedlysdk/matrix_api/model/matrix_device_keys.dart'; export 'package:famedlysdk/matrix_api/model/matrix_exception.dart'; +export 'package:famedlysdk/matrix_api/model/matrix_keys.dart'; export 'package:famedlysdk/matrix_api/model/message_types.dart'; export 'package:famedlysdk/matrix_api/model/presence_content.dart'; export 'package:famedlysdk/matrix_api/model/notifications_query_response.dart'; diff --git a/lib/matrix_api/matrix_api.dart b/lib/matrix_api/matrix_api.dart index 70b2e2a..4c3ddcb 100644 --- a/lib/matrix_api/matrix_api.dart +++ b/lib/matrix_api/matrix_api.dart @@ -36,8 +36,8 @@ import 'package:mime_type/mime_type.dart'; import 'package:moor/moor.dart'; import 'model/device.dart'; -import 'model/matrix_device_keys.dart'; import 'model/matrix_event.dart'; +import 'model/matrix_keys.dart'; import 'model/event_context.dart'; import 'model/events_sync_update.dart'; import 'model/login_response.dart'; diff --git a/lib/matrix_api/model/keys_query_response.dart b/lib/matrix_api/model/keys_query_response.dart index 4fef3f3..57bc16e 100644 --- a/lib/matrix_api/model/keys_query_response.dart +++ b/lib/matrix_api/model/keys_query_response.dart @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -import 'matrix_device_keys.dart'; -import 'matrix_cross_signing_key.dart'; +import 'matrix_keys.dart'; class KeysQueryResponse { Map failures; diff --git a/lib/matrix_api/model/matrix_cross_signing_key.dart b/lib/matrix_api/model/matrix_cross_signing_key.dart deleted file mode 100644 index 2a852a1..0000000 --- a/lib/matrix_api/model/matrix_cross_signing_key.dart +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Famedly Matrix SDK - * Copyright (C) 2020 Famedly GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -class MatrixCrossSigningKey { - String userId; - List usage; - Map keys; - Map> signatures; - Map unsigned; - String get publicKey => keys?.values?.first; - - MatrixCrossSigningKey( - this.userId, - this.usage, - this.keys, - this.signatures, { - this.unsigned, - }); - - // This object is used for signing so we need the raw json too - Map _json; - - MatrixCrossSigningKey.fromJson(Map json) { - _json = json; - userId = json['user_id']; - usage = List.from(json['usage']); - keys = Map.from(json['keys']); - signatures = Map>.from( - (json['signatures'] as Map) - .map((k, v) => MapEntry(k, Map.from(v)))); - unsigned = json['unsigned'] != null - ? Map.from(json['unsigned']) - : null; - } - - Map toJson() { - final data = _json ?? {}; - data['user_id'] = userId; - data['usage'] = usage; - data['keys'] = keys; - - if (signatures != null) { - data['signatures'] = signatures; - } - if (unsigned != null) { - data['unsigned'] = unsigned; - } - return data; - } -} diff --git a/lib/matrix_api/model/matrix_device_keys.dart b/lib/matrix_api/model/matrix_keys.dart similarity index 58% rename from lib/matrix_api/model/matrix_device_keys.dart rename to lib/matrix_api/model/matrix_keys.dart index 95a225b..05ffa28 100644 --- a/lib/matrix_api/model/matrix_device_keys.dart +++ b/lib/matrix_api/model/matrix_keys.dart @@ -16,38 +16,25 @@ * along with this program. If not, see . */ -class MatrixDeviceKeys { +class MatrixSignableKey { String userId; - String deviceId; - List algorithms; Map keys; Map> signatures; Map unsigned; - String get deviceDisplayName => - unsigned != null ? unsigned['device_display_name'] : null; + + MatrixSignableKey(this.userId, this.keys, this.signatures, {this.unsigned}); // This object is used for signing so we need the raw json too Map _json; - MatrixDeviceKeys( - this.userId, - this.deviceId, - this.algorithms, - this.keys, - this.signatures, { - this.unsigned, - }); - - MatrixDeviceKeys.fromJson(Map json) { + MatrixSignableKey.fromJson(Map json) { _json = json; userId = json['user_id']; - deviceId = json['device_id']; - algorithms = json['algorithms'].cast(); keys = Map.from(json['keys']); - signatures = Map>.from( + signatures = json['signatures'] is Map ? Map>.from( (json['signatures'] as Map) - .map((k, v) => MapEntry(k, Map.from(v)))); - unsigned = json['unsigned'] != null + .map((k, v) => MapEntry(k, Map.from(v)))) : null; + unsigned = json['unsigned'] is Map ? Map.from(json['unsigned']) : null; } @@ -55,8 +42,6 @@ class MatrixDeviceKeys { Map toJson() { final data = _json ?? {}; data['user_id'] = userId; - data['device_id'] = deviceId; - data['algorithms'] = algorithms; data['keys'] = keys; if (signatures != null) { @@ -68,3 +53,59 @@ class MatrixDeviceKeys { return data; } } + +class MatrixCrossSigningKey extends MatrixSignableKey { + List usage; + String get publicKey => keys?.values?.first; + + MatrixCrossSigningKey( + String userId, + this.usage, + Map keys, + Map> signatures, { + Map unsigned, + }) : super(userId, keys, signatures, unsigned: unsigned); + + @override + MatrixCrossSigningKey.fromJson(Map json) + : super.fromJson(json) { + usage = List.from(json['usage']); + } + + @override + Map toJson() { + final data = super.toJson(); + data['usage'] = usage; + return data; + } +} + +class MatrixDeviceKeys extends MatrixSignableKey { + String deviceId; + List algorithms; + String get deviceDisplayName => + unsigned != null ? unsigned['device_display_name'] : null; + + MatrixDeviceKeys( + String userId, + this.deviceId, + this.algorithms, + Map keys, + Map> signatures, { + Map unsigned, + }) : super(userId, keys, signatures, unsigned: unsigned); + + @override + MatrixDeviceKeys.fromJson(Map json) : super.fromJson(json) { + deviceId = json['device_id']; + algorithms = json['algorithms'].cast(); + } + + @override + Map toJson() { + final data = super.toJson(); + data['device_id'] = deviceId; + data['algorithms'] = algorithms; + return data; + } +} diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index 0297668..a39fda2 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -21,7 +21,7 @@ class DeviceKeysList { Map deviceKeys = {}; Map crossSigningKeys = {}; - SignedKey getKey(String id) { + SignableKey getKey(String id) { if (deviceKeys.containsKey(id)) { return deviceKeys[id]; } @@ -98,13 +98,9 @@ class DeviceKeysList { DeviceKeysList(this.userId); } -abstract class SignedKey { +abstract class SignableKey extends MatrixSignableKey { Client client; - String userId; String identifier; - Map content; - Map keys; - Map signatures; Map validSignatures; bool _verified; bool blocked; @@ -120,8 +116,15 @@ abstract class SignedKey { bool get crossVerified => hasValidSignatureChain(); bool get signed => hasValidSignatureChain(verifiedOnly: false); + SignableKey.fromJson(Map json, Client cl) + : client = cl, + super.fromJson(json) { + _verified = false; + blocked = false; + } + String get signingContent { - final data = Map.from(content); + final data = Map.from(super.toJson()); // some old data might have the custom verified and blocked keys data.remove('verified'); data.remove('blocked'); @@ -166,7 +169,7 @@ abstract class SignedKey { continue; } final keyId = fullKeyId.substring('ed25519:'.length); - SignedKey key; + SignableKey key; if (client.userDeviceKeys[otherUserId].deviceKeys.containsKey(keyId)) { key = client.userDeviceKeys[otherUserId].deviceKeys[keyId]; } else if (client.userDeviceKeys[otherUserId].crossSigningKeys @@ -236,8 +239,9 @@ abstract class SignedKey { Future setBlocked(bool newBlocked); + @override Map toJson() { - final data = Map.from(content); + final data = Map.from(super.toJson()); // some old data may have the verified and blocked keys which are unneeded now data.remove('verified'); data.remove('blocked'); @@ -248,7 +252,7 @@ abstract class SignedKey { String toString() => json.encode(toJson()); } -class CrossSigningKey extends SignedKey { +class CrossSigningKey extends SignableKey { String get publicKey => identifier; List usage; @@ -269,59 +273,35 @@ class CrossSigningKey extends SignedKey { newBlocked, client.id, userId, publicKey); } - CrossSigningKey.fromMatrixCrossSigningKey( - MatrixCrossSigningKey k, Client cl) { - client = cl; - content = Map.from(k.toJson()); - userId = k.userId; + CrossSigningKey.fromMatrixCrossSigningKey(MatrixCrossSigningKey k, Client cl) + : super.fromJson(Map.from(k.toJson()), cl) { + final json = toJson(); identifier = k.publicKey; - usage = content['usage'].cast(); - keys = content['keys'] != null - ? Map.from(content['keys']) - : null; - signatures = content['signatures'] != null - ? Map.from(content['signatures']) - : null; - _verified = false; - blocked = false; + usage = json['usage'].cast(); } - CrossSigningKey.fromDb(DbUserCrossSigningKey dbEntry, Client cl) { - client = cl; - final json = Event.getMapFromPayload(dbEntry.content); - content = Map.from(json); - userId = dbEntry.userId; + CrossSigningKey.fromDb(DbUserCrossSigningKey dbEntry, Client cl) + : super.fromJson(Event.getMapFromPayload(dbEntry.content), cl) { + final json = toJson(); identifier = dbEntry.publicKey; usage = json['usage'].cast(); - keys = json['keys'] != null ? Map.from(json['keys']) : null; - signatures = json['signatures'] != null - ? Map.from(json['signatures']) - : null; _verified = dbEntry.verified; blocked = dbEntry.blocked; } - CrossSigningKey.fromJson(Map json, Client cl) { - client = cl; - content = Map.from(json); - userId = json['user_id']; + CrossSigningKey.fromJson(Map json, Client cl) + : super.fromJson(Map.from(json), cl) { + final json = toJson(); usage = json['usage'].cast(); - keys = json['keys'] != null ? Map.from(json['keys']) : null; - signatures = json['signatures'] != null - ? Map.from(json['signatures']) - : null; - _verified = json['verified'] ?? false; - blocked = json['blocked'] ?? false; - if (keys != null) { + if (keys != null && keys.isNotEmpty) { identifier = keys.values.first; } } } -class DeviceKeys extends SignedKey { +class DeviceKeys extends SignableKey { String get deviceId => identifier; List algorithms; - Map unsigned; String get curve25519Key => keys['curve25519:$deviceId']; @@ -346,60 +326,27 @@ class DeviceKeys extends SignedKey { ?.setBlockedUserDeviceKey(newBlocked, client.id, userId, deviceId); } - DeviceKeys.fromMatrixDeviceKeys(MatrixDeviceKeys k, Client cl) { - client = cl; - content = Map.from(k.toJson()); - userId = k.userId; + DeviceKeys.fromMatrixDeviceKeys(MatrixDeviceKeys k, Client cl) + : super.fromJson(Map.from(k.toJson()), cl) { + final json = toJson(); identifier = k.deviceId; - algorithms = content['algorithms'].cast(); - keys = content['keys'] != null - ? Map.from(content['keys']) - : null; - signatures = content['signatures'] != null - ? Map.from(content['signatures']) - : null; - unsigned = content['unsigned'] != null - ? Map.from(content['unsigned']) - : null; - _verified = false; - blocked = false; + algorithms = json['algorithms'].cast(); } - DeviceKeys.fromDb(DbUserDeviceKeysKey dbEntry, Client cl) { - client = cl; - final json = Event.getMapFromPayload(dbEntry.content); - content = Map.from(json); - userId = dbEntry.userId; + DeviceKeys.fromDb(DbUserDeviceKeysKey dbEntry, Client cl) + : super.fromJson(Event.getMapFromPayload(dbEntry.content), cl) { + final json = toJson(); identifier = dbEntry.deviceId; - algorithms = content['algorithms'].cast(); - keys = content['keys'] != null - ? Map.from(content['keys']) - : null; - signatures = content['signatures'] != null - ? Map.from(content['signatures']) - : null; - unsigned = json['unsigned'] != null - ? Map.from(json['unsigned']) - : null; + algorithms = json['algorithms'].cast(); _verified = dbEntry.verified; blocked = dbEntry.blocked; } - DeviceKeys.fromJson(Map json, Client cl) { - client = cl; - content = Map.from(json); - userId = json['user_id']; + DeviceKeys.fromJson(Map json, Client cl) + : super.fromJson(Map.from(json), cl) { + final json = toJson(); identifier = json['device_id']; algorithms = json['algorithms'].cast(); - keys = json['keys'] != null ? Map.from(json['keys']) : null; - signatures = json['signatures'] != null - ? Map.from(json['signatures']) - : null; - unsigned = json['unsigned'] != null - ? Map.from(json['unsigned']) - : null; - _verified = json['verified'] ?? false; - blocked = json['blocked'] ?? false; } KeyVerification startVerification() { diff --git a/test/matrix_api_test.dart b/test/matrix_api_test.dart index 0d3fa02..317bae5 100644 --- a/test/matrix_api_test.dart +++ b/test/matrix_api_test.dart @@ -18,7 +18,7 @@ import 'dart:typed_data'; import 'package:famedlysdk/matrix_api.dart'; -import 'package:famedlysdk/matrix_api/model/matrix_device_keys.dart'; +import 'package:famedlysdk/matrix_api/model/matrix_keys.dart'; import 'package:famedlysdk/matrix_api/model/filter.dart'; import 'package:famedlysdk/matrix_api/model/matrix_exception.dart'; import 'package:famedlysdk/matrix_api/model/presence_content.dart';