diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
index af7dcfdc7..9d9074da2 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
@@ -4,7 +4,6 @@ import lombok.Getter;
 import net.mamoe.mirai.event.MiraiEventManager;
 import net.mamoe.mirai.event.events.server.ServerDisableEvent;
 import net.mamoe.mirai.event.events.server.ServerEnableEvent;
-import net.mamoe.mirai.network.RobotNetworkHandler;
 import net.mamoe.mirai.network.packet.login.LoginState;
 import net.mamoe.mirai.task.MiraiTaskManager;
 import net.mamoe.mirai.utils.LoggerTextFormat;
@@ -36,7 +35,7 @@ public class MiraiServer {
     @Getter //is running under UNIX
     private boolean unix;
 
-    @Getter//file path
+    @Getter//file pathq
     public File parentFolder;
 
     @Getter
@@ -121,8 +120,7 @@ public class MiraiServer {
         this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> {
             try {
                 Robot robot = new Robot(section);
-                RobotNetworkHandler robotNetworkHandler = robot.getNetworkHandler();
-                robotNetworkHandler.tryLogin$mirai_core(state -> {
+                robot.network.tryLogin$mirai_core(state -> {
                     if (state == LoginState.SUCCEED) {
                         Robot.instances.add(robot);
                     } else {
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java
index fbc066118..0c3a1c169 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java
@@ -5,21 +5,58 @@ import net.mamoe.mirai.contact.Group;
 import net.mamoe.mirai.contact.QQ;
 import net.mamoe.mirai.network.RobotNetworkHandler;
 import net.mamoe.mirai.utils.ContactList;
+import net.mamoe.mirai.utils.RobotAccount;
 import net.mamoe.mirai.utils.config.MiraiConfigSection;
+import org.jetbrains.annotations.NotNull;
 
 import java.io.Closeable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.*;
 
-public class Robot implements Closeable {
+/**
+ * Robot that is the base of the whole program.
+ * It contains a {@link ContactSystem}, which manage contacts such as {@link QQ} and {@link Group}.
+ */
+public final class Robot implements Closeable {
     public static final List<Robot> instances = Collections.synchronizedList(new LinkedList<>());
 
-    private final long qqNumber;
-    private final String password;
-    @Getter
-    private final RobotNetworkHandler networkHandler;
+    public final RobotAccount account;
+
+    public final ContactSystem contacts = new ContactSystem();
+
+    public final RobotNetworkHandler network;
+
+    /**
+     * Robot 联系人管理.
+     *
+     * @see Robot#contacts
+     */
+    public final class ContactSystem {
+        private final ContactList<Group> groups = new ContactList<>();
+        private final ContactList<QQ> qqs = new ContactList<>();
+
+        private ContactSystem() {
+
+        }
+
+        public QQ getQQ(long qqNumber) {
+            if (!this.qqs.containsKey(qqNumber)) {
+                this.qqs.put(qqNumber, new QQ(Robot.this, qqNumber));
+            }
+            return this.qqs.get(qqNumber);
+        }
+
+        public Group getGroupByNumber(long groupNumber) {
+            if (!this.groups.containsKey(groupNumber)) {
+                this.groups.put(groupNumber, new Group(Robot.this, groupNumber));
+            }
+            return groups.get(groupNumber);
+        }
+
+        public Group getGroupById(long groupId) {
+            return getGroupByNumber(Group.Companion.groupIdToNumber(groupId));
+        }
+    }
+
 
     /**
      * Ref list
@@ -27,57 +64,36 @@ public class Robot implements Closeable {
     @Getter
     private final List<String> owners;
 
-    private final ContactList<Group> groups = new ContactList<>();
-    private final ContactList<QQ> qqs = new ContactList<>();
-
-    public void close() {
-        this.networkHandler.close();
-        this.owners.clear();
-        this.groups.values().forEach(Group::close);
-        this.groups.clear();
-        this.qqs.clear();
-    }
-
     public boolean isOwnBy(String ownerName) {
         return owners.contains(ownerName);
     }
 
-    public long getQQNumber() {
-        return qqNumber;
-    }
-
     public Robot(MiraiConfigSection<Object> data) throws Throwable {
         this(
-                data.getLongOrThrow("account", () -> new IllegalArgumentException("account")),
-                data.getStringOrThrow("password", () -> new IllegalArgumentException("password")),
+                new RobotAccount(
+                        data.getLongOrThrow("account", () -> new IllegalArgumentException("account")),
+                        data.getStringOrThrow("password", () -> new IllegalArgumentException("password"))
+                ),
                 data.getAsOrDefault("owners", ArrayList::new)
         );
-
     }
 
-    public Robot(long qqNumber, String password, List<String> owners) {
-        this.qqNumber = qqNumber;
-        this.password = password;
+    public Robot(@NotNull RobotAccount account, @NotNull List<String> owners) {
+        Objects.requireNonNull(account);
+        Objects.requireNonNull(owners);
+        this.account = account;
         this.owners = Collections.unmodifiableList(owners);
-        this.networkHandler = new RobotNetworkHandler(this, this.qqNumber, this.password);
+        this.network = new RobotNetworkHandler(this);
     }
 
-    public QQ getQQ(long qqNumber) {
-        if (!this.qqs.containsKey(qqNumber)) {
-            this.qqs.put(qqNumber, new QQ(qqNumber));
-        }
-        return this.qqs.get(qqNumber);
+
+    public void close() {
+        this.network.close();
+        this.owners.clear();
+        this.contacts.groups.values().forEach(Group::close);
+        this.contacts.groups.clear();
+        this.contacts.qqs.clear();
     }
 
-    public Group getGroup(long groupNumber) {
-        if (!this.groups.containsKey(groupNumber)) {
-            this.groups.put(groupNumber, new Group(groupNumber));
-        }
-        return groups.get(groupNumber);
-    }
-
-    public Group getGroupByGroupId(long groupId) {
-        return getGroup(Group.Companion.groupIdToNumber(groupId));
-    }
 }
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt
index fa1a475c1..ab33c4d10 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt
@@ -1,14 +1,16 @@
 package net.mamoe.mirai.contact
 
+import net.mamoe.mirai.Robot
 import net.mamoe.mirai.message.Message
 import net.mamoe.mirai.message.defaults.PlainText
 
 /**
  * A contact is a [QQ] or a [Group] for one particular [Robot] instance only.
  *
+ * @param robot Owner [Robot]
  * @author Him188moe
  */
-abstract class Contact(val number: Long) {
+abstract class Contact(val robot: Robot, val number: Long) {
 
     /**
      * Async
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt
index 3d23d53b7..3c14af642 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt
@@ -1,15 +1,16 @@
 package net.mamoe.mirai.contact
 
+import net.mamoe.mirai.Robot
 import net.mamoe.mirai.message.Message
 import net.mamoe.mirai.utils.ContactList
 import java.io.Closeable
 
-class Group(number: Long) : Contact(number), Closeable {
+class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable {
     val groupId = groupNumberToId(number)
     val members = ContactList<QQ>()
 
     override fun sendMessage(message: Message) {
-
+        robot.network.packetSystem.sendGroupMessage(this, message)
     }
 
     override fun sendXMLMessage(message: String) {
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
index e7a0cf537..efab8f4a6 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
@@ -1,15 +1,18 @@
 package net.mamoe.mirai.contact
 
+import net.mamoe.mirai.Robot
 import net.mamoe.mirai.message.Message
 import net.mamoe.mirai.message.defaults.At
 
 /**
+ * A QQ instance helps you to receive message from or send message to.
+ * Notice that one QQ instance belong to one [Robot], that is, QQ instances from different [Robot] are NOT the same.
+ *
  * @author Him188moe
  */
-class QQ(number: Long) : Contact(number) {
-
+class QQ(robot: Robot, number: Long) : Contact(robot, number) {
     override fun sendMessage(message: Message) {
-
+        robot.network.packetSystem.sendFriendMessage(this, message)
     }
 
     override fun sendXMLMessage(message: String) {
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt
index 258aff770..f5c4bbfb3 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt
@@ -28,26 +28,44 @@ interface Protocol {
 
 
         const val head = "02"
-        const val ver = "37 13 "
-        const val fixVer = "03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00 "
-        const val tail = " 03"
-        const val _fixVer = "02 00 00 00 01 01 01 00 00 68 20 "
-        const val _0825data0 = "00 18 00 16 00 01 "
-        const val _0825data2 = "00 00 04 53 00 00 00 01 00 00 15 85 "
-        const val _0825key = "A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D"
+        const val ver = "37 13"
+        const val fixVer = "03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00"
+        const val tail = "03"
+        /**
+         * _fixVer
+         */
+        const val fixVer2 = "02 00 00 00 01 01 01 00 00 68 20"
+        /**
+         * 0825data1
+         */
+        const val constantData0 = "00 18 00 16 00 01 "
+        /**
+         * 0825data2
+         */
+        const val constantData1 = "00 00 04 53 00 00 00 01 00 00 15 85 "
+        const val key0825 = "A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D"
         const val redirectionKey = "A8 F2 14 5F 58 12 60 AF 07 63 97 D6 76 B2 1A 3B"
         const val publicKey = "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"
         const val shareKey = "1A E9 7F 7D C9 73 75 98 AC 02 E0 80 5F A9 C6 AF"
-        const val _0836fix = "06 A9 12 97 B7 F8 76 25 AF AF D3 EA B4 C8 BC E7 "
+        const val fix0836 = "06 A9 12 97 B7 F8 76 25 AF AF D3 EA B4 C8 BC E7 "
 
-        const val _00BaKey = "C1 9C B8 C8 7B 8C 81 BA 9E 9E 7A 89 E1 7A EC 94"
-        const val _00BaFixKey = "69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A"
+        const val key00BA = "C1 9C B8 C8 7B 8C 81 BA 9E 9E 7A 89 E1 7A EC 94"
+        const val key00BAFix = "69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A"
 
         const val encryptKey = "“BA 42 FF 01 CF B4 FF D2 12 F0 6E A7 1B 7C B3 08”"
 
-        const val _0836_622_fix2 = "00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B";
-        const val _0836_622_fix1 = "03 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 01 01 03 00 19";
-        const val _0836key1 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA"
+        /**
+         * 0836_622_fix2
+         */
+        const val passwordSubmissionKey2 = "00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B";
+        /**
+         * 0836_622_fix1
+         */
+        const val passwordSubmissionKey1 = "03 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 01 01 03 00 19";
+        /**
+         * fix_0836_1
+         */
+        const val key0836 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA"
 
         private val hexToByteArrayCacheMap: MutableMap<Int, ByteArray> = mutableMapOf()
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt
index e62c95502..0a8fb4c67 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt
@@ -2,33 +2,36 @@ package net.mamoe.mirai.network
 
 import net.mamoe.mirai.Robot
 import net.mamoe.mirai.contact.Group
+import net.mamoe.mirai.contact.QQ
 import net.mamoe.mirai.event.events.qq.FriendMessageEvent
 import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent
+import net.mamoe.mirai.message.Message
 import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.network.packet.login.*
-import net.mamoe.mirai.network.packet.message.ClientSendGroupMessagePacket
 import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket
 import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket
 import net.mamoe.mirai.task.MiraiThreadPool
-import net.mamoe.mirai.utils.*
+import net.mamoe.mirai.utils.ClientLoginStatus
+import net.mamoe.mirai.utils.MiraiLogger
+import net.mamoe.mirai.utils.getGTK
+import net.mamoe.mirai.utils.lazyEncode
 import java.io.Closeable
 import java.net.DatagramPacket
 import java.net.DatagramSocket
 import java.net.InetSocketAddress
 import java.util.concurrent.TimeUnit
 
-
 /**
  * A RobotNetworkHandler is used to connect with Tencent servers.
  *
  * @author Him188moe
  */
-@ExperimentalUnsignedTypes
-internal class RobotNetworkHandler(val robot: Robot, val number: Long, private val password: String) : Closeable {
+@Suppress("EXPERIMENTAL_API_USAGE")//to simplify code
+internal class RobotNetworkHandler(private val robot: Robot) : Closeable {
 
-    var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt())
+    private var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt())
 
-    var serverIP: String = ""
+    private var serverIP: String = ""
         set(value) {
             serverAddress = InetSocketAddress(value, 8000)
             field = value
@@ -45,7 +48,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
     private lateinit var loginIP: String
     private var tgtgtKey: ByteArray? = null
     private var tlv0105: ByteArray
-    private lateinit var _0828_rec_decr_key: ByteArray
+    private lateinit var sessionResponseDecryptionKey: ByteArray
 
     private var verificationCodeSequence: Int = 0//这两个验证码使用
     private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来
@@ -82,10 +85,6 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
         }
     }
 
-
-    @ExperimentalUnsignedTypes
-    private var md5_32: ByteArray = getRandomKey(32)
-
     /**
      * Try to login to server
      */
@@ -110,7 +109,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
         if (loginHook != null) {
             this.loginHook = loginHook
         }
-        this.sendPacket(ClientTouchPacket(this.number, this.serverIP))
+        this.sendPacket(ClientTouchPacket(this.robot.account.qqNumber, this.serverIP))
     }
 
     private fun restartSocket() {
@@ -151,20 +150,20 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
         packet.decode()
         MiraiLogger info "Packet received: $packet"
         if (packet is ServerEventPacket) {
-            sendPacket(ClientMessageResponsePacket(this.number, packet.packetId, this.sessionKey, packet.eventIdentity))
+            sendPacket(ClientMessageResponsePacket(this.robot.account.qqNumber, packet.packetId, this.sessionKey, packet.eventIdentity))
         }
         when (packet) {
             is ServerTouchResponsePacket -> {
                 if (packet.serverIP != null) {//redirection
                     serverIP = packet.serverIP!!
                     //connect(packet.serverIP!!)
-                    sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, number))
+                    sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, this.robot.account.qqNumber))
                 } else {//password submission
                     this.loginIP = packet.loginIP
                     this.loginTime = packet.loginTime
                     this.token0825 = packet.token0825
                     this.tgtgtKey = packet.tgtgtKey
-                    sendPacket(ClientPasswordSubmissionPacket(this.number, this.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825))
+                    sendPacket(ClientPasswordSubmissionPacket(this.robot.account.qqNumber, this.robot.account.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825))
                 }
             }
 
@@ -182,7 +181,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
 
                 if (packet.unknownBoolean != null && packet.unknownBoolean!!) {
                     this.verificationCodeSequence = 1
-                    sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.number, this.token0825, this.verificationCodeSequence, this.token00BA))
+                    sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA))
                 }
 
             }
@@ -190,7 +189,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
             is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么
                 this.tgtgtKey = packet.tgtgtKeyUpdate
                 this.token00BA = packet.token00BA
-                sendPacket(ClientLoginResendPacket3105(this.number, this.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA))
+                sendPacket(ClientLoginResendPacket3105(this.robot.account.qqNumber, this.robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA))
             }
 
             is ServerVerificationCodeTransmissionPacket -> {
@@ -210,26 +209,26 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
                     this.verificationCodeCache
                     TODO("验证码好了")
                 } else {
-                    sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, this.number, this.token0825, this.verificationCodeSequence, this.token00BA))
+                    sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, this.robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA))
                 }
             }
 
             is ServerLoginResponseSuccessPacket -> {
-                this._0828_rec_decr_key = packet._0828_rec_decr_key
-                sendPacket(ClientSessionRequestPacket(this.number, this.serverIP, this.loginIP, this.md5_32, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105))
+                this.sessionResponseDecryptionKey = packet._0828_rec_decr_key
+                sendPacket(ClientSessionRequestPacket(this.robot.account.qqNumber, this.serverIP, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105))
             }
 
             //是ClientPasswordSubmissionPacket之后服务器回复的
             is ServerLoginResponseResendPacket -> {
-                if (packet.tokenUnknown != null) {
-                    //this.token00BA = packet.token00BA!!
-                    //println("token00BA changed!!! to " + token00BA.toUByteArray())
-                }
+                //if (packet.tokenUnknown != null) {
+                //this.token00BA = packet.token00BA!!
+                //println("token00BA changed!!! to " + token00BA.toUByteArray())
+                //}
                 if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) {
                     this.tgtgtKey = packet.tgtgtKey
                     sendPacket(ClientLoginResendPacket3104(
-                            this.number,
-                            this.password,
+                            this.robot.account.qqNumber,
+                            this.robot.account.password,
                             this.loginTime,
                             this.loginIP,
                             this.tgtgtKey!!,
@@ -242,8 +241,8 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
                     ))
                 } else {
                     sendPacket(ClientLoginResendPacket3106(
-                            this.number,
-                            this.password,
+                            this.robot.account.qqNumber,
+                            this.robot.account.password,
                             this.loginTime,
                             this.loginIP,
                             this.tgtgtKey!!,
@@ -261,7 +260,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
             is ServerSessionKeyResponsePacket -> {
                 this.sessionKey = packet.sessionKey
                 MiraiThreadPool.getInstance().scheduleWithFixedDelay({
-                    sendPacket(ClientHeartbeatPacket(this.number, this.sessionKey))
+                    sendPacket(ClientHeartbeatPacket(this.robot.account.qqNumber, this.sessionKey))
                 }, 90000, 90000, TimeUnit.MILLISECONDS)
                 RobotLoginSucceedEvent(robot).broadcast()
 
@@ -270,24 +269,24 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
                 }, 2, TimeUnit.SECONDS)
 
                 this.tlv0105 = packet.tlv0105
-                sendPacket(ClientLoginStatusPacket(this.number, this.sessionKey, ClientLoginStatus.ONLINE))
+                sendPacket(ClientChangeOnlineStatusPacket(this.robot.account.qqNumber, this.sessionKey, ClientLoginStatus.ONLINE))
             }
 
             is ServerLoginSuccessPacket -> {
                 loginState = LoginState.SUCCEED
-                sendPacket(ClientSKeyRequestPacket(this.number, this.sessionKey))
+                sendPacket(ClientSKeyRequestPacket(this.robot.account.qqNumber, this.sessionKey))
             }
 
             is ServerSKeyResponsePacket -> {
                 this.sKey = packet.sKey
-                this.cookies = "uin=o" + this.number + ";skey=" + this.sKey + ";"
+                this.cookies = "uin=o" + this.robot.account.qqNumber + ";skey=" + this.sKey + ";"
 
                 MiraiThreadPool.getInstance().scheduleWithFixedDelay({
-                    sendPacket(ClientSKeyRefreshmentRequestPacket(this.number, this.sessionKey))
+                    sendPacket(ClientSKeyRefreshmentRequestPacket(this.robot.account.qqNumber, this.sessionKey))
                 }, 1800000, 1800000, TimeUnit.MILLISECONDS)
 
                 this.gtk = getGTK(sKey)
-                sendPacket(ClientAccountInfoRequestPacket(this.number, this.sessionKey))
+                sendPacket(ClientAccountInfoRequestPacket(this.robot.account.qqNumber, this.sessionKey))
             }
 
             is ServerHeartbeatResponsePacket -> {
@@ -304,17 +303,12 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
                     return
                 }
 
-                FriendMessageEvent(this.robot, this.robot.getQQ(packet.qq), packet.message)
+                FriendMessageEvent(this.robot, this.robot.contacts.getQQ(packet.qq), packet.message)
             }
 
             is ServerGroupMessageEventPacket -> {
-                //group message
-                if (packet.message == "牛逼") {
-                    sendPacket(ClientSendGroupMessagePacket(Group.groupNumberToId(packet.groupNumber), this.number, this.sessionKey, "牛逼!"))
-                }
-
-                //todo
-                //GroupMessageEvent(this.robot, this.robot.getGroup(packet.groupNumber), this.robot.getQQ(packet.qq), packet.message)
+                //todo message chain
+                //GroupMessageEvent(this.robot, this.robot.contacts.getGroupByNumber(packet.groupNumber), this.robot.contacts.getQQ(packet.qq), packet.message)
             }
 
             is UnknownServerEventPacket -> {
@@ -329,17 +323,17 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
 
             }
 
-            is ServerMessageEventPacketRaw -> onPacketReceived(packet.analyze())
+            is ServerEventPacket.Raw -> onPacketReceived(packet.distribute())
 
-            is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt())
-            is ServerLoginResponseVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt())
-            is ServerLoginResponseResendPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
-            is ServerLoginResponseSuccessPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
-            is ServerSessionKeyResponsePacketEncrypted -> onPacketReceived(packet.decrypt(this._0828_rec_decr_key))
-            is ServerTouchResponsePacketEncrypted -> onPacketReceived(packet.decrypt())
-            is ServerSKeyResponsePacketEncrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
-            is ServerAccountInfoResponsePacketEncrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
-            is ServerMessageEventPacketRawEncoded -> onPacketReceived(packet.decrypt(this.sessionKey))
+            is ServerVerificationCodePacket.Encrypted -> onPacketReceived(packet.decrypt())
+            is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> onPacketReceived(packet.decrypt())
+            is ServerLoginResponseResendPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
+            is ServerLoginResponseSuccessPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
+            is ServerSessionKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionResponseDecryptionKey))
+            is ServerTouchResponsePacket.Encrypted -> onPacketReceived(packet.decrypt())
+            is ServerSKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
+            is ServerAccountInfoResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
+            is ServerEventPacket.Raw.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
 
 
             is ServerSendFriendMessageResponsePacket,
