mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-08 17:20:11 +08:00
Fail-fast decryption and encryption
This commit is contained in:
parent
8353a6ae8d
commit
244996ac28
@ -1,10 +1,10 @@
|
|||||||
package net.mamoe.mirai.utils
|
package net.mamoe.mirai.utils
|
||||||
|
|
||||||
import kotlinx.io.core.IoBuffer
|
import kotlinx.io.core.IoBuffer
|
||||||
|
import kotlinx.io.core.readBytes
|
||||||
import kotlin.jvm.JvmStatic
|
import kotlin.jvm.JvmStatic
|
||||||
|
|
||||||
|
internal expect object TEA { //TODO 优化为 buffer
|
||||||
expect object TEA {
|
|
||||||
internal fun doOption(data: ByteArray, key: ByteArray, encrypt: Boolean): ByteArray
|
internal fun doOption(data: ByteArray, key: ByteArray, encrypt: Boolean): ByteArray
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@ -12,14 +12,18 @@ expect object TEA {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun decrypt(source: ByteArray, key: ByteArray): ByteArray
|
fun decrypt(source: ByteArray, key: ByteArray): ByteArray
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun decrypt(source: ByteArray, key: IoBuffer): ByteArray
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun decrypt(source: ByteArray, keyHex: String): ByteArray
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ByteArray.decryptBy(key: ByteArray): ByteArray = TEA.decrypt(this, key)
|
fun ByteArray.decryptBy(key: ByteArray): ByteArray = TEA.decrypt(checkLength(), key)
|
||||||
fun ByteArray.decryptBy(key: IoBuffer): ByteArray = TEA.decrypt(this, key)
|
fun ByteArray.decryptBy(key: IoBuffer): ByteArray = TEA.decrypt(checkLength(), key.readBytes())
|
||||||
fun ByteArray.decryptBy(key: String): ByteArray = TEA.decrypt(this, key)
|
fun ByteArray.decryptBy(keyHex: String): ByteArray = TEA.decrypt(checkLength(), keyHex.hexToBytes())
|
||||||
|
|
||||||
|
fun ByteArray.encryptBy(key: ByteArray): ByteArray = TEA.encrypt(checkLength(), key)
|
||||||
|
fun ByteArray.encryptBy(keyHex: String): ByteArray = TEA.encrypt(checkLength(), keyHex.hexToBytes())
|
||||||
|
|
||||||
|
private fun ByteArray.checkLength(): ByteArray {
|
||||||
|
size.let {
|
||||||
|
require(it % 8 == 0 && it >= 16) { "data must len % 8 == 0 && len >= 16 but given $it" }
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
@ -1,7 +1,5 @@
|
|||||||
package net.mamoe.mirai.utils
|
package net.mamoe.mirai.utils
|
||||||
|
|
||||||
import kotlinx.io.core.IoBuffer
|
|
||||||
import kotlinx.io.core.readBytes
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.experimental.and
|
import kotlin.experimental.and
|
||||||
@ -12,7 +10,7 @@ import kotlin.experimental.xor
|
|||||||
*
|
*
|
||||||
* @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java
|
* @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java
|
||||||
*/
|
*/
|
||||||
actual object TEA {
|
internal actual object TEA {
|
||||||
private const val UINT32_MASK = 0xffffffffL
|
private const val UINT32_MASK = 0xffffffffL
|
||||||
|
|
||||||
internal actual fun doOption(data: ByteArray, key: ByteArray, encrypt: Boolean): ByteArray {
|
internal actual fun doOption(data: ByteArray, key: ByteArray, encrypt: Boolean): ByteArray {
|
||||||
@ -163,14 +161,14 @@ actual object TEA {
|
|||||||
return mOutput
|
return mOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decrypt(cipherText: ByteArray, offset: Int, len: Int): ByteArray? {
|
fun decrypt(cipherText: ByteArray, offset: Int, len: Int): ByteArray {
|
||||||
require(!(len % 8 != 0 || len < 16)) { "data must len % 8 == 0 && len >= 16 but given $len" }
|
require(!(len % 8 != 0 || len < 16)) { "data must len % 8 == 0 && len >= 16 but given $len" }
|
||||||
mIV = decode(cipherText, offset)
|
mIV = decode(cipherText, offset)
|
||||||
mIndexPos = (mIV[0] and 7).toInt()
|
mIndexPos = (mIV[0] and 7).toInt()
|
||||||
var plen = len - mIndexPos - 10
|
var plen = len - mIndexPos - 10
|
||||||
isFirstBlock = true
|
isFirstBlock = true
|
||||||
if (plen < 0) {
|
if (plen < 0) {
|
||||||
return null
|
fail()
|
||||||
}
|
}
|
||||||
mOutput = ByteArray(plen)
|
mOutput = ByteArray(plen)
|
||||||
mPreOutPos = 0
|
mPreOutPos = 0
|
||||||
@ -185,7 +183,7 @@ actual object TEA {
|
|||||||
if (mIndexPos == 8) {
|
if (mIndexPos == 8) {
|
||||||
isFirstBlock = false
|
isFirstBlock = false
|
||||||
if (!decodeOneBlock(cipherText, offset, len)) {
|
if (!decodeOneBlock(cipherText, offset, len)) {
|
||||||
throw RuntimeException("Unable to dataDecode")
|
fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,7 +201,7 @@ actual object TEA {
|
|||||||
mPreOutPos = mOutPos - 8
|
mPreOutPos = mOutPos - 8
|
||||||
isFirstBlock = false
|
isFirstBlock = false
|
||||||
if (!decodeOneBlock(cipherText, offset, len)) {
|
if (!decodeOneBlock(cipherText, offset, len)) {
|
||||||
throw RuntimeException("Unable to dataDecode")
|
fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
plen--
|
plen--
|
||||||
@ -212,7 +210,7 @@ actual object TEA {
|
|||||||
while (g < 7) {
|
while (g < 7) {
|
||||||
if (mIndexPos < 8) {
|
if (mIndexPos < 8) {
|
||||||
if (cipherText[mPreOutPos + offset + mIndexPos].xor(mIV[mIndexPos]).toInt() != 0) {
|
if (cipherText[mPreOutPos + offset + mIndexPos].xor(mIV[mIndexPos]).toInt() != 0) {
|
||||||
throw RuntimeException()
|
fail()
|
||||||
} else {
|
} else {
|
||||||
++mIndexPos
|
++mIndexPos
|
||||||
}
|
}
|
||||||
@ -221,7 +219,7 @@ actual object TEA {
|
|||||||
if (mIndexPos == 8) {
|
if (mIndexPos == 8) {
|
||||||
mPreOutPos = mOutPos
|
mPreOutPos = mOutPos
|
||||||
if (!decodeOneBlock(cipherText, offset, len)) {
|
if (!decodeOneBlock(cipherText, offset, len)) {
|
||||||
throw RuntimeException("Unable to dataDecode")
|
fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g++
|
g++
|
||||||
@ -232,16 +230,12 @@ actual object TEA {
|
|||||||
return if (encrypt) {
|
return if (encrypt) {
|
||||||
encrypt(data, 0, data.size)
|
encrypt(data, 0, data.size)
|
||||||
} else {
|
} else {
|
||||||
try {
|
decrypt(data, 0, data.size)
|
||||||
return decrypt(data, 0, data.size)!!
|
|
||||||
} catch (e: Exception) {
|
|
||||||
//println("Source: " + data.toUHexString(" "))
|
|
||||||
// println("Key: " + key.toUHexString(" "))
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun fail(): Nothing = throw DecryptionFailedException()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
actual fun encrypt(source: ByteArray, key: ByteArray): ByteArray {
|
actual fun encrypt(source: ByteArray, key: ByteArray): ByteArray {
|
||||||
return doOption(source, key, true)
|
return doOption(source, key, true)
|
||||||
@ -252,16 +246,6 @@ actual object TEA {
|
|||||||
return doOption(source, key, false)
|
return doOption(source, key, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
actual fun decrypt(source: ByteArray, key: IoBuffer): ByteArray {
|
|
||||||
return doOption(source, key.readBytes(), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
actual fun decrypt(source: ByteArray, keyHex: String): ByteArray {
|
|
||||||
return decrypt(source, keyHex.hexToBytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("SameParameterValue")
|
@Suppress("SameParameterValue")
|
||||||
private fun pack(bytes: ByteArray, offset: Int, len: Int): Long {
|
private fun pack(bytes: ByteArray, offset: Int, len: Int): Long {
|
||||||
var result: Long = 0
|
var result: Long = 0
|
||||||
@ -271,4 +255,6 @@ actual object TEA {
|
|||||||
}
|
}
|
||||||
return result shr 32 or (result and UINT32_MASK)
|
return result shr 32 or (result and UINT32_MASK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DecryptionFailedException : Exception()
|
Loading…
Reference in New Issue
Block a user