2019-07-04 21:45:05 +00:00
|
|
|
import 'dart:convert';
|
2019-07-16 06:14:54 +00:00
|
|
|
import 'dart:math';
|
|
|
|
import 'dart:typed_data';
|
2019-07-04 21:45:05 +00:00
|
|
|
|
|
|
|
import 'package:crypt/crypt.dart';
|
2019-07-09 02:03:44 +00:00
|
|
|
import 'package:encrypt/encrypt.dart';
|
|
|
|
import 'package:password_hash/password_hash.dart';
|
2019-07-04 21:45:05 +00:00
|
|
|
|
|
|
|
String hashPassword(String password) {
|
2019-07-16 06:14:54 +00:00
|
|
|
final salt = Salt.generateAsBase64String(saltSize);
|
2019-07-04 21:45:05 +00:00
|
|
|
return Crypt.sha256(password, salt: salt).toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool matchHashedPassword(String hashedPassword, String password) =>
|
|
|
|
Crypt(hashedPassword).match(password);
|
2019-07-09 02:03:44 +00:00
|
|
|
|
2019-07-16 06:14:54 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-07-13 19:48:32 +00:00
|
|
|
final key = PBKDF2().generateKey(
|
2019-07-16 06:14:54 +00:00
|
|
|
masterpass,
|
|
|
|
privateKey,
|
|
|
|
pbkdf2Rounds,
|
|
|
|
keySize,
|
2019-07-13 19:48:32 +00:00
|
|
|
);
|
2019-07-09 02:03:44 +00:00
|
|
|
|
2019-07-13 19:48:32 +00:00
|
|
|
final ivBytes = cipherBytes.sublist(0, aesBlockSize);
|
|
|
|
cipherBytes = cipherBytes.sublist(aesBlockSize);
|
2019-07-09 02:03:44 +00:00
|
|
|
|
2019-07-13 19:48:32 +00:00
|
|
|
final iv = IV(ivBytes);
|
2019-07-09 02:03:44 +00:00
|
|
|
final encrypter = Encrypter(AES(Key(key), mode: AESMode.cbc));
|
2019-07-13 19:48:32 +00:00
|
|
|
return encrypter.decrypt(Encrypted(cipherBytes), iv: iv);
|
2019-07-09 02:03:44 +00:00
|
|
|
}
|
|
|
|
|
2019-07-16 06:14:54 +00:00
|
|
|
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();
|
2019-07-18 02:20:04 +00:00
|
|
|
final ivBytes =
|
|
|
|
List<int>.generate(aesBlockSize, (_) => random.nextInt(byteIntMax));
|
2019-07-16 06:14:54 +00:00
|
|
|
final iv = IV(Uint8List.fromList(ivBytes));
|
|
|
|
|
|
|
|
final encrypter = Encrypter(AES(Key(key), mode: AESMode.cbc));
|
2019-07-18 02:20:04 +00:00
|
|
|
final cipherBytes =
|
|
|
|
List<int>.from(encrypter.encrypt(plainText, iv: iv).bytes);
|
2019-07-16 06:14:54 +00:00
|
|
|
cipherBytes.insertAll(0, ivBytes);
|
|
|
|
|
|
|
|
if (privateKeyWasEmpty) {
|
|
|
|
final base64PrivKey = base64.decode(privateKey);
|
|
|
|
cipherBytes.insertAll(0, base64PrivKey);
|
|
|
|
cipherBytes.insert(0, base64PrivKey.length);
|
|
|
|
}
|
|
|
|
|
|
|
|
return base64.encode(cipherBytes);
|
|
|
|
}
|
|
|
|
|
2019-07-18 02:20:04 +00:00
|
|
|
String generatePassword(int length,
|
|
|
|
[bool numbers = true, bool specials = true]) {
|
|
|
|
const alphaValues = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
|
|
const numberValues = '1234567890';
|
|
|
|
const specialValues = '!@#\$%^&*()-_=+';
|
|
|
|
|
|
|
|
final random = Random.secure();
|
|
|
|
List<int> 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<int>.generate(length, (_) => values[random.nextInt(valuesLen)]);
|
|
|
|
|
|
|
|
return String.fromCharCodes(passValues);
|
|
|
|
}
|
|
|
|
|
2019-07-16 06:14:54 +00:00
|
|
|
const saltSize = 16;
|
2019-07-09 02:03:44 +00:00
|
|
|
const pbkdf2Rounds = 4096;
|
|
|
|
const keySize = 32;
|
|
|
|
const aesBlockSize = 16;
|
2019-07-16 06:14:54 +00:00
|
|
|
const byteIntMax = 256;
|