@@ -352,6 +346,21 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
 
     }
 
+    internal val packetSystem: PacketSystem = PacketSystem()
+
+    inner class PacketSystem {
+        fun sendFriendMessage(qq: QQ, message: Message) {
+            TODO()
+            //sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message))
+        }
+
+        fun sendGroupMessage(group: Group, message: Message): Unit {
+            TODO()
+            //sendPacket(ClientSendGroupMessagePacket(group.groupId, robot.account.qqNumber, sessionKey, message))
+        }
+
+    }
+
     @ExperimentalUnsignedTypes
     fun sendPacket(packet: ClientPacket) {
         MiraiThreadPool.getInstance().submit {
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt
index 90d50c89e..67d5d3113 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt
@@ -1,7 +1,7 @@
 package net.mamoe.mirai.network.packet
 
 import net.mamoe.mirai.network.Protocol
-import net.mamoe.mirai.utils.TEACryptor
+import net.mamoe.mirai.utils.TEA
 import java.io.DataInputStream
 
 /**
@@ -18,7 +18,7 @@ class ClientAccountInfoRequestPacket(
     override fun encode() {
         this.writeRandom(2)//part of packet id
         this.writeQQ(qq)
-        this.writeHex(Protocol._fixVer)
+        this.writeHex(Protocol.fixVer2)
         this.encryptAndWrite(sessionKey) {
             it.writeByte(0x88)
             it.writeQQ(qq)
@@ -27,6 +27,7 @@ class ClientAccountInfoRequestPacket(
     }
 }
 
+@PacketId("00 5C")
 class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(input) {
     //等级
     //升级剩余活跃天数
@@ -34,16 +35,13 @@ class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(inp
     override fun decode() {
 
     }
-}
 
-class ServerAccountInfoResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
-    override fun decode() {
-
-    }
-
-    fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket {
-        this.input goto 14
-        val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
-        return ServerAccountInfoResponsePacket(TEACryptor.decrypt(data, sessionKey).dataInputStream());
+    @PacketId("00 5C")
+    class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
+        fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket {
+            this.input goto 14
+            val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
+            return ServerAccountInfoResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream());
+        }
     }
 }
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
index 7ea56c462..2435134d0 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
@@ -108,15 +108,15 @@ fun DataOutputStream.writeVarInt(dec: UInt) {
 }
 
 fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, key: ByteArray) {
-    this.write(TEACryptor.encrypt(byteArray, key))
+    this.write(TEA.encrypt(byteArray, key))
 }
 
-fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, cryptor: TEACryptor) {
+fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, cryptor: TEA) {
     this.write(cryptor.encrypt(byteArray))
 }
 
 fun DataOutputStream.encryptAndWrite(key: ByteArray, encoder: (ByteArrayDataOutputStream) -> Unit) {
-    this.write(TEACryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }, key))
+    this.write(TEA.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }, key))
 }
 
 @ExperimentalUnsignedTypes
@@ -124,7 +124,7 @@ fun DataOutputStream.encryptAndWrite(keyHex: String, encoder: (ByteArrayDataOutp
     this.encryptAndWrite(keyHex.hexToBytes(), encoder)
 }
 
-fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDataOutputStream) -> Unit) {
+fun DataOutputStream.encryptAndWrite(cryptor: TEA, encoder: (ByteArrayDataOutputStream) -> Unit) {
     this.write(cryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }))
 }
 
@@ -132,24 +132,24 @@ fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDat
 @Throws(IOException::class)
 fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) {
     ByteArrayDataOutputStream().let {
-        it.writeHex("12 12 12 12")//it.writeRandom(4) todo
+        it.writeRandom(4)
         it.writeHex("00 02")
         it.writeQQ(qq)
-        it.writeHex(Protocol._0825data2)
+        it.writeHex(Protocol.constantData1)
         it.writeHex("00 00 01")
 
-        val md5_1 = md5(password);
-        val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray())
-        it.write(md5_1)
+        val firstMD5 = md5(password)
+        val secondMD5 = md5(firstMD5 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray())
+        it.write(firstMD5)
         it.writeInt(loginTime)
-        it.writeByte(0);
+        it.writeByte(0)
         it.writeZero(4 * 3)
         it.writeIP(loginIP)
         it.writeZero(8)
         it.writeHex("00 10")
         it.writeHex("15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B")
         it.write(tgtgtKey)
-        this.write(TEACryptor.encrypt(it.toByteArray(), md5_2))
+        this.write(TEA.encrypt(it.toByteArray(), secondMD5))
     }
 }
 
@@ -216,7 +216,7 @@ fun Int.toLByteArray(): ByteArray = byteArrayOf(
 )
 
 @ExperimentalUnsignedTypes
-fun Int.toHexString(separator: String = " "): String = this.toByteArray().toUByteArray().toUHexString(separator);
+fun Int.toHexString(separator: String = " "): String = this.toByteArray().toUByteArray().toUHexString(separator)
 
 internal fun md5(str: String): ByteArray = MessageDigest.getInstance("MD5").digest(str.toByteArray())
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt
index d8b1b8040..9fcd36304 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt
@@ -24,8 +24,4 @@ class ClientHeartbeatPacket(
     }
 }
 
-class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input) {
-    override fun decode() {
-
-    }
-}
\ No newline at end of file
+class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input)
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt
deleted file mode 100644
index 001cf7571..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-package net.mamoe.mirai.network.packet
-
-import net.mamoe.mirai.network.Protocol
-import net.mamoe.mirai.utils.TEACryptor
-import net.mamoe.mirai.utils.toUHexString
-import java.io.DataInputStream
-
-
-/**
- * 告知服务器已经收到数据
- */
-@PacketId("")//随后写入
-@ExperimentalUnsignedTypes
-class ClientMessageResponsePacket(
-        private val qq: Long,
-        private val packetIdFromServer: ByteArray,
-        private val sessionKey: ByteArray,
-        private val eventIdentity: ByteArray
-) : ClientPacket() {
-    override fun encode() {
-        this.write(packetIdFromServer)
-        this.writeQQ(qq)
-        this.writeHex(Protocol._fixVer)
-        this.encryptAndWrite(sessionKey) {
-            it.write(eventIdentity)
-        }
-    }
-}
-
-
-/**
- * 群聊和好友消息分发
- */
-@PacketId("00 17")
-class ServerMessageEventPacketRaw(
-        input: DataInputStream,
-        private val dataLength: Int,
-        private val packetId: ByteArray
-) : ServerPacket(input) {
-    lateinit var type: ByteArray;
-    lateinit var eventIdentity: ByteArray;
-
-    override fun decode() {
-        eventIdentity = this.input.readNBytes(16)
-        type = this.input.goto(18).readNBytes(2)
-    }
-
-    fun analyze(): ServerEventPacket = when (val typeHex = type.toUHexString()) {
-        "00 C4" -> {
-            if (this.input.goto(33).readBoolean()) {
-                ServerAndroidOnlineEventPacket(this.input, packetId, eventIdentity)
-            } else {
-                ServerAndroidOfflineEventPacket(this.input, packetId, eventIdentity)
-            }
-        }
-        "00 2D" -> ServerGroupUploadFileEventPacket(this.input, packetId, eventIdentity)
-
-        "00 52" -> ServerGroupMessageEventPacket(this.input, packetId, eventIdentity)
-
-        "00 A6" -> ServerFriendMessageEventPacket(this.input, packetId, eventIdentity)
-
-        //"02 10", "00 12" -> ServerUnknownEventPacket(this.input, packetId, eventIdentity)
-
-        else -> UnknownServerEventPacket(this.input, packetId, eventIdentity)
-    }
-}
-
-class UnknownServerEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity)
-
-@PacketId("00 17")
-class ServerMessageEventPacketRawEncoded(input: DataInputStream, val packetId: ByteArray) : ServerPacket(input) {
-
-
-    override fun decode() {
-
-    }
-
-    fun decrypt(sessionKey: ByteArray): ServerMessageEventPacketRaw {
-        this.input goto 14
-        val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
-        return ServerMessageEventPacketRaw(TEACryptor.decrypt(data, sessionKey).dataInputStream(), data.size, packetId);
-    }
-
-}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt
index 76b181fca..4ffb53ca3 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt
@@ -1,7 +1,7 @@
 package net.mamoe.mirai.network.packet
 
 import net.mamoe.mirai.network.Protocol
-import net.mamoe.mirai.utils.TEACryptor
+import net.mamoe.mirai.utils.TEA
 import java.io.DataInputStream
 
 
@@ -18,7 +18,7 @@ class ClientSKeyRequestPacket(
         this.writeRandom(2)//part of packet id
 
         this.writeQQ(qq)
-        this.writeHex(Protocol._fixVer)
+        this.writeHex(Protocol.fixVer2)
         this.encryptAndWrite(sessionKey) {
             it.writeHex("33 00 05 00 08 74 2E 71 71 2E 63 6F 6D 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 0C 6A 75 62 61 6F 2E 71 71 2E 63 6F 6D 00 09 6B 65 2E 71 71 2E 63 6F 6D")
         }
@@ -52,19 +52,13 @@ class ServerSKeyResponsePacket(input: DataInputStream) : ServerPacket(input) {
     override fun decode() {
         this.sKey = String(this.input.goto(4).readNBytes(10))
     }
-}
 
-/**
- * @author Him188moe
- */
-class ServerSKeyResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
-    override fun decode() {
 
-    }
-
-    fun decrypt(sessionKey: ByteArray): ServerSKeyResponsePacket {
-        this.input goto 14
-        val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
-        return ServerSKeyResponsePacket(TEACryptor.decrypt(data, sessionKey).dataInputStream());
+    class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
+        fun decrypt(sessionKey: ByteArray): ServerSKeyResponsePacket {
+            this.input goto 14
+            val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
+            return ServerSKeyResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream());
+        }
     }
 }
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
index acf94031d..ec54aeed5 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
@@ -2,6 +2,7 @@ package net.mamoe.mirai.network.packet
 
 import net.mamoe.mirai.message.defaults.MessageChain
 import net.mamoe.mirai.message.defaults.PlainText
