Skip to content

Commit e43bc1a

Browse files
authored
Merge pull request #1185 from atsign-foundation/replace_encryption_util_methods
feat: Replace EncryptionUtil decryption methods with at_chops
2 parents 795a70f + a3612b1 commit e43bc1a

File tree

8 files changed

+540
-80
lines changed

8 files changed

+540
-80
lines changed

packages/at_client/lib/src/decryption_service/local_key_decryption.dart

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:at_chops/at_chops.dart';
12
import 'package:at_client/at_client.dart';
23
import 'package:at_client/src/decryption_service/decryption.dart';
34
import 'package:at_client/src/encryption_service/abstract_atkey_encryption.dart';
@@ -10,10 +11,11 @@ import 'package:at_utils/at_logger.dart';
1011
class LocalKeyDecryption extends AbstractAtKeyEncryption
1112
implements AtKeyDecryption {
1213
late final AtSignLogger _logger;
14+
final AtClient _atClient;
1315

14-
LocalKeyDecryption(AtClient atClient) : super(atClient) {
16+
LocalKeyDecryption(this._atClient) : super(_atClient) {
1517
_logger =
16-
AtSignLogger('LocalKeyDecryption (${atClient.getCurrentAtSign()})');
18+
AtSignLogger('LocalKeyDecryption (${_atClient.getCurrentAtSign()})');
1719
}
1820

1921
@override
@@ -32,7 +34,25 @@ class LocalKeyDecryption extends AbstractAtKeyEncryption
3234
intent: Intent.fetchEncryptionSharedKey,
3335
exceptionScenario: ExceptionScenario.fetchEncryptionKeys);
3436
}
35-
return EncryptionUtil.decryptValue(encryptedValue, symmetricKey,
36-
ivBase64: atKey.metadata?.ivNonce);
37+
InitialisationVector iV;
38+
if (atKey.metadata?.ivNonce != null) {
39+
iV = AtChopsUtil.generateIVFromBase64String(atKey.metadata!.ivNonce!);
40+
} else {
41+
iV = AtChopsUtil.generateIVLegacy();
42+
}
43+
AtEncryptionResult decryptionResultFromAtChops;
44+
try {
45+
var encryptionAlgo = AESEncryptionAlgo(AESKey(symmetricKey));
46+
decryptionResultFromAtChops = _atClient.atChops!.decryptString(
47+
encryptedValue, EncryptionKeyType.aes256,
48+
encryptionAlgorithm: encryptionAlgo, iv: iV);
49+
_logger.finer(
50+
'decryptionResultFromAtChops: ${decryptionResultFromAtChops.result}');
51+
} on AtDecryptionException catch (e) {
52+
_logger.severe(
53+
'decryption exception during of key: ${atKey.key}. Reason: ${e.toString()}');
54+
rethrow;
55+
}
56+
return decryptionResultFromAtChops.result;
3757
}
3858
}

packages/at_client/lib/src/decryption_service/self_key_decryption.dart

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import 'package:at_client/at_client.dart';
2+
import 'package:at_chops/at_chops.dart';
3+
import 'package:at_utils/at_logger.dart';
24
import 'package:at_client/src/decryption_service/decryption.dart';
35
import 'package:at_client/src/response/default_response_parser.dart';
46

