Skip to content

Latest commit

 

History

History
118 lines (86 loc) · 4.82 KB

File metadata and controls

118 lines (86 loc) · 4.82 KB

协议加密


从12w17a开始,Minecraft开始使用一种类似于SSL的加密方式。

总览

  C->S : Handshake State=2
  C->S : Login Start
  S->C : Encryption Key Request
  (Client Auth)
  C->S : Encryption Key Response
  (Server Auth, Both enable encryption)
  S->C : Login Success

请查看协议常见问题解答来获取接下来更多会发生的信息。

服务器ID字符串

更新(1.7.x):服务器ID现在开始是一个空字符串。哈希值依然使用公钥,所以这仍然是正常的。 1.7.x前的版本:服务器ID字符串是一个随机生成的最大20个代码点长的字符串(客户端会因这个字符串长于20时意外断开连接)

若发送的服务器ID内含有不可显示的符号的话,客户端会收到错误的hash,为了避免这种情况发生请使用范围在U+0021-U+007E(包括)的代码点发送。这个范围包括了全部ARSCII码以及空格符号(U+0020)以及所有控制符号(U+0000-U+001F, U+007F)。 若发送的服务器ID太短客户端会受到错误的hash,大于15小于20的长度才是被Notchian服务端认可的(1.5.2版本已知)

Key交换

服务器会在启动的时候生成一个1024位的RSA密钥对。密钥在数据在加密请求打包后,会以x.509定义的ASN.1形式显示。ASN.1结构如下:

SubjectPublicKeyInfo ::= SEQUENCE {
  algorithm SEQUENCE {
    algorithm         OBJECT IDENTIFIER
    parameters        ANY OPTIONAL
  }
  subjectPublicKey  BITSTRING
}

SubjectPublicKey ::= SEQUENCE {
  modulus           INTEGER
  publicExponent    INTEGER
}

如果你在将它通过密码算法库导入时遇到困难,你可以把它转化为一般用base64编码的PEM形式并且加上“-----BEGIN PUBLIC KEY-----”和“-----END PUBLIC KEY-----”

对称加密

在收到服务器的加密请求后,客户端将会生成一个16字节的共享密钥,将与AES/CFB8流密码配合使用。然后它将会使用服务器的公钥来加密(PKCS#1 v1.5 padded), 并且用同样的方式加密在加密请求中接收到的token,然后在加密回应包里发送一组密钥对给服务端。

服务端通过密钥来解密公钥和token,然后检查token是否一致。登录成功消息,, 并且启用AES/CFB8加密。对于Initial Vector (IV)和AES设置,客户端和服务端都会使用私钥。类似的,客户端也将在发送加密回应的时候启用加密。从这时开始,所有东西都加密了。

认证

在服务器处于在线模式的情况下,客户端和服务端都需要给sessionserver.mojang.com发送一个请求。

客户端

生成私钥后,客户端将会生成以下hash:

 sha1 := Sha1()
 sha1.update(ASCII encoding of the server id string from Encryption Request) 
 sha1.update(shared secret) 
 sha1.update(server's encoded public key from Encryption Request) 
 hash := sha1.hexdigest()  # String of hex characters

注意Sha1.hexdigest()形式used by minecraft removes leading zeros and uses the two's-complement of negative numbers prefixed with a minus sign:

 sha1(Notch) :  4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
 sha1(jeb_)  : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
 sha1(simon) :  88e16a1019277b15d58faf0541e11910eb756f6

hash结果将会通过HTTP POST请求发送到:

https://sessionserver.mojang.com/session/minecraft/join

发送以下内容,Content-Type: application/json

   {
    "accessToken": "<accessToken>",
    "selectedProfile": "<selectedProfile>",
    "serverId": "<serverHash>"   
    }

服务端

在第二次加密回应解密解密公钥之后,服务端将会按照上面相同的方式生成登录hash并发送给

https://sessionserver.mojang.com/session/minecraft/hasJoined?username=username&serverId=hash

回应的是包括用户的UUID和皮肤blob的JSON文件

{
    "id": "<profile identifier>",
    "name": "<player name>",
    "properties": [ 
        {
            "name": "textures",
            "value": "<base64 string>",
            "signature": "<base64 string; signed data using Yggdrasil's private key>"
        }
    ]
}

示例代码

生成Java-style的hex digests示例: C#: http://git.io/kO6Ejg node.js: http://git.io/v2ue_A Go: http://git.io/-5ORag Java: http://git.io/7nLXYg

更多链接

Encrypt shared secret using OpenSSL Generate RSA-Keys and building the ASN.1v8 structure of the x.509 certificate using Crypto++ Decrypt shared secret using Crypto++ De/Encrypt data via AES using Crypto++ C# AES/CFB support with bouncy castle on Mono