+import net.mamoe.mirai.network.Protocol
 import net.mamoe.mirai.utils.MiraiLogger
 import net.mamoe.mirai.utils.toUHexString
 import java.io.ByteArrayOutputStream
@@ -9,15 +10,50 @@ import java.io.DataInputStream
 import java.util.zip.GZIPInputStream
 
 /**
+ * Packet id: `00 CE` or `00 17`
+ *
  * @author Him188moe
  */
 open class ServerEventPacket(input: DataInputStream, val packetId: ByteArray, val eventIdentity: ByteArray) : ServerPacket(input) {
+    @PacketId("00 17")
+    class Raw(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) {
+        @ExperimentalUnsignedTypes
+        fun distribute(): ServerEventPacket {
+            val eventIdentity = this.input.readNBytes(16)
+            val type = this.input.goto(18).readNBytes(2)
 
-    override fun decode() {
+            return when (type.toUHexString()) {
+                "00 C4" -> {
+                    if (this.input.goto(33).readBoolean()) {
+                        ServerAndroidOnlineEventPacket(this.input, packetId, eventIdentity)
+                    } else {
+                        ServerAndroidOfflineEventPacket(this.input, packetId, eventIdentity)
+                    }
+                }
+                "00 2D" -> ServerGroupUploadFileEventPacket(this.input, packetId, eventIdentity)
 
+                "00 52" -> ServerGroupMessageEventPacket(this.input, packetId, eventIdentity)
+
+                "00 A6" -> ServerFriendMessageEventPacket(this.input, packetId, eventIdentity)
+
+                //"02 10", "00 12" -> ServerUnknownEventPacket(this.input, packetId, eventIdentity)
+
+                else -> UnknownServerEventPacket(this.input, packetId, eventIdentity)
+            }
+        }
+
+        @PacketId("00 17")
+        class Encrypted(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) {
+            fun decrypt(sessionKey: ByteArray): Raw = Raw(decryptBy(sessionKey), packetId)
+        }
     }
 }
 
+/**
+ * Unknown event
+ */
+class UnknownServerEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity)
+
 /**
  * Android 客户端上线
  */
