mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-11 07:04:53 +08:00
update
This commit is contained in:
parent
e3e77053ae
commit
87e5f0dfcd
@ -25,6 +25,10 @@
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
|
@ -45,18 +45,15 @@ interface Protocol {
|
||||
const val encryptKey = "“BA 42 FF 01 CF B4 FF D2 12 F0 6E A7 1B 7C B3 08”"
|
||||
|
||||
|
||||
fun hexToBytes(hex: String): ByteArray = Arrays
|
||||
.stream(hex.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray())
|
||||
.map { value -> value.trim { it <= ' ' } }
|
||||
.map { s -> s.toInt(16).toByte() }
|
||||
.collect(Collectors.toList()).toByteArray()
|
||||
@ExperimentalUnsignedTypes
|
||||
fun hexToBytes(hex: String): ByteArray = hexToUBytes(hex).toByteArray()
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
fun hexToUBytes(hex: String): UByteArray = Arrays
|
||||
.stream(hex.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray())
|
||||
.map { value -> value.trim { it <= ' ' } }
|
||||
.map { s -> s.toInt(16).toByte() }
|
||||
.collect(Collectors.toList()).toByteArray().toUByteArray()
|
||||
.map { s -> s.toUByte(16) }
|
||||
.collect(Collectors.toList()).toUByteArray()
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package net.mamoe.mirai.network.packet.client
|
||||
|
||||
import net.mamoe.mirai.network.Protocol
|
||||
import net.mamoe.mirai.network.packet.PacketId
|
||||
import net.mamoe.mirai.util.TEAEncryption
|
||||
import net.mamoe.mirai.util.TEACryptor
|
||||
import net.mamoe.mirai.util.hexToBytes
|
||||
import java.io.IOException
|
||||
|
||||
@ -11,13 +11,14 @@ import java.io.IOException
|
||||
*/
|
||||
@PacketId(0x08_25_31_02)
|
||||
class Client0825ResponsePacket(private val serverIP: String, private val qq: Int) : ClientPacket() {
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun encode() {
|
||||
this.writeQQ(qq)
|
||||
this.writeHex(Protocol.fixVer)
|
||||
this.writeHex(Protocol.redirectionKey)
|
||||
|
||||
//TEA 加密
|
||||
this.write(TEAEncryption.encrypt(object : ClientPacket() {
|
||||
this.write(TEACryptor.encrypt(object : ClientPacket() {
|
||||
@Throws(IOException::class)
|
||||
override fun encode() {
|
||||
this.writeHex(Protocol._0825data0)
|
||||
|
@ -2,7 +2,7 @@ package net.mamoe.mirai.network.packet.client
|
||||
|
||||
import net.mamoe.mirai.network.Protocol
|
||||
import net.mamoe.mirai.network.packet.PacketId
|
||||
import net.mamoe.mirai.util.TEAEncryption
|
||||
import net.mamoe.mirai.util.TEACryptor
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
@ -18,6 +18,6 @@ class ClientHeartbeatPacket : ClientPacket() {
|
||||
this.writeRandom(2)
|
||||
this.writeQQ(qq)
|
||||
this.writeHex(Protocol.fixVer)
|
||||
this.write(TEAEncryption.encrypt(byteArrayOf(0x00, 0x01, 0x00, 0x01), sessionKey))
|
||||
this.write(TEACryptor.encrypt(byteArrayOf(0x00, 0x01, 0x00, 0x01), sessionKey))
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ package net.mamoe.mirai.network.packet.client
|
||||
import net.mamoe.mirai.network.Protocol
|
||||
import net.mamoe.mirai.network.packet.PacketId
|
||||
import net.mamoe.mirai.util.ByteArrayDataOutputStream
|
||||
import net.mamoe.mirai.util.TEAEncryption
|
||||
import net.mamoe.mirai.util.TEACryptor
|
||||
import net.mamoe.mirai.util.toHexString
|
||||
import java.io.IOException
|
||||
|
||||
@ -26,7 +26,7 @@ class ClientLoginPacket : ClientPacket() {
|
||||
|
||||
|
||||
//TEA 加密
|
||||
this.write(TEAEncryption.encrypt(object : ByteArrayDataOutputStream() {
|
||||
this.write(TEACryptor.CRYPTOR_0825KEY.encrypt(object : ByteArrayDataOutputStream() {
|
||||
@Throws(IOException::class)
|
||||
override fun toByteArray(): ByteArray {
|
||||
this.writeHex(Protocol._0825data0)
|
||||
@ -41,7 +41,7 @@ class ClientLoginPacket : ClientPacket() {
|
||||
println(this.toUByteArray().toHexString(" "))
|
||||
return super.toByteArray()
|
||||
}
|
||||
}.toByteArray(), Protocol.hexToBytes(Protocol._0825key)))
|
||||
}.toByteArray()))
|
||||
}
|
||||
|
||||
}
|
||||
@ -52,7 +52,7 @@ fun main() {
|
||||
pk.qq = 1994701021
|
||||
pk.encode()
|
||||
pk.writeHex(Protocol.tail)
|
||||
println("pk.toByteArray() = " + pk.toUByteArray().contentToString())
|
||||
//println("pk.toByteArray() = " + pk.toUByteArray().contentToString())
|
||||
println(pk.toUByteArray().toHexString(" "))
|
||||
|
||||
/*
|
||||
@ -94,6 +94,5 @@ fun main() {
|
||||
//mirai: 00 18 00 16 00 01 00 00 04 53 00 00 00 01 00 00 15 85 76 E4 B8 DD 00 00 00 00 03 09 00 08 00 01 C0 A8 01 01 00 02 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 02 00 19 02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3
|
||||
//epl : 00 18 00 16 00 01 00 00 04 53 00 00 00 01 00 00 15 85 76 E4 B8 DD 00 00 00 00 03 09 00 08 00 01 C0 A8 01 01 00 02 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 02 00 19 02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3
|
||||
|
||||
//whole package
|
||||
//mirai: 02 37 13 08 25 31 01 76 E4 B8 DD 03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00 A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D 91 DE 6C 86 08 E0 5C ED C7 78 97 E4 A2 3E A6 F9 59 89 91 0A A3 5B 17 35 8B 1A 1F 6A 6C EA 26 C0 CE A1 FE 70 47 A2 FC 6C FA 17 0B 0E 64 A3 8E 59 21 AA E3 EF 5E 3D 4A C3 03 2B 66 FB 44 B8 C4 3F AC BB 6E 12 D0 0D 55 CD 1D 9E 96 6C B5 AE 46 DC 28 B6 81 30 04 10 B0 A4 04 7C 51 E8 EF FE F5 D3 19 9C 77 F6 FD 7B A8 02 03
|
||||
//epl : 02 37 13 08 25 31 01 76 E4 B8 DD 03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00 A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D E6 3D D4 31 C7 80 74 0A EE 0F 6C 8F 4B 13 77 40 CE C9 C3 96 AB 05 13 3F C7 D0 1C 11 18 A9 03 32 FF 1F EB D9 6A 00 4E D4 AC 86 03 A4 30 2F 62 A0 77 6D 47 F3 4F EF AB 01 80 3D EB 47 65 8A A4 DB 63 8E 38 5A 4B 59 D0 D8 AF 42 6C 6D B3 F7 5B A4 2A 42 FD CA 8C 11 85 92 4A 0F 28 FB F3 3C A1 50 79 66 C4 21 09 E0 51 9E 03
|
||||
//mirai: 02 37 13 08 25 31 01 76 E4 B8 DD 03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00 A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D C3 47 F0 25 A1 8E 74 EF 1E 0B 32 5B 20 8A FA 3B 0B 52 8F 86 E6 04 F1 D6 F8 63 75 60 8C 0C 7D 06 D1 E0 22 F8 49 EF AF 61 EE 7E 69 72 EB 10 08 30 69 50 1C 84 A9 C2 16 D7 52 B9 1C 79 CA 5A CF FD BC AE D8 A6 BB DC 21 6E 79 26 E1 A2 23 11 AA B0 9A 49 39 72 ED 61 12 B6 88 4D A2 56 23 E9 92 11 92 27 4A 70 00 C9 01 7B 03
|
||||
//epl : 02 37 13 08 25 31 01 76 E4 B8 DD 03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00 A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D F0 1B 0A 8D 98 99 A9 78 B3 82 69 91 B1 8C FD 64 AC C1 DF B5 A1 A6 4C AC B6 CC A3 B2 11 51 15 00 A4 01 75 7C 61 83 C1 89 3E 93 42 A1 AF D4 1B B3 81 4E 52 67 C1 15 42 5D 28 00 3D 1E 40 28 B1 C9 CE 08 15 F3 2B B5 5A 88 59 4E F4 9A 15 CB 77 BE 56 86 16 CD 4F CD F6 14 D2 A6 B0 7B F1 22 B9 DD 64 98 5C 93 AE 6F 6C 43 03
|
@ -1,7 +1,7 @@
|
||||
package net.mamoe.mirai.network.packet.server
|
||||
|
||||
import net.mamoe.mirai.network.Protocol
|
||||
import net.mamoe.mirai.util.TEAEncryption
|
||||
import net.mamoe.mirai.util.TEACryptor
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
@ -24,7 +24,7 @@ class Server0825Packet(private val type: Type, inputStream: DataInputStream) : S
|
||||
|
||||
override fun decode() {
|
||||
input.skip(43 - 11)//todo: check
|
||||
val data = DataInputStream(TEAEncryption.decrypt(input.readAllBytes().let { it.copyOfRange(0, it.size - 2) }, when (type) {//todo: check array range
|
||||
val data = DataInputStream(TEACryptor.decrypt(input.readAllBytes().let { it.copyOfRange(0, it.size - 2) }, when (type) {//todo: check array range
|
||||
Type.TYPE_08_25_31_01 -> Protocol.redirectionKey.toByteArray()
|
||||
Type.TYPE_08_25_31_02 -> Protocol._0825key.toByteArray()
|
||||
}).inputStream());
|
||||
|
246
mirai-core/src/main/java/net/mamoe/mirai/util/TEACryptor.java
Normal file
246
mirai-core/src/main/java/net/mamoe/mirai/util/TEACryptor.java
Normal file
@ -0,0 +1,246 @@
|
||||
package net.mamoe.mirai.util;
|
||||
|
||||
import net.mamoe.mirai.network.Protocol;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java
|
||||
*/
|
||||
public class TEACryptor {
|
||||
public static final TEACryptor CRYPTOR_0825KEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._0825key));
|
||||
|
||||
private static final long UINT32_MASK = 0xffffffffL;
|
||||
private final long[] mKey;
|
||||
private final Random mRandom;
|
||||
private byte[] mOutput;
|
||||
private byte[] mInBlock;
|
||||
private int mIndexPos;
|
||||
private byte[] mIV;
|
||||
private int mOutPos;
|
||||
private int mPreOutPos;
|
||||
private boolean isFirstBlock;
|
||||
private boolean isRand;
|
||||
|
||||
public TEACryptor(byte[] key) {
|
||||
mKey = new long[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mKey[i] = pack(key, i * 4, 4);
|
||||
}
|
||||
isRand = true;
|
||||
mRandom = new Random();
|
||||
isFirstBlock = true;
|
||||
}
|
||||
|
||||
public static byte[] encrypt(byte[] key, byte[] source) {
|
||||
return new TEACryptor(key).encrypt(source);
|
||||
}
|
||||
|
||||
public static byte[] decrypt(byte[] key, byte[] source) {
|
||||
return new TEACryptor(key).decrypt(source);
|
||||
}
|
||||
|
||||
private static long pack(byte[] bytes, int offset, int len) {
|
||||
long result = 0;
|
||||
int max_offset = len > 8 ? offset + 8 : offset + len;
|
||||
for (int index = offset; index < max_offset; index++) {
|
||||
result = result << 8 | ((long) bytes[index] & 0xffL);
|
||||
}
|
||||
return result >> 32 | result & UINT32_MASK;
|
||||
}
|
||||
|
||||
private int rand() {
|
||||
return isRand ? mRandom.nextInt() : 0xff00ff;
|
||||
}
|
||||
|
||||
public void enableRandom(boolean rand) {
|
||||
isRand = rand;
|
||||
}
|
||||
|
||||
private byte[] encode(byte[] bytes) {
|
||||
long v0 = pack(bytes, 0, 4);
|
||||
long v1 = pack(bytes, 4, 4);
|
||||
long sum = 0;
|
||||
long delta = 0x9e3779b9L;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
sum = (sum + delta) & UINT32_MASK;
|
||||
v0 += ((v1 << 4) + mKey[0]) ^ (v1 + sum) ^ ((v1 >>> 5) + mKey[1]);
|
||||
v0 &= UINT32_MASK;
|
||||
v1 += ((v0 << 4) + mKey[2]) ^ (v0 + sum) ^ ((v0 >>> 5) + mKey[3]);
|
||||
v1 &= UINT32_MASK;
|
||||
}
|
||||
return ByteBuffer.allocate(8).putInt((int) v0).putInt((int) v1).array();
|
||||
}
|
||||
|
||||
private byte[] decode(byte[] bytes, int offset) {
|
||||
long v0 = pack(bytes, offset, 4);
|
||||
long v1 = pack(bytes, offset + 4, 4);
|
||||
long delta = 0x9e3779b9L;
|
||||
long sum = (delta << 4) & UINT32_MASK;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
v1 -= ((v0 << 4) + mKey[2]) ^ (v0 + sum) ^ ((v0 >>> 5) + mKey[3]);
|
||||
v1 &= UINT32_MASK;
|
||||
v0 -= ((v1 << 4) + mKey[0]) ^ (v1 + sum) ^ ((v1 >>> 5) + mKey[1]);
|
||||
v0 &= UINT32_MASK;
|
||||
sum = (sum - delta) & UINT32_MASK;
|
||||
}
|
||||
return ByteBuffer.allocate(8).putInt((int) v0).putInt((int) v1).array();
|
||||
}
|
||||
|
||||
private void encodeOneBlock() {
|
||||
for (mIndexPos = 0; mIndexPos < 8; mIndexPos++) {
|
||||
mInBlock[mIndexPos] = isFirstBlock ?
|
||||
mInBlock[mIndexPos]
|
||||
: ((byte) (mInBlock[mIndexPos] ^ mOutput[mPreOutPos + mIndexPos]));
|
||||
}
|
||||
|
||||
System.arraycopy(encode(mInBlock), 0, mOutput, mOutPos, 8);
|
||||
for (mIndexPos = 0; mIndexPos < 8; mIndexPos++) {
|
||||
int out_pos = mOutPos + mIndexPos;
|
||||
mOutput[out_pos] = (byte) (mOutput[out_pos] ^ mIV[mIndexPos]);
|
||||
}
|
||||
System.arraycopy(mInBlock, 0, mIV, 0, 8);
|
||||
mPreOutPos = mOutPos;
|
||||
mOutPos += 8;
|
||||
mIndexPos = 0;
|
||||
isFirstBlock = false;
|
||||
}
|
||||
|
||||
private boolean decodeOneBlock(byte[] ciphertext, int offset, int len) {
|
||||
for (mIndexPos = 0; mIndexPos < 8; mIndexPos++) {
|
||||
if (mOutPos + mIndexPos < len) {
|
||||
mIV[mIndexPos] = (byte) (mIV[mIndexPos] ^ ciphertext[mOutPos + offset + mIndexPos]);
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
mIV = decode(mIV, 0);
|
||||
mOutPos += 8;
|
||||
mIndexPos = 0;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private byte[] encrypt(byte[] plaintext, int offset, int len) {
|
||||
mInBlock = new byte[8];
|
||||
mIV = new byte[8];
|
||||
mOutPos = 0;
|
||||
mPreOutPos = 0;
|
||||
isFirstBlock = true;
|
||||
mIndexPos = (len + 10) % 8;
|
||||
if (mIndexPos != 0) {
|
||||
mIndexPos = 8 - mIndexPos;
|
||||
}
|
||||
mOutput = new byte[mIndexPos + len + 10];
|
||||
mInBlock[0] = (byte) (rand() & 0xf8 | mIndexPos);
|
||||
for (int i = 1; i <= mIndexPos; i++) {
|
||||
mInBlock[i] = (byte) (rand() & 0xff);
|
||||
}
|
||||
++mIndexPos;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
mIV[i] = 0;
|
||||
}
|
||||
|
||||
int g = 0;
|
||||
while (g < 2) {
|
||||
if (mIndexPos < 8) {
|
||||
mInBlock[mIndexPos++] = (byte) (rand() & 0xff);
|
||||
++g;
|
||||
}
|
||||
if (mIndexPos == 8) {
|
||||
encodeOneBlock();
|
||||
}
|
||||
}
|
||||
|
||||
for (; len > 0; len--) {
|
||||
if (mIndexPos < 8) {
|
||||
mInBlock[mIndexPos++] = plaintext[offset++];
|
||||
}
|
||||
if (mIndexPos == 8) {
|
||||
encodeOneBlock();
|
||||
}
|
||||
}
|
||||
for (g = 0; g < 7; g++) {
|
||||
if (mIndexPos < 8) {
|
||||
mInBlock[mIndexPos++] = (byte) 0;
|
||||
}
|
||||
if (mIndexPos == 8) {
|
||||
encodeOneBlock();
|
||||
}
|
||||
}
|
||||
return mOutput;
|
||||
}
|
||||
|
||||
private byte[] decrypt(byte[] ciphertext, int offset, int len) {
|
||||
if (len % 8 != 0 || len < 16) {
|
||||
return null;
|
||||
}
|
||||
mIV = decode(ciphertext, offset);
|
||||
mIndexPos = mIV[0] & 7;
|
||||
int plen = len - mIndexPos - 10;
|
||||
isFirstBlock = true;
|
||||
if (plen < 0) {
|
||||
return null;
|
||||
}
|
||||
mOutput = new byte[plen];
|
||||
mPreOutPos = 0;
|
||||
mOutPos = 8;
|
||||
++mIndexPos;
|
||||
int g = 0;
|
||||
while (g < 2) {
|
||||
if (mIndexPos < 8) {
|
||||
++mIndexPos;
|
||||
++g;
|
||||
}
|
||||
if (mIndexPos == 8) {
|
||||
isFirstBlock = false;
|
||||
if (!decodeOneBlock(ciphertext, offset, len)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int outpos = 0; plen != 0; plen--) {
|
||||
if (mIndexPos < 8) {
|
||||
mOutput[outpos++] = isFirstBlock ?
|
||||
mIV[mIndexPos] :
|
||||
(byte) (ciphertext[mPreOutPos + offset + mIndexPos] ^ mIV[mIndexPos]);
|
||||
++mIndexPos;
|
||||
}
|
||||
if (mIndexPos == 8) {
|
||||
mPreOutPos = mOutPos - 8;
|
||||
isFirstBlock = false;
|
||||
if (!decodeOneBlock(ciphertext, offset, len)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (g = 0; g < 7; g++) {
|
||||
if (mIndexPos < 8) {
|
||||
if ((ciphertext[mPreOutPos + offset + mIndexPos] ^ mIV[mIndexPos]) != 0) {
|
||||
return null;
|
||||
} else {
|
||||
++mIndexPos;
|
||||
}
|
||||
}
|
||||
|
||||
if (mIndexPos == 8) {
|
||||
mPreOutPos = mOutPos;
|
||||
if (!decodeOneBlock(ciphertext, offset, len)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mOutput;
|
||||
}
|
||||
|
||||
public byte[] encrypt(byte[] plaintext) {
|
||||
return encrypt(plaintext, 0, plaintext.length);
|
||||
}
|
||||
|
||||
public byte[] decrypt(byte[] ciphertext) {
|
||||
return decrypt(ciphertext, 0, ciphertext.length);
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package net.mamoe.mirai.util;
|
||||
|
||||
/**
|
||||
* @author Him188moe @ Mirai Project
|
||||
*/
|
||||
public final class TEAEncryption {
|
||||
public static byte[] encrypt(byte[] source, byte[] key) {
|
||||
return new _TEAEncryption().encrypt(source, key);
|
||||
}
|
||||
|
||||
public static byte[] decrypt(byte[] source, byte[] key) {
|
||||
return new _TEAEncryption().decrypt(source, key);
|
||||
}
|
||||
|
||||
public static byte[] decrypt(byte[] source, int offset, int length, byte[] key) {
|
||||
return new _TEAEncryption().decrypt(source, offset, length, key);
|
||||
}
|
||||
|
||||
}
|
||||
|
BIN
mirai-native/src/main/e/TEAEncryption.dll
Normal file
BIN
mirai-native/src/main/e/TEAEncryption.dll
Normal file
Binary file not shown.
Binary file not shown.
8
pom.xml
8
pom.xml
@ -94,11 +94,17 @@
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna -->
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<version>5.4.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
|
||||
|
Loading…
Reference in New Issue
Block a user