From 657a405954bf4e45ad4f6e1f1f8b07b9ac7aee40 Mon Sep 17 00:00:00 2001 From: Sitaram Kalluri Date: Wed, 11 Dec 2024 14:43:21 +0530 Subject: [PATCH] fix: at_onboarding_cli : Consume different ivs for encryptionPrivateKey and selfEncryptionKey in apkam flow --- packages/at_onboarding_cli/CHANGELOG.md | 3 + .../onboard/at_onboarding_service_impl.dart | 79 ++++++++++++++++--- packages/at_onboarding_cli/pubspec.yaml | 6 +- .../pubspec.yaml | 5 +- 4 files changed, 76 insertions(+), 17 deletions(-) diff --git a/packages/at_onboarding_cli/CHANGELOG.md b/packages/at_onboarding_cli/CHANGELOG.md index 608638c9..46cf1524 100644 --- a/packages/at_onboarding_cli/CHANGELOG.md +++ b/packages/at_onboarding_cli/CHANGELOG.md @@ -1,3 +1,6 @@ +## 1.8.1 +- fix: Replace legacy IVs with random IVs for encrypting "defaultEncryptionPrivateKey" and "selfEncryptionKey" in APKAM flow +- build[deps]: upgrade at_persistence_secondary_server to v3.1.0 ## 1.8.0 - feat: add `unrevoke` command to the activate CLI - feat: add `delete` command to the activate CLI diff --git a/packages/at_onboarding_cli/lib/src/onboard/at_onboarding_service_impl.dart b/packages/at_onboarding_cli/lib/src/onboard/at_onboarding_service_impl.dart index 2db825fd..1a748ec7 100644 --- a/packages/at_onboarding_cli/lib/src/onboard/at_onboarding_service_impl.dart +++ b/packages/at_onboarding_cli/lib/src/onboard/at_onboarding_service_impl.dart @@ -253,15 +253,28 @@ class AtOnboardingServiceImpl implements AtOnboardingService { logProgress: logProgress, ); - var decryptedEncryptionPrivateKey = EncryptionUtil.decryptValue( + // Fetches encrypted "defaultEncryptionPrivateKey" from server. The first + // argument holds the "defaultEncryptionPrivateKey" and the second argument + // hold the Initialization Vector(IV) to decrypt the data. + // Defaults to null to support legacy IV for backward compatibility. + (String, String?) encryptedPrivateKey = await _getEncryptionPrivateKeyFromServer( - enrollmentResponse.enrollmentId, _atLookUp!), - enrollmentResponse.atAuthKeys!.apkamSymmetricKey!); + enrollmentResponse.enrollmentId, _atLookUp!); + var decryptedEncryptionPrivateKey = EncryptionUtil.decryptValue( + encryptedPrivateKey.$1, + enrollmentResponse.atAuthKeys!.apkamSymmetricKey!, + ivBase64: encryptedPrivateKey.$2); + + // Fetches encrypted "selfEncryptionKey" from server. The first + // argument holds the "selfEncryptionKey" and the second argument + // hold the Initialization Vector(IV) to decrypt the data. + // Defaults to null to support legacy IV for backward compatibility. + (String, String?) selfEncryptionKey = await _getSelfEncryptionKeyFromServer( + enrollmentResponse.enrollmentId, _atLookUp!); var decryptedSelfEncryptionKey = EncryptionUtil.decryptValue( - await _getSelfEncryptionKeyFromServer( - enrollmentResponse.enrollmentId, _atLookUp!), - enrollmentResponse.atAuthKeys!.apkamSymmetricKey!); + selfEncryptionKey.$1, enrollmentResponse.atAuthKeys!.apkamSymmetricKey!, + ivBase64: selfEncryptionKey.$2); enrollmentResponse.atAuthKeys!.defaultEncryptionPrivateKey = decryptedEncryptionPrivateKey; @@ -269,17 +282,38 @@ class AtOnboardingServiceImpl implements AtOnboardingService { decryptedSelfEncryptionKey; } - Future _getEncryptionPrivateKeyFromServer( + /// Retrieves the encryption private key and its associated initialization vector (IV) + /// from the server for a given enrollment. + /// + /// The `privateKeyCommand` is constructed using the `enrollmentIdFromServer` and + /// `AtConstants.defaultEncryptionPrivateKey` with the format: + /// `'keys:get:keyName:..__manage$_atSign'`. + /// + /// This method sends a command to the `atLookUp` service to retrieve the private key data + /// from the server, then parses the JSON result to extract the private key (`value`) and + /// the IV (`iv`). + /// + /// Throws an [AtEnrollmentException] if: + /// - The private key returned from the server is `null` or empty. + /// - There is an exception during command execution. + /// + /// Returns: + /// - A tuple containing: + /// - `encryptionPrivateKeyFromServer` - The encrypted private key string from the server. + /// - `encryptionPrivateKeyIV` - The associated IV string, if present. + Future<(String, String?)> _getEncryptionPrivateKeyFromServer( String enrollmentIdFromServer, AtLookUp atLookUp) async { var privateKeyCommand = 'keys:get:keyName:$enrollmentIdFromServer.${AtConstants.defaultEncryptionPrivateKey}.__manage$_atSign\n'; String encryptionPrivateKeyFromServer; + String? encryptionPrivateKeyIV; try { var getPrivateKeyResult = await atLookUp.executeCommand(privateKeyCommand, auth: true); getPrivateKeyResult = getPrivateKeyResult?.replaceFirst('data:', ''); var privateKeyResultJson = jsonDecode(getPrivateKeyResult!); encryptionPrivateKeyFromServer = privateKeyResultJson['value']; + encryptionPrivateKeyIV = privateKeyResultJson['iv']; if (encryptionPrivateKeyFromServer == null || encryptionPrivateKeyFromServer.isEmpty) { throw AtEnrollmentException('$privateKeyCommand returned null/empty'); @@ -288,14 +322,38 @@ class AtOnboardingServiceImpl implements AtOnboardingService { throw AtEnrollmentException( 'Exception while getting encrypted private key/self key from server: $e'); } - return encryptionPrivateKeyFromServer; + return (encryptionPrivateKeyFromServer, encryptionPrivateKeyIV); } - Future _getSelfEncryptionKeyFromServer( + /// Retrieves the self-encryption key and its associated initialization vector (IV) + /// from the server for a given enrollment. + /// + /// The `selfEncryptionKeyCommand` is constructed using the `enrollmentIdFromServer` + /// and `AtConstants.defaultSelfEncryptionKey` in the format: + /// `'keys:get:keyName:..__manage$_atSign'`. + /// + /// This method sends a command to the `atLookUp` service to retrieve the self-encryption key data + /// from the server, then parses the JSON result to extract the key (`value`) and + /// the IV (`iv`). + /// + /// Throws an [AtEnrollmentException] if: + /// - The self-encryption key returned from the server is `null` or empty. + /// - There is an exception during the command execution. + /// + /// Parameters: + /// - `enrollmentIdFromServer` - The enrollment ID used to request the self-encryption key. + /// - `atLookUp` - The [AtLookUp] instance to execute the server command. + /// + /// Returns: + /// - A tuple containing: + /// - `selfEncryptionKeyFromServer` - The self-encryption key string retrieved from the server. + /// - `selfEncryptionKeyIV` - The associated IV string, if present. + Future<(String, String?)> _getSelfEncryptionKeyFromServer( String enrollmentIdFromServer, AtLookUp atLookUp) async { var selfEncryptionKeyCommand = 'keys:get:keyName:$enrollmentIdFromServer.${AtConstants.defaultSelfEncryptionKey}.__manage$_atSign\n'; String selfEncryptionKeyFromServer; + String? selfEncryptionKeyIV; try { var getSelfEncryptionKeyResult = await atLookUp.executeCommand(selfEncryptionKeyCommand, auth: true); @@ -303,6 +361,7 @@ class AtOnboardingServiceImpl implements AtOnboardingService { getSelfEncryptionKeyResult?.replaceFirst('data:', ''); var selfEncryptionKeyResultJson = jsonDecode(getSelfEncryptionKeyResult!); selfEncryptionKeyFromServer = selfEncryptionKeyResultJson['value']; + selfEncryptionKeyIV = selfEncryptionKeyResultJson['iv']; if (selfEncryptionKeyFromServer == null || selfEncryptionKeyFromServer.isEmpty) { throw AtEnrollmentException( @@ -312,7 +371,7 @@ class AtOnboardingServiceImpl implements AtOnboardingService { throw AtEnrollmentException( 'Exception while getting encrypted private key/self key from server: $e'); } - return selfEncryptionKeyFromServer; + return (selfEncryptionKeyFromServer, selfEncryptionKeyIV); } /// Pkam auth will be retried until server approves/denies/expires the enrollment diff --git a/packages/at_onboarding_cli/pubspec.yaml b/packages/at_onboarding_cli/pubspec.yaml index 7de808db..278148ce 100644 --- a/packages/at_onboarding_cli/pubspec.yaml +++ b/packages/at_onboarding_cli/pubspec.yaml @@ -1,6 +1,6 @@ name: at_onboarding_cli description: Dart tools for initial client onboarding, subsequent client enrollment, and enrollment management. -version: 1.8.0 +version: 1.8.1 repository: https://github.com/atsign-foundation/at_libraries homepage: https://atsign.com documentation: https://docs.atsign.com/ @@ -21,14 +21,14 @@ dependencies: meta: ^1.14.0 path: ^1.9.0 zxing2: ^0.2.0 - at_auth: ^2.0.9 + at_auth: ^2.0.10 at_chops: ^2.2.0 at_client: ^3.3.0 at_commons: ^5.0.2 at_lookup: ^3.0.49 at_server_status: ^1.0.5 at_utils: ^3.0.19 - at_persistence_secondary_server: ^3.0.66 + at_persistence_secondary_server: ^3.1.0 duration: ^4.0.3 crypto: ^3.0.5 chalkdart: ^2.0.9 diff --git a/tests/at_onboarding_cli_functional_tests/pubspec.yaml b/tests/at_onboarding_cli_functional_tests/pubspec.yaml index 3950df99..1e6171f4 100644 --- a/tests/at_onboarding_cli_functional_tests/pubspec.yaml +++ b/tests/at_onboarding_cli_functional_tests/pubspec.yaml @@ -16,10 +16,7 @@ dependency_overrides: at_auth: path: ../../packages/at_auth at_onboarding_cli: - git: - url: https://github.com/atsign-foundation/at_libraries.git - path: packages/at_onboarding_cli - ref: at-onboarding-cli-apkam-different-ivs + path: ../../packages/at_onboarding_cli at_commons: path: ../../packages/at_commons at_chops: