add hostname support + finish license automata
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
example of use rdpy as rdp client
|
||||
"""
|
||||
|
||||
import sys, os, getopt
|
||||
import sys, os, getopt, socket
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from rdpy.ui.qt4 import RDPClientQt
|
||||
@@ -77,6 +77,7 @@ class RDPClientQtFactory(rdp.ClientFactory):
|
||||
controller.setPassword(self._passwod)
|
||||
controller.setDomain(self._domain)
|
||||
controller.setKeyboardLayout(self._keyboardLayout)
|
||||
controller.setHostname(socket.gethostname())
|
||||
if self._optimized:
|
||||
controller.setPerformanceSession()
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ from rdpy.ui import view
|
||||
from twisted.internet import reactor
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
log._LOG_LEVEL = log.Level.INFO
|
||||
#log._LOG_LEVEL = log.Level.INFO
|
||||
|
||||
class ProxyServer(rdp.RDPServerObserver):
|
||||
"""
|
||||
|
||||
@@ -136,8 +136,7 @@ class Client(PDULayer, tpkt.IFastPathListener):
|
||||
self._listener = listener
|
||||
#enable or not fast path
|
||||
self._fastPathSender = None
|
||||
#todo generate hostname
|
||||
self._licenceManager = lic.LicenseManager(self, self._info.userName.value, "wav-glw-009")
|
||||
self._licenceManager = lic.LicenseManager(self)
|
||||
|
||||
def connect(self):
|
||||
"""
|
||||
@@ -592,8 +591,7 @@ class Server(PDULayer, tpkt.IFastPathListener):
|
||||
|
||||
def sendDemandActivePDU(self):
|
||||
"""
|
||||
Send server capabilities
|
||||
server automata PDU
|
||||
@summary: Send server capabilities server automata PDU
|
||||
"""
|
||||
#init general capability
|
||||
generalCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability
|
||||
|
||||
@@ -90,6 +90,7 @@ class Preambule(object):
|
||||
"""
|
||||
PREAMBLE_VERSION_2_0 = 0x2
|
||||
PREAMBLE_VERSION_3_0 = 0x3
|
||||
EXTENDED_ERROR_MSG_SUPPORTED = 0x80
|
||||
|
||||
class LicenseBinaryBlob(CompositeType):
|
||||
"""
|
||||
@@ -208,13 +209,13 @@ class ClientPLatformChallengeResponse(CompositeType):
|
||||
|
||||
def __init__(self):
|
||||
CompositeType.__init__(self)
|
||||
self.encryptedPlatformChallengeResponse = LicenseBinaryBlob(BinaryBlobType.BB_ENCRYPTED_DATA_BLOB)
|
||||
self.encryptedHWID = LicenseBinaryBlob(BinaryBlobType.BB_ENCRYPTED_DATA_BLOB)
|
||||
self.encryptedPlatformChallengeResponse = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB)
|
||||
self.encryptedHWID = LicenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB)
|
||||
self.MACData = String(readLen = UInt8(16))
|
||||
|
||||
class LicPacket(CompositeType):
|
||||
"""
|
||||
A license packet
|
||||
@summary: A license packet
|
||||
"""
|
||||
def __init__(self, message = None):
|
||||
CompositeType.__init__(self)
|
||||
@@ -225,7 +226,7 @@ class LicPacket(CompositeType):
|
||||
|
||||
def LicensingMessageFactory():
|
||||
"""
|
||||
factory for message nego
|
||||
@summary: factory for message nego
|
||||
Use in read mode
|
||||
"""
|
||||
for c in [LicensingErrorMessage, ServerLicenseRequest, ClientNewLicenseRequest, ServerPlatformChallenge, ClientPLatformChallengeResponse]:
|
||||
@@ -249,32 +250,33 @@ def createValidClientLicensingErrorMessage():
|
||||
message = LicensingErrorMessage()
|
||||
message.dwErrorCode.value = ErrorCode.STATUS_VALID_CLIENT
|
||||
message.dwStateTransition.value = StateTransition.ST_NO_TRANSITION
|
||||
return LicPacket(message = message)
|
||||
return LicPacket(message)
|
||||
|
||||
class LicenseManager(object):
|
||||
"""
|
||||
@summary: handle license automata
|
||||
@see: http://msdn.microsoft.com/en-us/library/cc241890.aspx
|
||||
"""
|
||||
def __init__(self, transport, username, hostname):
|
||||
def __init__(self, transport):
|
||||
"""
|
||||
@param transport: layer use to send packet
|
||||
"""
|
||||
self._preMasterSecret = "\x00" * 64
|
||||
self._clientRandom = "\x00" * 32
|
||||
self._serverRandom = None
|
||||
self._serverEncryptedChallenge = None
|
||||
self._transport = transport
|
||||
self._username = username
|
||||
self._hostname = hostname
|
||||
self._username = ""
|
||||
self._hostname = ""
|
||||
|
||||
def generateKeys(self):
|
||||
"""
|
||||
@summary: generate key for license session
|
||||
"""
|
||||
self._masterSecret = sec.generateMicrosoftKey("\x00" * 64, self._clientRandom, self._serverRandom)
|
||||
self._sessionKeyBlob = sec.generateMicrosoftKey(self._masterSecret, self._serverRandom, self._clientRandom)
|
||||
self._macSalt = self._sessionKeyBlob[:16]
|
||||
self._licenseKey = sec.md5_16_32_32(self._sessionKeyBlob[16:], self._clientRandom, self._serverRandom)
|
||||
masterSecret = sec.generateMicrosoftKey(self._preMasterSecret, self._clientRandom, self._serverRandom)
|
||||
sessionKeyBlob = sec.generateMicrosoftKey(masterSecret, self._serverRandom, self._clientRandom)
|
||||
self._macSalt = sessionKeyBlob[:16]
|
||||
self._licenseKey = sec.finalHash(sessionKeyBlob[16:32], self._clientRandom, self._serverRandom)
|
||||
|
||||
def recv(self, s):
|
||||
"""
|
||||
@@ -296,7 +298,11 @@ class LicenseManager(object):
|
||||
elif licPacket.bMsgtype.value == MessageType.PLATFORM_CHALLENGE:
|
||||
self._serverEncryptedChallenge = licPacket.licensingMessage.encryptedPlatformChallenge.blobData.value
|
||||
self.sendClientChallengeResponse()
|
||||
|
||||
|
||||
#yes get a new license
|
||||
elif licPacket.bMsgtype.value == MessageType.NEW_LICENSE:
|
||||
return True
|
||||
|
||||
else:
|
||||
raise InvalidExpectedDataException("Not a valid license packet")
|
||||
|
||||
@@ -309,25 +315,27 @@ class LicenseManager(object):
|
||||
"""
|
||||
message = ClientNewLicenseRequest()
|
||||
message.clientRandom.value = self._clientRandom
|
||||
message.encryptedPreMasterSecret.blobData = String("\x00" * (64 + 8))
|
||||
message.encryptedPreMasterSecret.blobData = String(self._preMasterSecret + "\x00" * 8)
|
||||
message.ClientMachineName.blobData = String(self._hostname + "\x00")
|
||||
message.ClientUserName.blobData = String(self._username + "\x00")
|
||||
self._transport.sendLicensePacket(LicPacket(message))
|
||||
|
||||
def sendClientChallengeResponse(self):
|
||||
#it should be TEST in unicode format
|
||||
"""
|
||||
@summary: generate valid challenge response
|
||||
"""
|
||||
#decrypt server challenge
|
||||
#it should be TEST word in unicode format
|
||||
serverChallenge = rc4.crypt(self._licenseKey, self._serverEncryptedChallenge)
|
||||
|
||||
#generate hwid
|
||||
s = Stream()
|
||||
s.writeType((UInt32Le(2), String(self._username + self._hostname + "\x00" * 20)))
|
||||
s.writeType((UInt32Le(2), String(self._hostname + "\x00" * 16)))
|
||||
hwid = s.getvalue()[:20]
|
||||
|
||||
signature = sec.macData(self._macSalt, serverChallenge + hwid)
|
||||
|
||||
message = ClientPLatformChallengeResponse()
|
||||
message.encryptedPlatformChallengeResponse.blobData.value = self._serverEncryptedChallenge
|
||||
message.encryptedHWID.blobData.value = rc4.crypt(self._licenseKey, hwid)
|
||||
message.MACData.value = signature
|
||||
message.MACData.value = sec.macData(self._macSalt, serverChallenge + hwid)
|
||||
|
||||
self._transport.sendLicensePacket(LicPacket(message))
|
||||
@@ -89,6 +89,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
|
||||
"""
|
||||
#username in PDU info packet
|
||||
self._pduLayer._info.userName.value = username
|
||||
self._pduLayer._licenceManager._username = username
|
||||
|
||||
def setPassword(self, password):
|
||||
"""
|
||||
@@ -120,6 +121,13 @@ class RDPClientController(pdu.layer.PDUClientListener):
|
||||
self._mcsLayer._clientSettings.getBlock(gcc.MessageType.CS_CORE).kbdLayout.value = gcc.KeyboardLayout.FRENCH
|
||||
elif layout == "us":
|
||||
self._mcsLayer._clientSettings.getBlock(gcc.MessageType.CS_CORE).kbdLayout.value = gcc.KeyboardLayout.US
|
||||
|
||||
def setHostname(self, hostname):
|
||||
"""
|
||||
@summary: set hostname of machine
|
||||
"""
|
||||
self._mcsLayer._clientSettings.getBlock(gcc.MessageType.CS_CORE).clientName.value = hostname[:15] + "\x00" * (15 - len(hostname))
|
||||
self._pduLayer._licenceManager._hostname = hostname
|
||||
|
||||
def addClientObserver(self, observer):
|
||||
"""
|
||||
|
||||
@@ -48,18 +48,18 @@ def saltedHash(inputData, salt, salt1, salt2):
|
||||
|
||||
return md5Digest.digest()
|
||||
|
||||
def md5_16_32_32(in0, in1, in2):
|
||||
def finalHash(key, random1, random2):
|
||||
"""
|
||||
@summary: MD5(in0[:16] + in1[:32] + in2[:32])
|
||||
@param in0: in 16
|
||||
@param in1: in 32
|
||||
@param in2: in 32
|
||||
@param key: in 16
|
||||
@param random1: in 32
|
||||
@param random2: in 32
|
||||
@return MD5(in0[:16] + in1[:32] + in2[:32])
|
||||
"""
|
||||
md5Digest = md5.new()
|
||||
md5Digest.update(in0[:16])
|
||||
md5Digest.update(in1[:32])
|
||||
md5Digest.update(in2[:32])
|
||||
md5Digest.update(key)
|
||||
md5Digest.update(random1)
|
||||
md5Digest.update(random2)
|
||||
return md5Digest.digest()
|
||||
|
||||
def generateMicrosoftKey(secret, random1, random2):
|
||||
@@ -72,6 +72,9 @@ def generateMicrosoftKey(secret, random1, random2):
|
||||
return saltedHash("A", secret, random1, random2) + saltedHash("BB", secret, random1, random2) + saltedHash("CCC", secret, random1, random2)
|
||||
|
||||
def macData(macSaltKey, data):
|
||||
"""
|
||||
@see: http://msdn.microsoft.com/en-us/library/cc241995.aspx
|
||||
"""
|
||||
sha1Digest = sha.new()
|
||||
md5Digest = md5.new()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user