191 lines
5.5 KiB
Dart
191 lines
5.5 KiB
Dart
///
|
|
/// Data structure for crypto operations in isolates
|
|
/// Handles serialization for isolate communication
|
|
///
|
|
import 'package:worker_manager/worker_manager.dart';
|
|
import 'ccc_iso_operation_id.dart';
|
|
import 'cipher_constants.dart';
|
|
|
|
/// Type of cryptographic operation
|
|
enum OperationType {
|
|
encrypt,
|
|
decrypt;
|
|
|
|
@override
|
|
String toString() => name;
|
|
|
|
static OperationType fromString(String value) {
|
|
return OperationType.values.firstWhere(
|
|
(type) => type.name == value,
|
|
orElse: () => throw ArgumentError('Invalid OperationType: $value'),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Cryptographic operation data for isolate workers
|
|
///
|
|
/// Key derivation (future ratchet implementation):
|
|
/// - channelUuid: Scope for key derivation (each channel has unique root key)
|
|
/// - messageSequence: Per-message key derivation index
|
|
/// - Final key = ratchet(channelRootKey, messageSequence)
|
|
///
|
|
/// Same derived key encrypts: MsgData + attachment files + thumbnails
|
|
class CryptoOperation {
|
|
final String id;
|
|
final List<int> data;
|
|
final List<int> cipherSequence;
|
|
final Map<String, dynamic> params;
|
|
final OperationType type;
|
|
final WorkPriority priority;
|
|
final String channelUuid; // Channel UUID for key derivation scope
|
|
final int? messageSequence; // Future: ratchet index for per-message key
|
|
final DateTime timestamp;
|
|
|
|
/// Create new crypto operation with auto-generated ID
|
|
CryptoOperation({
|
|
required this.data,
|
|
required this.cipherSequence,
|
|
required this.params,
|
|
required this.type,
|
|
required this.channelUuid,
|
|
this.messageSequence,
|
|
this.priority = WorkPriority.high,
|
|
}) : id = CryptoOperationId.generate(),
|
|
timestamp = DateTime.now();
|
|
|
|
/// Create crypto operation with custom ID (for testing)
|
|
CryptoOperation.withId({
|
|
required this.id,
|
|
required this.data,
|
|
required this.cipherSequence,
|
|
required this.params,
|
|
required this.type,
|
|
required this.channelUuid,
|
|
this.messageSequence,
|
|
this.priority = WorkPriority.high,
|
|
}) : timestamp = DateTime.now();
|
|
|
|
/// Create operation for encryption
|
|
factory CryptoOperation.encrypt({
|
|
required List<int> plaintext,
|
|
required List<int> cipherSequence,
|
|
required Map<String, dynamic> params,
|
|
required String channelUuid,
|
|
int? messageSequence,
|
|
bool isUserMessage = false,
|
|
}) {
|
|
return CryptoOperation(
|
|
data: plaintext,
|
|
cipherSequence: cipherSequence,
|
|
params: params,
|
|
type: OperationType.encrypt,
|
|
channelUuid: channelUuid,
|
|
messageSequence: messageSequence,
|
|
priority: isUserMessage ? WorkPriority.immediately : WorkPriority.high,
|
|
);
|
|
}
|
|
|
|
/// Create operation for decryption
|
|
factory CryptoOperation.decrypt({
|
|
required List<int> ciphertext,
|
|
required List<int> cipherSequence,
|
|
required Map<String, dynamic> params,
|
|
required String channelUuid,
|
|
int? messageSequence,
|
|
}) {
|
|
return CryptoOperation(
|
|
data: ciphertext,
|
|
cipherSequence: cipherSequence,
|
|
params: params,
|
|
type: OperationType.decrypt,
|
|
channelUuid: channelUuid,
|
|
messageSequence: messageSequence,
|
|
priority: WorkPriority.high,
|
|
);
|
|
}
|
|
|
|
/// Serialize for isolate communication
|
|
Map<String, dynamic> toMap() {
|
|
return {
|
|
'id': id,
|
|
'data': data,
|
|
'cipherSequence': cipherSequence,
|
|
'params': params,
|
|
'type': type.name,
|
|
'priority': priority.index,
|
|
'channelUuid': channelUuid,
|
|
'messageSequence': messageSequence,
|
|
'timestamp': timestamp.millisecondsSinceEpoch,
|
|
};
|
|
}
|
|
|
|
/// Deserialize from isolate communication
|
|
static CryptoOperation fromMap(Map<String, dynamic> map) {
|
|
return CryptoOperation.withId(
|
|
id: map['id'] as String,
|
|
data: List<int>.from(map['data'] as List),
|
|
cipherSequence: List<int>.from(map['cipherSequence'] as List),
|
|
params: Map<String, dynamic>.from(map['params'] as Map),
|
|
type: OperationType.fromString(map['type'] as String),
|
|
channelUuid: map['channelUuid'] as String,
|
|
messageSequence: map['messageSequence'] as int?,
|
|
priority: WorkPriority.values[map['priority'] as int],
|
|
);
|
|
}
|
|
|
|
/// Get cipher sequence as human-readable string
|
|
String get cipherSequenceDescription {
|
|
return CipherConstants.getSequenceDescription(cipherSequence);
|
|
}
|
|
|
|
/// Validate cipher sequence
|
|
bool get hasValidCipherSequence {
|
|
return CipherConstants.isValidSequence(cipherSequence);
|
|
}
|
|
|
|
/// Get data size in bytes
|
|
int get dataSize => data.length;
|
|
|
|
/// Get operation age
|
|
Duration get age => DateTime.now().difference(timestamp);
|
|
|
|
/// Check if operation is high priority
|
|
bool get isHighPriority => priority == WorkPriority.immediately;
|
|
|
|
/// Copy with new priority
|
|
CryptoOperation copyWithPriority(WorkPriority newPriority) {
|
|
return CryptoOperation.withId(
|
|
id: id,
|
|
data: data,
|
|
cipherSequence: cipherSequence,
|
|
params: params,
|
|
type: type,
|
|
channelUuid: channelUuid,
|
|
messageSequence: messageSequence,
|
|
priority: newPriority,
|
|
);
|
|
}
|
|
|
|
@override
|
|
String toString() {
|
|
return 'CryptoOperation('
|
|
'id: $id, '
|
|
'type: $type, '
|
|
'dataSize: ${dataSize}B, '
|
|
'ciphers: ${cipherSequence.length}, '
|
|
'priority: $priority, '
|
|
'channel: $channelUuid'
|
|
')';
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
identical(this, other) ||
|
|
other is CryptoOperation &&
|
|
runtimeType == other.runtimeType &&
|
|
id == other.id;
|
|
|
|
@override
|
|
int get hashCode => id.hashCode;
|
|
}
|