From a1112b5c80ac0c702efe93db4e60390ada0a1603 Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Wed, 25 May 2022 10:51:20 +0200 Subject: [PATCH] feat: export new exceptions --- .vscode/launch.json | 28 +++ .../example/lib/pages/cipher_page.dart | 6 +- packages/native_crypto/lib/native_crypto.dart | 4 +- .../lib/src/builders/aes_builder.dart | 9 +- .../lib/src/ciphers/aes/aes.dart | 15 +- .../lib/src/ciphers/aes/aes_mode.dart | 4 +- .../lib/src/ciphers/aes/aes_padding.dart | 4 +- packages/native_crypto/lib/src/core/core.dart | 3 +- .../lib/src/core/exceptions.dart | 41 ----- .../native_crypto/lib/src/kdf/pbkdf2.dart | 9 +- .../lib/src/keys/secret_key.dart | 13 +- packages/native_crypto/lib/src/platform.dart | 2 +- .../native_crypto_android/ciphers/AES.kt | 61 ++----- .../method_channel_native_crypto.dart | 156 +++++++++------- .../lib/src/utils/exception.dart | 170 ++++++++++++++---- 15 files changed, 313 insertions(+), 212 deletions(-) create mode 100644 .vscode/launch.json delete mode 100644 packages/native_crypto/lib/src/core/exceptions.dart diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d9becfd --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "native_crypto", + "cwd": "packages/native_crypto/example", + "request": "launch", + "type": "dart" + }, + { + "name": "native_crypto (profile mode)", + "cwd": "packages/native_crypto/example", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "native_crypto (release mode)", + "cwd": "packages/native_crypto/example", + "request": "launch", + "type": "dart", + "flutterMode": "release" + }, + ] +} \ No newline at end of file diff --git a/packages/native_crypto/example/lib/pages/cipher_page.dart b/packages/native_crypto/example/lib/pages/cipher_page.dart index 8a6bc7c..e953a87 100644 --- a/packages/native_crypto/example/lib/pages/cipher_page.dart +++ b/packages/native_crypto/example/lib/pages/cipher_page.dart @@ -3,7 +3,7 @@ // ----- // File: cipher_page.dart // Created Date: 28/12/2021 13:33:15 -// Last Modified: 28/12/2021 15:20:43 +// Last Modified: 25/05/2022 10:49:30 // ----- // Copyright (c) 2021 @@ -85,8 +85,8 @@ class CipherPage extends ConsumerWidget { var bytesToString = plainText.toStr(); decryptionStatus .print('String successfully decrypted:\n\n$bytesToString'); - } on DecryptionException catch (e) { - decryptionStatus.print(e.message); + } on NativeCryptoException catch (e) { + decryptionStatus.print(e.message ?? 'Decryption failed!'); } } } diff --git a/packages/native_crypto/lib/native_crypto.dart b/packages/native_crypto/lib/native_crypto.dart index 226381f..c42ea91 100644 --- a/packages/native_crypto/lib/native_crypto.dart +++ b/packages/native_crypto/lib/native_crypto.dart @@ -3,7 +3,7 @@ // ----- // File: native_crypto.dart // Created Date: 16/12/2021 16:28:00 -// Last Modified: 23/05/2022 23:09:10 +// Last Modified: 25/05/2022 10:48:20 // ----- // Copyright (c) 2021 @@ -13,6 +13,8 @@ /// Author: Hugo Pointcheval library native_crypto; +export 'package:native_crypto_platform_interface/src/utils/exception.dart'; + export 'src/builders/builders.dart'; export 'src/ciphers/ciphers.dart'; export 'src/core/core.dart'; diff --git a/packages/native_crypto/lib/src/builders/aes_builder.dart b/packages/native_crypto/lib/src/builders/aes_builder.dart index 955849c..e256d29 100644 --- a/packages/native_crypto/lib/src/builders/aes_builder.dart +++ b/packages/native_crypto/lib/src/builders/aes_builder.dart @@ -3,14 +3,14 @@ // ----- // File: aes_builder.dart // Created Date: 28/12/2021 12:03:11 -// Last Modified: 23/05/2022 23:05:19 +// Last Modified: 25/05/2022 10:47:11 // ----- // Copyright (c) 2021 import 'package:native_crypto/src/ciphers/aes/aes.dart'; -import 'package:native_crypto/src/core/exceptions.dart'; import 'package:native_crypto/src/interfaces/builder.dart'; import 'package:native_crypto/src/keys/secret_key.dart'; +import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; class AESBuilder implements Builder { SecretKey? _sk; @@ -36,7 +36,10 @@ class AESBuilder implements Builder { Future build() async { if (_sk == null) { if (_fsk == null) { - throw CipherInitException('You must specify or generate a secret key.'); + throw const CipherInitException( + message: 'You must specify or generate a secret key.', + code: 'missing_key', + ); } else { _sk = await _fsk; } diff --git a/packages/native_crypto/lib/src/ciphers/aes/aes.dart b/packages/native_crypto/lib/src/ciphers/aes/aes.dart index d740757..1f175ab 100644 --- a/packages/native_crypto/lib/src/ciphers/aes/aes.dart +++ b/packages/native_crypto/lib/src/ciphers/aes/aes.dart @@ -3,7 +3,7 @@ // ----- // File: aes.dart // Created Date: 16/12/2021 16:28:00 -// Last Modified: 24/05/2022 23:29:42 +// Last Modified: 25/05/2022 10:44:25 // ----- // Copyright (c) 2022 @@ -14,11 +14,11 @@ import 'package:native_crypto/src/ciphers/aes/aes_mode.dart'; import 'package:native_crypto/src/ciphers/aes/aes_padding.dart'; import 'package:native_crypto/src/core/cipher_text.dart'; import 'package:native_crypto/src/core/cipher_text_list.dart'; -import 'package:native_crypto/src/core/exceptions.dart'; import 'package:native_crypto/src/interfaces/cipher.dart'; import 'package:native_crypto/src/keys/secret_key.dart'; import 'package:native_crypto/src/platform.dart'; import 'package:native_crypto/src/utils/cipher_algorithm.dart'; +import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; export 'package:native_crypto/src/ciphers/aes/aes_key_size.dart'; export 'package:native_crypto/src/ciphers/aes/aes_mode.dart'; @@ -34,16 +34,21 @@ class AES implements Cipher { AES(this.key, this.mode, {this.padding = AESPadding.none}) { if (!AESKeySize.supportedSizes.contains(key.bytes.length * 8)) { - throw CipherInitException('Invalid key length!'); + throw const CipherInitException( + message: 'Invalid key length!', + code: 'invalid_key_length', + ); } final Map> _supported = { AESMode.gcm: [AESPadding.none], - AESMode.cbc: [AESPadding.pkcs5], }; if (!_supported[mode]!.contains(padding)) { - throw CipherInitException('Invalid padding!'); + throw const CipherInitException( + message: 'Invalid padding!', + code: 'invalid_padding', + ); } } diff --git a/packages/native_crypto/lib/src/ciphers/aes/aes_mode.dart b/packages/native_crypto/lib/src/ciphers/aes/aes_mode.dart index 1ff7b5d..c1d98cb 100644 --- a/packages/native_crypto/lib/src/ciphers/aes/aes_mode.dart +++ b/packages/native_crypto/lib/src/ciphers/aes/aes_mode.dart @@ -3,9 +3,9 @@ // ----- // File: aes_mode.dart // Created Date: 23/05/2022 22:09:16 -// Last Modified: 24/05/2022 23:17:01 +// Last Modified: 25/05/2022 09:23:54 // ----- // Copyright (c) 2022 /// Defines the AES modes of operation. -enum AESMode { gcm, cbc } +enum AESMode { gcm } diff --git a/packages/native_crypto/lib/src/ciphers/aes/aes_padding.dart b/packages/native_crypto/lib/src/ciphers/aes/aes_padding.dart index 676f526..343ae03 100644 --- a/packages/native_crypto/lib/src/ciphers/aes/aes_padding.dart +++ b/packages/native_crypto/lib/src/ciphers/aes/aes_padding.dart @@ -3,9 +3,9 @@ // ----- // File: aes_padding.dart // Created Date: 23/05/2022 22:10:17 -// Last Modified: 24/05/2022 23:17:25 +// Last Modified: 25/05/2022 09:23:49 // ----- // Copyright (c) 2022 /// Represents different paddings. -enum AESPadding { none, pkcs5 } +enum AESPadding { none } diff --git a/packages/native_crypto/lib/src/core/core.dart b/packages/native_crypto/lib/src/core/core.dart index 97597ac..5ab875c 100644 --- a/packages/native_crypto/lib/src/core/core.dart +++ b/packages/native_crypto/lib/src/core/core.dart @@ -3,10 +3,9 @@ // ----- // File: core.dart // Created Date: 23/05/2022 23:05:26 -// Last Modified: 23/05/2022 23:05:30 +// Last Modified: 25/05/2022 10:44:32 // ----- // Copyright (c) 2022 export 'cipher_text.dart'; export 'cipher_text_list.dart'; -export 'exceptions.dart'; diff --git a/packages/native_crypto/lib/src/core/exceptions.dart b/packages/native_crypto/lib/src/core/exceptions.dart deleted file mode 100644 index 96c21d0..0000000 --- a/packages/native_crypto/lib/src/core/exceptions.dart +++ /dev/null @@ -1,41 +0,0 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: exceptions.dart -// Created Date: 16/12/2021 16:28:00 -// Last Modified: 23/05/2022 22:30:27 -// ----- -// Copyright (c) 2021 - -class NativeCryptoException implements Exception { - final String message; - const NativeCryptoException(this.message); -} - -class UtilsException extends NativeCryptoException { - UtilsException(super.message); -} - -class KeyException extends NativeCryptoException { - KeyException(super.message); -} - -class KeyDerivationException extends NativeCryptoException { - KeyDerivationException(super.message); -} - -class CipherInitException extends NativeCryptoException { - CipherInitException(super.message); -} - -class EncryptionException extends NativeCryptoException { - EncryptionException(super.message); -} - -class DecryptionException extends NativeCryptoException { - DecryptionException(super.message); -} - -class NotImplementedException extends NativeCryptoException { - NotImplementedException(super.message); -} diff --git a/packages/native_crypto/lib/src/kdf/pbkdf2.dart b/packages/native_crypto/lib/src/kdf/pbkdf2.dart index 04672bd..7d8acc2 100644 --- a/packages/native_crypto/lib/src/kdf/pbkdf2.dart +++ b/packages/native_crypto/lib/src/kdf/pbkdf2.dart @@ -3,18 +3,18 @@ // ----- // File: pbkdf2.dart // Created Date: 17/12/2021 14:50:42 -// Last Modified: 23/05/2022 23:07:19 +// Last Modified: 25/05/2022 10:45:00 // ----- // Copyright (c) 2021 import 'dart:typed_data'; -import 'package:native_crypto/src/core/exceptions.dart'; import 'package:native_crypto/src/interfaces/keyderivation.dart'; import 'package:native_crypto/src/keys/secret_key.dart'; import 'package:native_crypto/src/platform.dart'; import 'package:native_crypto/src/utils/hash_algorithm.dart'; import 'package:native_crypto/src/utils/kdf_algorithm.dart'; +import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; class Pbkdf2 extends KeyDerivation { final int _keyBytesCount; @@ -35,7 +35,10 @@ class Pbkdf2 extends KeyDerivation { @override Future derive({String? password, String? salt}) async { if (password == null || salt == null) { - throw KeyDerivationException("Password or Salt can't be null!"); + throw const KeyDerivationException( + message: "Password or Salt can't be null!", + code: 'invalid_password_or_salt', + ); } final Uint8List derivation = (await platform.pbkdf2( diff --git a/packages/native_crypto/lib/src/keys/secret_key.dart b/packages/native_crypto/lib/src/keys/secret_key.dart index 98a1097..1aa9031 100644 --- a/packages/native_crypto/lib/src/keys/secret_key.dart +++ b/packages/native_crypto/lib/src/keys/secret_key.dart @@ -3,16 +3,15 @@ // ----- // File: secret_key.dart // Created Date: 28/12/2021 13:36:54 -// Last Modified: 23/05/2022 23:07:28 +// Last Modified: 25/05/2022 10:45:55 // ----- // Copyright (c) 2021 import 'dart:typed_data'; -import 'package:flutter/services.dart'; -import 'package:native_crypto/src/core/exceptions.dart'; import 'package:native_crypto/src/interfaces/key.dart'; import 'package:native_crypto/src/platform.dart'; +import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; /// A class representing a secret key. /// A secret key is a key that is not accessible by anyone else. @@ -29,8 +28,12 @@ class SecretKey extends Key { (await platform.generateSecretKey(bitsCount)) ?? Uint8List(0); return SecretKey(_key); - } on PlatformException catch (e) { - throw KeyException(e.toString()); + } catch (e, s) { + throw KeyException( + message: 'Failed to generate a secret key!', + code: 'failed_to_generate_secret_key', + stackTrace: s, + ); } } } diff --git a/packages/native_crypto/lib/src/platform.dart b/packages/native_crypto/lib/src/platform.dart index c4c13c1..5d62b5e 100644 --- a/packages/native_crypto/lib/src/platform.dart +++ b/packages/native_crypto/lib/src/platform.dart @@ -3,7 +3,7 @@ // ----- // File: platform.dart // Created Date: 27/12/2021 22:03:58 -// Last Modified: 27/12/2021 22:04:30 +// Last Modified: 25/05/2022 10:09:18 // ----- // Copyright (c) 2021 diff --git a/packages/native_crypto_android/android/src/main/kotlin/fr/pointcheval/native_crypto_android/ciphers/AES.kt b/packages/native_crypto_android/android/src/main/kotlin/fr/pointcheval/native_crypto_android/ciphers/AES.kt index 1bb2c3b..0b4c86c 100644 --- a/packages/native_crypto_android/android/src/main/kotlin/fr/pointcheval/native_crypto_android/ciphers/AES.kt +++ b/packages/native_crypto_android/android/src/main/kotlin/fr/pointcheval/native_crypto_android/ciphers/AES.kt @@ -11,74 +11,45 @@ class AES : Cipher { override val algorithm: CipherAlgorithm get() = CipherAlgorithm.aes - var forEncryption: Boolean = true var cipherInstance: javax.crypto.Cipher? = null; - var secretKey: SecretKeySpec? = null; -/* override fun encrypt(data: ByteArray, key: ByteArray): ByteArray { - val sk: SecretKey = SecretKeySpec(key, "AES") - val cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding") - cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, sk) - // javax.crypto representation = [CIPHERTEXT(n-16) || TAG(16)] - val bytes = cipher.doFinal(data) - val iv = cipher.iv.copyOf() // 12 bytes nonce - // native.crypto representation = [NONCE(12) || CIPHERTEXT(n-28) || TAG(16)] - return iv.plus(bytes) + fun lazyLoadCipher() { + if (cipherInstance == null) { + cipherInstance = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding") + } } - override fun decrypt(data: ByteArray, key: ByteArray): ByteArray { - val sk: SecretKey = SecretKeySpec(key, "AES") - // native.crypto representation = [NONCE(12) || CIPHERTEXT(n-16) || TAG(16)] - val iv: ByteArray = data.take(12).toByteArray() - // javax.crypto representation = [CIPHERTEXT(n-28) || TAG(16)] - val payload: ByteArray = data.drop(12).toByteArray() - val spec = GCMParameterSpec(16 * 8, iv) - val cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding") - cipher.init(javax.crypto.Cipher.DECRYPT_MODE, sk, spec) - return cipher.doFinal(payload) - }*/ - + // native.crypto cipherText representation = [NONCE(12) || CIPHERTEXT(n-28) || TAG(16)] + // javax.crypto cipherText representation = [NONCE(12)] + [CIPHERTEXT(n-16) || TAG(16)] override fun encrypt(data: ByteArray, key: ByteArray): ByteArray { val list : List = encryptAsList(data, key) return list.first().plus(list.last()) } + // native.crypto cipherText representation = [NONCE(12)] + [CIPHERTEXT(n-16) || TAG(16)] + // javax.crypto cipherText representation = [NONCE(12)] + [CIPHERTEXT(n-16) || TAG(16)] override fun encryptAsList(data: ByteArray, key: ByteArray): List { val sk = SecretKeySpec(key, "AES") - if (cipherInstance == null || !forEncryption || secretKey != sk) { - secretKey = sk - forEncryption = true - // native.crypto representation = [IV(16) || CIPHERTEXT(n-16)] - // javax.crypto representation = [CIPHERTEXT(n-16)] - cipherInstance = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding") - cipherInstance!!.init(javax.crypto.Cipher.ENCRYPT_MODE, sk) - } - // javax.crypto representation = [CIPHERTEXT(n-16)] + lazyLoadCipher() + cipherInstance!!.init(javax.crypto.Cipher.ENCRYPT_MODE, sk) val bytes: ByteArray = cipherInstance!!.doFinal(data) val iv: ByteArray = cipherInstance!!.iv - // native.crypto representation = [IV(16) || CIPHERTEXT(n-16)] return listOf(iv, bytes) } override fun decrypt(data: ByteArray, key: ByteArray): ByteArray { - // javax.crypto representation = [CIPHERTEXT(n-16)] - val iv: ByteArray = data.take(16).toByteArray() - val payload: ByteArray = data.drop(16).toByteArray() + val iv: ByteArray = data.take(12).toByteArray() + val payload: ByteArray = data.drop(12).toByteArray() return decryptAsList(listOf(iv, payload), key) } override fun decryptAsList(data: List, key: ByteArray): ByteArray { - if (cipherInstance == null) { - // native.crypto representation = [IV(16) || CIPHERTEXT(n-16)] - // javax.crypto representation = [CIPHERTEXT(n-16)] - cipherInstance = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding") - } val sk = SecretKeySpec(key, "AES") - val iv: ByteArray = data.first() - val ivSpec = IvParameterSpec(iv) - cipherInstance!!.init(javax.crypto.Cipher.DECRYPT_MODE, sk, ivSpec) - forEncryption = false val payload: ByteArray = data.last() + val iv: ByteArray = data.first() + val gcmSpec = GCMParameterSpec(16 * 8, iv) + lazyLoadCipher() + cipherInstance!!.init(javax.crypto.Cipher.DECRYPT_MODE, sk, gcmSpec) return cipherInstance!!.doFinal(payload) } } \ No newline at end of file diff --git a/packages/native_crypto_platform_interface/lib/src/method_channel/method_channel_native_crypto.dart b/packages/native_crypto_platform_interface/lib/src/method_channel/method_channel_native_crypto.dart index 7205096..0559ed4 100644 --- a/packages/native_crypto_platform_interface/lib/src/method_channel/method_channel_native_crypto.dart +++ b/packages/native_crypto_platform_interface/lib/src/method_channel/method_channel_native_crypto.dart @@ -3,7 +3,7 @@ // ----- // File: native_crypto_method_channel.dart // Created Date: 25/12/2021 16:58:04 -// Last Modified: 24/05/2022 22:59:32 +// Last Modified: 25/05/2022 10:40:29 // ----- // Copyright (c) 2021 @@ -11,7 +11,7 @@ import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import 'package:native_crypto_platform_interface/src/platform_interface/native_crypto_platform.dart'; +import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; /// An implementation of [NativeCryptoPlatform] that uses method channels. class MethodChannelNativeCrypto extends NativeCryptoPlatform { @@ -20,24 +20,32 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { MethodChannel channel = const MethodChannel('plugins.hugop.cl/native_crypto'); @override - Future digest(Uint8List data, String algorithm) { - return channel.invokeMethod( - 'digest', - { - 'data': data, - 'algorithm': algorithm, - }, - ); + Future digest(Uint8List data, String algorithm) async { + try { + return await channel.invokeMethod( + 'digest', + { + 'data': data, + 'algorithm': algorithm, + }, + ); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } } @override - Future generateSecretKey(int bitsCount) { - return channel.invokeMethod( - 'generateSecretKey', - { - 'bitsCount': bitsCount, - }, - ); + Future generateSecretKey(int bitsCount) async { + try { + return await channel.invokeMethod( + 'generateSecretKey', + { + 'bitsCount': bitsCount, + }, + ); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } } @override @@ -47,17 +55,21 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { int keyBytesCount, int iterations, String algorithm, - ) { - return channel.invokeMethod( - 'pbkdf2', - { - 'password': password, - 'salt': salt, - 'keyBytesCount': keyBytesCount, - 'iterations': iterations, - 'algorithm': algorithm, - }, - ); + ) async { + try { + return await channel.invokeMethod( + 'pbkdf2', + { + 'password': password, + 'salt': salt, + 'keyBytesCount': keyBytesCount, + 'iterations': iterations, + 'algorithm': algorithm, + }, + ); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } } @override @@ -65,15 +77,19 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { Uint8List data, Uint8List key, String algorithm, - ) { - return channel.invokeListMethod( - 'encryptAsList', - { - 'data': data, - 'key': key, - 'algorithm': algorithm, - }, - ); + ) async { + try { + return await channel.invokeListMethod( + 'encryptAsList', + { + 'data': data, + 'key': key, + 'algorithm': algorithm, + }, + ); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } } @override @@ -81,15 +97,19 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { List data, Uint8List key, String algorithm, - ) { - return channel.invokeMethod( - 'decryptAsList', - { - 'data': data, - 'key': key, - 'algorithm': algorithm, - }, - ); + ) async { + try { + return await channel.invokeMethod( + 'decryptAsList', + { + 'data': data, + 'key': key, + 'algorithm': algorithm, + }, + ); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } } @override @@ -97,15 +117,19 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { Uint8List data, Uint8List key, String algorithm, - ) { - return channel.invokeMethod( - 'encrypt', - { - 'data': data, - 'key': key, - 'algorithm': algorithm, - }, - ); + ) async { + try { + return await channel.invokeMethod( + 'encrypt', + { + 'data': data, + 'key': key, + 'algorithm': algorithm, + }, + ); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } } @override @@ -113,14 +137,18 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform { Uint8List data, Uint8List key, String algorithm, - ) { - return channel.invokeMethod( - 'decrypt', - { - 'data': data, - 'key': key, - 'algorithm': algorithm, - }, - ); + ) async { + try { + return await channel.invokeMethod( + 'decrypt', + { + 'data': data, + 'key': key, + 'algorithm': algorithm, + }, + ); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } } } diff --git a/packages/native_crypto_platform_interface/lib/src/utils/exception.dart b/packages/native_crypto_platform_interface/lib/src/utils/exception.dart index 24af864..196a2bd 100644 --- a/packages/native_crypto_platform_interface/lib/src/utils/exception.dart +++ b/packages/native_crypto_platform_interface/lib/src/utils/exception.dart @@ -3,51 +3,151 @@ // ----- // File: exception.dart // Created Date: 24/05/2022 18:54:48 -// Last Modified: 24/05/2022 18:58:39 +// Last Modified: 25/05/2022 10:43:29 // ----- // Copyright (c) 2022 +import 'dart:developer'; + import 'package:flutter/services.dart'; class NativeCryptoException implements Exception { - final String message; - const NativeCryptoException(this.message); -} + const NativeCryptoException({ + this.message, + String? code, + this.stackTrace, + // ignore: unnecessary_this + }) : this.code = code ?? 'unknown'; -/// Catches a [PlatformException] and returns an [Exception]. -/// -/// If the [Exception] is a [PlatformException], -/// a [NativeCryptoException] is returned. -Never convertPlatformException(Object exception, StackTrace stackTrace) { - if (exception is! Exception || exception is! PlatformException) { - Error.throwWithStackTrace(exception, stackTrace); + /// The long form message of the exception. + final String? message; + + /// The optional code to accommodate the message. + final String code; + + /// The stack trace which provides information to the user about the call + /// sequence that triggered an exception + final StackTrace? stackTrace; + + @override + String toString() { + String output = '[NativeException/$code] $message'; + + if (stackTrace != null) { + output += '\n\n${stackTrace.toString()}'; + } + + return output; } - Error.throwWithStackTrace( - platformExceptionToNativeCryptoException(exception, stackTrace), - stackTrace, - ); -} + /// Catches a [PlatformException] and returns an [Exception]. + /// + /// If the [Exception] is a [PlatformException], + /// a [NativeCryptoException] is returned. + static Never convertPlatformException( + Object exception, + StackTrace stackTrace, + ) { + log(exception.toString()); + if (exception is! Exception || exception is! PlatformException) { + Error.throwWithStackTrace(exception, stackTrace); + } -/// Converts a [PlatformException] into a [NativeCryptoException]. -/// -/// A [PlatformException] can only be converted to a [NativeCryptoException] -/// if the `details` of the exception exist. -NativeCryptoException platformExceptionToNativeCryptoException( - PlatformException platformException, - StackTrace stackTrace, -) { - final Map? details = platformException.details != null - ? Map.from( - platformException.details as Map, - ) - : null; - - String message = platformException.message ?? ''; - - if (details != null) { - message = details['message'] ?? message; + Error.throwWithStackTrace( + NativeCryptoException.fromPlatformException(exception, stackTrace), + stackTrace, + ); } - return NativeCryptoException(message); + /// Converts a [PlatformException] into a [NativeCryptoException]. + /// + /// A [PlatformException] can only be converted to a [NativeCryptoException] + /// if the `details` of the exception exist. + factory NativeCryptoException.fromPlatformException( + PlatformException platformException, + StackTrace stackTrace, + ) { + final Map? details = platformException.details != null + ? Map.from( + platformException.details as Map, + ) + : null; + + String code = 'unknown'; + String message = platformException.message ?? ''; + + if (details != null) { + code = details['code'] ?? code; + message = details['message'] ?? message; + } + + return NativeCryptoException( + message: message, + code: code, + stackTrace: stackTrace, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is NativeCryptoException && + other.message == message && + other.code == code && + other.stackTrace == stackTrace; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => message.hashCode ^ code.hashCode ^ stackTrace.hashCode; +} + +class KeyException extends NativeCryptoException { + const KeyException({ + super.message, + super.code, + super.stackTrace, + }); +} + +class KeyDerivationException extends NativeCryptoException { + const KeyDerivationException({ + super.message, + super.code, + super.stackTrace, + }); +} + +class CipherInitException extends NativeCryptoException { + const CipherInitException({ + super.message, + super.code, + super.stackTrace, + }); +} + +class EncryptionException extends NativeCryptoException { + const EncryptionException({ + super.message, + super.code, + super.stackTrace, + }); +} + +class DecryptionException extends NativeCryptoException { + const DecryptionException({ + super.message, + super.code, + super.stackTrace, + }); +} + +class NotImplementedException extends NativeCryptoException { + const NotImplementedException({ + super.message, + super.code, + super.stackTrace, + }); }