From 9ed94c8f3a1b48254b9839fdeb895d06249ead34 Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Fri, 5 Aug 2022 12:59:10 +0200 Subject: [PATCH] fix: Migrate to custom protobuf --- lib/src/double_ratchet/double_ratchet.dart | 24 +++++----- lib/src/omemo/sessionmanager.dart | 23 ++++----- .../protobuf/omemo_authenticated_message.dart | 18 +++---- lib/src/protobuf/omemo_key_exchange.dart | 33 +++++++------ lib/src/protobuf/omemo_message.dart | 30 +++++++----- test/protobuf_test.dart | 48 +++++++++---------- 6 files changed, 93 insertions(+), 83 deletions(-) diff --git a/lib/src/double_ratchet/double_ratchet.dart b/lib/src/double_ratchet/double_ratchet.dart index ef8f8ef..f0d2746 100644 --- a/lib/src/double_ratchet/double_ratchet.dart +++ b/lib/src/double_ratchet/double_ratchet.dart @@ -1,12 +1,12 @@ import 'package:cryptography/cryptography.dart'; import 'package:meta/meta.dart'; -import 'package:omemo_dart/protobuf/schema.pb.dart'; import 'package:omemo_dart/src/crypto.dart'; import 'package:omemo_dart/src/double_ratchet/crypto.dart'; import 'package:omemo_dart/src/double_ratchet/kdf.dart'; import 'package:omemo_dart/src/errors.dart'; import 'package:omemo_dart/src/helpers.dart'; import 'package:omemo_dart/src/keys.dart'; +import 'package:omemo_dart/src/protobuf/omemo_message.dart'; /// Amount of messages we may skip per session const maxSkip = 1000; @@ -14,7 +14,7 @@ const maxSkip = 1000; class RatchetStep { const RatchetStep(this.header, this.ciphertext); - final OMEMOMessage header; + final OmemoMessage header; final List ciphertext; } @@ -111,10 +111,10 @@ class OmemoDoubleRatchet { ); } - Future?> _trySkippedMessageKeys(OMEMOMessage header, List ciphertext) async { + Future?> _trySkippedMessageKeys(OmemoMessage header, List ciphertext) async { final key = SkippedKey( - OmemoPublicKey.fromBytes(header.dhPub, KeyPairType.x25519), - header.n, + OmemoPublicKey.fromBytes(header.dhPub!, KeyPairType.x25519), + header.n!, ); if (mkSkipped.containsKey(key)) { final mk = mkSkipped[key]!; @@ -142,11 +142,11 @@ class OmemoDoubleRatchet { } } - Future _dhRatchet(OMEMOMessage header) async { - pn = header.n; + Future _dhRatchet(OmemoMessage header) async { + pn = header.n!; ns = 0; nr = 0; - dhr = OmemoPublicKey.fromBytes(header.dhPub, KeyPairType.x25519); + dhr = OmemoPublicKey.fromBytes(header.dhPub!, KeyPairType.x25519); final newRk = await kdfRk(rk, await omemoDH(dhs, dhr!, 0)); rk = newRk; @@ -163,7 +163,7 @@ class OmemoDoubleRatchet { final mk = await kdfCk(cks!, kdfCkNextMessageKey); cks = newCks; - final header = OMEMOMessage() + final header = OmemoMessage() ..dhPub = await dhs.pk.getBytes() ..pn = pn ..n = ns; @@ -180,7 +180,7 @@ class OmemoDoubleRatchet { /// Ratchet. Returns the decrypted (raw) plaintext. /// /// Throws an SkippingTooManyMessagesException if too many messages were to be skipped. - Future> ratchetDecrypt(OMEMOMessage header, List ciphertext) async { + Future> ratchetDecrypt(OmemoMessage header, List ciphertext) async { // Check if we skipped too many messages final plaintext = await _trySkippedMessageKeys(header, ciphertext); if (plaintext != null) { @@ -188,11 +188,11 @@ class OmemoDoubleRatchet { } if (header.dhPub != await dhr?.getBytes()) { - await _skipMessageKeys(header.pn); + await _skipMessageKeys(header.pn!); await _dhRatchet(header); } - await _skipMessageKeys(header.n); + await _skipMessageKeys(header.n!); final newCkr = await kdfCk(ckr!, kdfCkNextChainKey); final mk = await kdfCk(ckr!, kdfCkNextMessageKey); ckr = newCkr; diff --git a/lib/src/omemo/sessionmanager.dart b/lib/src/omemo/sessionmanager.dart index 02d89d9..3f4c7e3 100644 --- a/lib/src/omemo/sessionmanager.dart +++ b/lib/src/omemo/sessionmanager.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'package:collection/collection.dart'; import 'package:cryptography/cryptography.dart'; -import 'package:omemo_dart/protobuf/schema.pb.dart'; import 'package:omemo_dart/src/crypto.dart'; import 'package:omemo_dart/src/double_ratchet/double_ratchet.dart'; import 'package:omemo_dart/src/errors.dart'; @@ -9,6 +8,9 @@ import 'package:omemo_dart/src/helpers.dart'; import 'package:omemo_dart/src/keys.dart'; import 'package:omemo_dart/src/omemo/bundle.dart'; import 'package:omemo_dart/src/omemo/device.dart'; +import 'package:omemo_dart/src/protobuf/omemo_authenticated_message.dart'; +import 'package:omemo_dart/src/protobuf/omemo_key_exchange.dart'; +import 'package:omemo_dart/src/protobuf/omemo_message.dart'; import 'package:omemo_dart/src/x3dh/x3dh.dart'; import 'package:synchronized/synchronized.dart'; @@ -80,7 +82,7 @@ class OmemoSessionManager { /// Create a ratchet session initiated by Alice to the user with Jid [jid] and the device /// [deviceId] from the bundle [bundle]. - Future addSessionFromBundle(String jid, int deviceId, OmemoBundle bundle) async { + Future addSessionFromBundle(String jid, int deviceId, OmemoBundle bundle) async { final kexResult = await x3dhFromBundle( bundle, device.ik, @@ -93,9 +95,8 @@ class OmemoSessionManager { await addSession(jid, deviceId, ratchet); - return OMEMOKeyExchange() + return OmemoKeyExchange() ..pkId = kexResult.opkId - // TODO(PapaTutuWawa): Fix ..spkId = 0 ..ik = await device.ik.pk.getBytes() ..ek = await kexResult.ek.pk.getBytes(); @@ -104,15 +105,15 @@ class OmemoSessionManager { /// Build a new session with the user at [jid] with the device [deviceId] using data /// from the key exchange [kex]. // TODO(PapaTutuWawa): Replace the OPK - Future addSessionFromKeyExchange(String jid, int deviceId, OMEMOKeyExchange kex) async { + Future addSessionFromKeyExchange(String jid, int deviceId, OmemoKeyExchange kex) async { final kexResult = await x3dhFromInitialMessage( X3DHMessage( - OmemoPublicKey.fromBytes(kex.ik, KeyPairType.ed25519), - OmemoPublicKey.fromBytes(kex.ek, KeyPairType.x25519), - kex.pkId, + OmemoPublicKey.fromBytes(kex.ik!, KeyPairType.ed25519), + OmemoPublicKey.fromBytes(kex.ek!, KeyPairType.x25519), + kex.pkId!, ), device.spk, - device.opks.values.elementAt(kex.pkId), + device.opks.values.elementAt(kex.pkId!), device.ik, ); final ratchet = await OmemoDoubleRatchet.acceptNewSession( @@ -174,8 +175,8 @@ class OmemoSessionManager { } final decodedRawKey = base64.decode(rawKey.value); - final authMessage = OMEMOAuthenticatedMessage.fromBuffer(decodedRawKey); - final message = OMEMOMessage.fromBuffer(authMessage.message); + final authMessage = OmemoAuthenticatedMessage.fromBuffer(decodedRawKey); + final message = OmemoMessage.fromBuffer(authMessage.message!); final ratchet = _ratchetMap[senderDeviceId]!; final keyAndHmac = await ratchet.ratchetDecrypt(message, decodedRawKey); diff --git a/lib/src/protobuf/omemo_authenticated_message.dart b/lib/src/protobuf/omemo_authenticated_message.dart index 9e55555..5f2f3f3 100644 --- a/lib/src/protobuf/omemo_authenticated_message.dart +++ b/lib/src/protobuf/omemo_authenticated_message.dart @@ -3,7 +3,7 @@ import 'package:omemo_dart/src/protobuf/protobuf.dart'; class OmemoAuthenticatedMessage { - const OmemoAuthenticatedMessage(this.mac, this.message); + OmemoAuthenticatedMessage(); factory OmemoAuthenticatedMessage.fromBuffer(List data) { var i = 0; @@ -20,18 +20,20 @@ class OmemoAuthenticatedMessage { } final message = data.sublist(i + 2, i + 2 + data[i + 1]); - return OmemoAuthenticatedMessage(mac, message); + return OmemoAuthenticatedMessage() + ..mac = mac + ..message = message; } - final List mac; - final List message; + List? mac; + List? message; List writeToBuffer() { return concat([ - [fieldId(1, fieldTypeByteArray), mac.length], - mac, - [fieldId(2, fieldTypeByteArray), message.length], - message, + [fieldId(1, fieldTypeByteArray), mac!.length], + mac!, + [fieldId(2, fieldTypeByteArray), message!.length], + message!, ]); } } diff --git a/lib/src/protobuf/omemo_key_exchange.dart b/lib/src/protobuf/omemo_key_exchange.dart index 4213958..788fa0d 100644 --- a/lib/src/protobuf/omemo_key_exchange.dart +++ b/lib/src/protobuf/omemo_key_exchange.dart @@ -4,7 +4,7 @@ import 'package:omemo_dart/src/protobuf/protobuf.dart'; class OmemoKeyExchange { - const OmemoKeyExchange(this.pkId, this.spkId, this.ik, this.ek, this.message); + OmemoKeyExchange(); factory OmemoKeyExchange.fromBuffer(List data) { var i = 0; @@ -40,26 +40,31 @@ class OmemoKeyExchange { } final message = OmemoAuthenticatedMessage.fromBuffer(data.sublist(i + 2)); - return OmemoKeyExchange(pkId, spkId, ik, ek, message); + return OmemoKeyExchange() + ..pkId = pkId + ..spkId = spkId + ..ik = ik + ..ek = ek + ..message = message; } - final int pkId; - final int spkId; - final List ik; - final List ek; - final OmemoAuthenticatedMessage message; + int? pkId; + int? spkId; + List? ik; + List? ek; + OmemoAuthenticatedMessage? message; List writeToBuffer() { - final msg = message.writeToBuffer(); + final msg = message!.writeToBuffer(); return concat([ [fieldId(1, fieldTypeUint32)], - encodeVarint(pkId), + encodeVarint(pkId!), [fieldId(2, fieldTypeUint32)], - encodeVarint(spkId), - [fieldId(3, fieldTypeByteArray), ik.length], - ik, - [fieldId(4, fieldTypeByteArray), ek.length], - ek, + encodeVarint(spkId!), + [fieldId(3, fieldTypeByteArray), ik!.length], + ik!, + [fieldId(4, fieldTypeByteArray), ek!.length], + ek!, [fieldId(5, fieldTypeByteArray), msg.length], msg, ]); diff --git a/lib/src/protobuf/omemo_message.dart b/lib/src/protobuf/omemo_message.dart index 6324cf5..6d77413 100644 --- a/lib/src/protobuf/omemo_message.dart +++ b/lib/src/protobuf/omemo_message.dart @@ -3,7 +3,7 @@ import 'package:omemo_dart/src/protobuf/protobuf.dart'; class OmemoMessage { - const OmemoMessage(this.n, this.pn, this.dhPub, this.ciphertext); + OmemoMessage(); factory OmemoMessage.fromBuffer(List data) { var i = 0; @@ -41,28 +41,32 @@ class OmemoMessage { ciphertext = data.sublist(i + 2, i + 2 + data[i + 1]); } - return OmemoMessage(n, pn, dhPub, ciphertext); + return OmemoMessage() + ..n = n + ..pn = pn + ..dhPub = dhPub + ..ciphertext = ciphertext; } - final int n; - final int pn; - final List dhPub; - final List? ciphertext; + int? n; + int? pn; + List? dhPub; + List? ciphertext; List writeToBuffer() { final data = concat([ - [8], - encodeVarint(n), - [16], - encodeVarint(pn), - [((3 << 3) | 2), dhPub.length], - dhPub, + [fieldId(1, fieldTypeUint32)], + encodeVarint(n!), + [fieldId(2, fieldTypeUint32)], + encodeVarint(pn!), + [fieldId(3, fieldTypeByteArray), dhPub!.length], + dhPub!, ]); if (ciphertext != null) { return concat([ data, - [((4 << 3) | 2), ciphertext!.length], + [fieldId(4, fieldTypeByteArray), ciphertext!.length], ciphertext!, ]); } diff --git a/test/protobuf_test.dart b/test/protobuf_test.dart index 3332570..14bbec5 100644 --- a/test/protobuf_test.dart +++ b/test/protobuf_test.dart @@ -79,12 +79,11 @@ void main() { expect(msg.ciphertext, null); }); test('Encode a OMEMOMessage', () { - const m = OmemoMessage( - 1, - 5, - [1, 2, 3], - [4, 5, 6], - ); + final m = OmemoMessage() + ..n = 1 + ..pn = 5 + ..dhPub = [1, 2, 3] + ..ciphertext = [4, 5, 6]; final serial = m.writeToBuffer(); final msg = OMEMOMessage.fromBuffer(serial); @@ -94,12 +93,10 @@ void main() { expect(msg.ciphertext, [4, 5, 6]); }); test('Encode a OMEMOMessage without ciphertext', () { - const m = OmemoMessage( - 1, - 5, - [1, 2, 3], - null, - ); + final m = OmemoMessage() + ..n = 1 + ..pn = 5 + ..dhPub = [1, 2, 3]; final serial = m.writeToBuffer(); final msg = OMEMOMessage.fromBuffer(serial); @@ -112,7 +109,9 @@ void main() { group('OMEMOAuthenticatedMessage', () { test('Test encoding a message', () { - const msg = OmemoAuthenticatedMessage([1, 2, 3], [4, 5, 6]); + final msg = OmemoAuthenticatedMessage() + ..mac = [1, 2, 3] + ..message = [4, 5, 6]; final decoded = OMEMOAuthenticatedMessage.fromBuffer(msg.writeToBuffer()); expect(decoded.mac, [1, 2, 3]); @@ -132,16 +131,15 @@ void main() { group('OMEMOKeyExchange', () { test('Test encoding a message', () { - const message = OmemoKeyExchange( - 698, - 245, - [1, 4, 6], - [4, 6, 7, 80], - OmemoAuthenticatedMessage( - [5, 6, 8, 0], - [4, 5, 7, 3, 2], - ), - ); + final authMessage = OmemoAuthenticatedMessage() + ..mac = [5, 6, 8, 0] + ..message = [4, 5, 7, 3, 2]; + final message = OmemoKeyExchange() + ..pkId = 698 + ..spkId = 245 + ..ik = [1, 4, 6] + ..ek = [4, 6, 7, 80] + ..message = authMessage; final kex = OMEMOKeyExchange.fromBuffer(message.writeToBuffer()); expect(kex.pkId, 698); @@ -169,8 +167,8 @@ void main() { expect(decoded.ik, [1, 4, 6]); expect(decoded.ek, [4 ,6 ,7 , 80]); - expect(decoded.message.mac, [5, 6, 8, 0]); - expect(decoded.message.message, [4, 5, 7, 3, 2]); + expect(decoded.message!.mac, [5, 6, 8, 0]); + expect(decoded.message!.message, [4, 5, 7, 3, 2]); }); }); }