feat: Each OPK now gets it's own unique id
This commit is contained in:
parent
234fee167f
commit
65c0975a77
@ -3,7 +3,15 @@ import 'package:omemo_dart/src/errors.dart';
|
|||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class DecryptionResult {
|
class DecryptionResult {
|
||||||
const DecryptionResult(this.payload, this.error);
|
const DecryptionResult(this.payload, this.usedOpkId, this.error);
|
||||||
|
|
||||||
|
/// The decrypted payload or null, if it was an empty OMEMO message.
|
||||||
final String? payload;
|
final String? payload;
|
||||||
|
|
||||||
|
/// In case a key exchange has been performed: The id of the used OPK. Useful for
|
||||||
|
/// replacing the OPK after a message catch-up.
|
||||||
|
final int? usedOpkId;
|
||||||
|
|
||||||
|
/// The error that occurred during decryption or null, if no error occurred.
|
||||||
final OmemoError? error;
|
final OmemoError? error;
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,16 @@ class OmemoDevice {
|
|||||||
|
|
||||||
final opks = <int, OmemoKeyPair>{};
|
final opks = <int, OmemoKeyPair>{};
|
||||||
for (var i = 0; i < opkAmount; i++) {
|
for (var i = 0; i < opkAmount; i++) {
|
||||||
opks[i] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
// Generate unique ids for each key
|
||||||
|
while (true) {
|
||||||
|
final opkId = generateRandom32BitNumber();
|
||||||
|
if (opks.containsKey(opkId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
opks[opkId] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return OmemoDevice(jid, id, ik, spk, spkId, signature, null, null, opks);
|
return OmemoDevice(jid, id, ik, spk, spkId, signature, null, null, opks);
|
||||||
@ -72,7 +81,18 @@ class OmemoDevice {
|
|||||||
/// a new Device object that copies over everything but replaces said key.
|
/// a new Device object that copies over everything but replaces said key.
|
||||||
@internal
|
@internal
|
||||||
Future<OmemoDevice> replaceOnetimePrekey(int id) async {
|
Future<OmemoDevice> replaceOnetimePrekey(int id) async {
|
||||||
opks[id] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
opks.remove(id);
|
||||||
|
|
||||||
|
// Generate a new unique id for the OPK.
|
||||||
|
while (true) {
|
||||||
|
final newId = generateRandom32BitNumber();
|
||||||
|
if (opks.containsKey(newId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
opks[newId] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return OmemoDevice(
|
return OmemoDevice(
|
||||||
jid,
|
jid,
|
||||||
|
@ -351,6 +351,7 @@ class OmemoManager {
|
|||||||
final key = stanza.keys.firstWhereOrNull((key) => key.rid == deviceId);
|
final key = stanza.keys.firstWhereOrNull((key) => key.rid == deviceId);
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
return DecryptionResult(
|
return DecryptionResult(
|
||||||
|
null,
|
||||||
null,
|
null,
|
||||||
NotEncryptedForDeviceError(),
|
NotEncryptedForDeviceError(),
|
||||||
);
|
);
|
||||||
@ -359,6 +360,7 @@ class OmemoManager {
|
|||||||
// Protobuf will happily parse this and return bogus data.
|
// Protobuf will happily parse this and return bogus data.
|
||||||
if (key.value.isEmpty) {
|
if (key.value.isEmpty) {
|
||||||
return DecryptionResult(
|
return DecryptionResult(
|
||||||
|
null,
|
||||||
null,
|
null,
|
||||||
MalformedEncryptedKeyError(),
|
MalformedEncryptedKeyError(),
|
||||||
);
|
);
|
||||||
@ -396,6 +398,7 @@ class OmemoManager {
|
|||||||
spk = device.oldSpk!;
|
spk = device.oldSpk!;
|
||||||
} else {
|
} else {
|
||||||
return DecryptionResult(
|
return DecryptionResult(
|
||||||
|
null,
|
||||||
null,
|
null,
|
||||||
UnknownSignedPrekeyError(),
|
UnknownSignedPrekeyError(),
|
||||||
);
|
);
|
||||||
@ -438,7 +441,7 @@ class OmemoManager {
|
|||||||
final error = keyAndHmac.get<OmemoError>();
|
final error = keyAndHmac.get<OmemoError>();
|
||||||
_log.warning('Failed to decrypt symmetric key: $error');
|
_log.warning('Failed to decrypt symmetric key: $error');
|
||||||
|
|
||||||
return DecryptionResult(null, error);
|
return DecryptionResult(null, null, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<OmemoError, String?> result;
|
Result<OmemoError, String?> result;
|
||||||
@ -452,6 +455,7 @@ class OmemoManager {
|
|||||||
_log.warning('Decrypting payload failed: $error');
|
_log.warning('Decrypting payload failed: $error');
|
||||||
|
|
||||||
return DecryptionResult(
|
return DecryptionResult(
|
||||||
|
null,
|
||||||
null,
|
null,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
@ -503,6 +507,7 @@ class OmemoManager {
|
|||||||
|
|
||||||
return DecryptionResult(
|
return DecryptionResult(
|
||||||
result.get<String?>(),
|
result.get<String?>(),
|
||||||
|
kexMessage.pkId,
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -517,6 +522,7 @@ class OmemoManager {
|
|||||||
await _sendOmemoHeartbeat(stanza.bareSenderJid);
|
await _sendOmemoHeartbeat(stanza.bareSenderJid);
|
||||||
|
|
||||||
return DecryptionResult(
|
return DecryptionResult(
|
||||||
|
null,
|
||||||
null,
|
null,
|
||||||
NoSessionWithDeviceError(),
|
NoSessionWithDeviceError(),
|
||||||
);
|
);
|
||||||
@ -540,7 +546,7 @@ class OmemoManager {
|
|||||||
if (keyAndHmac.isType<OmemoError>()) {
|
if (keyAndHmac.isType<OmemoError>()) {
|
||||||
final error = keyAndHmac.get<OmemoError>();
|
final error = keyAndHmac.get<OmemoError>();
|
||||||
_log.warning('Failed to decrypt symmetric key: $error');
|
_log.warning('Failed to decrypt symmetric key: $error');
|
||||||
return DecryptionResult(null, error);
|
return DecryptionResult(null, null, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<OmemoError, String?> result;
|
Result<OmemoError, String?> result;
|
||||||
@ -553,6 +559,7 @@ class OmemoManager {
|
|||||||
final error = result.get<OmemoError>();
|
final error = result.get<OmemoError>();
|
||||||
_log.warning('Failed to decrypt message: $error');
|
_log.warning('Failed to decrypt message: $error');
|
||||||
return DecryptionResult(
|
return DecryptionResult(
|
||||||
|
null,
|
||||||
null,
|
null,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
@ -586,6 +593,7 @@ class OmemoManager {
|
|||||||
return DecryptionResult(
|
return DecryptionResult(
|
||||||
result.get<String?>(),
|
result.get<String?>(),
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -958,7 +966,33 @@ class OmemoManager {
|
|||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
OmemoDoubleRatchet? getRatchet(RatchetMapKey key) => _ratchetMap[key];
|
OmemoDoubleRatchet? getRatchet(RatchetMapKey key) => _ratchetMap[key];
|
||||||
|
|
||||||
/// Trust management functions
|
/// Replaces the OPK with id [opkId] and commits the new device to storage. This
|
||||||
|
/// function should not be called. It's only useful for rotating OPKs after message
|
||||||
|
/// catch-up, because in that case the OPKs are not rotated automatically.
|
||||||
|
Future<void> replaceOnetimePrekey(int opkId) async {
|
||||||
|
await _deviceLock.synchronized(() async {
|
||||||
|
// Replace OPK
|
||||||
|
await _device.replaceOnetimePrekey(opkId);
|
||||||
|
|
||||||
|
// Commit the device
|
||||||
|
await commitDevice(_device);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces the SPK of our device and commits it to storage.
|
||||||
|
Future<void> replaceSignedPrekey() async {
|
||||||
|
await _deviceLock.synchronized(() async {
|
||||||
|
// Replace SPK
|
||||||
|
await _device.replaceSignedPrekey();
|
||||||
|
|
||||||
|
// Commit the device
|
||||||
|
await commitDevice(_device);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Acquire a lock for interacting with the trust manager for modifying the trust
|
||||||
|
/// state of [jid]. [callback] is called from within the critical section with the
|
||||||
|
/// trust manager as its parameter.
|
||||||
Future<void> withTrustManager(
|
Future<void> withTrustManager(
|
||||||
String jid,
|
String jid,
|
||||||
Future<void> Function(TrustManager) callback,
|
Future<void> Function(TrustManager) callback,
|
||||||
|
Loading…
Reference in New Issue
Block a user