@@ -9,7 +11,11 @@ import 'package:at_client/src/response/default_response_parser.dart';
911
/// llookup:@bob:phone@bob
1012
class SelfKeyDecryption implements AtKeyDecryption {
1113
final AtClient _atClient;
12-
SelfKeyDecryption(this._atClient);
14+
late final AtSignLogger _logger;
15+
SelfKeyDecryption(this._atClient) {
16+
_logger =
17+
AtSignLogger('SelfKeyDecryption (${_atClient.getCurrentAtSign()})');
18+
}
1319
@override
1420
Future<dynamic> decrypt(AtKey atKey, dynamic encryptedValue) async {
1521
if (encryptedValue == null ||
@@ -29,8 +35,24 @@ class SelfKeyDecryption implements AtKeyDecryption {
2935
exceptionScenario: ExceptionScenario.fetchEncryptionKeys);
3036
}
3137

32-
return EncryptionUtil.decryptValue(encryptedValue,
33-
DefaultResponseParser().parse(selfEncryptionKey).response,
34-
ivBase64: atKey.metadata?.ivNonce);
38+
InitialisationVector iV;
39+
if (atKey.metadata?.ivNonce != null) {
40+
iV = AtChopsUtil.generateIVFromBase64String(atKey.metadata!.ivNonce!);
41+
} else {
42+
iV = AtChopsUtil.generateIVLegacy();
43+
}
44+
AtEncryptionResult decryptionResultFromAtChops;
45+
try {
46+
var encryptionAlgo = AESEncryptionAlgo(
47+
AESKey(DefaultResponseParser().parse(selfEncryptionKey).response));
48+
decryptionResultFromAtChops = _atClient.atChops!.decryptString(
49+
encryptedValue, EncryptionKeyType.aes256,
50+
encryptionAlgorithm: encryptionAlgo, iv: iV);
51+
} on AtDecryptionException catch (e) {
52+
_logger.severe(
53+
'decryption exception during of key: ${atKey.key}. Reason: ${e.toString()}');
54+
rethrow;
55+
}
56+
return decryptionResultFromAtChops.result;
3557
}
3658
}

packages/at_client/lib/src/decryption_service/shared_key_decryption.dart

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import 'package:at_client/src/util/encryption_util.dart';
55
import 'package:at_commons/at_builders.dart';
66
import 'package:at_commons/at_commons.dart';
77
import 'package:at_utils/at_logger.dart';
8-
import 'package:meta/meta.dart';
98
import 'package:at_chops/at_chops.dart';
109

