Fix/Update #1
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: cipher_page.dart | ||||
| // Created Date: 28/12/2021 13:33:15 | ||||
| // Last Modified: 26/05/2022 20:39:37 | ||||
| // Last Modified: 26/05/2022 21:07:54 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| @ -26,7 +26,8 @@ class CipherPage extends ConsumerWidget { | ||||
|   final Output encryptionStatus = Output(); | ||||
|   final Output decryptionStatus = Output(); | ||||
| 
 | ||||
|   final TextEditingController _plainTextController = TextEditingController()..text = 'PlainText'; | ||||
|   final TextEditingController _plainTextController = TextEditingController() | ||||
|     ..text = 'PlainText'; | ||||
|   CipherTextWrapper? cipherText; | ||||
| 
 | ||||
|   Future<void> _encrypt(WidgetRef ref, Cipher cipher) async { | ||||
| @ -58,9 +59,10 @@ class CipherPage extends ConsumerWidget { | ||||
|       // Recreate cipher text with altered data | ||||
|       cipherText = CipherTextWrapper.fromBytes( | ||||
|         _altered, | ||||
|         12, | ||||
|         _altered.length - 28, | ||||
|         16, | ||||
|         ivLength: AESMode.gcm.ivLength, | ||||
|         messageLength: | ||||
|             _altered.length - (AESMode.gcm.ivLength + AESMode.gcm.tagLength), | ||||
|         tagLength: AESMode.gcm.tagLength, | ||||
|       ); | ||||
|       encryptionStatus.print('String successfully encrypted:\n'); | ||||
| 
 | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: kdf_page.dart | ||||
| // Created Date: 28/12/2021 13:40:34 | ||||
| // Last Modified: 26/05/2022 20:30:31 | ||||
| // Last Modified: 26/05/2022 21:09:47 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| @ -26,8 +26,10 @@ class KdfPage extends ConsumerWidget { | ||||
|   final Output pbkdf2Status = Output(); | ||||
|   final Output hashStatus = Output(large: true); | ||||
| 
 | ||||
|   final TextEditingController _pwdTextController = TextEditingController()..text = 'Password'; | ||||
|   final TextEditingController _messageTextController = TextEditingController()..text = 'Message'; | ||||
|   final TextEditingController _pwdTextController = TextEditingController() | ||||
|     ..text = 'Password'; | ||||
|   final TextEditingController _messageTextController = TextEditingController() | ||||
|     ..text = 'Message'; | ||||
| 
 | ||||
|   Future<void> _generate(WidgetRef ref) async { | ||||
|     Session state = ref.read(sessionProvider.state).state; | ||||
| @ -50,7 +52,11 @@ class KdfPage extends ConsumerWidget { | ||||
|     if (password.isEmpty) { | ||||
|       pbkdf2Status.print('Password is empty'); | ||||
|     } else { | ||||
|       Pbkdf2 _pbkdf2 = Pbkdf2(32, 1000, algorithm: HashAlgorithm.sha512); | ||||
|       Pbkdf2 _pbkdf2 = Pbkdf2( | ||||
|         keyBytesCount: 32, | ||||
|         iterations: 1000, | ||||
|         algorithm: HashAlgorithm.sha512, | ||||
|       ); | ||||
|       SecretKey sk = await _pbkdf2.derive(password: password, salt: 'salt'); | ||||
|       state.setKey(sk); | ||||
|       pbkdf2Status.print('Key successfully derived.'); | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: aes.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 26/05/2022 19:43:22 | ||||
| // Last Modified: 26/05/2022 21:07:01 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| @ -21,6 +21,10 @@ import 'package:native_crypto/src/utils/cipher_algorithm.dart'; | ||||
| import 'package:native_crypto/src/utils/extensions.dart'; | ||||
| import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; | ||||
| 
 | ||||
| export 'aes_key_size.dart'; | ||||
| export 'aes_mode.dart'; | ||||
| export 'aes_padding.dart'; | ||||
| 
 | ||||
| /// An AES cipher. | ||||
| /// | ||||
| /// [AES] is a [Cipher] that can be used to encrypt or decrypt data. | ||||
| @ -94,11 +98,11 @@ class AES implements Cipher { | ||||
|       ); | ||||
|     } else { | ||||
|       return CipherText.fromBytes( | ||||
|         12, | ||||
|         encrypted.length - 28, | ||||
|         16, | ||||
|         CipherAlgorithm.aes, | ||||
|         encrypted, | ||||
|         ivLength: 12, | ||||
|         messageLength: encrypted.length - 28, | ||||
|         tagLength: 16, | ||||
|         cipherAlgorithm: CipherAlgorithm.aes, | ||||
|       ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: aes_mode.dart | ||||
| // Created Date: 23/05/2022 22:09:16 | ||||
| // Last Modified: 26/05/2022 18:41:31 | ||||
| // Last Modified: 26/05/2022 21:03:26 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| @ -11,10 +11,20 @@ import 'package:native_crypto/src/ciphers/aes/aes_padding.dart'; | ||||
| 
 | ||||
| /// Defines the AES modes of operation. | ||||
| enum AESMode { | ||||
|   gcm([AESPadding.none]); | ||||
|   gcm([AESPadding.none], 12, 16); | ||||
| 
 | ||||
|   /// Returns the list of supported [AESPadding] for this [AESMode]. | ||||
|   final List<AESPadding> supportedPaddings; | ||||
| 
 | ||||
|   const AESMode(this.supportedPaddings); | ||||
|   /// Returns the default IV length for this [AESMode]. | ||||
|   final int ivLength; | ||||
| 
 | ||||
|   /// Returns the default tag length for this [AESMode]. | ||||
|   final int tagLength; | ||||
| 
 | ||||
|   const AESMode( | ||||
|     this.supportedPaddings, [ | ||||
|     this.ivLength = 16, | ||||
|     this.tagLength = 0, | ||||
|   ]); | ||||
| } | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: cipher_text.dart | ||||
| // Created Date: 16/12/2021 16:59:53 | ||||
| // Last Modified: 26/05/2022 19:43:57 | ||||
| // Last Modified: 26/05/2022 22:20:40 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| @ -45,16 +45,33 @@ class CipherText extends ByteArray { | ||||
|   ); | ||||
| 
 | ||||
|   factory CipherText.fromBytes( | ||||
|     int ivLength, | ||||
|     int messageLength, | ||||
|     int tagLength, | ||||
|     Uint8List bytes, { | ||||
|     required int ivLength, | ||||
|     required int messageLength, | ||||
|     required int tagLength, | ||||
|     CipherAlgorithm? cipherAlgorithm, | ||||
|     Uint8List bytes, | ||||
|   ) { | ||||
|   }) { | ||||
|     if (ivLength.isNegative || | ||||
|         messageLength.isNegative || | ||||
|         tagLength.isNegative) { | ||||
|       throw NativeCryptoException( | ||||
|         message: 'Invalid length! Must be positive.', | ||||
|         code: NativeCryptoExceptionCode.invalid_argument.code, | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     if (bytes.isEmpty) { | ||||
|       throw NativeCryptoException( | ||||
|         message: 'Passed data is empty!', | ||||
|         code: NativeCryptoExceptionCode.invalid_argument.code, | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     if (bytes.length != ivLength + messageLength + tagLength) { | ||||
|       throw NativeCryptoException( | ||||
|         message: 'Invalid cipher text length! ' | ||||
|             'Expected: ${ivLength + messageLength + tagLength} bytes', | ||||
|             'Expected: ${ivLength + messageLength + tagLength} bytes ' | ||||
|             'got: ${bytes.length} bytes.', | ||||
|         code: NativeCryptoExceptionCode.invalid_argument.code, | ||||
|       ); | ||||
|     } | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: cipher_text_wrapper.dart | ||||
| // Created Date: 26/05/2022 14:27:32 | ||||
| // Last Modified: 26/05/2022 20:32:38 | ||||
| // Last Modified: 26/05/2022 22:11:42 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| @ -49,10 +49,10 @@ class CipherTextWrapper { | ||||
|   /// [NativeCryptoExceptionCode.invalid_argument] if the [Uint8List] is | ||||
|   /// not a valid [CipherText] or a [List] of [CipherText]. | ||||
|   factory CipherTextWrapper.fromBytes( | ||||
|     Uint8List bytes, | ||||
|     int ivLength, | ||||
|     int messageLength, | ||||
|     int tagLength, { | ||||
|     Uint8List bytes, { | ||||
|     required int ivLength, | ||||
|     required int messageLength, | ||||
|     required int tagLength, | ||||
|     CipherAlgorithm? cipherAlgorithm, | ||||
|     int? chunkSize, | ||||
|   }) { | ||||
| @ -62,11 +62,11 @@ class CipherTextWrapper { | ||||
|     if (bytes.length <= chunkSize) { | ||||
|       return CipherTextWrapper.single( | ||||
|         CipherText.fromBytes( | ||||
|           ivLength, | ||||
|           messageLength, | ||||
|           tagLength, | ||||
|           cipherAlgorithm, | ||||
|           bytes, | ||||
|           ivLength: ivLength, | ||||
|           messageLength: messageLength, | ||||
|           tagLength: tagLength, | ||||
|           cipherAlgorithm: cipherAlgorithm, | ||||
|         ), | ||||
|       ); | ||||
|     } else { | ||||
| @ -75,11 +75,11 @@ class CipherTextWrapper { | ||||
|         final chunk = bytes.sublist(i, i + chunkSize); | ||||
|         cipherTexts.add( | ||||
|           CipherText.fromBytes( | ||||
|             ivLength, | ||||
|             messageLength, | ||||
|             tagLength, | ||||
|             cipherAlgorithm, | ||||
|             chunk, | ||||
|             ivLength: ivLength, | ||||
|             messageLength: messageLength, | ||||
|             tagLength: tagLength, | ||||
|             cipherAlgorithm: cipherAlgorithm, | ||||
|           ), | ||||
|         ); | ||||
|       } | ||||
| @ -128,7 +128,7 @@ class CipherTextWrapper { | ||||
|     if (isSingle) { | ||||
|       return single.bytes; | ||||
|     } else { | ||||
|       return list.map((cipherText) => cipherText.bytes).toList().sum(); | ||||
|       return list.map((cipherText) => cipherText.bytes).toList().combine(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: cipher.dart | ||||
| // Created Date: 16/12/2021 16:28:00 | ||||
| // Last Modified: 26/05/2022 17:38:26 | ||||
| // Last Modified: 26/05/2022 21:21:07 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| @ -20,7 +20,11 @@ import 'package:native_crypto/src/utils/cipher_algorithm.dart'; | ||||
| ///  | ||||
| /// This interface is implemented by all the ciphers in NativeCrypto. | ||||
| abstract class Cipher { | ||||
|   static int _bytesCountPerChunk = 33554432; | ||||
|   static const int _bytesCountPerChunkDefault = 33554432; | ||||
|   static int _bytesCountPerChunk = _bytesCountPerChunkDefault; | ||||
| 
 | ||||
|   /// Returns the default number of bytes per chunk. | ||||
|   static int get defaultBytesCountPerChunk => _bytesCountPerChunkDefault; | ||||
| 
 | ||||
|   /// Returns the size of a chunk of data  | ||||
|   /// that can be processed by the [Cipher]. | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: pbkdf2.dart | ||||
| // Created Date: 17/12/2021 14:50:42 | ||||
| // Last Modified: 26/05/2022 18:51:59 | ||||
| // Last Modified: 26/05/2022 23:19:46 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| @ -29,31 +29,64 @@ class Pbkdf2 extends KeyDerivation { | ||||
|   @override | ||||
|   KdfAlgorithm get algorithm => KdfAlgorithm.pbkdf2; | ||||
| 
 | ||||
|   Pbkdf2( | ||||
|     int keyBytesCount, | ||||
|     int iterations, { | ||||
|   Pbkdf2({ | ||||
|     required int keyBytesCount, | ||||
|     required int iterations, | ||||
|     HashAlgorithm algorithm = HashAlgorithm.sha256, | ||||
|   })  : _keyBytesCount = keyBytesCount, | ||||
|         _iterations = iterations, | ||||
|         _hash = algorithm; | ||||
| 
 | ||||
|   @override | ||||
|   Future<SecretKey> derive({String? password, String? salt}) async { | ||||
|     if (password == null || salt == null) { | ||||
|         _hash = algorithm { | ||||
|     if (keyBytesCount < 0) { | ||||
|       throw NativeCryptoException( | ||||
|         message: 'Password and salt cannot be null. ' | ||||
|             'Here is the password: $password, here is the salt: $salt', | ||||
|         message: 'keyBytesCount must be positive.', | ||||
|         code: NativeCryptoExceptionCode.invalid_argument.code, | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     final Uint8List? derivation = await platform.pbkdf2( | ||||
|       password, | ||||
|       salt, | ||||
|       _keyBytesCount, | ||||
|       _iterations, | ||||
|       _hash.name, | ||||
|     ); | ||||
|     if (iterations <= 0) { | ||||
|       throw NativeCryptoException( | ||||
|         message: 'iterations must be strictly positive.', | ||||
|         code: NativeCryptoExceptionCode.invalid_argument.code, | ||||
|       ); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Future<SecretKey> derive({String? password, String? salt}) async { | ||||
|     Uint8List? derivation; | ||||
| 
 | ||||
|     if (_keyBytesCount == 0) { | ||||
|       return SecretKey(Uint8List(0)); | ||||
|     } | ||||
|     if (password.isNull) { | ||||
|       throw NativeCryptoException( | ||||
|         message: 'Password cannot be null.', | ||||
|         code: NativeCryptoExceptionCode.invalid_argument.code, | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     if (salt.isNull) { | ||||
|       throw NativeCryptoException( | ||||
|         message: 'Salt cannot be null.', | ||||
|         code: NativeCryptoExceptionCode.invalid_argument.code, | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     try { | ||||
|       derivation = await platform.pbkdf2( | ||||
|         password!, | ||||
|         salt!, | ||||
|         _keyBytesCount, | ||||
|         _iterations, | ||||
|         _hash.name, | ||||
|       ); | ||||
|     } catch (e, s) { | ||||
|       throw NativeCryptoException( | ||||
|         message: '$e', | ||||
|         code: NativeCryptoExceptionCode.platform_throws.code, | ||||
|         stackTrace: s, | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     if (derivation.isNull) { | ||||
|       throw NativeCryptoException( | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: secret_key.dart | ||||
| // Created Date: 28/12/2021 13:36:54 | ||||
| // Last Modified: 26/05/2022 19:26:35 | ||||
| // Last Modified: 26/05/2022 23:13:10 | ||||
| // ----- | ||||
| // Copyright (c) 2021 | ||||
| 
 | ||||
| @ -28,6 +28,10 @@ class SecretKey extends BaseKey { | ||||
| 
 | ||||
|   static Future<SecretKey> fromSecureRandom(int bitsCount) async { | ||||
|     Uint8List? key; | ||||
|     if (bitsCount == 0) { | ||||
|       return SecretKey(Uint8List(0)); | ||||
|     } | ||||
| 
 | ||||
|     try { | ||||
|       key = await platform.generateSecretKey(bitsCount); | ||||
|     } catch (e, s) { | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| // ----- | ||||
| // File: extensions.dart | ||||
| // Created Date: 26/05/2022 12:12:48 | ||||
| // Last Modified: 26/05/2022 18:52:48 | ||||
| // Last Modified: 26/05/2022 22:15:33 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| @ -30,14 +30,10 @@ extension ListIntX on List<int> { | ||||
| } | ||||
| 
 | ||||
| extension ListUint8ListX on List<Uint8List> { | ||||
|    | ||||
|   /// Reduce a [List] of [Uint8List] to a [Uint8List]. | ||||
|   Uint8List sum() { | ||||
|     for (var i = 1; i < length; i++) { | ||||
|       first.addAll(this[i]); | ||||
|       removeAt(i); | ||||
|     } | ||||
|     return first; | ||||
|   Uint8List combine() { | ||||
|     if (isEmpty) return Uint8List(0); | ||||
|     return reduce((value, element) => value.plus(element)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @ -90,6 +86,5 @@ extension Uint8ListX on Uint8List { | ||||
|   } | ||||
| 
 | ||||
|   /// Returns a concatenation of this with the other [Uint8List]. | ||||
|   Uint8List operator +(final Uint8List other) => | ||||
|       [...this, ...other].toTypedList(); | ||||
|   Uint8List plus(final Uint8List other) => [...this, ...other].toTypedList(); | ||||
| } | ||||
|  | ||||
| @ -3,13 +3,15 @@ | ||||
| // ----- | ||||
| // File: hash_algorithm.dart | ||||
| // Created Date: 23/05/2022 22:01:59 | ||||
| // Last Modified: 26/05/2022 18:53:38 | ||||
| // Last Modified: 26/05/2022 22:59:04 | ||||
| // ----- | ||||
| // Copyright (c) 2022 | ||||
| 
 | ||||
| import 'dart:typed_data'; | ||||
| 
 | ||||
| import 'package:native_crypto/src/platform.dart'; | ||||
| import 'package:native_crypto/src/utils/extensions.dart'; | ||||
| import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; | ||||
| 
 | ||||
| /// Defines the hash algorithms. | ||||
| enum HashAlgorithm { | ||||
| @ -19,7 +21,30 @@ enum HashAlgorithm { | ||||
| 
 | ||||
|   /// Digest the [data] using this [HashAlgorithm]. | ||||
|   Future<Uint8List> digest(Uint8List data) async { | ||||
|     final Uint8List hash = (await platform.digest(data, name)) ?? Uint8List(0); | ||||
|     Uint8List? hash; | ||||
|     try { | ||||
|       hash = await platform.digest(data, name); | ||||
|     } catch (e, s) { | ||||
|       throw NativeCryptoException( | ||||
|         message: '$e', | ||||
|         code: NativeCryptoExceptionCode.platform_throws.code, | ||||
|         stackTrace: s, | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     if (hash.isNull) { | ||||
|       throw NativeCryptoException( | ||||
|         message: 'Failed to digest data! Platform returned null.', | ||||
|         code: NativeCryptoExceptionCode.platform_returned_null.code, | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     if (hash!.isEmpty) { | ||||
|       throw NativeCryptoException( | ||||
|         message: 'Failed to digest data! Platform returned no data.', | ||||
|         code: NativeCryptoExceptionCode.platform_returned_empty_data.code, | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     return hash; | ||||
|   } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user