@@ -32,7 +68,7 @@ class ServerAndroidOfflineEventPacket(input: DataInputStream, packetId: ByteArra
  * 群文件上传
  */
 class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
-    lateinit var xmlMessage: String
+    private lateinit var xmlMessage: String
 
     override fun decode() {
         xmlMessage = String(this.input.goto(65).readNBytes(this.input.goto(60).readShort().toInt()))
@@ -147,7 +183,6 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
     var qq: Long = 0
     lateinit var message: MessageChain
 
-
     @ExperimentalUnsignedTypes
     override fun decode() {
         //start at Sep1.0:27
@@ -166,6 +201,30 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
     }
 
 }
+
+
+/**
+ * 告知服务器已经收到数据
+ */
+@PacketId("")//随后写入
+@ExperimentalUnsignedTypes
+class ClientMessageResponsePacket(
+        private val qq: Long,
+        private val packetIdFromServer: ByteArray,//4bytes
+        private val sessionKey: ByteArray,
+        private val eventIdentity: ByteArray
+) : ClientPacket() {
+    override fun encode() {
+        this.write(packetIdFromServer)//packet id 4bytes
+
+        this.writeQQ(qq)
+        this.writeHex(Protocol.fixVer2)
+        this.encryptAndWrite(sessionKey) {
+            it.write(eventIdentity)
+        }
+    }
+}
+
 /*
 3E 03 3F A2 76 E4 B8 DD 00 09 7C 3F 64 5C 2A 60 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E4 5D 6B A8 F6 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A8 F6 08 7E 90 CE 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
 3E 03 3F A2 76 E4 B8 DD 00 03 5F 85 64 5C 2A A4 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E5 5D 6B A9 16 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A9 17 1B B3 4D D7 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
index 980bf9961..cd967e486 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
@@ -3,10 +3,7 @@ package net.mamoe.mirai.network.packet
 import net.mamoe.mirai.network.packet.login.*
 import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket
 import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket
-import net.mamoe.mirai.utils.MiraiLogger
-import net.mamoe.mirai.utils.getAllDeclaredFields
-import net.mamoe.mirai.utils.hexToBytes
-import net.mamoe.mirai.utils.toUHexString
+import net.mamoe.mirai.utils.*
 import java.io.DataInputStream
 
 /**
@@ -14,7 +11,9 @@ import java.io.DataInputStream
  */
 abstract class ServerPacket(val input: DataInputStream) : Packet {
 
-    abstract fun decode()
+    open fun decode() {
+
+    }
 
     companion object {
 
@@ -28,23 +27,22 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
 
 
             return when (val idHex = stream.readInt().toHexString(" ")) {
-                "08 25 31 01" -> ServerTouchResponsePacketEncrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, stream)
-
-                "08 25 31 02" -> ServerTouchResponsePacketEncrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_02, stream)
+                "08 25 31 01" -> ServerTouchResponsePacket.Encrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, stream)
+                "08 25 31 02" -> ServerTouchResponsePacket.Encrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_02, stream)
 
                 "08 36 31 03", "08 36 31 04", "08 36 31 05", "08 36 31 06" -> {
                     when (bytes.size) {
-                        271, 207 -> return ServerLoginResponseResendPacketEncrypted(stream, when (idHex) {
+                        271, 207 -> return ServerLoginResponseResendPacket.Encrypted(stream, when (idHex) {
                             "08 36 31 03" -> ServerLoginResponseResendPacket.Flag.`08 36 31 03`
                             else -> {
                                 MiraiLogger debug ("ServerLoginResponseResendPacketEncrypted: flag=$idHex"); ServerLoginResponseResendPacket.Flag.OTHER
                             }
                         })
-                        871 -> return ServerLoginResponseVerificationCodePacketEncrypted(stream)
+                        871 -> return ServerLoginResponseVerificationCodeInitPacket.Encrypted(stream)
                     }
 
                     if (bytes.size > 700) {
-                        return ServerLoginResponseSuccessPacketEncrypted(stream)
+                        return ServerLoginResponseSuccessPacket.Encrypted(stream)
                     }
 
                     return ServerLoginResponseFailedPacket(when (bytes.size) {
@@ -63,20 +61,20 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
                     }, stream)
                 }
 
-                "08 28 04 34" -> ServerSessionKeyResponsePacketEncrypted(stream)
+                "08 28 04 34" -> ServerSessionKeyResponsePacket.Encrypted(stream)
 
 
                 else -> when (idHex.substring(0, 5)) {
                     "00 EC" -> ServerLoginSuccessPacket(stream)
-                    "00 1D" -> ServerSKeyResponsePacketEncrypted(stream)
-                    "00 5C" -> ServerAccountInfoResponsePacketEncrypted(stream)
+                    "00 1D" -> ServerSKeyResponsePacket.Encrypted(stream)
+                    "00 5C" -> ServerAccountInfoResponsePacket.Encrypted(stream)
 
                     "00 58" -> ServerHeartbeatResponsePacket(stream)
 
-                    "00 BA" -> ServerVerificationCodePacketEncrypted(stream)
+                    "00 BA" -> ServerVerificationCodePacket.Encrypted(stream)
 
 
-                    "00 CE", "00 17" -> ServerMessageEventPacketRawEncoded(stream, idHex.hexToBytes())
+                    "00 CE", "00 17" -> ServerEventPacket.Raw.Encrypted(stream, idHex.hexToBytes())
 
                     "00 81" -> UnknownServerPacket(stream)
 
@@ -101,6 +99,16 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
         }
         }
     }
