lum_ccc_rust/flutter_src/ccc/ccc_channel_profile.dart

322 lines
10 KiB
Dart

///
/// Channel-level CCC profile derivation.
///
import 'package:letusmsg/ccc/ccc_kdf.dart';
import 'package:letusmsg/ccc/cipher_constants.dart';
import 'package:letusmsg/ccc/ccc_provider_spec.dart';
import 'package:letusmsg/data/ccc_data.dart';
/// One resolved cipher execution step for a channel CCC route.
///
/// The step identifies a primary provider and optional ordered fallbacks.
class CccRouteStep {
final int cipher;
final CccCryptoProvider provider;
final List<CccCryptoProvider> fallbackProviders;
const CccRouteStep({
required this.cipher,
required this.provider,
required this.fallbackProviders,
});
Map<String, dynamic> toMap() {
return {
'cipher': cipher,
'provider': provider.name,
'fallbackProviders': fallbackProviders.map((item) => item.name).toList(growable: false),
};
}
}
/// Concrete cipher configuration derived from per-channel `CCCData`.
class ChannelCccProfile {
final int combo;
final int iterations;
final CccExecutionMode executionMode;
final bool allowFallback;
final List<CccProviderSpec> providers;
final List<CccRouteStep> route;
final List<int> cipherSequence;
final Map<String, dynamic> cipherParams;
const ChannelCccProfile({
required this.combo,
required this.iterations,
required this.executionMode,
required this.allowFallback,
required this.providers,
required this.route,
required this.cipherSequence,
required this.cipherParams,
});
static const int _maxIterations = 16;
factory ChannelCccProfile.fromCccData(CCCData? cccData) {
final combo = cccData?.combo ?? 0;
final rawIterations = cccData?.iterrations ?? 0;
final kdfFunctionValue = normalizeCccKdfFunctionValue(cccData?.kdfFunction);
final kdfFunction = cccKdfFunctionFromInt(kdfFunctionValue);
final executionMode = cccExecutionModeFromString(cccData?.executionMode ?? 'auto');
final iterations = rawIterations <= 0
? 1
: rawIterations.clamp(1, _maxIterations);
final allowFallback = executionMode != CccExecutionMode.strict;
final providers = _providersForCombo(combo);
final route = _resolveRoute(providers, executionMode: executionMode, allowFallback: allowFallback);
final baseSequence = route.map((item) => item.cipher).toList(growable: false);
final expandedSequence = <int>[];
for (var i = 0; i < iterations; i++) {
expandedSequence.addAll(baseSequence);
}
final params = <String, dynamic>{
...CipherConstants.DEFAULT_CIPHER_PARAMS,
'ccc_combo': combo,
'ccc_iterations': iterations,
'ccc_kdf_function': kdfFunction.name,
'ccc_kdf_function_value': kdfFunction.value,
'ccc_execution_mode': executionMode.name,
'ccc_allow_fallback': allowFallback,
'ccc_providers': providers.map((provider) => provider.toMap()).toList(growable: false),
'ccc_route': route.map((step) => step.toMap()).toList(growable: false),
// Phase 3: length-hiding padding parameters
'ccc_min_padding_bytes': cccData?.minPaddingBytes ?? 32,
'ccc_block_size': cccData?.blockSize ?? 256,
};
return ChannelCccProfile(
combo: combo,
iterations: iterations,
executionMode: executionMode,
allowFallback: allowFallback,
providers: providers,
route: route,
cipherSequence: expandedSequence,
cipherParams: params,
);
}
static List<CccRouteStep> _resolveRoute(
List<CccProviderSpec> providers, {
required CccExecutionMode executionMode,
required bool allowFallback,
}) {
final strictRoute = <CccRouteStep>[];
for (final provider in providers) {
for (final cipher in provider.ciphers) {
strictRoute.add(CccRouteStep(
cipher: cipher,
provider: provider.provider,
fallbackProviders: const [],
));
}
}
if (executionMode == CccExecutionMode.strict) {
return strictRoute;
}
final optimizedRoute = <CccRouteStep>[];
for (final step in strictRoute) {
final ordered = _orderedProviderCandidates(
cipher: step.cipher,
configuredProviders: providers.map((item) => item.provider).toSet(),
executionMode: executionMode,
);
final primary = ordered.isNotEmpty ? ordered.first : step.provider;
final fallbacks = allowFallback
? ordered.where((provider) => provider != primary).toList(growable: false)
: const <CccCryptoProvider>[];
optimizedRoute.add(CccRouteStep(
cipher: step.cipher,
provider: primary,
fallbackProviders: fallbacks,
));
}
return optimizedRoute;
}
static List<CccCryptoProvider> _orderedProviderCandidates({
required int cipher,
required Set<CccCryptoProvider> configuredProviders,
required CccExecutionMode executionMode,
}) {
final configured = configuredProviders.where((provider) {
return CccProviderCatalog.supports(provider, cipher);
}).toList(growable: false);
if (executionMode == CccExecutionMode.efficient) {
final rankedConfigured = List<CccCryptoProvider>.from(configured)
..sort((a, b) {
final capA = CccProviderCatalog.capability(a, cipher);
final capB = CccProviderCatalog.capability(b, cipher);
final perf = (capB?.efficiencyScore ?? 0).compareTo(capA?.efficiencyScore ?? 0);
if (perf != 0) return perf;
return (capB?.reliabilityScore ?? 0).compareTo(capA?.reliabilityScore ?? 0);
});
return rankedConfigured;
}
final availableRanked = CccProviderCatalog.providersSupporting(cipher, availableOnly: true)
.where(configuredProviders.contains)
.toList(growable: false);
final unavailableRanked = CccProviderCatalog.providersSupporting(cipher, availableOnly: false)
.where((provider) => configuredProviders.contains(provider) && !availableRanked.contains(provider))
.toList(growable: false);
return [
...availableRanked,
...unavailableRanked,
];
}
static List<CccProviderSpec> _providersForCombo(int combo) {
switch (combo) {
case 0:
// Combo 0 is reserved as the plaintext / unencrypted legacy combo.
// It produces an empty cipher sequence so the CCC pipeline serializes
// and deserializes JSON only, with no encryption layers applied.
// Backwards-compatible with all channels created before Normal Mode.
// When Normal Mode is complete, CCCData.blank() will be updated to a
// real encrypted combo (e.g. combo 5 or higher) and combo 0 will
// remain available only for migration/legacy channels.
return [];
case 1:
return [
CccProviderSpec(
provider: CccCryptoProvider.wolfssl,
ciphers: [
CipherConstants.AES_GCM_256,
CipherConstants.CHACHA20_POLY1305,
],
),
CccProviderSpec(
provider: CccCryptoProvider.cryptography,
ciphers: [
CipherConstants.HMAC_SHA512,
CipherConstants.BLAKE2B,
],
),
];
case 2:
return [
CccProviderSpec(
provider: CccCryptoProvider.boringssl,
ciphers: [
CipherConstants.CHACHA20_POLY1305,
CipherConstants.XCHACHA20_POLY1305,
],
),
CccProviderSpec(
provider: CccCryptoProvider.cryptography,
ciphers: [
CipherConstants.AES_GCM_256,
],
),
];
case 3:
return [
CccProviderSpec(
provider: CccCryptoProvider.openssl,
ciphers: [
CipherConstants.AES_GCM_256,
],
),
CccProviderSpec(
provider: CccCryptoProvider.wolfssl,
ciphers: [
CipherConstants.CHACHA20_POLY1305,
],
),
CccProviderSpec(
provider: CccCryptoProvider.cryptography,
ciphers: [
CipherConstants.BLAKE2B,
],
),
];
case 4:
return [
CccProviderSpec(
provider: CccCryptoProvider.wolfssl,
ciphers: [
CipherConstants.XCHACHA20_POLY1305,
],
),
CccProviderSpec(
provider: CccCryptoProvider.openssl,
ciphers: [
CipherConstants.HMAC_SHA512,
],
),
CccProviderSpec(
provider: CccCryptoProvider.cryptography,
ciphers: [
CipherConstants.BLAKE2B,
],
),
];
// --- Basic / user-selectable combos (5-9) ---
case 5:
// Basic: single AES-256-GCM
return [
CccProviderSpec(
provider: CccCryptoProvider.cryptography,
ciphers: List<int>.from(CipherConstants.BASIC_AES_SEQUENCE),
),
];
case 6:
// Basic: single ChaCha20-Poly1305
return [
CccProviderSpec(
provider: CccCryptoProvider.cryptography,
ciphers: List<int>.from(CipherConstants.BASIC_CHACHA_SEQUENCE),
),
];
case 7:
// Basic: single XChaCha20-Poly1305
return [
CccProviderSpec(
provider: CccCryptoProvider.cryptography,
ciphers: List<int>.from(CipherConstants.BASIC_XCHACHA_SEQUENCE),
),
];
case 8:
// Dual AEAD: AES-256-GCM + ChaCha20-Poly1305
return [
CccProviderSpec(
provider: CccCryptoProvider.cryptography,
ciphers: List<int>.from(CipherConstants.DUAL_AEAD_SEQUENCE),
),
];
case 9:
// Triple AEAD: AES + ChaCha20 + XChaCha20
return [
CccProviderSpec(
provider: CccCryptoProvider.cryptography,
ciphers: List<int>.from(CipherConstants.TRIPLE_AEAD_SEQUENCE),
),
];
default:
// Unknown combo falls back to standard 5-layer
return [
CccProviderSpec(
provider: CccCryptoProvider.cryptography,
ciphers: List<int>.from(CipherConstants.PHASE1_SEQUENCE),
),
];
}
}
}