1110
/// Class responsible for decrypting the value of shared key's that are not owned
@@ -14,13 +13,12 @@ import 'package:at_chops/at_chops.dart';
1413
/// CurrentAtSign: @bob
1514
/// lookup:phone@alice
1615
class SharedKeyDecryption implements AtKeyDecryption {
17-
@visibleForTesting
18-
final AtClient atClient;
16+
final AtClient _atClient;
1917
late final AtSignLogger _logger;
2018

21-
SharedKeyDecryption(this.atClient) {
19+
SharedKeyDecryption(this._atClient) {
2220
_logger =
23-
AtSignLogger('SharedKeyDecryption (${atClient.getCurrentAtSign()})');
21+
AtSignLogger('SharedKeyDecryption (${_atClient.getCurrentAtSign()})');
2422
}
2523

2624
@override
@@ -31,64 +29,76 @@ class SharedKeyDecryption implements AtKeyDecryption {
3129
exceptionScenario: ExceptionScenario.decryptionFailed);
3230
}
3331
String? encryptedSharedKey;
34-
if (atKey.metadata != null && atKey.metadata!.pubKeyCS != null) {
32+
if (atKey.metadata != null) {
3533
encryptedSharedKey = atKey.metadata!.sharedKeyEnc;
36-
String? currentAtSignPublicKey;
37-
try {
38-
currentAtSignPublicKey = (await atClient
39-
.getLocalSecondary()!
40-
.getEncryptionPublicKey(atClient.getCurrentAtSign()!))
41-
?.trim();
42-
} on KeyNotFoundException {
43-
throw AtPublicKeyNotFoundException(
44-
'Failed to fetch the current atSign public key - public:publickey${atClient.getCurrentAtSign()!}',
45-
intent: Intent.fetchEncryptionPublicKey,
46-
exceptionScenario: ExceptionScenario.localVerbExecutionFailed);
47-
}
48-
if (currentAtSignPublicKey != null &&
49-
atKey.metadata!.pubKeyCS !=
50-
EncryptionUtil.md5CheckSum(currentAtSignPublicKey)) {
51-
throw AtPublicKeyChangeException(
52-
'Public key has changed. Cannot decrypt shared key ${atKey.toString()}',
53-
intent: Intent.fetchEncryptionPublicKey,
54-
exceptionScenario: ExceptionScenario.encryptionFailed);
55-
}
56-
} else {
57-
encryptedSharedKey = await _getEncryptedSharedKey(atKey);
5834
}
59-
if (encryptedSharedKey == null ||
60-
encryptedSharedKey.isEmpty ||
61-
encryptedSharedKey == 'null') {
35+
encryptedSharedKey ??= await _getEncryptedSharedKey(atKey);
36+
if (encryptedSharedKey.isEmpty || encryptedSharedKey == 'null') {
6237
throw SharedKeyNotFoundException('shared encryption key not found',
6338
intent: Intent.fetchEncryptionSharedKey,
6439
exceptionScenario: ExceptionScenario.fetchEncryptionKeys);
6540
}
66-
String decryptedValue = '';
41+
String? currentAtSignPublicKey;
42+
try {
43+
currentAtSignPublicKey = (await _atClient
44+
.getLocalSecondary()!
45+
.getEncryptionPublicKey(_atClient.getCurrentAtSign()!))
46+
?.trim();
47+
} on KeyNotFoundException {
48+
throw AtPublicKeyNotFoundException(
49+
'Failed to fetch the current atSign public key - public:publickey${_atClient.getCurrentAtSign()!}',
50+
intent: Intent.fetchEncryptionPublicKey,
51+
exceptionScenario: ExceptionScenario.localVerbExecutionFailed);
52+
}
53+
if (currentAtSignPublicKey != null &&
54+
atKey.metadata != null &&
55+
atKey.metadata!.pubKeyCS != null &&
56+
atKey.metadata!.pubKeyCS !=
57+
EncryptionUtil.md5CheckSum(currentAtSignPublicKey)) {
58+
throw AtPublicKeyChangeException(
59+
'Public key has changed. Cannot decrypt shared key ${atKey.toString()}',
60+
intent: Intent.fetchEncryptionPublicKey,
61+
exceptionScenario: ExceptionScenario.decryptionFailed);
62+
}
63+
64+
AtEncryptionResult decryptionResultFromAtChops;
6765
try {
68-
final decryptionResult = atClient.atChops!
66+
InitialisationVector iV;
67+
if (atKey.metadata?.ivNonce != null) {
68+
iV = AtChopsUtil.generateIVFromBase64String(atKey.metadata!.ivNonce!);
69+
} else {
70+
iV = AtChopsUtil.generateIVLegacy();
71+
}
72+
final decryptionResult = _atClient.atChops!
6973
.decryptString(encryptedSharedKey, EncryptionKeyType.rsa2048);
70-
decryptedValue = EncryptionUtil.decryptValue(
71-
encryptedValue, decryptionResult.result,
72-
ivBase64: atKey.metadata?.ivNonce);
74+
var encryptionAlgo = AESEncryptionAlgo(AESKey(
75+
DefaultResponseParser().parse(decryptionResult.result).response));
76+
decryptionResultFromAtChops = _atClient.atChops!.decryptString(
77+
encryptedValue, EncryptionKeyType.aes256,
78+
encryptionAlgorithm: encryptionAlgo, iv: iV);
7379
} on AtKeyException catch (e) {
7480
e.stack(AtChainedException(
7581
Intent.decryptData,
7682
ExceptionScenario.decryptionFailed,
7783
'Failed to decrypt ${atKey.toString()}'));
7884
rethrow;
85+
} on AtDecryptionException catch (e) {
86+
_logger.severe(
87+
'decryption exception during of key: ${atKey.key}. Reason: ${e.toString()}');
88+
rethrow;
7989
}
80-
return decryptedValue;
90+
return decryptionResultFromAtChops.result;
8191
}
8292

8393
Future<String> _getEncryptedSharedKey(AtKey atKey) async {
8494
String? encryptedSharedKey = '';
8595
var localLookupSharedKeyBuilder = LLookupVerbBuilder()
8696
..atKey = AtConstants.atEncryptionSharedKey
87-
..sharedWith = atClient.getCurrentAtSign()
97+
..sharedWith = _atClient.getCurrentAtSign()
8898
..sharedBy = atKey.sharedBy
8999
..isCached = true;
90100
try {
91-
encryptedSharedKey = await atClient
101+
encryptedSharedKey = await _atClient
92102
.getLocalSecondary()!
93103
.executeVerb(localLookupSharedKeyBuilder);
94104
} on KeyNotFoundException {
@@ -102,7 +112,7 @@ class SharedKeyDecryption implements AtKeyDecryption {
102112
..atKey = AtConstants.atEncryptionSharedKey
103113
..sharedBy = atKey.sharedBy
104114
..auth = true;
105-
encryptedSharedKey = await atClient
115+
encryptedSharedKey = await _atClient
106116
.getRemoteSecondary()!
107117
.executeVerb(sharedKeyLookUpBuilder);
108118
encryptedSharedKey =

packages/at_client/lib/src/util/encryption_util.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import 'package:encrypt/encrypt.dart';
77
import 'package:crypto/crypto.dart';
88
import 'package:at_utils/at_logger.dart';
99

10+
//#TODO Replace calls to methods in this class with at_chops methods and
11+
// move this class to test folder in next major release
1012
class EncryptionUtil {
1113
static final _logger = AtSignLogger('EncryptionUtil');
1214

packages/at_client/test/decryption_service_test.dart

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class MockGetRequestTransformer extends Mock implements GetRequestTransformer {}
2525

2626
class MockSecondaryManager extends Mock implements SecondaryManager {}
2727

28+
class FakeLocalLookUpVerbBuilder extends Fake implements LLookupVerbBuilder {}
29+
2830
void main() {
2931
AtLookupImpl mockAtLookup = MockAtLookup();
3032
AtClientImpl mockAtClientImpl = MockAtClientImpl();
@@ -35,12 +37,9 @@ void main() {
3537
..atKey = 'phone.wavi'
3638
..sharedBy = '@alice';
3739

38-
var llookupVerbBuilder = LLookupVerbBuilder()
39-
..atKey = 'shared_key.sitaram'
40-
..sharedBy = '@murali';
41-
4240
setUp(() {
4341
reset(mockAtLookup);
42+
registerFallbackValue(FakeLocalLookUpVerbBuilder());
4443
when(() => mockAtLookup.executeVerb(lookupVerbBuilder)).thenAnswer(
4544
(_) async =>
4645
throw AtExceptionUtils.get('AT0015', 'Connection timeout'));
@@ -49,7 +48,7 @@ void main() {
4948
when(() => mockAtClientImpl.getCurrentAtSign()).thenAnswer((_) => '@xyz');
5049
when(() => mockLocalSecondary.getEncryptionPublicKey('@xyz'))
5150
.thenAnswer((_) => Future.value('dummy_encryption_public_key'));
52-
when(() => mockLocalSecondary.executeVerb(llookupVerbBuilder))
51+
when(() => mockLocalSecondary.executeVerb(any<LLookupVerbBuilder>()))
5352
.thenAnswer((_) async => 'dummy_shared_key');
5453
when(() => mockAtClientImpl.atChops).thenAnswer((_) => mockAtChops);
5554
});
@@ -89,33 +88,6 @@ void main() {
8988
});
9089

9190
group('A group of tests to verify exceptions in decryption service', () {
92-
test(
93-
'A test to verify exception is thrown when public key checksum changes',
94-
() {
95-
var atKey = (AtKey.shared('phone', namespace: 'wavi', sharedBy: '@murali')
96-
..sharedWith('@sitaram'))
97-
.build();
98-
atKey.metadata = Metadata()..pubKeyCS = '1234';
99-
var sharedKeyDecryption = SharedKeyDecryption(mockAtClientImpl);
100-
expect(() => sharedKeyDecryption.decrypt(atKey, '123'),
101-
throwsA(predicate((dynamic e) => e is AtPublicKeyChangeException)));
102-
});
103-
104-
test('A test to verify exception is thrown when shared key is not found',
105-
() {
106-
var atKey = (AtKey.shared('phone', namespace: 'wavi', sharedBy: '@murali')
107-
..sharedWith('@sitaram'))
108-
.build();
109-
atKey.metadata = Metadata()
110-
..pubKeyCS = 'd4f6d9483907286a0563b9fdeb01aa61';
111-
var sharedKeyDecryption = SharedKeyDecryption(mockAtClientImpl);
112-
expect(
113-
() => sharedKeyDecryption.decrypt(atKey, '123'),
114-
throwsA(predicate((dynamic e) =>
115-
e is SharedKeyNotFoundException &&
116-
e.message == 'shared encryption key not found')));
117-
});
118-
11991
test(
12092
'A test to verify exception is thrown when current atsign public key is not found',
12193
() {

0 commit comments

Comments
 (0)