Add async "constructors" for key generation

This commit is contained in:
Hugo Pointcheval 2020-12-19 17:23:52 +01:00
parent acc9261a66
commit e4fa93a775
2 changed files with 49 additions and 39 deletions

View File

@ -9,6 +9,8 @@ import 'platform.dart';
import 'exceptions.dart'; import 'exceptions.dart';
import 'keyspec.dart'; import 'keyspec.dart';
import 'cipher.dart';
import 'utils.dart';
/// This is the base class of all key types. /// This is the base class of all key types.
abstract class Key { abstract class Key {
@ -33,21 +35,21 @@ abstract class Key {
/// This represents a secret key, usefull in /// This represents a secret key, usefull in
/// algorithms like AES or BlowFish. /// algorithms like AES or BlowFish.
class SecretKey extends Key { class SecretKey extends Key {
List<String> _supportedAlgorithms = ["AES", "Blowfish"];
/// Creates a key from raw byte array /// Creates a key from raw byte array
SecretKey.fromBytes(Uint8List bytes) : super(bytes: bytes); SecretKey.fromBytes(Uint8List bytes,
{CipherAlgorithm algorithm: CipherAlgorithm.None})
: super(bytes: bytes, algorithm: algorithm.name);
/// Creates a key from a specific size. /// Creates a key from a specific size.
SecretKey.generate(String algorithm, int size) { static Future<SecretKey> generate(int size, CipherAlgorithm algorithm) async {
if (!_supportedAlgorithms.contains(algorithm)) { if (algorithm == null) {
throw KeyException(algorithm + " not supported!"); throw KeyException("Algorithm can't be null");
} else if (algorithm == "AES") { } else if (algorithm == CipherAlgorithm.AES) {
List<int> supportedSizes = [128, 192, 256]; List<int> _supportedSizes = [128, 192, 256];
if (!supportedSizes.contains(size)) { if (!_supportedSizes.contains(size)) {
throw KeyException("AES must be 128, 192 or 256 bits long."); throw KeyException("AES must be 128, 192 or 256 bits long.");
} }
} else if (algorithm == "Blowfish") { } else if (algorithm == CipherAlgorithm.BlowFish) {
List<int> supportedSizes = List<int> supportedSizes =
List<int>.generate(52, (int index) => (index + 4) * 8); List<int>.generate(52, (int index) => (index + 4) * 8);
if (!supportedSizes.contains(size)) { if (!supportedSizes.contains(size)) {
@ -55,15 +57,12 @@ class SecretKey extends Key {
"Blowfish must be between 4 and 56 bytes (32 and 448 bits) long."); "Blowfish must be between 4 and 56 bytes (32 and 448 bits) long.");
} }
} }
_generate(algorithm, size);
}
Future<void> _generate(String algo, int size) async {
try { try {
_bytes = await Platform().keygen(size); Uint8List _key = await Platform().keygen(size);
_algo = algo; log("Generated SecretKey size: ${_key.length * 8} bits (${_key.length} bytes)",
log("Generated SecretKey size: ${_bytes.length * 8} bits (${_bytes.length} bytes)",
name: "NativeCrypto"); name: "NativeCrypto");
return SecretKey.fromBytes(_key, algorithm: algorithm);
} on PlatformException catch (e) { } on PlatformException catch (e) {
log(e.message, name: "NativeCrypto"); log(e.message, name: "NativeCrypto");
throw KeyException(e); throw KeyException(e);

View File

@ -12,15 +12,29 @@ import '../utils.dart';
/// Defines all available key sizes. /// Defines all available key sizes.
enum AESKeySize { bits128, bits192, bits256 } enum AESKeySize { bits128, bits192, bits256 }
extension AESKeySizeExtension on AESKeySize {
int get length {
int l;
switch (this) {
case AESKeySize.bits128:
l = 128;
break;
case AESKeySize.bits192:
l = 192;
break;
case AESKeySize.bits256:
l = 256;
break;
}
return l;
}
}
class AESCipher implements Cipher { class AESCipher implements Cipher {
SecretKey _sk; SecretKey _sk;
CipherParameters _params; CipherParameters _params;
bool _isInit; bool _isInit;
List<CipherParameters> _supportedCipherParams = [
CipherParameters(BlockCipherMode.CBC, Padding.PKCS5),
];
@override @override
CipherAlgorithm get algorithm => CipherAlgorithm.AES; CipherAlgorithm get algorithm => CipherAlgorithm.AES;
@ -33,34 +47,31 @@ class AESCipher implements Cipher {
@override @override
bool get isInitialized => _isInit; bool get isInitialized => _isInit;
@override
List<CipherParameters> get supportedParameters => [
CipherParameters(BlockCipherMode.CBC, PlainTextPadding.PKCS5),
];
/// Creates an AES cipher with specified secretKey and mode/padding /// Creates an AES cipher with specified secretKey and mode/padding
AESCipher(SecretKey secretKey, CipherParameters parameters) { AESCipher(SecretKey secretKey, CipherParameters parameters) {
if (secretKey.algorithm != "AES") { if (secretKey.algorithm != CipherAlgorithm.AES.name) {
throw CipherInitException("Invalid key type: " + secretKey.algorithm); List<int> _supportedSizes = [128, 192, 256];
} else if (!_supportedCipherParams.contains(parameters)) { if (!_supportedSizes.contains(secretKey.encoded.length)) {
throw CipherInitException("Invalid key length!");
}
} else if (!supportedParameters.contains(parameters)) {
throw CipherInitException("Invalid cipher parameters."); throw CipherInitException("Invalid cipher parameters.");
} }
_sk = secretKey;
_params = parameters; _params = parameters;
_isInit = true; _isInit = true;
} }
/// Generates a secret key of specified size, then creates an AES cipher. /// Generates a secret key of specified size, then creates an AES cipher.
AESCipher.generate(AESKeySize size, CipherParameters parameters) { static Future<AESCipher> generate(
Map<AESKeySize, int> _supportedSizes = { AESKeySize size, CipherParameters parameters) async {
AESKeySize.bits128: 128, SecretKey _sk = await SecretKey.generate(size.length, CipherAlgorithm.AES);
AESKeySize.bits192: 192, return AESCipher(_sk, parameters);
AESKeySize.bits256: 256
};
if (!_supportedCipherParams.contains(parameters)) {
throw CipherInitException("Invalid cipher parameters.");
} else if (!_supportedSizes.containsKey(size)) {
throw CipherInitException("Invalid key size.");
}
_sk = SecretKey.generate("AES", _supportedSizes[size]);
_params = parameters;
_isInit = true;
} }
@override @override