feat: Add events for commiting the device map and ratchet

This commit is contained in:
PapaTutuWawa 2022-08-06 13:51:07 +02:00
parent 859f25d867
commit be239fdb43
3 changed files with 58 additions and 16 deletions

View File

@ -1,11 +1,28 @@
import 'package:omemo_dart/src/double_ratchet/double_ratchet.dart';
import 'package:omemo_dart/src/omemo/device.dart'; import 'package:omemo_dart/src/omemo/device.dart';
abstract class OmemoEvent {} abstract class OmemoEvent {}
/// Triggered when a ratchet has been modified
class RatchetModifiedEvent extends OmemoEvent {
RatchetModifiedEvent(this.jid, this.deviceId, this.ratchet);
final String jid;
final int deviceId;
final OmemoDoubleRatchet ratchet;
}
/// Triggered when the device map has been modified
class DeviceMapModifiedEvent extends OmemoEvent {
DeviceMapModifiedEvent(this.map);
final Map<String, List<int>> map;
}
/// Triggered by the OmemoSessionManager when our own device bundle was modified /// Triggered by the OmemoSessionManager when our own device bundle was modified
/// and thus should be republished. /// and thus should be republished.
class DeviceBundleModifiedEvent extends OmemoEvent { class DeviceModifiedEvent extends OmemoEvent {
DeviceBundleModifiedEvent(this.device); DeviceModifiedEvent(this.device);
final Device device; final Device device;
} }

View File

@ -130,6 +130,9 @@ class OmemoSessionManager {
_deviceMap[jid]!.add(deviceId); _deviceMap[jid]!.add(deviceId);
} }
// Commit the device map
_eventStreamController.add(DeviceMapModifiedEvent(_deviceMap));
// Add the ratchet session // Add the ratchet session
final key = RatchetMapKey(jid, deviceId); final key = RatchetMapKey(jid, deviceId);
if (!_ratchetMap.containsKey(key)) { if (!_ratchetMap.containsKey(key)) {
@ -138,6 +141,9 @@ class OmemoSessionManager {
// TODO(PapaTutuWawa): What do we do now? // TODO(PapaTutuWawa): What do we do now?
throw Exception(); throw Exception();
} }
// Commit the ratchet
_eventStreamController.add(RatchetModifiedEvent(jid, deviceId, ratchet));
}); });
} }
@ -218,6 +224,9 @@ class OmemoSessionManager {
final ratchet = _ratchetMap[ratchetKey]!; final ratchet = _ratchetMap[ratchetKey]!;
final ciphertext = (await ratchet.ratchetEncrypt(concatKey)).ciphertext; final ciphertext = (await ratchet.ratchetEncrypt(concatKey)).ciphertext;
// Commit the ratchet
_eventStreamController.add(RatchetModifiedEvent(jid, deviceId, ratchet));
if (kex.isNotEmpty && kex.containsKey(deviceId)) { if (kex.isNotEmpty && kex.containsKey(deviceId)) {
final k = kex[deviceId]! final k = kex[deviceId]!
..message = OmemoAuthenticatedMessage.fromBuffer(ciphertext); ..message = OmemoAuthenticatedMessage.fromBuffer(ciphertext);
@ -274,9 +283,9 @@ class OmemoSessionManager {
// Replace the OPK // Replace the OPK
await _deviceLock.synchronized(() async { await _deviceLock.synchronized(() async {
device = await device.replaceOnetimePrekey(kex.pkId!); device = await device.replaceOnetimePrekey(kex.pkId!);
_eventStreamController.add(
DeviceBundleModifiedEvent(device), // Commit the device
); _eventStreamController.add(DeviceModifiedEvent(device));
}); });
} else { } else {
authMessage = OmemoAuthenticatedMessage.fromBuffer(decodedRawKey); authMessage = OmemoAuthenticatedMessage.fromBuffer(decodedRawKey);
@ -291,17 +300,22 @@ class OmemoSessionManager {
} }
final message = OmemoMessage.fromBuffer(authMessage.message!); final message = OmemoMessage.fromBuffer(authMessage.message!);
final ratchetKey = RatchetMapKey(senderJid, senderDeviceId); final ratchetKey = RatchetMapKey(senderJid, senderDeviceId);
final ratchet = _ratchetMap[ratchetKey]!; List<int>? keyAndHmac;
List<int> keyAndHmac; await _lock.synchronized(() async {
if (rawKey.kex) { final ratchet = _ratchetMap[ratchetKey]!;
keyAndHmac = await ratchet.ratchetDecrypt(message, authMessage.writeToBuffer()); if (rawKey.kex) {
} else { keyAndHmac = await ratchet.ratchetDecrypt(message, authMessage.writeToBuffer());
keyAndHmac = await ratchet.ratchetDecrypt(message, decodedRawKey); } else {
} keyAndHmac = await ratchet.ratchetDecrypt(message, decodedRawKey);
final key = keyAndHmac.sublist(0, 32); }
final hmac = keyAndHmac.sublist(32, 48);
// Commit the ratchet
_eventStreamController.add(RatchetModifiedEvent(senderJid, senderDeviceId, ratchet));
});
final key = keyAndHmac!.sublist(0, 32);
final hmac = keyAndHmac!.sublist(32, 48);
final derivedKeys = await deriveEncryptionKeys(key, omemoPayloadInfoString); final derivedKeys = await deriveEncryptionKeys(key, omemoPayloadInfoString);
final computedHmac = await truncatedHmac(ciphertext, derivedKeys.authenticationKey); final computedHmac = await truncatedHmac(ciphertext, derivedKeys.authenticationKey);

View File

@ -8,12 +8,18 @@ void main() {
// Alice and Bob generate their sessions // Alice and Bob generate their sessions
var deviceModified = false; var deviceModified = false;
var ratchetModified = 0;
var deviceMapModified = 0;
final aliceSession = await OmemoSessionManager.generateNewIdentity(opkAmount: 1); final aliceSession = await OmemoSessionManager.generateNewIdentity(opkAmount: 1);
final bobSession = await OmemoSessionManager.generateNewIdentity(opkAmount: 1); final bobSession = await OmemoSessionManager.generateNewIdentity(opkAmount: 1);
final bobOpks = (await bobSession.getDevice()).opks.values.toList(); final bobOpks = (await bobSession.getDevice()).opks.values.toList();
bobSession.eventStream.listen((event) { bobSession.eventStream.listen((event) {
if (event is DeviceBundleModifiedEvent) { if (event is DeviceModifiedEvent) {
deviceModified = true; deviceModified = true;
} else if (event is RatchetModifiedEvent) {
ratchetModified++;
} else if (event is DeviceMapModifiedEvent) {
deviceMapModified++;
} }
}); });
@ -39,6 +45,11 @@ void main() {
aliceMessage.encryptedKeys, aliceMessage.encryptedKeys,
); );
expect(messagePlaintext, bobMessage); expect(messagePlaintext, bobMessage);
// The ratchet should be modified two times: Once for when the ratchet is created and
// other time for when the message is decrypted
expect(ratchetModified, 2);
// Bob's device map should be modified once
expect(deviceMapModified, 1);
// The event should be triggered // The event should be triggered
expect(deviceModified, true); expect(deviceModified, true);
// Bob should have replaced his OPK // Bob should have replaced his OPK