### Project Configuration and Rust Integration Source: https://github.com/famedly/dart-vodozemac/blob/main/flutter/windows/CMakeLists.txt Configures the project name and integrates Rust code using Cargokit. This setup is necessary for bridging Dart and Rust functionalities. ```cmake set(PROJECT_NAME "flutter_vodozemac") project(${PROJECT_NAME} LANGUAGES CXX) ``` ```cmake include("../cargokit/cmake/cargokit.cmake") apply_cargokit(${PROJECT_NAME} ../rust vodozemac_bindings_dart "") ``` -------------------------------- ### Dart/Flutter Session Pickling Source: https://github.com/famedly/dart-vodozemac/blob/main/flutter/ios/README_NOTIFICATION_DECRYPT.md Example of how to create an encrypted pickled session in a Dart/Flutter application using vodozemac's native pickle format. This pickled session should then be stored for use in the notification extension. ```dart final session = InboundGroupSession(sessionKey); final pickledSession = session.toPickleEncrypted(pickleKey); // Store pickledSession for use in notification extension ``` -------------------------------- ### Basic Olm Account and Key Operations Source: https://github.com/famedly/dart-vodozemac/blob/main/dart/README.md Demonstrates creating an Olm account, generating fallback and one-time keys, and signing messages. Ensure the library is initialized before use. ```dart // load the library, possibly provide the path to the wasm or native library init(); // Create an olm account. Alternatively import it. final account = await Account.create(); // create some one time keys up to a library specific maximum. print(account.maxNumberOfOneTimeKeys()); await account.generateFallbackKey(); await account.generateOneTimeKeys(20); // You can sign messages and keys. String message = "Some str"; final signature = await account.sign(message); print("Signed '$message', signature '${signature.toBase64()}"); // And verify the signature try { await account.ed25519Key().verify(message: message, signature: signature); print("Signature verified"); } catch (e) { print("Signature not verified"); } ``` -------------------------------- ### Build vodozemac for Web Source: https://github.com/famedly/dart-vodozemac/blob/main/dart/README.md This script automates the process of building the vodozemac package for web deployment, including fetching the correct version and generating the necessary web assets. ```sh version=$(yq ".dependencies.flutter_vodozemac" < pubspec.yaml) version=$(expr "$version" : '\^*\(.*\)') git clone https://github.com/famedly/dart-vodozemac.git -b ${version} .vodozemac cd .vodozemac cargo install flutter_rust_bridge_codegen flutter_rust_bridge_codegen build-web --dart-root dart --rust-root $(readlink -f rust) --release cd .. mv .vodozemac/dart/web/pkg ./web/ rm -rf .vodozemac ``` -------------------------------- ### Run Local IO Tests Source: https://github.com/famedly/dart-vodozemac/blob/main/README.md Execute integration tests for your local platform (macOS/Linux/Windows). Ensure the script is executable. ```bash ./scripts/run_io_tests.sh ``` -------------------------------- ### Initialize Vodozemac for Pure Dart (Native) Source: https://context7.com/famedly/dart-vodozemac/llms.txt Initialize the vodozemac library for pure Dart applications targeting native desktop or mobile platforms. Requires specifying the path to the native library. ```dart import 'package:vodozemac/vodozemac.dart'; await init( libraryPath: '../rust/target/debug/', // path to .dylib / .so / .dll stem: 'vodozemac_bindings_dart', ); ``` -------------------------------- ### Initialize Vodozemac for Pure Dart (Web WASM) Source: https://context7.com/famedly/dart-vodozemac/llms.txt Initialize the vodozemac library for pure Dart applications targeting the web using WebAssembly. Requires specifying the path to the compiled WASM package directory. ```dart import 'package:vodozemac/vodozemac.dart'; await init( wasmPath: './web/pkg/', // path to the compiled WASM pkg directory ); ``` -------------------------------- ### Initialize vodozemac for Native Platforms Source: https://github.com/famedly/dart-vodozemac/blob/main/dart/README.md Import and initialize the vodozemac library for use on native mobile platforms within a Flutter application. ```dart import 'package:flutter_vodozemac/flutter_vodozemac.dart' as vod; await vod.init(); ``` -------------------------------- ### Olm Account Management with Vodozemac Source: https://context7.com/famedly/dart-vodozemac/llms.txt Manage Olm accounts, including key generation, signing, and persistence. This snippet demonstrates creating an account, generating one-time and fallback keys, signing messages, and persisting/restoring the account. ```dart import 'package:vodozemac/vodozemac.dart'; // Create a new account final account = Account(); print('Ed25519: ${account.ed25519Key.toBase64()}'); print('Curve25519: ${account.curve25519Key.toBase64()}'); print('Max OTKs: ${account.maxNumberOfOneTimeKeys}'); // typically ≥ 100 // Generate one-time keys and a fallback key account.generateOneTimeKeys(50); account.generateFallbackKey(); // Inspect keys that need to be uploaded to the homeserver final Map otks = account.oneTimeKeys; final Map fallback = account.fallbackKey; print('OTKs to upload: ${otks.length}'); // Mark keys as published so the account does not re-upload them account.markKeysAsPublished(); // Sign a message (e.g. a device keys JSON blob) final Ed25519Signature sig = account.sign('{"device_id":"ABCDEF"}'); print('Signature: ${sig.toBase64()}'); // Verify the signature with the public Ed25519 key try { account.ed25519Key.verify(message: '{"device_id":"ABCDEF"}', signature: sig); print('Signature valid'); } catch (e) { print('Signature invalid: $e'); } // Persist and restore the account final pickleKey = Uint8List.fromList(List.generate(32, (i) => i)); final pickle = account.toPickleEncrypted(pickleKey); final restored = Account.fromPickleEncrypted(pickle: pickle, pickleKey: pickleKey); print('Restored ed25519: ${restored.ed25519Key.toBase64()}'); // Import from a legacy libolm pickle final legacyAccount = Account.fromOlmPickleEncrypted( pickle: olmPickleString, pickleKey: Uint8List.fromList('key'.codeUnits), ); ``` -------------------------------- ### Import Olm Session from libolm Pickle Source: https://context7.com/famedly/dart-vodozemac/llms.txt Import an Olm Session from a libolm-serialized pickle. This allows for interoperability with legacy clients. ```dart // Import an Olm Session from libolm final olmSession = Session.fromOlmPickleEncrypted( pickle: olmSessionPickle, pickleKey: pickleKeyBytes, ); print(olmSession.sessionId); ``` -------------------------------- ### Import PkDecryption from libolm Pickle Source: https://context7.com/famedly/dart-vodozemac/llms.txt Import a PkDecryption object from a libolm-serialized pickle. This is relevant for key backup and cross-signing functionalities. ```dart // Import PkDecryption from libolm pickle final pkDecryptor = PkDecryption.fromLibolmPickle( pickle: olmPkDecryptionPickle, pickleKey: pickleKeyBytes, ); ``` -------------------------------- ### Import Account from libolm Pickle Source: https://context7.com/famedly/dart-vodozemac/llms.txt Use this method to import an Account object that was serialized by libolm. Ensure the pickle key is correctly provided as bytes. ```dart import 'dart:typed_data'; import 'package:vodozemac/vodozemac.dart'; // Import an Account serialized by libolm final olmPickle = '...'; // from olm.Account.pickle('key') final pickleKeyBytes = Uint8List.fromList('key'.codeUnits); final account = Account.fromOlmPickleEncrypted( pickle: olmPickle, pickleKey: pickleKeyBytes, ); // Identity keys are identical to the libolm originals print(account.curve25519Key.toBase64()); print(account.ed25519Key.toBase64()); ``` -------------------------------- ### Rust FFI Tests Source: https://github.com/famedly/dart-vodozemac/blob/main/flutter/ios/README_NOTIFICATION_DECRYPT.md Command to run the iOS FFI specific tests within the Rust implementation of vodozemac. This helps verify the correctness of the decryption logic. ```bash cd rust cargo test ios_ffi_bindings ``` -------------------------------- ### Initialize Vodozemac for Flutter Source: https://context7.com/famedly/dart-vodozemac/llms.txt Initialize the vodozemac library for use in Flutter applications. This function automatically selects the correct native library based on the platform. ```dart import 'package:flutter_vodozemac/flutter_vodozemac.dart' as vod; Future main() async { WidgetsFlutterBinding.ensureInitialized(); await vod.init(); // auto-selects the correct library per platform assert(vod.isInitialized()); runApp(const MyApp()); } ``` -------------------------------- ### Define Bundled Libraries Source: https://github.com/famedly/dart-vodozemac/blob/main/flutter/linux/CMakeLists.txt Lists absolute paths to libraries that will be bundled with the plugin. This can include prebuilt libraries or those generated by the build process. ```cmake set(flutter_vodozemac_bundled_libraries "${${PROJECT_NAME}_cargokit_lib}" PARENT_SCOPE ) ``` -------------------------------- ### Add flutter_vodozemac to Flutter Project Source: https://github.com/famedly/dart-vodozemac/blob/main/dart/README.md Use this command to add the flutter_vodozemac package, which provides native platform integration for Flutter. ```sh flutter pub add flutter_vodozemac ``` -------------------------------- ### Project Configuration and Rust Integration Source: https://github.com/famedly/dart-vodozemac/blob/main/flutter/linux/CMakeLists.txt Sets the project name and integrates Rust code using Cargokit. This includes applying Cargokit to the specified project and Rust directory. ```cmake set(PROJECT_NAME "flutter_vodozemac") project(${PROJECT_NAME} LANGUAGES CXX) include("../cargokit/cmake/cargokit.cmake") apply_cargokit(${PROJECT_NAME} ../rust vodozemac_bindings_dart "") ``` -------------------------------- ### One-to-One Encrypted Messaging with Session Source: https://context7.com/famedly/dart-vodozemac/llms.txt Demonstrates creating, sending, and receiving encrypted messages between two devices using the Session class. Includes session persistence. ```dart import 'package:vodozemac/vodozemac.dart'; // --- Sender side --- final alice = Account(); final bob = Account(); bob.generateOneTimeKeys(1); final oneTimeKey = bob.oneTimeKeys.values.first; bob.markKeysAsPublished(); // Alice creates an outbound session toward Bob final outbound = alice.createOutboundSession( identityKey: bob.curve25519Key, oneTimeKey: oneTimeKey, ); print('Has received message: ${outbound.hasReceivedMessage}'); // false // First message is always a pre-key message (messageType == 0) final firstMsg = outbound.encrypt('Hello Bob!'); print('messageType: ${firstMsg.messageType}'); // 0 = pre-key print('ciphertext: ${firstMsg.ciphertext}'); // --- Receiver side --- // Bob creates an inbound session from Alice's pre-key message final (:session, :plaintext) = bob.createInboundSession( theirIdentityKey: alice.curve25519Key, preKeyMessageBase64: firstMsg.ciphertext, ); print('Bob decrypted: $plaintext'); // "Hello Bob!" print('Has received message: ${session.hasReceivedMessage}'); // true // Bob replies; subsequent messages are normal messages (messageType == 1) final reply = session.encrypt('Hello Alice!'); print('messageType: ${reply.messageType}'); // 1 = normal final aliceDecrypted = outbound.decrypt( messageType: reply.messageType, ciphertext: reply.ciphertext, ); print('Alice decrypted: $aliceDecrypted'); // "Hello Alice!" // Persist a session final pickleKey = Uint8List.fromList(List.generate(32, (i) => i)); final pickle = session.toPickleEncrypted(pickleKey); final restoredSession = Session.fromPickleEncrypted(pickle: pickle, pickleKey: pickleKey); ``` -------------------------------- ### Run Dart Web Tests Source: https://github.com/famedly/dart-vodozemac/blob/main/README.md Execute integration tests specifically for the Dart web environment. Ensure the script is executable. ```bash ./scripts/run_web_tests.sh ``` -------------------------------- ### Import Outbound Group Session from libolm Pickle Source: https://context7.com/famedly/dart-vodozemac/llms.txt Import an Outbound Group Session serialized by libolm. This is useful for migrating room encryption states. ```dart // Import an Outbound Group Session from libolm final groupSession = GroupSession.fromOlmPickleEncrypted( pickle: olmOutboundPickle, pickleKey: pickleKeyBytes, ); print(groupSession.sessionId); ``` -------------------------------- ### Megolm Inbound Group Session Management in Dart Source: https://context7.com/famedly/dart-vodozemac/llms.txt Demonstrates creating, decrypting, exporting, importing, and persisting Megolm inbound group sessions. Handles session key creation, message decryption, and key backup/forwarding scenarios. ```dart import 'package:vodozemac/vodozemac.dart'; // Create from a session key shared by the sender final outbound = GroupSession(); final inbound = InboundGroupSession(outbound.sessionKey); // Decrypt messages final enc = outbound.encrypt('Secret message'); final (:plaintext, :messageIndex) = inbound.decrypt(enc); print('Plaintext: $plaintext, index: $messageIndex'); // Export and re-import at first known index (for key backup / forwarding) final exportedAll = inbound.exportAtFirstKnownIndex(); final reimported = InboundGroupSession.import(exportedAll); // Export at a specific index (recipient only gets keys from that point onwards) outbound.encrypt('msg at index 1'); outbound.encrypt('msg at index 2'); final enc3 = outbound.encrypt('msg at index 3'); final exportedAt2 = inbound.exportAt(2); // nullable – null if invalid index final partial = InboundGroupSession.import(exportedAt2!); print('firstKnownIndex: ${partial.firstKnownIndex}'); // 2 final (:plaintext: p3, messageIndex: _) = partial.decrypt(enc3); print('Decrypted: $p3'); // Persist final pickleKey = Uint8List.fromList(List.generate(32, (i) => i)); final pickle = inbound.toPickleEncrypted(pickleKey); final restored = InboundGroupSession.fromPickleEncrypted(pickle: pickle, pickleKey: pickleKey); // libolm compatibility final fromOlm = InboundGroupSession.fromOlmPickleEncrypted( pickle: olmPickle, pickleKey: Uint8List.fromList('key'.codeUnits), ); ``` -------------------------------- ### Group Encrypted Messaging with GroupSession Source: https://context7.com/famedly/dart-vodozemac/llms.txt Demonstrates creating an outbound group session for Matrix rooms and encrypting/decrypting messages. Includes session persistence and importing from libolm. ```dart import 'package:vodozemac/vodozemac.dart'; // Create an outbound group session final session = GroupSession(); print('Session ID: ${session.sessionId}'); print('Message idx: ${session.messageIndex}'); // starts at 0 // Share this key with room members so they can create InboundGroupSessions final String sharedKey = session.sessionKey; // Encrypt messages final String enc1 = session.encrypt('Hello room!'); final String enc2 = session.encrypt('Second message'); print('Message index after two encrypts: ${session.messageIndex}'); // 2 // Convert to an inbound session (for the sender to decrypt their own messages) final inbound = session.toInbound(); final (:plaintext, :messageIndex) = inbound.decrypt(enc1); print('Decrypted "$plaintext" at index $messageIndex'); // Persist final pickleKey = Uint8List.fromList(List.generate(32, (i) => i)); final pickle = session.toPickleEncrypted(pickleKey); final restored = GroupSession.fromPickleEncrypted(pickle: pickle, pickleKey: pickleKey); // Import from libolm outbound group session pickle final fromOlm = GroupSession.fromOlmPickleEncrypted( pickle: olmPickle, pickleKey: Uint8List.fromList('key'.codeUnits), ); ``` -------------------------------- ### Add vodozemac to Dart/Flutter Project Source: https://github.com/famedly/dart-vodozemac/blob/main/dart/README.md Use this command to add the vodozemac package as a dependency in your Dart or Flutter project. ```sh flutter pub add vodozemac ``` -------------------------------- ### Group Session Encryption and Decryption Source: https://github.com/famedly/dart-vodozemac/blob/main/dart/README.md Shows how to create a group session, encrypt messages, and decrypt them using the inbound session. This is useful for group communication. ```dart // You can also create group sessions final session = await GroupSession.create(); final inbound = session.toInbound(); // and encrypt with them final encrypted = await session.encrypt('This is a test'); print("Encrypted: $encrypted"); print("Index: ${session.messageIndex()}"); // Or decrypt final decrypted = await inbound.decrypt(encrypted); print("Decrypted: $decrypted"); // Olm session usage not pictured. ``` -------------------------------- ### SAS Verification Flow in Dart Source: https://context7.com/famedly/dart-vodozemac/llms.txt Illustrates initiating and establishing Short Authentication String (SAS) verification. Covers generating ephemeral keys, exchanging public keys, and generating verification codes (emoji/decimal) and MACs. ```dart import 'package:vodozemac/vodozemac.dart'; // Both parties create a Sas object and exchange public keys out-of-band final alice = Sas(); final bob = Sas(); // Each party calls establishSasSecret with the OTHER party's public key. // This consumes (disposes) the Sas object. final aliceSas = alice.establishSasSecret(bob.publicKey); final bobSas = bob.establishSasSecret(alice.publicKey); // Generate 6 bytes for emoji representation (both sides must produce identical bytes) final aliceEmoji = aliceSas.generateBytes('EMOJI', 6); final bobEmoji = bobSas.generateBytes('EMOJI', 6); assert(aliceEmoji.toString() == bobEmoji.toString()); // Generate 5 bytes for the decimal SAS method final aliceDec = aliceSas.generateBytes('DECIMAL', 5); final bobDec = bobSas.generateBytes('DECIMAL', 5); assert(aliceDec.toString() == bobDec.toString()); // Calculate MACs for device/key verification (hkdf-hmac-sha256.v2 – current standard) const msg = 'device_keys_json'; const info = 'MATRIX_KEY_VERIFICATION_MAC...'; final aliceMac = aliceSas.calculateMac(msg, info); final bobMac = bobSas.calculateMac(msg, info); // Each party verifies the other's MAC try { aliceSas.verifyMac(msg, info, bobMac); print('MAC verified – devices match'); } catch (e) { print('MAC mismatch – verification failed: $e'); } // Deprecated MAC format (hkdf-hmac-sha256) – for compatibility with old libolm clients final legacyMac = aliceSas.calculateMacDeprecated(msg, info); // Sas is disposed after establishSasSecret print('alice.disposed: ${alice.disposed}'); // true ``` -------------------------------- ### Key Types Source: https://context7.com/famedly/dart-vodozemac/llms.txt Provides immutable wrappers for cryptographic keys and signatures, supporting interoperability between Base64 and byte array formats for Curve25519 and Ed25519 keys, as well as Ed25519 signatures. ```APIDOC ## Key Types – `Curve25519PublicKey`, `Ed25519PublicKey`, `Ed25519Signature` Immutable wrappers around raw cryptographic key and signature bytes with Base64 and byte-array interoperability. ```dart import 'package:vodozemac/vodozemac.dart'; final account = Account(); // Curve25519PublicKey final curve = account.curve25519Key; final curveB64 = curve.toBase64(); // 43-char unpadded base64 final curveBytes = curve.toBytes(); // Uint8List of length 32 final fromB64 = Curve25519PublicKey.fromBase64(curveB64); final fromBytes = Curve25519PublicKey.fromBytes(curveBytes); assert(fromB64.toBase64() == fromBytes.toBase64()); // Ed25519PublicKey final ed25519 = account.ed25519Key; final edB64 = ed25519.toBase64(); // 43-char unpadded base64 final edBytes = ed25519.toBytes(); // Uint8List of length 32 final edFromB64 = Ed25519PublicKey.fromBase64(edB64); // Ed25519Signature final signature = account.sign('payload'); final sigB64 = signature.toBase64(); // 86-char unpadded base64 final sigBytes = signature.toBytes(); // Uint8List of length 64 final sigFromB64 = Ed25519Signature.fromBase64(sigB64); final sigFromBytes = Ed25519Signature.fromBytes(sigBytes); // Verify edFromB64.verify(message: 'payload', signature: sigFromBytes); // Access both identity keys at once final (:ed25519, :curve25519) = account.identityKeys; // Remove a consumed one-time key account.generateOneTimeKeys(1); final otk = account.oneTimeKeys.values.first; account.removeOneTimeKey(otk.toBase64()); assert(account.oneTimeKeys.isEmpty); ``` ``` -------------------------------- ### CocoaPods Dependency for Extension Source: https://github.com/famedly/dart-vodozemac/blob/main/flutter/ios/README_NOTIFICATION_DECRYPT.md Configuration for adding the `flutter_vodozemac` pod to your iOS Notification Service Extension using CocoaPods. Ensure the path is correctly set to link the library. ```ruby pod 'flutter_vodozemac', :path => '.symlinks/plugins/flutter_vodozemac/ios' ``` -------------------------------- ### PkEncryption and PkDecryption for Secure Messaging Source: https://context7.com/famedly/dart-vodozemac/llms.txt Encrypts messages using a recipient's public key and decrypts them with the corresponding private key. Useful for secure key backup and transfer. Supports reconstruction from Base64 encoded components and restoration from private key bytes or libolm pickle format. ```dart import 'package:vodozemac/vodozemac.dart'; // --- Setup --- final decryptor = PkDecryption(); final publicKey = decryptor.publicKey; // share this with the encryptor final encryptor = PkEncryption.fromPublicKey( Curve25519PublicKey.fromBase64(publicKey), ); // --- Encrypt --- final PkMessage encrypted = encryptor.encrypt("It's a secret to everybody"); // PkMessage carries ciphertext, mac, and an ephemeral key final (ctB64, macB64, epkB64) = encrypted.toBase64(); print('ciphertext: $ctB64'); print('mac: $macB64'); print('ephemeral key: $epkB64'); // Reconstruct a PkMessage from Base64 (e.g. received from server) final received = PkMessage.fromBase64( ciphertext: ctB64, mac: macB64, ephemeralKey: epkB64, ); // --- Decrypt --- final String plaintext = decryptor.decrypt(received); print('Decrypted: $plaintext'); // "It's a secret to everybody" // Restore PkDecryption from private key bytes final privateKeyBytes = decryptor.privateKey; final restoredDecryptor = PkDecryption.fromSecretKey( Curve25519PublicKey.fromBytes(privateKeyBytes), ); // Persist / restore using libolm pickle format final pickleKey = Uint8List.fromList(List.generate(32, (i) => i)); final pickle = decryptor.toLibolmPickle(pickleKey); final fromPickle = PkDecryption.fromLibolmPickle(pickle: pickle, pickleKey: pickleKey); ``` -------------------------------- ### CryptoUtils - PBKDF2 Source: https://context7.com/famedly/dart-vodozemac/llms.txt Derives a key from a passphrase using PBKDF2-SHA256. ```APIDOC ## CryptoUtils.pbkdf2 ### Description Derives a cryptographic key from a passphrase using the PBKDF2-SHA256 algorithm. This is used for Matrix key backup passphrase derivation. ### Method `CryptoUtils.pbkdf2(passphrase: List, salt: List, iterations: int) -> List` ### Parameters #### Path Parameters - **passphrase** (List) - The user's passphrase as a list of integers (byte values). - **salt** (List) - The salt used in the key derivation process as a list of integers (byte values). - **iterations** (int) - The number of iterations to perform for key derivation. ### Request Example ```dart final derivedKey = CryptoUtils.pbkdf2(passphrase: 'Password'.codeUnits, salt: 'salt'.codeUnits, iterations: 50000); print(base64Encode(derivedKey)); ``` ### Response Returns the derived key as a List. ``` -------------------------------- ### Sas / EstablishedSas Source: https://context7.com/famedly/dart-vodozemac/llms.txt Facilitates the Short Authentication String (SAS) interactive verification flow. The Sas class initiates the process by generating keys, and upon successful exchange, EstablishedSas is used for generating verification codes and MACs. ```APIDOC ## `Sas` / `EstablishedSas` – Short Authentication String Verification `Sas` initiates the SAS interactive verification flow by generating an ephemeral key pair. After exchanging public keys with the other party, `establishSasSecret` returns an `EstablishedSas` for generating emoji/decimal verification codes and computing/verifying MACs. ```dart import 'package:vodozemac/vodozemac.dart'; // Both parties create a Sas object and exchange public keys out-of-band final alice = Sas(); final bob = Sas(); // Each party calls establishSasSecret with the OTHER party's public key. // This consumes (disposes) the Sas object. final aliceSas = alice.establishSasSecret(bob.publicKey); final bobSas = bob.establishSasSecret(alice.publicKey); // Generate 6 bytes for emoji representation (both sides must produce identical bytes) final aliceEmoji = aliceSas.generateBytes('EMOJI', 6); final bobEmoji = bobSas.generateBytes('EMOJI', 6); assert(aliceEmoji.toString() == bobEmoji.toString()); // Generate 5 bytes for the decimal SAS method final aliceDec = aliceSas.generateBytes('DECIMAL', 5); final bobDec = bobSas.generateBytes('DECIMAL', 5); assert(aliceDec.toString() == bobDec.toString()); // Calculate MACs for device/key verification (hkdf-hmac-sha256.v2 – current standard) const msg = 'device_keys_json'; const info = 'MATRIX_KEY_VERIFICATION_MAC...'; final aliceMac = aliceSas.calculateMac(msg, info); final bobMac = bobSas.calculateMac(msg, info); // Each party verifies the other's MAC try { aliceSas.verifyMac(msg, info, bobMac); print('MAC verified – devices match'); } catch (e) { print('MAC mismatch – verification failed: $e'); } // Deprecated MAC format (hkdf-hmac-sha256) – for compatibility with old libolm clients final legacyMac = aliceSas.calculateMacDeprecated(msg, info); // Sas is disposed after establishSasSecret print('alice.disposed: ${alice.disposed}'); // true ``` ``` -------------------------------- ### Bridging Header for FFI Source: https://github.com/famedly/dart-vodozemac/blob/main/flutter/ios/README_NOTIFICATION_DECRYPT.md Content for the Objective-C bridging header file in your Notification Service Extension. This header imports the necessary C declarations for the vodozemac FFI bindings. ```objective-c #ifndef Notification_Extension_Bridging_Header_h #define Notification_Extension_Bridging_Header_h // Import the vodozemac C header #import "vodozemac_ios_ffi_bindings.h" #endif /* Notification_Extension_Bridging_Header_h */ ``` -------------------------------- ### InboundGroupSession Source: https://context7.com/famedly/dart-vodozemac/llms.txt Handles the decryption of room messages encrypted with Megolm. It can be initialized from a session key, imported from an exported session, or restored from a pickle. ```APIDOC ## `InboundGroupSession` – Megolm Inbound Group Session `InboundGroupSession` decrypts room messages encrypted with Megolm. It can be created from a session key, imported from an exported session (with a specific start index), or restored from a pickle. ```dart import 'package:vodozemac/vodozemac.dart'; // Create from a session key shared by the sender final outbound = GroupSession(); final inbound = InboundGroupSession(outbound.sessionKey); // Decrypt messages final enc = outbound.encrypt('Secret message'); final (:plaintext, :messageIndex) = inbound.decrypt(enc); print('Plaintext: $plaintext, index: $messageIndex'); // Export and re-import at first known index (for key backup / forwarding) final exportedAll = inbound.exportAtFirstKnownIndex(); final reimported = InboundGroupSession.import(exportedAll); // Export at a specific index (recipient only gets keys from that point onwards) outbound.encrypt('msg at index 1'); outbound.encrypt('msg at index 2'); final enc3 = outbound.encrypt('msg at index 3'); final exportedAt2 = inbound.exportAt(2); // nullable – null if invalid index final partial = InboundGroupSession.import(exportedAt2!); print('firstKnownIndex: ${partial.firstKnownIndex}'); // 2 final (:plaintext: p3, messageIndex: _) = partial.decrypt(enc3); print('Decrypted: $p3'); // Persist final pickleKey = Uint8List.fromList(List.generate(32, (i) => i)); final pickle = inbound.toPickleEncrypted(pickleKey); final restored = InboundGroupSession.fromPickleEncrypted(pickle: pickle, pickleKey: pickleKey); // libolm compatibility final fromOlm = InboundGroupSession.fromOlmPickleEncrypted( pickle: olmPickle, pickleKey: Uint8List.fromList('key'.codeUnits), ); ``` ``` -------------------------------- ### CryptoUtils - SHA-256 Source: https://context7.com/famedly/dart-vodozemac/llms.txt Calculates the SHA-256 hash of the input data. ```APIDOC ## CryptoUtils.sha256 ### Description Calculates the SHA-256 hash of the input data. ### Method `CryptoUtils.sha256(input: List) -> List` ### Parameters #### Path Parameters - **input** (List) - The input data as a list of integers (byte values). ### Request Example ```dart final sha256 = CryptoUtils.sha256(input: 'test'.codeUnits); print(base64Encode(sha256)); ``` ### Response Returns the SHA-256 hash as a List. ``` -------------------------------- ### PkSigning Source: https://context7.com/famedly/dart-vodozemac/llms.txt Generates an Ed25519 key pair for signing JSON blobs, enabling verification of signatures with the corresponding public key. Essential for features like Matrix cross-signing. ```APIDOC ## `PkSigning` – Public Key Signing `PkSigning` creates an Ed25519 key pair used for Matrix cross-signing. It can sign JSON blobs; the corresponding `Ed25519PublicKey` is used to verify signatures. ```dart import 'package:vodozemac/vodozemac.dart'; // Create a new signing key pair final signing = PkSigning(); print('Secret key: ${signing.secretKey}'); print('Public key: ${signing.publicKey.toBase64()}'); // Sign a message final Ed25519Signature sig = signing.sign('{"user_id":"@alice:example.org"}'); print('Signature: ${sig.toBase64()}'); // Verify with the public key try { signing.publicKey.verify( message: '{"user_id":"@alice:example.org"}', signature: sig, ); print('Valid signature'); } catch (e) { print('Invalid signature: $e'); } // Restore from a deterministic secret key (base64-encoded 32-byte seed) import 'dart:convert'; final seed = Uint8List.fromList(List.generate(32, (i) => i)); final seedB64 = base64Encode(seed).replaceAll(RegExp(r'=+$'), ''); final signing2 = PkSigning.fromSecretKey(seedB64); // signing2.publicKey is deterministic for the same seed ``` ``` -------------------------------- ### PkSigning for Ed25519 Key Generation and Signing Source: https://context7.com/famedly/dart-vodozemac/llms.txt Generates Ed25519 key pairs for signing JSON blobs, enabling verification with the corresponding public key. Supports restoration from deterministic secret keys. ```dart import 'package:vodozemac/vodozemac.dart'; // Create a new signing key pair final signing = PkSigning(); print('Secret key: ${signing.secretKey}'); print('Public key: ${signing.publicKey.toBase64()}'); // Sign a message final Ed25519Signature sig = signing.sign('{"user_id":"@alice:example.org"}'); print('Signature: ${sig.toBase64()}'); // Verify with the public key try { signing.publicKey.verify( message: '{"user_id":"@alice:example.org"}', signature: sig, ); print('Valid signature'); } catch (e) { print('Invalid signature: $e'); } // Restore from a deterministic secret key (base64-encoded 32-byte seed) import 'dart:convert'; final seed = Uint8List.fromList(List.generate(32, (i) => i)); final seedB64 = base64Encode(seed).replaceAll(RegExp(r'=+$'), ''); final signing2 = PkSigning.fromSecretKey(seedB64); // signing2.publicKey is deterministic for the same seed ``` -------------------------------- ### Key Type Wrappers: Curve25519PublicKey, Ed25519PublicKey, Ed25519Signature Source: https://context7.com/famedly/dart-vodozemac/llms.txt Provides immutable wrappers for cryptographic keys and signatures, offering interoperability with Base64 and byte arrays. Includes methods for conversion, verification, and managing identity keys and one-time keys. ```dart import 'package:vodozemac/vodozemac.dart'; final account = Account(); // Curve25519PublicKey final curve = account.curve25519Key; final curveB64 = curve.toBase64(); // 43-char unpadded base64 final curveBytes = curve.toBytes(); // Uint8List of length 32 final fromB64 = Curve25519PublicKey.fromBase64(curveB64); final fromBytes = Curve25519PublicKey.fromBytes(curveBytes); assert(fromB64.toBase64() == fromBytes.toBase64()); // Ed25519PublicKey final ed25519 = account.ed25519Key; final edB64 = ed25519.toBase64(); // 43-char unpadded base64 final edBytes = ed25519.toBytes(); // Uint8List of length 32 final edFromB64 = Ed25519PublicKey.fromBase64(edB64); // Ed25519Signature final signature = account.sign('payload'); final sigB64 = signature.toBase64(); // 86-char unpadded base64 final sigBytes = signature.toBytes(); // Uint8List of length 64 final sigFromB64 = Ed25519Signature.fromBase64(sigB64); final sigFromBytes = Ed25519Signature.fromBytes(sigBytes); // Verify edFromB64.verify(message: 'payload', signature: sigFromBytes); // Access both identity keys at once final (:ed25519, :curve25519) = account.identityKeys; // Remove a consumed one-time key account.generateOneTimeKeys(1); final otk = account.oneTimeKeys.values.first; account.removeOneTimeKey(otk.toBase64()); assert(account.oneTimeKeys.isEmpty); ``` -------------------------------- ### CryptoUtils - SHA-512 Source: https://context7.com/famedly/dart-vodozemac/llms.txt Calculates the SHA-512 hash of the input data. ```APIDOC ## CryptoUtils.sha512 ### Description Calculates the SHA-512 hash of the input data. ### Method `CryptoUtils.sha512(input: List) -> List` ### Parameters #### Path Parameters - **input** (List) - The input data as a list of integers (byte values). ### Request Example ```dart final sha512 = CryptoUtils.sha512(input: 'test'.codeUnits); print(base64Encode(sha512)); ``` ### Response Returns the SHA-512 hash as a List. ``` -------------------------------- ### CryptoUtils - HMAC-SHA256 Source: https://context7.com/famedly/dart-vodozemac/llms.txt Calculates the HMAC-SHA256 hash using a key and input data. ```APIDOC ## CryptoUtils.hmac ### Description Calculates the HMAC-SHA256 hash using a secret key and input data. ### Method `CryptoUtils.hmac(key: List, input: List) -> List` ### Parameters #### Path Parameters - **key** (List) - The secret key as a list of integers (byte values). - **input** (List) - The input data as a list of integers (byte values). ### Request Example ```dart final hmac = CryptoUtils.hmac(key: 'password'.codeUnits, input: 'test'.codeUnits); print(base64Encode(hmac)); ``` ### Response Returns the HMAC-SHA256 hash as a List. ``` -------------------------------- ### Set Minimum CMake Version Source: https://github.com/famedly/dart-vodozemac/blob/main/flutter/windows/CMakeLists.txt Specifies the minimum required CMake version for the project. Ensure this version is compatible with Flutter tooling. ```cmake cmake_minimum_required(VERSION 3.14) ``` -------------------------------- ### Import Inbound Group Session and Decrypt libolm Message Source: https://context7.com/famedly/dart-vodozemac/llms.txt Import an Inbound Group Session from libolm and decrypt a message originally encrypted by libolm. This verifies decryption compatibility. ```dart // Import an Inbound Group Session final inboundSession = InboundGroupSession.fromOlmPickleEncrypted( pickle: olmInboundPickle, pickleKey: pickleKeyBytes, ); // Decrypt a message that was originally encrypted by libolm final outbound = /* libolm-compatible outbound */ GroupSession.fromOlmPickleEncrypted(...); final enc = outbound.encrypt('hello'); final (:plaintext, :messageIndex) = inboundSession.decrypt(enc); print('$plaintext at index $messageIndex'); // "hello" at index 0 ``` -------------------------------- ### iOS Notification Service Extension Decryption Logic (Swift) Source: https://context7.com/famedly/dart-vodozemac/llms.txt Demonstrates how to call the `ios_decrypt_event` FFI function within an iOS Notification Service Extension to decrypt Matrix events. It handles reading payload data, retrieving keys, and processing the decryption result. ```swift // NotificationService.swift – iOS Notification Service Extension import Foundation class NotificationService: UNNotificationServiceExtension { override func didReceive( _ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void ) { let content = request.content.mutableCopy() as! UNMutableNotificationContent // Read encrypted event fields from the push payload guard let ciphertext = request.content.userInfo["ciphertext"] as? String, let sessionId = request.content.userInfo["session_id"] as? String else { contentHandler(content); return } // 32-byte pickle key stored in Keychain / shared app group let pickleKey: [UInt8] = retrievePickleKeyFromKeychain() // your helper // Pickled InboundGroupSession stored by the main app guard let pickledSession = loadPickledSession(sessionId: sessionId) else { contentHandler(content); return } // Call vodozemac FFI directly (no Flutter runtime needed) let result = ios_decrypt_event( pickledSession.cString(using: .utf8), pickleKey, ciphertext.cString(using: .utf8) ) defer { ios_free_result(result) } if let errorPtr = result.error { print("Decryption error: \(String(cString: errorPtr))") contentHandler(content); return } if let plaintextPtr = result.plaintext, let json = try? JSONSerialization.jsonObject( with: Data(String(cString: plaintextPtr).utf8) ) as? [String: Any], let body = (json["content"] as? [String: Any])?["body"] as? String { content.body = body } contentHandler(content) } } ``` -------------------------------- ### PkEncryption / PkDecryption Source: https://context7.com/famedly/dart-vodozemac/llms.txt Encrypts messages using a Curve25519 public key and decrypts them with the corresponding private key. This is useful for secure message transfer and key backup mechanisms. ```APIDOC ## `PkEncryption` / `PkDecryption` – Public Key Encryption `PkEncryption` encrypts a message to a Curve25519 public key. `PkDecryption` holds the private key and decrypts it. Used for Matrix key backup and cross-signing key transfer. ```dart import 'package:vodozemac/vodozemac.dart'; // --- Setup --- final decryptor = PkDecryption(); final publicKey = decryptor.publicKey; // share this with the encryptor final encryptor = PkEncryption.fromPublicKey( Curve25519PublicKey.fromBase64(publicKey), ); // --- Encrypt --- final PkMessage encrypted = encryptor.encrypt("It's a secret to everybody"); // PkMessage carries ciphertext, mac, and an ephemeral key final (ctB64, macB64, epkB64) = encrypted.toBase64(); print('ciphertext: $ctB64'); print('mac: $macB64'); print('ephemeral key: $epkB64'); // Reconstruct a PkMessage from Base64 (e.g. received from server) final received = PkMessage.fromBase64( ciphertext: ctB64, mac: macB64, ephemeralKey: epkB64, ); // --- Decrypt --- final String plaintext = decryptor.decrypt(received); print('Decrypted: $plaintext'); // "It's a secret to everybody" // Restore PkDecryption from private key bytes final privateKeyBytes = decryptor.privateKey; final restoredDecryptor = PkDecryption.fromSecretKey( Curve25519PublicKey.fromBytes(privateKeyBytes), ); // Persist / restore using libolm pickle format final pickleKey = Uint8List.fromList(List.generate(32, (i) => i)); final pickle = decryptor.toLibolmPickle(pickleKey); final fromPickle = PkDecryption.fromLibolmPickle(pickle: pickle, pickleKey: pickleKey); ``` ``` -------------------------------- ### PBKDF2-SHA256 Key Derivation in Dart Source: https://context7.com/famedly/dart-vodozemac/llms.txt Derives a cryptographic key using PBKDF2 with SHA256. This is used for Matrix key backup passphrase derivation. Requires a passphrase, salt, and iteration count. ```dart import 'dart:convert'; import 'dart:typed_data'; import 'package:vodozemac/vodozemac.dart'; // PBKDF2-SHA256 (Matrix key backup passphrase derivation) final derivedKey = CryptoUtils.pbkdf2( passphrase: 'Password'.codeUnits, salt: 'salt'.codeUnits, iterations: 50000, ); print(base64Encode(derivedKey)); // → lZtsDrDdlnt/XH95wCjDn/yXU1EPaAx/Zy+VeEXPuas= ``` -------------------------------- ### CryptoUtils - AES-CTR Source: https://context7.com/famedly/dart-vodozemac/llms.txt Encrypts or decrypts data using AES-CTR mode. ```APIDOC ## CryptoUtils.aesCtr ### Description Encrypts or decrypts data using AES-CTR mode. This is used for Matrix encrypted attachments. ### Method `CryptoUtils.aesCtr(input: List, key: Uint8List, iv: Uint8List) -> Uint8List` ### Parameters #### Path Parameters - **input** (List) - The data to encrypt or decrypt as a list of integers (byte values). - **key** (Uint8List) - The 32-byte AES key. - **iv** (Uint8List) - The 16-byte initialization vector (counter). ### Request Example ```dart final key = secureRandom(32); final iv = secureRandom(16)..[8] &= 0x7f; final encrypted = CryptoUtils.aesCtr(input: 'secret'.codeUnits, key: key, iv: iv); final decrypted = CryptoUtils.aesCtr(input: encrypted, key: key, iv: iv); print(String.fromCharCodes(decrypted)); // "secret" ``` ### Response Returns the encrypted or decrypted data as a Uint8List. ``` -------------------------------- ### SHA-256 Hashing in Dart Source: https://context7.com/famedly/dart-vodozemac/llms.txt Calculates the SHA-256 hash of input data. Ensure input is provided as a list of integers (e.g., from .codeUnits). ```dart import 'dart:convert'; import 'dart:typed_data'; import 'package:vodozemac/vodozemac.dart'; // SHA-256 final sha256 = CryptoUtils.sha256(input: 'test'.codeUnits); print(base64Encode(sha256)); // → n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= ``` -------------------------------- ### Account - Olm Account Management Source: https://context7.com/famedly/dart-vodozemac/llms.txt Manages the cryptographic identity of a Matrix device, including key generation, signing, and persistence. ```APIDOC ## Account - Olm Account Management `Account` manages the cryptographic identity of a Matrix device. It holds an Ed25519 signing key pair and a Curve25519 encryption key pair, generates one-time keys (OTKs) and a fallback key used in X3DH key agreement, and can sign arbitrary messages. ### Create a new account ```dart import 'package:vodozemac/vodozemac.dart'; final account = Account(); print('Ed25519: ${account.ed25519Key.toBase64()}'); print('Curve25519: ${account.curve25519Key.toBase64()}'); print('Max OTKs: ${account.maxNumberOfOneTimeKeys}'); ``` ### Generate one-time keys and a fallback key ```dart account.generateOneTimeKeys(50); account.generateFallbackKey(); final Map otks = account.oneTimeKeys; final Map fallback = account.fallbackKey; print('OTKs to upload: ${otks.length}'); ``` ### Mark keys as published ```dart account.markKeysAsPublished(); ``` ### Sign a message ```dart final Ed25519Signature sig = account.sign('{"device_id":"ABCDEF"}'); print('Signature: ${sig.toBase64()}'); ``` ### Verify a signature ```dart try { account.ed25519Key.verify(message: '{"device_id":"ABCDEF"}', signature: sig); print('Signature valid'); } catch (e) { print('Signature invalid: $e'); } ``` ### Persist and restore the account ```dart final pickleKey = Uint8List.fromList(List.generate(32, (i) => i)); final pickle = account.toPickleEncrypted(pickleKey); final restored = Account.fromPickleEncrypted(pickle: pickle, pickleKey: pickleKey); print('Restored ed25519: ${restored.ed25519Key.toBase64()}'); ``` ### Import from a legacy libolm pickle ```dart final legacyAccount = Account.fromOlmPickleEncrypted( pickle: olmPickleString, pickleKey: Uint8List.fromList('key'.codeUnits), ); ``` ```