+
+    fun decryptBy(key: ByteArray): DataInputStream {
+        input.goto(14)
+        return DataInputStream(TEA.decrypt(input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, key).inputStream())
+    }
+
+    @ExperimentalUnsignedTypes
+    fun decryptBy(keyHex: String): DataInputStream {
+        return this.decryptBy(keyHex.hexToBytes())
+    }
 }
 
 
@@ -173,4 +181,6 @@ fun <N : Number> DataInputStream.readByteAt(position: N): Byte {
 fun <N : Number> DataInputStream.readShortAt(position: N): Short {
     this.goto(position)
     return this.readShort();
-}
\ No newline at end of file
+}
+
+fun ByteArray.cutTail(length: Int): ByteArray = this.copyOfRange(0, this.size - length)
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt
index 4f55c4e88..301a2402f 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt
@@ -2,7 +2,7 @@ package net.mamoe.mirai.network.packet
 
 import net.mamoe.mirai.network.Protocol
 import net.mamoe.mirai.utils.ByteArrayDataOutputStream
-import net.mamoe.mirai.utils.TEACryptor
+import net.mamoe.mirai.utils.TEA
 import net.mamoe.mirai.utils.getRandomKey
 import net.mamoe.mirai.utils.lazyEncode
 import java.io.DataInputStream
