libsignal 1.0.1 copy "libsignal: ^1.0.1" to clipboard
libsignal: ^1.0.1 copied to clipboard

Dart FFI bindings for libsignal — Signal Protocol implementation for end-to-end encryption, sealed sender, group messaging, and secure cryptographic operations.

libsignal - Signal Protocol for Dart #

pub package CI Coverage License Dart Flutter libsignal

A Dart FFI wrapper for libsignal, providing Signal Protocol implementation for end-to-end encryption, sealed sender, group messaging, and secure cryptographic operations.

Platform Support #

Android iOS macOS Linux Windows
Support SDK 21+ 12.0+ 10.14+ arm64, x64 x64
Arch arm64, armv7, x64 arm64 arm64, x64 arm64, x64 x64

Features #

  • Flutter & CLI Support: Works with Flutter apps and standalone Dart CLI applications
  • Signal Protocol: End-to-end encryption with perfect forward secrecy (Double Ratchet, X3DH)
  • Sealed Sender: Anonymous message sending (server won't know who sent the message)
  • Group Messaging: Efficient group encryption using SenderKey distribution
  • Zero Configuration: Pre-built native libraries included via Build Hooks
  • High Performance: Direct FFI bindings with minimal overhead
  • Automated Updates: Native libraries auto-rebuild when new libsignal versions are released

Implementation Status #

Overview of wrapped functionality from the native libsignal library:

Category Status Description
Signal Protocol Double Ratchet, X3DH, session encryption/decryption
Key Management Ed25519, X25519, Kyber (post-quantum)
Pre-Keys Regular, signed, and Kyber pre-keys
Group Messaging SenderKey protocol for efficient group encryption
Sealed Sender Anonymous message sending with certificates
Fingerprints Safety numbers for identity verification
Crypto Utilities HKDF, AES-256-GCM-SIV
Store Interfaces All 6 store types with in-memory implementations
zkgroup Zero-knowledge groups, profile credentials
Registration Account registration service
Backup Message backup and restore
SVR Secure Value Recovery (PIN-based backup)
Call Links Call link credentials and authentication
Connection Manager Network connection handling
Detailed Implementation

Implemented Features #

Keys (lib/src/keys/)

Class Key Methods Native Functions
PrivateKey generate, sign, agree, serialize signal_privatekey_*
PublicKey verify, serialize, compare signal_publickey_*
IdentityKeyPair generate, serialize, signAlternateIdentity signal_identitykeypair_*
PreKeyPair generate, serialize signal_pre_key_record_*
SignedPreKeyPair generate, serialize signal_signed_pre_key_record_*
KyberPreKeyPair generate, serialize signal_kyber_*

Protocol (lib/src/protocol/)

Class Key Methods Native Functions
SessionCipher encrypt, decryptSignalMessage, decryptPreKeySignalMessage signal_encrypt_message, signal_decrypt_*
SessionBuilder processPreKeyBundle signal_process_prekey_bundle
SessionRecord serialize, deserialize signal_session_record_*
ProtocolAddress new, name, deviceId signal_address_*
SignalMessage serialize, body, counter, verifyMac signal_message_*
PreKeySignalMessage serialize, preKeyId, signedPreKeyId signal_pre_key_signal_message_*

Groups (lib/src/groups/)

Class Key Methods Native Functions
GroupSession createDistributionMessage, encrypt, decrypt signal_group_encrypt_message, signal_group_decrypt_message
SenderKeyRecord serialize, deserialize signal_sender_key_record_*
SenderKeyMessage serialize, getDistributionId signal_sender_key_message_*
SenderKeyDistributionMessage create, serialize signal_sender_key_distribution_message_*

Sealed Sender (lib/src/sealed_sender/)

Class Key Methods Native Functions
SealedSessionCipher encrypt, decrypt signal_sealed_session_cipher_*
SenderCertificate create, validate, serialize signal_sender_certificate_*
ServerCertificate create, serialize signal_server_certificate_*
UnidentifiedSenderMessageContent create, serialize signal_unidentified_sender_message_content_*

Crypto (lib/src/crypto/)

Class Key Methods Native Functions
Hkdf deriveSecrets signal_hkdf_derive
Aes256GcmSiv encrypt, decrypt signal_aes_gcm_siv_*
Fingerprint displayString, scannableEncoding, compare signal_fingerprint_*

Stores (lib/src/stores/)

Interface In-Memory Implementation Purpose
SessionStore InMemorySessionStore Session state persistence
IdentityKeyStore InMemoryIdentityKeyStore Identity key management
PreKeyStore InMemoryPreKeyStore One-time pre-keys
SignedPreKeyStore InMemorySignedPreKeyStore Signed pre-keys
KyberPreKeyStore InMemoryKyberPreKeyStore Post-quantum pre-keys
SenderKeyStore InMemorySenderKeyStore Group messaging keys

Not Implemented #

Category Native Functions Reason
zkgroup signal_group_secret_params_*, signal_profile_key_* Server-side verification, not needed for basic messaging
Registration signal_registration_* Account registration service
Backup signal_backup_*, signal_message_backup_* Message backup and restore
SVR signal_svr_* Secure Value Recovery for PIN-based backup
Call Links signal_call_link_* Call link credentials
Connection Manager signal_connection_manager_* Network connection handling
HSM Enclave signal_hsm_enclave_* Hardware security module communication
CDSI signal_cdsi_* Contact Discovery Service

Installation #

Add to your pubspec.yaml:

dependencies:
  libsignal: ^x.x.x

Native libraries are downloaded automatically during the build process.

Quick Start #

import 'package:libsignal/libsignal.dart';

void main() {
  // Initialize the library (optional but recommended for performance)
  LibSignal.init();

  // Generate identity key pair
  final identity = IdentityKeyPair.generate();
  print('Identity public key: ${identity.publicKey.serialize().length} bytes');

  // Clean up when done
  identity.dispose();
  LibSignal.cleanup();
}

API Reference #

Key Types #

import 'package:libsignal/libsignal.dart';

// Identity Key Pair (long-term identity)
final identity = IdentityKeyPair.generate();
print('Public key length: ${identity.publicKey.serialize().length}');
print('Private key length: ${identity.privateKey.serialize().length}');

// Pre-Keys (one-time keys for X3DH)
final preKey = PreKeyPair.generate(preKeyId: 1);
final signedPreKey = SignedPreKeyPair.generate(
  signedPreKeyId: 1,
  identityKeyPair: identity,
);

// Kyber Pre-Keys (post-quantum key exchange)
final kyberPreKey = KyberPreKeyPair.generate(
  kyberPreKeyId: 1,
  identityKeyPair: identity,
);

// Clean up
identity.dispose();
preKey.dispose();
signedPreKey.dispose();
kyberPreKey.dispose();

Session Encryption (Double Ratchet) #

import 'package:libsignal/libsignal.dart';

// Create stores
final sessionStore = InMemorySessionStore();
final identityStore = InMemoryIdentityKeyStore(identity, registrationId);

// Build session from pre-key bundle
final builder = SessionBuilder(
  sessionStore: sessionStore,
  identityKeyStore: identityStore,
);
await builder.processPreKeyBundle(recipientAddress, preKeyBundle);

// Encrypt messages
final cipher = SessionCipher(
  sessionStore: sessionStore,
  identityKeyStore: identityStore,
);
final encrypted = await cipher.encrypt(recipientAddress, plaintext);

// Decrypt messages
final decrypted = await cipher.decrypt(senderAddress, ciphertext);

Sealed Sender (Anonymous Messaging) #

import 'package:libsignal/libsignal.dart';

// Create sealed session cipher
final sealedCipher = SealedSessionCipher(
  sessionStore: sessionStore,
  identityKeyStore: identityStore,
);

// Create sender certificate (issued by server)
final senderCert = SenderCertificate.create(
  senderUuid: 'my-uuid',
  deviceId: 1,
  senderKey: identity.publicKey,
  expiration: DateTime.now().toUtc().add(Duration(days: 30)),
  signerCertificate: serverCert,
  signerKey: serverPrivateKey,
);

// Encrypt with sealed sender (server won't know who sent it)
final sealed = await sealedCipher.encrypt(
  recipientAddress,
  plaintext,
  senderCert,
  contentHint: ContentHint.resendable,
);

// Recipient decrypts and learns sender identity
final result = await recipientCipher.decrypt(
  sealed,
  trustRoot: trustRootPublicKey,
  timestamp: DateTime.now().toUtc(),
  localUuid: 'recipient-uuid',
  localDeviceId: 1,
);
print('Message from: ${result.senderUuid}');

Group Messaging (SenderKey) #

import 'package:libsignal/libsignal.dart';

// Create group session
final groupSession = GroupSession(
  senderKeyStore: InMemorySenderKeyStore(),
);

// Create distribution message (send to all group members)
final distributionMessage = await groupSession.createDistributionMessage(
  sender: myAddress,
  distributionId: groupId,
);

// Encrypt for group
final groupCiphertext = await groupSession.encrypt(
  sender: myAddress,
  distributionId: groupId,
  plaintext: message,
);

// Decrypt group message
final plaintext = await groupSession.decrypt(
  sender: senderAddress,
  distributionId: groupId,
  ciphertext: groupCiphertext,
);

Resource Management #

Basic Usage #

final identity = IdentityKeyPair.generate();
// Use identity...
identity.dispose(); // Clean up when done

Performance Optimization #

For better performance, initialize once at app start:

void main() {
  LibSignal.init(); // Recommended at app startup
  runApp(MyApp());
}

Security Notes #

Key Features:

  • Signal Protocol - Battle-tested encryption used by Signal, WhatsApp, and others
  • Perfect Forward Secrecy - Past messages stay secure even if keys are compromised
  • Kyber Support - Post-quantum key exchange for future-proof security

Best Practices:

  • Always call dispose() on key pairs and sessions to free native resources
  • Call clearSecrets() on sensitive data when done for immediate memory zeroing
  • Secrets are also auto-zeroed via Finalizers on GC (defense-in-depth), but don't rely solely on this
  • Use LibSignalUtils.constantTimeEquals() for comparing secrets (prevents timing attacks)
  • Keep the library updated to the latest version
  • Use UTC timestamps for certificate validation to avoid timezone issues
// Secure usage example
final identity = IdentityKeyPair.generate();
// ... use identity for encryption ...

// Clean up sensitive data
identity.clearSecrets();
identity.dispose();

Stores #

Signal Protocol requires persistent storage for session state (Double Ratchet). This library provides store interfaces and in-memory implementations.

In-Memory Stores (Testing Only) #

final sessionStore = InMemorySessionStore();
final identityStore = InMemoryIdentityKeyStore(identity, registrationId);
final preKeyStore = InMemoryPreKeyStore();
final signedPreKeyStore = InMemorySignedPreKeyStore();
final kyberPreKeyStore = InMemoryKyberPreKeyStore();
final senderKeyStore = InMemorySenderKeyStore();

Warning: In-memory stores lose all data on app restart. Use only for:

  • Unit tests
  • Development/debugging
  • Demo applications

Production Requirements #

For production apps, implement the store interfaces with secure storage:

Store Purpose Security Level
SessionStore Encrypted session state High (contains key material)
IdentityKeyStore Identity keys Critical (long-term secrets)
PreKeyStore One-time pre-keys High
SignedPreKeyStore Signed pre-keys High
KyberPreKeyStore Post-quantum pre-keys High
SenderKeyStore Group messaging keys High

Recommended storage options:

  • flutter_secure_storage - for identity keys and other critical secrets
  • drift / sqflite with SQLCipher - for session records
  • hive with encryption - lightweight alternative

Building from Source #

Prerequisites #

  • Flutter 3.38+
  • FVM (optional, for version management)
  • Rust toolchain (for building native libraries):
    • rustup - Rust toolchain installer and version manager
    • cargo - Rust package manager (installed automatically with rustup)
    • cbindgen - C header generator (installed automatically during build via cargo install)

Setup #

# Clone the repository
git clone https://github.com/djx-y-z/libsignal_dart.git
cd libsignal_dart

# Install dependencies
make setup

# Build native libraries for your platform
make build ARGS="macos"  # or linux, windows, ios, android

Available Commands #

make help           # Show all commands
make build ARGS="<platform>"  # Build native libraries
make test           # Run tests
make coverage       # Run tests with coverage report
make analyze        # Static analysis
make regen          # Regenerate FFI bindings

Architecture #

┌─────────────────────────────────────────────┐
│           libsignal (Rust)                  │  ← Core implementation
├─────────────────────────────────────────────┤
│           libsignal-ffi (Rust)              │  ← C FFI layer
├─────────────────────────────────────────────┤
│          signal_ffi.h (C header)            │  ← cbindgen output
├─────────────────────────────────────────────┤
│     libsignal_bindings.dart (Dart FFI)      │  ← ffigen output
├─────────────────────────────────────────────┤
│         libsignal (Dart API)                │  ← High-level API
└─────────────────────────────────────────────┘

Acknowledgements #

This library would not be possible without libsignal by Signal, which provides the underlying Rust implementation of the Signal Protocol.

License #

This project is licensed under the AGPL-3.0 License - see the LICENSE file for details.

The bundled libsignal library is also licensed under AGPL-3.0 - see LICENSE.libsignal for the Signal license.

Contributing #

Contributions are welcome! Please read our Contributing Guidelines before submitting issues or pull requests.

For major changes, please open an issue first to discuss what you would like to change.

1
likes
140
points
73
downloads

Publisher

unverified uploader

Weekly Downloads

Dart FFI bindings for libsignal — Signal Protocol implementation for end-to-end encryption, sealed sender, group messaging, and secure cryptographic operations.

Repository (GitHub)
View/report issues
Contributing

Topics

#encryption #signal-protocol #e2e-encryption #cryptography #messaging

Documentation

API reference

License

AGPL-3.0 (license)

Dependencies

code_assets, crypto, ffi, hooks

More

Packages that depend on libsignal