diff --git a/.github/workflows/app.yml b/.github/workflows/app.yml
index 4322566d..eb3ff6dc 100644
--- a/.github/workflows/app.yml
+++ b/.github/workflows/app.yml
@@ -18,6 +18,11 @@ jobs:
- uses: dart-lang/setup-dart@a57a6c04cf7d4840e88432aad6281d1e125f0d46
with:
sdk: ${{ env.dart_version }}
+ - uses: famedly/backend-build-workflows/.github/actions/rust-prepare@main
+ with:
+ gitlab_user: ${{ secrets.GITLAB_USER }}
+ gitlab_pass: ${{ secrets.GITLAB_PASS }}
+ gitlab_ssh: ${{ secrets.CI_SSH_PRIVATE_KEY}}
- name: Run tests
run: |
export HOMESERVER_IMPLEMENTATION=${{matrix.homeserver}}
@@ -27,6 +32,7 @@ jobs:
source scripts/integration-create-environment-variables.sh
scripts/integration-prepare-homeserver.sh
scripts/prepare.sh
+ scripts/prepare_vodozemac.sh
scripts/test_driver.sh
coverage_without_olm:
@@ -54,7 +60,7 @@ jobs:
coverage:
#runs-on: arm-ubuntu-latest-16core
runs-on: ubuntu-latest
- timeout-minutes: 5
+ timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- run: cat .github/workflows/versions.env >> $GITHUB_ENV
@@ -62,9 +68,15 @@ jobs:
with:
sdk: ${{ env.dart_version }}
#architecture: "arm64"
+ - uses: famedly/backend-build-workflows/.github/actions/rust-prepare@main
+ with:
+ gitlab_user: ${{ secrets.GITLAB_USER }}
+ gitlab_pass: ${{ secrets.GITLAB_PASS }}
+ gitlab_ssh: ${{ secrets.CI_SSH_PRIVATE_KEY}}
- name: Run tests
run: |
sudo apt-get update && sudo apt-get install --no-install-recommends --no-install-suggests -y lcov libsqlite3-0 libsqlite3-dev libolm3 libssl3
+ ./scripts/prepare_vodozemac.sh
./scripts/test.sh
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
diff --git a/.gitignore b/.gitignore
index 68373a03..5419541b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ coverage/
coverage_badge.svg
coverage.xml
TEST-report.*
+rust
# IntelliJ related
*.iml
diff --git a/lib/encryption/cross_signing.dart b/lib/encryption/cross_signing.dart
index 70c89a6d..f725fff2 100644
--- a/lib/encryption/cross_signing.dart
+++ b/lib/encryption/cross_signing.dart
@@ -16,9 +16,10 @@
* along with this program. If not, see .
*/
+import 'dart:convert';
import 'dart:typed_data';
-import 'package:olm/olm.dart' as olm;
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption/encryption.dart';
import 'package:matrix/encryption/ssss.dart';
@@ -31,26 +32,22 @@ class CrossSigning {
CrossSigning(this.encryption) {
encryption.ssss.setValidator(EventTypes.CrossSigningSelfSigning,
(String secret) async {
- final keyObj = olm.PkSigning();
try {
- return keyObj.init_with_seed(base64decodeUnpadded(secret)) ==
+ final keyObj = vod.PkSigning.fromSecretKey(secret);
+ return keyObj.publicKey.toBase64() ==
client.userDeviceKeys[client.userID]!.selfSigningKey!.ed25519Key;
} catch (_) {
return false;
- } finally {
- keyObj.free();
}
});
encryption.ssss.setValidator(EventTypes.CrossSigningUserSigning,
(String secret) async {
- final keyObj = olm.PkSigning();
try {
- return keyObj.init_with_seed(base64decodeUnpadded(secret)) ==
+ final keyObj = vod.PkSigning.fromSecretKey(secret);
+ return keyObj.publicKey.toBase64() ==
client.userDeviceKeys[client.userID]!.userSigningKey!.ed25519Key;
} catch (_) {
return false;
- } finally {
- keyObj.free();
}
});
}
@@ -92,14 +89,13 @@ class CrossSigning {
final masterPrivateKey = base64decodeUnpadded(
await handle.getStored(EventTypes.CrossSigningMasterKey),
);
- final keyObj = olm.PkSigning();
String? masterPubkey;
try {
- masterPubkey = keyObj.init_with_seed(masterPrivateKey);
+ masterPubkey = vod.PkSigning.fromSecretKey(base64Encode(masterPrivateKey))
+ .publicKey
+ .toBase64();
} catch (e) {
masterPubkey = null;
- } finally {
- keyObj.free();
}
final userDeviceKeys =
client.userDeviceKeys[client.userID]?.deviceKeys[client.deviceID];
@@ -210,12 +206,7 @@ class CrossSigning {
}
String _sign(String canonicalJson, Uint8List key) {
- final keyObj = olm.PkSigning();
- try {
- keyObj.init_with_seed(key);
- return keyObj.sign(canonicalJson);
- } finally {
- keyObj.free();
- }
+ final keyObj = vod.PkSigning.fromSecretKey(base64Encode(key));
+ return keyObj.sign(canonicalJson).toBase64();
}
}
diff --git a/lib/encryption/key_manager.dart b/lib/encryption/key_manager.dart
index 77fe1679..ee7ef210 100644
--- a/lib/encryption/key_manager.dart
+++ b/lib/encryption/key_manager.dart
@@ -21,6 +21,7 @@ import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption/encryption.dart';
import 'package:matrix/encryption/utils/base64_unpadded.dart';
@@ -45,19 +46,18 @@ class KeyManager {
KeyManager(this.encryption) {
encryption.ssss.setValidator(megolmKey, (String secret) async {
- final keyObj = olm.PkDecryption();
try {
+ final keyObj = vod.PkDecryption.fromSecretKey(
+ vod.Curve25519PublicKey.fromBase64(secret),
+ );
final info = await getRoomKeysBackupInfo(false);
if (info.algorithm !=
BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2) {
return false;
}
- return keyObj.init_with_private_key(base64decodeUnpadded(secret)) ==
- info.authData['public_key'];
+ return keyObj.publicKey == info.authData['public_key'];
} catch (_) {
return false;
- } finally {
- keyObj.free();
}
});
encryption.ssss.setCacheCallback(megolmKey, (String secret) {
@@ -669,54 +669,57 @@ class KeyManager {
}
final privateKey =
base64decodeUnpadded((await encryption.ssss.getCached(megolmKey))!);
- final decryption = olm.PkDecryption();
final info = await getRoomKeysBackupInfo();
String backupPubKey;
- try {
- backupPubKey = decryption.init_with_private_key(privateKey);
- if (info.algorithm != BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2 ||
- info.authData['public_key'] != backupPubKey) {
- return;
- }
- for (final roomEntry in keys.rooms.entries) {
- final roomId = roomEntry.key;
- for (final sessionEntry in roomEntry.value.sessions.entries) {
- final sessionId = sessionEntry.key;
- final session = sessionEntry.value;
- final sessionData = session.sessionData;
- Map? decrypted;
- try {
- decrypted = json.decode(
- decryption.decrypt(
- sessionData['ephemeral'] as String,
- sessionData['mac'] as String,
- sessionData['ciphertext'] as String,
+ final decryption = vod.PkDecryption.fromSecretKey(
+ vod.Curve25519PublicKey.fromBytes(privateKey),
+ );
+ backupPubKey = decryption.publicKey;
+
+ if (info.algorithm != BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2 ||
+ info.authData['public_key'] != backupPubKey) {
+ return;
+ }
+ for (final roomEntry in keys.rooms.entries) {
+ final roomId = roomEntry.key;
+ for (final sessionEntry in roomEntry.value.sessions.entries) {
+ final sessionId = sessionEntry.key;
+ final session = sessionEntry.value;
+ final sessionData = session.sessionData;
+ Map? decrypted;
+ try {
+ decrypted = json.decode(
+ decryption.decrypt(
+ vod.PkMessage(
+ base64decodeUnpadded(sessionData['ciphertext'] as String),
+ base64decodeUnpadded(sessionData['mac'] as String),
+ vod.Curve25519PublicKey.fromBase64(
+ sessionData['ephemeral'] as String,
+ ),
),
- );
- } catch (e, s) {
- Logs().e('[LibOlm] Error decrypting room key', e, s);
- }
- final senderKey = decrypted?.tryGet('sender_key');
- if (decrypted != null && senderKey != null) {
- decrypted['session_id'] = sessionId;
- decrypted['room_id'] = roomId;
- await setInboundGroupSession(
- roomId,
- sessionId,
- senderKey,
- decrypted,
- forwarded: true,
- senderClaimedKeys:
- decrypted.tryGetMap('sender_claimed_keys') ??
- {},
- uploaded: true,
- );
- }
+ ),
+ );
+ } catch (e, s) {
+ Logs().e('[LibOlm] Error decrypting room key', e, s);
+ }
+ final senderKey = decrypted?.tryGet('sender_key');
+ if (decrypted != null && senderKey != null) {
+ decrypted['session_id'] = sessionId;
+ decrypted['room_id'] = roomId;
+ await setInboundGroupSession(
+ roomId,
+ sessionId,
+ senderKey,
+ decrypted,
+ forwarded: true,
+ senderClaimedKeys:
+ decrypted.tryGetMap('sender_claimed_keys') ??
+ {},
+ uploaded: true,
+ );
}
}
- } finally {
- decryption.free();
}
}
@@ -875,57 +878,56 @@ class KeyManager {
final privateKey =
base64decodeUnpadded((await encryption.ssss.getCached(megolmKey))!);
// decryption is needed to calculate the public key and thus see if the claimed information is in fact valid
- final decryption = olm.PkDecryption();
+
final info = await getRoomKeysBackupInfo(false);
String backupPubKey;
- try {
- backupPubKey = decryption.init_with_private_key(privateKey);
- if (info.algorithm !=
- BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2 ||
- info.authData['public_key'] != backupPubKey) {
- decryption.free();
- return;
- }
- final args = GenerateUploadKeysArgs(
- pubkey: backupPubKey,
- dbSessions: [],
- userId: userID,
+ final decryption = vod.PkDecryption.fromSecretKey(
+ vod.Curve25519PublicKey.fromBytes(privateKey),
+ );
+ backupPubKey = decryption.publicKey;
+
+ if (info.algorithm !=
+ BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2 ||
+ info.authData['public_key'] != backupPubKey) {
+ return;
+ }
+ final args = GenerateUploadKeysArgs(
+ pubkey: backupPubKey,
+ dbSessions: [],
+ userId: userID,
+ );
+ // we need to calculate verified beforehand, as else we pass a closure to an isolate
+ // with 500 keys they do, however, noticably block the UI, which is why we give brief async suspentions in here
+ // so that the event loop can progress
+ var i = 0;
+ for (final dbSession in dbSessions) {
+ final device =
+ client.getUserDeviceKeysByCurve25519Key(dbSession.senderKey);
+ args.dbSessions.add(
+ DbInboundGroupSessionBundle(
+ dbSession: dbSession,
+ verified: device?.verified ?? false,
+ ),
);
- // we need to calculate verified beforehand, as else we pass a closure to an isolate
- // with 500 keys they do, however, noticably block the UI, which is why we give brief async suspentions in here
- // so that the event loop can progress
- var i = 0;
- for (final dbSession in dbSessions) {
- final device =
- client.getUserDeviceKeysByCurve25519Key(dbSession.senderKey);
- args.dbSessions.add(
- DbInboundGroupSessionBundle(
- dbSession: dbSession,
- verified: device?.verified ?? false,
- ),
- );
- i++;
- if (i > 10) {
- await Future.delayed(Duration(milliseconds: 1));
- i = 0;
- }
+ i++;
+ if (i > 10) {
+ await Future.delayed(Duration(milliseconds: 1));
+ i = 0;
}
- final roomKeys =
- await client.nativeImplementations.generateUploadKeys(args);
- Logs().i('[Key Manager] Uploading ${dbSessions.length} room keys...');
- // upload the payload...
- await client.putRoomKeys(info.version, roomKeys);
- // and now finally mark all the keys as uploaded
- // no need to optimze this, as we only run it so seldomly and almost never with many keys at once
- for (final dbSession in dbSessions) {
- await database.markInboundGroupSessionAsUploaded(
- dbSession.roomId,
- dbSession.sessionId,
- );
- }
- } finally {
- decryption.free();
+ }
+ final roomKeys =
+ await client.nativeImplementations.generateUploadKeys(args);
+ Logs().i('[Key Manager] Uploading ${dbSessions.length} room keys...');
+ // upload the payload...
+ await client.putRoomKeys(info.version, roomKeys);
+ // and now finally mark all the keys as uploaded
+ // no need to optimze this, as we only run it so seldomly and almost never with many keys at once
+ for (final dbSession in dbSessions) {
+ await database.markInboundGroupSessionAsUploaded(
+ dbSession.roomId,
+ dbSession.sessionId,
+ );
}
} catch (e, s) {
Logs().e('[Key Manager] Error uploading room keys', e, s);
@@ -1247,9 +1249,10 @@ class RoomKeyRequest extends ToDeviceEvent {
/// you would likely want to use [NativeImplementations] and
/// [Client.nativeImplementations] instead
RoomKeys generateUploadKeysImplementation(GenerateUploadKeysArgs args) {
- final enc = olm.PkEncryption();
try {
- enc.set_recipient_key(args.pubkey);
+ final enc = vod.PkEncryption.fromPublicKey(
+ vod.Curve25519PublicKey.fromBase64(args.pubkey),
+ );
// first we generate the payload to upload all the session keys in this chunk
final roomKeys = RoomKeys(rooms: {});
for (final dbSession in args.dbSessions) {
@@ -1279,17 +1282,15 @@ RoomKeys generateUploadKeysImplementation(GenerateUploadKeysArgs args) {
forwardedCount: sess.forwardingCurve25519KeyChain.length,
isVerified: dbSession.verified, //device?.verified ?? false,
sessionData: {
- 'ephemeral': encrypted.ephemeral,
- 'ciphertext': encrypted.ciphertext,
- 'mac': encrypted.mac,
+ 'ephemeral': encrypted.ephemeralKey.toBase64(),
+ 'ciphertext': base64Encode(encrypted.ciphertext),
+ 'mac': base64Encode(encrypted.mac),
},
);
}
- enc.free();
return roomKeys;
} catch (e, s) {
Logs().e('[Key Manager] Error generating payload', e, s);
- enc.free();
rethrow;
}
}
diff --git a/lib/encryption/utils/bootstrap.dart b/lib/encryption/utils/bootstrap.dart
index 1746f28e..1645115f 100644
--- a/lib/encryption/utils/bootstrap.dart
+++ b/lib/encryption/utils/bootstrap.dart
@@ -20,12 +20,11 @@ import 'dart:convert';
import 'dart:typed_data';
import 'package:canonical_json/canonical_json.dart';
-import 'package:olm/olm.dart' as olm;
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption/encryption.dart';
import 'package:matrix/encryption/key_manager.dart';
import 'package:matrix/encryption/ssss.dart';
-import 'package:matrix/encryption/utils/base64_unpadded.dart';
import 'package:matrix/matrix.dart';
enum BootstrapState {
@@ -371,106 +370,82 @@ class Bootstrap {
}
final userID = client.userID!;
try {
- Uint8List masterSigningKey;
+ String masterSigningKey;
final secretsToStore = {};
MatrixCrossSigningKey? masterKey;
MatrixCrossSigningKey? selfSigningKey;
MatrixCrossSigningKey? userSigningKey;
String? masterPub;
if (setupMasterKey) {
- final master = olm.PkSigning();
- try {
- masterSigningKey = master.generate_seed();
- masterPub = master.init_with_seed(masterSigningKey);
- final json = {
- 'user_id': userID,
- 'usage': ['master'],
- 'keys': {
- 'ed25519:$masterPub': masterPub,
- },
- };
- masterKey = MatrixCrossSigningKey.fromJson(json);
- secretsToStore[EventTypes.CrossSigningMasterKey] =
- base64.encode(masterSigningKey);
- } finally {
- master.free();
- }
+ final master = vod.PkSigning();
+ masterSigningKey = master.secretKey;
+ masterPub = master.publicKey.toBase64();
+ final json = {
+ 'user_id': userID,
+ 'usage': ['master'],
+ 'keys': {
+ 'ed25519:$masterPub': masterPub,
+ },
+ };
+ masterKey = MatrixCrossSigningKey.fromJson(json);
+ secretsToStore[EventTypes.CrossSigningMasterKey] = masterSigningKey;
} else {
Logs().v('Get stored key...');
- masterSigningKey = base64decodeUnpadded(
- await newSsssKey?.getStored(EventTypes.CrossSigningMasterKey) ?? '',
- );
+ masterSigningKey =
+ await newSsssKey?.getStored(EventTypes.CrossSigningMasterKey) ?? '';
if (masterSigningKey.isEmpty) {
// no master signing key :(
throw BootstrapBadStateException('No master key');
}
- final master = olm.PkSigning();
- try {
- masterPub = master.init_with_seed(masterSigningKey);
- } finally {
- master.free();
- }
+ final master = vod.PkSigning.fromSecretKey(masterSigningKey);
+ masterPub = master.publicKey.toBase64();
}
String? sign(Map object) {
- final keyObj = olm.PkSigning();
- try {
- keyObj.init_with_seed(masterSigningKey);
- return keyObj
- .sign(String.fromCharCodes(canonicalJson.encode(object)));
- } finally {
- keyObj.free();
- }
+ final keyObj = vod.PkSigning.fromSecretKey(masterSigningKey);
+ return keyObj
+ .sign(String.fromCharCodes(canonicalJson.encode(object)))
+ .toBase64();
}
if (setupSelfSigningKey) {
- final selfSigning = olm.PkSigning();
- try {
- final selfSigningPriv = selfSigning.generate_seed();
- final selfSigningPub = selfSigning.init_with_seed(selfSigningPriv);
- final json = {
- 'user_id': userID,
- 'usage': ['self_signing'],
- 'keys': {
- 'ed25519:$selfSigningPub': selfSigningPub,
- },
- };
- final signature = sign(json);
- json['signatures'] = {
- userID: {
- 'ed25519:$masterPub': signature,
- },
- };
- selfSigningKey = MatrixCrossSigningKey.fromJson(json);
- secretsToStore[EventTypes.CrossSigningSelfSigning] =
- base64.encode(selfSigningPriv);
- } finally {
- selfSigning.free();
- }
+ final selfSigning = vod.PkSigning();
+ final selfSigningPriv = selfSigning.secretKey;
+ final selfSigningPub = selfSigning.publicKey.toBase64();
+ final json = {
+ 'user_id': userID,
+ 'usage': ['self_signing'],
+ 'keys': {
+ 'ed25519:$selfSigningPub': selfSigningPub,
+ },
+ };
+ final signature = sign(json);
+ json['signatures'] = {
+ userID: {
+ 'ed25519:$masterPub': signature,
+ },
+ };
+ selfSigningKey = MatrixCrossSigningKey.fromJson(json);
+ secretsToStore[EventTypes.CrossSigningSelfSigning] = selfSigningPriv;
}
if (setupUserSigningKey) {
- final userSigning = olm.PkSigning();
- try {
- final userSigningPriv = userSigning.generate_seed();
- final userSigningPub = userSigning.init_with_seed(userSigningPriv);
- final json = {
- 'user_id': userID,
- 'usage': ['user_signing'],
- 'keys': {
- 'ed25519:$userSigningPub': userSigningPub,
- },
- };
- final signature = sign(json);
- json['signatures'] = {
- userID: {
- 'ed25519:$masterPub': signature,
- },
- };
- userSigningKey = MatrixCrossSigningKey.fromJson(json);
- secretsToStore[EventTypes.CrossSigningUserSigning] =
- base64.encode(userSigningPriv);
- } finally {
- userSigning.free();
- }
+ final userSigning = vod.PkSigning();
+ final userSigningPriv = userSigning.secretKey;
+ final userSigningPub = userSigning.publicKey.toBase64();
+ final json = {
+ 'user_id': userID,
+ 'usage': ['user_signing'],
+ 'keys': {
+ 'ed25519:$userSigningPub': userSigningPub,
+ },
+ };
+ final signature = sign(json);
+ json['signatures'] = {
+ userID: {
+ 'ed25519:$masterPub': signature,
+ },
+ };
+ userSigningKey = MatrixCrossSigningKey.fromJson(json);
+ secretsToStore[EventTypes.CrossSigningUserSigning] = userSigningPriv;
}
// upload the keys!
state = BootstrapState.loading;
@@ -561,15 +536,13 @@ class Bootstrap {
return;
}
try {
- final keyObj = olm.PkDecryption();
+ final keyObj = vod.PkDecryption();
String pubKey;
Uint8List privKey;
- try {
- pubKey = keyObj.generate_key();
- privKey = keyObj.get_private_key();
- } finally {
- keyObj.free();
- }
+
+ pubKey = keyObj.publicKey;
+ privKey = keyObj.privateKey;
+
Logs().v('Create the new backup version...');
await client.postRoomKeysVersion(
BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2,
diff --git a/lib/encryption/utils/json_signature_check_extension.dart b/lib/encryption/utils/json_signature_check_extension.dart
index 7c1f4f6c..e691d415 100644
--- a/lib/encryption/utils/json_signature_check_extension.dart
+++ b/lib/encryption/utils/json_signature_check_extension.dart
@@ -17,7 +17,7 @@
*/
import 'package:canonical_json/canonical_json.dart';
-import 'package:olm/olm.dart' as olm;
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
@@ -37,15 +37,15 @@ extension JsonSignatureCheckExtension on Map {
final canonical = canonicalJson.encode(this);
final message = String.fromCharCodes(canonical);
var isValid = false;
- final olmutil = olm.Utility();
try {
- olmutil.ed25519_verify(key, message, signature);
+ vod.Ed25519PublicKey.fromBase64(key).verify(
+ message: message,
+ signature: vod.Ed25519Signature.fromBase64(signature),
+ );
isValid = true;
} catch (e, s) {
isValid = false;
Logs().w('[LibOlm] Signature check failed', e, s);
- } finally {
- olmutil.free();
}
return isValid;
}
diff --git a/lib/encryption/utils/key_verification.dart b/lib/encryption/utils/key_verification.dart
index 007c00b2..467b0cde 100644
--- a/lib/encryption/utils/key_verification.dart
+++ b/lib/encryption/utils/key_verification.dart
@@ -21,8 +21,9 @@ import 'dart:convert';
import 'dart:typed_data';
import 'package:canonical_json/canonical_json.dart';
-import 'package:olm/olm.dart' as olm;
+import 'package:crypto/crypto.dart' as crypto;
import 'package:typed_data/typed_data.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption/encryption.dart';
import 'package:matrix/encryption/utils/base64_unpadded.dart';
@@ -1258,12 +1259,8 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
String? commitment;
late String theirPublicKey;
Map? macPayload;
- olm.SAS? sas;
-
- @override
- void dispose() {
- sas?.free();
- }
+ vod.Sas? sas;
+ vod.EstablishedSas? establishedSas;
List get knownAuthentificationTypes {
final types = [];
@@ -1322,7 +1319,7 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
await _sendKey();
} else {
// we already sent our key, time to verify the commitment being valid
- if (!_validateCommitment()) {
+ if (await _validateCommitment() == false) {
await request.cancel('m.mismatched_commitment');
return;
}
@@ -1415,8 +1412,8 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
}
Future _sendAccept() async {
- final sas = this.sas = olm.SAS();
- commitment = _makeCommitment(sas.get_pubkey(), startCanonicalJson);
+ final sas = this.sas = vod.Sas();
+ commitment = await _makeCommitment(sas.publicKey, startCanonicalJson);
await request.send(EventTypes.KeyVerificationAccept, {
'method': type,
'key_agreement_protocol': keyAgreementProtocol,
@@ -1451,31 +1448,31 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
}
authenticationTypes = possibleAuthenticationTypes;
commitment = payload['commitment'];
- sas = olm.SAS();
+ sas = vod.Sas();
return true;
}
Future _sendKey() async {
await request.send('m.key.verification.key', {
- 'key': sas!.get_pubkey(),
+ 'key': sas!.publicKey,
});
}
void _handleKey(Map payload) {
theirPublicKey = payload['key'];
- sas!.set_their_key(payload['key']);
+ establishedSas = sas!.establishSasSecret(payload['key']);
}
- bool _validateCommitment() {
- final checkCommitment = _makeCommitment(theirPublicKey, startCanonicalJson);
+ Future _validateCommitment() async {
+ final checkCommitment =
+ await _makeCommitment(theirPublicKey, startCanonicalJson);
return commitment == checkCommitment;
}
Uint8List makeSas(int bytes) {
var sasInfo = '';
if (keyAgreementProtocol == 'curve25519-hkdf-sha256') {
- final ourInfo =
- '${client.userID}|${client.deviceID}|${sas!.get_pubkey()}|';
+ final ourInfo = '${client.userID}|${client.deviceID}|${sas!.publicKey}|';
final theirInfo =
'${request.userId}|${request.deviceId}|$theirPublicKey|';
sasInfo =
@@ -1488,7 +1485,7 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
} else {
throw Exception('Unknown key agreement protocol');
}
- return sas!.generate_bytes(sasInfo, bytes);
+ return establishedSas!.generateBytes(sasInfo, bytes);
}
Future _sendMac() async {
@@ -1554,21 +1551,20 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
});
}
- String _makeCommitment(String pubKey, String canonicalJson) {
+ Future _makeCommitment(String pubKey, String canonicalJson) async {
if (hash == 'sha256') {
- final olmutil = olm.Utility();
- final ret = olmutil.sha256(pubKey + canonicalJson);
- olmutil.free();
- return ret;
+ final bytes = utf8.encode(pubKey + canonicalJson);
+ final digest = crypto.sha256.convert(bytes);
+ return base64.encode(digest.bytes);
}
throw Exception('Unknown hash method');
}
String _calculateMac(String input, String info) {
if (messageAuthenticationCode == 'hkdf-hmac-sha256.v2') {
- return sas!.calculate_mac_fixed_base64(input, info);
+ return establishedSas!.calculateMac(input, info);
} else if (messageAuthenticationCode == 'hkdf-hmac-sha256') {
- return sas!.calculate_mac(input, info);
+ return establishedSas!.calculateMacDeprecated(input, info);
} else {
throw Exception('Unknown message authentification code');
}
diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart
index a2e81cc5..073736ae 100644
--- a/lib/src/utils/device_keys_list.dart
+++ b/lib/src/utils/device_keys_list.dart
@@ -20,7 +20,7 @@ import 'dart:convert';
import 'package:canonical_json/canonical_json.dart';
import 'package:collection/collection.dart' show IterableExtension;
-import 'package:olm/olm.dart' as olm;
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption.dart';
import 'package:matrix/matrix.dart';
@@ -240,24 +240,17 @@ abstract class SignableKey extends MatrixSignableKey {
String signature, {
bool isSignatureWithoutLibolmValid = false,
}) {
- olm.Utility olmutil;
- try {
- olmutil = olm.Utility();
- } catch (e) {
- // if no libolm is present we land in this catch block, and return the default
- // set if no libolm is there. Some signatures should be assumed-valid while others
- // should be assumed-invalid
- return isSignatureWithoutLibolmValid;
- }
var valid = false;
try {
- olmutil.ed25519_verify(pubKey, signingContent, signature);
+ vod.Ed25519PublicKey.fromBase64(pubKey).verify(
+ message: signingContent,
+ signature: vod.Ed25519Signature.fromBase64(signature),
+ );
valid = true;
- } catch (_) {
+ } catch (e) {
+ Logs().d('Invalid Ed25519 signature', e);
// bad signature
valid = false;
- } finally {
- olmutil.free();
}
return valid;
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 8f282c70..a1333227 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -31,6 +31,11 @@ dependencies:
sqflite_common: ^2.4.5
sqlite3: ^2.1.0
typed_data: ^1.3.2
+ vodozemac:
+ git:
+ url: https://github.com/famedly/dart-vodozemac.git
+ path: dart
+ ref: main
webrtc_interface: ^1.2.0
dev_dependencies:
diff --git a/scripts/prepare_vodozemac.sh b/scripts/prepare_vodozemac.sh
new file mode 100755
index 00000000..d1b2b725
--- /dev/null
+++ b/scripts/prepare_vodozemac.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+git clone https://github.com/famedly/dart-vodozemac.git
+mv ./dart-vodozemac/rust ./
+rm -rf dart-vodozemac
+cd ./rust
+cargo build
+cd ..
\ No newline at end of file
diff --git a/test/client_test.dart b/test/client_test.dart
index f88a182d..6662ea1e 100644
--- a/test/client_test.dart
+++ b/test/client_test.dart
@@ -26,6 +26,7 @@ import 'package:collection/collection.dart';
import 'package:olm/olm.dart' as olm;
import 'package:path/path.dart' show join;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
import 'package:matrix/src/utils/client_init_exception.dart';
@@ -67,11 +68,15 @@ void main() {
group('client mem', tags: 'olm', () {
late Client matrix;
- Logs().level = Level.error;
+ Future? vodInit;
/// Check if all Elements get created
-
setUp(() async {
+ vodInit ??= vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
+ await vodInit;
matrix = await getClient();
});
diff --git a/test/device_keys_list_test.dart b/test/device_keys_list_test.dart
index e9e15ffe..b1b57f69 100644
--- a/test/device_keys_list_test.dart
+++ b/test/device_keys_list_test.dart
@@ -19,18 +19,26 @@
import 'dart:convert';
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
import './fake_client.dart';
-void main() {
+void main() async {
/// All Tests related to device keys
group('Device keys', tags: 'olm', () {
Logs().level = Level.error;
late Client client;
+ Future? vodInit;
+
test('setupClient', () async {
+ vodInit ??= vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
+ await vodInit;
client = await getClient();
await client.abortSync();
});
diff --git a/test/encryption/bootstrap_test.dart b/test/encryption/bootstrap_test.dart
index 6b4d1dbc..363e49bb 100644
--- a/test/encryption/bootstrap_test.dart
+++ b/test/encryption/bootstrap_test.dart
@@ -21,6 +21,7 @@ import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption.dart';
import 'package:matrix/matrix.dart';
@@ -35,6 +36,10 @@ void main() {
late String origKeyId;
setUpAll(() async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.get_library_version();
client = await getClient();
@@ -75,20 +80,16 @@ void main() {
// test all the x-signing keys match up
for (final keyType in {'master', 'user_signing', 'self_signing'}) {
- final privateKey = base64
- .decode(await defaultKey.getStored('m.cross_signing.$keyType'));
- final keyObj = olm.PkSigning();
- try {
- final pubKey = keyObj.init_with_seed(privateKey);
- expect(
- pubKey,
- client.userDeviceKeys[client.userID]
- ?.getCrossSigningKey(keyType)
- ?.publicKey,
- );
- } finally {
- keyObj.free();
- }
+ final privateKey =
+ await defaultKey.getStored('m.cross_signing.$keyType');
+ final keyObj = vod.PkSigning.fromSecretKey(privateKey);
+ final pubKey = keyObj.publicKey.toBase64();
+ expect(
+ pubKey,
+ client.userDeviceKeys[client.userID]
+ ?.getCrossSigningKey(keyType)
+ ?.publicKey,
+ );
}
await defaultKey.store('foxes', 'floof');
@@ -133,20 +134,16 @@ void main() {
// test all the x-signing keys match up
for (final keyType in {'master', 'user_signing', 'self_signing'}) {
- final privateKey = base64
- .decode(await defaultKey.getStored('m.cross_signing.$keyType'));
- final keyObj = olm.PkSigning();
- try {
- final pubKey = keyObj.init_with_seed(privateKey);
- expect(
- pubKey,
- client.userDeviceKeys[client.userID]
- ?.getCrossSigningKey(keyType)
- ?.publicKey,
- );
- } finally {
- keyObj.free();
- }
+ final privateKey =
+ await defaultKey.getStored('m.cross_signing.$keyType');
+ final keyObj = vod.PkSigning.fromSecretKey(privateKey);
+ final pubKey = keyObj.publicKey.toBase64();
+ expect(
+ pubKey,
+ client.userDeviceKeys[client.userID]
+ ?.getCrossSigningKey(keyType)
+ ?.publicKey,
+ );
}
expect(await defaultKey.getStored('foxes'), 'floof');
@@ -192,20 +189,16 @@ void main() {
// test all the x-signing keys match up
for (final keyType in {'master', 'user_signing', 'self_signing'}) {
- final privateKey = base64
- .decode(await defaultKey.getStored('m.cross_signing.$keyType'));
- final keyObj = olm.PkSigning();
- try {
- final pubKey = keyObj.init_with_seed(privateKey);
- expect(
- pubKey,
- client.userDeviceKeys[client.userID]
- ?.getCrossSigningKey(keyType)
- ?.publicKey,
- );
- } finally {
- keyObj.free();
- }
+ final privateKey =
+ await defaultKey.getStored('m.cross_signing.$keyType');
+ final keyObj = vod.PkSigning.fromSecretKey(privateKey);
+ final pubKey = keyObj.publicKey.toBase64();
+ expect(
+ pubKey,
+ client.userDeviceKeys[client.userID]
+ ?.getCrossSigningKey(keyType)
+ ?.publicKey,
+ );
}
expect(await defaultKey.getStored('foxes'), 'floof');
diff --git a/test/encryption/cross_signing_test.dart b/test/encryption/cross_signing_test.dart
index a901c0a7..d1c4ec04 100644
--- a/test/encryption/cross_signing_test.dart
+++ b/test/encryption/cross_signing_test.dart
@@ -20,6 +20,7 @@ import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
import '../fake_client.dart';
@@ -31,6 +32,10 @@ void main() {
late Client client;
setUpAll(() async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.get_library_version();
client = await getClient();
diff --git a/test/encryption/encrypt_decrypt_room_message_test.dart b/test/encryption/encrypt_decrypt_room_message_test.dart
index afa44c4e..18226297 100644
--- a/test/encryption/encrypt_decrypt_room_message_test.dart
+++ b/test/encryption/encrypt_decrypt_room_message_test.dart
@@ -18,6 +18,7 @@
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
import '../fake_client.dart';
@@ -33,6 +34,10 @@ void main() {
final now = DateTime.now();
setUpAll(() async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.get_library_version();
client = await getClient();
diff --git a/test/encryption/encrypt_decrypt_to_device_test.dart b/test/encryption/encrypt_decrypt_to_device_test.dart
index 2476617e..649b87c7 100644
--- a/test/encryption/encrypt_decrypt_to_device_test.dart
+++ b/test/encryption/encrypt_decrypt_to_device_test.dart
@@ -18,6 +18,7 @@
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
import '../fake_client.dart';
@@ -41,6 +42,10 @@ void main() async {
late Map payload;
setUpAll(() async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.get_library_version();
client = await getClient();
diff --git a/test/encryption/key_manager_test.dart b/test/encryption/key_manager_test.dart
index 300d97d3..f2b4c809 100644
--- a/test/encryption/key_manager_test.dart
+++ b/test/encryption/key_manager_test.dart
@@ -20,6 +20,7 @@ import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
import '../fake_client.dart';
@@ -30,6 +31,10 @@ void main() {
late Client client;
setUpAll(() async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.get_library_version();
client = await getClient();
diff --git a/test/encryption/key_request_test.dart b/test/encryption/key_request_test.dart
index fb0af33a..b74f4a62 100644
--- a/test/encryption/key_request_test.dart
+++ b/test/encryption/key_request_test.dart
@@ -20,6 +20,7 @@ import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
import '../fake_client.dart';
@@ -42,6 +43,10 @@ void main() {
Logs().level = Level.error;
setUpAll(() async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.get_library_version();
});
diff --git a/test/encryption/key_verification_test.dart b/test/encryption/key_verification_test.dart
index 06fafcd9..35b08ea4 100644
--- a/test/encryption/key_verification_test.dart
+++ b/test/encryption/key_verification_test.dart
@@ -22,6 +22,7 @@ import 'dart:typed_data';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption.dart';
import 'package:matrix/matrix.dart';
@@ -58,6 +59,10 @@ void main() async {
late Client client2;
setUpAll(() async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.get_library_version();
});
diff --git a/test/encryption/olm_manager_test.dart b/test/encryption/olm_manager_test.dart
index d6a7e06a..e3a8a9fa 100644
--- a/test/encryption/olm_manager_test.dart
+++ b/test/encryption/olm_manager_test.dart
@@ -20,6 +20,7 @@ import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption/utils/json_signature_check_extension.dart';
import 'package:matrix/matrix.dart';
@@ -32,6 +33,10 @@ void main() {
late Client client;
setUpAll(() async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.get_library_version();
client = await getClient();
diff --git a/test/encryption/online_key_backup_test.dart b/test/encryption/online_key_backup_test.dart
index 0774f436..0930ad3b 100644
--- a/test/encryption/online_key_backup_test.dart
+++ b/test/encryption/online_key_backup_test.dart
@@ -20,6 +20,7 @@ import 'dart:convert';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
import '../fake_client.dart';
@@ -35,6 +36,10 @@ void main() {
final senderKey = 'JBG7ZaPn54OBC7TuIEiylW3BZ+7WcGQhFBPB9pogbAg';
setUpAll(() async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.get_library_version();
client = await getClient();
diff --git a/test/encryption/qr_verification_self_test.dart b/test/encryption/qr_verification_self_test.dart
index 43ff4752..bc7e8a3a 100644
--- a/test/encryption/qr_verification_self_test.dart
+++ b/test/encryption/qr_verification_self_test.dart
@@ -20,6 +20,7 @@ import 'dart:async';
import 'dart:typed_data';
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption.dart';
import 'package:matrix/matrix.dart';
@@ -69,7 +70,14 @@ void main() async {
late Client client1;
late Client client2;
+ Future? vodInit;
+
setUp(() async {
+ vodInit ??= vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
+ await vodInit;
client1 = await getClient();
client2 = await getOtherClient();
diff --git a/test/encryption/ssss_test.dart b/test/encryption/ssss_test.dart
index c9670caa..4d5136ec 100644
--- a/test/encryption/ssss_test.dart
+++ b/test/encryption/ssss_test.dart
@@ -22,6 +22,7 @@ import 'dart:typed_data';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/encryption.dart';
import 'package:matrix/matrix.dart';
@@ -54,6 +55,10 @@ void main() {
late Client client;
setUpAll(() async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.get_library_version();
client = await getClient();
diff --git a/test/room_test.dart b/test/room_test.dart
index d51d698c..e11305b9 100644
--- a/test/room_test.dart
+++ b/test/room_test.dart
@@ -22,6 +22,7 @@ import 'dart:math';
import 'dart:typed_data';
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
import 'fake_client.dart';
@@ -671,12 +672,20 @@ void main() {
expect(fetchedParticipants.length, newParticipants.length);
});
- test('calcEncryptionHealthState', () async {
- expect(
- await room.calcEncryptionHealthState(),
- EncryptionHealthState.unverifiedDevices,
- );
- });
+ test(
+ 'calcEncryptionHealthState',
+ () async {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
+ expect(
+ await room.calcEncryptionHealthState(),
+ EncryptionHealthState.allVerified,
+ );
+ },
+ tags: 'olm',
+ );
test('getEventByID', () async {
final event = await room.getEventById('1234');
diff --git a/test_driver/matrixsdk_test.dart b/test_driver/matrixsdk_test.dart
index 2945a39f..4a216aca 100644
--- a/test_driver/matrixsdk_test.dart
+++ b/test_driver/matrixsdk_test.dart
@@ -20,6 +20,7 @@ import 'dart:io';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:vodozemac/vodozemac.dart' as vod;
import 'package:matrix/matrix.dart';
import '../test/fake_database.dart';
@@ -39,6 +40,10 @@ void main() => group(
Client? testClientA, testClientB;
try {
+ await vod.init(
+ wasmPath: './pkg/',
+ libraryPath: './rust/target/debug/',
+ );
await olm.init();
olm.Account();
Logs().i('[LibOlm] Enabled');