@@ -16,8 +16,6 @@ import java.net.InetAddress
 class ClientSessionRequestPacket(
         private val qq: Long,
         private val serverIp: String,
-        private val loginIP: String,
-        private val md5_32: ByteArray,
         private val token38: ByteArray,
         private val token88: ByteArray,
         private val encryptionKey: ByteArray,
@@ -28,7 +26,7 @@ class ClientSessionRequestPacket(
         this.writeHex("02 00 00 00 01 2E 01 00 00 68 52 00 30 00 3A")
         this.writeHex("00 38")
         this.write(token38)
-        this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() {
+        this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
             override fun toByteArray(): ByteArray {
                 this.writeHex("00 07 00 88")
                 this.write(token88)
@@ -36,10 +34,10 @@ class ClientSessionRequestPacket(
                 this.writeIP(serverIp)
                 this.writeHex("1F 40 00 00 00 00 00 15 00 30 00 01")//fix1
                 this.writeHex("01 92 A5 D2 59 00 10 54 2D CF 9B 60 BF BB EC 0D D4 81 CE 36 87 DE 35 02 AE 6D ED DC 00 10 ")
-                this.writeHex(Protocol._0836fix)
+                this.writeHex(Protocol.fix0836)
                 this.writeHex("00 36 00 12 00 02 00 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00")
-                this.writeHex(Protocol._0825data0)
-                this.writeHex(Protocol._0825data2)
+                this.writeHex(Protocol.constantData0)
+                this.writeHex(Protocol.constantData1)
                 this.writeQQ(qq)
                 this.writeHex("00 00 00 00 00 1F 00 22 00 01")
                 this.writeHex("1A 68 73 66 E4 BA 79 92 CC C2 D4 EC 14 7C 8B AF 43 B0 62 FB 65 58 A9 EB 37 55 1D 26 13 A8 E5 3D")//device ID
@@ -51,7 +49,7 @@ class ClientSessionRequestPacket(
 
                 //fix3
                 this.writeHex("00 63 3E 00 63 02 04 03 06 02 00 04 00 52 D9 00 00 00 00 A9 58 3E 6D 6D 49 AA F6 A6 D9 33 0A E7 7E 36 84 03 01 00 00 68 20 15 8B 00 00 01 02 00 00 03 00 07 DF 00 0A 00 0C 00 01 00 04 00 03 00 04 20 5C 00")
-                this.write(md5_32)
+                this.write(getRandomKey(32))//md5 32
                 this.writeHex("68")
 
                 this.writeHex("00 00 00 00 00 2D 00 06 00 01")
@@ -106,16 +104,12 @@ class ServerSessionKeyResponsePacket(inputStream: DataInputStream, private val d
         //tlv0105 = "01 05 00 88 00 01 01 02 00 40 02 01 03 3C 01 03 00 00" + 取文本中间(data, 取文本长度(data) - 367, 167) + “00 40 02 02 03 3C 01 03 00 00 ” + 取文本中间 (data, 取文本长度 (data) - 166, 167)
 
     }
-}
 
-class ServerSessionKeyResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
-    override fun decode() {
-
-    }
-
-    fun decrypt(_0828_rec_decr_key: ByteArray): ServerSessionKeyResponsePacket {
-        this.input goto 14
-        val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
-        return ServerSessionKeyResponsePacket(TEACryptor.decrypt(data, _0828_rec_decr_key).dataInputStream(), data.size);
+    class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
+        fun decrypt(_0828_rec_decr_key: ByteArray): ServerSessionKeyResponsePacket {
+            this.input goto 14
+            val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
+            return ServerSessionKeyResponsePacket(TEA.decrypt(data, _0828_rec_decr_key).dataInputStream(), data.size);
+        }
     }
 }
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt
index bf3624e84..6e10d37a9 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt
@@ -48,24 +48,13 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp
             }
         }
     }
-}
 
