ffr_crypto

A Flutter-first, Rust-powered native cryptography package using Dart FFI and Flutter Native Assets.

Features

  • Secure Random: CSPRNG random byte generation.
  • Asymmetric Cryptography:
    • RSA-OAEP encryption/decryption (2048, 3072, 4096-bit).
    • RSA-PSS signatures (signing/verification).
  • Symmetric Cryptography:
    • AES-GCM (128 & 256-bit keys) with AAD.
    • ChaCha20-Poly1305 with AAD.
  • Hashing: SHA-2 (SHA-256, SHA-512), SHA-3 (SHA3-256, SHA3-512), and BLAKE3 with one-shot and stateful streaming APIs.
  • Key Derivation (KDF): PBKDF2-HMAC-SHA-256, HKDF-SHA-256, and Argon2 (id, i, d).
  • Elliptic Curve Cryptography (ECC): Ed25519 signatures and X25519 Diffie-Hellman key exchange.
  • Hybrid Encryption (ECIES): Composed hybrid encryption using X25519, HKDF-SHA-256, and ChaCha20-Poly1305.

Performance & Design

  • Off-Thread Processing: All computationally expensive operations (RSA, KDFs, Hybrid, Signatures) run asynchronously on background Dart Isolates (Isolate.run), preventing UI frames from dropping.
  • Native Assets Pipeline: Uses modern Flutter native assets build hooks (hook/build.dart) to compile the underlying Rust library automatically.
  • Robust Error Handling: Translates C-ABI status codes into clear, typed CryptoException subclasses.

Platform Support

ffr_crypto compiles a native Rust library at build time via Flutter Native Assets. It works on all platforms where a Rust toolchain is available.

Platform Architectures Supported
🍎 macOS arm64, x64
📱 iOS arm64, x64 (simulator)
🤖 Android arm64-v8a, armeabi-v7a, x86, x86_64
🐧 Linux arm64, x64
🪟 Windows x64
🌐 Web ❌ (dart:ffi is unsupported on Web)

Getting Started

Add the package dependency to your pubspec.yaml:

dependencies:
dependencies:
  ffr_crypto: ^0.0.3

Prerequisites — Rust Toolchain

Install the Rust toolchain first, then add the targets for each platform you intend to build:

# macOS (Apple Silicon + Intel)
rustup target add aarch64-apple-darwin x86_64-apple-darwin

# iOS (Device + Simulator)
rustup target add aarch64-apple-ios x86_64-apple-ios

# Android (requires NDK via Android Studio or sdkmanager)
rustup target add aarch64-linux-android armv7-linux-androideabi \
                   i686-linux-android x86_64-linux-android

# Linux
rustup target add aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu

# Windows (run on a Windows host)
rustup target add x86_64-pc-windows-msvc

Note: Android builds additionally require the Android NDK. Install it via Android Studio → SDK Manager → SDK Tools → NDK.


API Usage Examples

1. Cryptographically Secure Random Bytes

import 'package:ffr_crypto/ffr_crypto.dart';

Uint8List bytes = await CryptoRandom.secureBytes(32);

2. Hashing (One-shot & Streaming)

import 'package:ffr_crypto/ffr_crypto.dart';

// One-shot
Uint8List sha256Digest = await CryptoHash.hash(HashAlgorithm.sha256, bytes);

// Incremental/Streaming
final hasher = await CryptoHasher.create(HashAlgorithm.blake3);
await hasher.update(chunk1);
await hasher.update(chunk2);
Uint8List blake3Digest = await hasher.finalize(); // Context is automatically freed

3. Symmetric Encryption (AES-GCM)

import 'package:ffr_crypto/ffr_crypto.dart';

Uint8List ciphertext = await AesGcm.encrypt(
  key: key256,
  plaintext: plaintext,
  nonce: nonce12,
  aad: optionalAad,
);

Uint8List decrypted = await AesGcm.decrypt(
  key: key256,
  ciphertext: ciphertext,
  nonce: nonce12,
  aad: optionalAad,
);

4. Asymmetric Cryptography (RSA-OAEP & RSA-PSS)

import 'package:ffr_crypto/ffr_crypto.dart';

// Generate key pair
RsaKeyPair pair = await RsaKeyPair.generate(2048);

// Encrypt & Decrypt
Uint8List ciphertext = await Rsa.encrypt(pair.publicKey, plaintext);
Uint8List decrypted = await Rsa.decrypt(pair.privateKey, ciphertext);

// Sign & Verify
Uint8List sig = await Rsa.sign(pair.privateKey, digest);
bool verified = await Rsa.verify(pair.publicKey, digest, sig);

5. Elliptic Curve Cryptography (ECC)

import 'package:ffr_crypto/ffr_crypto.dart';

// Ed25519 Sign/Verify
final edPair = await Ed25519.generateKeyPair();
final sig = await Ed25519.sign(privateKey: edPair.privateKey, message: msg);
final isValid = await Ed25519.verify(publicKey: edPair.publicKey, message: msg, signature: sig);

// X25519 Key Exchange
final alice = await X25519.generateKeyPair();
final bob = await X25519.generateKeyPair();
final secretAlice = await X25519.computeSharedSecret(privateKey: alice.privateKey, peerPublicKey: bob.publicKey);

6. Hybrid Encryption (ECIES)

import 'package:ffr_crypto/ffr_crypto.dart';

// Encrypt payload for recipient using their public key
Uint8List payload = await HybridEncryption.encrypt(
  recipientPublicKey: recipientPublicKey,
  plaintext: plaintext,
);

// Recipient decrypts payload using their private key
Uint8List decrypted = await HybridEncryption.decrypt(
  recipientPrivateKey: recipientPrivateKey,
  payload: payload,
);

7. Safe Resource Management (Streaming)

Since CryptoHasher retains a native pointer in Rust memory, you must ensure that memory is freed. Calling finalize() automatically releases the native resources, but if an error occurs beforehand, you must catch the error and free it manually:

import 'package:ffr_crypto/ffr_crypto.dart';

final hasher = await CryptoHasher.create(HashAlgorithm.blake3);
try {
  await hasher.update(chunk1);
  await hasher.update(chunk2);
  
  // finalize() automatically cleans up native memory context
  final digest = await hasher.finalize(); 
} catch (e) {
  // Free native resource if hash finalize was never reached
  hasher.free(); 
  rethrow;
}

8. Exception Handling

All cryptographic and memory status boundaries throw specific exceptions subclassed from CryptoException:

import 'package:ffr_crypto/ffr_crypto.dart';

try {
  final decrypted = await AesGcm.decrypt(
    key: key,
    ciphertext: manipulatedCiphertext,
    nonce: nonce,
  );
} on DecryptionException catch (e) {
  // Thrown if integrity check (AEAD tag) fails
  print('Decryption failed: Integrity check error.');
} on InvalidKeyException catch (e) {
  print('Decryption failed: Key is invalid.');
} on CryptoException catch (e) {
  print('An unexpected cryptographic error occurred: ${e.message}');
}

Libraries

ffr_crypto