diff --git a/src/en/nineanime/build.gradle b/src/en/nineanime/build.gradle
index 88b81902..728eee5b 100644
--- a/src/en/nineanime/build.gradle
+++ b/src/en/nineanime/build.gradle
@@ -1,7 +1,7 @@
 ext {
     extName = 'Aniwave'
     extClass = '.Aniwave'
-    extVersionCode = 74
+    extVersionCode = 75
 }
 
 apply from: "$rootDir/common.gradle"
diff --git a/src/en/nineanime/src/eu/kanade/tachiyomi/animeextension/en/nineanime/Aniwave.kt b/src/en/nineanime/src/eu/kanade/tachiyomi/animeextension/en/nineanime/Aniwave.kt
index b40fc5bb..c9d85d87 100644
--- a/src/en/nineanime/src/eu/kanade/tachiyomi/animeextension/en/nineanime/Aniwave.kt
+++ b/src/en/nineanime/src/eu/kanade/tachiyomi/animeextension/en/nineanime/Aniwave.kt
@@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.animeextension.en.nineanime
 
 import android.app.Application
 import android.content.SharedPreferences
-import android.util.Log
 import android.webkit.URLUtil
 import android.widget.Toast
 import androidx.preference.EditTextPreference
@@ -97,7 +96,7 @@ class Aniwave : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
     override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
         val filters = AniwaveFilters.getSearchParameters(filters)
 
-        val vrf = if (query.isNotBlank()) utils.vrfEncrypt(ENCRYPTION_KEY, query) else ""
+        val vrf = if (query.isNotBlank()) utils.vrfEncrypt(query) else ""
         var url = "$baseUrl/filter?keyword=$query"
 
         if (filters.genre.isNotBlank()) url += filters.genre
