Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ratchet on a single frame until ratchetWindowSize #544

Merged
merged 1 commit into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/src/e2ee/key_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ abstract class KeyProvider {
}

class BaseKeyProvider implements KeyProvider {
final Map<String, int> _latestSetIndex = {};
final Map<String, Map<int, Uint8List>> _keys = {};

int getLatestIndex(String participantId) {
return _keys[participantId]?.keys.last ?? 0;
return _latestSetIndex[participantId] ?? 0;
}

Uint8List? _sharedKey;
Expand Down Expand Up @@ -152,6 +153,7 @@ class BaseKeyProvider implements KeyProvider {
logger.info(
'_setKey for ${keyInfo.participantId}, idx: ${keyInfo.keyIndex}, key: ${base64Encode(keyInfo.key)}');
_keys[keyInfo.participantId]![keyInfo.keyIndex] = keyInfo.key;
_latestSetIndex[keyInfo.participantId] = keyInfo.keyIndex;
await _keyProvider.setKey(
participantId: keyInfo.participantId,
index: keyInfo.keyIndex,
Expand Down
4 changes: 2 additions & 2 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,10 @@ packages:
dependency: "direct main"
description:
name: flutter_webrtc
sha256: fd5f115a08dcdc00b988bea3003c956f1b60a78a61d899cbddfb44f5d0e44d4a
sha256: a09adf01e8b760a9ca6418323786f51417fb75986f210513e83d4753686795f0
url: "https://pub.dev"
source: hosted
version: "0.10.8"
version: "0.11.1"
glob:
dependency: transitive
description:
Expand Down
51 changes: 29 additions & 22 deletions web/e2ee.cryptor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -314,15 +314,12 @@ class FrameCryptor {
) async {
var buffer = frame.data.asUint8List();

if (!enabled ||
// skip for encryption for empty dtx frames
buffer.isEmpty) {
if (keyOptions.discardFrameWhenCryptorNotReady) {
return;
}
if (buffer.isEmpty) {
// skip for encryption for empty dtx frames
controller.enqueue(frame);
return;
}
if (!enabled && keyOptions.discardFrameWhenCryptorNotReady) return;

var secretKey = keyHandler.getKeySet(currentKeyIndex)?.encryptionKey;
var keyIndex = currentKeyIndex;
Expand Down Expand Up @@ -381,7 +378,8 @@ class FrameCryptor {
controller.enqueue(frame);

if (lastError != CryptorError.kOk) {
logger.info('$participantIdentity trackId: $trackId kind: $kind cryptorState changed from $lastError to kOk');
logger.info(
'$participantIdentity trackId: $trackId kind: $kind cryptorState changed from $lastError to kOk');
lastError = CryptorError.kOk;
postMessage({
'type': 'cryptorState',
Expand Down Expand Up @@ -425,15 +423,14 @@ class FrameCryptor {
KeySet? initialKeySet;
var initialKeyIndex = currentKeyIndex;

if (!enabled ||
// skip for encryption for empty dtx frames
buffer.isEmpty) {
sifGuard.recordUserFrame();
if (keyOptions.discardFrameWhenCryptorNotReady) return;
if (buffer.isEmpty) {
// skip for encryption for empty dtx frames
logger.fine('enqueing empty frame');
sifGuard.recordUserFrame();
controller.enqueue(frame);
return;
}
if (!enabled && keyOptions.discardFrameWhenCryptorNotReady) return;

if (keyOptions.uncryptedMagicBytes != null) {
var magicBytes = keyOptions.uncryptedMagicBytes!;
Expand Down Expand Up @@ -491,7 +488,8 @@ class FrameCryptor {
/// to throw missingkeys faster lower your failureTolerance
if (initialKeySet == null || !keyHandler.hasValidKey) {
if (lastError != CryptorError.kMissingKey) {
logger.info('$participantIdentity trackId: $trackId kind: $kind cryptorState changed from $lastError to kMissingKey');
logger.info(
'$participantIdentity trackId: $trackId kind: $kind cryptorState changed from $lastError to kMissingKey');
lastError = CryptorError.kMissingKey;
postMessage({
'type': 'cryptorState',
Expand All @@ -503,7 +501,6 @@ class FrameCryptor {
'error': 'Missing key for track $trackId'
});
}
// controller.enqueue(frame);
return;
}
var currentkeySet = initialKeySet;
Expand All @@ -528,7 +525,8 @@ class FrameCryptor {
}

if (currentkeySet != initialKeySet) {
logger.fine('ratchetKey: decryption ok, newState: kKeyRatcheted');
logger.fine(
'ratchetKey: $participantIdentity trackId: $trackId kind: $kind decryption ok, newState: kKeyRatcheted');
await keyHandler.setKeySetFromMaterial(
currentkeySet, initialKeyIndex);
}
Expand All @@ -539,9 +537,10 @@ class FrameCryptor {
logger.finer(
'KeyRatcheted: ssrc ${metaData.synchronizationSource} timestamp ${frame.timestamp} ratchetCount $ratchetCount participantId: $participantIdentity');
logger.finer(
'ratchetKey: lastError != CryptorError.kKeyRatcheted, reset state to kKeyRatcheted');
'ratchetKey: $participantIdentity trackId: $trackId kind: $kind lastError != CryptorError.kKeyRatcheted, reset state to kKeyRatcheted');

logger.info('$participantIdentity trackId: $trackId kind: $kind cryptorState changed from $lastError to kKeyRatcheted');
logger.info(
'$participantIdentity trackId: $trackId kind: $kind cryptorState changed from $lastError to kKeyRatcheted');
lastError = CryptorError.kKeyRatcheted;
postMessage({
'type': 'cryptorState',
Expand All @@ -556,9 +555,10 @@ class FrameCryptor {
}

Future<void> ratchedKeyInternal() async {
if (ratchetCount >= keyOptions.ratchetWindowSize ||
if (ratchetCount > keyOptions.ratchetWindowSize ||
keyOptions.ratchetWindowSize <= 0) {
throw Exception('[ratchedKeyInternal] cannot ratchet anymore');
throw Exception(
'[ratchedKeyInternal] cannot ratchet anymore $participantIdentity trackId: $trackId kind: $kind');
}

var newKeyBuffer = crypto.jsArrayBufferFrom(await keyHandler.ratchet(
Expand All @@ -568,7 +568,13 @@ class FrameCryptor {
currentkeySet =
await keyHandler.deriveKeys(newMaterial, keyOptions.ratchetSalt);
ratchetCount++;
await decryptFrameInternal();
try {
/// keep trying to ratchet until ratchetWindowSize
await decryptFrameInternal();
} catch (e) {
lastError = CryptorError.kInternalError;
await ratchedKeyInternal();
}
}

try {
Expand All @@ -583,7 +589,7 @@ class FrameCryptor {

if (decrypted == null) {
throw Exception(
'[decodeFunction] decryption failed even after ratchting');
'[decodeFunction] decryption failed even after ratchting $participantIdentity trackId: $trackId kind: $kind');
}

// we can now be sure that decryption was a success
Expand All @@ -600,7 +606,8 @@ class FrameCryptor {
controller.enqueue(frame);

if (lastError != CryptorError.kOk) {
logger.info('$participantIdentity trackId: $trackId kind: $kind cryptorState changed from $lastError to kOk');
logger.info(
'$participantIdentity trackId: $trackId kind: $kind cryptorState changed from $lastError to kOk');
lastError = CryptorError.kOk;
postMessage({
'type': 'cryptorState',
Expand Down
Loading