lum_ccc_rust/flutter_src/ccc/ccc_iso_manager.dart

248 lines
7.6 KiB
Dart

///
/// Crypto Isolate Manager
/// Manages worker pool for encryption/decryption operations
///
import 'dart:async';
import 'package:worker_manager/worker_manager.dart';
import 'ccc_iso_operation.dart';
import 'ccc_iso_result.dart';
import 'ccc_iso_operation_id.dart';
import 'ccc_iso.dart';
import 'cipher_constants.dart';
/// Manages isolate workers for cryptographic operations
///
/// CCC (Copius Cipher Chain) Architecture:
/// - Single encryption system for ALL data (messages, attachments, thumbnails)
/// - Uses channel UUID for key derivation scope
/// - Same key encrypts message + its attachments (bundled together)
/// - Used for both over-the-wire AND local storage encryption
///
/// FUTURE WORK: Ratchet System
/// - Per-message key derivation using Double Ratchet algorithm
/// - Keys derived from: channelUuid + messageSequence + rootKey
/// - Forward secrecy: compromise of one key doesn't reveal past messages
/// - Break-in recovery: new keys derived after compromise
///
/// Current State: Full CCC encryption with isolate workers
/// Future: Ratchet key derivation integration
class CryptoIsolateManager {
// Performance tracking
final CryptoMetrics _metrics = CryptoMetrics();
// Configuration
static const Duration OPERATION_TIMEOUT = Duration(seconds: 30);
static const int WORKER_POOL_SIZE = 4; // Fixed pool of 4 workers
bool _initialized = false;
bool _disposed = false;
/// Initialize the crypto isolate manager
Future<void> initialize() async {
if (_initialized) return;
// Initialize operation ID generator
CryptoOperationId.initialize();
// Configure worker manager with fixed pool size
await workerManager.init(isolatesCount: WORKER_POOL_SIZE);
_initialized = true;
}
/// Encrypt data with specified cipher sequence
/// In passthrough mode, returns data unchanged (for development)
///
/// [channelUuid] - Channel UUID for key derivation scope
/// [messageSequence] - Message sequence number for per-message key derivation (future: ratchet)
/// [isUserMessage] - Priority flag for worker queue
///
/// FUTURE: When ratchet is implemented, key = derive(channelRootKey, messageSequence)
/// Same key will encrypt: MsgData + all attachment files + all thumbnails for that message
Future<CryptoResult> encrypt(
List<int> plaintext, {
required String channelUuid,
int? messageSequence, // Future: used for ratchet key derivation
List<int>? cipherSequence,
Map<String, dynamic>? params,
bool isUserMessage = false,
}) async {
_ensureInitialized();
final operation = CryptoOperation.encrypt(
plaintext: plaintext,
cipherSequence: cipherSequence ?? CipherConstants.PHASE1_SEQUENCE,
params: params ?? CipherConstants.DEFAULT_CIPHER_PARAMS,
channelUuid: channelUuid,
messageSequence: messageSequence,
isUserMessage: isUserMessage,
);
return await _executeOperation(operation);
}
/// Decrypt data with specified cipher sequence
/// In passthrough mode, returns data unchanged (for development)
///
/// [channelUuid] - Channel UUID for key derivation scope
/// [messageSequence] - Message sequence number for per-message key derivation (future: ratchet)
///
/// FUTURE: When ratchet is implemented, key = derive(channelRootKey, messageSequence)
Future<CryptoResult> decrypt(
List<int> ciphertext, {
required String channelUuid,
int? messageSequence, // Future: used for ratchet key derivation
List<int>? cipherSequence,
Map<String, dynamic>? params,
}) async {
_ensureInitialized();
final operation = CryptoOperation.decrypt(
ciphertext: ciphertext,
cipherSequence: cipherSequence ?? CipherConstants.PHASE1_SEQUENCE,
params: params ?? CipherConstants.DEFAULT_CIPHER_PARAMS,
channelUuid: channelUuid,
messageSequence: messageSequence,
);
return await _executeOperation(operation);
}
/// Execute a crypto operation
Future<CryptoResult> _executeOperation(CryptoOperation operation) async {
_ensureInitialized();
if (_disposed) {
throw StateError('CryptoIsolateManager has been disposed');
}
try {
// Execute using the global workerManager with correct API
final resultMap = await workerManager.execute<Map<String, dynamic>>(
() => cryptoWorkerFunction(operation.toMap()),
priority: operation.priority,
).timeout(OPERATION_TIMEOUT);
// Deserialize result
final result = CryptoResult.fromMap(resultMap);
// Update metrics
_updateMetrics(operation, result);
return result;
} catch (error, stackTrace) {
// Create error result
final result = CryptoResult.error(
operationId: operation.id,
error: error.toString(),
stackTrace: stackTrace.toString(),
processingTime: operation.age,
workerId: 'manager_error',
);
// Update metrics
_metrics.recordError();
return result;
}
}
/// Update performance metrics
void _updateMetrics(CryptoOperation operation, CryptoResult result) {
if (result.success) {
if (operation.type == OperationType.encrypt) {
_metrics.recordEncryption(result.processingTime, operation.isHighPriority);
} else {
_metrics.recordDecryption(result.processingTime);
}
} else {
_metrics.recordError();
}
}
/// Get current performance metrics
CryptoMetrics get metrics => _metrics;
/// Get worker manager stats
String get workerStats {
return 'Crypto Manager Stats: ${_metrics.toString()}';
}
/// Check if manager is ready
bool get isReady => _initialized && !_disposed;
/// Ensure manager is initialized
void _ensureInitialized() {
if (!_initialized) {
throw StateError('CryptoIsolateManager must be initialized before use');
}
if (_disposed) {
throw StateError('CryptoIsolateManager has been disposed');
}
}
/// Dispose the isolate manager and clean up resources
Future<void> dispose() async {
if (_disposed) return;
_disposed = true;
// Dispose global worker manager
try {
await workerManager.dispose();
} catch (e) {
// Ignore disposal errors
}
// Clear metrics
_metrics.reset();
}
/// Create a test operation (for debugging)
Future<CryptoResult> testOperation({
String testData = 'Hello, Crypto World!',
String channelUuid = 'test-channel-uuid',
}) async {
final plaintext = testData.codeUnits;
// Encrypt
final encryptResult = await encrypt(
plaintext,
channelUuid: channelUuid,
isUserMessage: true,
);
if (!encryptResult.success) {
return encryptResult;
}
// Decrypt
final decryptResult = await decrypt(
encryptResult.data,
channelUuid: channelUuid,
);
if (!decryptResult.success) {
return decryptResult;
}
// Verify roundtrip
final decryptedText = String.fromCharCodes(decryptResult.data);
if (decryptedText == testData) {
return CryptoResult.success(
operationId: 'test_roundtrip',
data: decryptResult.data,
processingTime: encryptResult.processingTime + decryptResult.processingTime,
workerId: 'test_manager',
);
} else {
return CryptoResult.error(
operationId: 'test_roundtrip',
error: 'Roundtrip failed: expected "$testData", got "$decryptedText"',
processingTime: encryptResult.processingTime + decryptResult.processingTime,
workerId: 'test_manager',
);
}
}
}