diff --git a/pubnub/lib/src/core/crypto/crypto.dart b/pubnub/lib/src/core/crypto/crypto.dart index f932ab56..fd6edcf4 100644 --- a/pubnub/lib/src/core/crypto/crypto.dart +++ b/pubnub/lib/src/core/crypto/crypto.dart @@ -21,3 +21,22 @@ abstract class ICryptoModule { List encryptFileData(CipherKey key, List input); List decryptFileData(CipherKey key, List input); } + +/// @nodoc +abstract class ICryptor { + String get identifier; + EncryptedData encrypt(List input); + List decrypt(EncryptedData input); +} + +class EncryptedData { + List _data; + List _metadata; + + List get data => _data; + List get metadata => _metadata; + + EncryptedData._(this._data, this._metadata); + + factory EncryptedData.from(data, metadata) => EncryptedData._(data, metadata); +} diff --git a/pubnub/lib/src/crypto/aesCbcCryptor.dart b/pubnub/lib/src/crypto/aesCbcCryptor.dart new file mode 100644 index 00000000..dac4a6e5 --- /dev/null +++ b/pubnub/lib/src/crypto/aesCbcCryptor.dart @@ -0,0 +1,39 @@ +import 'package:encrypt/encrypt.dart' as crypto; +import 'package:crypto/crypto.dart' show sha256; +import 'dart:typed_data' show Uint8List; + +import 'package:pubnub/core.dart'; +class AesCbcCryptor implements ICryptor { + static const BLOCK_SIZE = 16; + CipherKey cipherKey; + + AesCbcCryptor(this.cipherKey); + @override + List decrypt(EncryptedData encryptedData) { + var encrypter = + crypto.Encrypter(crypto.AES(_getKey(), mode: crypto.AESMode.cbc)); + return encrypter.decryptBytes( + crypto.Encrypted(Uint8List.fromList(encryptedData.data.toList())), + iv: crypto.IV(Uint8List.fromList(encryptedData.metadata.toList()))); + } + + @override + EncryptedData encrypt(List input) { + var encrypter = + crypto.Encrypter(crypto.AES(_getKey(), mode: crypto.AESMode.cbc)); + var iv = _getIv(); + var data = encrypter.encryptBytes(input, iv: iv).bytes.toList(); + return EncryptedData.from(data, iv.bytes.toList()); + } + + @override + String get identifier => 'ACRH'; + + crypto.IV _getIv() { + return crypto.IV.fromSecureRandom(BLOCK_SIZE); + } + + crypto.Key _getKey() { + return crypto.Key.fromBase16(sha256.convert(cipherKey.data).toString()); + } +} diff --git a/pubnub/test/unit/crypto/crypto_test.dart b/pubnub/test/unit/crypto/crypto_test.dart index 79ba2c6c..abb57d11 100644 --- a/pubnub/test/unit/crypto/crypto_test.dart +++ b/pubnub/test/unit/crypto/crypto_test.dart @@ -1,4 +1,7 @@ +import 'dart:convert'; + import 'package:pubnub/core.dart'; +import 'package:pubnub/src/crypto/aesCbcCryptor.dart'; import 'package:pubnub/src/crypto/crypto.dart'; import 'package:test/test.dart'; @@ -28,8 +31,16 @@ void main() { var headerData = [80, 78, 69, 68, 1, 65, 67, 82, 72, 16]; var expectedBytes = [...headerData, ...List.filled(16, 0)]; - CryptorHeaderV1? header = CryptorHeader.tryParse(encryptedDataWithHeader.codeUnits); + var header = CryptorHeader.tryParse(encryptedDataWithHeader.codeUnits); expect(header!.data, equals(expectedBytes)); }); + + test('AesCbcCryptor should work as expected', () async { + var plainText = 'Hello there!'; + var cryptor = AesCbcCryptor(CipherKey.fromUtf8('pubnubenigma')); + var encryptedData = cryptor.encrypt(plainText.codeUnits); + var decrypted = cryptor.decrypt(encryptedData); + expect(utf8.decode(decrypted), equals(plainText)); + }); }); }