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 —
|
1 Project Restructure & FRB Setup Done —
|
||||||
2 Rust Bridge Crate (DTOs + API) Done Phase 1
|
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
|
4 Platform Build Verification Not Started Phase 3
|
||||||
5 Unit Tests Not Started Phase 3
|
5 Unit Tests Not Started Phase 3
|
||||||
6 Integration Tests & Polish Not Started Phase 4, 5
|
6 Integration Tests & Polish Not Started Phase 4, 5
|
||||||
|
|
@ -267,12 +267,20 @@ Exit Criteria
|
||||||
Phase 3 — Dart API Surface
|
Phase 3 — Dart API Surface
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
:Status: Not Started
|
:Status: Done
|
||||||
:Depends on: Phase 2
|
:Depends on: Phase 2
|
||||||
|
|
||||||
**Goal:** Build the clean Dart API layer that application code will
|
**Goal:** Build the clean Dart API layer that application code will
|
||||||
consume, wired to the FRB-generated bindings.
|
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
|
Tasks
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
|
|
@ -284,50 +292,58 @@ Tasks
|
||||||
- Task
|
- Task
|
||||||
- Status
|
- Status
|
||||||
* - 3.1
|
* - 3.1
|
||||||
- Create ``lib/ccc_crypto.dart`` — primary entry point class
|
- Create ``lib/ccc_crypto.dart`` — ``abstract final class CccCrypto``
|
||||||
``CccCrypto`` with all public methods:
|
with 13 static methods: ``init``, ``listProviders``,
|
||||||
``cccInit``, ``listProviders``, ``getCapabilities``,
|
``getCapabilities``, ``encryptAead``, ``decryptAead``,
|
||||||
``encryptAead``, ``decryptAead``, ``deriveKey``,
|
``deriveKey``, ``computeMac``, ``verifyMac``, ``hash``,
|
||||||
``computeMac``, ``verifyMac``, ``hash``,
|
|
||||||
``kemGenerateKeypair``, ``kemEncapsulate``, ``kemDecapsulate``,
|
``kemGenerateKeypair``, ``kemEncapsulate``, ``kemDecapsulate``,
|
||||||
``runSelfTest``
|
``runSelfTest``; each catches ``CccCryptoError`` and rethrows
|
||||||
- ☐
|
as typed ``CccException``
|
||||||
|
- ✅
|
||||||
* - 3.2
|
* - 3.2
|
||||||
- Create ``lib/ccc_provider_catalog.dart`` — ``CccProviderCatalog``
|
- 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
|
* - 3.3
|
||||||
- Create ``lib/ccc_self_test.dart`` — ``CccSelfTestResult``
|
- 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
|
* - 3.4
|
||||||
- Create ``lib/ccc_exceptions.dart`` — structured exception
|
- Create ``lib/ccc_exceptions.dart`` — ``sealed class CccException``
|
||||||
classes (``CccUnsupportedAlgorithm``, ``CccInvalidKey``,
|
with 7 subtypes (``CccUnsupportedAlgorithm``, ``CccInvalidKey``,
|
||||||
``CccInvalidNonce``, ``CccAuthenticationFailed``,
|
``CccInvalidNonce``, ``CccAuthenticationFailed``,
|
||||||
``CccInternalError``)
|
``CccInvalidInput``, ``CccFeatureNotCompiled``,
|
||||||
- ☐
|
``CccInternalError``); factory ``CccException.from()`` using
|
||||||
|
Dart 3 switch expression/pattern matching
|
||||||
|
- ✅
|
||||||
* - 3.5
|
* - 3.5
|
||||||
- Create ``lib/ccc_algorithm_ids.dart`` — algorithm ID constants
|
- Algorithm IDs: FRB-generated enums (``CccAeadAlgorithm``,
|
||||||
matching Rust enum discriminants 1-to-1 (values from
|
``CccKdfAlgorithm``, ``CccMacAlgorithm``, ``CccHashAlgorithm``,
|
||||||
``cipher_constants.dart``); no remapping
|
``CccKemAlgorithm``) re-exported directly from barrel file;
|
||||||
- ☐
|
separate constants file not needed
|
||||||
|
- ✅
|
||||||
* - 3.6
|
* - 3.6
|
||||||
- Wire all Dart API methods to FRB-generated bindings
|
- Wire all Dart API methods to FRB-generated bindings
|
||||||
- ☐
|
- ✅
|
||||||
* - 3.7
|
* - 3.7
|
||||||
- Create barrel export file ``lib/ccc_cryptography.dart``
|
- Update barrel export file ``lib/ccc_cryptography.dart``
|
||||||
re-exporting the public API
|
re-exporting the public API (CccCrypto, enums, DTOs,
|
||||||
- ☐
|
exceptions, provider catalog, self-test)
|
||||||
|
- ✅
|
||||||
* - 3.8
|
* - 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
|
Exit Criteria
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
* ``dart analyze`` reports no errors or warnings.
|
* ✅ ``dart analyze`` reports no errors or warnings.
|
||||||
* Public API matches the contract in the architecture design doc.
|
* ✅ Public API matches the contract in the architecture design doc.
|
||||||
* No crypto logic exists in Dart — orchestration only.
|
* ✅ 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:flutter/material.dart';
|
||||||
import 'package:ccc_cryptography/src/rust/api/simple.dart';
|
import 'package:ccc_cryptography/ccc_cryptography.dart';
|
||||||
import 'package:ccc_cryptography/src/rust/frb_generated.dart';
|
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
await RustLib.init();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
await CccCrypto.init();
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -15,26 +15,36 @@ class MyApp extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MyAppState extends State<MyApp> {
|
class _MyAppState extends State<MyApp> {
|
||||||
late String greetResult;
|
String _status = 'Running self-test…';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const textStyle = TextStyle(fontSize: 25);
|
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
appBar: AppBar(title: const Text('ccc_cryptography')),
|
appBar: AppBar(title: const Text('ccc_cryptography')),
|
||||||
body: Center(
|
body: Padding(
|
||||||
child: Text(
|
padding: const EdgeInsets.all(16),
|
||||||
greetResult,
|
child: Text(_status, style: const TextStyle(fontSize: 16)),
|
||||||
style: textStyle,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
/// CCC Cryptography — Flutter plugin providing cross-platform
|
||||||
|
/// cryptographic operations via `ccc_rust` and `flutter_rust_bridge`.
|
||||||
// // The original content is temporarily commented out to allow generating a self-contained demo - feel free to uncomment later.
|
///
|
||||||
//
|
/// Usage:
|
||||||
// //
|
/// ```dart
|
||||||
// // import 'dart:async';
|
/// import 'package:ccc_cryptography/ccc_cryptography.dart';
|
||||||
// // import 'dart:ffi';
|
///
|
||||||
// // import 'dart:io';
|
/// await CccCrypto.init();
|
||||||
// // import 'dart:isolate';
|
/// final ct = await CccCrypto.encryptAead(
|
||||||
// //
|
/// algorithm: CccAeadAlgorithm.aesGcm256,
|
||||||
// // import 'ccc_cryptography_bindings_generated.dart';
|
/// key: key, nonce: nonce, plaintext: data,
|
||||||
// //
|
/// );
|
||||||
// // /// 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;
|
|
||||||
//
|
|
||||||
|
|
||||||
library;
|
library;
|
||||||
|
|
||||||
export 'src/rust/api/simple.dart';
|
// Primary API
|
||||||
export 'src/rust/frb_generated.dart' show RustLib;
|
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