85 lines
3 KiB
Dart
85 lines
3 KiB
Dart
import 'dart:convert';
|
|
import 'dart:math';
|
|
import 'dart:typed_data';
|
|
import 'package:crypto/crypto.dart';
|
|
import 'package:encrypt/encrypt.dart' as encrypt;
|
|
|
|
class CryptoAES {
|
|
static String encryptAESCryptoJS(String plainText, String passphrase) {
|
|
try {
|
|
final salt = genRandomWithNonZero(8);
|
|
var keyndIV = deriveKeyAndIV(passphrase.trim(), salt);
|
|
final key = encrypt.Key(keyndIV.$1);
|
|
final iv = encrypt.IV(keyndIV.$2);
|
|
|
|
final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
|
|
final encrypted = encrypter.encrypt(plainText.trim(), iv: iv);
|
|
Uint8List encryptedBytesWithSalt =
|
|
Uint8List.fromList(createUint8ListFromString("Salted__") + salt + encrypted.bytes);
|
|
return base64.encode(encryptedBytesWithSalt);
|
|
} catch (error) {
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
static String decryptAESCryptoJS(String encrypted, String passphrase) {
|
|
try {
|
|
Uint8List encryptedBytesWithSalt = base64.decode(encrypted.trim());
|
|
|
|
Uint8List encryptedBytes = encryptedBytesWithSalt.sublist(16, encryptedBytesWithSalt.length);
|
|
final salt = encryptedBytesWithSalt.sublist(8, 16);
|
|
var keyndIV = deriveKeyAndIV(passphrase.trim(), salt);
|
|
final key = encrypt.Key(keyndIV.$1);
|
|
final iv = encrypt.IV(keyndIV.$2);
|
|
|
|
final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
|
|
final decrypted = encrypter.decrypt64(base64.encode(encryptedBytes), iv: iv);
|
|
return decrypted;
|
|
} catch (error) {
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
static (Uint8List, Uint8List) deriveKeyAndIV(String passphrase, Uint8List salt) {
|
|
var password = createUint8ListFromString(passphrase);
|
|
Uint8List concatenatedHashes = Uint8List(0);
|
|
Uint8List currentHash = Uint8List(0);
|
|
bool enoughBytesForKey = false;
|
|
Uint8List preHash = Uint8List(0);
|
|
|
|
while (!enoughBytesForKey) {
|
|
// int preHashLength = currentHash.length + password.length + salt.length;
|
|
if (currentHash.isNotEmpty) {
|
|
preHash = Uint8List.fromList(currentHash + password + salt);
|
|
} else {
|
|
preHash = Uint8List.fromList(password + salt);
|
|
}
|
|
|
|
currentHash = md5.convert(preHash).bytes as Uint8List;
|
|
concatenatedHashes = Uint8List.fromList(concatenatedHashes + currentHash);
|
|
if (concatenatedHashes.length >= 48) enoughBytesForKey = true;
|
|
}
|
|
|
|
var keyBtyes = concatenatedHashes.sublist(0, 32);
|
|
var ivBtyes = concatenatedHashes.sublist(32, 48);
|
|
return (keyBtyes, ivBtyes);
|
|
}
|
|
|
|
static Uint8List createUint8ListFromString(String s) {
|
|
var ret = Uint8List(s.length);
|
|
for (var i = 0; i < s.length; i++) {
|
|
ret[i] = s.codeUnitAt(i);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static Uint8List genRandomWithNonZero(int seedLength) {
|
|
final random = Random.secure();
|
|
const int randomMax = 245;
|
|
final Uint8List uint8list = Uint8List(seedLength);
|
|
for (int i = 0; i < seedLength; i++) {
|
|
uint8list[i] = random.nextInt(randomMax) + 1;
|
|
}
|
|
return uint8list;
|
|
}
|
|
}
|