4 from kmsBase
import kmsBase
5 from structure
import Structure
10 key
= bytearray([0x05, 0x3D, 0x83, 0x07, 0xF9, 0xE5, 0xF0, 0x88, 0xEB, 0x5E, 0xA6, 0x68, 0x6C, 0xF0, 0x37, 0xC7, 0xE4, 0xEF, 0xD2, 0xD6])
13 def xorBuffer(source
, offset
, destination
, size
):
14 for i
in range(0, size
):
15 destination
[i
] ^
= source
[i
+ offset
]
17 class kmsRequestV4(kmsBase
):
18 class RequestV4(Structure
):
21 ('bodyLength1', '<I'),
22 ('bodyLength2', '<I'),
23 ('request', ':', kmsBase
.kmsRequestStruct
),
28 class ResponseV4(Structure
):
31 ('bodyLength1', '<I=len(response) + len(hash)'),
32 ('unknown', '!I=0x00000200'),
33 ('bodyLength2', '<I=len(response) + len(hash)'),
34 ('response', ':', kmsBase
.kmsResponseStruct
),
39 def executeRequestLogic(self
):
40 requestData
= self
.RequestV4(self
.data
)
42 response
= self
.serverLogic(requestData
['request'])
43 hash = self
.generateHash(bytearray(str(response
)))
45 self
.responseData
= self
.generateResponse(response
, hash)
47 time
.sleep(1) # request sent back too quick for Windows 2008 R2, slow it down.
49 def generateHash(self
, message
):
51 The KMS v4 hash is a variant of CMAC-AES-128. There are two key differences:
52 * The 'AES' used is modified in particular ways:
53 * The basic algorithm is Rjindael with a conceptual 160bit key and 128bit blocks.
54 This isn't part of the AES standard, but it works the way you'd expect.
55 Accordingly, the algorithm uses 11 rounds and a 192 byte expanded key.
56 * The trailing block is not XORed with a generated subkey, as defined in CMAC.
57 This is probably because the subkey generation algorithm is only defined for
58 situations where block and key size are the same.
62 messageSize
= len(message
)
63 lastBlock
= bytearray(16)
64 hashBuffer
= bytearray(16)
66 # MessageSize / Blocksize
74 xorBuffer(message
, i
<< 4, hashBuffer
, 16)
75 hashBuffer
= bytearray(aes
.encrypt(hashBuffer
, key
, len(key
)))
79 for i
in range(j
<< 4, k
+ (j
<< 4)):
80 lastBlock
[ii
] = message
[i
]
84 xorBuffer(lastBlock
, 0, hashBuffer
, 16)
85 hashBuffer
= bytearray(aes
.encrypt(hashBuffer
, key
, len(key
)))
87 return str(hashBuffer
)
89 def generateResponse(self
, responseBuffer
, hash):
90 bodyLength
= len(responseBuffer
) + len(hash)
91 response
= self
.ResponseV4()
92 response
['response'] = responseBuffer
93 response
['hash'] = hash
94 response
['padding'] = self
.getResponsePadding(bodyLength
)
96 if self
.config
['debug']:
97 print "KMS V4 Response:", response
.dump()
98 print "KMS V4 Response Bytes:", binascii
.b2a_hex(str(response
))
102 def getResponse(self
):
103 return self
.responseData
105 def generateRequest(self
, requestBase
):
106 hash = str(self
.generateHash(bytearray(str(requestBase
))))
108 bodyLength
= len(requestBase
) + len(hash)
110 request
= kmsRequestV4
.RequestV4()
111 request
['bodyLength1'] = bodyLength
112 request
['bodyLength2'] = bodyLength
113 request
['request'] = requestBase
114 request
['hash'] = hash
115 request
['padding'] = self
.getResponsePadding(bodyLength
)
117 if self
.config
['debug']:
118 print "Request V4 Data:", request
.dump()
119 print "Request V4:", binascii
.b2a_hex(str(request
))