idk how to decrypt shit ;(((
This commit is contained in:
@ -0,0 +1,53 @@
|
|||||||
|
package eu.kanade.tachiyomi.animeextension.en.twistmoe
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import java.util.Base64
|
||||||
|
import javax.crypto.Cipher
|
||||||
|
import javax.crypto.spec.IvParameterSpec
|
||||||
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.O)
|
||||||
|
class AESDecrypt {
|
||||||
|
private val decoder = Base64.getDecoder()
|
||||||
|
private val encoder = Base64.getEncoder()
|
||||||
|
fun aesEncrypt(v: String, secretKey: ByteArray, initializationVector: ByteArray) = encrypt(v, secretKey, initializationVector)
|
||||||
|
fun aesDecrypt(v: ByteArray, secretKey: ByteArray, initializationVector: ByteArray) = decrypt(v, secretKey, initializationVector)
|
||||||
|
fun getIvAndKey(v: String): ByteArray {
|
||||||
|
val byteStr = decoder.decode(v.toByteArray(Charsets.UTF_8))
|
||||||
|
val md5 = MessageDigest.getInstance("MD5")
|
||||||
|
assert(byteStr.decodeToString(0, 8) == "Salted__")
|
||||||
|
val salt = byteStr.sliceArray(8..15)
|
||||||
|
val secretStr = "267041df55ca2b36f2e322d05ee2c9cf"
|
||||||
|
val secret = secretStr
|
||||||
|
.map { it.toByte() }
|
||||||
|
.toByteArray()
|
||||||
|
val step1 = md5.digest(salt)
|
||||||
|
val step2 = step1 + md5.digest(step1 + secret)
|
||||||
|
val step3 = step2 + md5.digest(step2 + secret)
|
||||||
|
Log.i("lol", step3.decodeToString())
|
||||||
|
assert(step3.lastIndex == 47)
|
||||||
|
return step3
|
||||||
|
}
|
||||||
|
fun getToDecode(v: String): ByteArray {
|
||||||
|
val byteStr = decoder.decode(v.toByteArray(Charsets.UTF_8))
|
||||||
|
assert(byteStr.decodeToString(0, 8) == "Salted__")
|
||||||
|
return byteStr.sliceArray(16..byteStr.lastIndex)
|
||||||
|
}
|
||||||
|
private fun cipher(opmode: Int, secretKey: ByteArray, initializationVector: ByteArray): Cipher {
|
||||||
|
if (secretKey.lastIndex != 31) throw RuntimeException("SecretKey length is not 32 chars")
|
||||||
|
val c = Cipher.getInstance("AES/CBC/NoPadding")
|
||||||
|
val sk = SecretKeySpec(secretKey, "AES")
|
||||||
|
val iv = IvParameterSpec(initializationVector)
|
||||||
|
c.init(opmode, sk, iv)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
private fun encrypt(str: String, secretKey: ByteArray, iv: ByteArray): String {
|
||||||
|
val encrypted = cipher(Cipher.ENCRYPT_MODE, secretKey, iv).doFinal(str.toByteArray(Charsets.UTF_8))
|
||||||
|
return String(encoder.encode(encrypted))
|
||||||
|
}
|
||||||
|
private fun decrypt(str: ByteArray, secretKey: ByteArray, iv: ByteArray): String {
|
||||||
|
return String(cipher(Cipher.DECRYPT_MODE, secretKey, iv).doFinal(str))
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.animeextension.en.twistmoe
|
package eu.kanade.tachiyomi.animeextension.en.twistmoe
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
@ -54,6 +55,8 @@ class TwistMoe : AnimeHttpSource() {
|
|||||||
1 -> SAnime.ONGOING
|
1 -> SAnime.ONGOING
|
||||||
else -> SAnime.UNKNOWN
|
else -> SAnime.UNKNOWN
|
||||||
}
|
}
|
||||||
|
anime.thumbnail_url = "https://homepages.cae.wisc.edu/~ece533/images/cat.png"
|
||||||
|
anime.initialized = true
|
||||||
animeList.add(anime)
|
animeList.add(anime)
|
||||||
}
|
}
|
||||||
return AnimesPage(animeList, false)
|
return AnimesPage(animeList, false)
|
||||||
@ -89,12 +92,20 @@ class TwistMoe : AnimeHttpSource() {
|
|||||||
return anime
|
return anime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun videoListRequest(episode: SEpisode): Request {
|
||||||
|
return super.videoListRequest(episode)
|
||||||
|
}
|
||||||
|
|
||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val responseString = response.body!!.string()
|
val responseString = response.body!!.string()
|
||||||
val jElement: JsonElement = JsonParser.parseString(responseString)
|
val jElement: JsonElement = JsonParser.parseString(responseString)
|
||||||
val jObject: JsonObject = jElement.asJsonObject
|
val jObject: JsonObject = jElement.asJsonObject
|
||||||
val server = jObject.get("videos_manifest").asJsonObject.get("servers").asJsonArray[0].asJsonObject
|
val server = jObject.get("videos_manifest").asJsonObject.get("servers").asJsonArray[0].asJsonObject
|
||||||
val streams = server.get("streams").asJsonArray
|
val streams = server.get("streams").asJsonArray
|
||||||
|
val aes = AESDecrypt()
|
||||||
|
val ivAndKey = aes.getIvAndKey("U2FsdGVkX19njUQXx448lKxE4wUQA8tH45sgjCYckbrdS15QHY3fW5ChD6UpcoackxmWn8/5Tk88yAAwSukKwKpfvI6rQ1ERxFcAspfBCj8U/IQYoE3gZy+Esgumt/Fz")
|
||||||
|
val toDecode = aes.getToDecode("U2FsdGVkX19njUQXx448lKxE4wUQA8tH45sgjCYckbrdS15QHY3fW5ChD6UpcoackxmWn8/5Tk88yAAwSukKwKpfvI6rQ1ERxFcAspfBCj8U/IQYoE3gZy+Esgumt/Fz")
|
||||||
|
Log.i("lol", aes.aesDecrypt(toDecode, ivAndKey.sliceArray(0..31), ivAndKey.sliceArray(32..47)))
|
||||||
val linkList = mutableListOf<Video>()
|
val linkList = mutableListOf<Video>()
|
||||||
for (stream in streams) {
|
for (stream in streams) {
|
||||||
if (stream.asJsonObject.get("kind").asString != "premium_alert") {
|
if (stream.asJsonObject.get("kind").asString != "premium_alert") {
|
||||||
@ -105,6 +116,12 @@ class TwistMoe : AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun episodeListRequest(anime: SAnime): Request {
|
override fun episodeListRequest(anime: SAnime): Request {
|
||||||
|
val aes = AESDecrypt()
|
||||||
|
val ivAndKey = aes.getIvAndKey("U2FsdGVkX19njUQXx448lKxE4wUQA8tH45sgjCYckbrdS15QHY3fW5ChD6UpcoackxmWn8/5Tk88yAAwSukKwKpfvI6rQ1ERxFcAspfBCj8U/IQYoE3gZy+Esgumt/Fz")
|
||||||
|
val toDecode = aes.getToDecode("U2FsdGVkX19njUQXx448lKxE4wUQA8tH45sgjCYckbrdS15QHY3fW5ChD6UpcoackxmWn8/5Tk88yAAwSukKwKpfvI6rQ1ERxFcAspfBCj8U/IQYoE3gZy+Esgumt/Fz")
|
||||||
|
Log.i("lol_key", ivAndKey.sliceArray(0..31).decodeToString())
|
||||||
|
Log.i("lol_iv", ivAndKey.sliceArray(32..47).decodeToString())
|
||||||
|
Log.i("lol_final", aes.aesDecrypt(toDecode, ivAndKey.sliceArray(0..31), ivAndKey.sliceArray(32..47)))
|
||||||
val slug = anime.url.substringAfter("/a/")
|
val slug = anime.url.substringAfter("/a/")
|
||||||
return GET("https://api.twist.moe/api/anime/$slug/sources", popularRequestHeaders)
|
return GET("https://api.twist.moe/api/anime/$slug/sources", popularRequestHeaders)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user