diff --git a/lib/symmetrical_crypto.dart b/lib/symmetrical_crypto.dart new file mode 100644 index 0000000..6d22be8 --- /dev/null +++ b/lib/symmetrical_crypto.dart @@ -0,0 +1,112 @@ +// Copyright (c) 2020 +// Author: Hugo Pointcheval +import 'dart:typed_data'; + +import 'package:native_crypto/native_crypto.dart'; +import 'package:native_crypto/src/exceptions.dart'; + +enum KeySize { bits128, bits192, bits256 } +enum Cipher { AES } + +/// AES Helper +/// +/// You can generate AES keys, encrypt and decrypt data. +class AES { + Uint8List key; + + bool isInitialized = false; + KeySize keySize; + + /// You can pass a key in constructor. + AES({this.key}) { + try { + bool isValidKey = _testKey(); + this.isInitialized = isValidKey; + } on KeyException { + this.isInitialized = false; + throw KeyException('Invalid key length.'); + } + } + + /// Tests if the key is valid. + /// + /// The key must be 128, 192 or 256 bits long. + bool _testKey() { + if (this.key != null) { + switch (this.key.length) { + case 16: + this.keySize = KeySize.bits128; + break; + case 24: + this.keySize = KeySize.bits192; + break; + case 32: + this.keySize = KeySize.bits256; + break; + default: + throw KeyException('Invalid key length.'); + } + return true; + } else { + return false; + } + } + + /// Generate an AES key. + init(KeySize keySize) async { + if (this.key != null) return null; + + if (keySize != KeySize.bits256) + throw NotImplementedException('This key size is not implemented yet.'); + + this.key = await NativeCrypto().symKeygen(); + try { + bool isValidKey = _testKey(); + this.isInitialized = isValidKey; + } on KeyException { + this.isInitialized = false; + throw KeyException('Invalid key length.'); + } + } + + /// Encrypt data + /// + /// Returns an `Encrypted` object. + Future encrypt(Uint8List data) async { + if (!this.isInitialized) throw EncryptionException('Instance not initialized.'); + List encryptedPayload = + await NativeCrypto().symEncrypt(data, this.key); + Encrypted encrypted = Encrypted.fromList(Cipher.AES, encryptedPayload); + + return encrypted; + } + + Future decrypt(Encrypted encrypted) async { + if (!this.isInitialized) throw DecryptionException('Instance not initialized.'); + Uint8List decryptedPayload = + await NativeCrypto().symDecrypt(encrypted.toList(), this.key); + return decryptedPayload; + } +} + +/// Contains data of an encrypted payload. +/// More practical than a list. +class Encrypted { + Cipher cipher; + Uint8List cipherText; + Uint8List iv; + Uint8List mac; + + Encrypted(); + + Encrypted.fromList(this.cipher, List encryptedPayload) { + this.mac = encryptedPayload[0].sublist(0, 32); + this.cipherText = encryptedPayload[0].sublist(32, encryptedPayload[0].length); + this.iv = encryptedPayload[1]; + } + + List toList() { + List encryptedPayload = [Uint8List.fromList(this.mac + this.cipherText), this.iv]; + return encryptedPayload; + } +}