This commit is contained in:
Him188moe 2019-08-17 17:49:45 +08:00
parent e3e77053ae
commit 87e5f0dfcd
11 changed files with 274 additions and 41 deletions

View File

@ -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>

View File

@ -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()
}
}

View File

@ -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)

View File

@ -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))
}
}

View File

@ -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

View File

@ -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());

View 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);
}
}

View File

@ -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);
}
}

Binary file not shown.

View File

@ -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 -->