Update to 1.3 protocol, sha1 digest still needs work

This commit is contained in:
Ammar Askar 2012-09-06 00:28:55 +05:00
parent fb7b22b771
commit f18c6496b8
3 changed files with 184 additions and 81 deletions

22
Utils.py Normal file
View File

@ -0,0 +1,22 @@
import array
def stringToByteArray(string):
return array.array('B', string.decode("hex"))
def TwosCompliment(hash):
hash = array.array('B', hash.decode("hex"))
carry = True
for i in range((hash.__len__() - 1), 0, -1):
if(carry):
carry = hash[i] == 0xFF
hash[i] += 1
return hash
def trimStart(string, character):
for c in string:
if (c == character):
string = string[1:]
else:
break
return string

View File

@ -2,10 +2,12 @@ import socket
import wx
import PacketListenerManager
import urllib2
import urllib
import traceback
import threading
import hashlib
import string
import Utils
from networking import PacketSenderManager
from Crypto.Random import _UserFriendlyRNG
from Crypto.Util import asn1
@ -65,28 +67,34 @@ class ServerConnection(threading.Thread):
packetFD = PacketListenerManager.handleFD(self.FileObject)
#Import the server's public key
print "#Import the server's public key"
self.pubkey = RSA.importKey(packetFD['Public Key'])
#Generate a 16 byte (128 bit) shared secret
print "#Generate a 16 byte (128 bit) shared secret"
self.sharedSecret = _UserFriendlyRNG.get_random_bytes(16)
#Grab the server id
print "#Grab the server id"
serverid = packetFD['ServerID']
sha1 = hashlib.sha1()
sha1.update(serverid)
sha1.update(str(self.sharedSecret))
sha1.update(str(self.pubkey))
serverid = sha1.hexdigest()
sha1.update(packetFD['ServerID'])
sha1.update(self.sharedSecret)
sha1.update(packetFD['Public Key'])
#lovely java style hex digest by SirCmpwn
sha1 = sha1.hexdigest()
negative = (int(sha1[0], 16) & 0x80) == 0x80
if(negative):
sha1 = Utils.TwosCompliment(sha1.digest())
#else:
# sha1 = sha1.digest()
Utils.trimStart(str(sha1), '0')
if (negative):
sha1 = '-' + sha1
serverid = sha1
#Authenticate the server from sessions.minecraft.net
print "#Authenticate the server from sessions.minecraft.net"
if(serverid != '-'):
try:
#Open up the url with the appropriate get parameters
url = "http://session.minecraft.net/game/joinserver.jsp?user=" + self.username + "&sessionId=" + self.sessionID + "&serverId=" + serverid
print url
response = urllib2.urlopen(url).read()
if(response != "OK"):
@ -99,20 +107,16 @@ class ServerConnection(threading.Thread):
return False
#Success \o/ We can now begin sending our stuff to the server
print "#Success \o/ We can now begin sending our stuff to the server"
#Instantiate our main packet listener
print "#Instantiate our main packet listener"
PacketListener(self, self.window, self.socket, self.FileObject).start()
#Encrypt the verification token from earlier along with our shared secret with the server's rsa key
print "#Encrypt the verification token from earlier along with our shared secret"
self.RSACipher = PKCS1_v1_5.new(self.pubkey)
encryptedSanityToken = self.RSACipher.encrypt(str(packetFD['Token']))
encryptedSharedSecret = self.RSACipher.encrypt(str(self.sharedSecret))
#Send out a a packet FC to the server
print "#Send out a a packet FC to the server"
PacketSenderManager.sendFC(self.socket, encryptedSharedSecret, encryptedSanityToken)
#GUI handling
@ -151,7 +155,9 @@ class EncryptedFileObjectHandler():
self.cipher = cipher
def read(self, length):
return self.cipher.decrypt(self.fileobject.read(length))
rawData = self.fileobject.read(length)
unencryptedData = self.cipher.decrypt(rawData)
return unencryptedData
class EncryptedSocketObjectHandler():
@ -161,9 +167,6 @@ class EncryptedSocketObjectHandler():
def send(self, stuff):
self.socket.send(self.cipher.encrypt(stuff))
def recv(self, length):
return self.cipher.decrypt(self.socket.recv(length))
def close(self):
self.socket.close()
@ -180,14 +183,13 @@ class PacketListener(threading.Thread):
def enableEncryption(self):
#Create an AES cipher from the previously obtained public key
print "#Create an AES cipher from the previously generated shared secret"
self.cipher = AES.new(str(self.connection.sharedSecret), AES.MODE_CFB, IV=self.connection.sharedSecret, segment_size=8)
self.cipher = AES.new(self.connection.sharedSecret, AES.MODE_CFB, IV=self.connection.sharedSecret)
self.decipher = AES.new(self.connection.sharedSecret, AES.MODE_CFB, IV=self.connection.sharedSecret)
self.rawsocket = self.socket
self.socket = EncryptedSocketObjectHandler(self.rawsocket, self.cipher)
self.rawFileObject = self.FileObject
self.FileObject = EncryptedFileObjectHandler(self.rawFileObject, self.cipher)
self.FileObject = EncryptedFileObjectHandler(self.rawFileObject, self.decipher)
self.encryptedConnection = True
print "#Encryption enabled"
def run(self):
while True:
@ -202,11 +204,11 @@ class PacketListener(threading.Thread):
print "Ping timeout"
traceback.print_exc()
break
print hex(ord(response))
if(response == "\x00"):
PacketListenerManager.handle00(self.FileObject, self.socket)
elif(response == "\x01"):
PacketListenerManager.handle01(self.FileObject)
packet01 = PacketListenerManager.handle01(self.FileObject)
print "Logged in \o/ Received an entity id of " + str(packet01['EntityID'])
elif(response == "\x03"):
message = PacketListenerManager.handle03(self.FileObject)
if(self.connection.NoGUI):
@ -275,8 +277,6 @@ class PacketListener(threading.Thread):
PacketListenerManager.handle2A(self.FileObject)
elif(response == "\x2B"):
PacketListenerManager.handle2B(self.FileObject)
elif(response == "\x32"):
PacketListenerManager.handle32(self.FileObject)
elif(response == "\x33"):
PacketListenerManager.handle33(self.FileObject)
elif(response == "\x34"):
@ -285,10 +285,16 @@ class PacketListener(threading.Thread):
PacketListenerManager.handle35(self.FileObject)
elif(response == "\x36"):
PacketListenerManager.handle36(self.FileObject)
elif(response == "\x37"):
PacketListenerManager.handle37(self.FileObject)
elif(response == "\x38"):
PacketListenerManager.handle38(self.FileObject)
elif(response == "\x3C"):
PacketListenerManager.handle3C(self.FileObject)
elif(response == "\x3D"):
PacketListenerManager.handle3D(self.FileObject)
elif(response == "\x3E"):
PacketListenerManager.handle3E(self.FileObject)
elif(response == "\x46"):
PacketListenerManager.handle46(self.FileObject)
elif(response == "\x47"):
@ -300,7 +306,7 @@ class PacketListener(threading.Thread):
elif(response == "\x67"):
PacketListenerManager.handle67(self.FileObject)
elif(response == "\x68"):
PacketListenerManager.handle68(self.FileObject)
print PacketListenerManager.handle68(self.FileObject)
elif(response == "\x69"):
PacketListenerManager.handle69(self.FileObject)
elif(response == "\x6A"):
@ -316,9 +322,11 @@ class PacketListener(threading.Thread):
elif(response == "\xC8"):
PacketListenerManager.handleC8(self.FileObject)
elif(response == "\xC9"):
PacketListenerManager.handleC9(self.FileObject)
print PacketListenerManager.handleC9(self.FileObject)
elif(response == "\xCA"):
PacketListenerManager.handleCA(self.FileObject)
elif(response == "\xCB"):
PacketListenerManager.handleCB(self.FileObject)
elif(response == "\xFA"):
PacketListenerManager.handleFA(self.FileObject)
elif(response == "\xFC"):