@@ -150,13 +149,12 @@ class Aniwave : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
     // ============================== Episodes ==============================
 
     override fun episodeListRequest(anime: SAnime): Request {
-        Log.i(name, "episodeListRequest")
         val response = client.newCall(GET(baseUrl + anime.url)).execute()
         var document = response.asJsoup()
         document = resolveSearchAnime(anime, document)
         val id = document.selectFirst("div[data-id]")?.attr("data-id") ?: throw Exception("ID not found")
 
-        val vrf = utils.vrfEncrypt(ENCRYPTION_KEY, id)
+        val vrf = utils.vrfEncrypt(id)
 
         val listHeaders = headers.newBuilder().apply {
             add("Accept", "application/json, text/javascript, */*; q=0.01")
@@ -212,7 +210,7 @@ class Aniwave : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
 
     override fun videoListRequest(episode: SEpisode): Request {
         val ids = episode.url.substringBefore("&")
-        val vrf = utils.vrfEncrypt(ENCRYPTION_KEY, ids)
+        val vrf = utils.vrfEncrypt(ids)
         val url = "/ajax/server/list/$ids?vrf=$vrf"
         val epurl = episode.url.substringAfter("epurl=")
 
@@ -265,7 +263,7 @@ class Aniwave : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
     private val mp4uploadExtractor by lazy { Mp4uploadExtractor(client) }
 
     private fun extractVideo(server: VideoData, epUrl: String): List<Video> {
-        val vrf = utils.vrfEncrypt(ENCRYPTION_KEY, server.serverId)
+        val vrf = utils.vrfEncrypt(server.serverId)
 
         val listHeaders = headers.newBuilder().apply {
             add("Accept", "application/json, text/javascript, */*; q=0.01")
@@ -280,7 +278,7 @@ class Aniwave : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
 
         return runCatching {
             val parsed = response.parseAs<ServerResponse>()
-            val embedLink = utils.vrfDecrypt(DECRYPTION_KEY, parsed.result.url)
+            val embedLink = utils.vrfDecrypt(parsed.result.url)
             when (server.serverName) {
                 "vidstream" -> vidsrcExtractor.videosFromUrl(embedLink, "Vidstream", server.type)
                 "megaf" -> vidsrcExtractor.videosFromUrl(embedLink, "MegaF", server.type)
@@ -327,7 +325,8 @@ class Aniwave : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
     private fun resolveSearchAnime(anime: SAnime, document: Document): Document {
         if (document.location().startsWith("$baseUrl/filter?keyword=")) { // redirected to search
             val element = document.selectFirst(searchAnimeSelector())
-            val foundAnimePath = element?.selectFirst("a[href]")?.attr("href") ?: throw Exception("Search element not found (resolveSearch)")
+            val foundAnimePath = element?.selectFirst("a[href]")?.attr("href")
+                ?: throw Exception("Search element not found (resolveSearch)")
             anime.url = foundAnimePath // probably doesn't work as intended
             return client.newCall(GET(baseUrl + foundAnimePath)).execute().asJsoup()
         }
@@ -398,9 +397,6 @@ class Aniwave : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
         private const val PREF_TYPE_TOGGLE_KEY = "type_selection"
         private val TYPES = arrayOf("Sub", "Softsub", "Dub")
         private val PREF_TYPES_TOGGLE_DEFAULT = TYPES.toSet()
-
-        private const val DECRYPTION_KEY = "ctpAbOz5u7S6OMkx"
-        private const val ENCRYPTION_KEY = "T78s2WjTc7hSIZZR"
     }
 
     // ============================== Settings ==============================
@@ -410,7 +406,7 @@ class Aniwave : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
         try {
             getHosters()
         } catch (e: Exception) {
-            Log.w(name, e.toString())
+            Toast.makeText(screen.context, e.toString(), Toast.LENGTH_LONG).show()
         }
 
         ListPreference(screen.context).apply {
diff --git a/src/en/nineanime/src/eu/kanade/tachiyomi/animeextension/en/nineanime/AniwaveUtils.kt b/src/en/nineanime/src/eu/kanade/tachiyomi/animeextension/en/nineanime/AniwaveUtils.kt
index 9c11922a..39cbf7ca 100644
--- a/src/en/nineanime/src/eu/kanade/tachiyomi/animeextension/en/nineanime/AniwaveUtils.kt
+++ b/src/en/nineanime/src/eu/kanade/tachiyomi/animeextension/en/nineanime/AniwaveUtils.kt
@@ -7,22 +7,111 @@ import javax.crypto.spec.SecretKeySpec
 
 class AniwaveUtils {
 
-    fun vrfEncrypt(key: String, input: String): String {
+    fun vrfEncrypt(input: String): String {
+        var vrf = input
+        ORDER.sortedBy {
+            it.first
+        }.forEach { item ->
+            when (item.second) {
+                "exchange" -> vrf = exchange(vrf, item.third)
+                "rc4" -> vrf = rc4Encrypt(item.third.get(0), vrf)
+                "reverse" -> vrf = vrf.reversed()
+                "base64" -> vrf = Base64.encode(vrf.toByteArray(), Base64.URL_SAFE or Base64.NO_WRAP).toString(Charsets.UTF_8)
+                else -> {}
+            }
+        }
+
+        return java.net.URLEncoder.encode(vrf, "utf-8")
+    }
+
+    fun vrfDecrypt(input: String): String {
+        var vrf = input
+        ORDER.sortedByDescending {
+            it.first
+        }.forEach { item ->
+            when (item.second) {
+                "exchange" -> vrf = exchange(vrf, item.third.reversed())
+                "rc4" -> vrf = rc4Decrypt(item.third.get(0), vrf)
+                "reverse" -> vrf = vrf.reversed()
+                "base64" -> vrf = Base64.decode(vrf, Base64.URL_SAFE).toString(Charsets.UTF_8)
+                else -> {}
+            }
+        }
+
+        return URLDecoder.decode(vrf, "utf-8")
+    }
+
+    private fun rc4Encrypt(key: String, input: String): String {
         val rc4Key = SecretKeySpec(key.toByteArray(), "RC4")
         val cipher = Cipher.getInstance("RC4")
         cipher.init(Cipher.DECRYPT_MODE, rc4Key, cipher.parameters)
-        var vrf = cipher.doFinal(input.toByteArray())
-        vrf = Base64.encode(vrf, Base64.URL_SAFE or Base64.NO_WRAP)
-        var vrfString = vrf.toString(Charsets.UTF_8)
-        return java.net.URLEncoder.encode(vrfString, "utf-8")
+
+        var output = cipher.doFinal(input.toByteArray())
+        output = Base64.encode(output, Base64.URL_SAFE or Base64.NO_WRAP)
+        return output.toString(Charsets.UTF_8)
     }
 
-    fun vrfDecrypt(key: String, input: String): String {
-        var vrf = Base64.decode(input.toByteArray(), Base64.URL_SAFE)
+    private fun rc4Decrypt(key: String, input: String): String {
+        var vrf = input.toByteArray()
+        vrf = Base64.decode(vrf, Base64.URL_SAFE)
+
         val rc4Key = SecretKeySpec(key.toByteArray(), "RC4")
         val cipher = Cipher.getInstance("RC4")
         cipher.init(Cipher.DECRYPT_MODE, rc4Key, cipher.parameters)
         vrf = cipher.doFinal(vrf)
-        return URLDecoder.decode(vrf.toString(Charsets.UTF_8), "utf-8")
+        return vrf.toString(Charsets.UTF_8)
+    }
+
+    private fun exchange(input: String, keys: List<String>): String {
+        val key1 = keys.get(0)
+        val key2 = keys.get(1)
+        return input.map { i ->
+            val index = key1.indexOf(i)
+            if (index != -1) {
+                key2[index]
+            } else {
+                i
+            }
+        }.joinToString("")
+    }
+
+    private fun rot13(vrf: ByteArray): ByteArray {
+        for (i in vrf.indices) {
+            val byte = vrf[i]
+            if (byte in 'A'.code..'Z'.code) {
+                vrf[i] = ((byte - 'A'.code + 13) % 26 + 'A'.code).toByte()
+            } else if (byte in 'a'.code..'z'.code) {
+                vrf[i] = ((byte - 'a'.code + 13) % 26 + 'a'.code).toByte()
+            }
+        }
+        return vrf
+    }
+
+    private fun vrfShift(vrf: ByteArray): ByteArray {
+        for (i in vrf.indices) {
+            val shift = arrayOf(-2, -4, -5, 6, 2, -3, 3, 6)[i % 8]
+            vrf[i] = vrf[i].plus(shift).toByte()
+        }
+        return vrf
+    }
+
+    companion object {
+        private val EXCHANGE_KEY_1 = listOf("AP6GeR8H0lwUz1", "UAz8Gwl10P6ReH")
+        private val KEY_1 = "ItFKjuWokn4ZpB"
+        private val KEY_2 = "fOyt97QWFB3"
+        private val EXCHANGE_KEY_2 = listOf("1majSlPQd2M5", "da1l2jSmP5QM")
+        private val EXCHANGE_KEY_3 = listOf("CPYvHj09Au3", "0jHA9CPYu3v")
+        private val KEY_3 = "736y1uTJpBLUX"
+
+        private val ORDER = listOf(
+            Triple(1, "exchange", EXCHANGE_KEY_1),
+            Triple(2, "rc4", listOf(KEY_1)),
+            Triple(3, "rc4", listOf(KEY_2)),
+            Triple(4, "exchange", EXCHANGE_KEY_2),
+            Triple(5, "exchange", EXCHANGE_KEY_3),
+            Triple(5, "reverse", emptyList()),
+            Triple(6, "rc4", listOf(KEY_3)),
+            Triple(7, "base64", emptyList()),
+        )
     }
 }