Skip to content

Frontend Encryption Integration

Overview

The AICO frontend implements end-to-end encryption for sensitive API communications through a sophisticated handshake protocol and automatic endpoint detection. This document details the encryption architecture, implementation patterns, and integration with the backend security system.

Architecture

Core Components

  • EncryptionService: Manages encryption keys, handshake protocol, and payload encryption/decryption
  • UnifiedApiClient: Automatically routes requests to encrypted or unencrypted endpoints
  • Platform Integration: Uses Flutter Secure Storage with native Keychain/Credential Manager
  • Handshake Protocol: Establishes secure sessions with backend using X25519 key exchange

Security Flow

sequenceDiagram
    participant F as Frontend
    participant E as EncryptionService
    participant U as UnifiedApiClient
    participant B as Backend

    F->>E: Initialize encryption
    E->>E: Generate X25519 keypair
    E->>U: Create handshake request
    U->>B: POST /handshake
    B->>U: Handshake response
    U->>E: Process response
    E->>E: Derive shared secret
    E->>F: Encryption ready

    F->>U: API request (sensitive endpoint)
    U->>E: Encrypt payload
    E->>U: Encrypted data
    U->>B: POST encrypted request
    B->>U: Encrypted response
    U->>E: Decrypt response
    E->>U: Decrypted data
    U->>F: Response data

Implementation Details

EncryptionService

The EncryptionService handles all cryptographic operations using the Sodium library for high-performance, secure encryption:

class EncryptionService {
  // X25519 key exchange for session establishment
  late KeyPair _keyPair;
  late Uint8List _sharedSecret;
  String? _clientId;

  Future<void> initialize() async {
    // Generate X25519 keypair for handshake
    _keyPair = CryptoBox.generateKeyPair();
    _clientId = _generateClientId();
  }

  Future<Map<String, dynamic>> createHandshakeRequest() async {
    return {
      'handshake_request': {
        'client_public_key': base64Encode(_keyPair.publicKey),
        'client_id': _clientId,
        'protocol_version': '1.0',
      }
    };
  }

  Map<String, dynamic> encryptPayload(Map<String, dynamic> data) {
    final plaintext = utf8.encode(jsonEncode(data));
    final nonce = randomBytes(24); // XSalsa20Poly1305 nonce
    final encrypted = CryptoBox.encrypt(plaintext, nonce, _sharedSecret);

    return {
      'data': base64Encode(encrypted),
      'nonce': base64Encode(nonce),
    };
  }
}

UnifiedApiClient Integration

The UnifiedApiClient provides transparent encryption by automatically detecting which endpoints require encryption:

class UnifiedApiClient {
  // Endpoints that should NOT be encrypted
  static const _unencryptedPaths = [
    '/health',
    '/gateway/status', 
    '/gateway/metrics',
    '/docs',
    '/redoc',
    '/openapi.json',
    '/handshake',
  ];

  Future<T> request<T>(String method, String endpoint, {
    Map<String, dynamic>? data,
    T Function(Map<String, dynamic>)? fromJson,
  }) async {
    final needsEncryption = _requiresEncryption(endpoint);

    if (needsEncryption) {
      // Encrypt sensitive endpoints
      if (!_handshakeCompleted || !_encryptionService.isSessionActive) {
        throw EncryptionConnectionException(
          'No active encryption session. Call initializeEncryption() first.'
        );
      }

      final encryptedPayload = data != null ? 
        _encryptionService.encryptPayload(data) : null;

      final encryptedRequest = {
        'encrypted': true,
        'payload': encryptedPayload,
        'client_id': _encryptionService.clientId,
      };

      // Send encrypted request via Dio
      final response = await _dio.request(endpoint, 
        data: encryptedRequest,
        options: Options(method: method)
      );

      // Decrypt response if needed
      if (response.data['encrypted'] == true) {
        final decrypted = _encryptionService.decryptPayload(
          response.data['payload']
        );
        return fromJson != null ? fromJson(decrypted) : decrypted as T;
      }
    } else {
      // Use plain HTTP for public endpoints
      return _handlePlainRequest<T>(method, endpoint, data: data, fromJson: fromJson);
    }
  }
}

