8 Commits

8 changed files with 87 additions and 14 deletions

View File

@@ -5,6 +5,6 @@ line-length=72
[title-trailing-punctuation] [title-trailing-punctuation]
[title-hard-tab] [title-hard-tab]
[title-match-regex] [title-match-regex]
regex=^(feat|fix|test|release|chore|security|docs|refactor|meta):.*$ regex=^(feat|fix|test|release|chore|security|docs|refactor):.*$
[body-trailing-whitespace] [body-trailing-whitespace]
[body-first-line-empty] [body-first-line-empty]

View File

@@ -4,3 +4,8 @@
- Implement the Double Ratchet, X3DH and OMEMO specific bits - Implement the Double Ratchet, X3DH and OMEMO specific bits
- Add a Blind-Trust-Before-Verification TrustManager - Add a Blind-Trust-Before-Verification TrustManager
- Supported OMEMO version: 0.8.3 - Supported OMEMO version: 0.8.3
## 0.1.3
- Fix bug with the Double Ratchet causing only the initial message to be decryptable
- Expose `getDeviceMap` as a developer usable function

View File

@@ -26,10 +26,10 @@ Include `omemo_dart` in your `pubspec.yaml` like this:
# [...] # [...]
dependencies: dependencies:
omemo_dart: omemo_dart:
hosted: https://git.polynom.me/api/packages/PapaTutuWawa/pub hosted: https://git.polynom.me/api/packages/PapaTutuWawa/pub
version: ^0.1.0 version: ^0.1.0
# [...] # [...]
# [...] # [...]
``` ```

View File

@@ -293,7 +293,11 @@ class OmemoDoubleRatchet {
return plaintext; return plaintext;
} }
if (header.dhPub != await dhr?.getBytes()) { final dhPubMatches = listsEqual(
header.dhPub ?? <int>[],
await dhr?.getBytes() ?? <int>[],
);
if (!dhPubMatches) {
await _skipMessageKeys(header.pn!); await _skipMessageKeys(header.pn!);
await _dhRatchet(header); await _dhRatchet(header);
} }

View File

@@ -387,11 +387,20 @@ class OmemoSessionManager {
}); });
} }
@visibleForTesting /// Returns the device map, i.e. the mapping of bare Jid to its device identifiers
OmemoDoubleRatchet getRatchet(String jid, int deviceId) => _ratchetMap[RatchetMapKey(jid, deviceId)]!; /// we have built sessions with.
Future<Map<String, List<int>>> getDeviceMap() async {
Map<String, List<int>>? map;
await _lock.synchronized(() async {
map = _deviceMap;
});
return map!;
}
@visibleForTesting @visibleForTesting
Map<String, List<int>> getDeviceMap() => _deviceMap; OmemoDoubleRatchet getRatchet(String jid, int deviceId) => _ratchetMap[RatchetMapKey(jid, deviceId)]!;
@visibleForTesting @visibleForTesting
Map<RatchetMapKey, OmemoDoubleRatchet> getRatchetMap() => _ratchetMap; Map<RatchetMapKey, OmemoDoubleRatchet> getRatchetMap() => _ratchetMap;

View File

@@ -1,11 +1,11 @@
name: omemo_dart name: omemo_dart
description: An XMPP library independent OMEMO library description: An XMPP library independent OMEMO library
version: 0.1.1 version: 0.1.3
homepage: https://github.com/PapaTutuWawa/omemo_dart homepage: https://github.com/PapaTutuWawa/omemo_dart
publish_to: https://git.polynom.me/api/packages/PapaTutuWawa/pub publish_to: https://git.polynom.me/api/packages/PapaTutuWawa/pub
environment: environment:
sdk: '>=2.15.0 <3.0.0' sdk: '>=2.17.0 <3.0.0'
dependencies: dependencies:
collection: ^1.16.0 collection: ^1.16.0

View File

@@ -7,7 +7,6 @@ void main() {
test('Test using OMEMO sessions with only one device per user', () async { test('Test using OMEMO sessions with only one device per user', () async {
const aliceJid = 'alice@server.example'; const aliceJid = 'alice@server.example';
const bobJid = 'bob@other.server.example'; const bobJid = 'bob@other.server.example';
// Alice and Bob generate their sessions // Alice and Bob generate their sessions
var deviceModified = false; var deviceModified = false;
var ratchetModified = 0; var ratchetModified = 0;
@@ -367,4 +366,60 @@ void main() {
// untrusted device. // untrusted device.
expect(aliceMessage.encryptedKeys.length, 1); expect(aliceMessage.encryptedKeys.length, 1);
}); });
test('Test by sending multiple messages back and forth', () async {
const aliceJid = 'alice@server.example';
const bobJid = 'bob@other.server.example';
// Alice and Bob generate their sessions
final aliceSession = await OmemoSessionManager.generateNewIdentity(
aliceJid,
AlwaysTrustingTrustManager(),
opkAmount: 1,
);
final bobSession = await OmemoSessionManager.generateNewIdentity(
bobJid,
AlwaysTrustingTrustManager(),
opkAmount: 1,
);
// Alice encrypts a message for Bob
final aliceMessage = await aliceSession.encryptToJid(
bobJid,
'Hello Bob!',
newSessions: [
await (await bobSession.getDevice()).toBundle(),
],
);
// Alice sends the message to Bob
// ...
await bobSession.decryptMessage(
aliceMessage.ciphertext,
aliceJid,
(await aliceSession.getDevice()).id,
aliceMessage.encryptedKeys,
);
for (var i = 0; i < 100; i++) {
final messageText = 'Test Message #$i';
// Bob responds to Alice
final bobResponseMessage = await bobSession.encryptToJid(
aliceJid,
messageText,
);
// Bob sends the message to Alice
// ...
// Alice decrypts it
final aliceReceivedMessage = await aliceSession.decryptMessage(
bobResponseMessage.ciphertext,
bobJid,
(await bobSession.getDevice()).id,
bobResponseMessage.encryptedKeys,
);
expect(messageText, aliceReceivedMessage);
}
});
} }

View File

@@ -93,7 +93,7 @@ void main() {
final oldDevice = await oldSession.getDevice(); final oldDevice = await oldSession.getDevice();
final newDevice = await newSession.getDevice(); final newDevice = await newSession.getDevice();
expect(await oldDevice.equals(newDevice), true); expect(await oldDevice.equals(newDevice), true);
expect(oldSession.getDeviceMap(), newSession.getDeviceMap()); expect(await oldSession.getDeviceMap(), await newSession.getDeviceMap());
expect(oldSession.getRatchetMap().length, newSession.getRatchetMap().length); expect(oldSession.getRatchetMap().length, newSession.getRatchetMap().length);
for (final session in oldSession.getRatchetMap().entries) { for (final session in oldSession.getRatchetMap().entries) {