fix: Track device Ids as integers

This commit is contained in:
PapaTutuWawa 2022-08-04 16:57:12 +02:00
parent 31ee61a5cd
commit 08ec093675
7 changed files with 51 additions and 46 deletions

View File

@ -12,16 +12,16 @@ class OmemoBundle {
this.ikEncoded, this.ikEncoded,
this.opksEncoded, this.opksEncoded,
); );
final String id; final int id;
/// The SPK but base64 encoded /// The SPK but base64 encoded
final String spkEncoded; final String spkEncoded;
final String spkId; final int spkId;
/// The SPK signature but base64 encoded /// The SPK signature but base64 encoded
final String spkSignatureEncoded; final String spkSignatureEncoded;
/// The IK but base64 encoded /// The IK but base64 encoded
final String ikEncoded; final String ikEncoded;
/// The mapping of a OPK's id to the base64 encoded data /// The mapping of a OPK's id to the base64 encoded data
final Map<String, String> opksEncoded; final Map<int, String> opksEncoded;
OmemoPublicKey get spk { OmemoPublicKey get spk {
final data = base64Decode(spkEncoded); final data = base64Decode(spkEncoded);
@ -33,7 +33,7 @@ class OmemoBundle {
return OmemoPublicKey.fromBytes(data, KeyPairType.ed25519); return OmemoPublicKey.fromBytes(data, KeyPairType.ed25519);
} }
OmemoPublicKey getOpk(String id) { OmemoPublicKey getOpk(int id) {
final data = base64Decode(opksEncoded[id]!); final data = base64Decode(opksEncoded[id]!);
return OmemoPublicKey.fromBytes(data, KeyPairType.x25519); return OmemoPublicKey.fromBytes(data, KeyPairType.x25519);
} }

View File

@ -20,16 +20,16 @@ class Device {
final spkId = generateRandom32BitNumber(); final spkId = generateRandom32BitNumber();
final signature = await sig(ik, await spk.pk.getBytes()); final signature = await sig(ik, await spk.pk.getBytes());
final opks = <String, OmemoKeyPair>{}; final opks = <int, OmemoKeyPair>{};
for (var i = 0; i < opkAmount; i++) { for (var i = 0; i < opkAmount; i++) {
opks[i.toString()] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); opks[i] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
} }
return Device(id.toString(), ik, spk, spkId.toString(), signature, opks); return Device(id, ik, spk, spkId, signature, opks);
} }
/// The device Id /// The device Id
final String id; final int id;
/// The identity key /// The identity key
final OmemoKeyPair ik; final OmemoKeyPair ik;
@ -37,16 +37,16 @@ class Device {
/// The signed prekey... /// The signed prekey...
final OmemoKeyPair spk; final OmemoKeyPair spk;
/// ...its Id, ... /// ...its Id, ...
final String spkId; final int spkId;
/// ...and its signature /// ...and its signature
final List<int> spkSignature; final List<int> spkSignature;
/// Map of an id to the associated Onetime-Prekey /// Map of an id to the associated Onetime-Prekey
final Map<String, OmemoKeyPair> opks; final Map<int, OmemoKeyPair> opks;
/// This replaces the Onetime-Prekey with id [id] with a completely new one. Returns /// This replaces the Onetime-Prekey with id [id] with a completely new one. Returns
/// a new Device object that copies over everything but replaces said key. /// a new Device object that copies over everything but replaces said key.
Future<Device> replaceOnetimePrekey(String id) async { Future<Device> replaceOnetimePrekey(int id) async {
final newOpk = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); final newOpk = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
return Device( return Device(
@ -76,14 +76,14 @@ class Device {
id, id,
ik, ik,
newSpk, newSpk,
newSpkId.toString(), newSpkId,
newSignature, newSignature,
opks, opks,
); );
} }
Future<OmemoBundle> toBundle() async { Future<OmemoBundle> toBundle() async {
final encodedOpks = <String, String>{}; final encodedOpks = <int, String>{};
for (final opkKey in opks.keys) { for (final opkKey in opks.keys) {
encodedOpks[opkKey] = base64.encode(await opks[opkKey]!.pk.getBytes()); encodedOpks[opkKey] = base64.encode(await opks[opkKey]!.pk.getBytes());

View File

@ -1,10 +1,12 @@
import 'dart:convert'; import 'dart:convert';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:cryptography/cryptography.dart';
import 'package:omemo_dart/protobuf/schema.pb.dart'; import 'package:omemo_dart/protobuf/schema.pb.dart';
import 'package:omemo_dart/src/crypto.dart'; import 'package:omemo_dart/src/crypto.dart';
import 'package:omemo_dart/src/double_ratchet/double_ratchet.dart'; import 'package:omemo_dart/src/double_ratchet/double_ratchet.dart';
import 'package:omemo_dart/src/errors.dart'; import 'package:omemo_dart/src/errors.dart';
import 'package:omemo_dart/src/helpers.dart'; 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/bundle.dart';
import 'package:omemo_dart/src/omemo/device.dart'; import 'package:omemo_dart/src/omemo/device.dart';
import 'package:omemo_dart/src/x3dh/x3dh.dart'; import 'package:omemo_dart/src/x3dh/x3dh.dart';
@ -22,13 +24,13 @@ class EncryptionResult {
/// Mapping of the device Id to the key for decrypting ciphertext, encrypted /// Mapping of the device Id to the key for decrypting ciphertext, encrypted
/// for the ratchet with said device Id /// for the ratchet with said device Id
final Map<String, List<int>> encryptedKeys; final Map<int, List<int>> encryptedKeys;
} }
class EncryptedKey { class EncryptedKey {
const EncryptedKey(this.rid, this.value); const EncryptedKey(this.rid, this.value);
final String rid; final int rid;
final String value; final String value;
} }
@ -48,16 +50,16 @@ class OmemoSessionManager {
final Lock _lock; final Lock _lock;
/// Mapping of the Device Id to its OMEMO session /// Mapping of the Device Id to its OMEMO session
final Map<String, OmemoDoubleRatchet> _ratchetMap; final Map<int, OmemoDoubleRatchet> _ratchetMap;
/// Mapping of a bare Jid to its Device Ids /// Mapping of a bare Jid to its Device Ids
final Map<String, List<String>> _deviceMap; final Map<String, List<int>> _deviceMap;
/// Our own keys /// Our own keys
Device device; Device device;
/// Add a session [ratchet] with the [deviceId] to the internal tracking state. /// Add a session [ratchet] with the [deviceId] to the internal tracking state.
Future<void> addSession(String jid, String deviceId, OmemoDoubleRatchet ratchet) async { Future<void> addSession(String jid, int deviceId, OmemoDoubleRatchet ratchet) async {
await _lock.synchronized(() async { await _lock.synchronized(() async {
// Add the bundle Id // Add the bundle Id
if (!_deviceMap.containsKey(jid)) { if (!_deviceMap.containsKey(jid)) {
@ -78,7 +80,7 @@ class OmemoSessionManager {
/// Create a ratchet session initiated by Alice to the user with Jid [jid] and the device /// Create a ratchet session initiated by Alice to the user with Jid [jid] and the device
/// [deviceId] from the bundle [bundle]. /// [deviceId] from the bundle [bundle].
Future<X3DHAliceResult> addSessionFromBundle(String jid, String deviceId, OmemoBundle bundle) async { Future<OMEMOKeyExchange> addSessionFromBundle(String jid, int deviceId, OmemoBundle bundle) async {
final kexResult = await x3dhFromBundle( final kexResult = await x3dhFromBundle(
bundle, bundle,
device.ik, device.ik,
@ -91,19 +93,26 @@ class OmemoSessionManager {
await addSession(jid, deviceId, ratchet); await addSession(jid, deviceId, ratchet);
return kexResult; return OMEMOKeyExchange()
..pkId = kexResult.opkId
// TODO(PapaTutuWawa): Fix
..spkId = 0
..ik = await device.ik.pk.getBytes()
..ek = await kexResult.ek.pk.getBytes();
} }
/// Build a new session with the user at [jid] with the device [deviceId] using data /// Build a new session with the user at [jid] with the device [deviceId] using data
/// from the key exchange [kex]. /// from the key exchange [kex].
// TODO(PapaTutuWawa): Use OMEMOKeyExchange
// TODO(PapaTutuWawa): Replace the OPK // TODO(PapaTutuWawa): Replace the OPK
Future<void> addSessionFromKeyExchange(String jid, String deviceId, X3DHMessage kex) async { Future<void> addSessionFromKeyExchange(String jid, int deviceId, OMEMOKeyExchange kex) async {
final kexResult = await x3dhFromInitialMessage( final kexResult = await x3dhFromInitialMessage(
kex, X3DHMessage(
OmemoPublicKey.fromBytes(kex.ik, KeyPairType.ed25519),
OmemoPublicKey.fromBytes(kex.ek, KeyPairType.x25519),
kex.pkId,
),
device.spk, device.spk,
// TODO(PapaTutuWawa): Fix device.opks.values.elementAt(kex.pkId),
device.opks.values.elementAt(0),
device.ik, device.ik,
); );
final ratchet = await OmemoDoubleRatchet.acceptNewSession( final ratchet = await OmemoDoubleRatchet.acceptNewSession(
@ -118,7 +127,7 @@ class OmemoSessionManager {
/// Encrypt the key [plaintext] for all known bundles of [jid]. Returns a map that /// Encrypt the key [plaintext] for all known bundles of [jid]. Returns a map that
/// maps the Bundle Id to the ciphertext of [plaintext]. /// maps the Bundle Id to the ciphertext of [plaintext].
Future<EncryptionResult> encryptToJid(String jid, String plaintext) async { Future<EncryptionResult> encryptToJid(String jid, String plaintext) async {
final encryptedKeys = <String, List<int>>{}; final encryptedKeys = <int, List<int>>{};
// Generate the key and encrypt the plaintext // Generate the key and encrypt the plaintext
final key = generateRandomBytes(32); final key = generateRandomBytes(32);
@ -149,7 +158,7 @@ class OmemoSessionManager {
/// <keys /> element with a "jid" attribute matching our own. [senderJid] refers to the /// <keys /> element with a "jid" attribute matching our own. [senderJid] refers to the
/// bare Jid of the sender. [senderDeviceId] refers to the "sid" attribute of the /// bare Jid of the sender. [senderDeviceId] refers to the "sid" attribute of the
/// <encrypted /> element. /// <encrypted /> element.
Future<String> decryptMessage(List<int> ciphertext, String senderJid, String senderDeviceId, List<EncryptedKey> keys) async { Future<String> decryptMessage(List<int> ciphertext, String senderJid, int senderDeviceId, List<EncryptedKey> keys) async {
// Try to find a session we can decrypt with. // Try to find a session we can decrypt with.
final rawKey = keys.firstWhereOrNull((key) => key.rid == device.id); final rawKey = keys.firstWhereOrNull((key) => key.rid == device.id);
if (rawKey == null) { if (rawKey == null) {

View File

@ -16,7 +16,7 @@ class X3DHAliceResult {
const X3DHAliceResult(this.ek, this.sk, this.opkId, this.ad); const X3DHAliceResult(this.ek, this.sk, this.opkId, this.ad);
final OmemoKeyPair ek; final OmemoKeyPair ek;
final List<int> sk; final List<int> sk;
final String opkId; final int opkId;
final List<int> ad; final List<int> ad;
} }
@ -26,7 +26,7 @@ class X3DHMessage {
const X3DHMessage(this.ik, this.ek, this.opkId); const X3DHMessage(this.ik, this.ek, this.opkId);
final OmemoPublicKey ik; final OmemoPublicKey ik;
final OmemoPublicKey ek; final OmemoPublicKey ek;
final String opkId; final int opkId;
} }
class X3DHBobResult { class X3DHBobResult {

View File

@ -41,16 +41,16 @@ void main() {
final spkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); final spkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
final opkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); final opkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
final bundleBob = OmemoBundle( final bundleBob = OmemoBundle(
'1', 1,
await spkBob.pk.asBase64(), await spkBob.pk.asBase64(),
'3', 3,
base64Encode( base64Encode(
await sig(ikBob, await spkBob.pk.getBytes()), await sig(ikBob, await spkBob.pk.getBytes()),
), ),
//'Q5in+/L4kJixEX692h6mJkPMyp4I3SlQ84L0E7ipPzqfPHOMiraUlqG2vG/O8wvFjLsKYZpPBraga9IvwhqVDA==', //'Q5in+/L4kJixEX692h6mJkPMyp4I3SlQ84L0E7ipPzqfPHOMiraUlqG2vG/O8wvFjLsKYZpPBraga9IvwhqVDA==',
await ikBob.pk.asBase64(), await ikBob.pk.asBase64(),
{ {
'2': await opkBob.pk.asBase64(), 2: await opkBob.pk.asBase64(),
}, },
); );
@ -65,7 +65,7 @@ void main() {
X3DHMessage( X3DHMessage(
ikAlice.pk, ikAlice.pk,
resultAlice.ek.pk, resultAlice.ek.pk,
'2', 2,
), ),
spkBob, spkBob,
opkBob, opkBob,

View File

@ -12,7 +12,7 @@ void main() {
final bobSession = await OmemoSessionManager.generateNewIdentity(opkAmount: 1); final bobSession = await OmemoSessionManager.generateNewIdentity(opkAmount: 1);
// Perform the X3DH // Perform the X3DH
final x3dhAliceResult = await aliceSession.addSessionFromBundle( final kex = await aliceSession.addSessionFromBundle(
bobJid, bobJid,
bobSession.device.id, bobSession.device.id,
await bobSession.device.toBundle(), await bobSession.device.toBundle(),
@ -20,11 +20,7 @@ void main() {
await bobSession.addSessionFromKeyExchange( await bobSession.addSessionFromKeyExchange(
aliceJid, aliceJid,
aliceSession.device.id, aliceSession.device.id,
X3DHMessage( kex,
aliceSession.device.ik.pk,
x3dhAliceResult.ek.pk,
'2',
),
); );
// Alice encrypts a message for Bob // Alice encrypts a message for Bob

View File

@ -11,16 +11,16 @@ void main() {
final spkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); final spkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
final opkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); final opkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
final bundleBob = OmemoBundle( final bundleBob = OmemoBundle(
'1', 1,
await spkBob.pk.asBase64(), await spkBob.pk.asBase64(),
'3', 3,
base64Encode( base64Encode(
await sig(ikBob, await spkBob.pk.getBytes()), await sig(ikBob, await spkBob.pk.getBytes()),
), ),
//'Q5in+/L4kJixEX692h6mJkPMyp4I3SlQ84L0E7ipPzqfPHOMiraUlqG2vG/O8wvFjLsKYZpPBraga9IvwhqVDA==', //'Q5in+/L4kJixEX692h6mJkPMyp4I3SlQ84L0E7ipPzqfPHOMiraUlqG2vG/O8wvFjLsKYZpPBraga9IvwhqVDA==',
await ikBob.pk.asBase64(), await ikBob.pk.asBase64(),
{ {
'2': await opkBob.pk.asBase64(), 2: await opkBob.pk.asBase64(),
}, },
); );
@ -35,7 +35,7 @@ void main() {
X3DHMessage( X3DHMessage(
ikAlice.pk, ikAlice.pk,
resultAlice.ek.pk, resultAlice.ek.pk,
'2', 2,
), ),
spkBob, spkBob,
opkBob, opkBob,
@ -53,15 +53,15 @@ void main() {
final spkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); final spkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
final opkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); final opkBob = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
final bundleBob = OmemoBundle( final bundleBob = OmemoBundle(
'1', 1,
await spkBob.pk.asBase64(), await spkBob.pk.asBase64(),
'3', 3,
// NOTE: A bit flakey, but it is highly unlikely that the same keypair as this one // NOTE: A bit flakey, but it is highly unlikely that the same keypair as this one
// gets generated. // gets generated.
'Q5in+/L4kJixEX692h6mJkPMyp4I3SlQ84L0E7ipPzqfPHOMiraUlqG2vG/O8wvFjLsKYZpPBraga9IvwhqVDA==', 'Q5in+/L4kJixEX692h6mJkPMyp4I3SlQ84L0E7ipPzqfPHOMiraUlqG2vG/O8wvFjLsKYZpPBraga9IvwhqVDA==',
await ikBob.pk.asBase64(), await ikBob.pk.asBase64(),
{ {
'2': await opkBob.pk.asBase64(), 2: await opkBob.pk.asBase64(),
}, },
); );