py-kms/py3-kms/kmsRequestV5.py
2018-02-28 23:27:12 +01:00

179 lines
7.8 KiB
Python

#!/usr/bin/env python3
import logging
import binascii
import hashlib
import random
import struct
from kmsBase import kmsBase
from structure import Structure
import aes
from formatText import justify, shell_message, byterize
class kmsRequestV5(kmsBase):
class RequestV5(Structure):
class Message(Structure):
commonHdr = ()
structure = (
('salt', '16s'),
('encrypted', '236s'), #kmsBase.kmsRequestStruct
('padding', ':'),
)
commonHdr = ()
structure = (
('bodyLength1', '<I'),
('bodyLength2', '<I'),
('versionMinor', '<H'),
('versionMajor', '<H'),
('message', ':', Message),
)
class DecryptedRequest(Structure):
commonHdr = ()
structure = (
('salt', '16s'),
('request', ':', kmsBase.kmsRequestStruct),
)
class ResponseV5(Structure):
commonHdr = ()
structure = (
('bodyLength1', '<I=2 + 2 + len(salt) + len(encrypted)'),
('unknown', '!I=0x00000200'),
('bodyLength2', '<I=2 + 2 + len(salt) + len(encrypted)'),
('versionMinor', '<H'),
('versionMajor', '<H'),
('salt', '16s'),
('encrypted', ':'), #DecryptedResponse
('padding', ':'),
)
class DecryptedResponse(Structure):
commonHdr = ()
structure = (
('response', ':', kmsBase.kmsResponseStruct),
('keys', '16s'),
('hash', '32s'),
)
key = bytearray([ 0xCD, 0x7E, 0x79, 0x6F, 0x2A, 0xB2, 0x5D, 0xCB, 0x55, 0xFF, 0xC8, 0xEF, 0x83, 0x64, 0xC4, 0x70 ])
v6 = False
ver = 5
def executeRequestLogic(self):
self.requestData = self.RequestV5(self.data)
decrypted = self.decryptRequest(self.requestData)
responseBuffer = self.serverLogic(decrypted['request'])
iv, encrypted = self.encryptResponse(self.requestData, decrypted, responseBuffer)
self.responseData = self.generateResponse(iv, encrypted)
def decryptRequest(self, request):
encrypted = bytearray(str(request['message']).encode('latin-1')) #*2to3*
iv = bytearray(request['message']['salt'].encode('latin-1')) #*2to3*
moo = aes.AESModeOfOperation()
moo.aes.v6 = self.v6
decrypted = moo.decrypt(encrypted, 256, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], iv) #*2to3*
decrypted = aes.strip_PKCS7_padding(decrypted)
decrypted = bytes(decrypted) #*2to3*
return self.DecryptedRequest(decrypted)
def encryptResponse(self, request, decrypted, response):
randomSalt = self.getRandomSalt()
sha256 = hashlib.sha256()
sha256.update(randomSalt) #*2to3*
result = sha256.digest()
iv = bytearray(request['message']['salt'].encode('latin-1')) #*2to3*
randomStuff = bytearray(16)
for i in range(0,16):
randomStuff[i] = (bytearray(decrypted['salt'].encode('latin-1'))[i] ^ iv[i] ^ randomSalt[i]) & 0xff #*2to3*
responsedata = self.DecryptedResponse()
responsedata['response'] = response
responsedata['keys'] = randomStuff #*2to3*
responsedata['hash'] = result
padded = aes.append_PKCS7_padding(str(responsedata).encode('latin-1')) #*2to3*
moo = aes.AESModeOfOperation()
moo.aes.v6 = self.v6
mode, orig_len, crypted = moo.encrypt(padded, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], iv) #*2to3*
return iv.decode('latin-1').encode('latin-1'), crypted #*2to3*
def decryptResponse(self, response):
paddingLength = response['bodyLength1'] % 8
iv = bytearray(response['salt'].encode('latin-1')) #*2to3*
encrypted = bytearray(response['encrypted'][:-paddingLength].encode('latin-1')) #*2to3*
moo = aes.AESModeOfOperation()
moo.aes.v6 = self.v6
decrypted = moo.decrypt(encrypted, 256, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], iv) #*2to3*
decrypted = aes.strip_PKCS7_padding(decrypted)
decrypted = bytes(decrypted) #*2to3*
return self.DecryptedResponse(decrypted)
def getRandomSalt(self):
return bytearray(random.getrandbits(8) for i in range(16))
def generateResponse(self, iv, encryptedResponse):
bodyLength = 4 + len(iv) + len(encryptedResponse)
response = self.ResponseV5()
response['versionMinor'] = self.requestData['versionMinor']
response['versionMajor'] = self.requestData['versionMajor']
response['salt'] = iv
response['encrypted'] = bytes(encryptedResponse) #*2to3*
response['padding'] = self.getResponsePadding(bodyLength).decode('latin-1').encode('latin-1') #*2to3*
shell_message(nshell = 16)
response = byterize(response)
logging.info("KMS V%d Response: \n%s\n" % (self.ver, justify(response.dump(print_to_stdout = False))))
logging.info("KMS V%d Structure Bytes: \n%s\n" % (self.ver, justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8')))) #*2to3*
return str(response)
def getResponse(self):
return self.responseData
def generateRequest(self, requestBase):
esalt = self.getRandomSalt()
moo = aes.AESModeOfOperation()
moo.aes.v6 = self.v6
dsalt = moo.decrypt(esalt, 16, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], esalt) #*2to3*
dsalt = bytearray(dsalt)
decrypted = self.DecryptedRequest()
decrypted['salt'] = dsalt #*2to3*
decrypted['request'] = requestBase
padded = aes.append_PKCS7_padding(str(decrypted).encode('latin-1')) #*2to3*
mode, orig_len, crypted = moo.encrypt(padded, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], esalt) #*2to3*
message = self.RequestV5.Message(bytes(crypted)) #*2to3*
bodyLength = len(message) + 2 + 2
request = self.RequestV5()
request['bodyLength1'] = bodyLength
request['bodyLength2'] = bodyLength
request['versionMinor'] = requestBase['versionMinor']
request['versionMajor'] = requestBase['versionMajor']
request['message'] = message
shell_message(nshell = 10)
request = byterize(request)
logging.info("Request V%d Data: \n%s\n" % (self.ver, justify(request.dump(print_to_stdout = False))))
logging.info("Request V%d: \n%s\n" % (self.ver, justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8')))) #*2to3*
return request