feat: export new exceptions
This commit is contained in:
parent
a7affea1e1
commit
a1112b5c80
28
.vscode/launch.json
vendored
Normal file
28
.vscode/launch.json
vendored
Normal file
@ -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"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: cipher_page.dart
|
// File: cipher_page.dart
|
||||||
// Created Date: 28/12/2021 13:33:15
|
// 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
|
// Copyright (c) 2021
|
||||||
|
|
||||||
@ -85,8 +85,8 @@ class CipherPage extends ConsumerWidget {
|
|||||||
var bytesToString = plainText.toStr();
|
var bytesToString = plainText.toStr();
|
||||||
decryptionStatus
|
decryptionStatus
|
||||||
.print('String successfully decrypted:\n\n$bytesToString');
|
.print('String successfully decrypted:\n\n$bytesToString');
|
||||||
} on DecryptionException catch (e) {
|
} on NativeCryptoException catch (e) {
|
||||||
decryptionStatus.print(e.message);
|
decryptionStatus.print(e.message ?? 'Decryption failed!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: native_crypto.dart
|
// File: native_crypto.dart
|
||||||
// Created Date: 16/12/2021 16:28:00
|
// 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
|
// Copyright (c) 2021
|
||||||
|
|
||||||
@ -13,6 +13,8 @@
|
|||||||
/// Author: Hugo Pointcheval
|
/// Author: Hugo Pointcheval
|
||||||
library native_crypto;
|
library native_crypto;
|
||||||
|
|
||||||
|
export 'package:native_crypto_platform_interface/src/utils/exception.dart';
|
||||||
|
|
||||||
export 'src/builders/builders.dart';
|
export 'src/builders/builders.dart';
|
||||||
export 'src/ciphers/ciphers.dart';
|
export 'src/ciphers/ciphers.dart';
|
||||||
export 'src/core/core.dart';
|
export 'src/core/core.dart';
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: aes_builder.dart
|
// File: aes_builder.dart
|
||||||
// Created Date: 28/12/2021 12:03:11
|
// 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
|
// Copyright (c) 2021
|
||||||
|
|
||||||
import 'package:native_crypto/src/ciphers/aes/aes.dart';
|
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/interfaces/builder.dart';
|
||||||
import 'package:native_crypto/src/keys/secret_key.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<AES> {
|
class AESBuilder implements Builder<AES> {
|
||||||
SecretKey? _sk;
|
SecretKey? _sk;
|
||||||
@ -36,7 +36,10 @@ class AESBuilder implements Builder<AES> {
|
|||||||
Future<AES> build() async {
|
Future<AES> build() async {
|
||||||
if (_sk == null) {
|
if (_sk == null) {
|
||||||
if (_fsk == 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 {
|
} else {
|
||||||
_sk = await _fsk;
|
_sk = await _fsk;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: aes.dart
|
// File: aes.dart
|
||||||
// Created Date: 16/12/2021 16:28:00
|
// 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
|
// 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/ciphers/aes/aes_padding.dart';
|
||||||
import 'package:native_crypto/src/core/cipher_text.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/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/interfaces/cipher.dart';
|
||||||
import 'package:native_crypto/src/keys/secret_key.dart';
|
import 'package:native_crypto/src/keys/secret_key.dart';
|
||||||
import 'package:native_crypto/src/platform.dart';
|
import 'package:native_crypto/src/platform.dart';
|
||||||
import 'package:native_crypto/src/utils/cipher_algorithm.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_key_size.dart';
|
||||||
export 'package:native_crypto/src/ciphers/aes/aes_mode.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}) {
|
AES(this.key, this.mode, {this.padding = AESPadding.none}) {
|
||||||
if (!AESKeySize.supportedSizes.contains(key.bytes.length * 8)) {
|
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<AESMode, List<AESPadding>> _supported = {
|
final Map<AESMode, List<AESPadding>> _supported = {
|
||||||
AESMode.gcm: [AESPadding.none],
|
AESMode.gcm: [AESPadding.none],
|
||||||
AESMode.cbc: [AESPadding.pkcs5],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!_supported[mode]!.contains(padding)) {
|
if (!_supported[mode]!.contains(padding)) {
|
||||||
throw CipherInitException('Invalid padding!');
|
throw const CipherInitException(
|
||||||
|
message: 'Invalid padding!',
|
||||||
|
code: 'invalid_padding',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: aes_mode.dart
|
// File: aes_mode.dart
|
||||||
// Created Date: 23/05/2022 22:09:16
|
// 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
|
// Copyright (c) 2022
|
||||||
|
|
||||||
/// Defines the AES modes of operation.
|
/// Defines the AES modes of operation.
|
||||||
enum AESMode { gcm, cbc }
|
enum AESMode { gcm }
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: aes_padding.dart
|
// File: aes_padding.dart
|
||||||
// Created Date: 23/05/2022 22:10:17
|
// 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
|
// Copyright (c) 2022
|
||||||
|
|
||||||
/// Represents different paddings.
|
/// Represents different paddings.
|
||||||
enum AESPadding { none, pkcs5 }
|
enum AESPadding { none }
|
||||||
|
@ -3,10 +3,9 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: core.dart
|
// File: core.dart
|
||||||
// Created Date: 23/05/2022 23:05:26
|
// 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
|
// Copyright (c) 2022
|
||||||
|
|
||||||
export 'cipher_text.dart';
|
export 'cipher_text.dart';
|
||||||
export 'cipher_text_list.dart';
|
export 'cipher_text_list.dart';
|
||||||
export 'exceptions.dart';
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -3,18 +3,18 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: pbkdf2.dart
|
// File: pbkdf2.dart
|
||||||
// Created Date: 17/12/2021 14:50:42
|
// 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
|
// Copyright (c) 2021
|
||||||
|
|
||||||
import 'dart:typed_data';
|
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/interfaces/keyderivation.dart';
|
||||||
import 'package:native_crypto/src/keys/secret_key.dart';
|
import 'package:native_crypto/src/keys/secret_key.dart';
|
||||||
import 'package:native_crypto/src/platform.dart';
|
import 'package:native_crypto/src/platform.dart';
|
||||||
import 'package:native_crypto/src/utils/hash_algorithm.dart';
|
import 'package:native_crypto/src/utils/hash_algorithm.dart';
|
||||||
import 'package:native_crypto/src/utils/kdf_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 {
|
class Pbkdf2 extends KeyDerivation {
|
||||||
final int _keyBytesCount;
|
final int _keyBytesCount;
|
||||||
@ -35,7 +35,10 @@ class Pbkdf2 extends KeyDerivation {
|
|||||||
@override
|
@override
|
||||||
Future<SecretKey> derive({String? password, String? salt}) async {
|
Future<SecretKey> derive({String? password, String? salt}) async {
|
||||||
if (password == null || salt == null) {
|
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(
|
final Uint8List derivation = (await platform.pbkdf2(
|
||||||
|
@ -3,16 +3,15 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: secret_key.dart
|
// File: secret_key.dart
|
||||||
// Created Date: 28/12/2021 13:36:54
|
// 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
|
// Copyright (c) 2021
|
||||||
|
|
||||||
import 'dart:typed_data';
|
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/interfaces/key.dart';
|
||||||
import 'package:native_crypto/src/platform.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 class representing a secret key.
|
||||||
/// A secret key is a key that is not accessible by anyone else.
|
/// 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);
|
(await platform.generateSecretKey(bitsCount)) ?? Uint8List(0);
|
||||||
|
|
||||||
return SecretKey(_key);
|
return SecretKey(_key);
|
||||||
} on PlatformException catch (e) {
|
} catch (e, s) {
|
||||||
throw KeyException(e.toString());
|
throw KeyException(
|
||||||
|
message: 'Failed to generate a secret key!',
|
||||||
|
code: 'failed_to_generate_secret_key',
|
||||||
|
stackTrace: s,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: platform.dart
|
// File: platform.dart
|
||||||
// Created Date: 27/12/2021 22:03:58
|
// 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
|
// Copyright (c) 2021
|
||||||
|
|
||||||
|
@ -11,74 +11,45 @@ class AES : Cipher {
|
|||||||
override val algorithm: CipherAlgorithm
|
override val algorithm: CipherAlgorithm
|
||||||
get() = CipherAlgorithm.aes
|
get() = CipherAlgorithm.aes
|
||||||
|
|
||||||
var forEncryption: Boolean = true
|
|
||||||
var cipherInstance: javax.crypto.Cipher? = null;
|
var cipherInstance: javax.crypto.Cipher? = null;
|
||||||
var secretKey: SecretKeySpec? = null;
|
|
||||||
|
|
||||||
/* override fun encrypt(data: ByteArray, key: ByteArray): ByteArray {
|
fun lazyLoadCipher() {
|
||||||
val sk: SecretKey = SecretKeySpec(key, "AES")
|
if (cipherInstance == null) {
|
||||||
val cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding")
|
cipherInstance = 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun decrypt(data: ByteArray, key: ByteArray): ByteArray {
|
// native.crypto cipherText representation = [NONCE(12) || CIPHERTEXT(n-28) || TAG(16)]
|
||||||
val sk: SecretKey = SecretKeySpec(key, "AES")
|
// javax.crypto cipherText representation = [NONCE(12)] + [CIPHERTEXT(n-16) || TAG(16)]
|
||||||
// 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)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
override fun encrypt(data: ByteArray, key: ByteArray): ByteArray {
|
override fun encrypt(data: ByteArray, key: ByteArray): ByteArray {
|
||||||
val list : List<ByteArray> = encryptAsList(data, key)
|
val list : List<ByteArray> = encryptAsList(data, key)
|
||||||
return list.first().plus(list.last())
|
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<ByteArray> {
|
override fun encryptAsList(data: ByteArray, key: ByteArray): List<ByteArray> {
|
||||||
val sk = SecretKeySpec(key, "AES")
|
val sk = SecretKeySpec(key, "AES")
|
||||||
if (cipherInstance == null || !forEncryption || secretKey != sk) {
|
lazyLoadCipher()
|
||||||
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)
|
cipherInstance!!.init(javax.crypto.Cipher.ENCRYPT_MODE, sk)
|
||||||
}
|
|
||||||
// javax.crypto representation = [CIPHERTEXT(n-16)]
|
|
||||||
val bytes: ByteArray = cipherInstance!!.doFinal(data)
|
val bytes: ByteArray = cipherInstance!!.doFinal(data)
|
||||||
val iv: ByteArray = cipherInstance!!.iv
|
val iv: ByteArray = cipherInstance!!.iv
|
||||||
// native.crypto representation = [IV(16) || CIPHERTEXT(n-16)]
|
|
||||||
return listOf(iv, bytes)
|
return listOf(iv, bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun decrypt(data: ByteArray, key: ByteArray): ByteArray {
|
override fun decrypt(data: ByteArray, key: ByteArray): ByteArray {
|
||||||
// javax.crypto representation = [CIPHERTEXT(n-16)]
|
val iv: ByteArray = data.take(12).toByteArray()
|
||||||
val iv: ByteArray = data.take(16).toByteArray()
|
val payload: ByteArray = data.drop(12).toByteArray()
|
||||||
val payload: ByteArray = data.drop(16).toByteArray()
|
|
||||||
return decryptAsList(listOf(iv, payload), key)
|
return decryptAsList(listOf(iv, payload), key)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun decryptAsList(data: List<ByteArray>, key: ByteArray): ByteArray {
|
override fun decryptAsList(data: List<ByteArray>, 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 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 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)
|
return cipherInstance!!.doFinal(payload)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,7 +3,7 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: native_crypto_method_channel.dart
|
// File: native_crypto_method_channel.dart
|
||||||
// Created Date: 25/12/2021 16:58:04
|
// 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
|
// Copyright (c) 2021
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ import 'dart:typed_data';
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.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.
|
/// An implementation of [NativeCryptoPlatform] that uses method channels.
|
||||||
class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
||||||
@ -20,24 +20,32 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
MethodChannel channel = const MethodChannel('plugins.hugop.cl/native_crypto');
|
MethodChannel channel = const MethodChannel('plugins.hugop.cl/native_crypto');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Uint8List?> digest(Uint8List data, String algorithm) {
|
Future<Uint8List?> digest(Uint8List data, String algorithm) async {
|
||||||
return channel.invokeMethod<Uint8List>(
|
try {
|
||||||
|
return await channel.invokeMethod<Uint8List>(
|
||||||
'digest',
|
'digest',
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'data': data,
|
'data': data,
|
||||||
'algorithm': algorithm,
|
'algorithm': algorithm,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
NativeCryptoException.convertPlatformException(e, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Uint8List?> generateSecretKey(int bitsCount) {
|
Future<Uint8List?> generateSecretKey(int bitsCount) async {
|
||||||
return channel.invokeMethod<Uint8List>(
|
try {
|
||||||
|
return await channel.invokeMethod<Uint8List>(
|
||||||
'generateSecretKey',
|
'generateSecretKey',
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'bitsCount': bitsCount,
|
'bitsCount': bitsCount,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
NativeCryptoException.convertPlatformException(e, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -47,8 +55,9 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
int keyBytesCount,
|
int keyBytesCount,
|
||||||
int iterations,
|
int iterations,
|
||||||
String algorithm,
|
String algorithm,
|
||||||
) {
|
) async {
|
||||||
return channel.invokeMethod<Uint8List>(
|
try {
|
||||||
|
return await channel.invokeMethod<Uint8List>(
|
||||||
'pbkdf2',
|
'pbkdf2',
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'password': password,
|
'password': password,
|
||||||
@ -58,6 +67,9 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
'algorithm': algorithm,
|
'algorithm': algorithm,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
NativeCryptoException.convertPlatformException(e, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -65,8 +77,9 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
Uint8List data,
|
Uint8List data,
|
||||||
Uint8List key,
|
Uint8List key,
|
||||||
String algorithm,
|
String algorithm,
|
||||||
) {
|
) async {
|
||||||
return channel.invokeListMethod(
|
try {
|
||||||
|
return await channel.invokeListMethod(
|
||||||
'encryptAsList',
|
'encryptAsList',
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'data': data,
|
'data': data,
|
||||||
@ -74,6 +87,9 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
'algorithm': algorithm,
|
'algorithm': algorithm,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
NativeCryptoException.convertPlatformException(e, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -81,8 +97,9 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
List<Uint8List> data,
|
List<Uint8List> data,
|
||||||
Uint8List key,
|
Uint8List key,
|
||||||
String algorithm,
|
String algorithm,
|
||||||
) {
|
) async {
|
||||||
return channel.invokeMethod<Uint8List>(
|
try {
|
||||||
|
return await channel.invokeMethod<Uint8List>(
|
||||||
'decryptAsList',
|
'decryptAsList',
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'data': data,
|
'data': data,
|
||||||
@ -90,6 +107,9 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
'algorithm': algorithm,
|
'algorithm': algorithm,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
NativeCryptoException.convertPlatformException(e, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -97,8 +117,9 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
Uint8List data,
|
Uint8List data,
|
||||||
Uint8List key,
|
Uint8List key,
|
||||||
String algorithm,
|
String algorithm,
|
||||||
) {
|
) async {
|
||||||
return channel.invokeMethod<Uint8List>(
|
try {
|
||||||
|
return await channel.invokeMethod<Uint8List>(
|
||||||
'encrypt',
|
'encrypt',
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'data': data,
|
'data': data,
|
||||||
@ -106,6 +127,9 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
'algorithm': algorithm,
|
'algorithm': algorithm,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
NativeCryptoException.convertPlatformException(e, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -113,8 +137,9 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
Uint8List data,
|
Uint8List data,
|
||||||
Uint8List key,
|
Uint8List key,
|
||||||
String algorithm,
|
String algorithm,
|
||||||
) {
|
) async {
|
||||||
return channel.invokeMethod<Uint8List>(
|
try {
|
||||||
|
return await channel.invokeMethod<Uint8List>(
|
||||||
'decrypt',
|
'decrypt',
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'data': data,
|
'data': data,
|
||||||
@ -122,5 +147,8 @@ class MethodChannelNativeCrypto extends NativeCryptoPlatform {
|
|||||||
'algorithm': algorithm,
|
'algorithm': algorithm,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
NativeCryptoException.convertPlatformException(e, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,51 +3,151 @@
|
|||||||
// -----
|
// -----
|
||||||
// File: exception.dart
|
// File: exception.dart
|
||||||
// Created Date: 24/05/2022 18:54:48
|
// 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
|
// Copyright (c) 2022
|
||||||
|
|
||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
class NativeCryptoException implements Exception {
|
class NativeCryptoException implements Exception {
|
||||||
final String message;
|
const NativeCryptoException({
|
||||||
const NativeCryptoException(this.message);
|
this.message,
|
||||||
}
|
String? code,
|
||||||
|
this.stackTrace,
|
||||||
|
// ignore: unnecessary_this
|
||||||
|
}) : this.code = code ?? 'unknown';
|
||||||
|
|
||||||
/// Catches a [PlatformException] and returns an [Exception].
|
/// The long form message of the exception.
|
||||||
///
|
final String? message;
|
||||||
/// If the [Exception] is a [PlatformException],
|
|
||||||
/// a [NativeCryptoException] is returned.
|
/// The optional code to accommodate the message.
|
||||||
Never convertPlatformException(Object exception, StackTrace stackTrace) {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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) {
|
if (exception is! Exception || exception is! PlatformException) {
|
||||||
Error.throwWithStackTrace(exception, stackTrace);
|
Error.throwWithStackTrace(exception, stackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error.throwWithStackTrace(
|
Error.throwWithStackTrace(
|
||||||
platformExceptionToNativeCryptoException(exception, stackTrace),
|
NativeCryptoException.fromPlatformException(exception, stackTrace),
|
||||||
stackTrace,
|
stackTrace,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a [PlatformException] into a [NativeCryptoException].
|
/// Converts a [PlatformException] into a [NativeCryptoException].
|
||||||
///
|
///
|
||||||
/// A [PlatformException] can only be converted to a [NativeCryptoException]
|
/// A [PlatformException] can only be converted to a [NativeCryptoException]
|
||||||
/// if the `details` of the exception exist.
|
/// if the `details` of the exception exist.
|
||||||
NativeCryptoException platformExceptionToNativeCryptoException(
|
factory NativeCryptoException.fromPlatformException(
|
||||||
PlatformException platformException,
|
PlatformException platformException,
|
||||||
StackTrace stackTrace,
|
StackTrace stackTrace,
|
||||||
) {
|
) {
|
||||||
final Map<String, String>? details = platformException.details != null
|
final Map<String, String>? details = platformException.details != null
|
||||||
? Map<String, String>.from(
|
? Map<String, String>.from(
|
||||||
platformException.details as Map<String, String>,
|
platformException.details as Map<String, String>,
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
String code = 'unknown';
|
||||||
String message = platformException.message ?? '';
|
String message = platformException.message ?? '';
|
||||||
|
|
||||||
if (details != null) {
|
if (details != null) {
|
||||||
|
code = details['code'] ?? code;
|
||||||
message = details['message'] ?? message;
|
message = details['message'] ?? message;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NativeCryptoException(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,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user