Platform Security Integration

Secure Key Storage

The frontend leverages platform-native secure storage for encryption keys:

// macOS: Keychain Services
// Windows: Credential Manager  
// Linux: Secret Service API
// Android: Android Keystore
// iOS: iOS Keychain

class SecureStorage {
  static const _storage = FlutterSecureStorage(
    aOptions: AndroidOptions(
      encryptedSharedPreferences: true,
    ),
    iOptions: IOSOptions(
      accessibility: IOSAccessibility.first_unlock_this_device,
    ),
  );

  Future<void> storeEncryptionKey(String key, Uint8List value) async {
    await _storage.write(
      key: key, 
      value: base64Encode(value)
    );
  }
}

Keychain Integration (macOS)

The frontend requires proper Keychain entitlements for secure key storage:

<!-- DebugProfile.entitlements & Release.entitlements -->
<dict>
  <key>keychain-access-groups</key>
  <array>
    <string>$(AppIdentifierPrefix)com.aico.frontend</string>
  </array>
  <key>com.apple.security.application-groups</key>
  <array>
    <string>group.com.aico.frontend</string>
  </array>
</dict>

Error Handling & Resilience

Encryption Failures

The system handles encryption failures gracefully with clear user feedback:

try {
  await client.initializeEncryption();
} catch (e) {
  if (e is EncryptionConnectionException) {
    // Show user-friendly error
    showError('Unable to establish secure connection. Please check your network.');
  } else {
    // Log technical details for debugging
    logger.error('Encryption initialization failed', error: e);
  }
}

Session Management

  • Automatic Renewal: Sessions are renewed before expiration
  • Graceful Degradation: Falls back to unencrypted endpoints when possible
  • Error Recovery: Automatic retry with exponential backoff
  • Session Persistence: Keys stored securely across app restarts

Security Guarantees

Cryptographic Strength

  • X25519: Elliptic curve Diffie-Hellman key exchange
  • XSalsa20Poly1305: Authenticated encryption with associated data
  • Perfect Forward Secrecy: Session keys are ephemeral
  • Zero-Knowledge: Backend cannot decrypt without client participation

Implementation Security

  • Constant-Time Operations: Sodium library prevents timing attacks
  • Memory Safety: Secure key erasure and memory protection
  • Platform Integration: Leverages OS-level security features
  • Audit Trail: Comprehensive logging for security monitoring

Testing & Validation

Unit Tests

group('EncryptionService', () {
  test('should generate valid handshake request', () async {
    final service = EncryptionService();
    await service.initialize();

    final handshake = await service.createHandshakeRequest();
    expect(handshake['handshake_request']['client_public_key'], isNotNull);
    expect(handshake['handshake_request']['client_id'], isNotNull);
  });

  test('should encrypt and decrypt payload correctly', () {
    final testData = {'message': 'Hello, World!'};
    final encrypted = service.encryptPayload(testData);
    final decrypted = service.decryptPayload(encrypted);

    expect(decrypted, equals(testData));
  });
});

Integration Tests

  • End-to-End Encryption: Full handshake and encrypted communication flow
  • Error Scenarios: Network failures, invalid keys, session expiration
  • Platform Testing: Keychain access across different platforms
  • Performance: Encryption overhead and throughput measurements

Future Enhancements

Planned Features

  • Certificate Pinning: Additional transport security for network requests
  • Hardware Security: Integration with platform hardware security modules
  • Multi-Device Sync: Secure key synchronization across user devices
  • Audit Logging: Enhanced security event logging and monitoring

Performance Optimizations

  • Key Caching: Intelligent session key caching strategies
  • Batch Encryption: Optimized encryption for multiple requests
  • Streaming Encryption: Support for large file uploads/downloads
  • Background Processing: Encryption operations on background threads

This encryption integration ensures that sensitive user data remains protected throughout the communication pipeline while maintaining excellent user experience and developer productivity.