Skip to content

Commit

Permalink
Merge pull request #1209 from atsign-foundation/replace_encryption_me…
Browse files Browse the repository at this point in the history
…thods_with_atchops

feat: Replace encryption methods/key generation from EncryptionUtil with AtChops
  • Loading branch information
gkc authored Jan 16, 2024
2 parents bd4d469 + be70991 commit b16337d
Show file tree
Hide file tree
Showing 7 changed files with 381 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,6 @@ class SharedKeyDecryption implements AtKeyDecryption {
decryptionResultFromAtChops = _atClient.atChops!.decryptString(
encryptedValue, EncryptionKeyType.aes256,
encryptionAlgorithm: encryptionAlgo, iv: iV);
} on AtKeyException catch (e) {
e.stack(AtChainedException(
Intent.decryptData,
ExceptionScenario.decryptionFailed,
'Failed to decrypt ${atKey.toString()}'));
rethrow;
} on AtDecryptionException catch (e) {
_logger.severe(
'decryption exception during of key: ${atKey.key}. Reason: ${e.toString()}');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ abstract class AbstractAtKeyEncryption implements AtKeyEncryption {
Future<dynamic> encrypt(AtKey atKey, dynamic value,
{bool storeSharedKeyEncryptedWithData = true}) async {
_sharedKey = await getMyCopyOfSharedSymmetricKey(atKey);

if (_sharedKey.isEmpty) {
_sharedKey = await createMyCopyOfSharedSymmetricKey(atKey);
}
Expand Down Expand Up @@ -121,26 +120,15 @@ abstract class AbstractAtKeyEncryption implements AtKeyEncryption {
Future<String> createMyCopyOfSharedSymmetricKey(AtKey atKey) async {
_logger.info(
"Creating new shared symmetric key as ${atKey.sharedBy} for ${atKey.sharedWith}");
// Fetch our encryption public key
String? currentAtSignEncryptionPublicKey;
try {
currentAtSignEncryptionPublicKey = await _atClient
.getLocalSecondary()!
.getEncryptionPublicKey(atKey.sharedBy!);
} on KeyNotFoundException catch (e) {
e.stack(AtChainedException(
Intent.fetchEncryptionPublicKey,
ExceptionScenario.fetchEncryptionKeys,
'Failed to fetch encryption public key of current atSign'));
rethrow;
}
// Generate new symmetric key
var newSymmetricKeyBase64 = EncryptionUtil.generateAESKey();

var newSymmetricKeyBase64 =
AtChopsUtil.generateSymmetricKey(EncryptionKeyType.aes256).key;
// Encrypt the new symmetric key with our public key
var encryptedSharedKeyMyCopy = EncryptionUtil.encryptKey(
newSymmetricKeyBase64, currentAtSignEncryptionPublicKey!);

var atChopsEncryptionResult = _atClient.atChops!
.encryptString(newSymmetricKeyBase64, EncryptionKeyType.rsa2048);
var encryptedSharedKeyMyCopy = atChopsEncryptionResult.result;
_logger.info(
'encryptedSharedKeyMyCopy from atChops: $encryptedSharedKeyMyCopy');
// Defensive code to ensure that we do not have an old 'their' copy on atServer
await deleteTheirCopyOfEncryptedSharedKey(
atKey, _atClient.getRemoteSecondary()!);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ import 'package:at_client/src/client/local_secondary.dart';
import 'package:at_client/src/encryption_service/encryption.dart';
import 'package:at_client/src/response/default_response_parser.dart';
import 'package:at_client/src/util/at_client_util.dart';
import 'package:at_client/src/util/encryption_util.dart';
import 'package:at_commons/at_commons.dart';
import 'package:at_chops/at_chops.dart';
import 'package:at_utils/at_logger.dart';

///Class responsible for encrypting the selfKey's
class SelfKeyEncryption implements AtKeyEncryption {
late final AtSignLogger _logger;

final AtClient atClient;
final AtClient _atClient;

SelfKeyEncryption(this.atClient) {
SelfKeyEncryption(this._atClient) {
_logger =
AtSignLogger('SelfKeyEncryption (${atClient.getCurrentAtSign()})');
AtSignLogger('SelfKeyEncryption (${_atClient.getCurrentAtSign()})');
}

@override
Expand All @@ -29,12 +29,27 @@ class SelfKeyEncryption implements AtKeyEncryption {
}
// Get AES key for current atSign
var selfEncryptionKey =
await _getSelfEncryptionKey(atClient.getLocalSecondary()!);
await _getSelfEncryptionKey(_atClient.getLocalSecondary()!);
selfEncryptionKey =
DefaultResponseParser().parse(selfEncryptionKey).response;
// Encrypt value using sharedKey
return EncryptionUtil.encryptValue(value, selfEncryptionKey,
ivBase64: atKey.metadata.ivNonce);
AtEncryptionResult encryptionResultFromAtChops;
try {
InitialisationVector iV;
if (atKey.metadata.ivNonce != null) {
iV = AtChopsUtil.generateIVFromBase64String(atKey.metadata.ivNonce!);
} else {
iV = AtChopsUtil.generateIVLegacy();
}
var encryptionAlgo = AESEncryptionAlgo(AESKey(selfEncryptionKey));
encryptionResultFromAtChops = _atClient.atChops!.encryptString(
value, EncryptionKeyType.aes256,
encryptionAlgorithm: encryptionAlgo, iv: iV);
} on AtEncryptionException catch (e) {
_logger.severe(
'encryption exception during self encryption of key: ${atKey.key}. Reason: ${e.toString()}');
rethrow;
}
return encryptionResultFromAtChops.result;
}

Future<String> _getSelfEncryptionKey(LocalSecondary localSecondary) async {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import 'package:at_client/at_client.dart';
import 'package:at_utils/at_logger.dart';
import 'package:at_chops/at_chops.dart';
import 'package:at_client/src/encryption_service/abstract_atkey_encryption.dart';

///Class responsible for encrypting the value of the SharedKey's
class SharedKeyEncryption extends AbstractAtKeyEncryption {
SharedKeyEncryption(AtClient atClient) : super(atClient);
final AtClient _atClient;
late final AtSignLogger _logger;
SharedKeyEncryption(this._atClient) : super(_atClient) {
_logger =
AtSignLogger('SelfKeyEncryption (${_atClient.getCurrentAtSign()})');
}

@override
Future<dynamic> encrypt(AtKey atKey, dynamic value,
Expand All @@ -17,9 +24,23 @@ class SharedKeyEncryption extends AbstractAtKeyEncryption {
// encryption key and setting it in super.sharedKey
await super.encrypt(atKey, value,
storeSharedKeyEncryptedWithData: storeSharedKeyEncryptedWithData);

// Encrypt the value
return EncryptionUtil.encryptValue(value, sharedKey,
ivBase64: atKey.metadata.ivNonce);
AtEncryptionResult encryptionResultFromAtChops;
try {
InitialisationVector iV;
if (atKey.metadata.ivNonce != null) {
iV = AtChopsUtil.generateIVFromBase64String(atKey.metadata.ivNonce!);
} else {
iV = AtChopsUtil.generateIVLegacy();
}
var encryptionAlgo = AESEncryptionAlgo(AESKey(sharedKey));
encryptionResultFromAtChops = _atClient.atChops!.encryptString(
value, EncryptionKeyType.aes256,
encryptionAlgorithm: encryptionAlgo, iv: iV);
} on AtEncryptionException catch (e) {
_logger.severe(
'encryption exception during shared key encryption of key: ${atKey.key}. Reason: ${e.toString()}');
rethrow;
}
return encryptionResultFromAtChops.result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import 'package:at_chops/at_chops.dart';
import 'package:at_client/at_client.dart';
import 'package:test/test.dart';

// Tests to verify whether encryption with EncryptionUtil, decryption with AtChops works and vice versa.
void main() {
test(
'A test to verify encrypting AES key with encryption util and decryption with at_chops',
() {
// Generate RSA key pair. Generate AES key. Encrypt AES key using RSA public key using EncryptionUtil method
// Decrypt encryptedAESKey using AtChops (uses RSA private key)
var encryptionKeyPair = AtChopsUtil.generateAtEncryptionKeyPair();
var encryptionPublicKey = encryptionKeyPair.atPublicKey.publicKey;
var aesKey = EncryptionUtil.generateAESKey();
var encryptedAesKey =
EncryptionUtil.encryptKey(aesKey, encryptionPublicKey);
AtChopsKeys atChopsKeys = AtChopsKeys.create(encryptionKeyPair, null);
var atChops = AtChopsImpl(atChopsKeys);
var decryptedAesKey = atChops
.decryptString(encryptedAesKey, EncryptionKeyType.rsa2048)
.result;
expect(decryptedAesKey, aesKey);
});
test(
'A test to verify encrypting AES key with at_chops and decryption with EncryptionUtil',
() {
// Generate RSA key pair. Generate AES key. Encrypt AES key using AtChops(uses RSA public key)
// Decrypt encryptedAESKey with EncryptionUtil using RSA private key
var encryptionKeyPair = AtChopsUtil.generateAtEncryptionKeyPair();
var encryptionPrivateKey = encryptionKeyPair.atPrivateKey.privateKey;
var aesKey = AtChopsUtil.generateSymmetricKey(EncryptionKeyType.aes256).key;

AtChopsKeys atChopsKeys = AtChopsKeys.create(encryptionKeyPair, null);
var atChops = AtChopsImpl(atChopsKeys);
var encryptedAesKey =
atChops.encryptString(aesKey, EncryptionKeyType.rsa2048).result;

var decryptedAesKey =
//ignore: deprecated_member_use_from_same_package
EncryptionUtil.decryptKey(encryptedAesKey, encryptionPrivateKey);
expect(decryptedAesKey, aesKey);
});

test(
'A test to verify data encryption with encryption util and decryption with at_chops',
() {
// Generate AES key. Encrypt data with EncryptionUtil using AES key
// Create a AESEncryption algo object using AES key and pass it to AtChops. Decrypt the encrypted value with AtChops
var aesKey = EncryptionUtil.generateAESKey();
var dataToEncrypt = '[email protected]';
var encryptedData = EncryptionUtil.encryptValue(dataToEncrypt, aesKey);
var encryptionAlgo = AESEncryptionAlgo(AESKey(aesKey));
AtChopsKeys atChopsKeys = AtChopsKeys.create(null, null);
var atChops = AtChopsImpl(atChopsKeys);
var decryptedData = atChops
.decryptString(encryptedData, EncryptionKeyType.aes256,
encryptionAlgorithm: encryptionAlgo,
iv: AtChopsUtil.generateIVLegacy())
.result;
expect(decryptedData, dataToEncrypt);
});

test(
'A test to verify data encryption with at_chops and decryption with encryption_util',
() {
// Generate AES key. Encrypt data with AtChops using AES key
// Decrypt the encrypted value with EncryptionUtil
var aesKey = AtChopsUtil.generateSymmetricKey(EncryptionKeyType.aes256);
var dataToEncrypt = '[email protected]';
var encryptionAlgo = AESEncryptionAlgo(AESKey(aesKey.key));
AtChopsKeys atChopsKeys = AtChopsKeys.create(null, null);
var atChops = AtChopsImpl(atChopsKeys);
var encryptedData = atChops
.encryptString(dataToEncrypt, EncryptionKeyType.aes256,
encryptionAlgorithm: encryptionAlgo,
iv: AtChopsUtil.generateIVLegacy())
.result;
var decryptedData = EncryptionUtil.decryptValue(encryptedData, aesKey.key);
expect(decryptedData, dataToEncrypt);
});

test(
'A test to verify data(with emoji) encryption with encryption util and decryption with at_chops',
() {
// Generate AES key. Encrypt data with EncryptionUtil using AES key
// Create a AESEncryption algo object using AES key and pass it to AtChops. Decrypt the encrypted value with AtChops
var aesKey = EncryptionUtil.generateAESKey();
var dataToEncrypt = 'alice@🦄🛠';
var encryptedData = EncryptionUtil.encryptValue(dataToEncrypt, aesKey);
var encryptionAlgo = AESEncryptionAlgo(AESKey(aesKey));
AtChopsKeys atChopsKeys = AtChopsKeys.create(null, null);
var atChops = AtChopsImpl(atChopsKeys);
var decryptedData = atChops
.decryptString(encryptedData, EncryptionKeyType.aes256,
encryptionAlgorithm: encryptionAlgo,
iv: AtChopsUtil.generateIVLegacy())
.result;
expect(decryptedData, dataToEncrypt);
});

test(
'A test to verify data(with emoji) encryption with at_chops and decryption with encryption_util',
() {
// Generate AES key. Encrypt data with AtChops using AES key
// Decrypt the encrypted value with EncryptionUtil
var aesKey = AtChopsUtil.generateSymmetricKey(EncryptionKeyType.aes256);
var dataToEncrypt = 'alice@🦄🛠';
var encryptionAlgo = AESEncryptionAlgo(AESKey(aesKey.key));
AtChopsKeys atChopsKeys = AtChopsKeys.create(null, null);
var atChops = AtChopsImpl(atChopsKeys);
var encryptedData = atChops
.encryptString(dataToEncrypt, EncryptionKeyType.aes256,
encryptionAlgorithm: encryptionAlgo,
iv: AtChopsUtil.generateIVLegacy())
.result;
var decryptedData = EncryptionUtil.decryptValue(encryptedData, aesKey.key);
expect(decryptedData, dataToEncrypt);
});
}
Loading

0 comments on commit b16337d

Please sign in to comment.