-class ServerTouchResponsePacketEncrypted(private val type: ServerTouchResponsePacket.Type, inputStream: DataInputStream) : ServerPacket(inputStream) {
-    override fun decode() {
-
-    }
-
-    @ExperimentalUnsignedTypes
-    fun decrypt(): ServerTouchResponsePacket {
-        input.skip(7)
-        var bytes = input.readAllBytes();
-        bytes = bytes.copyOfRange(0, bytes.size - 1);
-        println(bytes.toUByteArray().toUHexString())
-
-        return ServerTouchResponsePacket(DataInputStream(TEACryptor.decrypt(bytes, when (type) {
-            ServerTouchResponsePacket.Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes()
-            ServerTouchResponsePacket.Type.TYPE_08_25_31_01 -> Protocol._0825key.hexToBytes()
-        }).inputStream()));
+    class Encrypted(private val type: Type, inputStream: DataInputStream) : ServerPacket(inputStream) {
+        @ExperimentalUnsignedTypes
+        fun decrypt(): ServerTouchResponsePacket = ServerTouchResponsePacket(decryptBy(when (type) {
+            Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes()
+            Type.TYPE_08_25_31_01 -> Protocol.key0825.hexToBytes()
+        }))
     }
 }
 
@@ -82,13 +71,13 @@ class ClientTouchPacket(val qq: Long, val serverIp: String) : ClientPacket() {
     override fun encode() {
         this.writeQQ(qq)
         this.writeHex(Protocol.fixVer)
-        this.writeHex(Protocol._0825key)
+        this.writeHex(Protocol.key0825)
 
-        this.write(TEACryptor.CRYPTOR_0825KEY.encrypt(object : ByteArrayDataOutputStream() {
+        this.write(TEA.CRYPTOR_0825KEY.encrypt(object : ByteArrayDataOutputStream() {
             @Throws(IOException::class)
             override fun toByteArray(): ByteArray {
-                this.writeHex(Protocol._0825data0)
-                this.writeHex(Protocol._0825data2)
+                this.writeHex(Protocol.constantData0)
+                this.writeHex(Protocol.constantData1)
                 this.writeQQ(qq)
                 this.writeHex("00 00 00 00 03 09 00 08 00 01")
                 this.writeIP(serverIp);
@@ -116,11 +105,11 @@ class ClientServerRedirectionPacket(private val serverIP: String, private val qq
         this.writeHex(Protocol.redirectionKey)
 
 
-        this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() {
+        this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
             @Throws(IOException::class)
             override fun toByteArray(): ByteArray {
-                this.writeHex(Protocol._0825data0)
-                this.writeHex(Protocol._0825data2)
+                this.writeHex(Protocol.constantData0)
+                this.writeHex(Protocol.constantData1)
                 this.writeQQ(qq)
                 this.writeHex("00 01 00 00 03 09 00 0C 00 01")
                 this.writeIP(serverIP)
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt
index ba3e8d377..06e26e7b8 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt
@@ -23,11 +23,11 @@ class ClientVerificationCodeTransmissionRequestPacket(
         this.writeByte(count)//part of packet id
 
         this.writeQQ(qq)
-        this.writeHex(Protocol._fixVer)
-        this.writeHex(Protocol._00BaKey)
-        this.encryptAndWrite(Protocol._00BaKey) {
+        this.writeHex(Protocol.fixVer2)
+        this.writeHex(Protocol.key00BA)
+        this.encryptAndWrite(Protocol.key00BA) {
             it.writeHex("00 02 00 00 08 04 01 E0")
-            it.writeHex(Protocol._0825data2)
+            it.writeHex(Protocol.constantData1)
             it.writeHex("00 00 38")
             it.write(token0825)
             it.writeHex("01 03 00 19")
@@ -37,7 +37,7 @@ class ClientVerificationCodeTransmissionRequestPacket(
             it.writeHex("00 28")
             it.write(token00BA)
             it.writeHex("00 10")
-            it.writeHex(Protocol._00BaFixKey)
+            it.writeHex(Protocol.key00BAFix)
         }
     }
 }
@@ -87,22 +87,19 @@ class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerific
     }
 }
 
-abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input)
+abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) {
 
-@PacketId("00 BA")
-class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) {
-    override fun decode() {
-
-    }
-
-    @ExperimentalUnsignedTypes
-    fun decrypt(): ServerVerificationCodePacket {
-        this.input goto 14
-        val data = TEACryptor.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, Protocol._00BaKey.hexToBytes())
-        return if (data.size == 95) {
-            ServerVerificationCodeRepeatPacket(data.dataInputStream())
-        } else {
-            ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4))
+    @PacketId("00 BA")
+    class Encrypted(input: DataInputStream) : ServerPacket(input) {
+        @ExperimentalUnsignedTypes
+        fun decrypt(): ServerVerificationCodePacket {
+            this.input goto 14
+            val data = TEA.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, Protocol.key00BA.hexToBytes())
+            return if (data.size == 95) {
+                ServerVerificationCodeRepeatPacket(data.dataInputStream())
+            } else {
+                ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4))
+            }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientChangeOnlineStatusPacket.kt
similarity index 83%
rename from mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt
rename to mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientChangeOnlineStatusPacket.kt
index 7c2b2eae3..2007b99bc 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientChangeOnlineStatusPacket.kt
@@ -5,11 +5,13 @@ import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.utils.ClientLoginStatus
 
 /**
+ * 改变在线状态: "我在线上", "隐身" 等
+ *
  * @author Him188moe
  */
 @ExperimentalUnsignedTypes
 @PacketId("00 EC")
-class ClientLoginStatusPacket(
+class ClientChangeOnlineStatusPacket(
         private val qq: Long,
         private val sessionKey: ByteArray,
         private val loginStatus: ClientLoginStatus
@@ -18,7 +20,7 @@ class ClientLoginStatusPacket(
     override fun encode() {
         this.writeRandom(2)//part of packet id
         this.writeQQ(qq)
-        this.writeHex(Protocol._fixVer)
+        this.writeHex(Protocol.fixVer2)
         this.encryptAndWrite(sessionKey) {
             it.writeHex("01 00")
             it.writeByte(loginStatus.id)
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLogin.kt
similarity index 91%
rename from mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt
rename to mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLogin.kt
index 2330c1d30..7066ca1d8 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLogin.kt
@@ -4,7 +4,7 @@ import net.mamoe.mirai.network.Protocol
 import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.util.TestedSuccessfully
 import net.mamoe.mirai.utils.ByteArrayDataOutputStream
-import net.mamoe.mirai.utils.TEACryptor
+import net.mamoe.mirai.utils.TEA
 import net.mamoe.mirai.utils.hexToBytes
 import net.mamoe.mirai.utils.toUHexString
 import java.io.DataOutputStream
@@ -28,10 +28,10 @@ class ClientPasswordSubmissionPacket(
     @ExperimentalUnsignedTypes
     override fun encode() {
         this.writeQQ(qq)
-        this.writeHex(Protocol._0836_622_fix1)
+        this.writeHex(Protocol.passwordSubmissionKey1)
         this.writeHex(Protocol.publicKey)
         this.writeHex("00 00 00 10")
-        this.writeHex(Protocol._0836key1)
+        this.writeHex(Protocol.key0836)
 
         this.encryptAndWrite(Protocol.shareKey.hexToBytes()) {
             it.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825)
@@ -69,12 +69,12 @@ open class ClientLoginResendPacket internal constructor(
 ) : ClientPacket() {
     override fun encode() {
         this.writeQQ(qq)
-        this.writeHex(Protocol._0836_622_fix1)
+        this.writeHex(Protocol.passwordSubmissionKey1)
         this.writeHex(Protocol.publicKey)
         this.writeHex("00 00 00 10")
-        this.writeHex(Protocol._0836key1)
+        this.writeHex(Protocol.key0836)
 
-        this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() {
+        this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
             override fun toByteArray(): ByteArray {
                 this.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825, tlv_0006_encr)
 
@@ -115,12 +115,12 @@ private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: I
         this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey)
     }
     //fix
-    this.writeHex(Protocol._0836_622_fix2)
+    this.writeHex(Protocol.passwordSubmissionKey2)
     this.writeHex("00 1A")//tag
     this.writeHex("00 40")//length
-    this.write(TEACryptor.encrypt(Protocol._0836_622_fix2.hexToBytes(), tgtgtKey))
-    this.writeHex(Protocol._0825data0)
-    this.writeHex(Protocol._0825data2)
+    this.write(TEA.encrypt(Protocol.passwordSubmissionKey2.hexToBytes(), tgtgtKey))
+    this.writeHex(Protocol.constantData0)
+    this.writeHex(Protocol.constantData1)
     this.writeQQ(qq)
     this.writeZero(4)
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt
index 033f993d9..2313c45b5 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt
@@ -1,13 +1,9 @@
 package net.mamoe.mirai.network.packet.login
 
 import net.mamoe.mirai.network.Protocol
-import net.mamoe.mirai.network.packet.ServerPacket
-import net.mamoe.mirai.network.packet.goto
-import net.mamoe.mirai.network.packet.readNBytesAt
-import net.mamoe.mirai.network.packet.readVarString
+import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.util.TestedSuccessfully
-import net.mamoe.mirai.utils.TEACryptor
-import net.mamoe.mirai.utils.hexToBytes
+import net.mamoe.mirai.utils.TEA
 import net.mamoe.mirai.utils.toUHexString
 import java.io.DataInputStream
 
@@ -117,21 +113,14 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
 
         //this.gender = this.input.goto(packetDataLength - 32).readByteAt().toInt()
     }
-}
 
-class ServerLoginResponseSuccessPacketEncrypted(input: DataInputStream) : ServerPacket(input) {
-    override fun decode() {
 
+    class Encrypted(input: DataInputStream) : ServerPacket(input) {
+        @ExperimentalUnsignedTypes
+        fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket {
+            input goto 14
+            return ServerLoginResponseSuccessPacket(TEA.decrypt(TEA.decrypt(input.readAllBytes().cutTail(1), Protocol.shareKey), tgtgtKey).dataInputStream());
+        }
     }
 
-    @ExperimentalUnsignedTypes
-    fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket {
-        input goto 14
-        var bytes = input.readAllBytes()
-        bytes = bytes.copyOfRange(0, bytes.size - 1)
-        println(bytes.toUByteArray().toUHexString())
-
-        return ServerLoginResponseSuccessPacket(DataInputStream(TEACryptor.decrypt(TEACryptor.decrypt(bytes, Protocol.shareKey.hexToBytes()), tgtgtKey).inputStream()));
-        //TeaDecrypt(取文本中间(data, 43, 取文本长度(data) - 45), m_0828_rec_decr_key)
-    }
-}
+}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt
index 0303fcb6e..cfc72a965 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt
@@ -2,10 +2,8 @@ package net.mamoe.mirai.network.packet.login
 
 import net.mamoe.mirai.network.packet.PacketId
 import net.mamoe.mirai.network.packet.ServerPacket
-import net.mamoe.mirai.network.packet.dataInputStream
 import net.mamoe.mirai.network.packet.goto
 import net.mamoe.mirai.util.TestedSuccessfully
-import net.mamoe.mirai.utils.TEACryptor
 import java.io.DataInputStream
 
 /**
@@ -43,20 +41,9 @@ class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) :
             }
         }
     }
+
+    class Encrypted(input: DataInputStream, private val flag: Flag) : ServerPacket(input) {
+        @TestedSuccessfully
+        fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseResendPacket = ServerLoginResponseResendPacket(decryptBy(tgtgtKey), flag)
+    }
 }
-
-class ServerLoginResponseResendPacketEncrypted(input: DataInputStream, private val flag: ServerLoginResponseResendPacket.Flag) : ServerPacket(input) {
-    override fun decode() {
-
-    }
-
-    @TestedSuccessfully
-    fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseResendPacket {
-        //this.input.skip(7)
-        this.input goto 14
-        var data: ByteArray = this.input.readAllBytes()
-        data = TEACryptor.CRYPTOR_SHARE_KEY.decrypt(data.let { it.copyOfRange(0, it.size - 1) });
-        data = TEACryptor.decrypt(data, tgtgtKey)
-        return ServerLoginResponseResendPacket(data.dataInputStream(), flag)
-    }
-}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt
index 3d46f3b0f..49bab953e 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt
@@ -1,10 +1,11 @@
 package net.mamoe.mirai.network.packet.login
 
 import net.mamoe.mirai.network.packet.ServerPacket
+import net.mamoe.mirai.network.packet.cutTail
 import net.mamoe.mirai.network.packet.dataInputStream
 import net.mamoe.mirai.network.packet.goto
 import net.mamoe.mirai.util.TestedSuccessfully
-import net.mamoe.mirai.utils.TEACryptor
+import net.mamoe.mirai.utils.TEA
 import net.mamoe.mirai.utils.hexToUBytes
 import java.io.DataInputStream
 
@@ -32,6 +33,19 @@ class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, priv
 
         this.token00BA = this.input.goto(packetLength - 60).readNBytes(40)
     }
+
+
+    class Encrypted(input: DataInputStream) : ServerPacket(input) {
+        override fun decode() {
+
+        }
+
+        fun decrypt(): ServerLoginResponseVerificationCodeInitPacket {
+            this.input goto 14
+            val data = TEA.CRYPTOR_SHARE_KEY.decrypt(this.input.readAllBytes().cutTail(1));
+            return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size)
+        }
+    }
 }
 
 fun main() {
@@ -54,15 +68,3 @@ verify code
 token00ba
 42 E6 18 57 D4 B1 4D AE 51 27 D5 EF A2 38 91 39 15 37 6C 5A FE 75 93 49 DB FC 57 3C 12 3F 26 D9 16 1D 83 45 8B 78 39 D8
  */
-
-class ServerLoginResponseVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) {
-    override fun decode() {
-
-    }
-
-    fun decrypt(): ServerLoginResponseVerificationCodeInitPacket {
-        this.input goto 14
-        val data = TEACryptor.CRYPTOR_SHARE_KEY.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) });
-        return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size)
-    }
-}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginSuccessPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginSuccessPacket.kt
index 2aebc04d5..4b5d092d0 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginSuccessPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginSuccessPacket.kt
@@ -4,10 +4,8 @@ import net.mamoe.mirai.network.packet.ServerPacket
 import java.io.DataInputStream
 
 /**
+ * Congratulations!
+ *
  * @author Him188moe
  */
-class ServerLoginSuccessPacket(input: DataInputStream) : ServerPacket(input) {
-    override fun decode() {
-
-    }
-}
\ No newline at end of file
+class ServerLoginSuccessPacket(input: DataInputStream) : ServerPacket(input)
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt
index 6fa63d04d..7313a3bbb 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt
@@ -19,7 +19,7 @@ class ClientSendFriendMessagePacket(
     override fun encode() {
         this.writeRandom(2)//part of packet id
         this.writeQQ(robotQQ)
-        this.writeHex(Protocol._fixVer)
+        this.writeHex(Protocol.fixVer2)
 
         this.encryptAndWrite(sessionKey) {
             it.writeQQ(robotQQ)
@@ -58,7 +58,4 @@ class ClientSendFriendMessagePacket(
 }
 
 @PacketId("00 CD")
-class ServerSendFriendMessageResponsePacket(input: DataInputStream) : ServerPacket(input) {
-    override fun decode() {
-    }
-}
\ No newline at end of file
+class ServerSendFriendMessageResponsePacket(input: DataInputStream) : ServerPacket(input)
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt
index 2ef2a85cc..c16d27ae5 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt
@@ -2,7 +2,6 @@ package net.mamoe.mirai.network.packet.message
 
 import net.mamoe.mirai.network.Protocol
 import net.mamoe.mirai.network.packet.*
-import net.mamoe.mirai.utils.lazyEncode
 import net.mamoe.mirai.utils.toUHexString
 import java.io.DataInputStream
 
@@ -13,14 +12,14 @@ import java.io.DataInputStream
 @ExperimentalUnsignedTypes
 class ClientSendGroupMessagePacket(
         private val groupId: Long,//不是 number
-        private val qq: Long,
+        private val robotQQ: Long,
         private val sessionKey: ByteArray,
         private val message: String
 ) : ClientPacket() {
     override fun encode() {
         this.writeRandom(2)//part of packet id
-        this.writeQQ(qq)
-        this.writeHex(Protocol._fixVer)
+        this.writeQQ(robotQQ)
+        this.writeHex(Protocol.fixVer2)
 
         this.encryptAndWrite(sessionKey) {
             val bytes = message.toByteArray()
@@ -46,24 +45,5 @@ class ClientSendGroupMessagePacket(
     }
 }
 
-fun main() {
-    println(lazyEncode {
-        val bytes = "message".toByteArray()
-        it.writeByte(0x2A)
-        it.writeInt(580266363)
-        it.writeShort(19 + bytes.size)
-
-        it.writeByte(0x01)
-        it.writeByte(0x01)
-        it.writeShort(bytes.size + 3)
-        it.writeByte(0x01)
-        it.writeShort(bytes.size)
-        it.write(bytes)
-    }.toUHexString())
-}
-
 @PacketId("00 02")
-class ServerSendGroupMessageResponsePacket(input: DataInputStream) : ServerPacket(input) {
-    override fun decode() {
-    }
-}
\ No newline at end of file
+class ServerSendGroupMessageResponsePacket(input: DataInputStream) : ServerPacket(input)
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/ClientLoginStatus.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/ClientLoginStatus.java
index 45e1976fd..b2864cae6 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/utils/ClientLoginStatus.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/ClientLoginStatus.java
@@ -4,10 +4,14 @@ package net.mamoe.mirai.utils;
  * @author Him188moe
  */
 public enum ClientLoginStatus {
+    /**
+     * 我在线上
+     */
     ONLINE(0x0A);
 
-    // TODO: 2019/8/31 add more
-    public final int id;//1byte
+    // TODO: 2019/8/31 add more ClientLoginStatus
+
+    public final int id;//1 ubyte
 
     ClientLoginStatus(int id) {
         this.id = id;
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/RobotAccount.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/RobotAccount.java
new file mode 100644
index 000000000..0f2bea143
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/RobotAccount.java
@@ -0,0 +1,17 @@
+package net.mamoe.mirai.utils;
+
+import lombok.Data;
+
+/**
+ * @author Him188moe
+ */
+@Data
+public final class RobotAccount {
+    public final long qqNumber;
+    public final String password;
+
+    public RobotAccount(long qqNumber, String password) {
+        this.qqNumber = qqNumber;
+        this.password = password;
+    }
+}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/TEACryptor.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java
similarity index 91%
rename from mirai-core/src/main/java/net/mamoe/mirai/utils/TEACryptor.java
rename to mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java
index 9b6269c49..84121e2eb 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/utils/TEACryptor.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java
@@ -8,10 +8,10 @@ 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_SHARE_KEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol.shareKey));
-    public static final TEACryptor CRYPTOR_0825KEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._0825key));
-    public static final TEACryptor CRYPTOR_00BAKEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._00BaKey));
+public class TEA {
+    public static final TEA CRYPTOR_SHARE_KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.shareKey));
+    public static final TEA CRYPTOR_0825KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key0825));
+    public static final TEA CRYPTOR_00BAKEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key00BA));
 
     private static final long UINT32_MASK = 0xffffffffL;
     private final long[] mKey;
@@ -25,7 +25,7 @@ public class TEACryptor {
     private boolean isFirstBlock;
     private boolean isRand;
 
-    public TEACryptor(byte[] key) {
+    public TEA(byte[] key) {
         mKey = new long[4];
         for (int i = 0; i < 4; i++) {
             mKey[i] = pack(key, i * 4, 4);
@@ -36,11 +36,19 @@ public class TEACryptor {
     }
 
     public static byte[] encrypt(byte[] source, byte[] key) {
-        return new TEACryptor(key).encrypt(source);
+        return new TEA(key).encrypt(source);
+    }
+
+    public static byte[] encrypt(byte[] source, String keyHex) {
+        return encrypt(source, UtilsKt.hexToBytes(keyHex));
     }
 
     public static byte[] decrypt(byte[] source, byte[] key) {
-        return new TEACryptor(key).decrypt(source);
+        return new TEA(key).decrypt(source);
+    }
+
+    public static byte[] decrypt(byte[] source, String keyHex) {
+        return decrypt(source, UtilsKt.hexToBytes(keyHex));
     }
 
     private static long pack(byte[] bytes, int offset, int len) {