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';
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
/// and thus should be republished.
class DeviceBundleModifiedEvent extends OmemoEvent {
class DeviceModifiedEvent extends OmemoEvent {
DeviceBundleModifiedEvent(this.device);
DeviceModifiedEvent(this.device);
final Device device;
}

View File

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

View File

@ -8,12 +8,18 @@ void main() {
// Alice and Bob generate their sessions
var deviceModified = false;
var ratchetModified = 0;
var deviceMapModified = 0;
final aliceSession = await OmemoSessionManager.generateNewIdentity(opkAmount: 1);
final bobSession = await OmemoSessionManager.generateNewIdentity(opkAmount: 1);
final bobOpks = (await bobSession.getDevice()).opks.values.toList();
bobSession.eventStream.listen((event) {
if (event is DeviceBundleModifiedEvent) {
if (event is DeviceModifiedEvent) {
deviceModified = true;
} else if (event is RatchetModifiedEvent) {
ratchetModified++;
} else if (event is DeviceMapModifiedEvent) {
deviceMapModified++;
}
});
@ -39,6 +45,11 @@ void main() {
aliceMessage.encryptedKeys,
);
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
expect(deviceModified, true);
// Bob should have replaced his OPK