NEW dart API interface for crypto providers and their capabilities
This commit is contained in:
parent
b79878a0b5
commit
37b5ca6e8d
|
|
@ -40,7 +40,7 @@ Phase Title Status Depends on
|
|||
====== ========================================== ========== ============
|
||||
1 Project Restructure & FRB Setup Done —
|
||||
2 Rust Bridge Crate (DTOs + API) Done Phase 1
|
||||
3 Dart API Surface Not Started Phase 2
|
||||
3 Dart API Surface Done Phase 2
|
||||
4 Platform Build Verification Not Started Phase 3
|
||||
5 Unit Tests Not Started Phase 3
|
||||
6 Integration Tests & Polish Not Started Phase 4, 5
|
||||
|
|
@ -267,12 +267,20 @@ Exit Criteria
|
|||
Phase 3 — Dart API Surface
|
||||
----------------------------
|
||||
|
||||
:Status: Not Started
|
||||
:Status: Done
|
||||
:Depends on: Phase 2
|
||||
|
||||
**Goal:** Build the clean Dart API layer that application code will
|
||||
consume, wired to the FRB-generated bindings.
|
||||
|
||||
Files created:
|
||||
|
||||
* ``lib/ccc_crypto.dart`` — ``CccCrypto`` static façade (13 methods)
|
||||
* ``lib/ccc_exceptions.dart`` — sealed ``CccException`` hierarchy (7 subtypes)
|
||||
* ``lib/ccc_provider_catalog.dart`` — ``CccProviderCatalog`` + ``CccAlgorithmInfo``
|
||||
* ``lib/ccc_self_test.dart`` — ``CccSelfTestResult`` + ``CccAlgorithmTestResult``
|
||||
* ``lib/ccc_cryptography.dart`` — barrel export file (updated)
|
||||
|
||||
Tasks
|
||||
~~~~~
|
||||
|
||||
|
|
@ -284,50 +292,58 @@ Tasks
|
|||
- Task
|
||||
- Status
|
||||
* - 3.1
|
||||
- Create ``lib/ccc_crypto.dart`` — primary entry point class
|
||||
``CccCrypto`` with all public methods:
|
||||
``cccInit``, ``listProviders``, ``getCapabilities``,
|
||||
``encryptAead``, ``decryptAead``, ``deriveKey``,
|
||||
``computeMac``, ``verifyMac``, ``hash``,
|
||||
- Create ``lib/ccc_crypto.dart`` — ``abstract final class CccCrypto``
|
||||
with 13 static methods: ``init``, ``listProviders``,
|
||||
``getCapabilities``, ``encryptAead``, ``decryptAead``,
|
||||
``deriveKey``, ``computeMac``, ``verifyMac``, ``hash``,
|
||||
``kemGenerateKeypair``, ``kemEncapsulate``, ``kemDecapsulate``,
|
||||
``runSelfTest``
|
||||
- ☐
|
||||
``runSelfTest``; each catches ``CccCryptoError`` and rethrows
|
||||
as typed ``CccException``
|
||||
- ✅
|
||||
* - 3.2
|
||||
- Create ``lib/ccc_provider_catalog.dart`` — ``CccProviderCatalog``
|
||||
(provider name, algorithms, efficiency/reliability scores)
|
||||
- ☐
|
||||
(provider name, per-category algorithm lists with availability,
|
||||
efficiency/reliability scores); ``CccAlgorithmInfo`` wrapper
|
||||
- ✅
|
||||
* - 3.3
|
||||
- Create ``lib/ccc_self_test.dart`` — ``CccSelfTestResult``
|
||||
(per-algorithm pass/fail, overall status, diagnostics)
|
||||
- ☐
|
||||
(per-algorithm pass/fail, overall status, diagnostics);
|
||||
``CccAlgorithmTestResult`` wrapper
|
||||
- ✅
|
||||
* - 3.4
|
||||
- Create ``lib/ccc_exceptions.dart`` — structured exception
|
||||
classes (``CccUnsupportedAlgorithm``, ``CccInvalidKey``,
|
||||
- Create ``lib/ccc_exceptions.dart`` — ``sealed class CccException``
|
||||
with 7 subtypes (``CccUnsupportedAlgorithm``, ``CccInvalidKey``,
|
||||
``CccInvalidNonce``, ``CccAuthenticationFailed``,
|
||||
``CccInternalError``)
|
||||
- ☐
|
||||
``CccInvalidInput``, ``CccFeatureNotCompiled``,
|
||||
``CccInternalError``); factory ``CccException.from()`` using
|
||||
Dart 3 switch expression/pattern matching
|
||||
- ✅
|
||||
* - 3.5
|
||||
- Create ``lib/ccc_algorithm_ids.dart`` — algorithm ID constants
|
||||
matching Rust enum discriminants 1-to-1 (values from
|
||||
``cipher_constants.dart``); no remapping
|
||||
- ☐
|
||||
- Algorithm IDs: FRB-generated enums (``CccAeadAlgorithm``,
|
||||
``CccKdfAlgorithm``, ``CccMacAlgorithm``, ``CccHashAlgorithm``,
|
||||
``CccKemAlgorithm``) re-exported directly from barrel file;
|
||||
separate constants file not needed
|
||||
- ✅
|
||||
* - 3.6
|
||||
- Wire all Dart API methods to FRB-generated bindings
|
||||
- ☐
|
||||
- ✅
|
||||
* - 3.7
|
||||
- Create barrel export file ``lib/ccc_cryptography.dart``
|
||||
re-exporting the public API
|
||||
- ☐
|
||||
- Update barrel export file ``lib/ccc_cryptography.dart``
|
||||
re-exporting the public API (CccCrypto, enums, DTOs,
|
||||
exceptions, provider catalog, self-test)
|
||||
- ✅
|
||||
* - 3.8
|
||||
- Remove old placeholder Dart code (``sum``, ``sumAsync``)
|
||||
- ☐
|
||||
- Remove old placeholder Dart code; update example app
|
||||
to use ``CccCrypto.init()`` + ``runSelfTest()`` demo
|
||||
- ✅
|
||||
|
||||
Exit Criteria
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
* ``dart analyze`` reports no errors or warnings.
|
||||
* Public API matches the contract in the architecture design doc.
|
||||
* No crypto logic exists in Dart — orchestration only.
|
||||
* ✅ ``dart analyze`` reports no errors or warnings.
|
||||
* ✅ Public API matches the contract in the architecture design doc.
|
||||
* ✅ No crypto logic exists in Dart — orchestration only.
|
||||
* ✅ ``flutter build macos`` succeeds (44.5 MB).
|
||||
|
||||
----
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:ccc_cryptography/src/rust/api/simple.dart';
|
||||
import 'package:ccc_cryptography/src/rust/frb_generated.dart';
|
||||
import 'package:ccc_cryptography/ccc_cryptography.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
await RustLib.init();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await CccCrypto.init();
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
|
|
@ -15,26 +15,36 @@ class MyApp extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> {
|
||||
late String greetResult;
|
||||
String _status = 'Running self-test…';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
greetResult = greet(name: 'Flutter');
|
||||
_runSelfTest();
|
||||
}
|
||||
|
||||
Future<void> _runSelfTest() async {
|
||||
try {
|
||||
final result = await CccCrypto.runSelfTest();
|
||||
final providers = CccCrypto.listProviders();
|
||||
setState(() {
|
||||
_status = 'Providers: ${providers.join(", ")}\n'
|
||||
'Self-test: ${result.allPassed ? "ALL PASSED" : "FAILED"}\n'
|
||||
'${result.results.map((r) => ' ${r.algoName}: ${r.passed ? "✓" : "✗ ${r.errorMessage}"}').join("\n")}';
|
||||
});
|
||||
} on CccException catch (e) {
|
||||
setState(() => _status = 'Error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const textStyle = TextStyle(fontSize: 25);
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(title: const Text('ccc_cryptography')),
|
||||
body: Center(
|
||||
child: Text(
|
||||
greetResult,
|
||||
style: textStyle,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Text(_status, style: const TextStyle(fontSize: 16)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,235 @@
|
|||
/// Primary entry point for CCC cryptographic operations.
|
||||
///
|
||||
/// All methods delegate to the Rust bridge via `flutter_rust_bridge`.
|
||||
/// No cryptographic logic exists in Dart.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// await CccCrypto.init();
|
||||
/// final ct = await CccCrypto.encryptAead(
|
||||
/// algorithm: CccAeadAlgorithm.aesGcm256,
|
||||
/// key: key,
|
||||
/// nonce: nonce,
|
||||
/// plaintext: data,
|
||||
/// aad: Uint8List(0),
|
||||
/// );
|
||||
/// ```
|
||||
library;
|
||||
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:ccc_cryptography/ccc_exceptions.dart';
|
||||
import 'package:ccc_cryptography/ccc_provider_catalog.dart';
|
||||
import 'package:ccc_cryptography/ccc_self_test.dart';
|
||||
import 'package:ccc_cryptography/src/rust/api/crypto.dart' as bridge;
|
||||
import 'package:ccc_cryptography/src/rust/api/dto.dart';
|
||||
import 'package:ccc_cryptography/src/rust/frb_generated.dart';
|
||||
|
||||
/// Static façade for all CCC cryptographic operations.
|
||||
///
|
||||
/// Call [init] once at application startup before using any other method.
|
||||
abstract final class CccCrypto {
|
||||
/// Initialise the FRB runtime and register the wolfSSL provider.
|
||||
///
|
||||
/// Must be called once before any other [CccCrypto] method.
|
||||
/// Safe to call multiple times (idempotent).
|
||||
static Future<void> init() async {
|
||||
await RustLib.init();
|
||||
await bridge.cccInit();
|
||||
}
|
||||
|
||||
// ── Provider info ────────────────────────────────────────────────────────
|
||||
|
||||
/// Return the names of all registered crypto providers.
|
||||
static List<String> listProviders() => bridge.cccListProviders();
|
||||
|
||||
/// Return the capability catalog for the default provider.
|
||||
static Future<CccProviderCatalog> getCapabilities() async {
|
||||
try {
|
||||
final caps = await bridge.cccCapabilities();
|
||||
return CccProviderCatalog.fromCapabilities(caps);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
// ── AEAD ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Encrypt [plaintext] with an AEAD algorithm.
|
||||
///
|
||||
/// Returns ciphertext with appended authentication tag.
|
||||
static Future<Uint8List> encryptAead({
|
||||
required CccAeadAlgorithm algorithm,
|
||||
required Uint8List key,
|
||||
required Uint8List nonce,
|
||||
required Uint8List plaintext,
|
||||
Uint8List? aad,
|
||||
}) async {
|
||||
try {
|
||||
return await bridge.cccAeadEncrypt(
|
||||
algorithm: algorithm,
|
||||
key: key,
|
||||
nonce: nonce,
|
||||
plaintext: plaintext,
|
||||
aad: aad ?? Uint8List(0),
|
||||
);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Decrypt [ciphertext] (with appended tag) using an AEAD algorithm.
|
||||
///
|
||||
/// Throws [CccAuthenticationFailed] if the tag does not verify.
|
||||
static Future<Uint8List> decryptAead({
|
||||
required CccAeadAlgorithm algorithm,
|
||||
required Uint8List key,
|
||||
required Uint8List nonce,
|
||||
required Uint8List ciphertext,
|
||||
Uint8List? aad,
|
||||
}) async {
|
||||
try {
|
||||
return await bridge.cccAeadDecrypt(
|
||||
algorithm: algorithm,
|
||||
key: key,
|
||||
nonce: nonce,
|
||||
ciphertext: ciphertext,
|
||||
aad: aad ?? Uint8List(0),
|
||||
);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
// ── KDF ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Derive key material of [length] bytes.
|
||||
static Future<Uint8List> deriveKey({
|
||||
required CccKdfAlgorithm algorithm,
|
||||
required Uint8List ikm,
|
||||
Uint8List? salt,
|
||||
Uint8List? info,
|
||||
required int length,
|
||||
}) async {
|
||||
try {
|
||||
return await bridge.cccKdfDerive(
|
||||
algorithm: algorithm,
|
||||
ikm: ikm,
|
||||
salt: salt ?? Uint8List(0),
|
||||
info: info ?? Uint8List(0),
|
||||
length: length,
|
||||
);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
// ── MAC ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Compute a MAC tag over [data].
|
||||
static Future<Uint8List> computeMac({
|
||||
required CccMacAlgorithm algorithm,
|
||||
required Uint8List key,
|
||||
required Uint8List data,
|
||||
}) async {
|
||||
try {
|
||||
return await bridge.cccMacCompute(
|
||||
algorithm: algorithm,
|
||||
key: key,
|
||||
data: data,
|
||||
);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify a MAC tag. Returns `true` if valid, `false` otherwise.
|
||||
static Future<bool> verifyMac({
|
||||
required CccMacAlgorithm algorithm,
|
||||
required Uint8List key,
|
||||
required Uint8List data,
|
||||
required Uint8List mac,
|
||||
}) async {
|
||||
try {
|
||||
return await bridge.cccMacVerify(
|
||||
algorithm: algorithm,
|
||||
key: key,
|
||||
data: data,
|
||||
mac: mac,
|
||||
);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Hash ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Compute a cryptographic hash of [data].
|
||||
static Future<Uint8List> hash({
|
||||
required CccHashAlgorithm algorithm,
|
||||
required Uint8List data,
|
||||
}) async {
|
||||
try {
|
||||
return await bridge.cccHash(algorithm: algorithm, data: data);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
// ── KEM ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Generate a KEM key pair.
|
||||
static Future<CccKemKeyPair> kemGenerateKeypair({
|
||||
required CccKemAlgorithm algorithm,
|
||||
}) async {
|
||||
try {
|
||||
return await bridge.cccKemGenerateKeypair(algorithm: algorithm);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// KEM encapsulation — produce ciphertext + shared secret from a public key.
|
||||
static Future<CccKemEncapResult> kemEncapsulate({
|
||||
required CccKemAlgorithm algorithm,
|
||||
required Uint8List publicKey,
|
||||
}) async {
|
||||
try {
|
||||
return await bridge.cccKemEncapsulate(
|
||||
algorithm: algorithm,
|
||||
publicKey: publicKey,
|
||||
);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// KEM decapsulation — recover shared secret from ciphertext + private key.
|
||||
static Future<Uint8List> kemDecapsulate({
|
||||
required CccKemAlgorithm algorithm,
|
||||
required Uint8List privateKey,
|
||||
required Uint8List ciphertext,
|
||||
}) async {
|
||||
try {
|
||||
return await bridge.cccKemDecapsulate(
|
||||
algorithm: algorithm,
|
||||
privateKey: privateKey,
|
||||
ciphertext: ciphertext,
|
||||
);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Self-test ────────────────────────────────────────────────────────────
|
||||
|
||||
/// Run the provider self-test suite and return a structured report.
|
||||
static Future<CccSelfTestResult> runSelfTest() async {
|
||||
try {
|
||||
final report = await bridge.cccSelfTest();
|
||||
return CccSelfTestResult.fromReport(report);
|
||||
} on CccCryptoError catch (e) {
|
||||
throw CccException.from(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,147 +1,39 @@
|
|||
// The original content is temporarily commented out to allow generating a self-contained demo - feel free to uncomment later.
|
||||
|
||||
// // The original content is temporarily commented out to allow generating a self-contained demo - feel free to uncomment later.
|
||||
//
|
||||
// //
|
||||
// // import 'dart:async';
|
||||
// // import 'dart:ffi';
|
||||
// // import 'dart:io';
|
||||
// // import 'dart:isolate';
|
||||
// //
|
||||
// // import 'ccc_cryptography_bindings_generated.dart';
|
||||
// //
|
||||
// // /// A very short-lived native function.
|
||||
// // ///
|
||||
// // /// For very short-lived functions, it is fine to call them on the main isolate.
|
||||
// // /// They will block the Dart execution while running the native function, so
|
||||
// // /// only do this for native functions which are guaranteed to be short-lived.
|
||||
// // int sum(int a, int b) => _bindings.sum(a, b);
|
||||
// //
|
||||
// // /// A longer lived native function, which occupies the thread calling it.
|
||||
// // ///
|
||||
// // /// Do not call these kind of native functions in the main isolate. They will
|
||||
// // /// block Dart execution. This will cause dropped frames in Flutter applications.
|
||||
// // /// Instead, call these native functions on a separate isolate.
|
||||
// // ///
|
||||
// // /// Modify this to suit your own use case. Example use cases:
|
||||
// // ///
|
||||
// // /// 1. Reuse a single isolate for various different kinds of requests.
|
||||
// // /// 2. Use multiple helper isolates for parallel execution.
|
||||
// // Future<int> sumAsync(int a, int b) async {
|
||||
// // final SendPort helperIsolateSendPort = await _helperIsolateSendPort;
|
||||
// // final int requestId = _nextSumRequestId++;
|
||||
// // final _SumRequest request = _SumRequest(requestId, a, b);
|
||||
// // final Completer<int> completer = Completer<int>();
|
||||
// // _sumRequests[requestId] = completer;
|
||||
// // helperIsolateSendPort.send(request);
|
||||
// // return completer.future;
|
||||
// // }
|
||||
// //
|
||||
// // const String _libName = 'ccc_cryptography';
|
||||
// //
|
||||
// // /// The dynamic library in which the symbols for [CccCryptographyBindings] can be found.
|
||||
// // final DynamicLibrary _dylib = () {
|
||||
// // if (Platform.isMacOS || Platform.isIOS) {
|
||||
// // return DynamicLibrary.open('$_libName.framework/$_libName');
|
||||
// // }
|
||||
// // if (Platform.isAndroid || Platform.isLinux) {
|
||||
// // return DynamicLibrary.open('lib$_libName.so');
|
||||
// // }
|
||||
// // if (Platform.isWindows) {
|
||||
// // return DynamicLibrary.open('$_libName.dll');
|
||||
// // }
|
||||
// // throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
|
||||
// // }();
|
||||
// //
|
||||
// // /// The bindings to the native functions in [_dylib].
|
||||
// // final CccCryptographyBindings _bindings = CccCryptographyBindings(_dylib);
|
||||
// //
|
||||
// //
|
||||
// // /// A request to compute `sum`.
|
||||
// // ///
|
||||
// // /// Typically sent from one isolate to another.
|
||||
// // class _SumRequest {
|
||||
// // final int id;
|
||||
// // final int a;
|
||||
// // final int b;
|
||||
// //
|
||||
// // const _SumRequest(this.id, this.a, this.b);
|
||||
// // }
|
||||
// //
|
||||
// // /// A response with the result of `sum`.
|
||||
// // ///
|
||||
// // /// Typically sent from one isolate to another.
|
||||
// // class _SumResponse {
|
||||
// // final int id;
|
||||
// // final int result;
|
||||
// //
|
||||
// // const _SumResponse(this.id, this.result);
|
||||
// // }
|
||||
// //
|
||||
// // /// Counter to identify [_SumRequest]s and [_SumResponse]s.
|
||||
// // int _nextSumRequestId = 0;
|
||||
// //
|
||||
// // /// Mapping from [_SumRequest] `id`s to the completers corresponding to the correct future of the pending request.
|
||||
// // final Map<int, Completer<int>> _sumRequests = <int, Completer<int>>{};
|
||||
// //
|
||||
// // /// The SendPort belonging to the helper isolate.
|
||||
// // Future<SendPort> _helperIsolateSendPort = () async {
|
||||
// // // The helper isolate is going to send us back a SendPort, which we want to
|
||||
// // // wait for.
|
||||
// // final Completer<SendPort> completer = Completer<SendPort>();
|
||||
// //
|
||||
// // // Receive port on the main isolate to receive messages from the helper.
|
||||
// // // We receive two types of messages:
|
||||
// // // 1. A port to send messages on.
|
||||
// // // 2. Responses to requests we sent.
|
||||
// // final ReceivePort receivePort = ReceivePort()
|
||||
// // ..listen((dynamic data) {
|
||||
// // if (data is SendPort) {
|
||||
// // // The helper isolate sent us the port on which we can sent it requests.
|
||||
// // completer.complete(data);
|
||||
// // return;
|
||||
// // }
|
||||
// // if (data is _SumResponse) {
|
||||
// // // The helper isolate sent us a response to a request we sent.
|
||||
// // final Completer<int> completer = _sumRequests[data.id]!;
|
||||
// // _sumRequests.remove(data.id);
|
||||
// // completer.complete(data.result);
|
||||
// // return;
|
||||
// // }
|
||||
// // throw UnsupportedError('Unsupported message type: ${data.runtimeType}');
|
||||
// // });
|
||||
// //
|
||||
// // // Start the helper isolate.
|
||||
// // await Isolate.spawn((SendPort sendPort) async {
|
||||
// // final ReceivePort helperReceivePort = ReceivePort()
|
||||
// // ..listen((dynamic data) {
|
||||
// // // On the helper isolate listen to requests and respond to them.
|
||||
// // if (data is _SumRequest) {
|
||||
// // final int result = _bindings.sum_long_running(data.a, data.b);
|
||||
// // final _SumResponse response = _SumResponse(data.id, result);
|
||||
// // sendPort.send(response);
|
||||
// // return;
|
||||
// // }
|
||||
// // throw UnsupportedError('Unsupported message type: ${data.runtimeType}');
|
||||
// // });
|
||||
// //
|
||||
// // // Send the port to the main isolate on which we can receive requests.
|
||||
// // sendPort.send(helperReceivePort.sendPort);
|
||||
// // }, receivePort.sendPort);
|
||||
// //
|
||||
// // // Wait until the helper isolate has sent us back the SendPort on which we
|
||||
// // // can start sending requests.
|
||||
// // return completer.future;
|
||||
// // }();
|
||||
// //
|
||||
//
|
||||
// library ccc_cryptography;
|
||||
//
|
||||
// export 'src/rust/api/simple.dart';
|
||||
// export 'src/rust/frb_generated.dart' show RustLib;
|
||||
//
|
||||
|
||||
/// CCC Cryptography — Flutter plugin providing cross-platform
|
||||
/// cryptographic operations via `ccc_rust` and `flutter_rust_bridge`.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// import 'package:ccc_cryptography/ccc_cryptography.dart';
|
||||
///
|
||||
/// await CccCrypto.init();
|
||||
/// final ct = await CccCrypto.encryptAead(
|
||||
/// algorithm: CccAeadAlgorithm.aesGcm256,
|
||||
/// key: key, nonce: nonce, plaintext: data,
|
||||
/// );
|
||||
/// ```
|
||||
library;
|
||||
|
||||
export 'src/rust/api/simple.dart';
|
||||
export 'src/rust/frb_generated.dart' show RustLib;
|
||||
// Primary API
|
||||
export 'ccc_crypto.dart';
|
||||
|
||||
// Algorithm enum re-exports (FRB-generated)
|
||||
export 'src/rust/api/dto.dart'
|
||||
show
|
||||
CccAeadAlgorithm,
|
||||
CccKdfAlgorithm,
|
||||
CccMacAlgorithm,
|
||||
CccHashAlgorithm,
|
||||
CccKemAlgorithm,
|
||||
CccKemKeyPair,
|
||||
CccKemEncapResult;
|
||||
|
||||
// Exceptions
|
||||
export 'ccc_exceptions.dart';
|
||||
|
||||
// Provider catalog
|
||||
export 'ccc_provider_catalog.dart';
|
||||
|
||||
// Self-test result
|
||||
export 'ccc_self_test.dart';
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
/// Structured exception classes for CCC cryptographic operations.
|
||||
///
|
||||
/// These wrap the FRB-generated [CccCryptoError] into typed Dart exceptions
|
||||
/// so consuming code can catch specific failure modes.
|
||||
library;
|
||||
|
||||
import 'package:ccc_cryptography/src/rust/api/dto.dart';
|
||||
|
||||
/// Base class for all CCC cryptographic exceptions.
|
||||
sealed class CccException implements Exception {
|
||||
/// Human-readable error description.
|
||||
final String message;
|
||||
|
||||
const CccException(this.message);
|
||||
|
||||
@override
|
||||
String toString() => '$runtimeType: $message';
|
||||
|
||||
/// Convert a FRB-generated [CccCryptoError] into the appropriate
|
||||
/// typed [CccException] subclass.
|
||||
factory CccException.from(CccCryptoError error) {
|
||||
return switch (error) {
|
||||
CccCryptoError_UnsupportedAlgorithm(:final field0) =>
|
||||
CccUnsupportedAlgorithm(field0),
|
||||
CccCryptoError_InvalidKey(:final field0) => CccInvalidKey(field0),
|
||||
CccCryptoError_InvalidNonce(:final field0) => CccInvalidNonce(field0),
|
||||
CccCryptoError_AuthenticationFailed() =>
|
||||
const CccAuthenticationFailed(),
|
||||
CccCryptoError_InvalidInput(:final field0) => CccInvalidInput(field0),
|
||||
CccCryptoError_FeatureNotCompiled(:final field0) =>
|
||||
CccFeatureNotCompiled(field0),
|
||||
CccCryptoError_InternalError(:final field0) => CccInternalError(field0),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// The requested algorithm is not supported by any registered provider.
|
||||
class CccUnsupportedAlgorithm extends CccException {
|
||||
const CccUnsupportedAlgorithm(super.message);
|
||||
}
|
||||
|
||||
/// The supplied key is invalid (wrong length, weak key, etc.).
|
||||
class CccInvalidKey extends CccException {
|
||||
const CccInvalidKey(super.message);
|
||||
}
|
||||
|
||||
/// The supplied nonce/IV is invalid (wrong length, reuse detected, etc.).
|
||||
class CccInvalidNonce extends CccException {
|
||||
const CccInvalidNonce(super.message);
|
||||
}
|
||||
|
||||
/// AEAD authentication tag verification failed — ciphertext was tampered.
|
||||
class CccAuthenticationFailed extends CccException {
|
||||
const CccAuthenticationFailed() : super('authentication failed');
|
||||
}
|
||||
|
||||
/// The supplied input data is invalid.
|
||||
class CccInvalidInput extends CccException {
|
||||
const CccInvalidInput(super.message);
|
||||
}
|
||||
|
||||
/// The requested feature/algorithm is not compiled into the provider.
|
||||
class CccFeatureNotCompiled extends CccException {
|
||||
const CccFeatureNotCompiled(super.message);
|
||||
}
|
||||
|
||||
/// An unexpected internal error occurred in the cryptographic provider.
|
||||
class CccInternalError extends CccException {
|
||||
const CccInternalError(super.message);
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/// Provider catalog — describes what a registered provider supports.
|
||||
///
|
||||
/// Wraps the FRB-generated [CccCapabilities] into a Dart-idiomatic type
|
||||
/// for querying algorithm availability and quality scores.
|
||||
library;
|
||||
|
||||
import 'package:ccc_cryptography/src/rust/api/dto.dart';
|
||||
|
||||
/// Describes the full set of capabilities for a registered provider.
|
||||
class CccProviderCatalog {
|
||||
/// Provider name (e.g. "wolfssl").
|
||||
final String providerName;
|
||||
|
||||
/// AEAD algorithms supported by this provider.
|
||||
final List<CccAlgorithmInfo> aead;
|
||||
|
||||
/// KDF algorithms supported by this provider.
|
||||
final List<CccAlgorithmInfo> kdf;
|
||||
|
||||
/// MAC algorithms supported by this provider.
|
||||
final List<CccAlgorithmInfo> mac;
|
||||
|
||||
/// Hash algorithms supported by this provider.
|
||||
final List<CccAlgorithmInfo> hash;
|
||||
|
||||
/// KEM algorithms supported by this provider.
|
||||
final List<CccAlgorithmInfo> kem;
|
||||
|
||||
const CccProviderCatalog._({
|
||||
required this.providerName,
|
||||
required this.aead,
|
||||
required this.kdf,
|
||||
required this.mac,
|
||||
required this.hash,
|
||||
required this.kem,
|
||||
});
|
||||
|
||||
/// Convert from the FRB-generated capabilities DTO.
|
||||
factory CccProviderCatalog.fromCapabilities(CccCapabilities caps) {
|
||||
return CccProviderCatalog._(
|
||||
providerName: caps.providerName,
|
||||
aead: caps.aead.map(CccAlgorithmInfo._fromEntry).toList(growable: false),
|
||||
kdf: caps.kdf.map(CccAlgorithmInfo._fromEntry).toList(growable: false),
|
||||
mac: caps.mac.map(CccAlgorithmInfo._fromEntry).toList(growable: false),
|
||||
hash: caps.hash.map(CccAlgorithmInfo._fromEntry).toList(growable: false),
|
||||
kem: caps.kem.map(CccAlgorithmInfo._fromEntry).toList(growable: false),
|
||||
);
|
||||
}
|
||||
|
||||
/// All available AEAD algorithms.
|
||||
List<CccAlgorithmInfo> get availableAead =>
|
||||
aead.where((a) => a.available).toList(growable: false);
|
||||
|
||||
/// All available KDF algorithms.
|
||||
List<CccAlgorithmInfo> get availableKdf =>
|
||||
kdf.where((a) => a.available).toList(growable: false);
|
||||
|
||||
/// All available MAC algorithms.
|
||||
List<CccAlgorithmInfo> get availableMac =>
|
||||
mac.where((a) => a.available).toList(growable: false);
|
||||
|
||||
/// All available Hash algorithms.
|
||||
List<CccAlgorithmInfo> get availableHash =>
|
||||
hash.where((a) => a.available).toList(growable: false);
|
||||
|
||||
/// All available KEM algorithms.
|
||||
List<CccAlgorithmInfo> get availableKem =>
|
||||
kem.where((a) => a.available).toList(growable: false);
|
||||
}
|
||||
|
||||
/// Describes a single algorithm's availability and quality metrics.
|
||||
class CccAlgorithmInfo {
|
||||
/// Numeric algorithm identifier (matches Rust `#[repr(u32)]`).
|
||||
final int id;
|
||||
|
||||
/// Human-readable algorithm name (e.g. "AES-256-GCM").
|
||||
final String name;
|
||||
|
||||
/// Whether this algorithm is available in the provider.
|
||||
final bool available;
|
||||
|
||||
/// Whether the algorithm produces deterministic output for the same input.
|
||||
final bool deterministicIo;
|
||||
|
||||
/// Provider-reported efficiency score (0–100).
|
||||
final int efficiencyScore;
|
||||
|
||||
/// Provider-reported reliability score (0–100).
|
||||
final int reliabilityScore;
|
||||
|
||||
const CccAlgorithmInfo({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.available,
|
||||
required this.deterministicIo,
|
||||
required this.efficiencyScore,
|
||||
required this.reliabilityScore,
|
||||
});
|
||||
|
||||
factory CccAlgorithmInfo._fromEntry(CccAlgorithmEntry e) {
|
||||
return CccAlgorithmInfo(
|
||||
id: e.algoId,
|
||||
name: e.algoName,
|
||||
available: e.capability.available,
|
||||
deterministicIo: e.capability.deterministicIo,
|
||||
efficiencyScore: e.capability.efficiencyScore,
|
||||
reliabilityScore: e.capability.reliabilityScore,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/// Self-test result — wraps the FRB-generated report into Dart-idiomatic types.
|
||||
library;
|
||||
|
||||
import 'package:ccc_cryptography/src/rust/api/dto.dart';
|
||||
|
||||
/// Result of a single algorithm's self-test.
|
||||
class CccAlgorithmTestResult {
|
||||
/// Numeric algorithm identifier.
|
||||
final int algoId;
|
||||
|
||||
/// Human-readable algorithm name.
|
||||
final String algoName;
|
||||
|
||||
/// Whether the algorithm passed its self-test.
|
||||
final bool passed;
|
||||
|
||||
/// Diagnostic message if the test failed; `null` on success.
|
||||
final String? errorMessage;
|
||||
|
||||
const CccAlgorithmTestResult({
|
||||
required this.algoId,
|
||||
required this.algoName,
|
||||
required this.passed,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
factory CccAlgorithmTestResult._fromDto(CccAlgoTestResult dto) {
|
||||
return CccAlgorithmTestResult(
|
||||
algoId: dto.algoId,
|
||||
algoName: dto.algoName,
|
||||
passed: dto.passed,
|
||||
errorMessage: dto.errorMessage,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Aggregate result of the provider self-test.
|
||||
class CccSelfTestResult {
|
||||
/// Name of the provider that was tested.
|
||||
final String providerName;
|
||||
|
||||
/// Per-algorithm test results.
|
||||
final List<CccAlgorithmTestResult> results;
|
||||
|
||||
/// Whether all algorithms passed.
|
||||
final bool allPassed;
|
||||
|
||||
const CccSelfTestResult._({
|
||||
required this.providerName,
|
||||
required this.results,
|
||||
required this.allPassed,
|
||||
});
|
||||
|
||||
/// Convert from the FRB-generated self-test report DTO.
|
||||
factory CccSelfTestResult.fromReport(CccSelfTestReport report) {
|
||||
return CccSelfTestResult._(
|
||||
providerName: report.providerName,
|
||||
results: report.results
|
||||
.map(CccAlgorithmTestResult._fromDto)
|
||||
.toList(growable: false),
|
||||
allPassed: report.allPassed,
|
||||
);
|
||||
}
|
||||
|
||||
/// Algorithms that failed their self-test.
|
||||
List<CccAlgorithmTestResult> get failures =>
|
||||
results.where((r) => !r.passed).toList(growable: false);
|
||||
}
|
||||
Loading…
Reference in New Issue