import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; import 'package:crypt/crypt.dart'; import 'package:encrypt/encrypt.dart'; import 'package:password_hash/password_hash.dart'; String hashPassword(String password) { final salt = Salt.generateAsBase64String(saltSize); return Crypt.sha256(password, salt: salt).toString(); } bool matchHashedPassword(String hashedPassword, String password) => Crypt(hashedPassword).match(password); String decrypt(String cipherText, String masterpass, [String privateKey]) { var cipherBytes = base64.decode(cipherText); if (privateKey == null) { final saltLength = cipherBytes[0]; cipherBytes = cipherBytes.sublist(1); privateKey = base64.encode(cipherBytes.sublist(0, saltLength)); cipherBytes = cipherBytes.sublist(saltLength); } final key = PBKDF2().generateKey( masterpass, privateKey, pbkdf2Rounds, keySize, ); final ivBytes = cipherBytes.sublist(0, aesBlockSize); cipherBytes = cipherBytes.sublist(aesBlockSize); final iv = IV(ivBytes); final encrypter = Encrypter(AES(Key(key), mode: AESMode.cbc)); return encrypter.decrypt(Encrypted(cipherBytes), iv: iv); } String encrypt(String plainText, String masterpass, [String privateKey]) { bool privateKeyWasEmpty = false; if (privateKey == null) { privateKey = Salt.generateAsBase64String(saltSize); privateKeyWasEmpty = true; } final key = PBKDF2().generateKey( masterpass, privateKey, pbkdf2Rounds, keySize, ); final random = Random.secure(); final ivBytes = List.generate(aesBlockSize, (_) => random.nextInt(byteIntMax)); final iv = IV(Uint8List.fromList(ivBytes)); final encrypter = Encrypter(AES(Key(key), mode: AESMode.cbc)); final cipherBytes = List.from(encrypter.encrypt(plainText, iv: iv).bytes); cipherBytes.insertAll(0, ivBytes); if (privateKeyWasEmpty) { final base64PrivKey = base64.decode(privateKey); cipherBytes.insertAll(0, base64PrivKey); cipherBytes.insert(0, base64PrivKey.length); } return base64.encode(cipherBytes); } String generatePassword(int length, [bool numbers = true, bool specials = true]) { const alphaValues = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; const numberValues = '1234567890'; const specialValues = '!@#\$%^&*()-_=+'; final random = Random.secure(); List values; if (numbers && specials) { values = (alphaValues + numberValues + specialValues).codeUnits; } else if (numbers) { values = (alphaValues + numberValues).codeUnits; } else if (specials) { values = (alphaValues + specialValues).codeUnits; } final valuesLen = values.length; final passValues = List.generate(length, (_) => values[random.nextInt(valuesLen)]); return String.fromCharCodes(passValues); } const saltSize = 16; const pbkdf2Rounds = 4096; const keySize = 32; const aesBlockSize = 16; const byteIntMax = 256;