forked from myanaloglife/py-kms
-
Notifications
You must be signed in to change notification settings - Fork 9
/
kmsRequestV4.py
121 lines (95 loc) · 3.45 KB
/
kmsRequestV4.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import binascii
import struct
import time
from kmsBase import kmsBase
from structure import Structure
from aes import AES
# v4 AES Key
key = bytearray([0x05, 0x3D, 0x83, 0x07, 0xF9, 0xE5, 0xF0, 0x88, 0xEB, 0x5E, 0xA6, 0x68, 0x6C, 0xF0, 0x37, 0xC7, 0xE4, 0xEF, 0xD2, 0xD6])
# Xor Buffer
def xorBuffer(source, offset, destination, size):
for i in range(0, size):
destination[i] ^= source[i + offset]
class kmsRequestV4(kmsBase):
class RequestV4(Structure):
commonHdr = ()
structure = (
('bodyLength1', '<I'),
('bodyLength2', '<I'),
('request', ':', kmsBase.kmsRequestStruct),
('hash', '16s'),
('padding', ':'),
)
class ResponseV4(Structure):
commonHdr = ()
structure = (
('bodyLength1', '<I=len(response) + len(hash)'),
('unknown', '!I=0x00000200'),
('bodyLength2', '<I=len(response) + len(hash)'),
('response', ':', kmsBase.kmsResponseStruct),
('hash', '16s'),
('padding', ':'),
)
def executeRequestLogic(self):
requestData = self.RequestV4(self.data)
response = self.serverLogic(requestData['request'])
hash = self.generateHash(bytearray(str(response)))
self.responseData = self.generateResponse(response, hash)
time.sleep(1) # request sent back too quick for Windows 2008 R2, slow it down.
def generateHash(self, message):
"""
The KMS v4 hash is a variant of CMAC-AES-128. There are two key differences:
* The 'AES' used is modified in particular ways:
* The basic algorithm is Rjindael with a conceptual 160bit key and 128bit blocks.
This isn't part of the AES standard, but it works the way you'd expect.
Accordingly, the algorithm uses 11 rounds and a 192 byte expanded key.
* The trailing block is not XORed with a generated subkey, as defined in CMAC.
This is probably because the subkey generation algorithm is only defined for
situations where block and key size are the same.
"""
aes = AES()
messageSize = len(message)
lastBlock = bytearray(16)
hashBuffer = bytearray(16)
# MessageSize / Blocksize
j = messageSize >> 4
# Remainding bytes
k = messageSize & 0xf
# Hash
for i in range(0, j):
xorBuffer(message, i << 4, hashBuffer, 16)
hashBuffer = bytearray(aes.encrypt(hashBuffer, key, len(key)))
# Bit Padding
ii = 0
for i in range(j << 4, k + (j << 4)):
lastBlock[ii] = message[i]
ii += 1
lastBlock[k] = 0x80
xorBuffer(lastBlock, 0, hashBuffer, 16)
hashBuffer = bytearray(aes.encrypt(hashBuffer, key, len(key)))
return str(hashBuffer)
def generateResponse(self, responseBuffer, hash):
bodyLength = len(responseBuffer) + len(hash)
response = self.ResponseV4()
response['response'] = responseBuffer
response['hash'] = hash
response['padding'] = self.getResponsePadding(bodyLength)
if self.config['debug']:
print "KMS V4 Response:", response.dump()
print "KMS V4 Response Bytes:", binascii.b2a_hex(str(response))
return str(response)
def getResponse(self):
return self.responseData
def generateRequest(self, requestBase):
hash = str(self.generateHash(bytearray(str(requestBase))))
bodyLength = len(requestBase) + len(hash)
request = kmsRequestV4.RequestV4()
request['bodyLength1'] = bodyLength
request['bodyLength2'] = bodyLength
request['request'] = requestBase
request['hash'] = hash
request['padding'] = self.getResponsePadding(bodyLength)
if self.config['debug']:
print "Request V4 Data:", request.dump()
print "Request V4:", binascii.b2a_hex(str(request))
return request