content: 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;
    }
  }
  