-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
334 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import 'package:at_chops/at_chops.dart'; | ||
import 'package:at_client/src/decryption_service/self_key_decryption.dart'; | ||
import 'package:at_client/src/encryption_service/self_key_encryption.dart'; | ||
import 'package:at_commons/at_builders.dart'; | ||
import 'package:test/test.dart'; | ||
import 'package:mocktail/mocktail.dart'; | ||
import 'package:at_client/at_client.dart'; | ||
import 'package:at_lookup/at_lookup.dart'; | ||
|
||
class MockAtClientImpl extends Mock implements AtClient {} | ||
|
||
class MockLocalSecondary extends Mock implements LocalSecondary {} | ||
|
||
class MockRemoteSecondary extends Mock implements RemoteSecondary {} | ||
|
||
class MockAtLookupImpl extends Mock implements AtLookUp {} | ||
|
||
class FakeLocalLookUpVerbBuilder extends Fake implements LLookupVerbBuilder {} | ||
|
||
void main() { | ||
AtClient mockAtClient = MockAtClientImpl(); | ||
AtLookUp mockAtLookUp = MockAtLookupImpl(); | ||
LocalSecondary mockLocalSecondary = MockLocalSecondary(); | ||
RemoteSecondary mockRemoteSecondary = MockRemoteSecondary(); | ||
setUp(() { | ||
reset(mockAtLookUp); | ||
when(() => mockAtClient.getLocalSecondary()) | ||
.thenAnswer((_) => mockLocalSecondary); | ||
when(() => mockAtClient.getRemoteSecondary()) | ||
.thenAnswer((_) => mockRemoteSecondary); | ||
|
||
registerFallbackValue(FakeLocalLookUpVerbBuilder()); | ||
}); | ||
|
||
test('test to check encryption/decryption of self keys', () async { | ||
// This test encrypts a self key value and then checks whether decrypted value is same as original value | ||
// If @alice wants to maintain a location without sharing to anyone then the key-value format will be @alice:location@alice New Jersey | ||
// @alice uses self encryption AES key generated during onboarding process to encrypt the value. Same key is used for decryption | ||
var selfKeyEncryption = SelfKeyEncryption(mockAtClient); | ||
var selfKeyDecryption = SelfKeyDecryption(mockAtClient); | ||
// generate new AES key for the test | ||
var aliceSelfEncryptionKey = | ||
AtChopsUtil.generateSymmetricKey(EncryptionKeyType.aes256).key; | ||
// set atChops | ||
AtChopsKeys atChopsKeys = AtChopsKeys.create(null, null); | ||
atChopsKeys.selfEncryptionKey = AESKey(aliceSelfEncryptionKey); | ||
var atChopsImpl = AtChopsImpl(atChopsKeys); | ||
when(() => mockAtClient.atChops).thenAnswer((_) => atChopsImpl); | ||
when(() => mockLocalSecondary.getEncryptionSelfKey()) | ||
.thenAnswer((_) => Future.value(aliceSelfEncryptionKey)); | ||
var selfKey = AtKey() | ||
..sharedBy = '@alice' | ||
..sharedWith = '@bob' | ||
..key = 'location'; | ||
var location = 'New Jersey'; | ||
var encryptedValue = await selfKeyEncryption.encrypt(selfKey, location); | ||
expect(encryptedValue != location, true); | ||
var decryptionResult = | ||
await selfKeyDecryption.decrypt(selfKey, encryptedValue); | ||
expect(decryptionResult, location); | ||
}); | ||
test( | ||
'test to check self key encryption throws exception when passed value is not string type', | ||
() async { | ||
var selfKeyEncryption = SelfKeyEncryption(mockAtClient); | ||
var selfKey = AtKey() | ||
..sharedBy = '@alice' | ||
..sharedWith = '@bob' | ||
..key = 'location'; | ||
var locations = ['new jersey', 'new york']; | ||
expect( | ||
() async => await selfKeyEncryption.encrypt(selfKey, locations), | ||
throwsA(predicate((dynamic e) => | ||
e is AtEncryptionException && | ||
e.message == | ||
'Invalid value type found: List<String>. Valid value type is String'))); | ||
}); | ||
} |
220 changes: 220 additions & 0 deletions
220
packages/at_client/test/shared_key_encryption_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
import 'package:at_chops/at_chops.dart'; | ||
import 'package:at_client/src/decryption_service/shared_key_decryption.dart'; | ||
import 'package:at_client/src/encryption_service/shared_key_encryption.dart'; | ||
import 'package:at_commons/at_builders.dart'; | ||
import 'package:test/test.dart'; | ||
import 'package:mocktail/mocktail.dart'; | ||
import 'package:at_client/at_client.dart'; | ||
import 'package:at_lookup/at_lookup.dart'; | ||
|
||
class MockAtClientImpl extends Mock implements AtClient {} | ||
|
||
class MockLocalSecondary extends Mock implements LocalSecondary {} | ||
|
||
class MockRemoteSecondary extends Mock implements RemoteSecondary {} | ||
|
||
class MockAtLookupImpl extends Mock implements AtLookUp {} | ||
|
||
class FakeLocalLookUpVerbBuilder extends Fake implements LLookupVerbBuilder {} | ||
|
||
class FakeDeleteVerbBuilder extends Fake implements DeleteVerbBuilder {} | ||
|
||
void main() { | ||
AtClient mockAtClient = MockAtClientImpl(); | ||
AtLookUp mockAtLookUp = MockAtLookupImpl(); | ||
LocalSecondary mockLocalSecondary = MockLocalSecondary(); | ||
RemoteSecondary mockRemoteSecondary = MockRemoteSecondary(); | ||
setUp(() { | ||
reset(mockAtLookUp); | ||
when(() => mockAtClient.getLocalSecondary()) | ||
.thenAnswer((_) => mockLocalSecondary); | ||
when(() => mockAtClient.getRemoteSecondary()) | ||
.thenAnswer((_) => mockRemoteSecondary); | ||
|
||
registerFallbackValue(FakeLocalLookUpVerbBuilder()); | ||
registerFallbackValue(FakeDeleteVerbBuilder()); | ||
}); | ||
|
||
test( | ||
'test to verify encryption and decryption of a key shared by @alice with @bob - without IV', | ||
() async { | ||
// This test verifies encryption and decryption of a shared key value without using Initialization vector(IV) | ||
// Value of a shared key is encrypted and then test asserts whether decrypted value is same as original value | ||
// If @alice wants to share location value with bob, then key-value format is @bob:location@alice California | ||
// @alice will generate a AES key and will encrypt the location value - California | ||
// The AES key will be encrypted with @bob's public key and stored in @bob:shared_key@alice | ||
// When @bob wants to decrypt the @alice's location, @bob will read the encrypted AES key from @bob:shared_key@alice | ||
// @bob will decrypt the AES key using @bob's private key | ||
// @bob will decrypt the location value - California with AES key | ||
|
||
var sharedKeyEncryption = SharedKeyEncryption(mockAtClient); | ||
var bobMockAtClient = MockAtClientImpl(); | ||
var bobMockLocalSecondary = MockLocalSecondary(); | ||
// set up encryption key pair for @alice. This will be used during encryption process | ||
var aliceEncryptionKeyPair = AtChopsUtil.generateAtEncryptionKeyPair(); | ||
var aliceEncryptionPublicKey = aliceEncryptionKeyPair.atPublicKey.publicKey; | ||
// Set up encryption key pair for @bob. This will be used during decryption process | ||
var bobEncryptionKeyPair = AtChopsUtil.generateAtEncryptionKeyPair(); | ||
var bobEncryptionPublicKey = bobEncryptionKeyPair.atPublicKey.publicKey; | ||
|
||
// Generate the AES for encrypting the location value | ||
var aesSharedKey = | ||
AtChopsUtil.generateSymmetricKey(EncryptionKeyType.aes256).key; | ||
// set atChops for bob | ||
AtChopsKeys bobAtChopsKeys = AtChopsKeys.create(bobEncryptionKeyPair, null); | ||
var bobAtChopsImpl = AtChopsImpl(bobAtChopsKeys); | ||
when(() => bobMockAtClient.atChops).thenAnswer((_) => bobAtChopsImpl); | ||
when(() => bobMockAtClient.getLocalSecondary()) | ||
.thenAnswer((_) => bobMockLocalSecondary); | ||
when(() => bobMockAtClient.getCurrentAtSign()).thenReturn('@bob'); | ||
when(() => bobMockLocalSecondary.getEncryptionPublicKey('@bob')) | ||
.thenAnswer((_) => Future.value(bobEncryptionPublicKey)); | ||
var sharedKeyDecryption = SharedKeyDecryption(bobMockAtClient); | ||
|
||
// encrypted AES key @bob:shared_key@alice | ||
var sharedKeyEncryptedWithBobPublicKey = | ||
EncryptionUtil.encryptKey(aesSharedKey, bobEncryptionPublicKey); | ||
|
||
// local copy of the AES key that @alice maintains - shared_key.bob@alice | ||
var sharedKeyEncryptedWithAlicePublicKey = | ||
EncryptionUtil.encryptKey(aesSharedKey, aliceEncryptionPublicKey); | ||
|
||
var bobPublicKeyCheckSum = | ||
EncryptionUtil.md5CheckSum(bobEncryptionPublicKey); | ||
var location = 'California'; | ||
|
||
// set atChops for alice | ||
AtChopsKeys atChopsKeys = AtChopsKeys.create(aliceEncryptionKeyPair, null); | ||
var atChopsImpl = AtChopsImpl(atChopsKeys); | ||
when(() => mockAtClient.atChops).thenAnswer((_) => atChopsImpl); | ||
when(() => mockAtClient.getCurrentAtSign()).thenReturn('@alice'); | ||
when(() => mockLocalSecondary.getEncryptionPublicKey('@alice')) | ||
.thenAnswer((_) => Future.value(aliceEncryptionPublicKey)); | ||
when(() => mockLocalSecondary.executeVerb(any<LLookupVerbBuilder>())) | ||
.thenAnswer((Invocation invocation) { | ||
final builder = invocation.positionalArguments[0] as LLookupVerbBuilder; | ||
final buildKeyValue = builder.buildKey(); | ||
if (buildKeyValue == 'shared_key.bob@alice') { | ||
return Future.value('data:$sharedKeyEncryptedWithAlicePublicKey'); | ||
} else if (buildKeyValue == 'cached:public:publickey@bob') { | ||
return Future.value('data:$bobEncryptionPublicKey'); | ||
} else if (buildKeyValue == '@bob:shared_key@alice') { | ||
return Future.value('data:$sharedKeyEncryptedWithBobPublicKey'); | ||
} else { | ||
return Future.value('data:null'); | ||
} | ||
}); | ||
var sharedKey = AtKey() | ||
..sharedBy = '@alice' | ||
..sharedWith = '@bob' | ||
..key = 'location'; | ||
sharedKey.metadata = (Metadata()..pubKeyCS = bobPublicKeyCheckSum); | ||
var encryptionResult = | ||
await sharedKeyEncryption.encrypt(sharedKey, location); | ||
expect(encryptionResult != location, true); | ||
var decryptionResult = | ||
await sharedKeyDecryption.decrypt(sharedKey, encryptionResult); | ||
expect(decryptionResult, location); | ||
}); | ||
|
||
test( | ||
'test to verify encryption and decryption of a key shared by @alice with @bob - with IV', | ||
() async { | ||
// This test verifies encryption and decryption of a shared key value by using Initialization vector(IV) | ||
// If @alice wants to share location value with bob, then key-value format is @bob:location@alice California | ||
// @alice will generate a AES key and will encrypt the location value - California | ||
// The AES key will be encrypted with @bob's public key and stored in @bob:shared_key@alice | ||
// When @bob wants to decrypt the @alice's location, @bob will read the encrypted AES key from @bob:shared_key@alice | ||
// @bob will decrypt the AES key using @bob's private key | ||
// @bob will decrypt the location value - California with AES key | ||
|
||
var sharedKeyEncryption = SharedKeyEncryption(mockAtClient); | ||
var bobMockAtClient = MockAtClientImpl(); | ||
var bobMockLocalSecondary = MockLocalSecondary(); | ||
// set up encryption key pair for @alice. This will be used during encryption process | ||
var aliceEncryptionKeyPair = AtChopsUtil.generateAtEncryptionKeyPair(); | ||
var aliceEncryptionPublicKey = aliceEncryptionKeyPair.atPublicKey.publicKey; | ||
// Set up encryption key pair for @bob. This will be used during decryption process | ||
var bobEncryptionKeyPair = AtChopsUtil.generateAtEncryptionKeyPair(); | ||
var bobEncryptionPublicKey = bobEncryptionKeyPair.atPublicKey.publicKey; | ||
|
||
// Generate the AES for encrypting the location value | ||
var aesSharedKey = | ||
AtChopsUtil.generateSymmetricKey(EncryptionKeyType.aes256).key; | ||
// set atChops for bob | ||
AtChopsKeys bobAtChopsKeys = AtChopsKeys.create(bobEncryptionKeyPair, null); | ||
var bobAtChopsImpl = AtChopsImpl(bobAtChopsKeys); | ||
when(() => bobMockAtClient.atChops).thenAnswer((_) => bobAtChopsImpl); | ||
when(() => bobMockAtClient.getLocalSecondary()) | ||
.thenAnswer((_) => bobMockLocalSecondary); | ||
when(() => bobMockAtClient.getCurrentAtSign()).thenReturn('@bob'); | ||
when(() => bobMockLocalSecondary.getEncryptionPublicKey('@bob')) | ||
.thenAnswer((_) => Future.value(bobEncryptionPublicKey)); | ||
var sharedKeyDecryption = SharedKeyDecryption(bobMockAtClient); | ||
|
||
// encrypted AES key @bob:shared_key@alice | ||
var sharedKeyEncryptedWithBobPublicKey = | ||
EncryptionUtil.encryptKey(aesSharedKey, bobEncryptionPublicKey); | ||
|
||
// local copy of the AES key that @alice maintains - shared_key.bob@alice | ||
var sharedKeyEncryptedWithAlicePublicKey = | ||
EncryptionUtil.encryptKey(aesSharedKey, aliceEncryptionPublicKey); | ||
|
||
var bobPublicKeyCheckSum = | ||
EncryptionUtil.md5CheckSum(bobEncryptionPublicKey); | ||
var location = 'California'; | ||
|
||
// set atChops for alice | ||
AtChopsKeys atChopsKeys = AtChopsKeys.create(aliceEncryptionKeyPair, null); | ||
var atChopsImpl = AtChopsImpl(atChopsKeys); | ||
when(() => mockAtClient.atChops).thenAnswer((_) => atChopsImpl); | ||
when(() => mockAtClient.getCurrentAtSign()).thenReturn('@alice'); | ||
when(() => mockLocalSecondary.getEncryptionPublicKey('@alice')) | ||
.thenAnswer((_) => Future.value(aliceEncryptionPublicKey)); | ||
when(() => mockLocalSecondary.executeVerb(any<LLookupVerbBuilder>())) | ||
.thenAnswer((Invocation invocation) { | ||
final builder = invocation.positionalArguments[0] as LLookupVerbBuilder; | ||
final buildKeyValue = builder.buildKey(); | ||
if (buildKeyValue == 'shared_key.bob@alice') { | ||
return Future.value('data:$sharedKeyEncryptedWithAlicePublicKey'); | ||
} else if (buildKeyValue == 'cached:public:publickey@bob') { | ||
return Future.value('data:$bobEncryptionPublicKey'); | ||
} else if (buildKeyValue == '@bob:shared_key@alice') { | ||
return Future.value('data:$sharedKeyEncryptedWithBobPublicKey'); | ||
} else { | ||
return Future.value('data:null'); | ||
} | ||
}); | ||
var sharedKey = AtKey() | ||
..sharedBy = '@alice' | ||
..sharedWith = '@bob' | ||
..key = 'location'; | ||
// random IV string | ||
var ivBase64String = 'YmFzZTY0IGVuY29kaW5n'; | ||
sharedKey.metadata = Metadata() | ||
..pubKeyCS = bobPublicKeyCheckSum | ||
..ivNonce = ivBase64String; | ||
var encryptionResult = | ||
await sharedKeyEncryption.encrypt(sharedKey, location); | ||
expect(encryptionResult != location, true); | ||
var decryptionResult = | ||
await sharedKeyDecryption.decrypt(sharedKey, encryptionResult); | ||
expect(decryptionResult, location); | ||
}); | ||
test( | ||
'test to check shared key encryption throws exception when passed value is not string type', | ||
() async { | ||
var sharedKeyEncryption = SharedKeyEncryption(mockAtClient); | ||
var selfKey = AtKey() | ||
..sharedBy = '@alice' | ||
..sharedWith = '@bob' | ||
..key = 'location'; | ||
var locations = ['new jersey', 'new york']; | ||
expect( | ||
() async => await sharedKeyEncryption.encrypt(selfKey, locations), | ||
throwsA(predicate((dynamic e) => | ||
e is AtEncryptionException && | ||
e.message == | ||
'Invalid value type found: List<String>. Valid value type is String'))); | ||
}); | ||
} |
Oops, something went wrong.