View File

@ -9,8 +9,8 @@ def handle01(FileObject):
Eid = struct.unpack('!i', FileObject.read(4))[0]
length = struct.unpack('!h', FileObject.read(2))[0] * 2
world = FileObject.read(length).decode('utf-16be')
mode = struct.unpack('!i', FileObject.read(4))[0]
dimension = struct.unpack('!i', FileObject.read(4))[0]
mode = struct.unpack('!b', FileObject.read(1))[0]
dimension = struct.unpack('!b', FileObject.read(1))[0]
difficulty = struct.unpack('!b', FileObject.read(1))[0]
FileObject.read(1)
maxplayers = struct.unpack('!B', FileObject.read(1))[0]
@ -29,6 +29,12 @@ def handle02(FileObject):
message = message.decode('utf-16be', 'strict')
return message
def handle03(FileObject):
length = struct.unpack('!h', FileObject.read(2))[0] * 2
message = FileObject.read(length)
message = message.decode('utf-16be','strict')
return message
def handle04(FileObject):
time = struct.unpack('!q', FileObject.read(8))[0]
return time
@ -140,7 +146,6 @@ def handle14(FileObject):
'curItem' : curItem,
'Metadata' : metadata
}
print toReturn
return toReturn
def handle15(FileObject):
@ -211,6 +216,9 @@ def handle18(FileObject):
Yaw = struct.unpack('!b', FileObject.read(1))[0]
Pitch = struct.unpack('!b', FileObject.read(1))[0]
HeadYaw = struct.unpack('!b', FileObject.read(1))[0]
VelocityX = struct.unpack('!h', FileObject.read(2))[0]
VelocityY = struct.unpack('!h', FileObject.read(2))[0]
VelocityZ = struct.unpack('!h', FileObject.read(2))[0]
metadata = readEntityMetadata(FileObject)
return {'EntityID' : EntityID,
@ -221,7 +229,10 @@ def handle18(FileObject):
'Yaw' : Yaw,
'Pitch' : Pitch,
'HeadYaw' : HeadYaw,
'Metadata' : metadata
'Metadata' : metadata,
'VelocityX' : VelocityX,
'VelocityY' : VelocityY,
'VelocityZ' : VelocityZ
}
def handle19(FileObject):
@ -266,8 +277,11 @@ def handle1C(FileObject):
}
def handle1D(FileObject):
EntityID = struct.unpack('!i', FileObject.read(4))[0]
return EntityID
EntityArrayLength = struct.unpack('!b', FileObject.read(1))[0]
Entities = []
for i in range(EntityArrayLength):
Entities.append(struct.unpack('!i', FileObject.read(4))[0])
return Entities
def handle1E(FileObject):
EntityID = struct.unpack('!i', FileObject.read(4))[0]
@ -377,16 +391,6 @@ def handle2B(FileObject):
'Level' : Level,
'TotalExp' : TotalExp
}
def handle32(FileObject):
X = struct.unpack('!i', FileObject.read(4))[0]
raw = FileObject.read(4)
Z = struct.unpack('!i', raw)[0]
Mode = struct.unpack('?', FileObject.read(1))[0]
return {'x' : X,
'z' : Z,
'Mode' : Mode
}
def handle33(FileObject):
X = struct.unpack('!i', FileObject.read(4))[0]
@ -395,7 +399,6 @@ def handle33(FileObject):
PrimaryBitMap = struct.unpack('!H', FileObject.read(2))[0]
AddBitMap = struct.unpack('!H', FileObject.read(2))[0]
CompressedSize = struct.unpack('!i', FileObject.read(4))[0]
FileObject.read(4) #unused int
FileObject.read(CompressedSize) #not going to be deflating and using this data until I know how to :3
return {'x' : X,
'z' : Z
@ -416,7 +419,7 @@ def handle35(FileObject):
X = struct.unpack('!i', FileObject.read(4))[0]
Y = struct.unpack('!b', FileObject.read(1))[0]
Z = struct.unpack('!i', FileObject.read(4))[0]
BlockType = struct.unpack('!b', FileObject.read(1))[0]
BlockType = struct.unpack('!h', FileObject.read(2))[0]
BlockMetaData = struct.unpack('!b', FileObject.read(1))[0]
return {'x' : X,
'y' : Y,
@ -431,18 +434,57 @@ def handle36(FileObject):
Z = struct.unpack('!i', FileObject.read(4))[0]
Byte1 = struct.unpack('!b', FileObject.read(1))[0]
Byte2 = struct.unpack('!b', FileObject.read(1))[0]
BlockID = struct.unpack('!h', FileObject.read(2))[0]
return {'x' : X,
'y' : Y,
'z' : Z,
'Byte1' : Byte1,
'Byte2' : Byte2
'Byte2' : Byte2,
'BlockID' : BlockID
}
def handle37(FileObject):
#int - EntityID
EntityID = struct.unpack('!i', FileObject.read(4))[0]
#int - X cord
x = struct.unpack('!i', FileObject.read(4))[0]
#int - Y cord
y = struct.unpack('!i', FileObject.read(4))[0]
#int - Z cord
z = struct.unpack('!i', FileObject.read(4))[0]
#byte - Stage
DestroyedStage = struct.unpack('!b', FileObject.read(1))[0]
return {'EntityID' : EntityID,
'x' : x,
'y' : y,
'z' : z,
'DestroyedStage' : DestroyedStage
}
def handle38(FileObject):
#short - number of chunks
ChunkCount = struct.unpack('!h', FileObject.read(2))[0]
#int - chunk data length
ChunkDataLength = struct.unpack('!i', FileObject.read(4))[0]
FileObject.read(ChunkDataLength) #just gonna ignore this for now
#metadata - ignoring this
for i in range(ChunkCount):
FileObject.read(12)
return {'ChunkCount' : ChunkCount
}
def handle3C(FileObject):
X = struct.unpack('!d', FileObject.read(8))[0]
Y = struct.unpack('!d', FileObject.read(8))[0]
Z = struct.unpack('!d', FileObject.read(8))[0]
FileObject.read(4) #Unknown what this float does
Radius = struct.unpack('!f', FileObject.read(4))[0]
RecordCount = struct.unpack('!i', FileObject.read(4))[0]
AffectedBlocks = []
for i in range((RecordCount * 3)):
@ -450,9 +492,15 @@ def handle3C(FileObject):
y = struct.unpack('!b', FileObject.read(1))[0]
z = struct.unpack('!b', FileObject.read(1))[0]
AffectedBlocks.append({'x' : x, 'y' : y, 'z' : z})
return {'X' : X,
'Y' : Y,
'Z' : Z,
#---Unknown what these floats do
FileObject.read(4)
FileObject.read(4)
FileObject.read(4)
#---
return {'x' : X,
'y' : Y,
'z' : Z,
'Raidus' : Radius,
'AffectedBlocks' : AffectedBlocks
}
@ -469,6 +517,22 @@ def handle3D(FileObject):
'Data' : Data
}
def handle3E(FileObject):
length = struct.unpack('!h', FileObject.read(2))[0] * 2
Sound = FileObject.read(length).decode('utf-16be')
x = struct.unpack('!i', FileObject.read(4))[0]
y = struct.unpack('!i', FileObject.read(4))[0]
z = struct.unpack('!i', FileObject.read(4))[0]
Volume = struct.unpack('!f', FileObject.read(4))[0]
Pitch = struct.unpack('!b', FileObject.read(1))[0]
return {'Sound' : Sound,
'x' : x,
'y' : y,
'z' : z,
'Volume' : Volume,
'Pitch' : Pitch
}
def handle46(FileObject):
Reason = struct.unpack('!b', FileObject.read(1))[0]
GameMode = struct.unpack('!b', FileObject.read(1))[0]
@ -519,7 +583,6 @@ def handle68(FileObject):
Slots = []
for i in range(Count):
SlotData = decodeSlotData(FileObject)
SlotData["index"] = i
Slots.append(SlotData)
return {'WindowID' : WindowID,
'Count' : Count,
@ -555,7 +618,7 @@ def handle82(FileObject):
X = struct.unpack('!i', FileObject.read(4))[0]
Y = struct.unpack('!h', FileObject.read(2))[0]
Z = struct.unpack('!i', FileObject.read(4))[0]
length = struct.unpack('!i', FileObject.read(2))[0] * 2
length = struct.unpack('!h', FileObject.read(2))[0] * 2
Line1 = FileObject.read(length).decode("utf-16be")
length = struct.unpack('!h', FileObject.read(2))[0] * 2
Line2 = FileObject.read(length).decode("utf-16be")
@ -587,16 +650,19 @@ def handle84(FileObject):
Y = struct.unpack('!h', FileObject.read(2))[0]
Z = struct.unpack('!i', FileObject.read(4))[0]
Action = struct.unpack('!b', FileObject.read(1))[0]
Custom1 = struct.unpack('!i', FileObject.read(4))[0]
Custom2 = struct.unpack('!i', FileObject.read(4))[0]
Custom3 = struct.unpack('!i', FileObject.read(4))[0]
DataLength = struct.unpack('!h', FileObject.read(2))[0]
if (DataLength != -1):
NBTData = struct.unpack(str(DataLength) + "s", FileObject.read(DataLength))[0]
return {'x' : X,
'y' : Y,
'z' : Z,
'Action' : Action,
'NBTData' : NBTData
}
return {'x' : X,
'y' : Y,
'z' : Z,
'Action' : Action,
'Custom1' : Custom1,
'Custom2' : Custom2,
'Custom3': Custom3
'Action' : Action
}
def handleC8(FileObject):
@ -617,16 +683,24 @@ def handleC9(FileObject):
}
def handleCA(FileObject):
Invulnerable = struct.unpack('?', FileObject.read(1))[0]
IsFlying = struct.unpack('?', FileObject.read(1))[0]
CanFly = struct.unpack('?', FileObject.read(1))[0]
InstantDestroy = struct.unpack('?', FileObject.read(1))[0]
return {'Invulnerable' : Invulnerable,
'IsFlying' : IsFlying,
'CanFly' : CanFly,
'InstantDestroy' : InstantDestroy
#byte - flags
Flags = struct.unpack('!b', FileObject.read(1))[0]
#byte - fly speed
FlySpeed = struct.unpack('!b', FileObject.read(1))[0]
#byte - walk speed
WalkSpeed = struct.unpack('!b', FileObject.read(1))[0]
return {'Flags' : Flags,
'Fly Speed' : FlySpeed,
'Walk Speed' : WalkSpeed
}
def handleCB(FileObject):
length = struct.unpack('!h', FileObject.read(2))[0] * 2
text = FileObject.read(length).decode("utf-16be")
return {'Text' : text}
def handleFA(FileObject):
length = struct.unpack('!h', FileObject.read(2))[0] * 2
Channel = FileObject.read(length).decode("utf-16be")
@ -716,22 +790,21 @@ def decodeSlotData(FileObject):
BlockID = struct.unpack('!h', FileObject.read(2))[0]
if(BlockID != -1):
ItemCount = struct.unpack('!b', FileObject.read(1))[0]
MetaData = struct.unpack('!h', FileObject.read(2))[0]
if((256 <= BlockID and BlockID <= 259) or (267 <= BlockID and BlockID <= 279) or (283 <= BlockID and BlockID <= 286) or (290 <= BlockID and BlockID <= 294) or (298 <= BlockID and BlockID <= 317) or BlockID == 261 or BlockID == 359 or BlockID == 346):
IncomingDataLength = struct.unpack('!h', FileObject.read(2))[0]
if(IncomingDataLength != -1):
raw = FileObject.read(IncomingDataLength)
ByteArray = struct.unpack(str(IncomingDataLength) + "s", raw)[0]
Data = zlib.decompress(ByteArray, 15+32)
return {'BlockID' : BlockID,
'ItemCount' : ItemCount,
'MetaData' : MetaData,
'Data' : Data
}
Damage = struct.unpack('!h', FileObject.read(2))[0]
MetadataLength = struct.unpack('!h', FileObject.read(2))[0]
if(MetadataLength != -1):
raw = FileObject.read(MetadataLength)
ByteArray = struct.unpack(str(MetadataLength) + "s", raw)[0]
Data = zlib.decompress(ByteArray, 15+32)
return {'BlockID' : BlockID,
'ItemCount' : ItemCount,
'Damage' : Damage,
'Data' : Data
}
return {'BlockID' : BlockID,
'ItemCount' : ItemCount,
'MetaData' : MetaData
'Damage' : Damage
}
return {'BlockID' : -1,
'ItemCount' : -1
'ItemCount' : 0
}